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
|
/* $OpenBSD: sdmmcvar.h,v 1.34 2020/08/14 14:49:04 kettenis 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_
#include <sys/queue.h>
#include <sys/rwlock.h>
#include <machine/bus.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <dev/sdmmc/sdmmcchip.h>
#include <dev/sdmmc/sdmmcreg.h>
struct sdmmc_csd {
int csdver; /* CSD structure format */
int mmcver; /* MMC version (for CID format) */
int capacity; /* total number of sectors */
int sector_size; /* sector size in bytes */
int read_bl_len; /* block length for reads */
int tran_speed; /* transfer speed (kbit/s) */
int ccc; /* Card Command Class for SD */
/* ... */
};
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 u_int32_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 (0)
#define sdmmc_task_pending(xtask) ((xtask)->onqueue)
struct sdmmc_command {
struct sdmmc_task c_task; /* task queue entry */
u_int16_t c_opcode; /* SD or MMC command index */
u_int32_t c_arg; /* SD/MMC command argument */
sdmmc_response c_resp; /* response buffer */
bus_dmamap_t c_dmamap;
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 0x0001 /* command is complete */
#define SCF_CMD(flags) ((flags) & 0x00f0)
#define SCF_CMD_AC 0x0000
#define SCF_CMD_ADTC 0x0010
#define SCF_CMD_BC 0x0020
#define SCF_CMD_BCR 0x0030
#define SCF_CMD_READ 0x0040 /* read command (data expected) */
#define SCF_RSP_BSY 0x0100
#define SCF_RSP_136 0x0200
#define SCF_RSP_CRC 0x0400
#define SCF_RSP_IDX 0x0800
#define SCF_RSP_PRESENT 0x1000
/* 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)
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 {
u_int16_t manufacturer;
#define SDMMC_VENDOR_INVALID 0xffff
u_int16_t product;
#define SDMMC_PRODUCT_INVALID 0xffff
u_int8_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 */
u_int16_t rca; /* relative card address */
int flags;
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
#define SFF_SDHC 0x0002 /* SD High Capacity card */
void *cookie; /* pass extra info from bus to dev */
SIMPLEQ_ENTRY(sdmmc_function) sf_list;
/* SD card I/O function members */
int number; /* I/O function number or -1 */
struct device *child; /* function driver */
struct sdmmc_cis cis; /* decoded CIS */
unsigned int cur_blklen; /* current block length */
/* SD/MMC memory card members */
struct sdmmc_csd csd; /* decoded CSD value */
struct sdmmc_cid cid; /* decoded CID value */
sdmmc_response raw_cid; /* temp. storage for decoding */
struct sdmmc_scr scr; /* decoded SCR value */
};
/*
* Structure describing a single SD/MMC/SDIO card slot.
*/
struct sdmmc_softc {
struct device sc_dev; /* base device */
#define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
sdmmc_chipset_tag_t sct; /* host controller chipset tag */
sdmmc_chipset_handle_t sch; /* host controller chipset handle */
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmap;
#define SDMMC_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1)
int sc_flags;
#define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */
#define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */
#define SMF_MEM_MODE 0x0004 /* host in memory mode (SD or MMC) */
#define SMF_UHS_MODE 0x0010 /* host in UHS mode */
#define SMF_CARD_PRESENT 0x0020 /* card presence noticed */
#define SMF_CARD_ATTACHED 0x0040 /* card driver(s) attached */
#define SMF_STOP_AFTER_MULTIPLE 0x0080 /* send a stop after a multiple cmd */
#define SMF_CONFIG_PENDING 0x0100 /* config_pending_incr() called */
uint32_t sc_caps; /* host capability */
#define SMC_CAPS_AUTO_STOP 0x0001 /* send CMD12 automagically by host */
#define SMC_CAPS_4BIT_MODE 0x0002 /* 4-bits data bus width */
#define SMC_CAPS_DMA 0x0004 /* DMA transfer */
#define SMC_CAPS_SPI_MODE 0x0008 /* SPI mode */
#define SMC_CAPS_POLL_CARD_DET 0x0010 /* Polling card detect */
#define SMC_CAPS_SINGLE_ONLY 0x0020 /* only single read/write */
#define SMC_CAPS_8BIT_MODE 0x0040 /* 8-bits data bus width */
#define SMC_CAPS_MULTI_SEG_DMA 0x0080 /* multiple segment DMA transfer */
#define SMC_CAPS_SD_HIGHSPEED 0x0100 /* SD high-speed timing */
#define SMC_CAPS_MMC_HIGHSPEED 0x0200 /* MMC high-speed timing */
#define SMC_CAPS_UHS_SDR50 0x0400 /* UHS SDR50 timing */
#define SMC_CAPS_UHS_SDR104 0x0800 /* UHS SDR104 timing */
#define SMC_CAPS_UHS_DDR50 0x1000 /* UHS DDR50 timing */
#define SMC_CAPS_UHS_MASK 0x1c00
#define SMC_CAPS_MMC_DDR52 0x2000 /* eMMC DDR52 timing */
#define SMC_CAPS_MMC_HS200 0x4000 /* eMMC HS200 timing */
#define SMC_CAPS_MMC_HS400 0x8000 /* eMMC HS400 timing */
#define SMC_CAPS_NONREMOVABLE 0x10000 /* non-removable devices */
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 */
int sc_dying; /* bus driver is shutting down */
struct proc *sc_task_thread; /* asynchronous tasks */
TAILQ_HEAD(, sdmmc_task) sc_tskq; /* task thread work queue */
struct sdmmc_task sc_discover_task; /* card attach/detach task */
struct sdmmc_task sc_intr_task; /* card interrupt task */
struct rwlock sc_lock; /* lock around host controller */
void *sc_scsibus; /* SCSI bus emulation softc */
TAILQ_HEAD(, sdmmc_intr_handler) sc_intrq; /* interrupt handlers */
long sc_max_seg; /* maximum segment size */
long sc_max_xfer; /* maximum transfer size */
void *sc_cookies[SDMMC_MAX_FUNCTIONS]; /* pass extra info from bus to dev */
};
/*
* Attach devices at the sdmmc bus.
*/
struct sdmmc_attach_args {
struct scsibus_attach_args saa;
struct sdmmc_function *sf;
};
#define IPL_SDMMC IPL_BIO
#define splsdmmc() splbio()
#define SDMMC_ASSERT_LOCKED(sc) \
rw_assert_wrlock(&(sc)->sc_lock)
void sdmmc_add_task(struct sdmmc_softc *, struct sdmmc_task *);
void sdmmc_del_task(struct sdmmc_task *);
struct sdmmc_function *sdmmc_function_alloc(struct sdmmc_softc *);
void sdmmc_function_free(struct sdmmc_function *);
int sdmmc_set_bus_power(struct sdmmc_softc *, u_int32_t, u_int32_t);
int sdmmc_mmc_command(struct sdmmc_softc *, struct sdmmc_command *);
int sdmmc_app_command(struct sdmmc_softc *, struct sdmmc_command *);
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 *);
int sdmmc_send_if_cond(struct sdmmc_softc *, uint32_t);
void sdmmc_intr_enable(struct sdmmc_function *);
void sdmmc_intr_disable(struct sdmmc_function *);
void *sdmmc_intr_establish(struct device *, int (*)(void *),
void *, const char *);
void sdmmc_intr_disestablish(void *);
void sdmmc_intr_task(void *);
int sdmmc_io_enable(struct sdmmc_softc *);
void sdmmc_io_scan(struct sdmmc_softc *);
int sdmmc_io_init(struct sdmmc_softc *, struct sdmmc_function *);
void sdmmc_io_attach(struct sdmmc_softc *);
void sdmmc_io_detach(struct sdmmc_softc *);
u_int8_t sdmmc_io_read_1(struct sdmmc_function *, int);
u_int16_t sdmmc_io_read_2(struct sdmmc_function *, int);
u_int32_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, u_int8_t);
void sdmmc_io_write_2(struct sdmmc_function *, int, u_int16_t);
void sdmmc_io_write_4(struct sdmmc_function *, int, u_int32_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_ready(struct sdmmc_function *);
int sdmmc_io_function_enable(struct sdmmc_function *);
void sdmmc_io_function_disable(struct sdmmc_function *);
void sdmmc_io_set_blocklen(struct sdmmc_function *, unsigned int);
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_read_block(struct sdmmc_function *, int, u_char *, size_t);
int sdmmc_mem_write_block(struct sdmmc_function *, int, u_char *, size_t);
#ifdef HIBERNATE
int sdmmc_mem_hibernate_write(struct sdmmc_function *, daddr_t, u_char *,
size_t);
#endif
/* ioctls */
#include <sys/ioccom.h>
struct bio_sdmmc_command {
void *cookie;
struct sdmmc_command cmd;
};
struct bio_sdmmc_debug {
void *cookie;
int debug;
};
#define SDIOCEXECMMC _IOWR('S',0, struct bio_sdmmc_command)
#define SDIOCEXECAPP _IOWR('S',1, struct bio_sdmmc_command)
#define SDIOCSETDEBUG _IOWR('S',2, struct bio_sdmmc_debug)
#endif
|