xref: /openbsd-src/sys/dev/sdmmc/sdmmcvar.h (revision a62fc20a112dc2cec994ce46422c87e62e6d4cae)
1*a62fc20aSkettenis /*	$OpenBSD: sdmmcvar.h,v 1.34 2020/08/14 14:49:04 kettenis Exp $	*/
2aae4fe77Suwe 
3aae4fe77Suwe /*
4aae4fe77Suwe  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
5aae4fe77Suwe  *
6aae4fe77Suwe  * Permission to use, copy, modify, and distribute this software for any
7aae4fe77Suwe  * purpose with or without fee is hereby granted, provided that the above
8aae4fe77Suwe  * copyright notice and this permission notice appear in all copies.
9aae4fe77Suwe  *
10aae4fe77Suwe  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11aae4fe77Suwe  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12aae4fe77Suwe  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13aae4fe77Suwe  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14aae4fe77Suwe  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15aae4fe77Suwe  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16aae4fe77Suwe  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17aae4fe77Suwe  */
18aae4fe77Suwe 
19aae4fe77Suwe #ifndef _SDMMCVAR_H_
20aae4fe77Suwe #define _SDMMCVAR_H_
21aae4fe77Suwe 
22aae4fe77Suwe #include <sys/queue.h>
239de6240fSblambert #include <sys/rwlock.h>
24cfd1c195Suwe 
25c6293583Skettenis #include <machine/bus.h>
26c6293583Skettenis 
27cfd1c195Suwe #include <scsi/scsi_all.h>
28cfd1c195Suwe #include <scsi/scsiconf.h>
29cfd1c195Suwe 
30aae4fe77Suwe #include <dev/sdmmc/sdmmcchip.h>
31aae4fe77Suwe #include <dev/sdmmc/sdmmcreg.h>
32aae4fe77Suwe 
33aae4fe77Suwe struct sdmmc_csd {
34aae4fe77Suwe 	int	csdver;		/* CSD structure format */
35aae4fe77Suwe 	int	mmcver;		/* MMC version (for CID format) */
36aae4fe77Suwe 	int	capacity;	/* total number of sectors */
37aae4fe77Suwe 	int	sector_size;	/* sector size in bytes */
38aae4fe77Suwe 	int	read_bl_len;	/* block length for reads */
39*a62fc20aSkettenis 	int	tran_speed;	/* transfer speed (kbit/s) */
409ca7c972Skettenis 	int	ccc;		/* Card Command Class for SD */
41aae4fe77Suwe 	/* ... */
42aae4fe77Suwe };
43aae4fe77Suwe 
44aae4fe77Suwe struct sdmmc_cid {
45aae4fe77Suwe 	int	mid;		/* manufacturer identification number */
46aae4fe77Suwe 	int	oid;		/* OEM/product identification number */
47aae4fe77Suwe 	char	pnm[8];		/* product name (MMC v1 has the longest) */
48aae4fe77Suwe 	int	rev;		/* product revision */
49aae4fe77Suwe 	int	psn;		/* product serial number */
50aae4fe77Suwe 	int	mdt;		/* manufacturing date */
51aae4fe77Suwe };
52aae4fe77Suwe 
53b140af5cSkettenis struct sdmmc_scr {
54b140af5cSkettenis 	int	sd_spec;
55b140af5cSkettenis 	int	bus_width;
56b140af5cSkettenis };
57b140af5cSkettenis 
58aae4fe77Suwe typedef u_int32_t sdmmc_response[4];
59a6fd99a7Suwe 
60a6fd99a7Suwe struct sdmmc_softc;
61a6fd99a7Suwe 
62a6fd99a7Suwe struct sdmmc_task {
63a6fd99a7Suwe 	void (*func)(void *arg);
64a6fd99a7Suwe 	void *arg;
65a6fd99a7Suwe 	int onqueue;
66a6fd99a7Suwe 	struct sdmmc_softc *sc;
67a6fd99a7Suwe 	TAILQ_ENTRY(sdmmc_task) next;
68a6fd99a7Suwe };
69a6fd99a7Suwe 
70a6fd99a7Suwe #define	sdmmc_init_task(xtask, xfunc, xarg) do {			\
71a6fd99a7Suwe 	(xtask)->func = (xfunc);					\
72a6fd99a7Suwe 	(xtask)->arg = (xarg);						\
73a6fd99a7Suwe 	(xtask)->onqueue = 0;						\
74a6fd99a7Suwe 	(xtask)->sc = NULL;						\
75a6fd99a7Suwe } while (0)
76a6fd99a7Suwe 
77a6fd99a7Suwe #define sdmmc_task_pending(xtask) ((xtask)->onqueue)
78aae4fe77Suwe 
79aae4fe77Suwe struct sdmmc_command {
80a6fd99a7Suwe 	struct sdmmc_task c_task;	/* task queue entry */
81aae4fe77Suwe 	u_int16_t	 c_opcode;	/* SD or MMC command index */
82aae4fe77Suwe 	u_int32_t	 c_arg;		/* SD/MMC command argument */
83aae4fe77Suwe 	sdmmc_response	 c_resp;	/* response buffer */
84c6293583Skettenis 	bus_dmamap_t	 c_dmamap;
85aae4fe77Suwe 	void		*c_data;	/* buffer to send or read into */
86aae4fe77Suwe 	int		 c_datalen;	/* length of data buffer */
87aae4fe77Suwe 	int		 c_blklen;	/* block length */
88aae4fe77Suwe 	int		 c_flags;	/* see below */
89a6fd99a7Suwe #define SCF_ITSDONE	 0x0001		/* command is complete */
9058eb2f8fSuwe #define SCF_CMD(flags)	 ((flags) & 0x00f0)
91aae4fe77Suwe #define SCF_CMD_AC	 0x0000
92aae4fe77Suwe #define SCF_CMD_ADTC	 0x0010
93aae4fe77Suwe #define SCF_CMD_BC	 0x0020
94aae4fe77Suwe #define SCF_CMD_BCR	 0x0030
95aae4fe77Suwe #define SCF_CMD_READ	 0x0040		/* read command (data expected) */
96aae4fe77Suwe #define SCF_RSP_BSY	 0x0100
97aae4fe77Suwe #define SCF_RSP_136	 0x0200
98aae4fe77Suwe #define SCF_RSP_CRC	 0x0400
99aae4fe77Suwe #define SCF_RSP_IDX	 0x0800
100aae4fe77Suwe #define SCF_RSP_PRESENT	 0x1000
101aae4fe77Suwe /* response types */
102aae4fe77Suwe #define SCF_RSP_R0	 0 /* none */
103aae4fe77Suwe #define SCF_RSP_R1	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
1041b5fa04aSuwe #define SCF_RSP_R1B	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
105aae4fe77Suwe #define SCF_RSP_R2	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
106aae4fe77Suwe #define SCF_RSP_R3	 (SCF_RSP_PRESENT)
107aae4fe77Suwe #define SCF_RSP_R4	 (SCF_RSP_PRESENT)
108cfd1c195Suwe #define SCF_RSP_R5	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
109cfd1c195Suwe #define SCF_RSP_R5B	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
11058eb2f8fSuwe #define SCF_RSP_R6	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
1118323add6Sjsg #define SCF_RSP_R7	 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
112aae4fe77Suwe 	int		 c_error;	/* errno value on completion */
11358eb2f8fSuwe 
11458eb2f8fSuwe 	/* Host controller owned fields for data xfer in progress */
11558eb2f8fSuwe 	int c_resid;			/* remaining I/O */
11658eb2f8fSuwe 	u_char *c_buf;			/* remaining data */
117aae4fe77Suwe };
118aae4fe77Suwe 
119cfd1c195Suwe /*
120cfd1c195Suwe  * Decoded PC Card 16 based Card Information Structure (CIS),
121cfd1c195Suwe  * per card (function 0) and per function (1 and greater).
122cfd1c195Suwe  */
123cfd1c195Suwe struct sdmmc_cis {
124cfd1c195Suwe 	u_int16_t	 manufacturer;
125cfd1c195Suwe #define SDMMC_VENDOR_INVALID	0xffff
126cfd1c195Suwe 	u_int16_t	 product;
127cfd1c195Suwe #define SDMMC_PRODUCT_INVALID	0xffff
128cfd1c195Suwe 	u_int8_t	 function;
129cfd1c195Suwe #define SDMMC_FUNCTION_INVALID	0xff
130cfd1c195Suwe 	u_char		 cis1_major;
131cfd1c195Suwe 	u_char		 cis1_minor;
132cfd1c195Suwe 	char		 cis1_info_buf[256];
133cfd1c195Suwe 	char		*cis1_info[4];
134aae4fe77Suwe };
135aae4fe77Suwe 
136cfd1c195Suwe /*
137cfd1c195Suwe  * Structure describing either an SD card I/O function or a SD/MMC
138cfd1c195Suwe  * memory card from a "stack of cards" that responded to CMD2.  For a
139cfd1c195Suwe  * combo card with one I/O function and one memory card, there will be
140cfd1c195Suwe  * two of these structures allocated.  Each card slot has such a list
141cfd1c195Suwe  * of sdmmc_function structures.
142cfd1c195Suwe  */
143cfd1c195Suwe struct sdmmc_function {
144cfd1c195Suwe 	/* common members */
145cfd1c195Suwe 	struct sdmmc_softc *sc;		/* card slot softc */
146cfd1c195Suwe 	u_int16_t rca;			/* relative card address */
147cfd1c195Suwe 	int flags;
148cfd1c195Suwe #define SFF_ERROR		0x0001	/* function is poo; ignore it */
1498323add6Sjsg #define SFF_SDHC		0x0002	/* SD High Capacity card */
15068a1c7f6Spatrick 	void *cookie;			/* pass extra info from bus to dev */
151cfd1c195Suwe 	SIMPLEQ_ENTRY(sdmmc_function) sf_list;
152cfd1c195Suwe 	/* SD card I/O function members */
153cfd1c195Suwe 	int number;			/* I/O function number or -1 */
154cfd1c195Suwe 	struct device *child;		/* function driver */
155cfd1c195Suwe 	struct sdmmc_cis cis;		/* decoded CIS */
156dae1f2dbSpatrick 	unsigned int cur_blklen;	/* current block length */
157cfd1c195Suwe 	/* SD/MMC memory card members */
158cfd1c195Suwe 	struct sdmmc_csd csd;		/* decoded CSD value */
159cfd1c195Suwe 	struct sdmmc_cid cid;		/* decoded CID value */
160cfd1c195Suwe 	sdmmc_response raw_cid;		/* temp. storage for decoding */
161b140af5cSkettenis 	struct sdmmc_scr scr;		/* decoded SCR value */
162cfd1c195Suwe };
163cfd1c195Suwe 
164cfd1c195Suwe /*
165cfd1c195Suwe  * Structure describing a single SD/MMC/SDIO card slot.
166cfd1c195Suwe  */
167aae4fe77Suwe struct sdmmc_softc {
168aae4fe77Suwe 	struct device sc_dev;		/* base device */
169a93f47f6Sjasper #define DEVNAME(sc)	((sc)->sc_dev.dv_xname)
170aae4fe77Suwe 	sdmmc_chipset_tag_t sct;	/* host controller chipset tag */
171aae4fe77Suwe 	sdmmc_chipset_handle_t sch;	/* host controller chipset handle */
172c6293583Skettenis 
173c6293583Skettenis 	bus_dma_tag_t sc_dmat;
174c6293583Skettenis 	bus_dmamap_t sc_dmap;
175c6293583Skettenis #define SDMMC_MAXNSEGS	((MAXPHYS / PAGE_SIZE) + 1)
176c6293583Skettenis 
177aae4fe77Suwe 	int sc_flags;
178aae4fe77Suwe #define SMF_SD_MODE		0x0001	/* host in SD mode (MMC otherwise) */
179cfd1c195Suwe #define SMF_IO_MODE		0x0002	/* host in I/O mode (SD mode only) */
180aae4fe77Suwe #define SMF_MEM_MODE		0x0004	/* host in memory mode (SD or MMC) */
181*a62fc20aSkettenis #define SMF_UHS_MODE		0x0010	/* host in UHS mode */
182*a62fc20aSkettenis #define SMF_CARD_PRESENT	0x0020	/* card presence noticed */
183*a62fc20aSkettenis #define SMF_CARD_ATTACHED	0x0040	/* card driver(s) attached */
184*a62fc20aSkettenis #define SMF_STOP_AFTER_MULTIPLE	0x0080	/* send a stop after a multiple cmd */
185*a62fc20aSkettenis #define SMF_CONFIG_PENDING	0x0100	/* config_pending_incr() called */
18624518680Srapha 
18724518680Srapha 	uint32_t sc_caps;		/* host capability */
18824518680Srapha #define SMC_CAPS_AUTO_STOP	0x0001	/* send CMD12 automagically by host */
18924518680Srapha #define SMC_CAPS_4BIT_MODE	0x0002	/* 4-bits data bus width */
19024518680Srapha #define SMC_CAPS_DMA		0x0004	/* DMA transfer */
19124518680Srapha #define SMC_CAPS_SPI_MODE	0x0008	/* SPI mode */
19224518680Srapha #define SMC_CAPS_POLL_CARD_DET	0x0010	/* Polling card detect */
19324518680Srapha #define SMC_CAPS_SINGLE_ONLY	0x0020	/* only single read/write */
19424518680Srapha #define SMC_CAPS_8BIT_MODE	0x0040	/* 8-bits data bus width */
19524518680Srapha #define SMC_CAPS_MULTI_SEG_DMA	0x0080	/* multiple segment DMA transfer */
19624518680Srapha #define SMC_CAPS_SD_HIGHSPEED	0x0100	/* SD high-speed timing */
19724518680Srapha #define SMC_CAPS_MMC_HIGHSPEED	0x0200	/* MMC high-speed timing */
198820e06f1Skettenis #define SMC_CAPS_UHS_SDR50	0x0400	/* UHS SDR50 timing */
199820e06f1Skettenis #define SMC_CAPS_UHS_SDR104	0x0800	/* UHS SDR104 timing */
200820e06f1Skettenis #define SMC_CAPS_UHS_DDR50	0x1000	/* UHS DDR50 timing */
201820e06f1Skettenis #define SMC_CAPS_UHS_MASK	0x1c00
202820e06f1Skettenis #define SMC_CAPS_MMC_DDR52	0x2000  /* eMMC DDR52 timing */
203820e06f1Skettenis #define SMC_CAPS_MMC_HS200	0x4000	/* eMMC HS200 timing */
204820e06f1Skettenis #define SMC_CAPS_MMC_HS400	0x8000	/* eMMC HS400 timing */
205fd406f4dSstsp #define SMC_CAPS_NONREMOVABLE	0x10000	/* non-removable devices */
20624518680Srapha 
207cfd1c195Suwe 	int sc_function_count;		/* number of I/O functions (SDIO) */
208cfd1c195Suwe 	struct sdmmc_function *sc_card;	/* selected card */
209cfd1c195Suwe 	struct sdmmc_function *sc_fn0;	/* function 0, the card itself */
210a6fd99a7Suwe 	SIMPLEQ_HEAD(, sdmmc_function) sf_head; /* list of card functions */
211a6fd99a7Suwe 	int sc_dying;			/* bus driver is shutting down */
212a6fd99a7Suwe 	struct proc *sc_task_thread;	/* asynchronous tasks */
213a6fd99a7Suwe 	TAILQ_HEAD(, sdmmc_task) sc_tskq;   /* task thread work queue */
214a6fd99a7Suwe 	struct sdmmc_task sc_discover_task; /* card attach/detach task */
215b979651fSuwe 	struct sdmmc_task sc_intr_task;	/* card interrupt task */
2169de6240fSblambert 	struct rwlock sc_lock;		/* lock around host controller */
217a6fd99a7Suwe 	void *sc_scsibus;		/* SCSI bus emulation softc */
218b979651fSuwe 	TAILQ_HEAD(, sdmmc_intr_handler) sc_intrq; /* interrupt handlers */
2192afcf50dSpatrick 	long sc_max_seg;		/* maximum segment size */
22046a44037Smiod 	long sc_max_xfer;		/* maximum transfer size */
22168a1c7f6Spatrick 	void *sc_cookies[SDMMC_MAX_FUNCTIONS]; /* pass extra info from bus to dev */
222cfd1c195Suwe };
223cfd1c195Suwe 
224cfd1c195Suwe /*
225cfd1c195Suwe  * Attach devices at the sdmmc bus.
226cfd1c195Suwe  */
227cfd1c195Suwe struct sdmmc_attach_args {
228185ff997Skrw 	struct scsibus_attach_args	 saa;
229cfd1c195Suwe 	struct sdmmc_function		*sf;
230aae4fe77Suwe };
231aae4fe77Suwe 
232aae4fe77Suwe #define IPL_SDMMC	IPL_BIO
233aae4fe77Suwe #define splsdmmc()	splbio()
234aae4fe77Suwe 
2354f39d9f1Sblambert #define	SDMMC_ASSERT_LOCKED(sc) \
2369de6240fSblambert 	rw_assert_wrlock(&(sc)->sc_lock)
237a6fd99a7Suwe 
238a6fd99a7Suwe void	sdmmc_add_task(struct sdmmc_softc *, struct sdmmc_task *);
239a6fd99a7Suwe void	sdmmc_del_task(struct sdmmc_task *);
240a6fd99a7Suwe 
241cfd1c195Suwe struct	sdmmc_function *sdmmc_function_alloc(struct sdmmc_softc *);
242cfd1c195Suwe void	sdmmc_function_free(struct sdmmc_function *);
243aae4fe77Suwe int	sdmmc_set_bus_power(struct sdmmc_softc *, u_int32_t, u_int32_t);
244aae4fe77Suwe int	sdmmc_mmc_command(struct sdmmc_softc *, struct sdmmc_command *);
245aae4fe77Suwe int	sdmmc_app_command(struct sdmmc_softc *, struct sdmmc_command *);
246aae4fe77Suwe void	sdmmc_go_idle_state(struct sdmmc_softc *);
247cfd1c195Suwe int	sdmmc_select_card(struct sdmmc_softc *, struct sdmmc_function *);
248cfd1c195Suwe int	sdmmc_set_relative_addr(struct sdmmc_softc *,
249cfd1c195Suwe 	    struct sdmmc_function *);
2508323add6Sjsg int	sdmmc_send_if_cond(struct sdmmc_softc *, uint32_t);
251aae4fe77Suwe 
252b979651fSuwe void	sdmmc_intr_enable(struct sdmmc_function *);
253b979651fSuwe void	sdmmc_intr_disable(struct sdmmc_function *);
254b979651fSuwe void	*sdmmc_intr_establish(struct device *, int (*)(void *),
255b979651fSuwe 	    void *, const char *);
256b979651fSuwe void	sdmmc_intr_disestablish(void *);
257b979651fSuwe void	sdmmc_intr_task(void *);
258b979651fSuwe 
259aae4fe77Suwe int	sdmmc_io_enable(struct sdmmc_softc *);
260cfd1c195Suwe void	sdmmc_io_scan(struct sdmmc_softc *);
261cfd1c195Suwe int	sdmmc_io_init(struct sdmmc_softc *, struct sdmmc_function *);
262cfd1c195Suwe void	sdmmc_io_attach(struct sdmmc_softc *);
263cfd1c195Suwe void	sdmmc_io_detach(struct sdmmc_softc *);
264cfd1c195Suwe u_int8_t sdmmc_io_read_1(struct sdmmc_function *, int);
265cfd1c195Suwe u_int16_t sdmmc_io_read_2(struct sdmmc_function *, int);
266cfd1c195Suwe u_int32_t sdmmc_io_read_4(struct sdmmc_function *, int);
26783acf2fcSuwe int	sdmmc_io_read_multi_1(struct sdmmc_function *, int, u_char *, int);
2681f8b50cbSpatrick int	sdmmc_io_read_region_1(struct sdmmc_function *, int, u_char *, int);
269cfd1c195Suwe void	sdmmc_io_write_1(struct sdmmc_function *, int, u_int8_t);
270cfd1c195Suwe void	sdmmc_io_write_2(struct sdmmc_function *, int, u_int16_t);
271cfd1c195Suwe void	sdmmc_io_write_4(struct sdmmc_function *, int, u_int32_t);
27283acf2fcSuwe int	sdmmc_io_write_multi_1(struct sdmmc_function *, int, u_char *, int);
2731f8b50cbSpatrick int	sdmmc_io_write_region_1(struct sdmmc_function *, int, u_char *, int);
27483acf2fcSuwe int	sdmmc_io_function_ready(struct sdmmc_function *);
27583acf2fcSuwe int	sdmmc_io_function_enable(struct sdmmc_function *);
276cfd1c195Suwe void	sdmmc_io_function_disable(struct sdmmc_function *);
277dae1f2dbSpatrick void	sdmmc_io_set_blocklen(struct sdmmc_function *, unsigned int);
278cfd1c195Suwe 
279cfd1c195Suwe int	sdmmc_read_cis(struct sdmmc_function *, struct sdmmc_cis *);
280cfd1c195Suwe void	sdmmc_print_cis(struct sdmmc_function *);
281cfd1c195Suwe void	sdmmc_check_cis_quirks(struct sdmmc_function *);
282aae4fe77Suwe 
283aae4fe77Suwe int	sdmmc_mem_enable(struct sdmmc_softc *);
284cfd1c195Suwe void	sdmmc_mem_scan(struct sdmmc_softc *);
285cfd1c195Suwe int	sdmmc_mem_init(struct sdmmc_softc *, struct sdmmc_function *);
286a6fd99a7Suwe int	sdmmc_mem_read_block(struct sdmmc_function *, int, u_char *, size_t);
287a6fd99a7Suwe int	sdmmc_mem_write_block(struct sdmmc_function *, int, u_char *, size_t);
288aae4fe77Suwe 
289f3036462Sjmatthew #ifdef HIBERNATE
290f3036462Sjmatthew int	sdmmc_mem_hibernate_write(struct sdmmc_function *, daddr_t, u_char *,
291f3036462Sjmatthew 	    size_t);
292f3036462Sjmatthew #endif
293f3036462Sjmatthew 
294f372147dSuwe /* ioctls */
295f372147dSuwe 
296f372147dSuwe #include <sys/ioccom.h>
297f372147dSuwe 
298f372147dSuwe struct bio_sdmmc_command {
299f372147dSuwe 	void *cookie;
300f372147dSuwe 	struct sdmmc_command cmd;
301f372147dSuwe };
302f372147dSuwe 
303f372147dSuwe struct bio_sdmmc_debug {
304f372147dSuwe 	void *cookie;
305f372147dSuwe 	int debug;
306f372147dSuwe };
307f372147dSuwe 
308f372147dSuwe #define SDIOCEXECMMC	_IOWR('S',0, struct bio_sdmmc_command)
309f372147dSuwe #define SDIOCEXECAPP	_IOWR('S',1, struct bio_sdmmc_command)
310f372147dSuwe #define SDIOCSETDEBUG	_IOWR('S',2, struct bio_sdmmc_debug)
311f372147dSuwe 
312aae4fe77Suwe #endif
313