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
385
386
387
388
389
390
391
392
393
394
395
396
|
/* $NetBSD: sdmmcvar.h,v 1.36 2021/03/13 23:22:44 mlelstv Exp $ */
/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SDMMCVAR_H_
#define _SDMMCVAR_H_
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
#endif
#include <sys/queue.h>
#include <sys/mutex.h>
#include <sys/callout.h>
#include <sys/evcnt.h>
#include <sys/bus.h>
#include <dev/sdmmc/sdmmcchip.h>
#include <dev/sdmmc/sdmmcreg.h>
#define SDMMC_SECTOR_SIZE_SB 9
#define SDMMC_SECTOR_SIZE (1 << SDMMC_SECTOR_SIZE_SB) /* =512 */
struct sdmmc_csd {
int csdver; /* CSD structure format */
u_int mmcver; /* MMC version (for CID format) */
int capacity; /* total number of sectors */
int read_bl_len; /* block length for reads */
int write_bl_len; /* block length for writes */
int r2w_factor;
int tran_speed; /* transfer speed (kbit/s) */
int ccc; /* Card Command Class for SD */
/* ... */
};
struct sdmmc_ext_csd {
uint8_t rev;
uint8_t rst_n_function; /* RST_n_FUNCTION */
uint32_t cache_size;
};
struct sdmmc_cid {
int mid; /* manufacturer identification number */
int oid; /* OEM/product identification number */
char pnm[8]; /* product name (MMC v1 has the longest) */
int rev; /* product revision */
int psn; /* product serial number */
int mdt; /* manufacturing date */
};
struct sdmmc_scr {
int sd_spec;
int bus_width;
};
typedef uint32_t sdmmc_response[4];
struct sdmmc_softc;
struct sdmmc_task {
void (*func)(void *arg);
void *arg;
int onqueue;
struct sdmmc_softc *sc;
TAILQ_ENTRY(sdmmc_task) next;
};
#define sdmmc_init_task(xtask, xfunc, xarg) \
do { \
(xtask)->func = (xfunc); \
(xtask)->arg = (xarg); \
(xtask)->onqueue = 0; \
(xtask)->sc = NULL; \
} while (/*CONSTCOND*/0)
struct sdmmc_command {
struct sdmmc_task c_task; /* task queue entry */
uint16_t c_opcode; /* SD or MMC command index */
uint32_t c_arg; /* SD/MMC command argument */
sdmmc_response c_resp; /* response buffer */
bus_dmamap_t c_dmamap;
int c_dmaseg; /* DMA segment number */
int c_dmaoff; /* offset in DMA segment */
void *c_data; /* buffer to send or read into */
int c_datalen; /* length of data buffer */
int c_blklen; /* block length */
int c_flags; /* see below */
#define SCF_ITSDONE (1U << 0) /* command is complete */
#define SCF_RSP_PRESENT (1U << 1)
#define SCF_RSP_BSY (1U << 2)
#define SCF_RSP_136 (1U << 3)
#define SCF_RSP_CRC (1U << 4)
#define SCF_RSP_IDX (1U << 5)
#define SCF_CMD_READ (1U << 6) /* read command (data expected) */
/* non SPI */
#define SCF_CMD_AC (0U << 8)
#define SCF_CMD_ADTC (1U << 8)
#define SCF_CMD_BC (2U << 8)
#define SCF_CMD_BCR (3U << 8)
#define SCF_CMD_MASK (3U << 8)
/* SPI */
#define SCF_RSP_SPI_S1 (1U << 10)
#define SCF_RSP_SPI_S2 (1U << 11)
#define SCF_RSP_SPI_B4 (1U << 12)
#define SCF_RSP_SPI_BSY (1U << 13)
/* Probing */
#define SCF_TOUT_OK (1U << 14) /* command timeout expected */
/* Command hints */
#define SCF_XFER_SDHC (1U << 15) /* card is SDHC */
#define SCF_POLL (1U << 16) /* polling required */
#define SCF_NEED_BOUNCE (1U << 17) /* (driver) transfer requires bounce buffer */
#define SCF_NO_STOP (1U << 18) /* don't enable automatic stop CMD12 */
/* response types */
#define SCF_RSP_R0 0 /* none */
#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
#define SCF_RSP_R3 (SCF_RSP_PRESENT)
#define SCF_RSP_R4 (SCF_RSP_PRESENT)
#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_MASK (0x1f << 1)
/* SPI */
#define SCF_RSP_SPI_R1 (SCF_RSP_SPI_S1)
#define SCF_RSP_SPI_R1B (SCF_RSP_SPI_S1|SCF_RSP_SPI_BSY)
#define SCF_RSP_SPI_R2 (SCF_RSP_SPI_S1|SCF_RSP_SPI_S2)
#define SCF_RSP_SPI_R3 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4)
#define SCF_RSP_SPI_R4 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4)
#define SCF_RSP_SPI_R5 (SCF_RSP_SPI_S1|SCF_RSP_SPI_S2)
#define SCF_RSP_SPI_R7 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4)
#define SCF_RSP_SPI_MASK (0xf << 10)
int c_error; /* errno value on completion */
/* Host controller owned fields for data xfer in progress */
int c_resid; /* remaining I/O */
u_char *c_buf; /* remaining data */
};
/*
* Decoded PC Card 16 based Card Information Structure (CIS),
* per card (function 0) and per function (1 and greater).
*/
struct sdmmc_cis {
uint16_t manufacturer;
#define SDMMC_VENDOR_INVALID 0xffff
uint16_t product;
#define SDMMC_PRODUCT_INVALID 0xffff
uint8_t function;
#define SDMMC_FUNCTION_INVALID 0xff
u_char cis1_major;
u_char cis1_minor;
char cis1_info_buf[256];
char *cis1_info[4];
};
/*
* Structure describing either an SD card I/O function or a SD/MMC
* memory card from a "stack of cards" that responded to CMD2. For a
* combo card with one I/O function and one memory card, there will be
* two of these structures allocated. Each card slot has such a list
* of sdmmc_function structures.
*/
struct sdmmc_function {
/* common members */
struct sdmmc_softc *sc; /* card slot softc */
uint16_t rca; /* relative card address */
int interface; /* SD/MMC:0, SDIO:standard interface */
int width; /* bus width */
u_int blklen; /* block length */
int flags;
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
#define SFF_SDHC 0x0002 /* SD High Capacity card */
#define SFF_CACHE_ENABLED 0x0004 /* cache enabled */
SIMPLEQ_ENTRY(sdmmc_function) sf_list;
/* SD card I/O function members */
int number; /* I/O function number or -1 */
device_t child; /* function driver */
struct sdmmc_cis cis; /* decoded CIS */
/* SD/MMC memory card members */
struct sdmmc_csd csd; /* decoded CSD value */
struct sdmmc_ext_csd ext_csd; /* decoded EXT_CSD value */
struct sdmmc_cid cid; /* decoded CID value */
sdmmc_response raw_cid; /* temp. storage for decoding */
uint32_t raw_scr[2];
struct sdmmc_scr scr; /* decoded SCR value */
void *bbuf; /* bounce buffer */
bus_dmamap_t bbuf_dmap; /* DMA map for bounce buffer */
bus_dmamap_t sseg_dmap; /* DMA map for single segment */
};
/*
* Structure describing a single SD/MMC/SDIO card slot.
*/
struct sdmmc_softc {
device_t sc_dev; /* base device */
#define SDMMCDEVNAME(sc) (device_xname(sc->sc_dev))
sdmmc_chipset_tag_t sc_sct; /* host controller chipset tag */
sdmmc_spi_chipset_tag_t sc_spi_sct;
sdmmc_chipset_handle_t sc_sch; /* host controller chipset handle */
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmap;
#define SDMMC_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1)
struct kmutex sc_mtx; /* lock around host controller */
int sc_dying; /* bus driver is shutting down */
uint32_t sc_flags;
#define SMF_INITED 0x0001
#define SMF_SD_MODE 0x0002 /* host in SD mode (MMC otherwise) */
#define SMF_IO_MODE 0x0004 /* host in I/O mode (SD mode only) */
#define SMF_MEM_MODE 0x0008 /* host in memory mode (SD or MMC) */
#define SMF_CARD_PRESENT 0x4000 /* card presence noticed */
#define SMF_CARD_ATTACHED 0x8000 /* card driver(s) attached */
#define SMF_UHS_MODE 0x10000 /* host in UHS mode */
uint32_t sc_caps; /* host capability */
#define SMC_CAPS_AUTO_STOP __BIT(0) /* send CMD12 automagically by host */
#define SMC_CAPS_4BIT_MODE __BIT(1) /* 4-bits data bus width */
#define SMC_CAPS_DMA __BIT(2) /* DMA transfer */
#define SMC_CAPS_SPI_MODE __BIT(3) /* SPI mode */
#define SMC_CAPS_POLL_CARD_DET __BIT(4) /* Polling card detect */
#define SMC_CAPS_SINGLE_ONLY __BIT(5) /* only single read/write */
#define SMC_CAPS_8BIT_MODE __BIT(6) /* 8-bits data bus width */
#define SMC_CAPS_MULTI_SEG_DMA __BIT(7) /* multiple segment DMA transfer */
#define SMC_CAPS_SD_HIGHSPEED __BIT(8) /* SD high-speed timing */
#define SMC_CAPS_MMC_HIGHSPEED __BIT(9) /* MMC high-speed timing */
#define SMC_CAPS_MMC_DDR52 __BIT(10) /* MMC HS DDR52 timing */
/* __BIT(11) */
#define SMC_CAPS_UHS_SDR50 __BIT(12) /* UHS SDR50 timing */
#define SMC_CAPS_UHS_SDR104 __BIT(13) /* UHS SDR104 timing */
#define SMC_CAPS_UHS_DDR50 __BIT(14) /* UHS DDR50 timing */
#define SMC_CAPS_UHS_MASK (SMC_CAPS_UHS_SDR50 \
| SMC_CAPS_UHS_SDR104 \
| SMC_CAPS_UHS_DDR50)
#define SMC_CAPS_MMC_HS200 __BIT(15) /* eMMC HS200 timing */
#define SMC_CAPS_POLLING __BIT(30) /* driver supports cmd polling */
/* function */
int sc_function_count; /* number of I/O functions (SDIO) */
struct sdmmc_function *sc_card; /* selected card */
struct sdmmc_function *sc_fn0; /* function 0, the card itself */
SIMPLEQ_HEAD(, sdmmc_function) sf_head; /* list of card functions */
/* task queue */
struct lwp *sc_tskq_lwp; /* asynchronous tasks */
TAILQ_HEAD(, sdmmc_task) sc_tskq; /* task thread work queue */
struct kmutex sc_tskq_mtx;
struct kcondvar sc_tskq_cv;
struct sdmmc_task *sc_curtask;
/* discover task */
struct sdmmc_task sc_discover_task; /* card attach/detach task */
struct kmutex sc_discover_task_mtx;
/* interrupt task */
struct sdmmc_task sc_intr_task; /* card interrupt task */
TAILQ_HEAD(, sdmmc_intr_handler) sc_intrq; /* interrupt handlers */
u_int sc_clkmin; /* host min bus clock */
u_int sc_clkmax; /* host max bus clock */
u_int sc_busclk; /* host bus clock */
bool sc_busddr; /* host bus clock is in DDR mode */
int sc_buswidth; /* host bus width */
const char *sc_transfer_mode; /* current transfer mode */
callout_t sc_card_detect_ch; /* polling card insert/remove */
/* event counters */
struct evcnt sc_ev_xfer; /* xfer count */
struct evcnt sc_ev_xfer_aligned[8]; /* aligned xfer counts */
struct evcnt sc_ev_xfer_unaligned; /* unaligned xfer count */
struct evcnt sc_ev_xfer_error; /* error xfer count */
uint32_t sc_max_seg; /* maximum segment size */
};
/*
* Attach devices at the sdmmc bus.
*/
struct sdmmc_attach_args {
uint16_t manufacturer;
uint16_t product;
int interface;
struct sdmmc_function *sf;
};
struct sdmmc_product {
uint16_t pp_vendor;
uint16_t pp_product;
const char *pp_cisinfo[4];
};
#ifndef IPL_SDMMC
#define IPL_SDMMC IPL_BIO
#endif
#ifndef splsdmmc
#define splsdmmc() splbio()
#endif
#define SDMMC_LOCK(sc)
#define SDMMC_UNLOCK(sc)
#ifdef SDMMC_DEBUG
extern int sdmmcdebug;
#endif
void sdmmc_add_task(struct sdmmc_softc *, struct sdmmc_task *);
bool sdmmc_del_task(struct sdmmc_softc *, struct sdmmc_task *, kmutex_t *);
struct sdmmc_function *sdmmc_function_alloc(struct sdmmc_softc *);
void sdmmc_function_free(struct sdmmc_function *);
int sdmmc_set_bus_power(struct sdmmc_softc *, uint32_t, uint32_t);
int sdmmc_mmc_command(struct sdmmc_softc *, struct sdmmc_command *);
int sdmmc_app_command(struct sdmmc_softc *, struct sdmmc_function *,
struct sdmmc_command *);
void sdmmc_stop_transmission(struct sdmmc_softc *);
void sdmmc_go_idle_state(struct sdmmc_softc *);
int sdmmc_select_card(struct sdmmc_softc *, struct sdmmc_function *);
int sdmmc_set_relative_addr(struct sdmmc_softc *, struct sdmmc_function *);
void sdmmc_intr_enable(struct sdmmc_function *);
void sdmmc_intr_disable(struct sdmmc_function *);
void *sdmmc_intr_establish(device_t, int (*)(void *), void *, const char *);
void sdmmc_intr_disestablish(void *);
void sdmmc_intr_task(void *);
int sdmmc_decode_csd(struct sdmmc_softc *, sdmmc_response,
struct sdmmc_function *);
int sdmmc_decode_cid(struct sdmmc_softc *, sdmmc_response,
struct sdmmc_function *);
void sdmmc_print_cid(struct sdmmc_cid *);
#ifdef SDMMC_DUMP_CSD
void sdmmc_print_csd(sdmmc_response, struct sdmmc_csd *);
#endif
void sdmmc_dump_data(const char *, void *, size_t);
int sdmmc_io_enable(struct sdmmc_softc *);
void sdmmc_io_scan(struct sdmmc_softc *);
int sdmmc_io_init(struct sdmmc_softc *, struct sdmmc_function *);
int sdmmc_io_set_blocklen(struct sdmmc_function *, int);
uint8_t sdmmc_io_read_1(struct sdmmc_function *, int);
uint16_t sdmmc_io_read_2(struct sdmmc_function *, int);
uint32_t sdmmc_io_read_4(struct sdmmc_function *, int);
int sdmmc_io_read_multi_1(struct sdmmc_function *, int, u_char *, int);
int sdmmc_io_read_region_1(struct sdmmc_function *, int, u_char *, int);
void sdmmc_io_write_1(struct sdmmc_function *, int, uint8_t);
void sdmmc_io_write_2(struct sdmmc_function *, int, uint16_t);
void sdmmc_io_write_4(struct sdmmc_function *, int, uint32_t);
int sdmmc_io_write_multi_1(struct sdmmc_function *, int, u_char *, int);
int sdmmc_io_write_region_1(struct sdmmc_function *, int, u_char *, int);
int sdmmc_io_function_enable(struct sdmmc_function *);
void sdmmc_io_function_disable(struct sdmmc_function *);
int sdmmc_io_function_abort(struct sdmmc_function *);
int sdmmc_read_cis(struct sdmmc_function *, struct sdmmc_cis *);
void sdmmc_print_cis(struct sdmmc_function *);
void sdmmc_check_cis_quirks(struct sdmmc_function *);
int sdmmc_mem_enable(struct sdmmc_softc *);
void sdmmc_mem_scan(struct sdmmc_softc *);
int sdmmc_mem_init(struct sdmmc_softc *, struct sdmmc_function *);
int sdmmc_mem_send_op_cond(struct sdmmc_softc *, uint32_t, uint32_t *);
int sdmmc_mem_send_if_cond(struct sdmmc_softc *, uint32_t, uint32_t *);
int sdmmc_mem_set_blocklen(struct sdmmc_softc *, struct sdmmc_function *,
int);
int sdmmc_mem_read_block(struct sdmmc_function *, uint32_t, u_char *,
size_t);
int sdmmc_mem_write_block(struct sdmmc_function *, uint32_t, u_char *,
size_t);
int sdmmc_mem_discard(struct sdmmc_function *, uint32_t, uint32_t);
int sdmmc_mem_flush_cache(struct sdmmc_function *, bool);
void sdmmc_pause(u_int, kmutex_t *);
#endif /* _SDMMCVAR_H_ */
|