summaryrefslogtreecommitdiff
path: root/bsp/allwinner/libraries/sunxi-hal/hal/source/sdmmc/_core.h
blob: 149c4ad9728c120f1149dc7c84d7bdc0594e392a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
/*
 * Copyright (C) 2017 ALLWINNERTECH TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of ALLWINNERTECH TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _ROM_DRIVER_CHIP_SDMMC__CORE_H_
#define _ROM_DRIVER_CHIP_SDMMC__CORE_H_

//#include "rom_debug.h"
#include "rom_debug.h"

#include "card.h"

#ifdef CONFIG_USE_SDIO
#include "sdio.h"
#endif
#include "sdmmc.h"

#include "_sdhost.h"

#ifdef __cplusplus
extern "C" {
#endif

struct mmc_data {
    uint32_t blksz;     /* data block size */
    uint32_t blocks;    /* number of blocks */
    uint32_t flags;

#define MMC_DATA_WRITE          (1 << 8)
#define MMC_DATA_READ           (1 << 9)
#define MMC_DATA_STREAM         (1 << 10)

    uint32_t                bytes_xfered;
    uint32_t                sg_len;         /* size of scatter list */
    struct scatterlist      *sg;            /* I/O scatter list */
};

struct mmc_command {
    uint32_t opcode;
    uint32_t arg;
    uint32_t resp[4];
    uint32_t flags;                         /* expected response type */
    /* data transfer */
    volatile uint32_t stop        :1,
                      boot        :1,
                      vol_switch  :1;

#define MMC_RSP_MASK            (0x1f << 0)
#define MMC_RSP_PRESENT         (1 << 0)
#define MMC_RSP_136             (1 << 1)        /* 136 bit response */
#define MMC_RSP_CRC             (1 << 2)        /* expect valid crc */
#define MMC_RSP_BUSY            (1 << 3)        /* card may send busy */
#define MMC_RSP_OPCODE          (1 << 4)        /* response contains opcode */

#define MMC_CMD_MASK            (3 << 5)        /* non-SPI command type */
#define MMC_CMD_AC              (0 << 5)        /* addressed comamnd without data transfer */
#define MMC_CMD_ADTC            (1 << 5)        /* addressed command with data transfer */
#define MMC_CMD_BC              (2 << 5)        /* broadcast command without response */
#define MMC_CMD_BCR             (3 << 5)        /* broadcast command with response */

#define MMC_RSP_SPI_S1          (1 << 7)        /* one status byte */
#define MMC_RSP_SPI_S2          (1 << 8)        /* second byte */
#define MMC_RSP_SPI_B4          (1 << 9)        /* four data bytes */
#define MMC_RSP_SPI_BUSY        (1 << 10)       /* card may send busy */

/* These are the native response types, and correspond to valid bit
 * patterns of the above flags.  One additional valid pattern
 * is all zeros, which means we don't expect a response.
 */
#define MMC_RSP_NONE            (0)
#define MMC_RSP_R1              (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R1B             (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
#define MMC_RSP_R2              (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3              (MMC_RSP_PRESENT)
#define MMC_RSP_R4              (MMC_RSP_PRESENT)
#define MMC_RSP_R5              (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R6              (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7              (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)

#define mmc_resp_type(cmd)      ((cmd)->flags & MMC_RSP_MASK)

/*
 * These are the SPI response types for MMC, SD, and SDIO cards.
 * Commands return R1, with maybe more info.  Zero is an error type;
 * callers must always provide the appropriate MMC_RSP_SPI_Rx flags.
 */
#define MMC_RSP_SPI_R1          (MMC_RSP_SPI_S1)
#define MMC_RSP_SPI_R1B         (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY)
#define MMC_RSP_SPI_R2          (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
#define MMC_RSP_SPI_R3          (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
#define MMC_RSP_SPI_R4          (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
#define MMC_RSP_SPI_R5          (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
#define MMC_RSP_SPI_R7          (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)

/* These are the command types. */
#define mmc_cmd_type(cmd)       ((cmd)->flags & MMC_CMD_MASK)

#if ((defined CONFIG_USE_SD) || (defined CONFIG_USE_MMC))
    uint32_t retries;               /* max number of retries */

