| 1 | /* $NetBSD: sdmmcvar.h,v 1.21 2015/11/29 23:38:47 jmcneill Exp $ */ |
| 2 | /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ |
| 3 | |
| 4 | /* |
| 5 | * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> |
| 6 | * |
| 7 | * Permission to use, copy, modify, and distribute this software for any |
| 8 | * purpose with or without fee is hereby granted, provided that the above |
| 9 | * copyright notice and this permission notice appear in all copies. |
| 10 | * |
| 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 18 | */ |
| 19 | |
| 20 | #ifndef _SDMMCVAR_H_ |
| 21 | #define _SDMMCVAR_H_ |
| 22 | |
| 23 | #ifdef _KERNEL_OPT |
| 24 | #include "opt_sdmmc.h" |
| 25 | #endif |
| 26 | |
| 27 | #include <sys/queue.h> |
| 28 | #include <sys/mutex.h> |
| 29 | #include <sys/callout.h> |
| 30 | #include <sys/evcnt.h> |
| 31 | |
| 32 | #include <sys/bus.h> |
| 33 | |
| 34 | #include <dev/sdmmc/sdmmcchip.h> |
| 35 | #include <dev/sdmmc/sdmmcreg.h> |
| 36 | |
| 37 | #define SDMMC_SECTOR_SIZE_SB 9 |
| 38 | #define SDMMC_SECTOR_SIZE (1 << SDMMC_SECTOR_SIZE_SB) /* =512 */ |
| 39 | |
| 40 | struct sdmmc_csd { |
| 41 | int csdver; /* CSD structure format */ |
| 42 | u_int mmcver; /* MMC version (for CID format) */ |
| 43 | int capacity; /* total number of sectors */ |
| 44 | int read_bl_len; /* block length for reads */ |
| 45 | int write_bl_len; /* block length for writes */ |
| 46 | int r2w_factor; |
| 47 | int tran_speed; /* transfer speed (kbit/s) */ |
| 48 | int ccc; /* Card Command Class for SD */ |
| 49 | /* ... */ |
| 50 | }; |
| 51 | |
| 52 | struct sdmmc_cid { |
| 53 | int mid; /* manufacturer identification number */ |
| 54 | int oid; /* OEM/product identification number */ |
| 55 | char pnm[8]; /* product name (MMC v1 has the longest) */ |
| 56 | int rev; /* product revision */ |
| 57 | int psn; /* product serial number */ |
| 58 | int mdt; /* manufacturing date */ |
| 59 | }; |
| 60 | |
| 61 | struct sdmmc_scr { |
| 62 | int sd_spec; |
| 63 | int bus_width; |
| 64 | }; |
| 65 | |
| 66 | typedef uint32_t sdmmc_response[4]; |
| 67 | |
| 68 | struct sdmmc_softc; |
| 69 | |
| 70 | struct sdmmc_task { |
| 71 | void (*func)(void *arg); |
| 72 | void *arg; |
| 73 | int onqueue; |
| 74 | struct sdmmc_softc *sc; |
| 75 | TAILQ_ENTRY(sdmmc_task) next; |
| 76 | }; |
| 77 | |
| 78 | #define sdmmc_init_task(xtask, xfunc, xarg) \ |
| 79 | do { \ |
| 80 | (xtask)->func = (xfunc); \ |
| 81 | (xtask)->arg = (xarg); \ |
| 82 | (xtask)->onqueue = 0; \ |
| 83 | (xtask)->sc = NULL; \ |
| 84 | } while (/*CONSTCOND*/0) |
| 85 | |
| 86 | #define sdmmc_task_pending(xtask) ((xtask)->onqueue) |
| 87 | |
| 88 | struct sdmmc_command { |
| 89 | struct sdmmc_task c_task; /* task queue entry */ |
| 90 | uint16_t c_opcode; /* SD or MMC command index */ |
| 91 | uint32_t c_arg; /* SD/MMC command argument */ |
| 92 | sdmmc_response c_resp; /* response buffer */ |
| 93 | bus_dmamap_t c_dmamap; |
| 94 | int c_dmaseg; /* DMA segment number */ |
| 95 | int c_dmaoff; /* offset in DMA segment */ |
| 96 | void *c_data; /* buffer to send or read into */ |
| 97 | int c_datalen; /* length of data buffer */ |
| 98 | int c_blklen; /* block length */ |
| 99 | int c_flags; /* see below */ |
| 100 | #define SCF_ITSDONE (1U << 0) /* command is complete */ |
| 101 | #define SCF_RSP_PRESENT (1U << 1) |
| 102 | #define SCF_RSP_BSY (1U << 2) |
| 103 | #define SCF_RSP_136 (1U << 3) |
| 104 | #define SCF_RSP_CRC (1U << 4) |
| 105 | #define SCF_RSP_IDX (1U << 5) |
| 106 | #define SCF_CMD_READ (1U << 6) /* read command (data expected) */ |
| 107 | /* non SPI */ |
| 108 | #define SCF_CMD_AC (0U << 8) |
| 109 | #define SCF_CMD_ADTC (1U << 8) |
| 110 | #define SCF_CMD_BC (2U << 8) |
| 111 | #define SCF_CMD_BCR (3U << 8) |
| 112 | #define SCF_CMD_MASK (3U << 8) |
| 113 | /* SPI */ |
| 114 | #define SCF_RSP_SPI_S1 (1U << 10) |
| 115 | #define SCF_RSP_SPI_S2 (1U << 11) |
| 116 | #define SCF_RSP_SPI_B4 (1U << 12) |
| 117 | #define SCF_RSP_SPI_BSY (1U << 13) |
| 118 | /* Probing */ |
| 119 | #define SCF_TOUT_OK (1U << 14) /* command timeout expected */ |
| 120 | /* response types */ |
| 121 | #define SCF_RSP_R0 0 /* none */ |
| 122 | #define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) |
| 123 | #define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) |
| 124 | #define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136) |
| 125 | #define SCF_RSP_R3 (SCF_RSP_PRESENT) |
| 126 | #define SCF_RSP_R4 (SCF_RSP_PRESENT) |
| 127 | #define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) |
| 128 | #define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) |
| 129 | #define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) |
| 130 | #define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) |
| 131 | #define SCF_RSP_MASK (0x1f << 1) |
| 132 | /* SPI */ |
| 133 | #define SCF_RSP_SPI_R1 (SCF_RSP_SPI_S1) |
| 134 | #define SCF_RSP_SPI_R1B (SCF_RSP_SPI_S1|SCF_RSP_SPI_BSY) |
| 135 | #define SCF_RSP_SPI_R2 (SCF_RSP_SPI_S1|SCF_RSP_SPI_S2) |
| 136 | #define SCF_RSP_SPI_R3 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4) |
| 137 | #define SCF_RSP_SPI_R4 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4) |
| 138 | #define SCF_RSP_SPI_R5 (SCF_RSP_SPI_S1|SCF_RSP_SPI_S2) |
| 139 | #define SCF_RSP_SPI_R7 (SCF_RSP_SPI_S1|SCF_RSP_SPI_B4) |
| 140 | #define SCF_RSP_SPI_MASK (0xf << 10) |
| 141 | int c_error; /* errno value on completion */ |
| 142 | |
| 143 | /* Host controller owned fields for data xfer in progress */ |
| 144 | int c_resid; /* remaining I/O */ |
| 145 | u_char *c_buf; /* remaining data */ |
| 146 | }; |
| 147 | |
| 148 | /* |
| 149 | * Decoded PC Card 16 based Card Information Structure (CIS), |
| 150 | * per card (function 0) and per function (1 and greater). |
| 151 | */ |
| 152 | struct sdmmc_cis { |
| 153 | uint16_t manufacturer; |
| 154 | #define SDMMC_VENDOR_INVALID 0xffff |
| 155 | uint16_t product; |
| 156 | #define SDMMC_PRODUCT_INVALID 0xffff |
| 157 | uint8_t function; |
| 158 | #define SDMMC_FUNCTION_INVALID 0xff |
| 159 | u_char cis1_major; |
| 160 | u_char cis1_minor; |
| 161 | char cis1_info_buf[256]; |
| 162 | char *cis1_info[4]; |
| 163 | }; |
| 164 | |
| 165 | /* |
| 166 | * Structure describing either an SD card I/O function or a SD/MMC |
| 167 | * memory card from a "stack of cards" that responded to CMD2. For a |
| 168 | * combo card with one I/O function and one memory card, there will be |
| 169 | * two of these structures allocated. Each card slot has such a list |
| 170 | * of sdmmc_function structures. |
| 171 | */ |
| 172 | struct sdmmc_function { |
| 173 | /* common members */ |
| 174 | struct sdmmc_softc *sc; /* card slot softc */ |
| 175 | uint16_t rca; /* relative card address */ |
| 176 | int interface; /* SD/MMC:0, SDIO:standard interface */ |
| 177 | int width; /* bus width */ |
| 178 | int flags; |
| 179 | #define SFF_ERROR 0x0001 /* function is poo; ignore it */ |
| 180 | #define SFF_SDHC 0x0002 /* SD High Capacity card */ |
| 181 | SIMPLEQ_ENTRY(sdmmc_function) sf_list; |
| 182 | /* SD card I/O function members */ |
| 183 | int number; /* I/O function number or -1 */ |
| 184 | device_t child; /* function driver */ |
| 185 | struct sdmmc_cis cis; /* decoded CIS */ |
| 186 | /* SD/MMC memory card members */ |
| 187 | struct sdmmc_csd csd; /* decoded CSD value */ |
| 188 | struct sdmmc_cid cid; /* decoded CID value */ |
| 189 | sdmmc_response raw_cid; /* temp. storage for decoding */ |
| 190 | uint32_t raw_scr[2]; |
| 191 | struct sdmmc_scr scr; /* decoded SCR value */ |
| 192 | |
| 193 | void *bbuf; /* bounce buffer */ |
| 194 | bus_dmamap_t bbuf_dmap; /* DMA map for bounce buffer */ |
| 195 | bus_dmamap_t sseg_dmap; /* DMA map for single segment */ |
| 196 | }; |
| 197 | |
| 198 | /* |
| 199 | * Structure describing a single SD/MMC/SDIO card slot. |
| 200 | */ |
| 201 | struct sdmmc_softc { |
| 202 | device_t sc_dev; /* base device */ |
| 203 | #define SDMMCDEVNAME(sc) (device_xname(sc->sc_dev)) |
| 204 | |
| 205 | sdmmc_chipset_tag_t sc_sct; /* host controller chipset tag */ |
| 206 | sdmmc_spi_chipset_tag_t sc_spi_sct; |
| 207 | sdmmc_chipset_handle_t sc_sch; /* host controller chipset handle */ |
| 208 | bus_dma_tag_t sc_dmat; |
| 209 | bus_dmamap_t sc_dmap; |
| 210 | #define SDMMC_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1) |
| 211 | |
| 212 | struct kmutex sc_mtx; /* lock around host controller */ |
| 213 | int sc_dying; /* bus driver is shutting down */ |
| 214 | |
| 215 | uint32_t sc_flags; |
| 216 | #define SMF_INITED 0x0001 |
| 217 | #define SMF_SD_MODE 0x0002 /* host in SD mode (MMC otherwise) */ |
| 218 | #define SMF_IO_MODE 0x0004 /* host in I/O mode (SD mode only) */ |
| 219 | #define SMF_MEM_MODE 0x0008 /* host in memory mode (SD or MMC) */ |
| 220 | #define SMF_CARD_PRESENT 0x4000 /* card presence noticed */ |
| 221 | #define SMF_CARD_ATTACHED 0x8000 /* card driver(s) attached */ |
| 222 | #define SMF_UHS_MODE 0x10000 /* host in UHS mode */ |
| 223 | |
| 224 | uint32_t sc_caps; /* host capability */ |
| 225 | #define SMC_CAPS_AUTO_STOP 0x0001 /* send CMD12 automagically by host */ |
| 226 | #define SMC_CAPS_4BIT_MODE 0x0002 /* 4-bits data bus width */ |
| 227 | #define SMC_CAPS_DMA 0x0004 /* DMA transfer */ |
| 228 | #define SMC_CAPS_SPI_MODE 0x0008 /* SPI mode */ |
| 229 | #define SMC_CAPS_POLL_CARD_DET 0x0010 /* Polling card detect */ |
| 230 | #define SMC_CAPS_SINGLE_ONLY 0x0020 /* only single read/write */ |
| 231 | #define SMC_CAPS_8BIT_MODE 0x0040 /* 8-bits data bus width */ |
| 232 | #define SMC_CAPS_MULTI_SEG_DMA 0x0080 /* multiple segment DMA transfer */ |
| 233 | #define SMC_CAPS_SD_HIGHSPEED 0x0100 /* SD high-speed timing */ |
| 234 | #define SMC_CAPS_MMC_HIGHSPEED 0x0200 /* MMC high-speed timing */ |
| 235 | #define SMC_CAPS_UHS_SDR50 0x1000 /* UHS SDR50 timing */ |
| 236 | #define SMC_CAPS_UHS_SDR104 0x2000 /* UHS SDR104 timing */ |
| 237 | #define SMC_CAPS_UHS_DDR50 0x4000 /* UHS DDR50 timing */ |
| 238 | #define SMC_CAPS_UHS_MASK 0x7000 |
| 239 | #define SMC_CAPS_MMC_HS200 0x8000 /* eMMC HS200 timing */ |
| 240 | |
| 241 | /* function */ |
| 242 | int sc_function_count; /* number of I/O functions (SDIO) */ |
| 243 | struct sdmmc_function *sc_card; /* selected card */ |
| 244 | struct sdmmc_function *sc_fn0; /* function 0, the card itself */ |
| 245 | SIMPLEQ_HEAD(, sdmmc_function) sf_head; /* list of card functions */ |
| 246 | |
| 247 | /* task queue */ |
| 248 | struct lwp *sc_tskq_lwp; /* asynchronous tasks */ |
| 249 | TAILQ_HEAD(, sdmmc_task) sc_tskq; /* task thread work queue */ |
| 250 | struct kmutex sc_tskq_mtx; |
| 251 | struct kcondvar sc_tskq_cv; |
| 252 | |
| 253 | /* discover task */ |
| 254 | struct sdmmc_task sc_discover_task; /* card attach/detach task */ |
| 255 | struct kmutex sc_discover_task_mtx; |
| 256 | |
| 257 | /* interrupt task */ |
| 258 | struct sdmmc_task sc_intr_task; /* card interrupt task */ |
| 259 | struct kmutex sc_intr_task_mtx; |
| 260 | TAILQ_HEAD(, sdmmc_intr_handler) sc_intrq; /* interrupt handlers */ |
| 261 | |
| 262 | u_int sc_clkmin; /* host min bus clock */ |
| 263 | u_int sc_clkmax; /* host max bus clock */ |
| 264 | u_int sc_busclk; /* host bus clock */ |
| 265 | bool sc_busddr; /* host bus clock is in DDR mode */ |
| 266 | int sc_buswidth; /* host bus width */ |
| 267 | const char *sc_transfer_mode; /* current transfer mode */ |
| 268 | |
| 269 | callout_t sc_card_detect_ch; /* polling card insert/remove */ |
| 270 | |
| 271 | /* event counters */ |
| 272 | struct evcnt sc_ev_xfer; /* xfer count */ |
| 273 | struct evcnt sc_ev_xfer_aligned[8]; /* aligned xfer counts */ |
| 274 | struct evcnt sc_ev_xfer_unaligned; /* unaligned xfer count */ |
| 275 | struct evcnt sc_ev_xfer_error; /* error xfer count */ |
| 276 | }; |
| 277 | |
| 278 | /* |
| 279 | * Attach devices at the sdmmc bus. |
| 280 | */ |
| 281 | struct sdmmc_attach_args { |
| 282 | uint16_t manufacturer; |
| 283 | uint16_t product; |
| 284 | int interface; |
| 285 | struct sdmmc_function *sf; |
| 286 | }; |
| 287 | |
| 288 | struct sdmmc_product { |
| 289 | uint16_t pp_vendor; |
| 290 | uint16_t pp_product; |
| 291 | const char *pp_cisinfo[4]; |
| 292 | }; |
| 293 | |
| 294 | #ifndef IPL_SDMMC |
| 295 | #define IPL_SDMMC IPL_BIO |
| 296 | #endif |
| 297 | |
| 298 | #ifndef splsdmmc |
| 299 | #define splsdmmc() splbio() |
| 300 | #endif |
| 301 | |
| 302 | #define SDMMC_LOCK(sc) |
| 303 | #define SDMMC_UNLOCK(sc) |
| 304 | |
| 305 | #ifdef SDMMC_DEBUG |
| 306 | extern int sdmmcdebug; |
| 307 | #endif |
| 308 | |
| 309 | void sdmmc_add_task(struct sdmmc_softc *, struct sdmmc_task *); |
| 310 | void sdmmc_del_task(struct sdmmc_task *); |
| 311 | |
| 312 | struct sdmmc_function *sdmmc_function_alloc(struct sdmmc_softc *); |
| 313 | void sdmmc_function_free(struct sdmmc_function *); |
| 314 | int sdmmc_set_bus_power(struct sdmmc_softc *, uint32_t, uint32_t); |
| 315 | int sdmmc_mmc_command(struct sdmmc_softc *, struct sdmmc_command *); |
| 316 | int sdmmc_app_command(struct sdmmc_softc *, struct sdmmc_function *, |
| 317 | struct sdmmc_command *); |
| 318 | void sdmmc_stop_transmission(struct sdmmc_softc *); |
| 319 | void sdmmc_go_idle_state(struct sdmmc_softc *); |
| 320 | int sdmmc_select_card(struct sdmmc_softc *, struct sdmmc_function *); |
| 321 | int sdmmc_set_relative_addr(struct sdmmc_softc *, struct sdmmc_function *); |
| 322 | |
| 323 | void sdmmc_intr_enable(struct sdmmc_function *); |
| 324 | void sdmmc_intr_disable(struct sdmmc_function *); |
| 325 | void *sdmmc_intr_establish(device_t, int (*)(void *), void *, const char *); |
| 326 | void sdmmc_intr_disestablish(void *); |
| 327 | void sdmmc_intr_task(void *); |
| 328 | |
| 329 | int sdmmc_decode_csd(struct sdmmc_softc *, sdmmc_response, |
| 330 | struct sdmmc_function *); |
| 331 | int sdmmc_decode_cid(struct sdmmc_softc *, sdmmc_response, |
| 332 | struct sdmmc_function *); |
| 333 | void sdmmc_print_cid(struct sdmmc_cid *); |
| 334 | #ifdef SDMMC_DUMP_CSD |
| 335 | void sdmmc_print_csd(sdmmc_response, struct sdmmc_csd *); |
| 336 | #endif |
| 337 | void sdmmc_dump_data(const char *, void *, size_t); |
| 338 | |
| 339 | int sdmmc_io_enable(struct sdmmc_softc *); |
| 340 | void sdmmc_io_scan(struct sdmmc_softc *); |
| 341 | int sdmmc_io_init(struct sdmmc_softc *, struct sdmmc_function *); |
| 342 | uint8_t sdmmc_io_read_1(struct sdmmc_function *, int); |
| 343 | uint16_t sdmmc_io_read_2(struct sdmmc_function *, int); |
| 344 | uint32_t sdmmc_io_read_4(struct sdmmc_function *, int); |
| 345 | int sdmmc_io_read_multi_1(struct sdmmc_function *, int, u_char *, int); |
| 346 | void sdmmc_io_write_1(struct sdmmc_function *, int, uint8_t); |
| 347 | void sdmmc_io_write_2(struct sdmmc_function *, int, uint16_t); |
| 348 | void sdmmc_io_write_4(struct sdmmc_function *, int, uint32_t); |
| 349 | int sdmmc_io_write_multi_1(struct sdmmc_function *, int, u_char *, int); |
| 350 | int sdmmc_io_function_enable(struct sdmmc_function *); |
| 351 | void sdmmc_io_function_disable(struct sdmmc_function *); |
| 352 | |
| 353 | int sdmmc_read_cis(struct sdmmc_function *, struct sdmmc_cis *); |
| 354 | void sdmmc_print_cis(struct sdmmc_function *); |
| 355 | void sdmmc_check_cis_quirks(struct sdmmc_function *); |
| 356 | |
| 357 | int sdmmc_mem_enable(struct sdmmc_softc *); |
| 358 | void sdmmc_mem_scan(struct sdmmc_softc *); |
| 359 | int sdmmc_mem_init(struct sdmmc_softc *, struct sdmmc_function *); |
| 360 | int sdmmc_mem_send_op_cond(struct sdmmc_softc *, uint32_t, uint32_t *); |
| 361 | int sdmmc_mem_send_if_cond(struct sdmmc_softc *, uint32_t, uint32_t *); |
| 362 | int sdmmc_mem_set_blocklen(struct sdmmc_softc *, struct sdmmc_function *, |
| 363 | int); |
| 364 | int sdmmc_mem_read_block(struct sdmmc_function *, uint32_t, u_char *, |
| 365 | size_t); |
| 366 | int sdmmc_mem_write_block(struct sdmmc_function *, uint32_t, u_char *, |
| 367 | size_t); |
| 368 | |
| 369 | #endif /* _SDMMCVAR_H_ */ |
| 370 | |