    /* Standard errno values are used for errors, but some have specific
     * meaning in the MMC layer:
     *
     * ETIMEDOUT    Card took too long to respond
     * EILSEQ       Basic format problem with the received or sent data
     *              (e.g. CRC check failed, incorrect opcode in response
     *              or bad end bit)
     * EINVAL       Request cannot be performed because of restrictions
     *              in hardware and/or the driver
     * ENOMEDIUM    Host can determine that the slot is empty and is
     *              actively failing requests
     */
    uint32_t erase_timeout;         /* in milliseconds */
#endif

    struct mmc_data         *data;          /* data segment associated with cmd */
};

struct mmc_request {
    //struct mmc_command    *sbc;           /* SET_BLOCK_COUNT for multiblock */
    struct mmc_command      *cmd;
    struct mmc_data         *data;
    //struct mmc_command    *stop;

    //struct completion     completion;
    //void                  (*done)(struct mmc_request *); /* completion function */
};

#define UNSTUFF_BITS(resp,start,size)                                   \
    ({                                                              \
        const int32_t __size = size;                            \
        const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;    \
        const int32_t __off = 3 - ((start) / 32);                       \
        const int32_t __shft = (start) & 31;                    \
        uint32_t __res;                                         \
                                                                \
        __res = resp[__off] >> __shft;                          \
        if (__size + __shft > 32)                               \
            __res |= resp[__off-1] << ((32 - __shft) % 32); \
        __res & __mask;                                         \
    })

#ifdef CONFIG_USE_MMC_QUIRK

#define SDIO_ANY_ID (~0)

/*
 *  The world is not perfect and supplies us with broken mmc/sdio devices.
 *  For at least some of these bugs we need a work-around.
 */

struct mmc_fixup {
    /* CID-specific fields. */
    const char *name;

    /* Valid revision range */
    uint64_t rev_start, rev_end;

    int32_t manfid;
    int16_t oemid;

    /* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
    uint16_t cis_vendor, cis_device;

    void (*vendor_fixup)(struct mmc_card *card, int32_t data);
    int32_t data;
};

#define CID_MANFID_ANY (-1u)
#define CID_OEMID_ANY ((unsigned short) -1)
#define CID_NAME_ANY (NULL)

#define END_FIXUP { 0 }

#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,    \
           _cis_vendor, _cis_device,                \
           _fixup, _data)                   \
    {                          \
        .name = (_name),               \
        .manfid = (_manfid),               \
        .oemid = (_oemid),             \
        .rev_start = (_rev_start),         \
        .rev_end = (_rev_end),             \
        .cis_vendor = (_cis_vendor),           \
        .cis_device = (_cis_device),           \
        .vendor_fixup = (_fixup),          \
        .data = (_data),               \
     }

#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \
    _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,    \
            CID_OEMID_ANY, 0, -1ull,        \
           _vendor, _device,            \
           _fixup, _data)           \

#define cid_rev(hwrev, fwrev, year, month)  \
    (((uint64_t) hwrev) << 40 |          \
     ((uint64_t) fwrev) << 32 |          \
     ((uint64_t) year) << 16 |           \
     ((uint64_t) month))

#define cid_rev_card(card)        \
    cid_rev(card->cid.hwrev,      \
            card->cid.fwrev,      \
            card->cid.year,   \
            card->cid.month)

/*
 * This hook just adds a quirk for all sdio devices
 */
static void add_quirk_for_sdio_devices(struct mmc_card *card, int32_t data)
{
    if (mmc_card_sdio(card))
        card->quirks |= data;
}

static inline void add_quirk(struct mmc_card *card, int32_t data)
{
    card->quirks |= data;
}

static inline void remove_quirk(struct mmc_card *card, int32_t data)
{
    card->quirks &= ~data;
}

/*
 * Quirk add/remove for MMC products.
 */

static inline void add_quirk_mmc(struct mmc_card *card, int data)
{
    if (mmc_card_mmc(card))
        card->quirks |= data;
}

static inline void remove_quirk_mmc(struct mmc_card *card,
                           int data)
{
    if (mmc_card_mmc(card))
        card->quirks &= ~data;
}

/*
 * Quirk add/remove for SD products.
 */

static inline void add_quirk_sd(struct mmc_card *card, int data)
{
    if (mmc_card_sd(card))
        card->quirks |= data;
}

static inline void remove_quirk_sd(struct mmc_card *card,
                           int data)
{
    if (mmc_card_sd(card))
        card->quirks &= ~data;
}

static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
{
    return c->quirks & MMC_QUIRK_LENIENT_FN0;
}

static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
{
    return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
}

/*
static inline int mmc_card_disable_cd(const struct mmc_card *c)
{
    return c->quirks & MMC_QUIRK_DISABLE_CD;
}
*/

static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
{
    return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
}

static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)
{
    return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512;
}

static inline int mmc_card_long_read_time(const struct mmc_card *c)
{
    return c->quirks & MMC_QUIRK_LONG_READ_TIME;
}

#endif

void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);

extern int32_t mmc_align_data_size(struct mmc_card *card, uint32_t sz);
extern int32_t mmc_send_status(struct mmc_card *card, uint32_t *status);
extern int32_t mmc_sd_switch(struct mmc_card *card, uint8_t mode, uint8_t group,
                             uint16_t value, uint8_t *resp);
extern void mmc_enumerate_card_info(struct mmc_card *card);
extern int32_t mmc_switch_to_high_speed(struct mmc_card *card);
extern int32_t __sdmmc_block_rw(struct mmc_card *card, uint32_t blk_num, uint32_t blk_cnt,
                                uint32_t sg_len, struct scatterlist *sg, int write);
extern int32_t mmc_sd_switch_hs(struct mmc_card *card);
extern int32_t mmc_app_set_bus_width(struct mmc_card *card, uint32_t width);
extern int32_t mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd);
extern int32_t mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq);
//#ifndef __CONFIG_ROM
extern int32_t mmc_attach_sd(struct mmc_card *card, struct mmc_host *host);
extern void mmc_deattach_sd(struct mmc_card *card, struct mmc_host *host);
//#endif
extern int32_t mmc_select_card(struct mmc_card *card, uint32_t select);
extern int32_t mmc_all_send_cid(struct mmc_host *host, uint32_t *cid);
extern int32_t mmc_send_relative_addr(struct mmc_host *host, uint32_t *rca);
extern void mmc_add_card(struct mmc_card *card);
#ifdef CONFIG_USE_MMC_QUIRK
extern void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table);
#endif

static inline int mmc_card_disable_cd(const struct mmc_card *c)
{
#ifdef CONFIG_USE_MMC_QUIRK
    return c->quirks & MMC_QUIRK_DISABLE_CD;
#else
    return 0;
#endif
}

/**
 * @brief Exclusively claim a host.
 * @note Claim a host for a set of operations.
 * @param host:
 *        @host->mmc host to claim.
 * @retval  None.
 */
static inline void mmc_claim_host(struct mmc_host *host)
{
    HAL_SDC_Claim_Host(host);
}

/**
 * @brief Release a host.
 * @note Release a MMC host, allowing others to claim the host for their operations.
 * @param host:
 *        @host->mmc host to release.
 * @retval  None.
 */
static inline void mmc_release_host(struct mmc_host *host)
{
    HAL_SDC_Release_Host(host);
}

#ifdef __cplusplus
}
#endif

#endif /* _ROM_DRIVER_CHIP_SDMMC__CORE_H_ */