xref: /freebsd-src/sys/dev/rtsx/rtsx.c (revision 3ddaf8200bc90b1410755ebac7b5c979ea90a2f6)
1926ce35aSJung-uk Kim /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3926ce35aSJung-uk Kim  *
4926ce35aSJung-uk Kim  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
5926ce35aSJung-uk Kim  * Copyright (c) 2012 Stefan Sperling <stsp@openbsd.org>
6926ce35aSJung-uk Kim  * Copyright (c) 2020 Henri Hennebert <hlh@restart.be>
7926ce35aSJung-uk Kim  * Copyright (c) 2020 Gary Jennejohn <gj@freebsd.org>
8926ce35aSJung-uk Kim  * Copyright (c) 2020 Jesper Schmitz Mouridsen <jsm@FreeBSD.org>
9926ce35aSJung-uk Kim  * All rights reserved.
10926ce35aSJung-uk Kim  *
11926ce35aSJung-uk Kim  * Patch from:
12926ce35aSJung-uk Kim  * - Lutz Bichler <Lutz.Bichler@gmail.com>
13926ce35aSJung-uk Kim  *
14926ce35aSJung-uk Kim  * Base on OpenBSD /sys/dev/pci/rtsx_pci.c & /dev/ic/rtsx.c
15926ce35aSJung-uk Kim  *      on Linux   /drivers/mmc/host/rtsx_pci_sdmmc.c,
16926ce35aSJung-uk Kim  *                 /include/linux/rtsx_pci.h &
17926ce35aSJung-uk Kim  *                 /drivers/misc/cardreader/rtsx_pcr.c
18926ce35aSJung-uk Kim  *      on NetBSD  /sys/dev/ic/rtsx.c
19926ce35aSJung-uk Kim  *
20926ce35aSJung-uk Kim  * Permission to use, copy, modify, and distribute this software for any
21926ce35aSJung-uk Kim  * purpose with or without fee is hereby granted, provided that the above
22926ce35aSJung-uk Kim  * copyright notice and this permission notice appear in all copies.
23926ce35aSJung-uk Kim  *
24926ce35aSJung-uk Kim  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25926ce35aSJung-uk Kim  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26926ce35aSJung-uk Kim  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27926ce35aSJung-uk Kim  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28926ce35aSJung-uk Kim  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29926ce35aSJung-uk Kim  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30926ce35aSJung-uk Kim  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31926ce35aSJung-uk Kim  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32926ce35aSJung-uk Kim  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33926ce35aSJung-uk Kim  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34926ce35aSJung-uk Kim  * SUCH DAMAGE.
35926ce35aSJung-uk Kim  */
36926ce35aSJung-uk Kim 
37926ce35aSJung-uk Kim #include <sys/param.h>
38926ce35aSJung-uk Kim #include <sys/module.h>
39926ce35aSJung-uk Kim #include <sys/systm.h> /* For FreeBSD 11 */
40926ce35aSJung-uk Kim #include <sys/types.h> /* For FreeBSD 11 */
41926ce35aSJung-uk Kim #include <sys/errno.h>
42926ce35aSJung-uk Kim #include <sys/kernel.h>
43926ce35aSJung-uk Kim #include <sys/bus.h>
44926ce35aSJung-uk Kim #include <sys/endian.h>
45926ce35aSJung-uk Kim #include <machine/bus.h>
46926ce35aSJung-uk Kim #include <sys/mutex.h>
479d3bc163SHenri Hennebert #include <sys/malloc.h>
48926ce35aSJung-uk Kim #include <sys/rman.h>
49926ce35aSJung-uk Kim #include <sys/queue.h>
50926ce35aSJung-uk Kim #include <sys/taskqueue.h>
51926ce35aSJung-uk Kim #include <sys/sysctl.h>
52926ce35aSJung-uk Kim #include <dev/pci/pcivar.h>
53926ce35aSJung-uk Kim #include <dev/pci/pcireg.h>
54926ce35aSJung-uk Kim #include <dev/mmc/bridge.h>
55926ce35aSJung-uk Kim #include <dev/mmc/mmcreg.h>
56926ce35aSJung-uk Kim #include <dev/mmc/mmcbrvar.h>
57926ce35aSJung-uk Kim #include <machine/_inttypes.h>
58926ce35aSJung-uk Kim 
59926ce35aSJung-uk Kim #include "opt_mmccam.h"
60926ce35aSJung-uk Kim 
61926ce35aSJung-uk Kim #ifdef MMCCAM
62926ce35aSJung-uk Kim #include <cam/cam.h>
63926ce35aSJung-uk Kim #include <cam/cam_ccb.h>
64926ce35aSJung-uk Kim #include <cam/cam_debug.h>
65926ce35aSJung-uk Kim #include <cam/cam_sim.h>
66926ce35aSJung-uk Kim #include <cam/cam_xpt_sim.h>
678e9740b6SHenri Hennebert #include <cam/mmc/mmc_sim.h>
688e9740b6SHenri Hennebert #include "mmc_sim_if.h"
69926ce35aSJung-uk Kim #endif /* MMCCAM */
70926ce35aSJung-uk Kim 
71926ce35aSJung-uk Kim #include "rtsxreg.h"
72926ce35aSJung-uk Kim 
73926ce35aSJung-uk Kim /* The softc holds our per-instance data. */
74926ce35aSJung-uk Kim struct rtsx_softc {
75926ce35aSJung-uk Kim 	struct mtx	rtsx_mtx;		/* device mutex */
76926ce35aSJung-uk Kim 	device_t	rtsx_dev;		/* device */
77926ce35aSJung-uk Kim 	uint16_t	rtsx_flags;		/* device flags */
78926ce35aSJung-uk Kim 	uint16_t	rtsx_device_id;		/* device ID */
79926ce35aSJung-uk Kim 	device_t	rtsx_mmc_dev;		/* device of mmc bus */
80926ce35aSJung-uk Kim 	uint32_t	rtsx_intr_enabled;	/* enabled interrupts */
81926ce35aSJung-uk Kim 	uint32_t 	rtsx_intr_status;	/* soft interrupt status */
82926ce35aSJung-uk Kim 	int		rtsx_irq_res_id;	/* bus IRQ resource id */
83926ce35aSJung-uk Kim 	struct resource *rtsx_irq_res;		/* bus IRQ resource */
84926ce35aSJung-uk Kim 	void		*rtsx_irq_cookie;	/* bus IRQ resource cookie */
85926ce35aSJung-uk Kim 	struct callout	rtsx_timeout_callout;	/* callout for timeout */
869d3bc163SHenri Hennebert 	int		rtsx_timeout_cmd;	/* interrupt timeout for setup commands */
879d3bc163SHenri Hennebert 	int		rtsx_timeout_io;	/* interrupt timeout for I/O commands */
88926ce35aSJung-uk Kim 	void		(*rtsx_intr_trans_ok)(struct rtsx_softc *sc);
89926ce35aSJung-uk Kim 						/* function to call if transfer succeed */
90926ce35aSJung-uk Kim 	void		(*rtsx_intr_trans_ko)(struct rtsx_softc *sc);
91926ce35aSJung-uk Kim 						/* function to call if transfer fail */
929d3bc163SHenri Hennebert 
93926ce35aSJung-uk Kim 	struct timeout_task
94926ce35aSJung-uk Kim 			rtsx_card_insert_task;	/* card insert delayed task */
95926ce35aSJung-uk Kim 	struct task	rtsx_card_remove_task;	/* card remove task */
96926ce35aSJung-uk Kim 
972e883067SHenri Hennebert 	int		rtsx_mem_res_id;	/* bus memory resource id */
982e883067SHenri Hennebert 	struct resource *rtsx_mem_res;		/* bus memory resource */
992e883067SHenri Hennebert 	bus_space_tag_t	   rtsx_mem_btag;	/* host register set tag */
1002e883067SHenri Hennebert 	bus_space_handle_t rtsx_mem_bhandle;	/* host register set handle */
101926ce35aSJung-uk Kim 
102926ce35aSJung-uk Kim 	bus_dma_tag_t	rtsx_cmd_dma_tag;	/* DMA tag for command transfer */
103926ce35aSJung-uk Kim 	bus_dmamap_t	rtsx_cmd_dmamap;	/* DMA map for command transfer */
104926ce35aSJung-uk Kim 	void		*rtsx_cmd_dmamem;	/* DMA mem for command transfer */
105926ce35aSJung-uk Kim 	bus_addr_t	rtsx_cmd_buffer;	/* device visible address of the DMA segment */
106926ce35aSJung-uk Kim 	int		rtsx_cmd_index;		/* index in rtsx_cmd_buffer */
107926ce35aSJung-uk Kim 
108926ce35aSJung-uk Kim 	bus_dma_tag_t	rtsx_data_dma_tag;	/* DMA tag for data transfer */
109926ce35aSJung-uk Kim 	bus_dmamap_t	rtsx_data_dmamap;	/* DMA map for data transfer */
110926ce35aSJung-uk Kim 	void		*rtsx_data_dmamem;	/* DMA mem for data transfer */
111926ce35aSJung-uk Kim 	bus_addr_t	rtsx_data_buffer;	/* device visible address of the DMA segment */
112926ce35aSJung-uk Kim 
113926ce35aSJung-uk Kim #ifdef MMCCAM
114926ce35aSJung-uk Kim 	union ccb		*rtsx_ccb;	/* CAM control block */
1158e9740b6SHenri Hennebert 	struct mmc_sim		rtsx_mmc_sim;	/* CAM generic sim */
116926ce35aSJung-uk Kim 	struct mmc_request	rtsx_cam_req;	/* CAM MMC request */
117926ce35aSJung-uk Kim #endif /* MMCCAM */
118926ce35aSJung-uk Kim 
119926ce35aSJung-uk Kim 	struct mmc_request *rtsx_req;		/* MMC request */
120926ce35aSJung-uk Kim 	struct mmc_host rtsx_host;		/* host parameters */
121926ce35aSJung-uk Kim 	int		rtsx_pcie_cap;		/* PCIe capability offset */
122926ce35aSJung-uk Kim 	int8_t		rtsx_bus_busy;		/* bus busy status */
123926ce35aSJung-uk Kim 	int8_t		rtsx_ios_bus_width;	/* current host.ios.bus_width */
124926ce35aSJung-uk Kim 	int32_t		rtsx_ios_clock;		/* current host.ios.clock */
125926ce35aSJung-uk Kim 	int8_t		rtsx_ios_power_mode;	/* current host.ios.power mode */
126926ce35aSJung-uk Kim 	int8_t		rtsx_ios_timing;	/* current host.ios.timing */
127926ce35aSJung-uk Kim 	int8_t		rtsx_ios_vccq;		/* current host.ios.vccq */
128926ce35aSJung-uk Kim 	uint8_t		rtsx_read_only;		/* card read only status */
129926ce35aSJung-uk Kim 	uint8_t		rtsx_inversion;		/* inversion of card detection and read only status */
130926ce35aSJung-uk Kim 	uint8_t		rtsx_force_timing;	/* force bus_timing_uhs_sdr50 */
131577130e5SHenri Hennebert 	uint8_t		rtsx_debug_mask;	/* debugging mask */
132577130e5SHenri Hennebert #define 	RTSX_DEBUG_BASIC	0x01	/* debug basic flow */
133577130e5SHenri Hennebert #define 	RTSX_TRACE_SD_CMD	0x02	/* trace SD commands */
134577130e5SHenri Hennebert #define 	RTSX_DEBUG_TUNING	0x04	/* debug tuning */
135926ce35aSJung-uk Kim #ifdef MMCCAM
136926ce35aSJung-uk Kim 	uint8_t		rtsx_cam_status;	/* CAM status - 1 if card in use */
137926ce35aSJung-uk Kim #endif /* MMCCAM */
138926ce35aSJung-uk Kim 	uint64_t	rtsx_read_count;	/* count of read operations */
139926ce35aSJung-uk Kim 	uint64_t	rtsx_write_count;	/* count of write operations */
140926ce35aSJung-uk Kim 	bool		rtsx_discovery_mode;	/* are we in discovery mode? */
141926ce35aSJung-uk Kim 	bool		rtsx_tuning_mode;	/* are we tuning */
142926ce35aSJung-uk Kim 	bool		rtsx_double_clk;	/* double clock freqency */
143926ce35aSJung-uk Kim 	bool		rtsx_vpclk;		/* voltage at Pulse-width Modulation(PWM) clock? */
144926ce35aSJung-uk Kim 	uint8_t		rtsx_ssc_depth;		/* Spread spectrum clocking depth */
145926ce35aSJung-uk Kim 	uint8_t		rtsx_card_drive_sel;	/* value for RTSX_CARD_DRIVE_SEL */
146926ce35aSJung-uk Kim 	uint8_t		rtsx_sd30_drive_sel_3v3;/* value for RTSX_SD30_DRIVE_SEL */
147926ce35aSJung-uk Kim };
148926ce35aSJung-uk Kim 
149926ce35aSJung-uk Kim /* rtsx_flags values */
150926ce35aSJung-uk Kim #define	RTSX_F_DEFAULT		0x0000
151926ce35aSJung-uk Kim #define	RTSX_F_CARD_PRESENT	0x0001
152926ce35aSJung-uk Kim #define	RTSX_F_SDIO_SUPPORT	0x0002
153926ce35aSJung-uk Kim #define	RTSX_F_VERSION_A	0x0004
154926ce35aSJung-uk Kim #define	RTSX_F_VERSION_B	0x0008
155926ce35aSJung-uk Kim #define	RTSX_F_VERSION_C	0x0010
156926ce35aSJung-uk Kim #define	RTSX_F_VERSION_D	0x0020
157926ce35aSJung-uk Kim #define	RTSX_F_8411B_QFN48	0x0040
158926ce35aSJung-uk Kim #define	RTSX_F_REVERSE_SOCKET	0x0080
159926ce35aSJung-uk Kim 
160926ce35aSJung-uk Kim #define	RTSX_REALTEK		0x10ec
161926ce35aSJung-uk Kim #define	RTSX_RTS5209		0x5209
162926ce35aSJung-uk Kim #define	RTSX_RTS5227		0x5227
163926ce35aSJung-uk Kim #define	RTSX_RTS5229		0x5229
164926ce35aSJung-uk Kim #define	RTSX_RTS522A		0x522a
165926ce35aSJung-uk Kim #define	RTSX_RTS525A		0x525a
166926ce35aSJung-uk Kim #define	RTSX_RTS5249		0x5249
167577130e5SHenri Hennebert #define	RTSX_RTS5260		0x5260
168926ce35aSJung-uk Kim #define	RTSX_RTL8402		0x5286
169926ce35aSJung-uk Kim #define	RTSX_RTL8411		0x5289
170926ce35aSJung-uk Kim #define	RTSX_RTL8411B		0x5287
171926ce35aSJung-uk Kim 
1728290c144SHenri Hennebert #define	RTSX_VERSION		"2.1g"
173926ce35aSJung-uk Kim 
17471883128SHenri Hennebert static const struct rtsx_pciids {
175926ce35aSJung-uk Kim 	uint16_t	device_id;
176926ce35aSJung-uk Kim 	const char	*desc;
17771883128SHenri Hennebert } rtsx_ids[] = {
17871883128SHenri Hennebert 	{ RTSX_RTS5209, RTSX_VERSION " Realtek RTS5209 PCIe SD Card Reader" },
17971883128SHenri Hennebert 	{ RTSX_RTS5227, RTSX_VERSION " Realtek RTS5227 PCIe SD Card Reader" },
18071883128SHenri Hennebert 	{ RTSX_RTS5229, RTSX_VERSION " Realtek RTS5229 PCIe SD Card Reader" },
18171883128SHenri Hennebert 	{ RTSX_RTS522A, RTSX_VERSION " Realtek RTS522A PCIe SD Card Reader" },
18271883128SHenri Hennebert 	{ RTSX_RTS525A, RTSX_VERSION " Realtek RTS525A PCIe SD Card Reader" },
18371883128SHenri Hennebert 	{ RTSX_RTS5249, RTSX_VERSION " Realtek RTS5249 PCIe SD Card Reader" },
18471883128SHenri Hennebert 	{ RTSX_RTS5260, RTSX_VERSION " Realtek RTS5260 PCIe SD Card Reader" },
18571883128SHenri Hennebert 	{ RTSX_RTL8402, RTSX_VERSION " Realtek RTL8402 PCIe SD Card Reader" },
18671883128SHenri Hennebert 	{ RTSX_RTL8411, RTSX_VERSION " Realtek RTL8411 PCIe SD Card Reader" },
18771883128SHenri Hennebert 	{ RTSX_RTL8411B, RTSX_VERSION " Realtek RTL8411B PCIe SD Card Reader" },
188926ce35aSJung-uk Kim };
189926ce35aSJung-uk Kim 
1909d3bc163SHenri Hennebert /* See `kenv | grep smbios.system` */
1919d3bc163SHenri Hennebert static const struct rtsx_inversion_model {
1929d3bc163SHenri Hennebert 	char	*maker;
1939d3bc163SHenri Hennebert 	char	*family;
1949d3bc163SHenri Hennebert 	char	*product;
1959d3bc163SHenri Hennebert } rtsx_inversion_models[] = {
1969d3bc163SHenri Hennebert 	{ "LENOVO",		"ThinkPad T470p",	"20J7S0PM00"},
19771883128SHenri Hennebert 	{ "LENOVO",		"ThinkPad X13 Gen 1",	"20UF000QRT"},
1989d3bc163SHenri Hennebert 	{ NULL,			NULL,			NULL}
1999d3bc163SHenri Hennebert };
2009d3bc163SHenri Hennebert 
201926ce35aSJung-uk Kim static int	rtsx_dma_alloc(struct rtsx_softc *sc);
202926ce35aSJung-uk Kim static void	rtsx_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
203926ce35aSJung-uk Kim static void	rtsx_dma_free(struct rtsx_softc *sc);
204926ce35aSJung-uk Kim static void	rtsx_intr(void *arg);
205926ce35aSJung-uk Kim static void	rtsx_handle_card_present(struct rtsx_softc *sc);
206926ce35aSJung-uk Kim static void	rtsx_card_task(void *arg, int pending __unused);
207926ce35aSJung-uk Kim static bool	rtsx_is_card_present(struct rtsx_softc *sc);
208926ce35aSJung-uk Kim static int	rtsx_init(struct rtsx_softc *sc);
209926ce35aSJung-uk Kim static int	rtsx_map_sd_drive(int index);
210926ce35aSJung-uk Kim static int	rtsx_rts5227_fill_driving(struct rtsx_softc *sc);
211926ce35aSJung-uk Kim static int	rtsx_rts5249_fill_driving(struct rtsx_softc *sc);
212577130e5SHenri Hennebert static int	rtsx_rts5260_fill_driving(struct rtsx_softc *sc);
213926ce35aSJung-uk Kim static int	rtsx_read(struct rtsx_softc *, uint16_t, uint8_t *);
214926ce35aSJung-uk Kim static int	rtsx_read_cfg(struct rtsx_softc *sc, uint8_t func, uint16_t addr, uint32_t *val);
215926ce35aSJung-uk Kim static int	rtsx_write(struct rtsx_softc *sc, uint16_t addr, uint8_t mask, uint8_t val);
216926ce35aSJung-uk Kim static int	rtsx_read_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t *val);
217926ce35aSJung-uk Kim static int	rtsx_write_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t val);
218926ce35aSJung-uk Kim static int	rtsx_bus_power_off(struct rtsx_softc *sc);
219926ce35aSJung-uk Kim static int	rtsx_bus_power_on(struct rtsx_softc *sc);
220926ce35aSJung-uk Kim static int	rtsx_set_bus_width(struct rtsx_softc *sc, enum mmc_bus_width width);
221926ce35aSJung-uk Kim static int	rtsx_set_sd_timing(struct rtsx_softc *sc, enum mmc_bus_timing timing);
222926ce35aSJung-uk Kim static int	rtsx_set_sd_clock(struct rtsx_softc *sc, uint32_t freq);
223926ce35aSJung-uk Kim static int	rtsx_stop_sd_clock(struct rtsx_softc *sc);
224926ce35aSJung-uk Kim static int	rtsx_switch_sd_clock(struct rtsx_softc *sc, uint8_t clk, uint8_t n, uint8_t div, uint8_t mcu);
2258e9740b6SHenri Hennebert #ifndef MMCCAM
226926ce35aSJung-uk Kim static void	rtsx_sd_change_tx_phase(struct rtsx_softc *sc, uint8_t sample_point);
227926ce35aSJung-uk Kim static void	rtsx_sd_change_rx_phase(struct rtsx_softc *sc, uint8_t sample_point);
228926ce35aSJung-uk Kim static void	rtsx_sd_tuning_rx_phase(struct rtsx_softc *sc, uint32_t *phase_map);
229926ce35aSJung-uk Kim static int	rtsx_sd_tuning_rx_cmd(struct rtsx_softc *sc, uint8_t sample_point);
230926ce35aSJung-uk Kim static int	rtsx_sd_tuning_rx_cmd_wait(struct rtsx_softc *sc, struct mmc_command *cmd);
231926ce35aSJung-uk Kim static void	rtsx_sd_tuning_rx_cmd_wakeup(struct rtsx_softc *sc);
232926ce35aSJung-uk Kim static void	rtsx_sd_wait_data_idle(struct rtsx_softc *sc);
233926ce35aSJung-uk Kim static uint8_t	rtsx_sd_search_final_rx_phase(struct rtsx_softc *sc, uint32_t phase_map);
234926ce35aSJung-uk Kim static int	rtsx_sd_get_rx_phase_len(uint32_t phase_map, int start_bit);
2358e9740b6SHenri Hennebert #endif /* !MMCCAM */
236926ce35aSJung-uk Kim #if 0	/* For led */
237926ce35aSJung-uk Kim static int	rtsx_led_enable(struct rtsx_softc *sc);
238926ce35aSJung-uk Kim static int	rtsx_led_disable(struct rtsx_softc *sc);
239926ce35aSJung-uk Kim #endif	/* For led */
240926ce35aSJung-uk Kim static uint8_t	rtsx_response_type(uint16_t mmc_rsp);
241926ce35aSJung-uk Kim static void	rtsx_init_cmd(struct rtsx_softc *sc, struct mmc_command *cmd);
242926ce35aSJung-uk Kim static void	rtsx_push_cmd(struct rtsx_softc *sc, uint8_t cmd, uint16_t reg,
243926ce35aSJung-uk Kim 			      uint8_t mask, uint8_t data);
244926ce35aSJung-uk Kim static void	rtsx_set_cmd_data_len(struct rtsx_softc *sc, uint16_t block_cnt, uint16_t byte_cnt);
245926ce35aSJung-uk Kim static void	rtsx_send_cmd(struct rtsx_softc *sc);
246926ce35aSJung-uk Kim static void	rtsx_ret_resp(struct rtsx_softc *sc);
247926ce35aSJung-uk Kim static void	rtsx_set_resp(struct rtsx_softc *sc, struct mmc_command *cmd);
248926ce35aSJung-uk Kim static void	rtsx_stop_cmd(struct rtsx_softc *sc);
249926ce35aSJung-uk Kim static void	rtsx_clear_error(struct rtsx_softc *sc);
250926ce35aSJung-uk Kim static void	rtsx_req_done(struct rtsx_softc *sc);
251926ce35aSJung-uk Kim static int	rtsx_send_req(struct rtsx_softc *sc, struct mmc_command *cmd);
252926ce35aSJung-uk Kim static int	rtsx_xfer_short(struct rtsx_softc *sc, struct mmc_command *cmd);
253926ce35aSJung-uk Kim static void	rtsx_ask_ppbuf_part1(struct rtsx_softc *sc);
254926ce35aSJung-uk Kim static void	rtsx_get_ppbuf_part1(struct rtsx_softc *sc);
255926ce35aSJung-uk Kim static void	rtsx_get_ppbuf_part2(struct rtsx_softc *sc);
256926ce35aSJung-uk Kim static void	rtsx_put_ppbuf_part1(struct rtsx_softc *sc);
257926ce35aSJung-uk Kim static void	rtsx_put_ppbuf_part2(struct rtsx_softc *sc);
258926ce35aSJung-uk Kim static void	rtsx_write_ppbuf(struct rtsx_softc *sc);
259926ce35aSJung-uk Kim static int	rtsx_xfer(struct rtsx_softc *sc, struct mmc_command *cmd);
260926ce35aSJung-uk Kim static void	rtsx_xfer_begin(struct rtsx_softc *sc);
261926ce35aSJung-uk Kim static void	rtsx_xfer_start(struct rtsx_softc *sc);
262926ce35aSJung-uk Kim static void	rtsx_xfer_finish(struct rtsx_softc *sc);
263926ce35aSJung-uk Kim static void	rtsx_timeout(void *arg);
264926ce35aSJung-uk Kim 
265926ce35aSJung-uk Kim #ifdef MMCCAM
2668e9740b6SHenri Hennebert static int	rtsx_get_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts);
2678e9740b6SHenri Hennebert static int	rtsx_set_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts);
2688e9740b6SHenri Hennebert static int	rtsx_cam_request(device_t dev, union ccb *ccb);
269926ce35aSJung-uk Kim #endif /* MMCCAM */
270926ce35aSJung-uk Kim 
271926ce35aSJung-uk Kim static int	rtsx_read_ivar(device_t bus, device_t child, int which, uintptr_t *result);
272926ce35aSJung-uk Kim static int	rtsx_write_ivar(device_t bus, device_t child, int which, uintptr_t value);
273926ce35aSJung-uk Kim 
274926ce35aSJung-uk Kim static int	rtsx_mmcbr_update_ios(device_t bus, device_t child __unused);
275926ce35aSJung-uk Kim static int	rtsx_mmcbr_switch_vccq(device_t bus, device_t child __unused);
2768e9740b6SHenri Hennebert static int	rtsx_mmcbr_request(device_t bus, device_t child __unused, struct mmc_request *req);
2778e9740b6SHenri Hennebert #ifndef MMCCAM
278926ce35aSJung-uk Kim static int	rtsx_mmcbr_tune(device_t bus, device_t child __unused, bool hs400 __unused);
279926ce35aSJung-uk Kim static int	rtsx_mmcbr_retune(device_t bus, device_t child __unused, bool reset __unused);
280926ce35aSJung-uk Kim static int	rtsx_mmcbr_get_ro(device_t bus, device_t child __unused);
281926ce35aSJung-uk Kim static int	rtsx_mmcbr_acquire_host(device_t bus, device_t child __unused);
282926ce35aSJung-uk Kim static int	rtsx_mmcbr_release_host(device_t bus, device_t child __unused);
2838e9740b6SHenri Hennebert #endif /* !MMCCAM */
284926ce35aSJung-uk Kim 
285926ce35aSJung-uk Kim static int	rtsx_probe(device_t dev);
286926ce35aSJung-uk Kim static int	rtsx_attach(device_t dev);
287926ce35aSJung-uk Kim static int	rtsx_detach(device_t dev);
288926ce35aSJung-uk Kim static int	rtsx_shutdown(device_t dev);
289926ce35aSJung-uk Kim static int	rtsx_suspend(device_t dev);
290926ce35aSJung-uk Kim static int	rtsx_resume(device_t dev);
291926ce35aSJung-uk Kim 
292926ce35aSJung-uk Kim #define	RTSX_LOCK_INIT(_sc)	mtx_init(&(_sc)->rtsx_mtx,	\
293926ce35aSJung-uk Kim 					 device_get_nameunit(sc->rtsx_dev), "rtsx", MTX_DEF)
294926ce35aSJung-uk Kim #define	RTSX_LOCK(_sc)		mtx_lock(&(_sc)->rtsx_mtx)
295926ce35aSJung-uk Kim #define	RTSX_UNLOCK(_sc)	mtx_unlock(&(_sc)->rtsx_mtx)
296926ce35aSJung-uk Kim #define	RTSX_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->rtsx_mtx)
297926ce35aSJung-uk Kim 
298926ce35aSJung-uk Kim #define	RTSX_SDCLK_OFF			0
299926ce35aSJung-uk Kim #define	RTSX_SDCLK_250KHZ	   250000
300926ce35aSJung-uk Kim #define	RTSX_SDCLK_400KHZ	   400000
301926ce35aSJung-uk Kim #define	RTSX_SDCLK_25MHZ	 25000000
302926ce35aSJung-uk Kim #define	RTSX_SDCLK_50MHZ	 50000000
303926ce35aSJung-uk Kim #define	RTSX_SDCLK_100MHZ	100000000
304926ce35aSJung-uk Kim #define	RTSX_SDCLK_208MHZ	208000000
305926ce35aSJung-uk Kim 
306926ce35aSJung-uk Kim #define	RTSX_MIN_DIV_N		80
307926ce35aSJung-uk Kim #define	RTSX_MAX_DIV_N		208
308926ce35aSJung-uk Kim 
309926ce35aSJung-uk Kim #define	RTSX_MAX_DATA_BLKLEN	512
310926ce35aSJung-uk Kim 
311926ce35aSJung-uk Kim #define	RTSX_DMA_ALIGN		4
312926ce35aSJung-uk Kim #define	RTSX_HOSTCMD_MAX	256
313926ce35aSJung-uk Kim #define	RTSX_DMA_CMD_BIFSIZE	(sizeof(uint32_t) * RTSX_HOSTCMD_MAX)
31413a5a46cSAndrew Gallatin #define	RTSX_DMA_DATA_BUFSIZE	maxphys
315926ce35aSJung-uk Kim 
316926ce35aSJung-uk Kim #define	ISSET(t, f) ((t) & (f))
317926ce35aSJung-uk Kim 
318926ce35aSJung-uk Kim #define	READ4(sc, reg)						\
3192e883067SHenri Hennebert 	(bus_space_read_4((sc)->rtsx_mem_btag, (sc)->rtsx_mem_bhandle, (reg)))
320926ce35aSJung-uk Kim #define	WRITE4(sc, reg, val)					\
3212e883067SHenri Hennebert 	(bus_space_write_4((sc)->rtsx_mem_btag, (sc)->rtsx_mem_bhandle, (reg), (val)))
322926ce35aSJung-uk Kim 
323926ce35aSJung-uk Kim #define	RTSX_READ(sc, reg, val) 				\
324926ce35aSJung-uk Kim 	do { 							\
325926ce35aSJung-uk Kim 		int err = rtsx_read((sc), (reg), (val)); 	\
326926ce35aSJung-uk Kim 		if (err) 					\
327926ce35aSJung-uk Kim 			return (err);				\
328926ce35aSJung-uk Kim 	} while (0)
329926ce35aSJung-uk Kim 
330926ce35aSJung-uk Kim #define	RTSX_WRITE(sc, reg, val) 				\
331926ce35aSJung-uk Kim 	do { 							\
332926ce35aSJung-uk Kim 		int err = rtsx_write((sc), (reg), 0xff, (val));	\
333926ce35aSJung-uk Kim 		if (err) 					\
334926ce35aSJung-uk Kim 			return (err);				\
335926ce35aSJung-uk Kim 	} while (0)
336926ce35aSJung-uk Kim #define	RTSX_CLR(sc, reg, bits)					\
337926ce35aSJung-uk Kim 	do { 							\
338926ce35aSJung-uk Kim 		int err = rtsx_write((sc), (reg), (bits), 0); 	\
339926ce35aSJung-uk Kim 		if (err) 					\
340926ce35aSJung-uk Kim 			return (err);				\
341926ce35aSJung-uk Kim 	} while (0)
342926ce35aSJung-uk Kim 
343926ce35aSJung-uk Kim #define	RTSX_SET(sc, reg, bits)					\
344926ce35aSJung-uk Kim 	do { 							\
345926ce35aSJung-uk Kim 		int err = rtsx_write((sc), (reg), (bits), 0xff);\
346926ce35aSJung-uk Kim 		if (err) 					\
347926ce35aSJung-uk Kim 			return (err);				\
348926ce35aSJung-uk Kim 	} while (0)
349926ce35aSJung-uk Kim 
350926ce35aSJung-uk Kim #define	RTSX_BITOP(sc, reg, mask, bits)				\
351926ce35aSJung-uk Kim 	do {							\
352926ce35aSJung-uk Kim 		int err = rtsx_write((sc), (reg), (mask), (bits));	\
353926ce35aSJung-uk Kim 		if (err)					\
354926ce35aSJung-uk Kim 			return (err);				\
355926ce35aSJung-uk Kim 	} while (0)
356926ce35aSJung-uk Kim 
357926ce35aSJung-uk Kim /*
358926ce35aSJung-uk Kim  * We use two DMA buffers: a command buffer and a data buffer.
359926ce35aSJung-uk Kim  *
360926ce35aSJung-uk Kim  * The command buffer contains a command queue for the host controller,
361926ce35aSJung-uk Kim  * which describes SD/MMC commands to run, and other parameters. The chip
362926ce35aSJung-uk Kim  * runs the command queue when a special bit in the RTSX_HCBAR register is
363926ce35aSJung-uk Kim  * set and signals completion with the RTSX_TRANS_OK_INT interrupt.
364926ce35aSJung-uk Kim  * Each command is encoded as a 4 byte sequence containing command number
365926ce35aSJung-uk Kim  * (read, write, or check a host controller register), a register address,
366926ce35aSJung-uk Kim  * and a data bit-mask and value.
367926ce35aSJung-uk Kim  * SD/MMC commands which do not transfer any data from/to the card only use
368926ce35aSJung-uk Kim  * the command buffer.
369926ce35aSJung-uk Kim  *
370926ce35aSJung-uk Kim  * The data buffer is used for transfer longer than 512. Data transfer is
371926ce35aSJung-uk Kim  * controlled via the RTSX_HDBAR register and completion is signalled by
372926ce35aSJung-uk Kim  * the RTSX_TRANS_OK_INT interrupt.
373926ce35aSJung-uk Kim  *
374926ce35aSJung-uk Kim  * The chip is unable to perform DMA above 4GB.
375926ce35aSJung-uk Kim  */
376926ce35aSJung-uk Kim 
377926ce35aSJung-uk Kim /*
378926ce35aSJung-uk Kim  * Main commands in the usual seqence used:
379926ce35aSJung-uk Kim  *
380926ce35aSJung-uk Kim  * CMD0		Go idle state
381926ce35aSJung-uk Kim  * CMD8		Send interface condition
382926ce35aSJung-uk Kim  * CMD55	Application Command for next ACMD
383926ce35aSJung-uk Kim  * ACMD41	Send Operation Conditions Register (OCR: voltage profile of the card)
384926ce35aSJung-uk Kim  * CMD2		Send Card Identification (CID) Register
385926ce35aSJung-uk Kim  * CMD3		Send relative address
386926ce35aSJung-uk Kim  * CMD9		Send Card Specific Data (CSD)
387926ce35aSJung-uk Kim  * CMD13	Send status (32 bits -  bit 25: card password protected)
388926ce35aSJung-uk Kim  * CMD7		Select card (before Get card SCR)
389926ce35aSJung-uk Kim  * ACMD51	Send SCR (SD CARD Configuration Register - [51:48]: Bus widths supported)
390926ce35aSJung-uk Kim  * CMD6		SD switch function
391926ce35aSJung-uk Kim  * ACMD13	Send SD status (512 bits)
392926ce35aSJung-uk Kim  * ACMD42	Set/Clear card detect
393926ce35aSJung-uk Kim  * ACMD6	Set bus width
394926ce35aSJung-uk Kim  * CMD19	Send tuning block
395926ce35aSJung-uk Kim  * CMD12	Stop transmission
396926ce35aSJung-uk Kim  *
397926ce35aSJung-uk Kim  * CMD17	Read single block (<=512)
398926ce35aSJung-uk Kim  * CMD18	Read multiple blocks (>512)
399926ce35aSJung-uk Kim  * CMD24	Write single block (<=512)
400926ce35aSJung-uk Kim  * CMD25	Write multiple blocks (>512)
401926ce35aSJung-uk Kim  *
402926ce35aSJung-uk Kim  * CMD52	IO R/W direct
403926ce35aSJung-uk Kim  * CMD5		Send Operation Conditions
404926ce35aSJung-uk Kim  */
405926ce35aSJung-uk Kim 
406926ce35aSJung-uk Kim static int
407926ce35aSJung-uk Kim rtsx_dma_alloc(struct rtsx_softc *sc)
408926ce35aSJung-uk Kim {
409926ce35aSJung-uk Kim 	int	error = 0;
410926ce35aSJung-uk Kim 
411926ce35aSJung-uk Kim 	error = bus_dma_tag_create(bus_get_dma_tag(sc->rtsx_dev), /* inherit from parent */
412926ce35aSJung-uk Kim 	    RTSX_DMA_ALIGN, 0,		/* alignment, boundary */
413926ce35aSJung-uk Kim 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
414926ce35aSJung-uk Kim 	    BUS_SPACE_MAXADDR,		/* highaddr */
415926ce35aSJung-uk Kim 	    NULL, NULL,			/* filter, filterarg */
416926ce35aSJung-uk Kim 	    RTSX_DMA_CMD_BIFSIZE, 1,	/* maxsize, nsegments */
417926ce35aSJung-uk Kim 	    RTSX_DMA_CMD_BIFSIZE,	/* maxsegsize */
418926ce35aSJung-uk Kim 	    0,				/* flags */
419926ce35aSJung-uk Kim 	    NULL, NULL,			/* lockfunc, lockarg */
420926ce35aSJung-uk Kim 	    &sc->rtsx_cmd_dma_tag);
421926ce35aSJung-uk Kim 	if (error) {
422926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
423926ce35aSJung-uk Kim 			      "Can't create cmd parent DMA tag\n");
424926ce35aSJung-uk Kim 		return (error);
425926ce35aSJung-uk Kim 	}
426926ce35aSJung-uk Kim 	error = bus_dmamem_alloc(sc->rtsx_cmd_dma_tag,		/* DMA tag */
427926ce35aSJung-uk Kim 	    &sc->rtsx_cmd_dmamem,				/* will hold the KVA pointer */
428926ce35aSJung-uk Kim 	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,	/* flags */
429926ce35aSJung-uk Kim 	    &sc->rtsx_cmd_dmamap); 				/* DMA map */
430926ce35aSJung-uk Kim 	if (error) {
431926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
432926ce35aSJung-uk Kim 			      "Can't create DMA map for command transfer\n");
433926ce35aSJung-uk Kim 		goto destroy_cmd_dma_tag;
434926ce35aSJung-uk Kim 
435926ce35aSJung-uk Kim 	}
436926ce35aSJung-uk Kim 	error = bus_dmamap_load(sc->rtsx_cmd_dma_tag,	/* DMA tag */
437926ce35aSJung-uk Kim 	    sc->rtsx_cmd_dmamap,	/* DMA map */
438926ce35aSJung-uk Kim 	    sc->rtsx_cmd_dmamem,	/* KVA pointer to be mapped */
439926ce35aSJung-uk Kim 	    RTSX_DMA_CMD_BIFSIZE,	/* size of buffer */
440926ce35aSJung-uk Kim 	    rtsx_dmamap_cb,		/* callback */
441926ce35aSJung-uk Kim 	    &sc->rtsx_cmd_buffer,	/* first arg of callback */
442926ce35aSJung-uk Kim 	    0);				/* flags */
443926ce35aSJung-uk Kim 	if (error || sc->rtsx_cmd_buffer == 0) {
444926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
445926ce35aSJung-uk Kim 			      "Can't load DMA memory for command transfer\n");
446926ce35aSJung-uk Kim 		error = (error) ? error : EFAULT;
447926ce35aSJung-uk Kim 		goto destroy_cmd_dmamem_alloc;
448926ce35aSJung-uk Kim 	}
449926ce35aSJung-uk Kim 
450926ce35aSJung-uk Kim 	error = bus_dma_tag_create(bus_get_dma_tag(sc->rtsx_dev),	/* inherit from parent */
451926ce35aSJung-uk Kim 	    RTSX_DMA_DATA_BUFSIZE, 0,	/* alignment, boundary */
452926ce35aSJung-uk Kim 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
453926ce35aSJung-uk Kim 	    BUS_SPACE_MAXADDR,		/* highaddr */
454926ce35aSJung-uk Kim 	    NULL, NULL,			/* filter, filterarg */
455926ce35aSJung-uk Kim 	    RTSX_DMA_DATA_BUFSIZE, 1,	/* maxsize, nsegments */
456926ce35aSJung-uk Kim 	    RTSX_DMA_DATA_BUFSIZE,	/* maxsegsize */
457926ce35aSJung-uk Kim 	    0,				/* flags */
458926ce35aSJung-uk Kim 	    NULL, NULL,			/* lockfunc, lockarg */
459926ce35aSJung-uk Kim 	    &sc->rtsx_data_dma_tag);
460926ce35aSJung-uk Kim 	if (error) {
461926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
462926ce35aSJung-uk Kim 			      "Can't create data parent DMA tag\n");
463926ce35aSJung-uk Kim 		goto destroy_cmd_dmamap_load;
464926ce35aSJung-uk Kim 	}
465926ce35aSJung-uk Kim 	error = bus_dmamem_alloc(sc->rtsx_data_dma_tag,		/* DMA tag */
466926ce35aSJung-uk Kim 	    &sc->rtsx_data_dmamem,				/* will hold the KVA pointer */
467926ce35aSJung-uk Kim 	    BUS_DMA_WAITOK | BUS_DMA_ZERO,			/* flags */
468926ce35aSJung-uk Kim 	    &sc->rtsx_data_dmamap); 				/* DMA map */
469926ce35aSJung-uk Kim 	if (error) {
470926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
471926ce35aSJung-uk Kim 			      "Can't create DMA map for data transfer\n");
472926ce35aSJung-uk Kim 		goto destroy_data_dma_tag;
473926ce35aSJung-uk Kim 	}
474926ce35aSJung-uk Kim 	error = bus_dmamap_load(sc->rtsx_data_dma_tag,	/* DMA tag */
475926ce35aSJung-uk Kim 	    sc->rtsx_data_dmamap,	/* DMA map */
476926ce35aSJung-uk Kim 	    sc->rtsx_data_dmamem,	/* KVA pointer to be mapped */
477926ce35aSJung-uk Kim 	    RTSX_DMA_DATA_BUFSIZE,	/* size of buffer */
478926ce35aSJung-uk Kim 	    rtsx_dmamap_cb,		/* callback */
479926ce35aSJung-uk Kim 	    &sc->rtsx_data_buffer,	/* first arg of callback */
480926ce35aSJung-uk Kim 	    0);				/* flags */
481926ce35aSJung-uk Kim 	if (error || sc->rtsx_data_buffer == 0) {
482926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
483926ce35aSJung-uk Kim 			      "Can't load DMA memory for data transfer\n");
484926ce35aSJung-uk Kim 		error = (error) ? error : EFAULT;
485926ce35aSJung-uk Kim 		goto destroy_data_dmamem_alloc;
486926ce35aSJung-uk Kim 	}
487926ce35aSJung-uk Kim 	return (error);
488926ce35aSJung-uk Kim 
489926ce35aSJung-uk Kim  destroy_data_dmamem_alloc:
490926ce35aSJung-uk Kim 	bus_dmamem_free(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamem, sc->rtsx_data_dmamap);
491926ce35aSJung-uk Kim  destroy_data_dma_tag:
492926ce35aSJung-uk Kim 	bus_dma_tag_destroy(sc->rtsx_data_dma_tag);
493926ce35aSJung-uk Kim  destroy_cmd_dmamap_load:
494926ce35aSJung-uk Kim 	bus_dmamap_unload(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap);
495926ce35aSJung-uk Kim  destroy_cmd_dmamem_alloc:
496926ce35aSJung-uk Kim 	bus_dmamem_free(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamem, sc->rtsx_cmd_dmamap);
497926ce35aSJung-uk Kim  destroy_cmd_dma_tag:
498926ce35aSJung-uk Kim 	bus_dma_tag_destroy(sc->rtsx_cmd_dma_tag);
499926ce35aSJung-uk Kim 
500926ce35aSJung-uk Kim 	return (error);
501926ce35aSJung-uk Kim }
502926ce35aSJung-uk Kim 
503926ce35aSJung-uk Kim static void
504926ce35aSJung-uk Kim rtsx_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
505926ce35aSJung-uk Kim {
506926ce35aSJung-uk Kim 	if (error) {
507926ce35aSJung-uk Kim 		printf("rtsx_dmamap_cb: error %d\n", error);
508926ce35aSJung-uk Kim 		return;
509926ce35aSJung-uk Kim 	}
510926ce35aSJung-uk Kim 	*(bus_addr_t *)arg = segs[0].ds_addr;
511926ce35aSJung-uk Kim }
512926ce35aSJung-uk Kim 
513926ce35aSJung-uk Kim static void
514926ce35aSJung-uk Kim rtsx_dma_free(struct rtsx_softc *sc)
515926ce35aSJung-uk Kim {
516926ce35aSJung-uk Kim 	if (sc->rtsx_cmd_dma_tag != NULL) {
517926ce35aSJung-uk Kim 		if (sc->rtsx_cmd_dmamap != NULL)
518926ce35aSJung-uk Kim 			bus_dmamap_unload(sc->rtsx_cmd_dma_tag,
519926ce35aSJung-uk Kim 					  sc->rtsx_cmd_dmamap);
520926ce35aSJung-uk Kim 		if (sc->rtsx_cmd_dmamem != NULL)
521926ce35aSJung-uk Kim 			bus_dmamem_free(sc->rtsx_cmd_dma_tag,
522926ce35aSJung-uk Kim 					sc->rtsx_cmd_dmamem,
523926ce35aSJung-uk Kim 					sc->rtsx_cmd_dmamap);
524926ce35aSJung-uk Kim 		sc->rtsx_cmd_dmamap = NULL;
525926ce35aSJung-uk Kim 		sc->rtsx_cmd_dmamem = NULL;
526926ce35aSJung-uk Kim 		sc->rtsx_cmd_buffer = 0;
527926ce35aSJung-uk Kim 		bus_dma_tag_destroy(sc->rtsx_cmd_dma_tag);
528926ce35aSJung-uk Kim 		sc->rtsx_cmd_dma_tag = NULL;
529926ce35aSJung-uk Kim 	}
530926ce35aSJung-uk Kim 	if (sc->rtsx_data_dma_tag != NULL) {
531926ce35aSJung-uk Kim 		if (sc->rtsx_data_dmamap != NULL)
532926ce35aSJung-uk Kim 			bus_dmamap_unload(sc->rtsx_data_dma_tag,
533926ce35aSJung-uk Kim 					  sc->rtsx_data_dmamap);
534926ce35aSJung-uk Kim 		if (sc->rtsx_data_dmamem != NULL)
535926ce35aSJung-uk Kim 			bus_dmamem_free(sc->rtsx_data_dma_tag,
536926ce35aSJung-uk Kim 					sc->rtsx_data_dmamem,
537926ce35aSJung-uk Kim 					sc->rtsx_data_dmamap);
538926ce35aSJung-uk Kim 		sc->rtsx_data_dmamap = NULL;
539926ce35aSJung-uk Kim 		sc->rtsx_data_dmamem = NULL;
540926ce35aSJung-uk Kim 		sc->rtsx_data_buffer = 0;
541926ce35aSJung-uk Kim 		bus_dma_tag_destroy(sc->rtsx_data_dma_tag);
542926ce35aSJung-uk Kim 		sc->rtsx_data_dma_tag = NULL;
543926ce35aSJung-uk Kim 	}
544926ce35aSJung-uk Kim }
545926ce35aSJung-uk Kim 
546926ce35aSJung-uk Kim static void
547926ce35aSJung-uk Kim rtsx_intr(void *arg)
548926ce35aSJung-uk Kim {
549926ce35aSJung-uk Kim 	struct rtsx_softc *sc = arg;
550926ce35aSJung-uk Kim 	uint32_t	enabled;
551926ce35aSJung-uk Kim 	uint32_t	status;
552926ce35aSJung-uk Kim 
553926ce35aSJung-uk Kim 	RTSX_LOCK(sc);
554926ce35aSJung-uk Kim 
555926ce35aSJung-uk Kim 	enabled = sc->rtsx_intr_enabled;
556926ce35aSJung-uk Kim 	status = READ4(sc, RTSX_BIPR);	/* read Bus Interrupt Pending Register */
557926ce35aSJung-uk Kim 	sc->rtsx_intr_status = status;
558926ce35aSJung-uk Kim 
559577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
560926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Interrupt handler - enabled: 0x%08x, status: 0x%08x\n", enabled, status);
561926ce35aSJung-uk Kim 
562926ce35aSJung-uk Kim 	/* Ack interrupts. */
563926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_BIPR, status);
564926ce35aSJung-uk Kim 
565926ce35aSJung-uk Kim 	if (((enabled & status) == 0) || status == 0xffffffff) {
566926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Spurious interrupt - enabled: 0x%08x, status: 0x%08x\n", enabled, status);
567926ce35aSJung-uk Kim 		RTSX_UNLOCK(sc);
568926ce35aSJung-uk Kim 		return;
569926ce35aSJung-uk Kim 	}
570926ce35aSJung-uk Kim 
571926ce35aSJung-uk Kim 	/* Detect write protect. */
572926ce35aSJung-uk Kim 	if (status & RTSX_SD_WRITE_PROTECT)
573926ce35aSJung-uk Kim 		sc->rtsx_read_only = 1;
574926ce35aSJung-uk Kim 	else
575926ce35aSJung-uk Kim 		sc->rtsx_read_only = 0;
576926ce35aSJung-uk Kim 
577926ce35aSJung-uk Kim 	/* Start task to handle SD card status change (from dwmmc.c). */
578926ce35aSJung-uk Kim 	if (status & RTSX_SD_INT) {
579926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Interrupt card inserted/removed\n");
580926ce35aSJung-uk Kim 		rtsx_handle_card_present(sc);
581926ce35aSJung-uk Kim 	}
582926ce35aSJung-uk Kim 
583926ce35aSJung-uk Kim 	if (sc->rtsx_req == NULL) {
584926ce35aSJung-uk Kim 		RTSX_UNLOCK(sc);
585926ce35aSJung-uk Kim 		return;
586926ce35aSJung-uk Kim 	}
587926ce35aSJung-uk Kim 
588926ce35aSJung-uk Kim 	if (status & RTSX_TRANS_OK_INT) {
589926ce35aSJung-uk Kim 		sc->rtsx_req->cmd->error = MMC_ERR_NONE;
590926ce35aSJung-uk Kim 		if (sc->rtsx_intr_trans_ok != NULL)
591926ce35aSJung-uk Kim 			sc->rtsx_intr_trans_ok(sc);
592926ce35aSJung-uk Kim 	} else if (status & RTSX_TRANS_FAIL_INT) {
593926ce35aSJung-uk Kim 		uint8_t stat1;
594926ce35aSJung-uk Kim 		sc->rtsx_req->cmd->error = MMC_ERR_FAILED;
595926ce35aSJung-uk Kim 		if (rtsx_read(sc, RTSX_SD_STAT1, &stat1) == 0 &&
596926ce35aSJung-uk Kim 		    (stat1 & RTSX_SD_CRC_ERR)) {
597926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "CRC error\n");
598926ce35aSJung-uk Kim 			sc->rtsx_req->cmd->error = MMC_ERR_BADCRC;
599926ce35aSJung-uk Kim 		}
600926ce35aSJung-uk Kim 		if (!sc->rtsx_tuning_mode)
601926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "Transfer fail - status: 0x%08x\n", status);
602926ce35aSJung-uk Kim 		rtsx_stop_cmd(sc);
603926ce35aSJung-uk Kim 		if (sc->rtsx_intr_trans_ko != NULL)
604926ce35aSJung-uk Kim 			sc->rtsx_intr_trans_ko(sc);
605926ce35aSJung-uk Kim 	}
606926ce35aSJung-uk Kim 
607926ce35aSJung-uk Kim 	RTSX_UNLOCK(sc);
608926ce35aSJung-uk Kim }
609926ce35aSJung-uk Kim 
610926ce35aSJung-uk Kim /*
611926ce35aSJung-uk Kim  * Function called from the IRQ handler (from dwmmc.c).
612926ce35aSJung-uk Kim  */
613926ce35aSJung-uk Kim static void
614926ce35aSJung-uk Kim rtsx_handle_card_present(struct rtsx_softc *sc)
615926ce35aSJung-uk Kim {
616926ce35aSJung-uk Kim 	bool	was_present;
617926ce35aSJung-uk Kim 	bool	is_present;
618926ce35aSJung-uk Kim 
619926ce35aSJung-uk Kim #ifdef MMCCAM
620926ce35aSJung-uk Kim 	was_present = sc->rtsx_cam_status;
6219d3bc163SHenri Hennebert #else  /* !MMCCAM */
622926ce35aSJung-uk Kim 	was_present = sc->rtsx_mmc_dev != NULL;
623926ce35aSJung-uk Kim #endif /* MMCCAM */
624926ce35aSJung-uk Kim 	is_present = rtsx_is_card_present(sc);
625926ce35aSJung-uk Kim 	if (is_present)
626926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Card present\n");
627926ce35aSJung-uk Kim 	else
628926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Card absent\n");
629926ce35aSJung-uk Kim 
630926ce35aSJung-uk Kim 	if (!was_present && is_present) {
631926ce35aSJung-uk Kim 		/*
632926ce35aSJung-uk Kim 		 * The delay is to debounce the card insert
633926ce35aSJung-uk Kim 		 * (sometimes the card detect pin stabilizes
634926ce35aSJung-uk Kim 		 * before the other pins have made good contact).
635926ce35aSJung-uk Kim 		 */
636926ce35aSJung-uk Kim 		taskqueue_enqueue_timeout(taskqueue_swi_giant,
637926ce35aSJung-uk Kim 					  &sc->rtsx_card_insert_task, -hz);
638926ce35aSJung-uk Kim 	} else if (was_present && !is_present) {
639926ce35aSJung-uk Kim 		taskqueue_enqueue(taskqueue_swi_giant, &sc->rtsx_card_remove_task);
640926ce35aSJung-uk Kim 	}
641926ce35aSJung-uk Kim }
642926ce35aSJung-uk Kim 
643926ce35aSJung-uk Kim /*
6445bdf58e1SGordon Bergling  * This function is called at startup.
645926ce35aSJung-uk Kim  */
646926ce35aSJung-uk Kim static void
647926ce35aSJung-uk Kim rtsx_card_task(void *arg, int pending __unused)
648926ce35aSJung-uk Kim {
649926ce35aSJung-uk Kim 	struct rtsx_softc *sc = arg;
650926ce35aSJung-uk Kim 
651926ce35aSJung-uk Kim 	if (rtsx_is_card_present(sc)) {
652926ce35aSJung-uk Kim 		sc->rtsx_flags |= RTSX_F_CARD_PRESENT;
653926ce35aSJung-uk Kim 		/* Card is present, attach if necessary. */
654926ce35aSJung-uk Kim #ifdef MMCCAM
655926ce35aSJung-uk Kim 		if (sc->rtsx_cam_status == 0) {
6569d3bc163SHenri Hennebert #else  /* !MMCCAM */
657926ce35aSJung-uk Kim 		if (sc->rtsx_mmc_dev == NULL) {
658926ce35aSJung-uk Kim #endif /* MMCCAM */
659577130e5SHenri Hennebert 			if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
660926ce35aSJung-uk Kim 				device_printf(sc->rtsx_dev, "Card inserted\n");
661926ce35aSJung-uk Kim 
662926ce35aSJung-uk Kim 			sc->rtsx_read_count = sc->rtsx_write_count = 0;
663926ce35aSJung-uk Kim #ifdef MMCCAM
664926ce35aSJung-uk Kim 			sc->rtsx_cam_status = 1;
6658e9740b6SHenri Hennebert 			mmc_cam_sim_discover(&sc->rtsx_mmc_sim);
6669d3bc163SHenri Hennebert #else  /* !MMCCAM */
6678e9740b6SHenri Hennebert 			RTSX_LOCK(sc);
6685b56413dSWarner Losh 			sc->rtsx_mmc_dev = device_add_child(sc->rtsx_dev, "mmc", DEVICE_UNIT_ANY);
669926ce35aSJung-uk Kim 			RTSX_UNLOCK(sc);
670926ce35aSJung-uk Kim 			if (sc->rtsx_mmc_dev == NULL) {
671926ce35aSJung-uk Kim 				device_printf(sc->rtsx_dev, "Adding MMC bus failed\n");
672926ce35aSJung-uk Kim 			} else {
673926ce35aSJung-uk Kim 				device_set_ivars(sc->rtsx_mmc_dev, sc);
674926ce35aSJung-uk Kim 				device_probe_and_attach(sc->rtsx_mmc_dev);
675926ce35aSJung-uk Kim 			}
676926ce35aSJung-uk Kim #endif /* MMCCAM */
6778e9740b6SHenri Hennebert 		}
678926ce35aSJung-uk Kim 	} else {
679926ce35aSJung-uk Kim 		sc->rtsx_flags &= ~RTSX_F_CARD_PRESENT;
680926ce35aSJung-uk Kim 		/* Card isn't present, detach if necessary. */
681926ce35aSJung-uk Kim #ifdef MMCCAM
682926ce35aSJung-uk Kim 		if (sc->rtsx_cam_status != 0) {
6839d3bc163SHenri Hennebert #else  /* !MMCCAM */
684926ce35aSJung-uk Kim 		if (sc->rtsx_mmc_dev != NULL) {
685926ce35aSJung-uk Kim #endif /* MMCCAM */
686577130e5SHenri Hennebert 			if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
687926ce35aSJung-uk Kim 				device_printf(sc->rtsx_dev, "Card removed\n");
688926ce35aSJung-uk Kim 
689577130e5SHenri Hennebert 			if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
690926ce35aSJung-uk Kim 				device_printf(sc->rtsx_dev, "Read count: %" PRIu64 ", write count: %" PRIu64 "\n",
691926ce35aSJung-uk Kim 					      sc->rtsx_read_count, sc->rtsx_write_count);
692926ce35aSJung-uk Kim #ifdef MMCCAM
693926ce35aSJung-uk Kim 			sc->rtsx_cam_status = 0;
6948e9740b6SHenri Hennebert 			mmc_cam_sim_discover(&sc->rtsx_mmc_sim);
6959d3bc163SHenri Hennebert #else  /* !MMCCAM */
696926ce35aSJung-uk Kim 			if (device_delete_child(sc->rtsx_dev, sc->rtsx_mmc_dev))
697926ce35aSJung-uk Kim 				device_printf(sc->rtsx_dev, "Detaching MMC bus failed\n");
698926ce35aSJung-uk Kim 			sc->rtsx_mmc_dev = NULL;
699926ce35aSJung-uk Kim #endif /* MMCCAM */
7008e9740b6SHenri Hennebert 		}
701926ce35aSJung-uk Kim 	}
702926ce35aSJung-uk Kim }
703926ce35aSJung-uk Kim 
704926ce35aSJung-uk Kim static bool
705926ce35aSJung-uk Kim rtsx_is_card_present(struct rtsx_softc *sc)
706926ce35aSJung-uk Kim {
707926ce35aSJung-uk Kim 	uint32_t status;
708926ce35aSJung-uk Kim 
709926ce35aSJung-uk Kim 	status = READ4(sc, RTSX_BIPR);
710926ce35aSJung-uk Kim 	if (sc->rtsx_inversion == 0)
711926ce35aSJung-uk Kim 		return (status & RTSX_SD_EXIST);
712926ce35aSJung-uk Kim 	else
713926ce35aSJung-uk Kim 		return !(status & RTSX_SD_EXIST);
714926ce35aSJung-uk Kim }
715926ce35aSJung-uk Kim 
716926ce35aSJung-uk Kim static int
717926ce35aSJung-uk Kim rtsx_init(struct rtsx_softc *sc)
718926ce35aSJung-uk Kim {
719926ce35aSJung-uk Kim 	uint8_t	version;
720926ce35aSJung-uk Kim 	uint8_t	val;
721926ce35aSJung-uk Kim 	int	error;
722926ce35aSJung-uk Kim 
723926ce35aSJung-uk Kim 	sc->rtsx_host.host_ocr = RTSX_SUPPORTED_VOLTAGE;
724926ce35aSJung-uk Kim 	sc->rtsx_host.f_min = RTSX_SDCLK_250KHZ;
725926ce35aSJung-uk Kim 	sc->rtsx_host.f_max = RTSX_SDCLK_208MHZ;
726926ce35aSJung-uk Kim 	sc->rtsx_host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED |
727926ce35aSJung-uk Kim 		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
728926ce35aSJung-uk Kim 
729926ce35aSJung-uk Kim 	sc->rtsx_host.caps |= MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104;
730926ce35aSJung-uk Kim 	if (sc->rtsx_device_id == RTSX_RTS5209)
731926ce35aSJung-uk Kim 		sc->rtsx_host.caps |= MMC_CAP_8_BIT_DATA;
732926ce35aSJung-uk Kim 	pci_find_cap(sc->rtsx_dev, PCIY_EXPRESS, &(sc->rtsx_pcie_cap));
733926ce35aSJung-uk Kim 
734926ce35aSJung-uk Kim 	/*
735926ce35aSJung-uk Kim 	 * Check IC version.
736926ce35aSJung-uk Kim 	 */
737926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
738926ce35aSJung-uk Kim 	case RTSX_RTS5229:
739926ce35aSJung-uk Kim 		/* Read IC version from dummy register. */
740926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_DUMMY_REG, &version);
741926ce35aSJung-uk Kim 		if ((version & 0x0F) == RTSX_IC_VERSION_C)
742926ce35aSJung-uk Kim 			sc->rtsx_flags |= RTSX_F_VERSION_C;
743926ce35aSJung-uk Kim 		break;
744926ce35aSJung-uk Kim 	case RTSX_RTS522A:
745926ce35aSJung-uk Kim 		/* Read IC version from dummy register. */
746926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_DUMMY_REG, &version);
747926ce35aSJung-uk Kim 		if ((version & 0x0F) == RTSX_IC_VERSION_A)
748926ce35aSJung-uk Kim 			sc->rtsx_flags |= RTSX_F_VERSION_A;
749926ce35aSJung-uk Kim 		break;
750926ce35aSJung-uk Kim 	case RTSX_RTS525A:
751926ce35aSJung-uk Kim 		/* Read IC version from dummy register. */
752926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_DUMMY_REG, &version);
753926ce35aSJung-uk Kim 		if ((version & 0x0F) == RTSX_IC_VERSION_A)
754926ce35aSJung-uk Kim 			sc->rtsx_flags |= RTSX_F_VERSION_A;
755926ce35aSJung-uk Kim 		break;
756926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
757926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_RTL8411B_PACKAGE, &version);
758926ce35aSJung-uk Kim 		if (version & RTSX_RTL8411B_QFN48)
759926ce35aSJung-uk Kim 			sc->rtsx_flags |= RTSX_F_8411B_QFN48;
760926ce35aSJung-uk Kim 		break;
761926ce35aSJung-uk Kim 	}
762926ce35aSJung-uk Kim 
763926ce35aSJung-uk Kim 	/*
764926ce35aSJung-uk Kim 	 * Fetch vendor settings.
765926ce35aSJung-uk Kim 	 */
766926ce35aSJung-uk Kim 	/*
767926ce35aSJung-uk Kim 	 * Normally OEMs will set vendor setting to the config space
768926ce35aSJung-uk Kim 	 * of Realtek card reader in BIOS stage. This statement reads
769926ce35aSJung-uk Kim 	 * the setting and configure the internal registers according
770926ce35aSJung-uk Kim 	 * to it, to improve card reader's compatibility condition.
771926ce35aSJung-uk Kim 	 */
772926ce35aSJung-uk Kim 	sc->rtsx_card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
773926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
774926ce35aSJung-uk Kim 		uint32_t reg;
775926ce35aSJung-uk Kim 		uint32_t reg1;
776926ce35aSJung-uk Kim 		uint8_t  reg3;
777926ce35aSJung-uk Kim 	case RTSX_RTS5209:
778926ce35aSJung-uk Kim 		sc->rtsx_card_drive_sel = RTSX_RTS5209_CARD_DRIVE_DEFAULT;
779926ce35aSJung-uk Kim 		sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D;
780926ce35aSJung-uk Kim 		reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4);
781926ce35aSJung-uk Kim 		if (!(reg & 0x80)) {
782926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel = (reg >> 8) & 0x3F;
783926ce35aSJung-uk Kim 			sc->rtsx_sd30_drive_sel_3v3 = reg & 0x07;
784577130e5SHenri Hennebert 		} else if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
785926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg);
786926ce35aSJung-uk Kim 		}
787577130e5SHenri Hennebert 		if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
788926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n",
789926ce35aSJung-uk Kim 				      sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3);
790926ce35aSJung-uk Kim 		break;
791926ce35aSJung-uk Kim 	case RTSX_RTS5227:
792926ce35aSJung-uk Kim 	case RTSX_RTS522A:
793926ce35aSJung-uk Kim 		sc->rtsx_sd30_drive_sel_3v3 = RTSX_CFG_DRIVER_TYPE_B;
794926ce35aSJung-uk Kim 		reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4);
795926ce35aSJung-uk Kim 		if (!(reg & 0x1000000)) {
796926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel &= 0x3F;
797926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel |= ((reg >> 25) & 0x01) << 6;
798926ce35aSJung-uk Kim 			reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4);
799926ce35aSJung-uk Kim 			sc->rtsx_sd30_drive_sel_3v3 = (reg >> 5) & 0x03;
800926ce35aSJung-uk Kim 			if (reg & 0x4000)
801926ce35aSJung-uk Kim 				sc->rtsx_flags |= RTSX_F_REVERSE_SOCKET;
802577130e5SHenri Hennebert 		} else if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
803926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg);
804926ce35aSJung-uk Kim 		}
805577130e5SHenri Hennebert 		if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
806926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev,
807926ce35aSJung-uk Kim 				      "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x, reverse_socket is %s\n",
808926ce35aSJung-uk Kim 				      sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3,
809926ce35aSJung-uk Kim 				      (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) ? "true" : "false");
810926ce35aSJung-uk Kim 		break;
811926ce35aSJung-uk Kim 	case RTSX_RTS5229:
812926ce35aSJung-uk Kim 		sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D;
813926ce35aSJung-uk Kim 		reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4);
814926ce35aSJung-uk Kim 		if (!(reg & 0x1000000)) {
815926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel &= 0x3F;
816926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel |= ((reg >> 25) & 0x01) << 6;
817926ce35aSJung-uk Kim 			reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4);
818926ce35aSJung-uk Kim 			sc->rtsx_sd30_drive_sel_3v3 = rtsx_map_sd_drive((reg >> 5) & 0x03);
819577130e5SHenri Hennebert 		} else if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
820926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg);
821926ce35aSJung-uk Kim 		}
822577130e5SHenri Hennebert 		if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
823926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n",
824926ce35aSJung-uk Kim 				      sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3);
825926ce35aSJung-uk Kim 		break;
826926ce35aSJung-uk Kim 	case RTSX_RTS525A:
827926ce35aSJung-uk Kim 	case RTSX_RTS5249:
828577130e5SHenri Hennebert 	case RTSX_RTS5260:
829926ce35aSJung-uk Kim 		sc->rtsx_sd30_drive_sel_3v3 = RTSX_CFG_DRIVER_TYPE_B;
830926ce35aSJung-uk Kim 		reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4);
831926ce35aSJung-uk Kim 		if ((reg & 0x1000000)) {
832926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel &= 0x3F;
833926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel |= ((reg >> 25) & 0x01) << 6;
834926ce35aSJung-uk Kim 			reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4);
835926ce35aSJung-uk Kim 			sc->rtsx_sd30_drive_sel_3v3 = (reg >> 5) & 0x03;
836926ce35aSJung-uk Kim 			if (reg & 0x4000)
837926ce35aSJung-uk Kim 				sc->rtsx_flags |= RTSX_F_REVERSE_SOCKET;
838577130e5SHenri Hennebert 		} else if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
839926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg);
840926ce35aSJung-uk Kim 		}
841577130e5SHenri Hennebert 		if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
842926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev,
843926ce35aSJung-uk Kim 				      "card_drive_sel = 0x%02x, sd30_drive_sel_3v3: 0x%02x, reverse_socket is %s\n",
844926ce35aSJung-uk Kim 				      sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3,
845926ce35aSJung-uk Kim 				      (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) ? "true" : "false");
846926ce35aSJung-uk Kim 		break;
847926ce35aSJung-uk Kim 	case RTSX_RTL8402:
848926ce35aSJung-uk Kim 	case RTSX_RTL8411:
849926ce35aSJung-uk Kim 		sc->rtsx_card_drive_sel = RTSX_RTL8411_CARD_DRIVE_DEFAULT;
850926ce35aSJung-uk Kim 		sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D;
851926ce35aSJung-uk Kim 		reg1 = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4);
852926ce35aSJung-uk Kim 		if (reg1 & 0x1000000) {
853926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel &= 0x3F;
854926ce35aSJung-uk Kim 			sc->rtsx_card_drive_sel |= ((reg1 >> 25) & 0x01) << 6;
855926ce35aSJung-uk Kim 			reg3 = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG3, 1);
856926ce35aSJung-uk Kim 			sc->rtsx_sd30_drive_sel_3v3 = (reg3 >> 5) & 0x07;
857577130e5SHenri Hennebert 		} else if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
858926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "pci_read_config() error - reg1: 0x%08x\n", reg1);
859926ce35aSJung-uk Kim 		}
860577130e5SHenri Hennebert 		if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
861926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev,
862926ce35aSJung-uk Kim 				      "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n",
863926ce35aSJung-uk Kim 				      sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3);
864926ce35aSJung-uk Kim 		break;
865926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
866926ce35aSJung-uk Kim 		sc->rtsx_card_drive_sel = RTSX_RTL8411_CARD_DRIVE_DEFAULT;
867926ce35aSJung-uk Kim 		sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D;
868926ce35aSJung-uk Kim 		reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4);
869926ce35aSJung-uk Kim 		if (!(reg & 0x1000000)) {
870926ce35aSJung-uk Kim 			sc->rtsx_sd30_drive_sel_3v3 = rtsx_map_sd_drive(reg & 0x03);
871577130e5SHenri Hennebert 		} else if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
872926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg);
873926ce35aSJung-uk Kim 		}
874577130e5SHenri Hennebert 		if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
875926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev,
876926ce35aSJung-uk Kim 				      "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n",
877926ce35aSJung-uk Kim 				      sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3);
878926ce35aSJung-uk Kim 		break;
879926ce35aSJung-uk Kim 	}
880926ce35aSJung-uk Kim 
881577130e5SHenri Hennebert 	if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
882926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_init() rtsx_flags: 0x%04x\n", sc->rtsx_flags);
883926ce35aSJung-uk Kim 
884926ce35aSJung-uk Kim 	/* Enable interrupts. */
8858290c144SHenri Hennebert 	sc->rtsx_intr_enabled = RTSX_TRANS_OK_INT_EN | RTSX_TRANS_FAIL_INT_EN | RTSX_SD_INT_EN;
886926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_BIER, sc->rtsx_intr_enabled);
887926ce35aSJung-uk Kim 
888926ce35aSJung-uk Kim 	/* Power on SSC clock. */
889926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_FPDCTL, RTSX_SSC_POWER_DOWN);
890926ce35aSJung-uk Kim 	/* Wait SSC power stable. */
891926ce35aSJung-uk Kim 	DELAY(200);
892926ce35aSJung-uk Kim 
893926ce35aSJung-uk Kim 	/* Disable ASPM */
894926ce35aSJung-uk Kim 	val = pci_read_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_LINK_CTL, 1);
895926ce35aSJung-uk Kim 	pci_write_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_LINK_CTL, val & 0xfc, 1);
896926ce35aSJung-uk Kim 
897926ce35aSJung-uk Kim 	/*
898926ce35aSJung-uk Kim 	 * Optimize phy.
899926ce35aSJung-uk Kim 	 */
900926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
901926ce35aSJung-uk Kim 	case RTSX_RTS5209:
902926ce35aSJung-uk Kim 		/* Some magic numbers from Linux driver. */
903926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, 0x00, 0xB966)))
904926ce35aSJung-uk Kim 			return (error);
905926ce35aSJung-uk Kim 		break;
906926ce35aSJung-uk Kim 	case RTSX_RTS5227:
907926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_PM_CTRL3, RTSX_D3_DELINK_MODE_EN);
908926ce35aSJung-uk Kim 
909926ce35aSJung-uk Kim 		/* Optimize RX sensitivity. */
910926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, 0x00, 0xBA42)))
911926ce35aSJung-uk Kim 			return (error);
912926ce35aSJung-uk Kim 		break;
913926ce35aSJung-uk Kim 	case RTSX_RTS5229:
914926ce35aSJung-uk Kim 		/* Optimize RX sensitivity. */
915926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, 0x00, 0xBA42)))
916926ce35aSJung-uk Kim 			return (error);
917926ce35aSJung-uk Kim 		break;
918926ce35aSJung-uk Kim 	case RTSX_RTS522A:
919926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_RTS522A_PM_CTRL3, RTSX_D3_DELINK_MODE_EN);
920926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_VERSION_A) {
921926ce35aSJung-uk Kim 			if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR2, RTSX_PHY_RCR2_INIT_27S)))
922926ce35aSJung-uk Kim 				return (error);
923926ce35aSJung-uk Kim 		}
924926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR1, RTSX_PHY_RCR1_INIT_27S)))
925926ce35aSJung-uk Kim 			return (error);
926926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD0, RTSX_PHY_FLD0_INIT_27S)))
927926ce35aSJung-uk Kim 			return (error);
928926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD3, RTSX_PHY_FLD3_INIT_27S)))
929926ce35aSJung-uk Kim 			return (error);
930926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD4, RTSX_PHY_FLD4_INIT_27S)))
931926ce35aSJung-uk Kim 			return (error);
932926ce35aSJung-uk Kim 		break;
933926ce35aSJung-uk Kim 	case RTSX_RTS525A:
934926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX__PHY_FLD0,
935926ce35aSJung-uk Kim 					    RTSX__PHY_FLD0_CLK_REQ_20C | RTSX__PHY_FLD0_RX_IDLE_EN |
936926ce35aSJung-uk Kim 					    RTSX__PHY_FLD0_BIT_ERR_RSTN | RTSX__PHY_FLD0_BER_COUNT |
937926ce35aSJung-uk Kim 					    RTSX__PHY_FLD0_BER_TIMER | RTSX__PHY_FLD0_CHECK_EN)))
938926ce35aSJung-uk Kim 			return (error);
939926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX__PHY_ANA03,
940926ce35aSJung-uk Kim 					    RTSX__PHY_ANA03_TIMER_MAX | RTSX__PHY_ANA03_OOBS_DEB_EN |
941926ce35aSJung-uk Kim 					    RTSX__PHY_CMU_DEBUG_EN)))
942926ce35aSJung-uk Kim 			return (error);
943926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_VERSION_A)
944926ce35aSJung-uk Kim 			if ((error = rtsx_write_phy(sc, RTSX__PHY_REV0,
945926ce35aSJung-uk Kim 						    RTSX__PHY_REV0_FILTER_OUT | RTSX__PHY_REV0_CDR_BYPASS_PFD |
946926ce35aSJung-uk Kim 						    RTSX__PHY_REV0_CDR_RX_IDLE_BYPASS)))
947926ce35aSJung-uk Kim 				return (error);
948926ce35aSJung-uk Kim 		break;
949926ce35aSJung-uk Kim 	case RTSX_RTS5249:
950926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_PM_CTRL3, RTSX_D3_DELINK_MODE_EN);
951926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_REV,
952926ce35aSJung-uk Kim 					    RTSX_PHY_REV_RESV | RTSX_PHY_REV_RXIDLE_LATCHED |
953926ce35aSJung-uk Kim 					    RTSX_PHY_REV_P1_EN | RTSX_PHY_REV_RXIDLE_EN |
954926ce35aSJung-uk Kim 					    RTSX_PHY_REV_CLKREQ_TX_EN | RTSX_PHY_REV_RX_PWST |
955926ce35aSJung-uk Kim 					    RTSX_PHY_REV_CLKREQ_DT_1_0 | RTSX_PHY_REV_STOP_CLKRD |
956926ce35aSJung-uk Kim 					    RTSX_PHY_REV_STOP_CLKWR)))
957926ce35aSJung-uk Kim 			return (error);
9589d3bc163SHenri Hennebert 		DELAY(1000);
959926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_BPCR,
960926ce35aSJung-uk Kim 					    RTSX_PHY_BPCR_IBRXSEL | RTSX_PHY_BPCR_IBTXSEL |
961926ce35aSJung-uk Kim 					    RTSX_PHY_BPCR_IB_FILTER | RTSX_PHY_BPCR_CMIRROR_EN)))
962926ce35aSJung-uk Kim 			return (error);
963926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_PCR,
964926ce35aSJung-uk Kim 					    RTSX_PHY_PCR_FORCE_CODE | RTSX_PHY_PCR_OOBS_CALI_50 |
965926ce35aSJung-uk Kim 					    RTSX_PHY_PCR_OOBS_VCM_08 | RTSX_PHY_PCR_OOBS_SEN_90 |
966926ce35aSJung-uk Kim 					    RTSX_PHY_PCR_RSSI_EN | RTSX_PHY_PCR_RX10K)))
967926ce35aSJung-uk Kim 			return (error);
968926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR2,
969926ce35aSJung-uk Kim 					    RTSX_PHY_RCR2_EMPHASE_EN | RTSX_PHY_RCR2_NADJR |
970926ce35aSJung-uk Kim 					    RTSX_PHY_RCR2_CDR_SR_2 | RTSX_PHY_RCR2_FREQSEL_12 |
971926ce35aSJung-uk Kim 					    RTSX_PHY_RCR2_CDR_SC_12P | RTSX_PHY_RCR2_CALIB_LATE)))
972926ce35aSJung-uk Kim 			return (error);
973926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD4,
974926ce35aSJung-uk Kim 					    RTSX_PHY_FLD4_FLDEN_SEL | RTSX_PHY_FLD4_REQ_REF |
975926ce35aSJung-uk Kim 					    RTSX_PHY_FLD4_RXAMP_OFF | RTSX_PHY_FLD4_REQ_ADDA |
976926ce35aSJung-uk Kim 					    RTSX_PHY_FLD4_BER_COUNT | RTSX_PHY_FLD4_BER_TIMER |
977926ce35aSJung-uk Kim 					    RTSX_PHY_FLD4_BER_CHK_EN)))
978926ce35aSJung-uk Kim 			return (error);
979926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_RDR,
980926ce35aSJung-uk Kim 					    RTSX_PHY_RDR_RXDSEL_1_9 | RTSX_PHY_SSC_AUTO_PWD)))
981926ce35aSJung-uk Kim 			return (error);
982926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR1,
983926ce35aSJung-uk Kim 					    RTSX_PHY_RCR1_ADP_TIME_4 | RTSX_PHY_RCR1_VCO_COARSE)))
984926ce35aSJung-uk Kim 			return (error);
985926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD3,
986926ce35aSJung-uk Kim 					    RTSX_PHY_FLD3_TIMER_4 | RTSX_PHY_FLD3_TIMER_6 |
987926ce35aSJung-uk Kim 					    RTSX_PHY_FLD3_RXDELINK)))
988926ce35aSJung-uk Kim 			return (error);
989926ce35aSJung-uk Kim 		if ((error = rtsx_write_phy(sc, RTSX_PHY_TUNE,
990926ce35aSJung-uk Kim 					    RTSX_PHY_TUNE_TUNEREF_1_0 | RTSX_PHY_TUNE_VBGSEL_1252 |
991926ce35aSJung-uk Kim 					    RTSX_PHY_TUNE_SDBUS_33 | RTSX_PHY_TUNE_TUNED18 |
992926ce35aSJung-uk Kim 					    RTSX_PHY_TUNE_TUNED12 | RTSX_PHY_TUNE_TUNEA12)))
993926ce35aSJung-uk Kim 			return (error);
994926ce35aSJung-uk Kim 		break;
995926ce35aSJung-uk Kim 	}
996926ce35aSJung-uk Kim 
997926ce35aSJung-uk Kim 	/* Set mcu_cnt to 7 to ensure data can be sampled properly. */
998926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CLK_DIV, 0x07, 0x07);
999926ce35aSJung-uk Kim 
1000926ce35aSJung-uk Kim 	/* Disable sleep mode. */
1001926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_HOST_SLEEP_STATE,
1002926ce35aSJung-uk Kim 		 RTSX_HOST_ENTER_S1 | RTSX_HOST_ENTER_S3);
1003926ce35aSJung-uk Kim 
1004926ce35aSJung-uk Kim 	/* Disable card clock. */
1005926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_CARD_CLK_EN, RTSX_CARD_CLK_EN_ALL);
1006926ce35aSJung-uk Kim 
1007926ce35aSJung-uk Kim 	/* Reset delink mode. */
1008926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_CHANGE_LINK_STATE,
1009926ce35aSJung-uk Kim 		 RTSX_FORCE_RST_CORE_EN | RTSX_NON_STICKY_RST_N_DBG);
1010926ce35aSJung-uk Kim 
1011926ce35aSJung-uk Kim 	/* Card driving select. */
1012926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_CARD_DRIVE_SEL, sc->rtsx_card_drive_sel);
1013926ce35aSJung-uk Kim 
1014926ce35aSJung-uk Kim 	/* Enable SSC clock. */
1015926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SSC_CTL1, RTSX_SSC_8X_EN | RTSX_SSC_SEL_4M);
1016926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SSC_CTL2, 0x12);
1017926ce35aSJung-uk Kim 
1018926ce35aSJung-uk Kim 	/* Disable cd_pwr_save. */
1019926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CHANGE_LINK_STATE, 0x16, RTSX_MAC_PHY_RST_N_DBG);
1020926ce35aSJung-uk Kim 
1021926ce35aSJung-uk Kim 	/* Clear Link Ready Interrupt. */
1022926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_IRQSTAT0, RTSX_LINK_READY_INT, RTSX_LINK_READY_INT);
1023926ce35aSJung-uk Kim 
1024926ce35aSJung-uk Kim 	/* Enlarge the estimation window of PERST# glitch
1025926ce35aSJung-uk Kim 	 * to reduce the chance of invalid card interrupt. */
1026926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PERST_GLITCH_WIDTH, 0x80);
1027926ce35aSJung-uk Kim 
1028926ce35aSJung-uk Kim 	/* Set RC oscillator to 400K. */
1029926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_RCCTL, RTSX_RCCTL_F_2M);
1030926ce35aSJung-uk Kim 
1031926ce35aSJung-uk Kim 	/* Enable interrupt write-clear (default is read-clear). */
1032926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_NFTS_TX_CTRL, RTSX_INT_READ_CLR);
1033926ce35aSJung-uk Kim 
10348290c144SHenri Hennebert 	switch (sc->rtsx_device_id) {
10358290c144SHenri Hennebert 	case RTSX_RTS525A:
10368290c144SHenri Hennebert 	case RTSX_RTS5260:
1037926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PM_CLK_FORCE_CTL, 1, 1);
10388290c144SHenri Hennebert 		break;
10398290c144SHenri Hennebert 	}
1040926ce35aSJung-uk Kim 
1041926ce35aSJung-uk Kim 	/* OC power down. */
1042926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_FPDCTL, RTSX_SD_OC_POWER_DOWN, RTSX_SD_OC_POWER_DOWN);
1043926ce35aSJung-uk Kim 
1044926ce35aSJung-uk Kim 	/* Enable clk_request_n to enable clock power management */
1045926ce35aSJung-uk Kim 	pci_write_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_LINK_CTL + 1, 1, 1);
1046926ce35aSJung-uk Kim 
1047926ce35aSJung-uk Kim 	/* Enter L1 when host tx idle */
1048926ce35aSJung-uk Kim 	pci_write_config(sc->rtsx_dev, 0x70F, 0x5B, 1);
1049926ce35aSJung-uk Kim 
1050926ce35aSJung-uk Kim 	/*
1051926ce35aSJung-uk Kim 	 * Specific extra init.
1052926ce35aSJung-uk Kim 	 */
1053926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
1054926ce35aSJung-uk Kim 		uint16_t cap;
1055926ce35aSJung-uk Kim 	case RTSX_RTS5209:
1056926ce35aSJung-uk Kim 		/* Turn off LED. */
1057926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_GPIO, 0x03);
1058926ce35aSJung-uk Kim 		/* Reset ASPM state to default value. */
1059926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK);
1060926ce35aSJung-uk Kim 		/* Force CLKREQ# PIN to drive 0 to request clock. */
1061926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PETXCFG, 0x08, 0x08);
1062926ce35aSJung-uk Kim 		/* Configure GPIO as output. */
1063926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_GPIO_DIR, 0x03);
1064926ce35aSJung-uk Kim 		/* Configure driving. */
1065926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3);
1066926ce35aSJung-uk Kim 		break;
1067926ce35aSJung-uk Kim 	case RTSX_RTS5227:
1068926ce35aSJung-uk Kim 		/* Configure GPIO as output. */
1069926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON);
1070926ce35aSJung-uk Kim 		/* Reset ASPM state to default value. */
1071926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM);
1072926ce35aSJung-uk Kim 		/* Switch LDO3318 source from DV33 to 3V3. */
1073926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33);
1074926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3);
1075926ce35aSJung-uk Kim 		/* Set default OLT blink period. */
1076926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD);
1077926ce35aSJung-uk Kim 		/* Configure LTR. */
1078926ce35aSJung-uk Kim 		cap = pci_read_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_DEVICE_CTL2, 2);
1079926ce35aSJung-uk Kim 		if (cap & PCIEM_CTL2_LTR_ENABLE)
1080926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_LTR_CTL, 0xa3);
1081926ce35aSJung-uk Kim 		/* Configure OBFF. */
1082926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OBFF_CFG, RTSX_OBFF_EN_MASK, RTSX_OBFF_ENABLE);
1083926ce35aSJung-uk Kim 		/* Configure driving. */
1084926ce35aSJung-uk Kim 		if ((error = rtsx_rts5227_fill_driving(sc)))
1085926ce35aSJung-uk Kim 			return (error);
1086926ce35aSJung-uk Kim 		/* Configure force_clock_req. */
1087926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET)
1088926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0xB8);
1089926ce35aSJung-uk Kim 		else
1090926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0x88);
1091926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_PM_CTRL3, RTSX_D3_DELINK_MODE_EN);
1092926ce35aSJung-uk Kim 		/*!!! Added for reboot after Windows. */
1093926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PM_CTRL3, RTSX_PM_WAKE_EN, RTSX_PM_WAKE_EN);
1094926ce35aSJung-uk Kim 		break;
1095926ce35aSJung-uk Kim 	case RTSX_RTS5229:
1096926ce35aSJung-uk Kim 		/* Configure GPIO as output. */
1097926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON);
1098926ce35aSJung-uk Kim 		/* Reset ASPM state to default value. */
1099926ce35aSJung-uk Kim 		/*  With this reset: dd if=/dev/random of=/dev/mmcsd0 encounter a timeout. */
1100926ce35aSJung-uk Kim //!!!		RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM);
1101926ce35aSJung-uk Kim 		/* Force CLKREQ# PIN to drive 0 to request clock. */
1102926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PETXCFG, 0x08, 0x08);
1103926ce35aSJung-uk Kim 		/* Switch LDO3318 source from DV33 to card_3v3. */
1104926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33);
1105926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3);
1106926ce35aSJung-uk Kim 		/* Set default OLT blink period. */
1107926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD);
1108926ce35aSJung-uk Kim 		/* Configure driving. */
1109926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3);
1110926ce35aSJung-uk Kim 		break;
1111926ce35aSJung-uk Kim 	case RTSX_RTS522A:
1112926ce35aSJung-uk Kim 		/* Add specific init from RTS5227. */
1113926ce35aSJung-uk Kim 		/* Configure GPIO as output. */
1114926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON);
1115926ce35aSJung-uk Kim 		/* Reset ASPM state to default value. */
1116926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM);
1117926ce35aSJung-uk Kim 		/* Switch LDO3318 source from DV33 to 3V3. */
1118926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33);
1119926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3);
1120926ce35aSJung-uk Kim 		/* Set default OLT blink period. */
1121926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD);
1122926ce35aSJung-uk Kim 		/* Configure LTR. */
1123926ce35aSJung-uk Kim 		cap = pci_read_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_DEVICE_CTL2, 2);
1124926ce35aSJung-uk Kim 		if (cap & PCIEM_CTL2_LTR_ENABLE)
1125926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_LTR_CTL, 0xa3);
1126926ce35aSJung-uk Kim 		/* Configure OBFF. */
1127926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OBFF_CFG, RTSX_OBFF_EN_MASK, RTSX_OBFF_ENABLE);
1128926ce35aSJung-uk Kim 		/* Configure driving. */
1129926ce35aSJung-uk Kim 		if ((error = rtsx_rts5227_fill_driving(sc)))
1130926ce35aSJung-uk Kim 			return (error);
1131926ce35aSJung-uk Kim 		/* Configure force_clock_req. */
1132926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET)
1133926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0xB8);
1134926ce35aSJung-uk Kim 		else
1135926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0x88);
1136926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_RTS522A_PM_CTRL3,  0x10);
1137926ce35aSJung-uk Kim 
1138926ce35aSJung-uk Kim 		/* specific for RTS522A. */
1139926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_FUNC_FORCE_CTL,
1140926ce35aSJung-uk Kim 			   RTSX_FUNC_FORCE_UPME_XMT_DBG, RTSX_FUNC_FORCE_UPME_XMT_DBG);
1141926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PCLK_CTL, 0x04, 0x04);
1142926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PM_EVENT_DEBUG,
1143926ce35aSJung-uk Kim 			   RTSX_PME_DEBUG_0, RTSX_PME_DEBUG_0);
1144926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_PM_CLK_FORCE_CTL, 0x11);
1145926ce35aSJung-uk Kim 		break;
1146926ce35aSJung-uk Kim 	case RTSX_RTS525A:
1147926ce35aSJung-uk Kim 		/* Add specific init from RTS5249. */
1148926ce35aSJung-uk Kim 		/* Rest L1SUB Config. */
1149926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_L1SUB_CONFIG3, 0xff);
1150926ce35aSJung-uk Kim 		/* Configure GPIO as output. */
1151926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON);
1152926ce35aSJung-uk Kim 		/* Reset ASPM state to default value. */
1153926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM);
1154926ce35aSJung-uk Kim 		/* Switch LDO3318 source from DV33 to 3V3. */
1155926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33);
1156926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3);
1157926ce35aSJung-uk Kim 		/* Set default OLT blink period. */
1158926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD);
1159926ce35aSJung-uk Kim 		/* Configure driving. */
1160926ce35aSJung-uk Kim 		if ((error = rtsx_rts5249_fill_driving(sc)))
1161926ce35aSJung-uk Kim 			return (error);
1162926ce35aSJung-uk Kim 		/* Configure force_clock_req. */
1163926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET)
1164926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0xB0);
1165926ce35aSJung-uk Kim 		else
1166926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0x80);
1167926ce35aSJung-uk Kim 
1168926ce35aSJung-uk Kim 		/* Specifc for RTS525A. */
1169926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PCLK_CTL, RTSX_PCLK_MODE_SEL, RTSX_PCLK_MODE_SEL);
1170926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_VERSION_A) {
1171926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_L1SUB_CONFIG2, RTSX_L1SUB_AUTO_CFG);
1172926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_RREF_CFG,
1173926ce35aSJung-uk Kim 				   RTSX_RREF_VBGSEL_MASK, RTSX_RREF_VBGSEL_1V25);
1174926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_VIO_CFG,
1175926ce35aSJung-uk Kim 				   RTSX_LDO_VIO_TUNE_MASK, RTSX_LDO_VIO_1V7);
1176926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_DV12S_CFG,
1177926ce35aSJung-uk Kim 				   RTSX_LDO_D12_TUNE_MASK, RTSX_LDO_D12_TUNE_DF);
1178926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_AV12S_CFG,
1179926ce35aSJung-uk Kim 				   RTSX_LDO_AV12S_TUNE_MASK, RTSX_LDO_AV12S_TUNE_DF);
1180926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_VCC_CFG0,
1181926ce35aSJung-uk Kim 				   RTSX_LDO_VCC_LMTVTH_MASK, RTSX_LDO_VCC_LMTVTH_2A);
1182926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_OOBS_CONFIG,
1183926ce35aSJung-uk Kim 				   RTSX_OOBS_AUTOK_DIS | RTSX_OOBS_VAL_MASK, 0x89);
1184926ce35aSJung-uk Kim 		}
1185926ce35aSJung-uk Kim 		break;
1186926ce35aSJung-uk Kim 	case RTSX_RTS5249:
1187926ce35aSJung-uk Kim 		/* Rest L1SUB Config. */
1188926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_L1SUB_CONFIG3, 0xff);
1189926ce35aSJung-uk Kim 		/* Configure GPIO as output. */
1190926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON);
1191926ce35aSJung-uk Kim 		/* Reset ASPM state to default value. */
1192926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM);
1193926ce35aSJung-uk Kim 		/* Switch LDO3318 source from DV33 to 3V3. */
1194926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33);
1195926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3);
1196926ce35aSJung-uk Kim 		/* Set default OLT blink period. */
1197926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD);
1198926ce35aSJung-uk Kim 		/* Configure driving. */
1199926ce35aSJung-uk Kim 		if ((error = rtsx_rts5249_fill_driving(sc)))
1200926ce35aSJung-uk Kim 			return (error);
1201926ce35aSJung-uk Kim 		/* Configure force_clock_req. */
1202926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET)
1203926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0xB0);
1204926ce35aSJung-uk Kim 		else
1205926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0x80);
1206926ce35aSJung-uk Kim 		break;
1207577130e5SHenri Hennebert 	case RTSX_RTS5260:
1208577130e5SHenri Hennebert 		/* Set mcu_cnt to 7 to ensure data can be sampled properly. */
1209577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_CLK_DIV, 0x07, 0x07);
1210577130e5SHenri Hennebert 		RTSX_WRITE(sc, RTSX_SSC_DIV_N_0, 0x5D);
12118290c144SHenri Hennebert 		/* Force no MDIO */
1212577130e5SHenri Hennebert 		RTSX_WRITE(sc, RTSX_RTS5260_AUTOLOAD_CFG4, RTSX_RTS5260_MIMO_DISABLE);
1213577130e5SHenri Hennebert 		/* Modify SDVCC Tune Default Parameters! */
1214577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_VCC_CFG0, RTSX_RTS5260_DVCC_TUNE_MASK, RTSX_RTS5260_DVCC_33);
12158290c144SHenri Hennebert 
1216577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_PCLK_CTL, RTSX_PCLK_MODE_SEL, RTSX_PCLK_MODE_SEL);
12178290c144SHenri Hennebert 
1218577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_L1SUB_CONFIG1, RTSX_AUX_CLK_ACTIVE_SEL_MASK, RTSX_MAC_CKSW_DONE);
1219577130e5SHenri Hennebert 		/* Rest L1SUB Config */
1220577130e5SHenri Hennebert 		RTSX_CLR(sc, RTSX_L1SUB_CONFIG3, 0xFF);
1221577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_PM_CLK_FORCE_CTL, RTSX_CLK_PM_EN, RTSX_CLK_PM_EN);
12228290c144SHenri Hennebert 		RTSX_WRITE(sc, RTSX_PWD_SUSPEND_EN, 0xFF);
1223577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_PWR_GATE_EN, RTSX_PWR_GATE_EN);
12248290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_REG_VREF, RTSX_PWD_SUSPND_EN, RTSX_PWD_SUSPND_EN);
12258290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_RBCTL, RTSX_U_AUTO_DMA_EN_MASK, RTSX_U_AUTO_DMA_DISABLE);
1226577130e5SHenri Hennebert 		if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET)
1227577130e5SHenri Hennebert 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0xB0);
1228577130e5SHenri Hennebert 		else
1229577130e5SHenri Hennebert 			RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0x80);
1230577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_OBFF_CFG, RTSX_OBFF_EN_MASK, RTSX_OBFF_DISABLE);
12318290c144SHenri Hennebert 
12328290c144SHenri Hennebert 		RTSX_CLR(sc, RTSX_RTS5260_DVCC_CTRL, RTSX_RTS5260_DVCC_OCP_EN | RTSX_RTS5260_DVCC_OCP_CL_EN);
12338290c144SHenri Hennebert 
12348290c144SHenri Hennebert 		/* CLKREQ# PIN will be forced to drive low. */
12358290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_PETXCFG, RTSX_FORCE_CLKREQ_DELINK_MASK, RTSX_FORCE_CLKREQ_LOW);
12368290c144SHenri Hennebert 
12378290c144SHenri Hennebert 		RTSX_CLR(sc, RTSX_RTS522A_PM_CTRL3,  0x10);
1238577130e5SHenri Hennebert 		break;
1239926ce35aSJung-uk Kim 	case RTSX_RTL8402:
1240926ce35aSJung-uk Kim 	case RTSX_RTL8411:
1241926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3);
1242926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PAD_CTL, RTSX_CD_DISABLE_MASK | RTSX_CD_AUTO_DISABLE,
1243926ce35aSJung-uk Kim 			   RTSX_CD_ENABLE);
1244926ce35aSJung-uk Kim 		break;
1245926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
1246926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_8411B_QFN48)
1247926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xf5);
1248926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3);
1249926ce35aSJung-uk Kim 		/* Enable SD interrupt. */
1250926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PAD_CTL, RTSX_CD_DISABLE_MASK | RTSX_CD_AUTO_DISABLE,
1251926ce35aSJung-uk Kim 			   RTSX_CD_ENABLE);
1252926ce35aSJung-uk Kim 		/* Clear hw_pfm_en to disable hardware PFM mode. */
1253926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_FUNC_FORCE_CTL, 0x06, 0x00);
1254926ce35aSJung-uk Kim 		break;
1255926ce35aSJung-uk Kim 	}
1256926ce35aSJung-uk Kim 
1257926ce35aSJung-uk Kim 	/*!!! Added for reboot after Windows. */
1258926ce35aSJung-uk Kim 	rtsx_bus_power_off(sc);
1259926ce35aSJung-uk Kim 	rtsx_set_sd_timing(sc, bus_timing_normal);
1260926ce35aSJung-uk Kim 	rtsx_set_sd_clock(sc, 0);
1261926ce35aSJung-uk Kim 	/*!!! Added for reboot after Windows. */
1262926ce35aSJung-uk Kim 
1263926ce35aSJung-uk Kim 	return (0);
1264926ce35aSJung-uk Kim }
1265926ce35aSJung-uk Kim 
1266926ce35aSJung-uk Kim static int
1267926ce35aSJung-uk Kim rtsx_map_sd_drive(int index)
1268926ce35aSJung-uk Kim {
1269926ce35aSJung-uk Kim 	uint8_t	sd_drive[4] =
1270926ce35aSJung-uk Kim 		{
1271926ce35aSJung-uk Kim 		 0x01,	/* Type D */
1272926ce35aSJung-uk Kim 		 0x02,	/* Type C */
1273926ce35aSJung-uk Kim 		 0x05,	/* Type A */
1274926ce35aSJung-uk Kim 		 0x03	/* Type B */
1275926ce35aSJung-uk Kim 		};
1276926ce35aSJung-uk Kim 	return (sd_drive[index]);
1277926ce35aSJung-uk Kim }
1278926ce35aSJung-uk Kim 
1279926ce35aSJung-uk Kim /* For voltage 3v3. */
1280926ce35aSJung-uk Kim static int
1281926ce35aSJung-uk Kim rtsx_rts5227_fill_driving(struct rtsx_softc *sc)
1282926ce35aSJung-uk Kim {
1283926ce35aSJung-uk Kim 	u_char	driving_3v3[4][3] = {
1284926ce35aSJung-uk Kim 				     {0x13, 0x13, 0x13},
1285926ce35aSJung-uk Kim 				     {0x96, 0x96, 0x96},
1286926ce35aSJung-uk Kim 				     {0x7F, 0x7F, 0x7F},
1287926ce35aSJung-uk Kim 				     {0x96, 0x96, 0x96},
1288926ce35aSJung-uk Kim 	};
1289926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SD30_CLK_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][0]);
1290926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][1]);
1291926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SD30_DAT_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][2]);
1292926ce35aSJung-uk Kim 
1293926ce35aSJung-uk Kim 	return (0);
1294926ce35aSJung-uk Kim }
1295926ce35aSJung-uk Kim 
1296926ce35aSJung-uk Kim /* For voltage 3v3. */
1297926ce35aSJung-uk Kim static int
1298926ce35aSJung-uk Kim rtsx_rts5249_fill_driving(struct rtsx_softc *sc)
1299926ce35aSJung-uk Kim {
1300926ce35aSJung-uk Kim 	u_char	driving_3v3[4][3] = {
1301926ce35aSJung-uk Kim 				     {0x11, 0x11, 0x18},
1302926ce35aSJung-uk Kim 				     {0x55, 0x55, 0x5C},
1303926ce35aSJung-uk Kim 				     {0xFF, 0xFF, 0xFF},
1304926ce35aSJung-uk Kim 				     {0x96, 0x96, 0x96},
1305926ce35aSJung-uk Kim 	};
1306926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SD30_CLK_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][0]);
1307926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][1]);
1308926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SD30_DAT_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][2]);
1309926ce35aSJung-uk Kim 
1310926ce35aSJung-uk Kim 	return (0);
1311926ce35aSJung-uk Kim }
1312926ce35aSJung-uk Kim 
1313926ce35aSJung-uk Kim static int
1314577130e5SHenri Hennebert rtsx_rts5260_fill_driving(struct rtsx_softc *sc)
1315577130e5SHenri Hennebert {
1316577130e5SHenri Hennebert 	u_char	driving_3v3[4][3] = {
1317577130e5SHenri Hennebert 				     {0x11, 0x11, 0x11},
1318577130e5SHenri Hennebert 				     {0x22, 0x22, 0x22},
1319577130e5SHenri Hennebert 				     {0x55, 0x55, 0x55},
1320577130e5SHenri Hennebert 				     {0x33, 0x33, 0x33},
1321577130e5SHenri Hennebert 	};
1322577130e5SHenri Hennebert 	RTSX_WRITE(sc, RTSX_SD30_CLK_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][0]);
1323577130e5SHenri Hennebert 	RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][1]);
1324577130e5SHenri Hennebert 	RTSX_WRITE(sc, RTSX_SD30_DAT_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][2]);
1325577130e5SHenri Hennebert 
1326577130e5SHenri Hennebert 	return (0);
1327577130e5SHenri Hennebert }
1328577130e5SHenri Hennebert 
1329577130e5SHenri Hennebert static int
1330926ce35aSJung-uk Kim rtsx_read(struct rtsx_softc *sc, uint16_t addr, uint8_t *val)
1331926ce35aSJung-uk Kim {
1332926ce35aSJung-uk Kim 	int	 tries = 1024;
13339b261d2eSHenri Hennebert 	uint32_t arg;
1334926ce35aSJung-uk Kim 	uint32_t reg;
1335926ce35aSJung-uk Kim 
13369b261d2eSHenri Hennebert 	arg = RTSX_HAIMR_BUSY | (uint32_t)((addr & 0x3FFF) << 16);
13379b261d2eSHenri Hennebert 	WRITE4(sc, RTSX_HAIMR, arg);
1338926ce35aSJung-uk Kim 
1339926ce35aSJung-uk Kim 	while (tries--) {
1340926ce35aSJung-uk Kim 		reg = READ4(sc, RTSX_HAIMR);
1341926ce35aSJung-uk Kim 		if (!(reg & RTSX_HAIMR_BUSY))
1342926ce35aSJung-uk Kim 			break;
1343926ce35aSJung-uk Kim 	}
1344926ce35aSJung-uk Kim 	*val = (reg & 0xff);
1345926ce35aSJung-uk Kim 
13469b261d2eSHenri Hennebert 	if (tries > 0) {
13479b261d2eSHenri Hennebert 		return (0);
13489b261d2eSHenri Hennebert 	} else {
13499b261d2eSHenri Hennebert 		device_printf(sc->rtsx_dev, "rtsx_read(0x%x) timeout\n", arg);
13509b261d2eSHenri Hennebert 		return (ETIMEDOUT);
13519b261d2eSHenri Hennebert 	}
1352926ce35aSJung-uk Kim }
1353926ce35aSJung-uk Kim 
1354926ce35aSJung-uk Kim static int
1355926ce35aSJung-uk Kim rtsx_read_cfg(struct rtsx_softc *sc, uint8_t func, uint16_t addr, uint32_t *val)
1356926ce35aSJung-uk Kim {
1357926ce35aSJung-uk Kim 	int	tries = 1024;
1358926ce35aSJung-uk Kim 	uint8_t	data0, data1, data2, data3, rwctl;
1359926ce35aSJung-uk Kim 
1360926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_CFGADDR0, addr);
1361926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_CFGADDR1, addr >> 8);
1362926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_CFGRWCTL, RTSX_CFG_BUSY | (func & 0x03 << 4));
1363926ce35aSJung-uk Kim 
1364926ce35aSJung-uk Kim 	while (tries--) {
1365926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_CFGRWCTL, &rwctl);
1366926ce35aSJung-uk Kim 		if (!(rwctl & RTSX_CFG_BUSY))
1367926ce35aSJung-uk Kim 			break;
1368926ce35aSJung-uk Kim 	}
1369926ce35aSJung-uk Kim 
1370926ce35aSJung-uk Kim 	if (tries == 0)
1371926ce35aSJung-uk Kim 		return (ETIMEDOUT);
1372926ce35aSJung-uk Kim 
1373926ce35aSJung-uk Kim 	RTSX_READ(sc, RTSX_CFGDATA0, &data0);
1374926ce35aSJung-uk Kim 	RTSX_READ(sc, RTSX_CFGDATA1, &data1);
1375926ce35aSJung-uk Kim 	RTSX_READ(sc, RTSX_CFGDATA2, &data2);
1376926ce35aSJung-uk Kim 	RTSX_READ(sc, RTSX_CFGDATA3, &data3);
1377926ce35aSJung-uk Kim 
1378926ce35aSJung-uk Kim 	*val = (data3 << 24) | (data2 << 16) | (data1 << 8) | data0;
1379926ce35aSJung-uk Kim 
1380926ce35aSJung-uk Kim 	return (0);
1381926ce35aSJung-uk Kim }
1382926ce35aSJung-uk Kim 
1383926ce35aSJung-uk Kim static int
1384926ce35aSJung-uk Kim rtsx_write(struct rtsx_softc *sc, uint16_t addr, uint8_t mask, uint8_t val)
1385926ce35aSJung-uk Kim {
1386926ce35aSJung-uk Kim 	int 	 tries = 1024;
13879b261d2eSHenri Hennebert 	uint32_t arg;
1388926ce35aSJung-uk Kim 	uint32_t reg;
1389926ce35aSJung-uk Kim 
13909b261d2eSHenri Hennebert 	arg = RTSX_HAIMR_BUSY | RTSX_HAIMR_WRITE |
1391926ce35aSJung-uk Kim 		(uint32_t)(((addr & 0x3FFF) << 16) |
13929b261d2eSHenri Hennebert 			   (mask << 8) | val);
13939b261d2eSHenri Hennebert 	WRITE4(sc, RTSX_HAIMR, arg);
1394926ce35aSJung-uk Kim 
1395926ce35aSJung-uk Kim 	while (tries--) {
1396926ce35aSJung-uk Kim 		reg = READ4(sc, RTSX_HAIMR);
1397926ce35aSJung-uk Kim 		if (!(reg & RTSX_HAIMR_BUSY)) {
13989b261d2eSHenri Hennebert 			if (val != (reg & 0xff)) {
13999b261d2eSHenri Hennebert 				device_printf(sc->rtsx_dev, "rtsx_write(0x%x) error reg=0x%x\n", arg, reg);
1400926ce35aSJung-uk Kim 				return (EIO);
14019b261d2eSHenri Hennebert 			}
1402926ce35aSJung-uk Kim 			return (0);
1403926ce35aSJung-uk Kim 		}
1404926ce35aSJung-uk Kim 	}
14059b261d2eSHenri Hennebert 	device_printf(sc->rtsx_dev, "rtsx_write(0x%x) timeout\n", arg);
1406926ce35aSJung-uk Kim 
1407926ce35aSJung-uk Kim 	return (ETIMEDOUT);
1408926ce35aSJung-uk Kim }
1409926ce35aSJung-uk Kim 
1410926ce35aSJung-uk Kim static int
1411926ce35aSJung-uk Kim rtsx_read_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t *val)
1412926ce35aSJung-uk Kim {
1413926ce35aSJung-uk Kim 	int	tries = 100000;
1414926ce35aSJung-uk Kim 	uint8_t	data0, data1, rwctl;
1415926ce35aSJung-uk Kim 
1416926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PHY_ADDR, addr);
1417926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PHY_RWCTL, RTSX_PHY_BUSY | RTSX_PHY_READ);
1418926ce35aSJung-uk Kim 
1419926ce35aSJung-uk Kim 	while (tries--) {
1420926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_PHY_RWCTL, &rwctl);
1421926ce35aSJung-uk Kim 		if (!(rwctl & RTSX_PHY_BUSY))
1422926ce35aSJung-uk Kim 			break;
1423926ce35aSJung-uk Kim 	}
1424926ce35aSJung-uk Kim 	if (tries == 0)
1425926ce35aSJung-uk Kim 		return (ETIMEDOUT);
1426926ce35aSJung-uk Kim 
1427926ce35aSJung-uk Kim 	RTSX_READ(sc, RTSX_PHY_DATA0, &data0);
1428926ce35aSJung-uk Kim 	RTSX_READ(sc, RTSX_PHY_DATA1, &data1);
1429926ce35aSJung-uk Kim 	*val = data1 << 8 | data0;
1430926ce35aSJung-uk Kim 
1431926ce35aSJung-uk Kim 	return (0);
1432926ce35aSJung-uk Kim }
1433926ce35aSJung-uk Kim 
1434926ce35aSJung-uk Kim static int
1435926ce35aSJung-uk Kim rtsx_write_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t val)
1436926ce35aSJung-uk Kim {
1437926ce35aSJung-uk Kim 	int	tries = 100000;
1438926ce35aSJung-uk Kim 	uint8_t	rwctl;
1439926ce35aSJung-uk Kim 
1440926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PHY_DATA0, val);
1441926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PHY_DATA1, val >> 8);
1442926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PHY_ADDR, addr);
1443926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_PHY_RWCTL, RTSX_PHY_BUSY | RTSX_PHY_WRITE);
1444926ce35aSJung-uk Kim 
1445926ce35aSJung-uk Kim 	while (tries--) {
1446926ce35aSJung-uk Kim 		RTSX_READ(sc, RTSX_PHY_RWCTL, &rwctl);
1447926ce35aSJung-uk Kim 		if (!(rwctl & RTSX_PHY_BUSY))
1448926ce35aSJung-uk Kim 			break;
1449926ce35aSJung-uk Kim 	}
1450926ce35aSJung-uk Kim 
1451926ce35aSJung-uk Kim 	return ((tries == 0) ? ETIMEDOUT : 0);
1452926ce35aSJung-uk Kim }
1453926ce35aSJung-uk Kim 
1454926ce35aSJung-uk Kim /*
1455926ce35aSJung-uk Kim  * Notice that the meaning of RTSX_PWR_GATE_CTRL changes between RTS5209 and
1456926ce35aSJung-uk Kim  * RTS5229. In RTS5209 it is a mask of disabled power gates, while in RTS5229
1457926ce35aSJung-uk Kim  * it is a mask of *enabled* gates.
1458926ce35aSJung-uk Kim  */
1459926ce35aSJung-uk Kim static int
1460926ce35aSJung-uk Kim rtsx_bus_power_off(struct rtsx_softc *sc)
1461926ce35aSJung-uk Kim {
1462577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
1463926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_bus_power_off()\n");
1464926ce35aSJung-uk Kim 
1465926ce35aSJung-uk Kim 	/* Disable SD clock. */
1466926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_CARD_CLK_EN, RTSX_SD_CLK_EN);
1467926ce35aSJung-uk Kim 
1468926ce35aSJung-uk Kim 	/* Disable SD output. */
1469926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN);
1470926ce35aSJung-uk Kim 
1471926ce35aSJung-uk Kim 	/* Turn off power. */
1472926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
1473926ce35aSJung-uk Kim 	case RTSX_RTS5209:
1474926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK | RTSX_PMOS_STRG_MASK,
1475926ce35aSJung-uk Kim 			   RTSX_SD_PWR_OFF | RTSX_PMOS_STRG_400mA);
1476926ce35aSJung-uk Kim 		RTSX_SET(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_OFF);
1477926ce35aSJung-uk Kim 		break;
1478926ce35aSJung-uk Kim 	case RTSX_RTS5227:
1479926ce35aSJung-uk Kim 	case RTSX_RTS5229:
1480926ce35aSJung-uk Kim 	case RTSX_RTS522A:
1481926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK | RTSX_PMOS_STRG_MASK,
1482926ce35aSJung-uk Kim 			   RTSX_SD_PWR_OFF | RTSX_PMOS_STRG_400mA);
1483926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK);
1484926ce35aSJung-uk Kim 		break;
1485577130e5SHenri Hennebert 	case RTSX_RTS5260:
14868290c144SHenri Hennebert 		rtsx_stop_cmd(sc);
14878290c144SHenri Hennebert 		/* Switch vccq to 330 */
14888290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_DV331812_VDD1, RTSX_DV331812_VDD1);
14898290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_DV18_CFG, RTSX_DV331812_MASK, RTSX_DV331812_33);
14908290c144SHenri Hennebert 		RTSX_CLR(sc, RTSX_SD_PAD_CTL, RTSX_SD_IO_USING_1V8);
14918290c144SHenri Hennebert 		rtsx_rts5260_fill_driving(sc);
14928290c144SHenri Hennebert 
1493577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_VCC_CFG1, RTSX_LDO_POW_SDVDD1_MASK, RTSX_LDO_POW_SDVDD1_OFF);
1494577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_DV331812_POWERON, RTSX_DV331812_POWEROFF);
1495577130e5SHenri Hennebert 		break;
1496926ce35aSJung-uk Kim 	case RTSX_RTL8402:
1497926ce35aSJung-uk Kim 	case RTSX_RTL8411:
1498926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
1499926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK,
1500926ce35aSJung-uk Kim 			   RTSX_BPP_POWER_OFF);
1501926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_CTL, RTSX_BPP_LDO_POWB,
1502926ce35aSJung-uk Kim 			   RTSX_BPP_LDO_SUSPEND);
1503926ce35aSJung-uk Kim 		break;
1504926ce35aSJung-uk Kim 	default:
1505926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK);
1506926ce35aSJung-uk Kim 		RTSX_SET(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_OFF);
1507926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CARD_PWR_CTL, RTSX_PMOS_STRG_800mA);
1508926ce35aSJung-uk Kim 		break;
1509926ce35aSJung-uk Kim 	}
1510926ce35aSJung-uk Kim 
1511926ce35aSJung-uk Kim 	/* Disable pull control. */
1512926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
1513926ce35aSJung-uk Kim 	case RTSX_RTS5209:
1514926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, RTSX_PULL_CTL_DISABLE12);
1515926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12);
1516926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3);
1517926ce35aSJung-uk Kim 		break;
1518926ce35aSJung-uk Kim 	case RTSX_RTS5227:
1519926ce35aSJung-uk Kim 	case RTSX_RTS522A:
1520926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12);
1521926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3);
1522926ce35aSJung-uk Kim 		break;
1523926ce35aSJung-uk Kim 	case RTSX_RTS5229:
1524926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12);
1525926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_VERSION_C)
1526926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3_TYPE_C);
1527926ce35aSJung-uk Kim 		else
1528926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3);
1529926ce35aSJung-uk Kim 		break;
1530926ce35aSJung-uk Kim 	case RTSX_RTS525A:
1531926ce35aSJung-uk Kim 	case RTSX_RTS5249:
1532577130e5SHenri Hennebert 	case RTSX_RTS5260:
1533926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x66);
1534926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12);
1535926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3);
1536926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x55);
1537926ce35aSJung-uk Kim 		break;
1538926ce35aSJung-uk Kim 	case RTSX_RTL8402:
1539926ce35aSJung-uk Kim 	case RTSX_RTL8411:
1540926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x65);
1541926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0x55);
1542926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0x95);
1543926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x09);
1544926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x05);
1545926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x04);
1546926ce35aSJung-uk Kim 		break;
1547926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
1548926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_8411B_QFN48) {
1549926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0x55);
1550926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xf5);
1551926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x15);
1552926ce35aSJung-uk Kim 		} else {
1553926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x65);
1554926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0x55);
1555926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xd5);
1556926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x59);
1557926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x55);
1558926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x15);
1559926ce35aSJung-uk Kim 		}
1560926ce35aSJung-uk Kim 		break;
1561926ce35aSJung-uk Kim 	}
1562926ce35aSJung-uk Kim 
1563926ce35aSJung-uk Kim 	return (0);
1564926ce35aSJung-uk Kim }
1565926ce35aSJung-uk Kim 
1566926ce35aSJung-uk Kim static int
1567926ce35aSJung-uk Kim rtsx_bus_power_on(struct rtsx_softc *sc)
1568926ce35aSJung-uk Kim {
1569577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
1570926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_bus_power_on()\n");
1571926ce35aSJung-uk Kim 
1572926ce35aSJung-uk Kim 	/* Select SD card. */
1573926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CARD_SELECT, 0x07, RTSX_SD_MOD_SEL);
1574926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CARD_SHARE_MODE, RTSX_CARD_SHARE_MASK, RTSX_CARD_SHARE_48_SD);
1575926ce35aSJung-uk Kim 
1576926ce35aSJung-uk Kim 	/* Enable SD clock. */
1577926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CARD_CLK_EN, RTSX_SD_CLK_EN,  RTSX_SD_CLK_EN);
1578926ce35aSJung-uk Kim 
1579926ce35aSJung-uk Kim 	/* Enable pull control. */
1580926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
1581926ce35aSJung-uk Kim 	case RTSX_RTS5209:
1582926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, RTSX_PULL_CTL_ENABLE12);
1583926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12);
1584926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3);
1585926ce35aSJung-uk Kim 		break;
1586926ce35aSJung-uk Kim 	case RTSX_RTS5227:
1587926ce35aSJung-uk Kim 	case RTSX_RTS522A:
1588926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12);
1589926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3);
1590926ce35aSJung-uk Kim 		break;
1591926ce35aSJung-uk Kim 	case RTSX_RTS5229:
1592926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12);
1593926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_VERSION_C)
1594926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3_TYPE_C);
1595926ce35aSJung-uk Kim 		else
1596926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3);
1597926ce35aSJung-uk Kim 		break;
1598926ce35aSJung-uk Kim 	case RTSX_RTS525A:
1599926ce35aSJung-uk Kim 	case RTSX_RTS5249:
1600577130e5SHenri Hennebert 	case RTSX_RTS5260:
1601926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x66);
1602926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12);
1603926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3);
1604926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0xaa);
1605926ce35aSJung-uk Kim 		break;
1606926ce35aSJung-uk Kim 	case RTSX_RTL8402:
1607926ce35aSJung-uk Kim 	case RTSX_RTL8411:
1608926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0xaa);
1609926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0xaa);
1610926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xa9);
1611926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x09);
1612926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x09);
1613926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x04);
1614926ce35aSJung-uk Kim 		break;
1615926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
1616926ce35aSJung-uk Kim 		if (sc->rtsx_flags & RTSX_F_8411B_QFN48) {
1617926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0xaa);
1618926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xf9);
1619926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x19);
1620926ce35aSJung-uk Kim 		} else {
1621926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0xaa);
1622926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0xaa);
1623926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xd9);
1624926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x59);
1625926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x55);
1626926ce35aSJung-uk Kim 			RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x15);
1627926ce35aSJung-uk Kim 		}
1628926ce35aSJung-uk Kim 		break;
1629926ce35aSJung-uk Kim 	}
1630926ce35aSJung-uk Kim 
1631926ce35aSJung-uk Kim 	/*
1632926ce35aSJung-uk Kim 	 * To avoid a current peak, enable card power in two phases
1633926ce35aSJung-uk Kim 	 * with a delay in between.
1634926ce35aSJung-uk Kim 	 */
1635926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
1636926ce35aSJung-uk Kim 	case RTSX_RTS5209:
1637926ce35aSJung-uk Kim 		/* Partial power. */
1638926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON);
1639926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC2);
1640926ce35aSJung-uk Kim 
1641926ce35aSJung-uk Kim 		DELAY(200);
1642926ce35aSJung-uk Kim 
1643926ce35aSJung-uk Kim 		/* Full power. */
1644926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON);
1645926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_ON);
1646926ce35aSJung-uk Kim 		break;
1647926ce35aSJung-uk Kim 	case RTSX_RTS5227:
1648926ce35aSJung-uk Kim 	case RTSX_RTS522A:
1649926ce35aSJung-uk Kim 		/* Partial power. */
1650926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON);
1651926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC1);
1652926ce35aSJung-uk Kim 
16539d3bc163SHenri Hennebert 		DELAY(20000);
1654926ce35aSJung-uk Kim 
1655926ce35aSJung-uk Kim 		/* Full power. */
1656926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON);
1657926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK,
1658926ce35aSJung-uk Kim 			   RTSX_LDO3318_VCC1 | RTSX_LDO3318_VCC2);
1659926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN, RTSX_SD_OUTPUT_EN);
1660926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_OE, RTSX_MS_OUTPUT_EN, RTSX_MS_OUTPUT_EN);
1661926ce35aSJung-uk Kim 		break;
1662926ce35aSJung-uk Kim 	case RTSX_RTS5229:
1663926ce35aSJung-uk Kim 		/* Partial power. */
1664926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON);
1665926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC1);
1666926ce35aSJung-uk Kim 
1667926ce35aSJung-uk Kim 		DELAY(200);
1668926ce35aSJung-uk Kim 
1669926ce35aSJung-uk Kim 		/* Full power. */
1670926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON);
1671926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK,
1672926ce35aSJung-uk Kim 			   RTSX_LDO3318_VCC1 | RTSX_LDO3318_VCC2);
1673926ce35aSJung-uk Kim 		break;
1674926ce35aSJung-uk Kim 	case RTSX_RTS525A:
1675926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_VCC_CFG1, RTSX_LDO_VCC_TUNE_MASK, RTSX_LDO_VCC_3V3);
1676926ce35aSJung-uk Kim 	case RTSX_RTS5249:
1677926ce35aSJung-uk Kim 		/* Partial power. */
1678926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON);
1679926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC1);
1680926ce35aSJung-uk Kim 
16819d3bc163SHenri Hennebert 		DELAY(5000);
1682926ce35aSJung-uk Kim 
1683926ce35aSJung-uk Kim 		/* Full power. */
1684926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON);
1685926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK,
1686926ce35aSJung-uk Kim 			   RTSX_LDO3318_VCC1 | RTSX_LDO3318_VCC2);
1687926ce35aSJung-uk Kim 		break;
1688577130e5SHenri Hennebert 	case RTSX_RTS5260:
1689577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_DV331812_VDD1, RTSX_DV331812_VDD1);
1690577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_VCC_CFG0, RTSX_RTS5260_DVCC_TUNE_MASK, RTSX_RTS5260_DVCC_33);
1691577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_VCC_CFG1, RTSX_LDO_POW_SDVDD1_MASK, RTSX_LDO_POW_SDVDD1_ON);
1692577130e5SHenri Hennebert 		RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_DV331812_POWERON, RTSX_DV331812_POWERON);
1693577130e5SHenri Hennebert 
1694577130e5SHenri Hennebert 		DELAY(20000);
1695577130e5SHenri Hennebert 
16968290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_SD_MODE_MASK | RTSX_SD_ASYNC_FIFO_NOT_RST,
16978290c144SHenri Hennebert 			   RTSX_SD30_MODE | RTSX_SD_ASYNC_FIFO_NOT_RST);
16988290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, RTSX_CLK_LOW_FREQ);
16998290c144SHenri Hennebert 		RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE,
17008290c144SHenri Hennebert 			   RTSX_CRC_VAR_CLK0 | RTSX_SD30_FIX_CLK | RTSX_SAMPLE_VAR_CLK1);
17018290c144SHenri Hennebert 		RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ);
17028290c144SHenri Hennebert 
1703577130e5SHenri Hennebert 		/* Initialize SD_CFG1 register */
1704577130e5SHenri Hennebert 		RTSX_WRITE(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_128 | RTSX_SD20_MODE);
1705577130e5SHenri Hennebert 		RTSX_WRITE(sc, RTSX_SD_SAMPLE_POINT_CTL, RTSX_SD20_RX_POS_EDGE);
1706577130e5SHenri Hennebert 		RTSX_CLR(sc, RTSX_SD_PUSH_POINT_CTL, 0xff);
17078290c144SHenri Hennebert 		RTSX_BITOP(sc, RTSX_CARD_STOP, RTSX_SD_STOP | RTSX_SD_CLR_ERR,
17088290c144SHenri Hennebert 			   RTSX_SD_STOP | RTSX_SD_CLR_ERR);
1709577130e5SHenri Hennebert 		/* Reset SD_CFG3 register */
1710577130e5SHenri Hennebert 		RTSX_CLR(sc, RTSX_SD_CFG3, RTSX_SD30_CLK_END_EN);
1711577130e5SHenri Hennebert 		RTSX_CLR(sc, RTSX_REG_SD_STOP_SDCLK_CFG,
1712577130e5SHenri Hennebert 			 RTSX_SD30_CLK_STOP_CFG_EN | RTSX_SD30_CLK_STOP_CFG0 | RTSX_SD30_CLK_STOP_CFG1);
1713577130e5SHenri Hennebert 		RTSX_CLR(sc, RTSX_REG_PRE_RW_MODE, RTSX_EN_INFINITE_MODE);
1714577130e5SHenri Hennebert 		break;
1715926ce35aSJung-uk Kim 	case RTSX_RTL8402:
1716926ce35aSJung-uk Kim 	case RTSX_RTL8411:
1717926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
1718926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK,
1719926ce35aSJung-uk Kim 			   RTSX_BPP_POWER_5_PERCENT_ON);
1720926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_CTL, RTSX_BPP_LDO_POWB,
1721926ce35aSJung-uk Kim 			   RTSX_BPP_LDO_SUSPEND);
1722926ce35aSJung-uk Kim 		DELAY(150);
1723926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK,
1724926ce35aSJung-uk Kim 			   RTSX_BPP_POWER_10_PERCENT_ON);
1725926ce35aSJung-uk Kim 		DELAY(150);
1726926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK,
1727926ce35aSJung-uk Kim 			   RTSX_BPP_POWER_15_PERCENT_ON);
1728926ce35aSJung-uk Kim 		DELAY(150);
1729926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK,
1730926ce35aSJung-uk Kim 			   RTSX_BPP_POWER_ON);
1731926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_LDO_CTL, RTSX_BPP_LDO_POWB,
1732926ce35aSJung-uk Kim 			   RTSX_BPP_LDO_ON);
1733926ce35aSJung-uk Kim 		break;
1734926ce35aSJung-uk Kim 	}
1735926ce35aSJung-uk Kim 
1736926ce35aSJung-uk Kim 	/* Enable SD card output. */
1737926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN);
1738926ce35aSJung-uk Kim 
1739926ce35aSJung-uk Kim 	DELAY(200);
1740926ce35aSJung-uk Kim 
1741926ce35aSJung-uk Kim 	return (0);
1742926ce35aSJung-uk Kim }
1743926ce35aSJung-uk Kim 
1744926ce35aSJung-uk Kim /*
1745926ce35aSJung-uk Kim  * Set but width.
1746926ce35aSJung-uk Kim  */
1747926ce35aSJung-uk Kim static int
1748926ce35aSJung-uk Kim rtsx_set_bus_width(struct rtsx_softc *sc, enum mmc_bus_width width)
1749926ce35aSJung-uk Kim {
1750926ce35aSJung-uk Kim 	uint32_t bus_width;
1751926ce35aSJung-uk Kim 
1752926ce35aSJung-uk Kim 	switch (width) {
1753926ce35aSJung-uk Kim 	case bus_width_1:
1754926ce35aSJung-uk Kim 		bus_width = RTSX_BUS_WIDTH_1;
1755926ce35aSJung-uk Kim 		break;
1756926ce35aSJung-uk Kim 	case bus_width_4:
1757926ce35aSJung-uk Kim 		bus_width = RTSX_BUS_WIDTH_4;
1758926ce35aSJung-uk Kim 		break;
1759926ce35aSJung-uk Kim 	case bus_width_8:
1760926ce35aSJung-uk Kim 		bus_width = RTSX_BUS_WIDTH_8;
1761926ce35aSJung-uk Kim 		break;
1762926ce35aSJung-uk Kim 	default:
1763926ce35aSJung-uk Kim 		return (MMC_ERR_INVALID);
1764926ce35aSJung-uk Kim 	}
1765926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_BUS_WIDTH_MASK, bus_width);
1766926ce35aSJung-uk Kim 
1767577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
1768926ce35aSJung-uk Kim 		char *busw[] = {
1769926ce35aSJung-uk Kim 				"1 bit",
1770926ce35aSJung-uk Kim 				"4 bits",
1771926ce35aSJung-uk Kim 				"8 bits"
1772926ce35aSJung-uk Kim 		};
1773926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Setting bus width to %s\n", busw[bus_width]);
1774926ce35aSJung-uk Kim 	}
1775926ce35aSJung-uk Kim 	return (0);
1776926ce35aSJung-uk Kim }
1777926ce35aSJung-uk Kim 
1778926ce35aSJung-uk Kim static int
1779926ce35aSJung-uk Kim rtsx_set_sd_timing(struct rtsx_softc *sc, enum mmc_bus_timing timing)
1780926ce35aSJung-uk Kim {
1781926ce35aSJung-uk Kim 	if (timing == bus_timing_hs && sc->rtsx_force_timing) {
1782926ce35aSJung-uk Kim 		timing = bus_timing_uhs_sdr50;
1783926ce35aSJung-uk Kim 		sc->rtsx_ios_timing = timing;
1784926ce35aSJung-uk Kim 	}
1785926ce35aSJung-uk Kim 
1786577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
1787926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_set_sd_timing(%u)\n", timing);
1788926ce35aSJung-uk Kim 
1789926ce35aSJung-uk Kim 	switch (timing) {
1790926ce35aSJung-uk Kim 	case bus_timing_uhs_sdr50:
1791926ce35aSJung-uk Kim 	case bus_timing_uhs_sdr104:
1792926ce35aSJung-uk Kim 		sc->rtsx_double_clk = false;
1793926ce35aSJung-uk Kim 		sc->rtsx_vpclk = true;
1794926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_CFG1, 0x0c | RTSX_SD_ASYNC_FIFO_NOT_RST,
1795926ce35aSJung-uk Kim 			   RTSX_SD30_MODE | RTSX_SD_ASYNC_FIFO_NOT_RST);
1796926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ);
1797926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE,
1798926ce35aSJung-uk Kim 			   RTSX_CRC_VAR_CLK0 | RTSX_SD30_FIX_CLK | RTSX_SAMPLE_VAR_CLK1);
1799926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ);
1800926ce35aSJung-uk Kim 		break;
1801926ce35aSJung-uk Kim 	case bus_timing_hs:
1802926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_SD_MODE_MASK, RTSX_SD20_MODE);
1803926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ);
1804926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE,
1805926ce35aSJung-uk Kim 			   RTSX_CRC_FIX_CLK | RTSX_SD30_VAR_CLK0 | RTSX_SAMPLE_VAR_CLK1);
1806926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ);
1807926ce35aSJung-uk Kim 
1808926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_PUSH_POINT_CTL,
1809926ce35aSJung-uk Kim 			   RTSX_SD20_TX_SEL_MASK, RTSX_SD20_TX_14_AHEAD);
1810926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_SAMPLE_POINT_CTL,
1811926ce35aSJung-uk Kim 			   RTSX_SD20_RX_SEL_MASK, RTSX_SD20_RX_14_DELAY);
1812926ce35aSJung-uk Kim 		break;
1813926ce35aSJung-uk Kim 	default:
1814926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_SD_MODE_MASK, RTSX_SD20_MODE);
1815926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ);
1816926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE,
1817926ce35aSJung-uk Kim 			   RTSX_CRC_FIX_CLK | RTSX_SD30_VAR_CLK0 | RTSX_SAMPLE_VAR_CLK1);
1818926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ);
1819926ce35aSJung-uk Kim 
1820926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_SD_PUSH_POINT_CTL, RTSX_SD20_TX_NEG_EDGE);
1821926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_SAMPLE_POINT_CTL,
1822926ce35aSJung-uk Kim 			   RTSX_SD20_RX_SEL_MASK, RTSX_SD20_RX_POS_EDGE);
1823926ce35aSJung-uk Kim 		break;
1824926ce35aSJung-uk Kim 	}
1825926ce35aSJung-uk Kim 
1826926ce35aSJung-uk Kim 	return (0);
1827926ce35aSJung-uk Kim }
1828926ce35aSJung-uk Kim 
1829926ce35aSJung-uk Kim /*
1830926ce35aSJung-uk Kim  * Set or change SDCLK frequency or disable the SD clock.
1831926ce35aSJung-uk Kim  * Return zero on success.
1832926ce35aSJung-uk Kim  */
1833926ce35aSJung-uk Kim static int
1834926ce35aSJung-uk Kim rtsx_set_sd_clock(struct rtsx_softc *sc, uint32_t freq)
1835926ce35aSJung-uk Kim {
1836926ce35aSJung-uk Kim 	uint8_t	clk;
1837926ce35aSJung-uk Kim 	uint8_t	clk_divider, n, div, mcu;
1838926ce35aSJung-uk Kim 	int	error = 0;
1839926ce35aSJung-uk Kim 
1840577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
1841926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_set_sd_clock(%u)\n", freq);
1842926ce35aSJung-uk Kim 
1843926ce35aSJung-uk Kim 	if (freq == RTSX_SDCLK_OFF) {
1844926ce35aSJung-uk Kim 		error = rtsx_stop_sd_clock(sc);
1845926ce35aSJung-uk Kim 		return error;
1846926ce35aSJung-uk Kim 	}
1847926ce35aSJung-uk Kim 
1848926ce35aSJung-uk Kim 	sc->rtsx_ssc_depth = RTSX_SSC_DEPTH_500K;
1849926ce35aSJung-uk Kim 	sc->rtsx_discovery_mode = (freq <= 1000000) ? true : false;
1850926ce35aSJung-uk Kim 
1851926ce35aSJung-uk Kim 	if (sc->rtsx_discovery_mode) {
1852926ce35aSJung-uk Kim 		/* We use 250k(around) here, in discovery stage. */
1853926ce35aSJung-uk Kim 		clk_divider = RTSX_CLK_DIVIDE_128;
1854926ce35aSJung-uk Kim 		freq = 30000000;
1855926ce35aSJung-uk Kim 	} else {
1856926ce35aSJung-uk Kim 		clk_divider = RTSX_CLK_DIVIDE_0;
1857926ce35aSJung-uk Kim 	}
1858926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, clk_divider);
1859926ce35aSJung-uk Kim 
1860926ce35aSJung-uk Kim 	freq /= 1000000;
1861926ce35aSJung-uk Kim 	if (sc->rtsx_discovery_mode || !sc->rtsx_double_clk)
1862926ce35aSJung-uk Kim 		clk = freq;
1863926ce35aSJung-uk Kim 	else
1864926ce35aSJung-uk Kim 		clk = freq * 2;
1865926ce35aSJung-uk Kim 
1866926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
1867926ce35aSJung-uk Kim 	case RTSX_RTL8402:
1868926ce35aSJung-uk Kim 	case RTSX_RTL8411:
1869926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
1870926ce35aSJung-uk Kim 		n = clk * 4 / 5 - 2;
1871926ce35aSJung-uk Kim 		break;
1872926ce35aSJung-uk Kim 	default:
1873926ce35aSJung-uk Kim 		n = clk - 2;
1874926ce35aSJung-uk Kim 		break;
1875926ce35aSJung-uk Kim 	}
1876926ce35aSJung-uk Kim 	if ((clk <= 2) || (n > RTSX_MAX_DIV_N))
1877926ce35aSJung-uk Kim 		return (MMC_ERR_INVALID);
1878926ce35aSJung-uk Kim 
1879926ce35aSJung-uk Kim 	mcu = 125 / clk + 3;
1880926ce35aSJung-uk Kim 	if (mcu > 15)
1881926ce35aSJung-uk Kim 		mcu = 15;
1882926ce35aSJung-uk Kim 
1883926ce35aSJung-uk Kim 	/* Make sure that the SSC clock div_n is not less than RTSX_MIN_DIV_N. */
1884926ce35aSJung-uk Kim 	div = RTSX_CLK_DIV_1;
1885926ce35aSJung-uk Kim 	while ((n < RTSX_MIN_DIV_N) && (div < RTSX_CLK_DIV_8)) {
1886926ce35aSJung-uk Kim 		switch (sc->rtsx_device_id) {
1887926ce35aSJung-uk Kim 		case RTSX_RTL8402:
1888926ce35aSJung-uk Kim 		case RTSX_RTL8411:
1889926ce35aSJung-uk Kim 		case RTSX_RTL8411B:
1890926ce35aSJung-uk Kim 			n = (((n + 2) * 5 / 4) * 2) * 4 / 5 - 2;
1891926ce35aSJung-uk Kim 			break;
1892926ce35aSJung-uk Kim 		default:
1893926ce35aSJung-uk Kim 			n = (n + 2) * 2 - 2;
1894926ce35aSJung-uk Kim 			break;
1895926ce35aSJung-uk Kim 		}
1896926ce35aSJung-uk Kim 		div++;
1897926ce35aSJung-uk Kim 	}
1898926ce35aSJung-uk Kim 
1899926ce35aSJung-uk Kim 	if (sc->rtsx_double_clk && sc->rtsx_ssc_depth > 1)
1900926ce35aSJung-uk Kim 		sc->rtsx_ssc_depth -= 1;
1901926ce35aSJung-uk Kim 
1902926ce35aSJung-uk Kim 	if (div > RTSX_CLK_DIV_1) {
1903926ce35aSJung-uk Kim 		if (sc->rtsx_ssc_depth > (div - 1))
1904926ce35aSJung-uk Kim 			sc->rtsx_ssc_depth -= (div - 1);
1905926ce35aSJung-uk Kim 		else
1906926ce35aSJung-uk Kim 			sc->rtsx_ssc_depth = RTSX_SSC_DEPTH_4M;
1907926ce35aSJung-uk Kim 	}
1908926ce35aSJung-uk Kim 
1909926ce35aSJung-uk Kim 	/* Enable SD clock. */
1910926ce35aSJung-uk Kim 	error = rtsx_switch_sd_clock(sc, clk, n, div, mcu);
1911926ce35aSJung-uk Kim 
1912926ce35aSJung-uk Kim 	return (error);
1913926ce35aSJung-uk Kim }
1914926ce35aSJung-uk Kim 
1915926ce35aSJung-uk Kim static int
1916926ce35aSJung-uk Kim rtsx_stop_sd_clock(struct rtsx_softc *sc)
1917926ce35aSJung-uk Kim {
1918926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_CARD_CLK_EN, RTSX_CARD_CLK_EN_ALL);
1919926ce35aSJung-uk Kim 	RTSX_SET(sc, RTSX_SD_BUS_STAT, RTSX_SD_CLK_FORCE_STOP);
1920926ce35aSJung-uk Kim 
1921926ce35aSJung-uk Kim 	return (0);
1922926ce35aSJung-uk Kim }
1923926ce35aSJung-uk Kim 
1924926ce35aSJung-uk Kim static int
1925926ce35aSJung-uk Kim rtsx_switch_sd_clock(struct rtsx_softc *sc, uint8_t clk, uint8_t n, uint8_t div, uint8_t mcu)
1926926ce35aSJung-uk Kim {
1927577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC) {
1928926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_switch_sd_clock() - discovery-mode is %s, ssc_depth: %d\n",
1929926ce35aSJung-uk Kim 			      (sc->rtsx_discovery_mode) ? "true" : "false", sc->rtsx_ssc_depth);
1930926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_switch_sd_clock() - clk: %d, n: %d, div: %d, mcu: %d\n",
1931926ce35aSJung-uk Kim 			      clk, n, div, mcu);
1932926ce35aSJung-uk Kim 	}
1933926ce35aSJung-uk Kim 
1934926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ);
1935926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_CLK_DIV, (div << 4) | mcu);
1936926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_SSC_CTL1, RTSX_RSTB);
1937926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_SSC_CTL2, RTSX_SSC_DEPTH_MASK, sc->rtsx_ssc_depth);
1938926ce35aSJung-uk Kim 	RTSX_WRITE(sc, RTSX_SSC_DIV_N_0, n);
1939926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_SSC_CTL1, RTSX_RSTB, RTSX_RSTB);
1940926ce35aSJung-uk Kim 	if (sc->rtsx_vpclk) {
1941926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET);
1942926ce35aSJung-uk Kim 		RTSX_BITOP(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET, RTSX_PHASE_NOT_RESET);
1943926ce35aSJung-uk Kim 	}
1944926ce35aSJung-uk Kim 
1945926ce35aSJung-uk Kim 	/* Wait SSC clock stable. */
1946926ce35aSJung-uk Kim 	DELAY(200);
1947926ce35aSJung-uk Kim 
1948926ce35aSJung-uk Kim 	RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ);
1949926ce35aSJung-uk Kim 
1950926ce35aSJung-uk Kim 	return (0);
1951926ce35aSJung-uk Kim }
1952926ce35aSJung-uk Kim 
19538e9740b6SHenri Hennebert #ifndef MMCCAM
1954926ce35aSJung-uk Kim static void
1955926ce35aSJung-uk Kim rtsx_sd_change_tx_phase(struct rtsx_softc *sc, uint8_t sample_point)
1956926ce35aSJung-uk Kim {
1957577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
1958926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_sd_change_tx_phase() - sample_point: %d\n", sample_point);
1959926ce35aSJung-uk Kim 
1960926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, RTSX_CHANGE_CLK);
1961926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_SELECT_MASK, sample_point);
1962926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET, 0);
1963926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET, RTSX_PHASE_NOT_RESET);
1964926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, 0);
1965926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_CFG1, RTSX_SD_ASYNC_FIFO_NOT_RST, 0);
1966926ce35aSJung-uk Kim }
1967926ce35aSJung-uk Kim 
1968926ce35aSJung-uk Kim static void
1969926ce35aSJung-uk Kim rtsx_sd_change_rx_phase(struct rtsx_softc *sc, uint8_t sample_point)
1970926ce35aSJung-uk Kim {
1971577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_TUNING)
1972926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_sd_change_rx_phase() - sample_point: %d\n", sample_point);
1973926ce35aSJung-uk Kim 
1974926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, RTSX_CHANGE_CLK);
1975926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_VPCLK1_CTL, RTSX_PHASE_SELECT_MASK, sample_point);
1976926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_VPCLK1_CTL, RTSX_PHASE_NOT_RESET, 0);
1977926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_VPCLK1_CTL, RTSX_PHASE_NOT_RESET, RTSX_PHASE_NOT_RESET);
1978926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, 0);
1979926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_CFG1, RTSX_SD_ASYNC_FIFO_NOT_RST, 0);
1980926ce35aSJung-uk Kim }
1981926ce35aSJung-uk Kim 
1982926ce35aSJung-uk Kim static void
1983926ce35aSJung-uk Kim rtsx_sd_tuning_rx_phase(struct rtsx_softc *sc, uint32_t *phase_map)
1984926ce35aSJung-uk Kim {
1985926ce35aSJung-uk Kim 	uint32_t raw_phase_map = 0;
1986926ce35aSJung-uk Kim 	int	 i;
1987926ce35aSJung-uk Kim 	int	 error;
1988926ce35aSJung-uk Kim 
1989926ce35aSJung-uk Kim 	for (i = 0; i < RTSX_RX_PHASE_MAX; i++) {
1990926ce35aSJung-uk Kim 		error = rtsx_sd_tuning_rx_cmd(sc, (uint8_t)i);
1991926ce35aSJung-uk Kim 		if (error == 0)
1992926ce35aSJung-uk Kim 			raw_phase_map |= 1 << i;
1993926ce35aSJung-uk Kim 	}
1994926ce35aSJung-uk Kim 	if (phase_map != NULL)
1995926ce35aSJung-uk Kim 		*phase_map = raw_phase_map;
1996926ce35aSJung-uk Kim }
1997926ce35aSJung-uk Kim 
1998926ce35aSJung-uk Kim static int
1999926ce35aSJung-uk Kim rtsx_sd_tuning_rx_cmd(struct rtsx_softc *sc, uint8_t sample_point)
2000926ce35aSJung-uk Kim {
2001926ce35aSJung-uk Kim 	struct mmc_request req = {};
2002926ce35aSJung-uk Kim 	struct mmc_command cmd = {};
2003926ce35aSJung-uk Kim 	int	error = 0;
2004926ce35aSJung-uk Kim 
2005926ce35aSJung-uk Kim 	cmd.opcode = MMC_SEND_TUNING_BLOCK;
2006926ce35aSJung-uk Kim 	cmd.arg = 0;
2007926ce35aSJung-uk Kim 	req.cmd = &cmd;
2008926ce35aSJung-uk Kim 
2009926ce35aSJung-uk Kim 	RTSX_LOCK(sc);
2010926ce35aSJung-uk Kim 
2011926ce35aSJung-uk Kim 	sc->rtsx_req = &req;
2012926ce35aSJung-uk Kim 
2013926ce35aSJung-uk Kim 	rtsx_sd_change_rx_phase(sc, sample_point);
2014926ce35aSJung-uk Kim 
2015926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_CFG3, RTSX_SD_RSP_80CLK_TIMEOUT_EN,
2016926ce35aSJung-uk Kim 		   RTSX_SD_RSP_80CLK_TIMEOUT_EN);
2017926ce35aSJung-uk Kim 
2018926ce35aSJung-uk Kim 	rtsx_init_cmd(sc, &cmd);
2019926ce35aSJung-uk Kim 	rtsx_set_cmd_data_len(sc, 1, 0x40);
2020926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff,
2021926ce35aSJung-uk Kim 		      RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC16 |
2022926ce35aSJung-uk Kim 		      RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_CHECK_CRC7 | RTSX_SD_RSP_LEN_6);
2023926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER,
2024926ce35aSJung-uk Kim 		      0xff, RTSX_TM_AUTO_TUNING | RTSX_SD_TRANSFER_START);
2025926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER,
2026926ce35aSJung-uk Kim 		      RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END);
2027926ce35aSJung-uk Kim 
2028926ce35aSJung-uk Kim 	/* Set interrupt post processing */
2029926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ok = rtsx_sd_tuning_rx_cmd_wakeup;
2030926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ko = rtsx_sd_tuning_rx_cmd_wakeup;
2031926ce35aSJung-uk Kim 
2032926ce35aSJung-uk Kim 	/* Run the command queue. */
2033926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2034926ce35aSJung-uk Kim 
2035926ce35aSJung-uk Kim 	error = rtsx_sd_tuning_rx_cmd_wait(sc, &cmd);
2036926ce35aSJung-uk Kim 
2037926ce35aSJung-uk Kim 	if (error) {
2038577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_TUNING)
2039926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "rtsx_sd_tuning_rx_cmd() - error: %d\n", error);
2040926ce35aSJung-uk Kim 		rtsx_sd_wait_data_idle(sc);
2041926ce35aSJung-uk Kim 		rtsx_clear_error(sc);
2042926ce35aSJung-uk Kim 	}
2043926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_SD_CFG3, RTSX_SD_RSP_80CLK_TIMEOUT_EN, 0);
2044926ce35aSJung-uk Kim 
2045926ce35aSJung-uk Kim 	sc->rtsx_req = NULL;
2046926ce35aSJung-uk Kim 
2047926ce35aSJung-uk Kim 	RTSX_UNLOCK(sc);
2048926ce35aSJung-uk Kim 
2049926ce35aSJung-uk Kim 	return (error);
2050926ce35aSJung-uk Kim }
2051926ce35aSJung-uk Kim 
2052926ce35aSJung-uk Kim static int
2053926ce35aSJung-uk Kim rtsx_sd_tuning_rx_cmd_wait(struct rtsx_softc *sc, struct mmc_command *cmd)
2054926ce35aSJung-uk Kim {
2055926ce35aSJung-uk Kim 	int	status;
2056926ce35aSJung-uk Kim 	int	mask = RTSX_TRANS_OK_INT | RTSX_TRANS_FAIL_INT;
2057926ce35aSJung-uk Kim 
2058926ce35aSJung-uk Kim 	status = sc->rtsx_intr_status & mask;
2059926ce35aSJung-uk Kim 	while (status == 0) {
20609d3bc163SHenri Hennebert 		if (msleep(&sc->rtsx_intr_status, &sc->rtsx_mtx, 0, "rtsxintr", sc->rtsx_timeout_cmd) == EWOULDBLOCK) {
2061926ce35aSJung-uk Kim 			cmd->error = MMC_ERR_TIMEOUT;
2062926ce35aSJung-uk Kim 			return (MMC_ERR_TIMEOUT);
2063926ce35aSJung-uk Kim 		}
2064926ce35aSJung-uk Kim 		status = sc->rtsx_intr_status & mask;
2065926ce35aSJung-uk Kim 	}
2066926ce35aSJung-uk Kim 	return (cmd->error);
2067926ce35aSJung-uk Kim }
2068926ce35aSJung-uk Kim 
2069926ce35aSJung-uk Kim static void
2070926ce35aSJung-uk Kim rtsx_sd_tuning_rx_cmd_wakeup(struct rtsx_softc *sc)
2071926ce35aSJung-uk Kim {
2072926ce35aSJung-uk Kim 	wakeup(&sc->rtsx_intr_status);
2073926ce35aSJung-uk Kim }
2074926ce35aSJung-uk Kim 
2075926ce35aSJung-uk Kim static void
2076926ce35aSJung-uk Kim rtsx_sd_wait_data_idle(struct rtsx_softc *sc)
2077926ce35aSJung-uk Kim {
2078926ce35aSJung-uk Kim 	int	i;
2079926ce35aSJung-uk Kim 	uint8_t	val;
2080926ce35aSJung-uk Kim 
2081926ce35aSJung-uk Kim 	for (i = 0; i < 100; i++) {
2082926ce35aSJung-uk Kim 		rtsx_read(sc, RTSX_SD_DATA_STATE, &val);
2083926ce35aSJung-uk Kim 		if (val & RTSX_SD_DATA_IDLE)
2084926ce35aSJung-uk Kim 			return;
2085926ce35aSJung-uk Kim 		DELAY(100);
2086926ce35aSJung-uk Kim 	}
2087926ce35aSJung-uk Kim }
2088926ce35aSJung-uk Kim 
2089926ce35aSJung-uk Kim static uint8_t
2090926ce35aSJung-uk Kim rtsx_sd_search_final_rx_phase(struct rtsx_softc *sc, uint32_t phase_map)
2091926ce35aSJung-uk Kim {
2092926ce35aSJung-uk Kim 	int	start = 0, len = 0;
2093926ce35aSJung-uk Kim 	int	start_final = 0, len_final = 0;
2094926ce35aSJung-uk Kim 	uint8_t	final_phase = 0xff;
2095926ce35aSJung-uk Kim 
2096926ce35aSJung-uk Kim 	while (start < RTSX_RX_PHASE_MAX) {
2097926ce35aSJung-uk Kim 		len = rtsx_sd_get_rx_phase_len(phase_map, start);
2098926ce35aSJung-uk Kim 		if (len_final < len) {
2099926ce35aSJung-uk Kim 			start_final = start;
2100926ce35aSJung-uk Kim 			len_final = len;
2101926ce35aSJung-uk Kim 		}
2102926ce35aSJung-uk Kim 		start += len ? len : 1;
2103926ce35aSJung-uk Kim 	}
2104926ce35aSJung-uk Kim 
2105926ce35aSJung-uk Kim 	final_phase = (start_final + len_final / 2) % RTSX_RX_PHASE_MAX;
2106926ce35aSJung-uk Kim 
2107577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
2108926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev,
2109926ce35aSJung-uk Kim 			      "rtsx_sd_search_final_rx_phase() - phase_map: %x, start_final: %d, len_final: %d, final_phase: %d\n",
2110926ce35aSJung-uk Kim 			      phase_map, start_final, len_final, final_phase);
2111926ce35aSJung-uk Kim 
2112926ce35aSJung-uk Kim 	return final_phase;
2113926ce35aSJung-uk Kim }
2114926ce35aSJung-uk Kim 
2115926ce35aSJung-uk Kim static int
2116926ce35aSJung-uk Kim rtsx_sd_get_rx_phase_len(uint32_t phase_map, int start_bit)
2117926ce35aSJung-uk Kim {
2118926ce35aSJung-uk Kim 	int	i;
2119926ce35aSJung-uk Kim 
2120926ce35aSJung-uk Kim 	for (i = 0; i < RTSX_RX_PHASE_MAX; i++) {
2121926ce35aSJung-uk Kim 		if ((phase_map & (1 << (start_bit + i) % RTSX_RX_PHASE_MAX)) == 0)
2122926ce35aSJung-uk Kim 			return i;
2123926ce35aSJung-uk Kim 	}
2124926ce35aSJung-uk Kim 	return RTSX_RX_PHASE_MAX;
2125926ce35aSJung-uk Kim }
21268e9740b6SHenri Hennebert #endif /* !MMCCAM */
2127926ce35aSJung-uk Kim 
2128926ce35aSJung-uk Kim #if 0	/* For led */
2129926ce35aSJung-uk Kim static int
2130926ce35aSJung-uk Kim rtsx_led_enable(struct rtsx_softc *sc)
2131926ce35aSJung-uk Kim {
2132926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
2133926ce35aSJung-uk Kim 	case RTSX_RTS5209:
2134926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CARD_GPIO, RTSX_CARD_GPIO_LED_OFF);
2135926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_AUTO_BLINK,
2136926ce35aSJung-uk Kim 			   RTSX_LED_BLINK_EN | RTSX_LED_BLINK_SPEED);
2137926ce35aSJung-uk Kim 		break;
2138926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
2139926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_GPIO_CTL, 0x01);
2140926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_AUTO_BLINK,
2141926ce35aSJung-uk Kim 			   RTSX_LED_BLINK_EN | RTSX_LED_BLINK_SPEED);
2142926ce35aSJung-uk Kim 		break;
2143926ce35aSJung-uk Kim 	default:
2144926ce35aSJung-uk Kim 		RTSX_SET(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON);
2145926ce35aSJung-uk Kim 		RTSX_SET(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_AUTOBLINK);
2146926ce35aSJung-uk Kim 		break;
2147926ce35aSJung-uk Kim 	}
2148926ce35aSJung-uk Kim 
2149926ce35aSJung-uk Kim 	return (0);
2150926ce35aSJung-uk Kim }
2151926ce35aSJung-uk Kim 
2152926ce35aSJung-uk Kim static int
2153926ce35aSJung-uk Kim rtsx_led_disable(struct rtsx_softc *sc)
2154926ce35aSJung-uk Kim {
2155926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
2156926ce35aSJung-uk Kim 	case RTSX_RTS5209:
2157926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CARD_AUTO_BLINK, RTSX_LED_BLINK_EN);
2158926ce35aSJung-uk Kim 		RTSX_WRITE(sc, RTSX_CARD_GPIO, RTSX_CARD_GPIO_LED_OFF);
2159926ce35aSJung-uk Kim 		break;
2160926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
2161926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_CARD_AUTO_BLINK, RTSX_LED_BLINK_EN);
2162926ce35aSJung-uk Kim 		RTSX_SET(sc, RTSX_GPIO_CTL, 0x01);
2163926ce35aSJung-uk Kim 		break;
2164926ce35aSJung-uk Kim 	default:
2165926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_AUTOBLINK);
2166926ce35aSJung-uk Kim 		RTSX_CLR(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON);
2167926ce35aSJung-uk Kim 		break;
2168926ce35aSJung-uk Kim 	}
2169926ce35aSJung-uk Kim 
2170926ce35aSJung-uk Kim 	return (0);
2171926ce35aSJung-uk Kim }
2172926ce35aSJung-uk Kim #endif	/* For led */
2173926ce35aSJung-uk Kim 
2174926ce35aSJung-uk Kim static uint8_t
2175926ce35aSJung-uk Kim rtsx_response_type(uint16_t mmc_rsp)
2176926ce35aSJung-uk Kim {
2177926ce35aSJung-uk Kim 	int	i;
2178926ce35aSJung-uk Kim 	struct rsp_type {
2179926ce35aSJung-uk Kim 		uint16_t mmc_rsp;
2180926ce35aSJung-uk Kim 		uint8_t  rtsx_rsp;
2181926ce35aSJung-uk Kim 	} rsp_types[] = {
2182926ce35aSJung-uk Kim 		{ MMC_RSP_NONE,	RTSX_SD_RSP_TYPE_R0 },
2183926ce35aSJung-uk Kim 		{ MMC_RSP_R1,	RTSX_SD_RSP_TYPE_R1 },
2184926ce35aSJung-uk Kim 		{ MMC_RSP_R1B,	RTSX_SD_RSP_TYPE_R1B },
2185926ce35aSJung-uk Kim 		{ MMC_RSP_R2,	RTSX_SD_RSP_TYPE_R2 },
2186926ce35aSJung-uk Kim 		{ MMC_RSP_R3,	RTSX_SD_RSP_TYPE_R3 },
2187926ce35aSJung-uk Kim 		{ MMC_RSP_R4,	RTSX_SD_RSP_TYPE_R4 },
2188926ce35aSJung-uk Kim 		{ MMC_RSP_R5,	RTSX_SD_RSP_TYPE_R5 },
2189926ce35aSJung-uk Kim 		{ MMC_RSP_R6,	RTSX_SD_RSP_TYPE_R6 },
2190926ce35aSJung-uk Kim 		{ MMC_RSP_R7,	RTSX_SD_RSP_TYPE_R7 }
2191926ce35aSJung-uk Kim 	};
2192926ce35aSJung-uk Kim 
2193926ce35aSJung-uk Kim 	for (i = 0; i < nitems(rsp_types); i++) {
2194926ce35aSJung-uk Kim 		if (mmc_rsp == rsp_types[i].mmc_rsp)
2195926ce35aSJung-uk Kim 			return (rsp_types[i].rtsx_rsp);
2196926ce35aSJung-uk Kim 	}
2197926ce35aSJung-uk Kim 
2198926ce35aSJung-uk Kim 	return (0);
2199926ce35aSJung-uk Kim }
2200926ce35aSJung-uk Kim 
2201926ce35aSJung-uk Kim /*
2202926ce35aSJung-uk Kim  * Init command buffer with SD command index and argument.
2203926ce35aSJung-uk Kim  */
2204926ce35aSJung-uk Kim static void
2205926ce35aSJung-uk Kim rtsx_init_cmd(struct rtsx_softc *sc, struct mmc_command *cmd)
2206926ce35aSJung-uk Kim {
2207926ce35aSJung-uk Kim 	sc->rtsx_cmd_index = 0;
2208926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD0,
2209926ce35aSJung-uk Kim 		      0xff, RTSX_SD_CMD_START  | cmd->opcode);
2210926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD1,
2211926ce35aSJung-uk Kim 		     0xff, cmd->arg >> 24);
2212926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD2,
2213926ce35aSJung-uk Kim 		      0xff, cmd->arg >> 16);
2214926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD3,
2215926ce35aSJung-uk Kim 		     0xff, cmd->arg >> 8);
2216926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD4,
2217926ce35aSJung-uk Kim 		     0xff, cmd->arg);
2218926ce35aSJung-uk Kim }
2219926ce35aSJung-uk Kim 
2220926ce35aSJung-uk Kim /*
2221926ce35aSJung-uk Kim  * Append a properly encoded host command to the host command buffer.
2222926ce35aSJung-uk Kim  */
2223926ce35aSJung-uk Kim static void
2224926ce35aSJung-uk Kim rtsx_push_cmd(struct rtsx_softc *sc, uint8_t cmd, uint16_t reg,
2225926ce35aSJung-uk Kim 	      uint8_t mask, uint8_t data)
2226926ce35aSJung-uk Kim {
2227926ce35aSJung-uk Kim 	KASSERT(sc->rtsx_cmd_index < RTSX_HOSTCMD_MAX,
2228926ce35aSJung-uk Kim 		("rtsx: Too many host commands (%d)\n", sc->rtsx_cmd_index));
2229926ce35aSJung-uk Kim 
2230926ce35aSJung-uk Kim 	uint32_t *cmd_buffer = (uint32_t *)(sc->rtsx_cmd_dmamem);
2231926ce35aSJung-uk Kim 	cmd_buffer[sc->rtsx_cmd_index++] =
2232926ce35aSJung-uk Kim 		htole32((uint32_t)(cmd & 0x3) << 30) |
2233926ce35aSJung-uk Kim 		((uint32_t)(reg & 0x3fff) << 16) |
2234926ce35aSJung-uk Kim 		((uint32_t)(mask) << 8) |
2235926ce35aSJung-uk Kim 		((uint32_t)data);
2236926ce35aSJung-uk Kim }
2237926ce35aSJung-uk Kim 
2238926ce35aSJung-uk Kim /*
2239926ce35aSJung-uk Kim  * Queue commands to configure data transfer size.
2240926ce35aSJung-uk Kim  */
2241926ce35aSJung-uk Kim static void
2242926ce35aSJung-uk Kim rtsx_set_cmd_data_len(struct rtsx_softc *sc, uint16_t block_cnt, uint16_t byte_cnt)
2243926ce35aSJung-uk Kim {
2244926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_L,
2245926ce35aSJung-uk Kim 		      0xff, block_cnt & 0xff);
2246926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_H,
2247926ce35aSJung-uk Kim 		      0xff, block_cnt >> 8);
2248926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_L,
2249926ce35aSJung-uk Kim 		      0xff, byte_cnt & 0xff);
2250926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_H,
2251926ce35aSJung-uk Kim 		      0xff, byte_cnt >> 8);
2252926ce35aSJung-uk Kim }
2253926ce35aSJung-uk Kim 
2254926ce35aSJung-uk Kim /*
2255926ce35aSJung-uk Kim  * Run the command queue.
2256926ce35aSJung-uk Kim  */
2257926ce35aSJung-uk Kim static void
2258926ce35aSJung-uk Kim rtsx_send_cmd(struct rtsx_softc *sc)
2259926ce35aSJung-uk Kim {
2260577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2261926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_send_cmd()\n");
2262926ce35aSJung-uk Kim 
2263926ce35aSJung-uk Kim 	sc->rtsx_intr_status = 0;
2264926ce35aSJung-uk Kim 
2265926ce35aSJung-uk Kim 	/* Sync command DMA buffer. */
2266926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_PREREAD);
2267926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_PREWRITE);
2268926ce35aSJung-uk Kim 
2269926ce35aSJung-uk Kim 	/* Tell the chip where the command buffer is and run the commands. */
2270926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_HCBAR, (uint32_t)sc->rtsx_cmd_buffer);
2271926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_HCBCTLR,
2272926ce35aSJung-uk Kim 	       ((sc->rtsx_cmd_index * 4) & 0x00ffffff) | RTSX_START_CMD | RTSX_HW_AUTO_RSP);
2273926ce35aSJung-uk Kim }
2274926ce35aSJung-uk Kim 
2275926ce35aSJung-uk Kim /*
2276926ce35aSJung-uk Kim  * Stop previous command.
2277926ce35aSJung-uk Kim  */
2278926ce35aSJung-uk Kim static void
2279926ce35aSJung-uk Kim rtsx_stop_cmd(struct rtsx_softc *sc)
2280926ce35aSJung-uk Kim {
2281926ce35aSJung-uk Kim 	/* Stop command transfer. */
2282926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_HCBCTLR, RTSX_STOP_CMD);
2283926ce35aSJung-uk Kim 
2284926ce35aSJung-uk Kim 	/* Stop DMA transfer. */
2285926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_HDBCTLR, RTSX_STOP_DMA);
2286926ce35aSJung-uk Kim 
2287577130e5SHenri Hennebert 	switch (sc->rtsx_device_id) {
2288577130e5SHenri Hennebert 	case RTSX_RTS5260:
2289577130e5SHenri Hennebert 		rtsx_write(sc, RTSX_RTS5260_DMA_RST_CTL_0,
2290577130e5SHenri Hennebert 			   RTSX_RTS5260_DMA_RST | RTSX_RTS5260_ADMA3_RST,
2291577130e5SHenri Hennebert 			   RTSX_RTS5260_DMA_RST | RTSX_RTS5260_ADMA3_RST);
2292577130e5SHenri Hennebert 		rtsx_write(sc, RTSX_RBCTL, RTSX_RB_FLUSH, RTSX_RB_FLUSH);
2293577130e5SHenri Hennebert 		break;
22948290c144SHenri Hennebert 	default:
2295926ce35aSJung-uk Kim 		rtsx_write(sc, RTSX_DMACTL, RTSX_DMA_RST, RTSX_DMA_RST);
2296926ce35aSJung-uk Kim 
2297926ce35aSJung-uk Kim 		rtsx_write(sc, RTSX_RBCTL, RTSX_RB_FLUSH, RTSX_RB_FLUSH);
22988290c144SHenri Hennebert 		break;
22998290c144SHenri Hennebert 	}
2300926ce35aSJung-uk Kim }
2301926ce35aSJung-uk Kim 
2302926ce35aSJung-uk Kim /*
2303926ce35aSJung-uk Kim  * Clear error.
2304926ce35aSJung-uk Kim  */
2305926ce35aSJung-uk Kim static void
2306926ce35aSJung-uk Kim rtsx_clear_error(struct rtsx_softc *sc)
2307926ce35aSJung-uk Kim {
2308926ce35aSJung-uk Kim 	/* Clear error. */
2309926ce35aSJung-uk Kim 	rtsx_write(sc, RTSX_CARD_STOP, RTSX_SD_STOP | RTSX_SD_CLR_ERR,
2310926ce35aSJung-uk Kim 		   RTSX_SD_STOP | RTSX_SD_CLR_ERR);
2311926ce35aSJung-uk Kim }
2312926ce35aSJung-uk Kim 
2313926ce35aSJung-uk Kim /*
2314926ce35aSJung-uk Kim  * Signal end of request to mmc/mmcsd.
2315926ce35aSJung-uk Kim  */
2316926ce35aSJung-uk Kim static void
2317926ce35aSJung-uk Kim rtsx_req_done(struct rtsx_softc *sc)
2318926ce35aSJung-uk Kim {
2319926ce35aSJung-uk Kim #ifdef MMCCAM
2320926ce35aSJung-uk Kim 	union ccb *ccb;
2321926ce35aSJung-uk Kim #endif /* MMCCAM */
2322926ce35aSJung-uk Kim 	struct mmc_request *req;
2323926ce35aSJung-uk Kim 
2324926ce35aSJung-uk Kim 	req = sc->rtsx_req;
2325926ce35aSJung-uk Kim 	if (req->cmd->error == MMC_ERR_NONE) {
2326926ce35aSJung-uk Kim 		if (req->cmd->opcode == MMC_READ_SINGLE_BLOCK ||
2327926ce35aSJung-uk Kim 		    req->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
2328926ce35aSJung-uk Kim 			sc->rtsx_read_count++;
2329926ce35aSJung-uk Kim 		else if (req->cmd->opcode == MMC_WRITE_BLOCK ||
2330926ce35aSJung-uk Kim 			 req->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
2331926ce35aSJung-uk Kim 			sc->rtsx_write_count++;
2332926ce35aSJung-uk Kim 	} else {
2333926ce35aSJung-uk Kim 		rtsx_clear_error(sc);
2334926ce35aSJung-uk Kim 	}
2335926ce35aSJung-uk Kim 	callout_stop(&sc->rtsx_timeout_callout);
2336926ce35aSJung-uk Kim 	sc->rtsx_req = NULL;
2337926ce35aSJung-uk Kim #ifdef MMCCAM
2338926ce35aSJung-uk Kim 	ccb = sc->rtsx_ccb;
2339926ce35aSJung-uk Kim 	sc->rtsx_ccb = NULL;
2340926ce35aSJung-uk Kim 	ccb->ccb_h.status = (req->cmd->error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR);
2341926ce35aSJung-uk Kim 	xpt_done(ccb);
23429d3bc163SHenri Hennebert #else  /* !MMCCAM */
2343926ce35aSJung-uk Kim 	req->done(req);
2344926ce35aSJung-uk Kim #endif /* MMCCAM */
2345926ce35aSJung-uk Kim }
2346926ce35aSJung-uk Kim 
2347926ce35aSJung-uk Kim /*
2348926ce35aSJung-uk Kim  * Send request.
2349926ce35aSJung-uk Kim  */
2350926ce35aSJung-uk Kim static int
2351926ce35aSJung-uk Kim rtsx_send_req(struct rtsx_softc *sc, struct mmc_command *cmd)
2352926ce35aSJung-uk Kim {
2353926ce35aSJung-uk Kim 	uint8_t	 rsp_type;
2354926ce35aSJung-uk Kim 	uint16_t reg;
2355926ce35aSJung-uk Kim 
2356577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2357926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_send_req() - CMD%d\n", cmd->opcode);
2358926ce35aSJung-uk Kim 
2359926ce35aSJung-uk Kim 	/* Convert response type. */
2360926ce35aSJung-uk Kim 	rsp_type = rtsx_response_type(cmd->flags & MMC_RSP_MASK);
2361926ce35aSJung-uk Kim 	if (rsp_type == 0) {
2362926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Unknown rsp_type: 0x%lx\n", (cmd->flags & MMC_RSP_MASK));
2363926ce35aSJung-uk Kim 		cmd->error = MMC_ERR_INVALID;
2364926ce35aSJung-uk Kim 		return (MMC_ERR_INVALID);
2365926ce35aSJung-uk Kim 	}
2366926ce35aSJung-uk Kim 
2367926ce35aSJung-uk Kim 	rtsx_init_cmd(sc, cmd);
2368926ce35aSJung-uk Kim 
2369926ce35aSJung-uk Kim 	/* Queue command to set response type. */
2370926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, rsp_type);
2371926ce35aSJung-uk Kim 
2372926ce35aSJung-uk Kim 	/* Use the ping-pong buffer (cmd buffer) for commands which do not transfer data. */
2373926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE,
2374926ce35aSJung-uk Kim 		      0x01, RTSX_PINGPONG_BUFFER);
2375926ce35aSJung-uk Kim 
2376926ce35aSJung-uk Kim 	/* Queue commands to perform SD transfer. */
2377926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER,
2378926ce35aSJung-uk Kim 		      0xff, RTSX_TM_CMD_RSP | RTSX_SD_TRANSFER_START);
2379926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER,
2380926ce35aSJung-uk Kim 		      RTSX_SD_TRANSFER_END|RTSX_SD_STAT_IDLE,
2381926ce35aSJung-uk Kim 		      RTSX_SD_TRANSFER_END|RTSX_SD_STAT_IDLE);
2382926ce35aSJung-uk Kim 
2383926ce35aSJung-uk Kim 	/* If needed queue commands to read back card status response. */
2384926ce35aSJung-uk Kim 	if (rsp_type == RTSX_SD_RSP_TYPE_R2) {
2385926ce35aSJung-uk Kim 		/* Read data from ping-pong buffer. */
2386926ce35aSJung-uk Kim 		for (reg = RTSX_PPBUF_BASE2; reg < RTSX_PPBUF_BASE2 + 16; reg++)
2387926ce35aSJung-uk Kim 			rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg, 0, 0);
2388926ce35aSJung-uk Kim 	} else if (rsp_type != RTSX_SD_RSP_TYPE_R0) {
2389926ce35aSJung-uk Kim 		/* Read data from SD_CMDx registers. */
2390926ce35aSJung-uk Kim 		for (reg = RTSX_SD_CMD0; reg <= RTSX_SD_CMD4; reg++)
2391926ce35aSJung-uk Kim 			rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg, 0, 0);
2392926ce35aSJung-uk Kim 	}
2393926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_READ_REG_CMD, RTSX_SD_STAT1, 0, 0);
2394926ce35aSJung-uk Kim 
2395926ce35aSJung-uk Kim 	/* Set transfer OK function. */
2396926ce35aSJung-uk Kim 	if (sc->rtsx_intr_trans_ok == NULL)
2397926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_ret_resp;
2398926ce35aSJung-uk Kim 
2399926ce35aSJung-uk Kim 	/* Run the command queue. */
2400926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2401926ce35aSJung-uk Kim 
2402926ce35aSJung-uk Kim 	return (0);
2403926ce35aSJung-uk Kim }
2404926ce35aSJung-uk Kim 
2405926ce35aSJung-uk Kim /*
2406926ce35aSJung-uk Kim  * Return response of previous command (case cmd->data == NULL) and complete resquest.
2407926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2408926ce35aSJung-uk Kim  */
2409926ce35aSJung-uk Kim static void
2410926ce35aSJung-uk Kim rtsx_ret_resp(struct rtsx_softc *sc)
2411926ce35aSJung-uk Kim {
2412926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2413926ce35aSJung-uk Kim 
2414926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2415926ce35aSJung-uk Kim 	rtsx_set_resp(sc, cmd);
2416926ce35aSJung-uk Kim 	rtsx_req_done(sc);
2417926ce35aSJung-uk Kim }
2418926ce35aSJung-uk Kim 
2419926ce35aSJung-uk Kim /*
2420926ce35aSJung-uk Kim  * Set response of previous command.
2421926ce35aSJung-uk Kim  */
2422926ce35aSJung-uk Kim static void
2423926ce35aSJung-uk Kim rtsx_set_resp(struct rtsx_softc *sc, struct mmc_command *cmd)
2424926ce35aSJung-uk Kim {
2425926ce35aSJung-uk Kim 	uint8_t	 rsp_type;
2426926ce35aSJung-uk Kim 
2427926ce35aSJung-uk Kim 	rsp_type = rtsx_response_type(cmd->flags & MMC_RSP_MASK);
2428926ce35aSJung-uk Kim 
2429926ce35aSJung-uk Kim 	/* Sync command DMA buffer. */
2430926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTREAD);
2431926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTWRITE);
2432926ce35aSJung-uk Kim 
2433926ce35aSJung-uk Kim 	/* Copy card response into mmc response buffer. */
2434926ce35aSJung-uk Kim 	if (ISSET(cmd->flags, MMC_RSP_PRESENT)) {
2435926ce35aSJung-uk Kim 		uint32_t *cmd_buffer = (uint32_t *)(sc->rtsx_cmd_dmamem);
2436926ce35aSJung-uk Kim 
2437577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD) {
2438926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "cmd_buffer: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
2439926ce35aSJung-uk Kim 				      cmd_buffer[0], cmd_buffer[1], cmd_buffer[2], cmd_buffer[3], cmd_buffer[4]);
2440926ce35aSJung-uk Kim 		}
2441926ce35aSJung-uk Kim 
2442926ce35aSJung-uk Kim 		if (rsp_type == RTSX_SD_RSP_TYPE_R2) {
2443926ce35aSJung-uk Kim 			/* First byte is CHECK_REG_CMD return value, skip it. */
2444926ce35aSJung-uk Kim 			unsigned char *ptr = (unsigned char *)cmd_buffer + 1;
2445926ce35aSJung-uk Kim 			int i;
2446926ce35aSJung-uk Kim 
2447926ce35aSJung-uk Kim 			/*
2448926ce35aSJung-uk Kim 			 * The controller offloads the last byte {CRC-7, end bit 1}
2449926ce35aSJung-uk Kim 			 * of response type R2. Assign dummy CRC, 0, and end bit to this
2450926ce35aSJung-uk Kim 			 * byte (ptr[16], goes into the LSB of resp[3] later).
2451926ce35aSJung-uk Kim 			 */
2452926ce35aSJung-uk Kim 			ptr[16] = 0x01;
2453926ce35aSJung-uk Kim 			/* The second byte is the status of response, skip it. */
2454926ce35aSJung-uk Kim 			for (i = 0; i < 4; i++)
2455926ce35aSJung-uk Kim 				cmd->resp[i] = be32dec(ptr + 1 + i * 4);
2456926ce35aSJung-uk Kim 		} else {
2457926ce35aSJung-uk Kim 			/*
2458926ce35aSJung-uk Kim 			 * First byte is CHECK_REG_CMD return value, second
2459926ce35aSJung-uk Kim 			 * one is the command op code -- we skip those.
2460926ce35aSJung-uk Kim 			 */
2461926ce35aSJung-uk Kim 			cmd->resp[0] =
2462926ce35aSJung-uk Kim 				((be32toh(cmd_buffer[0]) & 0x0000ffff) << 16) |
2463926ce35aSJung-uk Kim 				((be32toh(cmd_buffer[1]) & 0xffff0000) >> 16);
2464926ce35aSJung-uk Kim 		}
2465926ce35aSJung-uk Kim 
2466577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2467926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "cmd->resp: 0x%08x 0x%08x 0x%08x 0x%08x\n",
2468926ce35aSJung-uk Kim 				      cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
2469926ce35aSJung-uk Kim 	}
2470926ce35aSJung-uk Kim }
2471926ce35aSJung-uk Kim 
2472926ce35aSJung-uk Kim /*
2473926ce35aSJung-uk Kim  * Use the ping-pong buffer (cmd buffer) for transfer <= 512 bytes.
2474926ce35aSJung-uk Kim  */
2475926ce35aSJung-uk Kim static int
2476926ce35aSJung-uk Kim rtsx_xfer_short(struct rtsx_softc *sc, struct mmc_command *cmd)
2477926ce35aSJung-uk Kim {
2478926ce35aSJung-uk Kim 	int	read;
2479926ce35aSJung-uk Kim 
2480926ce35aSJung-uk Kim 	if (cmd->data == NULL || cmd->data->len == 0) {
2481926ce35aSJung-uk Kim 		cmd->error = MMC_ERR_INVALID;
2482926ce35aSJung-uk Kim 		return (MMC_ERR_INVALID);
2483926ce35aSJung-uk Kim 	}
2484926ce35aSJung-uk Kim 	cmd->data->xfer_len = (cmd->data->len > RTSX_MAX_DATA_BLKLEN) ?
2485926ce35aSJung-uk Kim 		RTSX_MAX_DATA_BLKLEN : cmd->data->len;
2486926ce35aSJung-uk Kim 
2487926ce35aSJung-uk Kim 	read = ISSET(cmd->data->flags, MMC_DATA_READ);
2488926ce35aSJung-uk Kim 
2489577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2490926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_xfer_short() - %s xfer: %ld bytes with block size %ld\n",
2491926ce35aSJung-uk Kim 			      read ? "Read" : "Write",
2492926ce35aSJung-uk Kim 			      (unsigned long)cmd->data->len, (unsigned long)cmd->data->xfer_len);
2493926ce35aSJung-uk Kim 
2494926ce35aSJung-uk Kim 	if (cmd->data->len > 512) {
2495926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_xfer_short() - length too large: %ld > 512\n",
2496926ce35aSJung-uk Kim 			      (unsigned long)cmd->data->len);
2497926ce35aSJung-uk Kim 		cmd->error = MMC_ERR_INVALID;
2498926ce35aSJung-uk Kim 		return (MMC_ERR_INVALID);
2499926ce35aSJung-uk Kim 	}
2500926ce35aSJung-uk Kim 
2501926ce35aSJung-uk Kim 	if (read) {
2502926ce35aSJung-uk Kim 		if (sc->rtsx_discovery_mode)
2503926ce35aSJung-uk Kim 			rtsx_write(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, RTSX_CLK_DIVIDE_0);
2504926ce35aSJung-uk Kim 
2505926ce35aSJung-uk Kim 		rtsx_init_cmd(sc, cmd);
2506926ce35aSJung-uk Kim 
2507926ce35aSJung-uk Kim 		/* Queue commands to configure data transfer size. */
2508926ce35aSJung-uk Kim 		rtsx_set_cmd_data_len(sc, cmd->data->len / cmd->data->xfer_len, cmd->data->xfer_len);
2509926ce35aSJung-uk Kim 
2510926ce35aSJung-uk Kim 		/* From Linux: rtsx_pci_sdmmc.c sd_read_data(). */
2511926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff,
2512926ce35aSJung-uk Kim 			      RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC16 |
2513926ce35aSJung-uk Kim 			      RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_CHECK_CRC7 | RTSX_SD_RSP_LEN_6);
2514926ce35aSJung-uk Kim 
2515926ce35aSJung-uk Kim 		/* Use the ping-pong buffer (cmd buffer). */
2516926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE,
2517926ce35aSJung-uk Kim 			      0x01, RTSX_PINGPONG_BUFFER);
2518926ce35aSJung-uk Kim 
2519926ce35aSJung-uk Kim 		/* Queue commands to perform SD transfer. */
2520926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER,
2521926ce35aSJung-uk Kim 			      0xff, RTSX_TM_NORMAL_READ | RTSX_SD_TRANSFER_START);
2522926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER,
2523926ce35aSJung-uk Kim 			      RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END);
2524926ce35aSJung-uk Kim 
2525926ce35aSJung-uk Kim 		/* Set transfer OK function. */
2526926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_ask_ppbuf_part1;
2527926ce35aSJung-uk Kim 
2528926ce35aSJung-uk Kim 		/* Run the command queue. */
2529926ce35aSJung-uk Kim 		rtsx_send_cmd(sc);
2530926ce35aSJung-uk Kim 	} else {
2531926ce35aSJung-uk Kim 		/* Set transfer OK function. */
2532926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_put_ppbuf_part1;
2533926ce35aSJung-uk Kim 
2534926ce35aSJung-uk Kim 		/* Run the command queue. */
2535926ce35aSJung-uk Kim 		rtsx_send_req(sc, cmd);
2536926ce35aSJung-uk Kim 	}
2537926ce35aSJung-uk Kim 
2538926ce35aSJung-uk Kim 	return (0);
2539926ce35aSJung-uk Kim }
2540926ce35aSJung-uk Kim 
2541926ce35aSJung-uk Kim /*
2542926ce35aSJung-uk Kim  * Use the ping-pong buffer (cmd buffer) for the transfer - first part <= 256 bytes.
2543926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2544926ce35aSJung-uk Kim  */
2545926ce35aSJung-uk Kim static void
2546926ce35aSJung-uk Kim rtsx_ask_ppbuf_part1(struct rtsx_softc *sc)
2547926ce35aSJung-uk Kim {
2548926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2549926ce35aSJung-uk Kim 	uint16_t reg = RTSX_PPBUF_BASE2;
2550926ce35aSJung-uk Kim 	int	 len;
2551926ce35aSJung-uk Kim 	int	 i;
2552926ce35aSJung-uk Kim 
2553926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2554926ce35aSJung-uk Kim 	len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? RTSX_HOSTCMD_MAX : cmd->data->len;
2555926ce35aSJung-uk Kim 
2556926ce35aSJung-uk Kim 	sc->rtsx_cmd_index = 0;
2557926ce35aSJung-uk Kim 	for (i = 0; i < len; i++) {
2558926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg++, 0, 0);
2559926ce35aSJung-uk Kim 	}
2560926ce35aSJung-uk Kim 
2561926ce35aSJung-uk Kim 	/* Set transfer OK function. */
2562926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ok = rtsx_get_ppbuf_part1;
2563926ce35aSJung-uk Kim 
2564926ce35aSJung-uk Kim 	/* Run the command queue. */
2565926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2566926ce35aSJung-uk Kim }
2567926ce35aSJung-uk Kim 
2568926ce35aSJung-uk Kim /*
2569926ce35aSJung-uk Kim  * Get the data from the ping-pong buffer (cmd buffer) - first part <= 256 bytes.
2570926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2571926ce35aSJung-uk Kim  */
2572926ce35aSJung-uk Kim static void
2573926ce35aSJung-uk Kim rtsx_get_ppbuf_part1(struct rtsx_softc *sc)
2574926ce35aSJung-uk Kim {
2575926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2576926ce35aSJung-uk Kim 	uint8_t	 *ptr;
2577926ce35aSJung-uk Kim 	int	 len;
2578926ce35aSJung-uk Kim 
2579926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2580926ce35aSJung-uk Kim 	ptr = cmd->data->data;
2581926ce35aSJung-uk Kim 	len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? RTSX_HOSTCMD_MAX : cmd->data->len;
2582926ce35aSJung-uk Kim 
2583926ce35aSJung-uk Kim 	/* Sync command DMA buffer. */
2584926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTREAD);
2585926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTWRITE);
2586926ce35aSJung-uk Kim 
2587926ce35aSJung-uk Kim 	memcpy(ptr, sc->rtsx_cmd_dmamem, len);
2588926ce35aSJung-uk Kim 
2589926ce35aSJung-uk Kim 	len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? cmd->data->len - RTSX_HOSTCMD_MAX : 0;
2590926ce35aSJung-uk Kim 
2591926ce35aSJung-uk Kim 	/* Use the ping-pong buffer (cmd buffer) for the transfer - second part > 256 bytes. */
2592926ce35aSJung-uk Kim 	if (len > 0) {
2593926ce35aSJung-uk Kim 		uint16_t reg = RTSX_PPBUF_BASE2 + RTSX_HOSTCMD_MAX;
2594926ce35aSJung-uk Kim 		int	 i;
2595926ce35aSJung-uk Kim 
2596926ce35aSJung-uk Kim 		sc->rtsx_cmd_index = 0;
2597926ce35aSJung-uk Kim 		for (i = 0; i < len; i++) {
2598926ce35aSJung-uk Kim 			rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg++, 0, 0);
2599926ce35aSJung-uk Kim 		}
2600926ce35aSJung-uk Kim 
2601926ce35aSJung-uk Kim 		/* Set transfer OK function. */
2602926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_get_ppbuf_part2;
2603926ce35aSJung-uk Kim 
2604926ce35aSJung-uk Kim 		/* Run the command queue. */
2605926ce35aSJung-uk Kim 		rtsx_send_cmd(sc);
2606926ce35aSJung-uk Kim 	} else {
2607577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD && cmd->opcode == ACMD_SEND_SCR) {
2608926ce35aSJung-uk Kim 			uint8_t *ptr = cmd->data->data;
2609926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "SCR: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
2610926ce35aSJung-uk Kim 				      ptr[0], ptr[1], ptr[2], ptr[3],
2611926ce35aSJung-uk Kim 				      ptr[4], ptr[5], ptr[6], ptr[7]);
2612926ce35aSJung-uk Kim 		}
2613926ce35aSJung-uk Kim 
2614926ce35aSJung-uk Kim 		if (sc->rtsx_discovery_mode)
2615926ce35aSJung-uk Kim 			rtsx_write(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, RTSX_CLK_DIVIDE_128);
2616926ce35aSJung-uk Kim 
2617926ce35aSJung-uk Kim 		rtsx_req_done(sc);
2618926ce35aSJung-uk Kim 	}
2619926ce35aSJung-uk Kim }
2620926ce35aSJung-uk Kim 
2621926ce35aSJung-uk Kim /*
2622926ce35aSJung-uk Kim  * Get the data from the ping-pong buffer (cmd buffer) - second part > 256 bytes.
2623926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2624926ce35aSJung-uk Kim  */
2625926ce35aSJung-uk Kim static void
2626926ce35aSJung-uk Kim rtsx_get_ppbuf_part2(struct rtsx_softc *sc)
2627926ce35aSJung-uk Kim {
2628926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2629926ce35aSJung-uk Kim 	uint8_t	*ptr;
2630926ce35aSJung-uk Kim 	int	len;
2631926ce35aSJung-uk Kim 
2632926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2633926ce35aSJung-uk Kim 	ptr = cmd->data->data;
2634926ce35aSJung-uk Kim 	ptr += RTSX_HOSTCMD_MAX;
2635926ce35aSJung-uk Kim 	len = cmd->data->len - RTSX_HOSTCMD_MAX;
2636926ce35aSJung-uk Kim 
2637926ce35aSJung-uk Kim 	/* Sync command DMA buffer. */
2638926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTREAD);
2639926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTWRITE);
2640926ce35aSJung-uk Kim 
2641926ce35aSJung-uk Kim 	memcpy(ptr, sc->rtsx_cmd_dmamem, len);
2642926ce35aSJung-uk Kim 
2643926ce35aSJung-uk Kim 	if (sc->rtsx_discovery_mode)
2644926ce35aSJung-uk Kim 		rtsx_write(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, RTSX_CLK_DIVIDE_128);
2645926ce35aSJung-uk Kim 
2646926ce35aSJung-uk Kim 	rtsx_req_done(sc);
2647926ce35aSJung-uk Kim }
2648926ce35aSJung-uk Kim 
2649926ce35aSJung-uk Kim /*
2650926ce35aSJung-uk Kim  * Use the ping-pong buffer (cmd buffer) for transfer - first part <= 256 bytes.
2651926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2652926ce35aSJung-uk Kim  */
2653926ce35aSJung-uk Kim static void
2654926ce35aSJung-uk Kim rtsx_put_ppbuf_part1(struct rtsx_softc *sc)
2655926ce35aSJung-uk Kim {
2656926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2657926ce35aSJung-uk Kim 	uint16_t reg = RTSX_PPBUF_BASE2;
2658926ce35aSJung-uk Kim 	uint8_t	 *ptr;
2659926ce35aSJung-uk Kim 	int	 len;
2660926ce35aSJung-uk Kim 	int	 i;
2661926ce35aSJung-uk Kim 
2662926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2663926ce35aSJung-uk Kim 	ptr = cmd->data->data;
2664926ce35aSJung-uk Kim 	len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? RTSX_HOSTCMD_MAX : cmd->data->len;
2665926ce35aSJung-uk Kim 
2666926ce35aSJung-uk Kim 	rtsx_set_resp(sc, cmd);
2667926ce35aSJung-uk Kim 
2668926ce35aSJung-uk Kim 	sc->rtsx_cmd_index = 0;
2669926ce35aSJung-uk Kim 	for (i = 0; i < len; i++) {
2670926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, reg++, 0xff, *ptr);
2671926ce35aSJung-uk Kim 		ptr++;
2672926ce35aSJung-uk Kim 	}
2673926ce35aSJung-uk Kim 
2674926ce35aSJung-uk Kim 	/* Set transfer OK function. */
2675926ce35aSJung-uk Kim 	if (cmd->data->len > RTSX_HOSTCMD_MAX)
2676926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_put_ppbuf_part2;
2677926ce35aSJung-uk Kim 	else
2678926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_write_ppbuf;
2679926ce35aSJung-uk Kim 
2680926ce35aSJung-uk Kim 	/* Run the command queue. */
2681926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2682926ce35aSJung-uk Kim }
2683926ce35aSJung-uk Kim 
2684926ce35aSJung-uk Kim /*
2685926ce35aSJung-uk Kim  * Use the ping-pong buffer (cmd buffer) for transfer - second part > 256 bytes.
2686926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2687926ce35aSJung-uk Kim  */
2688926ce35aSJung-uk Kim static void
2689926ce35aSJung-uk Kim rtsx_put_ppbuf_part2(struct rtsx_softc *sc)
2690926ce35aSJung-uk Kim {
2691926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2692926ce35aSJung-uk Kim 	uint16_t reg = RTSX_PPBUF_BASE2 + RTSX_HOSTCMD_MAX;
2693926ce35aSJung-uk Kim 	uint8_t	 *ptr;
2694926ce35aSJung-uk Kim 	int	 len;
2695926ce35aSJung-uk Kim 	int	 i;
2696926ce35aSJung-uk Kim 
2697926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2698926ce35aSJung-uk Kim 	ptr = cmd->data->data;
2699926ce35aSJung-uk Kim 	ptr += RTSX_HOSTCMD_MAX;
2700926ce35aSJung-uk Kim 	len = cmd->data->len - RTSX_HOSTCMD_MAX;
2701926ce35aSJung-uk Kim 
2702926ce35aSJung-uk Kim 	sc->rtsx_cmd_index = 0;
2703926ce35aSJung-uk Kim 	for (i = 0; i < len; i++) {
2704926ce35aSJung-uk Kim 		rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, reg++, 0xff, *ptr);
2705926ce35aSJung-uk Kim 		ptr++;
2706926ce35aSJung-uk Kim 	}
2707926ce35aSJung-uk Kim 
2708926ce35aSJung-uk Kim 	/* Set transfer OK function. */
2709926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ok = rtsx_write_ppbuf;
2710926ce35aSJung-uk Kim 
2711926ce35aSJung-uk Kim 	/* Run the command queue. */
2712926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2713926ce35aSJung-uk Kim }
2714926ce35aSJung-uk Kim 
2715926ce35aSJung-uk Kim /*
2716926ce35aSJung-uk Kim  * Write the data previously given via the ping-pong buffer on the card.
2717926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2718926ce35aSJung-uk Kim  */
2719926ce35aSJung-uk Kim static void
2720926ce35aSJung-uk Kim rtsx_write_ppbuf(struct rtsx_softc *sc)
2721926ce35aSJung-uk Kim {
2722926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2723926ce35aSJung-uk Kim 
2724926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2725926ce35aSJung-uk Kim 
2726926ce35aSJung-uk Kim 	sc->rtsx_cmd_index = 0;
2727926ce35aSJung-uk Kim 
2728926ce35aSJung-uk Kim 	/* Queue commands to configure data transfer size. */
2729926ce35aSJung-uk Kim 	rtsx_set_cmd_data_len(sc, cmd->data->len / cmd->data->xfer_len, cmd->data->xfer_len);
2730926ce35aSJung-uk Kim 
2731926ce35aSJung-uk Kim 	/* From Linux: rtsx_pci_sdmmc.c sd_write_data(). */
2732926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff,
2733926ce35aSJung-uk Kim 		      RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC16 |
2734926ce35aSJung-uk Kim 		      RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_CHECK_CRC7 | RTSX_SD_RSP_LEN_0);
2735926ce35aSJung-uk Kim 
2736926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, 0xff,
2737926ce35aSJung-uk Kim 		      RTSX_TM_AUTO_WRITE3 | RTSX_SD_TRANSFER_START);
2738926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER,
2739926ce35aSJung-uk Kim 		      RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END);
2740926ce35aSJung-uk Kim 
2741926ce35aSJung-uk Kim 	/* Set transfer OK function. */
2742926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ok = rtsx_req_done;
2743926ce35aSJung-uk Kim 
2744926ce35aSJung-uk Kim 	/* Run the command queue. */
2745926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2746926ce35aSJung-uk Kim }
2747926ce35aSJung-uk Kim 
2748926ce35aSJung-uk Kim /*
2749926ce35aSJung-uk Kim  * Use the data buffer for transfer > 512 bytes.
2750926ce35aSJung-uk Kim  */
2751926ce35aSJung-uk Kim static int
2752926ce35aSJung-uk Kim rtsx_xfer(struct rtsx_softc *sc, struct mmc_command *cmd)
2753926ce35aSJung-uk Kim {
2754926ce35aSJung-uk Kim 	int	read = ISSET(cmd->data->flags, MMC_DATA_READ);
2755926ce35aSJung-uk Kim 
2756926ce35aSJung-uk Kim 	cmd->data->xfer_len = (cmd->data->len > RTSX_MAX_DATA_BLKLEN) ?
2757926ce35aSJung-uk Kim 		RTSX_MAX_DATA_BLKLEN : cmd->data->len;
2758926ce35aSJung-uk Kim 
2759577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2760926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_xfer() - %s xfer: %ld bytes with block size %ld\n",
2761926ce35aSJung-uk Kim 			      read ? "Read" : "Write",
2762926ce35aSJung-uk Kim 			      (unsigned long)cmd->data->len, (unsigned long)cmd->data->xfer_len);
2763926ce35aSJung-uk Kim 
2764926ce35aSJung-uk Kim 	if (cmd->data->len > RTSX_DMA_DATA_BUFSIZE) {
276513a5a46cSAndrew Gallatin 		device_printf(sc->rtsx_dev, "rtsx_xfer() length too large: %ld > %ld\n",
2766926ce35aSJung-uk Kim 			      (unsigned long)cmd->data->len, RTSX_DMA_DATA_BUFSIZE);
2767926ce35aSJung-uk Kim 		cmd->error = MMC_ERR_INVALID;
2768926ce35aSJung-uk Kim 		return (MMC_ERR_INVALID);
2769926ce35aSJung-uk Kim 	}
2770926ce35aSJung-uk Kim 
2771926ce35aSJung-uk Kim 	if (!read) {
2772926ce35aSJung-uk Kim 		/* Set transfer OK function. */
2773926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = rtsx_xfer_begin;
2774926ce35aSJung-uk Kim 
2775926ce35aSJung-uk Kim 		/* Run the command queue. */
2776926ce35aSJung-uk Kim 		rtsx_send_req(sc, cmd);
2777926ce35aSJung-uk Kim 	} else {
2778926ce35aSJung-uk Kim 		rtsx_xfer_start(sc);
2779926ce35aSJung-uk Kim 	}
2780926ce35aSJung-uk Kim 
2781926ce35aSJung-uk Kim 	return (0);
2782926ce35aSJung-uk Kim }
2783926ce35aSJung-uk Kim 
2784926ce35aSJung-uk Kim /*
2785926ce35aSJung-uk Kim  * Get request response and start dma data transfer (write command).
2786926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2787926ce35aSJung-uk Kim  */
2788926ce35aSJung-uk Kim static void
2789926ce35aSJung-uk Kim rtsx_xfer_begin(struct rtsx_softc *sc)
2790926ce35aSJung-uk Kim {
2791926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2792926ce35aSJung-uk Kim 
2793926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2794926ce35aSJung-uk Kim 
2795577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2796926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_xfer_begin() - CMD%d\n", cmd->opcode);
2797926ce35aSJung-uk Kim 
2798926ce35aSJung-uk Kim 	rtsx_set_resp(sc, cmd);
2799926ce35aSJung-uk Kim 	rtsx_xfer_start(sc);
2800926ce35aSJung-uk Kim }
2801926ce35aSJung-uk Kim 
2802926ce35aSJung-uk Kim /*
2803926ce35aSJung-uk Kim  * Start dma data transfer.
2804926ce35aSJung-uk Kim  */
2805926ce35aSJung-uk Kim static void
2806926ce35aSJung-uk Kim rtsx_xfer_start(struct rtsx_softc *sc)
2807926ce35aSJung-uk Kim {
2808926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2809926ce35aSJung-uk Kim 	int	read;
2810926ce35aSJung-uk Kim 	uint8_t	cfg2;
2811926ce35aSJung-uk Kim 	int	dma_dir;
2812926ce35aSJung-uk Kim 	int	tmode;
2813926ce35aSJung-uk Kim 
2814926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2815926ce35aSJung-uk Kim 	read = ISSET(cmd->data->flags, MMC_DATA_READ);
2816926ce35aSJung-uk Kim 
2817926ce35aSJung-uk Kim 	/* Configure DMA transfer mode parameters. */
2818926ce35aSJung-uk Kim 	if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
2819926ce35aSJung-uk Kim 		cfg2 = RTSX_SD_CHECK_CRC16 | RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_RSP_LEN_6;
2820926ce35aSJung-uk Kim 	else
2821926ce35aSJung-uk Kim 		cfg2 = RTSX_SD_CHECK_CRC16 | RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_RSP_LEN_0;
2822926ce35aSJung-uk Kim 	if (read) {
2823926ce35aSJung-uk Kim 		dma_dir = RTSX_DMA_DIR_FROM_CARD;
2824926ce35aSJung-uk Kim 		/*
2825926ce35aSJung-uk Kim 		 * Use transfer mode AUTO_READ1, which assume we not
2826926ce35aSJung-uk Kim 		 * already send the read command and don't need to send
2827926ce35aSJung-uk Kim 		 * CMD 12 manually after read.
2828926ce35aSJung-uk Kim 		 */
2829926ce35aSJung-uk Kim 		tmode = RTSX_TM_AUTO_READ1;
2830926ce35aSJung-uk Kim 		cfg2 |= RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC7;
2831926ce35aSJung-uk Kim 
2832926ce35aSJung-uk Kim 		rtsx_init_cmd(sc, cmd);
2833926ce35aSJung-uk Kim 	} else {
2834926ce35aSJung-uk Kim 		dma_dir = RTSX_DMA_DIR_TO_CARD;
2835926ce35aSJung-uk Kim 		/*
2836926ce35aSJung-uk Kim 		 * Use transfer mode AUTO_WRITE3, wich assumes we've already
2837926ce35aSJung-uk Kim 		 * sent the write command and gotten the response, and will
2838926ce35aSJung-uk Kim 		 * send CMD 12 manually after writing.
2839926ce35aSJung-uk Kim 		 */
2840926ce35aSJung-uk Kim 		tmode = RTSX_TM_AUTO_WRITE3;
2841926ce35aSJung-uk Kim 		cfg2 |= RTSX_SD_NO_CALCULATE_CRC7 | RTSX_SD_NO_CHECK_CRC7;
2842926ce35aSJung-uk Kim 
2843926ce35aSJung-uk Kim 		sc->rtsx_cmd_index = 0;
2844926ce35aSJung-uk Kim 	}
2845926ce35aSJung-uk Kim 
2846926ce35aSJung-uk Kim 	/* Queue commands to configure data transfer size. */
2847926ce35aSJung-uk Kim 	rtsx_set_cmd_data_len(sc, cmd->data->len / cmd->data->xfer_len, cmd->data->xfer_len);
2848926ce35aSJung-uk Kim 
2849926ce35aSJung-uk Kim 	/* Configure DMA controller. */
2850926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_IRQSTAT0,
2851926ce35aSJung-uk Kim 		     RTSX_DMA_DONE_INT, RTSX_DMA_DONE_INT);
2852926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC3,
2853926ce35aSJung-uk Kim 		     0xff, cmd->data->len >> 24);
2854926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC2,
2855926ce35aSJung-uk Kim 		     0xff, cmd->data->len >> 16);
2856926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC1,
2857926ce35aSJung-uk Kim 		     0xff, cmd->data->len >> 8);
2858926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC0,
2859926ce35aSJung-uk Kim 		     0xff, cmd->data->len);
2860926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMACTL,
2861926ce35aSJung-uk Kim 		     RTSX_DMA_EN | RTSX_DMA_DIR | RTSX_DMA_PACK_SIZE_MASK,
2862926ce35aSJung-uk Kim 		     RTSX_DMA_EN | dma_dir | RTSX_DMA_512);
2863926ce35aSJung-uk Kim 
2864926ce35aSJung-uk Kim 	/* Use the DMA ring buffer for commands which transfer data. */
2865926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE,
2866926ce35aSJung-uk Kim 		      0x01, RTSX_RING_BUFFER);
2867926ce35aSJung-uk Kim 
2868926ce35aSJung-uk Kim 	/* Queue command to set response type. */
2869926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, cfg2);
2870926ce35aSJung-uk Kim 
2871926ce35aSJung-uk Kim 	/* Queue commands to perform SD transfer. */
2872926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER,
2873926ce35aSJung-uk Kim 		      0xff, tmode | RTSX_SD_TRANSFER_START);
2874926ce35aSJung-uk Kim 	rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER,
2875926ce35aSJung-uk Kim 		      RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END);
2876926ce35aSJung-uk Kim 
2877926ce35aSJung-uk Kim 	/* Run the command queue. */
2878926ce35aSJung-uk Kim 	rtsx_send_cmd(sc);
2879926ce35aSJung-uk Kim 
2880926ce35aSJung-uk Kim 	if (!read)
2881926ce35aSJung-uk Kim 		memcpy(sc->rtsx_data_dmamem, cmd->data->data, cmd->data->len);
2882926ce35aSJung-uk Kim 
2883926ce35aSJung-uk Kim 	/* Sync data DMA buffer. */
2884926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_PREREAD);
2885926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_PREWRITE);
2886926ce35aSJung-uk Kim 
2887926ce35aSJung-uk Kim 	/* Set transfer OK function. */
2888926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ok = rtsx_xfer_finish;
2889926ce35aSJung-uk Kim 
2890926ce35aSJung-uk Kim 	/* Tell the chip where the data buffer is and run the transfer. */
2891926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_HDBAR, sc->rtsx_data_buffer);
2892926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_HDBCTLR, RTSX_TRIG_DMA | (read ? RTSX_DMA_READ : 0) |
2893926ce35aSJung-uk Kim 	       (cmd->data->len & 0x00ffffff));
2894926ce35aSJung-uk Kim }
2895926ce35aSJung-uk Kim 
2896926ce35aSJung-uk Kim /*
2897926ce35aSJung-uk Kim  * Finish dma data transfer.
2898926ce35aSJung-uk Kim  * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok.
2899926ce35aSJung-uk Kim  */
2900926ce35aSJung-uk Kim static void
2901926ce35aSJung-uk Kim rtsx_xfer_finish(struct rtsx_softc *sc)
2902926ce35aSJung-uk Kim {
2903926ce35aSJung-uk Kim 	struct mmc_command *cmd;
2904926ce35aSJung-uk Kim 	int	read;
2905926ce35aSJung-uk Kim 
2906926ce35aSJung-uk Kim 	cmd = sc->rtsx_req->cmd;
2907926ce35aSJung-uk Kim 
2908577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
2909926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_xfer_finish() - CMD%d\n", cmd->opcode);
2910926ce35aSJung-uk Kim 
2911926ce35aSJung-uk Kim 	read = ISSET(cmd->data->flags, MMC_DATA_READ);
2912926ce35aSJung-uk Kim 
2913926ce35aSJung-uk Kim 	/* Sync data DMA buffer. */
2914926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_POSTREAD);
2915926ce35aSJung-uk Kim 	bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_POSTWRITE);
2916926ce35aSJung-uk Kim 
2917926ce35aSJung-uk Kim 	if (read) {
2918926ce35aSJung-uk Kim 		memcpy(cmd->data->data, sc->rtsx_data_dmamem, cmd->data->len);
2919926ce35aSJung-uk Kim 		rtsx_req_done(sc);
2920926ce35aSJung-uk Kim 	} else {
2921926ce35aSJung-uk Kim 		/* Send CMD12 after AUTO_WRITE3 (see mmcsd_rw() in mmcsd.c) */
2922926ce35aSJung-uk Kim 		/* and complete request. */
2923926ce35aSJung-uk Kim 		sc->rtsx_intr_trans_ok = NULL;
2924926ce35aSJung-uk Kim 		rtsx_send_req(sc, sc->rtsx_req->stop);
2925926ce35aSJung-uk Kim 	}
2926926ce35aSJung-uk Kim }
2927926ce35aSJung-uk Kim 
2928926ce35aSJung-uk Kim /*
2929926ce35aSJung-uk Kim  * Manage request timeout.
2930926ce35aSJung-uk Kim  */
2931926ce35aSJung-uk Kim static void
2932926ce35aSJung-uk Kim rtsx_timeout(void *arg)
2933926ce35aSJung-uk Kim {
2934926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
2935926ce35aSJung-uk Kim 
2936926ce35aSJung-uk Kim 	sc = (struct rtsx_softc *)arg;
2937926ce35aSJung-uk Kim 	if (sc->rtsx_req != NULL) {
2938926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Controller timeout for CMD%u\n",
2939926ce35aSJung-uk Kim 			      sc->rtsx_req->cmd->opcode);
2940926ce35aSJung-uk Kim 		sc->rtsx_req->cmd->error = MMC_ERR_TIMEOUT;
2941926ce35aSJung-uk Kim 		rtsx_stop_cmd(sc);
2942926ce35aSJung-uk Kim 		rtsx_req_done(sc);
2943926ce35aSJung-uk Kim 	} else {
2944926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "Controller timeout!\n");
2945926ce35aSJung-uk Kim 	}
2946926ce35aSJung-uk Kim }
2947926ce35aSJung-uk Kim 
2948926ce35aSJung-uk Kim #ifdef MMCCAM
29498e9740b6SHenri Hennebert static int
29508e9740b6SHenri Hennebert rtsx_get_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts)
2951926ce35aSJung-uk Kim {
2952926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
2953926ce35aSJung-uk Kim 
29548e9740b6SHenri Hennebert 	sc = device_get_softc(dev);
2955926ce35aSJung-uk Kim 
29568e9740b6SHenri Hennebert 	cts->host_ocr = sc->rtsx_host.host_ocr;
29578e9740b6SHenri Hennebert 	cts->host_f_min = sc->rtsx_host.f_min;
29588e9740b6SHenri Hennebert 	cts->host_f_max = sc->rtsx_host.f_max;
29598e9740b6SHenri Hennebert 	cts->host_caps = sc->rtsx_host.caps;
29608e9740b6SHenri Hennebert 	cts->host_max_data = RTSX_DMA_DATA_BUFSIZE / MMC_SECTOR_SIZE;
29618e9740b6SHenri Hennebert 	memcpy(&cts->ios, &sc->rtsx_host.ios, sizeof(struct mmc_ios));
2962926ce35aSJung-uk Kim 
29638e9740b6SHenri Hennebert 	return (0);
2964926ce35aSJung-uk Kim }
2965926ce35aSJung-uk Kim 
2966926ce35aSJung-uk Kim /*
29678e9740b6SHenri Hennebert  *  Apply settings and return status accordingly.
2968926ce35aSJung-uk Kim */
29698e9740b6SHenri Hennebert static int
29708e9740b6SHenri Hennebert rtsx_set_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts)
2971926ce35aSJung-uk Kim {
29728e9740b6SHenri Hennebert 	struct rtsx_softc *sc;
2973926ce35aSJung-uk Kim 	struct mmc_ios *ios;
2974926ce35aSJung-uk Kim 	struct mmc_ios *new_ios;
29758e9740b6SHenri Hennebert 
29768e9740b6SHenri Hennebert 	sc = device_get_softc(dev);
2977926ce35aSJung-uk Kim 
2978926ce35aSJung-uk Kim 	ios = &sc->rtsx_host.ios;
2979926ce35aSJung-uk Kim 	new_ios = &cts->ios;
2980926ce35aSJung-uk Kim 
2981926ce35aSJung-uk Kim 	/* Update only requested fields */
2982926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_CLK) {
2983926ce35aSJung-uk Kim 		ios->clock = new_ios->clock;
2984926ce35aSJung-uk Kim 		sc->rtsx_ios_clock = -1;	/* To be updated by rtsx_mmcbr_update_ios(). */
2985577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
29868e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - clock: %u\n", ios->clock);
2987926ce35aSJung-uk Kim 	}
2988926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_VDD) {
2989926ce35aSJung-uk Kim 		ios->vdd = new_ios->vdd;
2990577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
29918e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - vdd: %d\n", ios->vdd);
2992926ce35aSJung-uk Kim 	}
2993926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_CS) {
2994926ce35aSJung-uk Kim 		ios->chip_select = new_ios->chip_select;
2995577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
29968e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - chip_select: %d\n", ios->chip_select);
2997926ce35aSJung-uk Kim 	}
2998926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_BW) {
2999926ce35aSJung-uk Kim 		ios->bus_width = new_ios->bus_width;
3000926ce35aSJung-uk Kim 		sc->rtsx_ios_bus_width = -1;	/* To be updated by rtsx_mmcbr_update_ios(). */
3001577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
30028e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - bus width: %d\n", ios->bus_width);
3003926ce35aSJung-uk Kim 	}
3004926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_PM) {
3005926ce35aSJung-uk Kim 		ios->power_mode = new_ios->power_mode;
3006926ce35aSJung-uk Kim 		sc->rtsx_ios_power_mode = -1;	/* To be updated by rtsx_mmcbr_update_ios(). */
3007577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
30088e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - power mode: %d\n", ios->power_mode);
3009926ce35aSJung-uk Kim 	}
3010926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_BT) {
3011926ce35aSJung-uk Kim 		ios->timing = new_ios->timing;
3012926ce35aSJung-uk Kim 		sc->rtsx_ios_timing = -1;	/* To be updated by rtsx_mmcbr_update_ios(). */
3013577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
30148e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - timing: %d\n", ios->timing);
3015926ce35aSJung-uk Kim 	}
3016926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_BM) {
3017926ce35aSJung-uk Kim 		ios->bus_mode = new_ios->bus_mode;
3018577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
30198e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - bus mode: %d\n", ios->bus_mode);
3020926ce35aSJung-uk Kim 	}
30217e5933b3SHenri Hennebert #if  __FreeBSD_version >= 1300000
3022926ce35aSJung-uk Kim 	if (cts->ios_valid & MMC_VCCQ) {
3023926ce35aSJung-uk Kim 		ios->vccq = new_ios->vccq;
3024926ce35aSJung-uk Kim 		sc->rtsx_ios_vccq = -1;		/* To be updated by rtsx_mmcbr_update_ios(). */
3025577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
30268e9740b6SHenri Hennebert 			device_printf(sc->rtsx_dev, "rtsx_set_tran_settings() - vccq: %d\n", ios->vccq);
3027926ce35aSJung-uk Kim 	}
30287e5933b3SHenri Hennebert #endif /* __FreeBSD_version >= 1300000 */
3029926ce35aSJung-uk Kim 	if (rtsx_mmcbr_update_ios(sc->rtsx_dev, NULL) == 0)
30308e9740b6SHenri Hennebert 		return (CAM_REQ_CMP);
3031926ce35aSJung-uk Kim 	else
30328e9740b6SHenri Hennebert 		return (CAM_REQ_CMP_ERR);
3033926ce35aSJung-uk Kim }
3034926ce35aSJung-uk Kim 
3035926ce35aSJung-uk Kim /*
3036926ce35aSJung-uk Kim  * Build a request and run it.
3037926ce35aSJung-uk Kim  */
30388e9740b6SHenri Hennebert static int
30398e9740b6SHenri Hennebert rtsx_cam_request(device_t dev, union ccb *ccb)
3040926ce35aSJung-uk Kim {
30418e9740b6SHenri Hennebert 	struct rtsx_softc *sc;
30428e9740b6SHenri Hennebert 
30438e9740b6SHenri Hennebert 	sc = device_get_softc(dev);
30448e9740b6SHenri Hennebert 
3045926ce35aSJung-uk Kim 	RTSX_LOCK(sc);
3046926ce35aSJung-uk Kim 	if (sc->rtsx_ccb != NULL) {
3047926ce35aSJung-uk Kim 		RTSX_UNLOCK(sc);
30488e9740b6SHenri Hennebert 		return (CAM_BUSY);
3049926ce35aSJung-uk Kim 	}
3050926ce35aSJung-uk Kim 	sc->rtsx_ccb = ccb;
3051926ce35aSJung-uk Kim 	sc->rtsx_cam_req.cmd = &ccb->mmcio.cmd;
3052926ce35aSJung-uk Kim 	sc->rtsx_cam_req.stop = &ccb->mmcio.stop;
3053926ce35aSJung-uk Kim 	RTSX_UNLOCK(sc);
3054926ce35aSJung-uk Kim 
3055926ce35aSJung-uk Kim 	rtsx_mmcbr_request(sc->rtsx_dev, NULL, &sc->rtsx_cam_req);
30568e9740b6SHenri Hennebert 	return (0);
3057926ce35aSJung-uk Kim }
3058926ce35aSJung-uk Kim #endif /* MMCCAM */
3059926ce35aSJung-uk Kim 
3060926ce35aSJung-uk Kim static int
3061926ce35aSJung-uk Kim rtsx_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
3062926ce35aSJung-uk Kim {
3063926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3064926ce35aSJung-uk Kim 
3065926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3066926ce35aSJung-uk Kim 	switch (which) {
3067926ce35aSJung-uk Kim 	case MMCBR_IVAR_BUS_MODE:		/* ivar  0 - 1 = opendrain, 2 = pushpull */
3068926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.bus_mode;
3069926ce35aSJung-uk Kim 		break;
3070926ce35aSJung-uk Kim 	case MMCBR_IVAR_BUS_WIDTH:		/* ivar  1 - 0 = 1b   2 = 4b, 3 = 8b */
3071926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.bus_width;
3072926ce35aSJung-uk Kim 		break;
3073926ce35aSJung-uk Kim 	case MMCBR_IVAR_CHIP_SELECT:		/* ivar  2 - O = dontcare, 1 = cs_high, 2 = cs_low */
3074926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.chip_select;
3075926ce35aSJung-uk Kim 		break;
3076926ce35aSJung-uk Kim 	case MMCBR_IVAR_CLOCK:			/* ivar  3 - clock in Hz */
3077926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.clock;
3078926ce35aSJung-uk Kim 		break;
3079926ce35aSJung-uk Kim 	case MMCBR_IVAR_F_MIN:			/* ivar  4 */
3080926ce35aSJung-uk Kim 		*result = sc->rtsx_host.f_min;
3081926ce35aSJung-uk Kim 		break;
3082926ce35aSJung-uk Kim 	case MMCBR_IVAR_F_MAX:			/* ivar  5 */
3083926ce35aSJung-uk Kim 		*result = sc->rtsx_host.f_max;
3084926ce35aSJung-uk Kim 		break;
3085926ce35aSJung-uk Kim 	case MMCBR_IVAR_HOST_OCR: 		/* ivar  6 - host operation conditions register */
3086926ce35aSJung-uk Kim 		*result = sc->rtsx_host.host_ocr;
3087926ce35aSJung-uk Kim 		break;
3088926ce35aSJung-uk Kim 	case MMCBR_IVAR_MODE:			/* ivar  7 - 0 = mode_mmc, 1 = mode_sd */
3089926ce35aSJung-uk Kim 		*result = sc->rtsx_host.mode;
3090926ce35aSJung-uk Kim 		break;
3091926ce35aSJung-uk Kim 	case MMCBR_IVAR_OCR:			/* ivar  8 - operation conditions register */
3092926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ocr;
3093926ce35aSJung-uk Kim 		break;
3094926ce35aSJung-uk Kim 	case MMCBR_IVAR_POWER_MODE:		/* ivar  9 - 0 = off, 1 = up, 2 = on */
3095926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.power_mode;
3096926ce35aSJung-uk Kim 		break;
3097926ce35aSJung-uk Kim 	case MMCBR_IVAR_VDD:			/* ivar 11 - voltage power pin */
3098926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.vdd;
3099926ce35aSJung-uk Kim 		break;
3100926ce35aSJung-uk Kim 	case MMCBR_IVAR_VCCQ:			/* ivar 12 - signaling: 0 = 1.20V, 1 = 1.80V, 2 = 3.30V */
3101926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.vccq;
3102926ce35aSJung-uk Kim 		break;
3103926ce35aSJung-uk Kim 	case MMCBR_IVAR_CAPS:			/* ivar 13 */
3104926ce35aSJung-uk Kim 		*result = sc->rtsx_host.caps;
3105926ce35aSJung-uk Kim 		break;
3106926ce35aSJung-uk Kim 	case MMCBR_IVAR_TIMING:			/* ivar 14 - 0 = normal, 1 = timing_hs, ... */
3107926ce35aSJung-uk Kim 		*result = sc->rtsx_host.ios.timing;
3108926ce35aSJung-uk Kim 		break;
3109926ce35aSJung-uk Kim 	case MMCBR_IVAR_MAX_DATA:		/* ivar 15 */
3110926ce35aSJung-uk Kim 		*result = RTSX_DMA_DATA_BUFSIZE / MMC_SECTOR_SIZE;
3111926ce35aSJung-uk Kim 		break;
3112926ce35aSJung-uk Kim 	case MMCBR_IVAR_RETUNE_REQ:		/* ivar 10 */
3113926ce35aSJung-uk Kim 	case MMCBR_IVAR_MAX_BUSY_TIMEOUT:	/* ivar 16 */
3114926ce35aSJung-uk Kim 	default:
3115926ce35aSJung-uk Kim 		return (EINVAL);
3116926ce35aSJung-uk Kim 	}
3117926ce35aSJung-uk Kim 
3118577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3119926ce35aSJung-uk Kim 		device_printf(bus, "Read ivar #%d, value %#x / #%d\n",
3120926ce35aSJung-uk Kim 			      which, *(int *)result, *(int *)result);
3121926ce35aSJung-uk Kim 
3122926ce35aSJung-uk Kim 	return (0);
3123926ce35aSJung-uk Kim }
3124926ce35aSJung-uk Kim 
3125926ce35aSJung-uk Kim static int
3126926ce35aSJung-uk Kim rtsx_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
3127926ce35aSJung-uk Kim {
3128926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3129926ce35aSJung-uk Kim 
3130577130e5SHenri Hennebert 	sc = device_get_softc(bus);
3131577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3132926ce35aSJung-uk Kim 		device_printf(bus, "Write ivar #%d, value %#x / #%d\n",
3133926ce35aSJung-uk Kim 			      which, (int)value, (int)value);
3134926ce35aSJung-uk Kim 
3135926ce35aSJung-uk Kim 	switch (which) {
3136926ce35aSJung-uk Kim 	case MMCBR_IVAR_BUS_MODE:		/* ivar  0 - 1 = opendrain, 2 = pushpull */
3137926ce35aSJung-uk Kim 		sc->rtsx_host.ios.bus_mode = value;
3138926ce35aSJung-uk Kim 		break;
3139926ce35aSJung-uk Kim 	case MMCBR_IVAR_BUS_WIDTH:		/* ivar  1 - 0 = 1b   2 = 4b, 3 = 8b */
3140926ce35aSJung-uk Kim 		sc->rtsx_host.ios.bus_width = value;
3141926ce35aSJung-uk Kim 		sc->rtsx_ios_bus_width = -1;	/* To be updated on next rtsx_mmcbr_update_ios(). */
3142926ce35aSJung-uk Kim 		break;
3143926ce35aSJung-uk Kim 	case MMCBR_IVAR_CHIP_SELECT:		/* ivar  2 - O = dontcare, 1 = cs_high, 2 = cs_low */
3144926ce35aSJung-uk Kim 		sc->rtsx_host.ios.chip_select = value;
3145926ce35aSJung-uk Kim 		break;
3146926ce35aSJung-uk Kim 	case MMCBR_IVAR_CLOCK:			/* ivar  3 - clock in Hz */
3147926ce35aSJung-uk Kim 		sc->rtsx_host.ios.clock = value;
3148926ce35aSJung-uk Kim 		sc->rtsx_ios_clock = -1;	/* To be updated on next rtsx_mmcbr_update_ios(). */
3149926ce35aSJung-uk Kim 		break;
3150926ce35aSJung-uk Kim 	case MMCBR_IVAR_MODE:			/* ivar  7 - 0 = mode_mmc, 1 = mode_sd */
3151926ce35aSJung-uk Kim 		sc->rtsx_host.mode = value;
3152926ce35aSJung-uk Kim 		break;
3153926ce35aSJung-uk Kim 	case MMCBR_IVAR_OCR:			/* ivar  8 - operation conditions register */
3154926ce35aSJung-uk Kim 		sc->rtsx_host.ocr = value;
3155926ce35aSJung-uk Kim 		break;
3156926ce35aSJung-uk Kim 	case MMCBR_IVAR_POWER_MODE:		/* ivar  9 - 0 = off, 1 = up, 2 = on */
3157926ce35aSJung-uk Kim 		sc->rtsx_host.ios.power_mode = value;
3158926ce35aSJung-uk Kim 		sc->rtsx_ios_power_mode = -1;	/* To be updated on next rtsx_mmcbr_update_ios(). */
3159926ce35aSJung-uk Kim 		break;
3160926ce35aSJung-uk Kim 	case MMCBR_IVAR_VDD:			/* ivar 11 - voltage power pin */
3161926ce35aSJung-uk Kim 		sc->rtsx_host.ios.vdd = value;
3162926ce35aSJung-uk Kim 		break;
3163926ce35aSJung-uk Kim 	case MMCBR_IVAR_VCCQ:			/* ivar 12 - signaling: 0 = 1.20V, 1 = 1.80V, 2 = 3.30V */
3164926ce35aSJung-uk Kim 		sc->rtsx_host.ios.vccq = value;
3165926ce35aSJung-uk Kim 		sc->rtsx_ios_vccq = value;	/* rtsx_mmcbr_switch_vccq() will be called by mmc.c (MMCCAM undef). */
3166926ce35aSJung-uk Kim 		break;
3167926ce35aSJung-uk Kim 	case MMCBR_IVAR_TIMING:			/* ivar 14 - 0 = normal, 1 = timing_hs, ... */
3168926ce35aSJung-uk Kim 		sc->rtsx_host.ios.timing = value;
3169926ce35aSJung-uk Kim 		sc->rtsx_ios_timing = -1;	/* To be updated on next rtsx_mmcbr_update_ios(). */
3170926ce35aSJung-uk Kim 		break;
3171926ce35aSJung-uk Kim 	/* These are read-only. */
3172926ce35aSJung-uk Kim 	case MMCBR_IVAR_F_MIN:			/* ivar  4 */
3173926ce35aSJung-uk Kim 	case MMCBR_IVAR_F_MAX:			/* ivar  5 */
3174926ce35aSJung-uk Kim 	case MMCBR_IVAR_HOST_OCR: 		/* ivar  6 - host operation conditions register */
3175926ce35aSJung-uk Kim 	case MMCBR_IVAR_RETUNE_REQ:		/* ivar 10 */
3176926ce35aSJung-uk Kim 	case MMCBR_IVAR_CAPS:			/* ivar 13 */
3177926ce35aSJung-uk Kim 	case MMCBR_IVAR_MAX_DATA:		/* ivar 15 */
3178926ce35aSJung-uk Kim 	case MMCBR_IVAR_MAX_BUSY_TIMEOUT:	/* ivar 16 */
3179926ce35aSJung-uk Kim 	default:
3180926ce35aSJung-uk Kim 		return (EINVAL);
3181926ce35aSJung-uk Kim 	}
3182926ce35aSJung-uk Kim 
3183926ce35aSJung-uk Kim 	return (0);
3184926ce35aSJung-uk Kim }
3185926ce35aSJung-uk Kim 
3186926ce35aSJung-uk Kim static int
3187926ce35aSJung-uk Kim rtsx_mmcbr_update_ios(device_t bus, device_t child__unused)
3188926ce35aSJung-uk Kim {
3189926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3190926ce35aSJung-uk Kim 	struct mmc_ios	  *ios;
3191926ce35aSJung-uk Kim 	int	error;
3192926ce35aSJung-uk Kim 
3193926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3194926ce35aSJung-uk Kim 	ios = &sc->rtsx_host.ios;
3195926ce35aSJung-uk Kim 
3196577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3197926ce35aSJung-uk Kim 		device_printf(bus, "rtsx_mmcbr_update_ios()\n");
3198926ce35aSJung-uk Kim 
3199926ce35aSJung-uk Kim 	/* if MMCBR_IVAR_BUS_WIDTH updated. */
3200926ce35aSJung-uk Kim 	if (sc->rtsx_ios_bus_width < 0) {
3201926ce35aSJung-uk Kim 		sc->rtsx_ios_bus_width = ios->bus_width;
3202926ce35aSJung-uk Kim 		if ((error = rtsx_set_bus_width(sc, ios->bus_width)))
3203926ce35aSJung-uk Kim 			return (error);
3204926ce35aSJung-uk Kim 	}
3205926ce35aSJung-uk Kim 
3206926ce35aSJung-uk Kim 	/* if MMCBR_IVAR_POWER_MODE updated. */
3207926ce35aSJung-uk Kim 	if (sc->rtsx_ios_power_mode < 0) {
3208926ce35aSJung-uk Kim 		sc->rtsx_ios_power_mode = ios->power_mode;
3209926ce35aSJung-uk Kim 		switch (ios->power_mode) {
3210926ce35aSJung-uk Kim 		case power_off:
3211926ce35aSJung-uk Kim 			if ((error = rtsx_bus_power_off(sc)))
3212926ce35aSJung-uk Kim 				return (error);
3213926ce35aSJung-uk Kim 			break;
3214926ce35aSJung-uk Kim 		case power_up:
3215926ce35aSJung-uk Kim 			if ((error = rtsx_bus_power_on(sc)))
3216926ce35aSJung-uk Kim 				return (error);
3217926ce35aSJung-uk Kim 			break;
3218926ce35aSJung-uk Kim 		case power_on:
3219926ce35aSJung-uk Kim 			if ((error = rtsx_bus_power_on(sc)))
3220926ce35aSJung-uk Kim 				return (error);
3221926ce35aSJung-uk Kim 			break;
3222926ce35aSJung-uk Kim 		}
3223926ce35aSJung-uk Kim 	}
3224926ce35aSJung-uk Kim 
3225926ce35aSJung-uk Kim 	sc->rtsx_double_clk = true;
3226926ce35aSJung-uk Kim 	sc->rtsx_vpclk = false;
3227926ce35aSJung-uk Kim 
3228926ce35aSJung-uk Kim 	/* if MMCBR_IVAR_TIMING updated. */
3229926ce35aSJung-uk Kim 	if (sc->rtsx_ios_timing < 0) {
3230926ce35aSJung-uk Kim 		sc->rtsx_ios_timing = ios->timing;
3231926ce35aSJung-uk Kim 		if ((error = rtsx_set_sd_timing(sc, ios->timing)))
3232926ce35aSJung-uk Kim 			return (error);
3233926ce35aSJung-uk Kim 	}
3234926ce35aSJung-uk Kim 
3235926ce35aSJung-uk Kim 	/* if MMCBR_IVAR_CLOCK updated, must be after rtsx_set_sd_timing() */
3236926ce35aSJung-uk Kim 	if (sc->rtsx_ios_clock < 0) {
3237926ce35aSJung-uk Kim 		sc->rtsx_ios_clock = ios->clock;
3238926ce35aSJung-uk Kim 		if ((error = rtsx_set_sd_clock(sc, ios->clock)))
3239926ce35aSJung-uk Kim 			return (error);
3240926ce35aSJung-uk Kim 	}
3241926ce35aSJung-uk Kim 
3242926ce35aSJung-uk Kim 	/* if MMCCAM and vccq updated */
3243926ce35aSJung-uk Kim 	if (sc->rtsx_ios_vccq < 0) {
3244926ce35aSJung-uk Kim 		sc->rtsx_ios_vccq = ios->vccq;
3245926ce35aSJung-uk Kim 		if ((error = rtsx_mmcbr_switch_vccq(sc->rtsx_dev, NULL)))
3246926ce35aSJung-uk Kim 			return (error);
3247926ce35aSJung-uk Kim 	}
3248926ce35aSJung-uk Kim 
3249926ce35aSJung-uk Kim 	return (0);
3250926ce35aSJung-uk Kim }
3251926ce35aSJung-uk Kim 
3252926ce35aSJung-uk Kim /*
3253926ce35aSJung-uk Kim  * Set output stage logic power voltage.
3254926ce35aSJung-uk Kim  */
3255926ce35aSJung-uk Kim static int
3256926ce35aSJung-uk Kim rtsx_mmcbr_switch_vccq(device_t bus, device_t child __unused)
3257926ce35aSJung-uk Kim {
3258926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3259926ce35aSJung-uk Kim 	int	vccq = 0;
3260926ce35aSJung-uk Kim 	int	error;
3261926ce35aSJung-uk Kim 
3262926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3263926ce35aSJung-uk Kim 
3264926ce35aSJung-uk Kim 	switch (sc->rtsx_host.ios.vccq) {
3265926ce35aSJung-uk Kim 	case vccq_120:
3266926ce35aSJung-uk Kim 		vccq = 120;
3267926ce35aSJung-uk Kim 		break;
3268926ce35aSJung-uk Kim 	case vccq_180:
3269926ce35aSJung-uk Kim 		vccq = 180;
3270926ce35aSJung-uk Kim 		break;
3271926ce35aSJung-uk Kim 	case vccq_330:
3272926ce35aSJung-uk Kim 		vccq = 330;
3273926ce35aSJung-uk Kim 		break;
3274926ce35aSJung-uk Kim 	};
3275926ce35aSJung-uk Kim 	/* It seems it is always vccq_330. */
3276926ce35aSJung-uk Kim 	if (vccq == 330) {
3277926ce35aSJung-uk Kim 		switch (sc->rtsx_device_id) {
3278926ce35aSJung-uk Kim 			uint16_t val;
3279926ce35aSJung-uk Kim 		case RTSX_RTS5227:
3280926ce35aSJung-uk Kim 			if ((error = rtsx_write_phy(sc, 0x08, 0x4FE4)))
3281926ce35aSJung-uk Kim 				return (error);
3282926ce35aSJung-uk Kim 			if ((error = rtsx_rts5227_fill_driving(sc)))
3283926ce35aSJung-uk Kim 				return (error);
3284926ce35aSJung-uk Kim 			break;
3285926ce35aSJung-uk Kim 		case RTSX_RTS5209:
3286926ce35aSJung-uk Kim 		case RTSX_RTS5229:
3287926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_SD30_CMD_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_MASK, sc->rtsx_sd30_drive_sel_3v3);
3288926ce35aSJung-uk Kim 			if ((error = rtsx_write_phy(sc, 0x08, 0x4FE4)))
3289926ce35aSJung-uk Kim 				return (error);
3290926ce35aSJung-uk Kim 			break;
3291926ce35aSJung-uk Kim 		case RTSX_RTS522A:
3292926ce35aSJung-uk Kim 			if ((error = rtsx_write_phy(sc, 0x08, 0x57E4)))
3293926ce35aSJung-uk Kim 				return (error);
3294926ce35aSJung-uk Kim 			if ((error = rtsx_rts5227_fill_driving(sc)))
3295926ce35aSJung-uk Kim 				return (error);
3296926ce35aSJung-uk Kim 			break;
3297926ce35aSJung-uk Kim 		case RTSX_RTS525A:
3298926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_LDO_D3318_MASK, RTSX_LDO_D3318_33V);
3299926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_SD_PAD_CTL, RTSX_SD_IO_USING_1V8, 0);
3300926ce35aSJung-uk Kim 			if ((error = rtsx_rts5249_fill_driving(sc)))
3301926ce35aSJung-uk Kim 				return (error);
3302926ce35aSJung-uk Kim 			break;
3303926ce35aSJung-uk Kim 		case RTSX_RTS5249:
3304926ce35aSJung-uk Kim 			if ((error = rtsx_read_phy(sc, RTSX_PHY_TUNE, &val)))
3305926ce35aSJung-uk Kim 				return (error);
3306926ce35aSJung-uk Kim 			if ((error = rtsx_write_phy(sc, RTSX_PHY_TUNE,
3307926ce35aSJung-uk Kim 						    (val & RTSX_PHY_TUNE_VOLTAGE_MASK) | RTSX_PHY_TUNE_VOLTAGE_3V3)))
3308926ce35aSJung-uk Kim 				return (error);
3309926ce35aSJung-uk Kim 			if ((error = rtsx_rts5249_fill_driving(sc)))
3310926ce35aSJung-uk Kim 				return (error);
3311926ce35aSJung-uk Kim 			break;
3312577130e5SHenri Hennebert 		case RTSX_RTS5260:
3313577130e5SHenri Hennebert 			RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_DV331812_VDD1, RTSX_DV331812_VDD1);
3314577130e5SHenri Hennebert 			RTSX_BITOP(sc, RTSX_LDO_DV18_CFG, RTSX_DV331812_MASK, RTSX_DV331812_33);
33158290c144SHenri Hennebert 			RTSX_CLR(sc, RTSX_SD_PAD_CTL, RTSX_SD_IO_USING_1V8);
3316577130e5SHenri Hennebert 			if ((error = rtsx_rts5260_fill_driving(sc)))
3317577130e5SHenri Hennebert 				return (error);
3318577130e5SHenri Hennebert 			break;
3319926ce35aSJung-uk Kim 		case RTSX_RTL8402:
3320926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_SD30_CMD_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_MASK, sc->rtsx_sd30_drive_sel_3v3);
3321926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_CTL,
3322926ce35aSJung-uk Kim 				   (RTSX_BPP_ASIC_MASK << RTSX_BPP_SHIFT_8402) | RTSX_BPP_PAD_MASK,
3323926ce35aSJung-uk Kim 				   (RTSX_BPP_ASIC_3V3 << RTSX_BPP_SHIFT_8402) | RTSX_BPP_PAD_3V3);
3324926ce35aSJung-uk Kim 			break;
3325926ce35aSJung-uk Kim 		case RTSX_RTL8411:
3326926ce35aSJung-uk Kim 		case RTSX_RTL8411B:
3327926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_SD30_CMD_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_MASK, sc->rtsx_sd30_drive_sel_3v3);
3328926ce35aSJung-uk Kim 			RTSX_BITOP(sc, RTSX_LDO_CTL,
3329926ce35aSJung-uk Kim 				   (RTSX_BPP_ASIC_MASK << RTSX_BPP_SHIFT_8411) | RTSX_BPP_PAD_MASK,
3330926ce35aSJung-uk Kim 				   (RTSX_BPP_ASIC_3V3 << RTSX_BPP_SHIFT_8411) | RTSX_BPP_PAD_3V3);
3331926ce35aSJung-uk Kim 			break;
3332926ce35aSJung-uk Kim 		}
3333926ce35aSJung-uk Kim 		DELAY(300);
3334926ce35aSJung-uk Kim 	}
3335926ce35aSJung-uk Kim 
3336577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & (RTSX_DEBUG_BASIC | RTSX_TRACE_SD_CMD))
3337926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_mmcbr_switch_vccq(%d)\n", vccq);
3338926ce35aSJung-uk Kim 
3339926ce35aSJung-uk Kim 	return (0);
3340926ce35aSJung-uk Kim }
3341926ce35aSJung-uk Kim 
33428e9740b6SHenri Hennebert #ifndef MMCCAM
3343926ce35aSJung-uk Kim /*
3344926ce35aSJung-uk Kim  * Tune card if bus_timing_uhs_sdr50.
3345926ce35aSJung-uk Kim  */
3346926ce35aSJung-uk Kim static int
3347926ce35aSJung-uk Kim rtsx_mmcbr_tune(device_t bus, device_t child __unused, bool hs400)
3348926ce35aSJung-uk Kim {
3349926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3350926ce35aSJung-uk Kim 	uint32_t raw_phase_map[RTSX_RX_TUNING_CNT] = {0};
3351926ce35aSJung-uk Kim 	uint32_t phase_map;
3352926ce35aSJung-uk Kim 	uint8_t	 final_phase;
3353926ce35aSJung-uk Kim 	int	 i;
3354926ce35aSJung-uk Kim 
3355926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3356926ce35aSJung-uk Kim 
3357577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
3358926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_mmcbr_tune() - hs400 is %s\n",
3359926ce35aSJung-uk Kim 			      (hs400) ? "true" : "false");
3360926ce35aSJung-uk Kim 
3361926ce35aSJung-uk Kim 	if (sc->rtsx_ios_timing != bus_timing_uhs_sdr50)
3362926ce35aSJung-uk Kim 		return (0);
3363926ce35aSJung-uk Kim 
3364926ce35aSJung-uk Kim 	sc->rtsx_tuning_mode = true;
3365926ce35aSJung-uk Kim 
3366926ce35aSJung-uk Kim 	switch (sc->rtsx_device_id) {
3367926ce35aSJung-uk Kim 	case RTSX_RTS5209:
3368926ce35aSJung-uk Kim 	case RTSX_RTS5227:
3369926ce35aSJung-uk Kim 		rtsx_sd_change_tx_phase(sc, 27);
3370926ce35aSJung-uk Kim 		break;
3371926ce35aSJung-uk Kim 	case RTSX_RTS522A:
3372926ce35aSJung-uk Kim 		rtsx_sd_change_tx_phase(sc, 20);
3373926ce35aSJung-uk Kim 		break;
3374926ce35aSJung-uk Kim 	case RTSX_RTS5229:
3375926ce35aSJung-uk Kim 		rtsx_sd_change_tx_phase(sc, 27);
3376926ce35aSJung-uk Kim 		break;
3377926ce35aSJung-uk Kim 	case RTSX_RTS525A:
3378926ce35aSJung-uk Kim 	case RTSX_RTS5249:
3379926ce35aSJung-uk Kim 		rtsx_sd_change_tx_phase(sc, 29);
3380926ce35aSJung-uk Kim 		break;
3381926ce35aSJung-uk Kim 	case RTSX_RTL8402:
3382926ce35aSJung-uk Kim 	case RTSX_RTL8411:
3383926ce35aSJung-uk Kim 	case RTSX_RTL8411B:
3384926ce35aSJung-uk Kim 		rtsx_sd_change_tx_phase(sc, 7);
3385926ce35aSJung-uk Kim 		break;
3386926ce35aSJung-uk Kim 	}
3387926ce35aSJung-uk Kim 
3388926ce35aSJung-uk Kim 	/* trying rx tuning for bus_timing_uhs_sdr50. */
3389926ce35aSJung-uk Kim 	for (i = 0; i < RTSX_RX_TUNING_CNT; i++) {
3390926ce35aSJung-uk Kim 		rtsx_sd_tuning_rx_phase(sc, &(raw_phase_map[i]));
3391926ce35aSJung-uk Kim 		if (raw_phase_map[i] == 0)
3392926ce35aSJung-uk Kim 			break;
3393926ce35aSJung-uk Kim 	}
3394926ce35aSJung-uk Kim 
3395926ce35aSJung-uk Kim 	phase_map = 0xffffffff;
3396926ce35aSJung-uk Kim 	for (i = 0; i < RTSX_RX_TUNING_CNT; i++) {
3397577130e5SHenri Hennebert 		if (sc->rtsx_debug_mask & (RTSX_DEBUG_BASIC | RTSX_DEBUG_TUNING))
3398926ce35aSJung-uk Kim 			device_printf(sc->rtsx_dev, "rtsx_mmcbr_tune() - RX raw_phase_map[%d]: 0x%08x\n",
3399926ce35aSJung-uk Kim 				      i, raw_phase_map[i]);
3400926ce35aSJung-uk Kim 		phase_map &= raw_phase_map[i];
3401926ce35aSJung-uk Kim 	}
3402577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
3403926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_mmcbr_tune() - RX phase_map: 0x%08x\n", phase_map);
3404926ce35aSJung-uk Kim 
3405926ce35aSJung-uk Kim 	if (phase_map) {
3406926ce35aSJung-uk Kim 		final_phase = rtsx_sd_search_final_rx_phase(sc, phase_map);
3407926ce35aSJung-uk Kim 		if (final_phase != 0xff) {
3408926ce35aSJung-uk Kim 			rtsx_sd_change_rx_phase(sc, final_phase);
3409926ce35aSJung-uk Kim 		}
3410926ce35aSJung-uk Kim 	}
3411926ce35aSJung-uk Kim 
3412926ce35aSJung-uk Kim 	sc->rtsx_tuning_mode = false;
3413926ce35aSJung-uk Kim 
3414926ce35aSJung-uk Kim 	return (0);
3415926ce35aSJung-uk Kim }
3416926ce35aSJung-uk Kim 
3417926ce35aSJung-uk Kim static int
3418926ce35aSJung-uk Kim rtsx_mmcbr_retune(device_t bus, device_t child __unused, bool reset __unused)
3419926ce35aSJung-uk Kim {
3420926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3421926ce35aSJung-uk Kim 
3422926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3423926ce35aSJung-uk Kim 
3424577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3425926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_mmcbr_retune()\n");
3426926ce35aSJung-uk Kim 
3427926ce35aSJung-uk Kim 	return (0);
3428926ce35aSJung-uk Kim }
34298e9740b6SHenri Hennebert #endif /* !MMCCAM */
3430926ce35aSJung-uk Kim 
3431926ce35aSJung-uk Kim static int
3432926ce35aSJung-uk Kim rtsx_mmcbr_request(device_t bus, device_t child __unused, struct mmc_request *req)
3433926ce35aSJung-uk Kim {
3434926ce35aSJung-uk Kim 	struct rtsx_softc  *sc;
3435926ce35aSJung-uk Kim 	struct mmc_command *cmd;
34369d3bc163SHenri Hennebert 	int	timeout;
3437926ce35aSJung-uk Kim 	int	error;
3438926ce35aSJung-uk Kim 
3439926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3440926ce35aSJung-uk Kim 
3441926ce35aSJung-uk Kim 	RTSX_LOCK(sc);
3442926ce35aSJung-uk Kim 	if (sc->rtsx_req != NULL) {
3443926ce35aSJung-uk Kim 		RTSX_UNLOCK(sc);
3444926ce35aSJung-uk Kim 		return (EBUSY);
3445926ce35aSJung-uk Kim 	}
3446926ce35aSJung-uk Kim 	sc->rtsx_req = req;
3447926ce35aSJung-uk Kim 	cmd = req->cmd;
3448926ce35aSJung-uk Kim 	cmd->error = error = MMC_ERR_NONE;
3449926ce35aSJung-uk Kim 	sc->rtsx_intr_status = 0;
3450926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ok = NULL;
3451926ce35aSJung-uk Kim 	sc->rtsx_intr_trans_ko = rtsx_req_done;
3452926ce35aSJung-uk Kim 
3453577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3454926ce35aSJung-uk Kim 		device_printf(sc->rtsx_dev, "rtsx_mmcbr_request(CMD%u arg %#x, flags %#x, dlen %u, dflags %#x)\n",
3455926ce35aSJung-uk Kim 			      cmd->opcode, cmd->arg, cmd->flags,
3456926ce35aSJung-uk Kim 			      cmd->data != NULL ? (unsigned int)cmd->data->len : 0,
3457926ce35aSJung-uk Kim 			      cmd->data != NULL ? cmd->data->flags : 0);
3458926ce35aSJung-uk Kim 
3459926ce35aSJung-uk Kim 	/* Check if card present. */
3460926ce35aSJung-uk Kim 	if (!ISSET(sc->rtsx_flags, RTSX_F_CARD_PRESENT)) {
3461926ce35aSJung-uk Kim 		cmd->error = error = MMC_ERR_FAILED;
3462926ce35aSJung-uk Kim 		goto end;
3463926ce35aSJung-uk Kim 	}
3464926ce35aSJung-uk Kim 
3465926ce35aSJung-uk Kim 	/* Refuse SDIO probe if the chip doesn't support SDIO. */
3466926ce35aSJung-uk Kim 	if (cmd->opcode == IO_SEND_OP_COND &&
3467926ce35aSJung-uk Kim 	    !ISSET(sc->rtsx_flags, RTSX_F_SDIO_SUPPORT)) {
3468926ce35aSJung-uk Kim 		cmd->error = error = MMC_ERR_INVALID;
3469926ce35aSJung-uk Kim 		goto end;
3470926ce35aSJung-uk Kim 	}
3471926ce35aSJung-uk Kim 
3472926ce35aSJung-uk Kim 	/* Return MMC_ERR_TIMEOUT for SD_IO_RW_DIRECT and IO_SEND_OP_COND. */
3473926ce35aSJung-uk Kim 	if (cmd->opcode == SD_IO_RW_DIRECT || cmd->opcode == IO_SEND_OP_COND) {
3474926ce35aSJung-uk Kim 		cmd->error = error = MMC_ERR_TIMEOUT;
3475926ce35aSJung-uk Kim 		goto end;
3476926ce35aSJung-uk Kim 	}
3477926ce35aSJung-uk Kim 
3478926ce35aSJung-uk Kim 	/* Select SD card. */
3479926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CARD_SELECT, 0x07, RTSX_SD_MOD_SEL);
3480926ce35aSJung-uk Kim 	RTSX_BITOP(sc, RTSX_CARD_SHARE_MODE, RTSX_CARD_SHARE_MASK, RTSX_CARD_SHARE_48_SD);
3481926ce35aSJung-uk Kim 
3482926ce35aSJung-uk Kim 	if (cmd->data == NULL) {
3483926ce35aSJung-uk Kim 		DELAY(200);
34849d3bc163SHenri Hennebert 		timeout = sc->rtsx_timeout_cmd;
3485926ce35aSJung-uk Kim 		error = rtsx_send_req(sc, cmd);
3486926ce35aSJung-uk Kim 	} else if (cmd->data->len <= 512) {
34879d3bc163SHenri Hennebert 		timeout = sc->rtsx_timeout_io;
3488926ce35aSJung-uk Kim 		error = rtsx_xfer_short(sc, cmd);
3489926ce35aSJung-uk Kim 	} else {
34909d3bc163SHenri Hennebert 		timeout = sc->rtsx_timeout_io;
3491926ce35aSJung-uk Kim 		error = rtsx_xfer(sc, cmd);
3492926ce35aSJung-uk Kim 	}
3493926ce35aSJung-uk Kim  end:
3494926ce35aSJung-uk Kim 	if (error == MMC_ERR_NONE) {
34959d3bc163SHenri Hennebert 		callout_reset(&sc->rtsx_timeout_callout, timeout * hz, rtsx_timeout, sc);
3496926ce35aSJung-uk Kim 	} else {
3497926ce35aSJung-uk Kim 		rtsx_req_done(sc);
3498926ce35aSJung-uk Kim 	}
3499926ce35aSJung-uk Kim 	RTSX_UNLOCK(sc);
3500926ce35aSJung-uk Kim 
3501926ce35aSJung-uk Kim 	return (error);
3502926ce35aSJung-uk Kim }
3503926ce35aSJung-uk Kim 
35048e9740b6SHenri Hennebert #ifndef MMCCAM
3505926ce35aSJung-uk Kim static int
3506926ce35aSJung-uk Kim rtsx_mmcbr_get_ro(device_t bus, device_t child __unused)
3507926ce35aSJung-uk Kim {
3508926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3509926ce35aSJung-uk Kim 
3510926ce35aSJung-uk Kim 	sc = device_get_softc(bus);
3511926ce35aSJung-uk Kim 
3512926ce35aSJung-uk Kim 	if (sc->rtsx_inversion == 0)
3513926ce35aSJung-uk Kim 		return (sc->rtsx_read_only);
3514926ce35aSJung-uk Kim 	else
3515926ce35aSJung-uk Kim 		return !(sc->rtsx_read_only);
3516926ce35aSJung-uk Kim }
3517926ce35aSJung-uk Kim 
3518926ce35aSJung-uk Kim static int
3519926ce35aSJung-uk Kim rtsx_mmcbr_acquire_host(device_t bus, device_t child __unused)
3520926ce35aSJung-uk Kim {
3521926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3522926ce35aSJung-uk Kim 
3523577130e5SHenri Hennebert 	sc = device_get_softc(bus);
3524577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3525926ce35aSJung-uk Kim 		device_printf(bus, "rtsx_mmcbr_acquire_host()\n");
3526926ce35aSJung-uk Kim 
3527926ce35aSJung-uk Kim 	RTSX_LOCK(sc);
3528926ce35aSJung-uk Kim 	while (sc->rtsx_bus_busy)
3529926ce35aSJung-uk Kim 		msleep(&sc->rtsx_bus_busy, &sc->rtsx_mtx, 0, "rtsxah", 0);
3530926ce35aSJung-uk Kim 	sc->rtsx_bus_busy++;
3531926ce35aSJung-uk Kim 	RTSX_UNLOCK(sc);
3532926ce35aSJung-uk Kim 
3533926ce35aSJung-uk Kim 	return (0);
3534926ce35aSJung-uk Kim }
3535926ce35aSJung-uk Kim 
3536926ce35aSJung-uk Kim static int
3537926ce35aSJung-uk Kim rtsx_mmcbr_release_host(device_t bus, device_t child __unused)
3538926ce35aSJung-uk Kim {
3539926ce35aSJung-uk Kim 	struct rtsx_softc *sc;
3540926ce35aSJung-uk Kim 
3541577130e5SHenri Hennebert 	sc = device_get_softc(bus);
3542577130e5SHenri Hennebert 	if (sc->rtsx_debug_mask & RTSX_TRACE_SD_CMD)
3543926ce35aSJung-uk Kim 		device_printf(bus, "rtsx_mmcbr_release_host()\n");
3544926ce35aSJung-uk Kim 
3545926ce35aSJung-uk Kim 	RTSX_LOCK(sc);
3546926ce35aSJung-uk Kim 	sc->rtsx_bus_busy--;
3547926ce35aSJung-uk Kim 	wakeup(&sc->rtsx_bus_busy);
35489339e7c0SWarner Losh 	RTSX_UNLOCK(sc);
3549926ce35aSJung-uk Kim 
3550926ce35aSJung-uk Kim 	return (0);
3551926ce35aSJung-uk Kim }
35528e9740b6SHenri Hennebert #endif /* !MMCCAM */
3553926ce35aSJung-uk Kim 
3554926ce35aSJung-uk Kim /*
3555926ce35aSJung-uk Kim  *
3556926ce35aSJung-uk Kim  * PCI Support Functions
3557926ce35aSJung-uk Kim  *
3558926ce35aSJung-uk Kim  */
3559926ce35aSJung-uk Kim 
3560926ce35aSJung-uk Kim /*
3561926ce35aSJung-uk Kim  * Compare the device ID (chip) of this device against the IDs that this driver
3562926ce35aSJung-uk Kim  * supports. If there is a match, set the description and return success.
3563926ce35aSJung-uk Kim  */
3564926ce35aSJung-uk Kim static int
3565926ce35aSJung-uk Kim rtsx_probe(device_t dev)
3566926ce35aSJung-uk Kim {
3567926ce35aSJung-uk Kim 	uint16_t vendor_id;
3568926ce35aSJung-uk Kim 	uint16_t device_id;
3569926ce35aSJung-uk Kim 	int	 i;
3570926ce35aSJung-uk Kim 
3571926ce35aSJung-uk Kim 	vendor_id = pci_get_vendor(dev);
3572926ce35aSJung-uk Kim 	device_id = pci_get_device(dev);
3573926ce35aSJung-uk Kim 
357471883128SHenri Hennebert 	if (vendor_id != RTSX_REALTEK)
357571883128SHenri Hennebert 		return (ENXIO);
357671883128SHenri Hennebert 	for (i = 0; i < nitems(rtsx_ids); i++) {
357771883128SHenri Hennebert 		if (rtsx_ids[i].device_id == device_id) {
357871883128SHenri Hennebert 			device_set_desc(dev, rtsx_ids[i].desc);
357971883128SHenri Hennebert 			return (BUS_PROBE_DEFAULT);
3580926ce35aSJung-uk Kim 		}
3581926ce35aSJung-uk Kim 	}
358271883128SHenri Hennebert 	return (ENXIO);
3583926ce35aSJung-uk Kim }
3584926ce35aSJung-uk Kim 
3585926ce35aSJung-uk Kim /*
3586926ce35aSJung-uk Kim  * Attach function is only called if the probe is successful.
3587926ce35aSJung-uk Kim  */
3588926ce35aSJung-uk Kim static int
3589926ce35aSJung-uk Kim rtsx_attach(device_t dev)
3590926ce35aSJung-uk Kim {
3591926ce35aSJung-uk Kim 	struct rtsx_softc 	*sc = device_get_softc(dev);
35922e883067SHenri Hennebert 	uint16_t 		vendor_id;
35932e883067SHenri Hennebert 	uint16_t 		device_id;
3594926ce35aSJung-uk Kim 	struct sysctl_ctx_list	*ctx;
3595926ce35aSJung-uk Kim 	struct sysctl_oid_list	*tree;
3596926ce35aSJung-uk Kim 	int			msi_count = 1;
3597926ce35aSJung-uk Kim 	uint32_t		sdio_cfg;
3598926ce35aSJung-uk Kim 	int			error;
35999d3bc163SHenri Hennebert 	char			*maker;
36009d3bc163SHenri Hennebert 	char			*family;
36019d3bc163SHenri Hennebert 	char			*product;
36029d3bc163SHenri Hennebert 	int			i;
3603926ce35aSJung-uk Kim 
36042e883067SHenri Hennebert 	vendor_id = pci_get_vendor(dev);
36052e883067SHenri Hennebert 	device_id = pci_get_device(dev);
3606926ce35aSJung-uk Kim 	if (bootverbose)
3607926ce35aSJung-uk Kim 		device_printf(dev, "Attach - Vendor ID: 0x%x - Device ID: 0x%x\n",
36082e883067SHenri Hennebert 			      vendor_id, device_id);
3609926ce35aSJung-uk Kim 
3610926ce35aSJung-uk Kim 	sc->rtsx_dev = dev;
36112e883067SHenri Hennebert 	sc->rtsx_device_id = device_id;
3612926ce35aSJung-uk Kim 	sc->rtsx_req = NULL;
36139d3bc163SHenri Hennebert 	sc->rtsx_timeout_cmd = 1;
36149d3bc163SHenri Hennebert 	sc->rtsx_timeout_io = 10;
3615926ce35aSJung-uk Kim 	sc->rtsx_read_only = 0;
36169d3bc163SHenri Hennebert 	sc->rtsx_inversion = 0;
3617926ce35aSJung-uk Kim 	sc->rtsx_force_timing = 0;
3618577130e5SHenri Hennebert 	sc->rtsx_debug_mask = 0;
3619926ce35aSJung-uk Kim 	sc->rtsx_read_count = 0;
3620926ce35aSJung-uk Kim 	sc->rtsx_write_count = 0;
3621926ce35aSJung-uk Kim 
36229d3bc163SHenri Hennebert 	maker = kern_getenv("smbios.system.maker");
36239d3bc163SHenri Hennebert 	family = kern_getenv("smbios.system.family");
36249d3bc163SHenri Hennebert 	product = kern_getenv("smbios.system.product");
36259d3bc163SHenri Hennebert 	for (i = 0; rtsx_inversion_models[i].maker != NULL; i++) {
36269d3bc163SHenri Hennebert 		if (strcmp(rtsx_inversion_models[i].maker, maker) == 0 &&
36279d3bc163SHenri Hennebert 		    strcmp(rtsx_inversion_models[i].family, family) == 0 &&
36289d3bc163SHenri Hennebert 		    strcmp(rtsx_inversion_models[i].product, product) == 0) {
36299d3bc163SHenri Hennebert 			device_printf(dev, "Inversion activated for %s/%s/%s, see BUG in rtsx(4)\n", maker, family, product);
36309d3bc163SHenri Hennebert 			device_printf(dev, "If a card is detected without an SD card present,"
36319d3bc163SHenri Hennebert 				      " add dev.rtsx.0.inversion=0 in loader.conf(5)\n");
36329d3bc163SHenri Hennebert 			sc->rtsx_inversion = 1;
3633459404cbSWarner Losh 			break;
36349d3bc163SHenri Hennebert 		}
36359d3bc163SHenri Hennebert 	}
36369d3bc163SHenri Hennebert 
3637926ce35aSJung-uk Kim 	RTSX_LOCK_INIT(sc);
3638926ce35aSJung-uk Kim 
3639926ce35aSJung-uk Kim 	ctx = device_get_sysctl_ctx(dev);
3640926ce35aSJung-uk Kim 	tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
36419d3bc163SHenri Hennebert 	SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "timeout_io", CTLFLAG_RW,
36429d3bc163SHenri Hennebert 		       &sc->rtsx_timeout_io, 0, "Request timeout for I/O commands in seconds");
36439d3bc163SHenri Hennebert 	SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "timeout_cmd", CTLFLAG_RW,
36449d3bc163SHenri Hennebert 		       &sc->rtsx_timeout_cmd, 0, "Request timeout for setup commands in seconds");
3645926ce35aSJung-uk Kim 	SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "read_only", CTLFLAG_RD,
3646926ce35aSJung-uk Kim 		      &sc->rtsx_read_only, 0, "Card is write protected");
3647926ce35aSJung-uk Kim 	SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "inversion", CTLFLAG_RWTUN,
3648926ce35aSJung-uk Kim 		      &sc->rtsx_inversion, 0, "Inversion of card detection and read only status");
3649926ce35aSJung-uk Kim 	SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "force_timing", CTLFLAG_RW,
3650926ce35aSJung-uk Kim 		      &sc->rtsx_force_timing, 0, "Force bus_timing_uhs_sdr50");
3651577130e5SHenri Hennebert 	SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "debug_mask", CTLFLAG_RWTUN,
3652577130e5SHenri Hennebert 		      &sc->rtsx_debug_mask, 0, "debugging mask, see rtsx(4)");
3653ec1f122bSHenri Hennebert 	SYSCTL_ADD_U64(ctx, tree, OID_AUTO, "read_count", CTLFLAG_RD | CTLFLAG_STATS,
3654926ce35aSJung-uk Kim 		       &sc->rtsx_read_count, 0, "Count of read operations");
3655ec1f122bSHenri Hennebert 	SYSCTL_ADD_U64(ctx, tree, OID_AUTO, "write_count", CTLFLAG_RD | CTLFLAG_STATS,
3656926ce35aSJung-uk Kim 		       &sc->rtsx_write_count, 0, "Count of write operations");
3657926ce35aSJung-uk Kim 
3658577130e5SHenri Hennebert 	if (bootverbose || sc->rtsx_debug_mask & RTSX_DEBUG_BASIC)
36599d3bc163SHenri Hennebert 		device_printf(dev, "We are running with inversion: %d\n", sc->rtsx_inversion);
36609d3bc163SHenri Hennebert 
3661926ce35aSJung-uk Kim 	/* Allocate IRQ. */
3662926ce35aSJung-uk Kim 	sc->rtsx_irq_res_id = 0;
3663926ce35aSJung-uk Kim 	if (pci_alloc_msi(dev, &msi_count) == 0)
3664926ce35aSJung-uk Kim 		sc->rtsx_irq_res_id = 1;
3665926ce35aSJung-uk Kim 	sc->rtsx_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rtsx_irq_res_id,
3666926ce35aSJung-uk Kim 						  RF_ACTIVE | (sc->rtsx_irq_res_id != 0 ? 0 : RF_SHAREABLE));
3667926ce35aSJung-uk Kim 	if (sc->rtsx_irq_res == NULL) {
3668926ce35aSJung-uk Kim 		device_printf(dev, "Can't allocate IRQ resources for %d\n", sc->rtsx_irq_res_id);
3669926ce35aSJung-uk Kim 		pci_release_msi(dev);
3670926ce35aSJung-uk Kim 		return (ENXIO);
3671926ce35aSJung-uk Kim 	}
3672926ce35aSJung-uk Kim 
3673926ce35aSJung-uk Kim 	callout_init_mtx(&sc->rtsx_timeout_callout, &sc->rtsx_mtx, 0);
3674926ce35aSJung-uk Kim 
3675926ce35aSJung-uk Kim 	/* Allocate memory resource. */
3676926ce35aSJung-uk Kim 	if (sc->rtsx_device_id == RTSX_RTS525A)
36772e883067SHenri Hennebert 		sc->rtsx_mem_res_id = PCIR_BAR(1);
3678926ce35aSJung-uk Kim 	else
36792e883067SHenri Hennebert 		sc->rtsx_mem_res_id = PCIR_BAR(0);
36802e883067SHenri Hennebert 	sc->rtsx_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rtsx_mem_res_id, RF_ACTIVE);
36812e883067SHenri Hennebert 	if (sc->rtsx_mem_res == NULL) {
36822e883067SHenri Hennebert 		device_printf(dev, "Can't allocate memory resource for %d\n", sc->rtsx_mem_res_id);
3683926ce35aSJung-uk Kim 		goto destroy_rtsx_irq_res;
3684926ce35aSJung-uk Kim 	}
3685926ce35aSJung-uk Kim 
3686926ce35aSJung-uk Kim 	if (bootverbose)
36872e883067SHenri Hennebert 		device_printf(dev, "rtsx_irq_res_id: %d, rtsx_mem_res_id: %d\n",
36882e883067SHenri Hennebert 			      sc->rtsx_irq_res_id, sc->rtsx_mem_res_id);
3689926ce35aSJung-uk Kim 
36902e883067SHenri Hennebert 	sc->rtsx_mem_btag = rman_get_bustag(sc->rtsx_mem_res);
36912e883067SHenri Hennebert 	sc->rtsx_mem_bhandle = rman_get_bushandle(sc->rtsx_mem_res);
3692926ce35aSJung-uk Kim 
36939d3bc163SHenri Hennebert 	TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->rtsx_card_insert_task, 0,
36949d3bc163SHenri Hennebert 			  rtsx_card_task, sc);
36959d3bc163SHenri Hennebert 	TASK_INIT(&sc->rtsx_card_remove_task, 0, rtsx_card_task, sc);
36969d3bc163SHenri Hennebert 
36979d3bc163SHenri Hennebert 	/* Allocate two DMA buffers: a command buffer and a data buffer. */
36989d3bc163SHenri Hennebert 	error = rtsx_dma_alloc(sc);
36999d3bc163SHenri Hennebert 	if (error)
37009d3bc163SHenri Hennebert 		goto destroy_rtsx_irq_res;
37019d3bc163SHenri Hennebert 
3702926ce35aSJung-uk Kim 	/* Activate the interrupt. */
3703926ce35aSJung-uk Kim 	error = bus_setup_intr(dev, sc->rtsx_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
3704926ce35aSJung-uk Kim 			       NULL, rtsx_intr, sc, &sc->rtsx_irq_cookie);
3705926ce35aSJung-uk Kim 	if (error) {
3706926ce35aSJung-uk Kim 		device_printf(dev, "Can't set up irq [0x%x]!\n", error);
37072e883067SHenri Hennebert 		goto destroy_rtsx_mem_res;
3708926ce35aSJung-uk Kim 	}
3709926ce35aSJung-uk Kim 	pci_enable_busmaster(dev);
3710926ce35aSJung-uk Kim 
3711926ce35aSJung-uk Kim 	if (rtsx_read_cfg(sc, 0, RTSX_SDIOCFG_REG, &sdio_cfg) == 0) {
3712926ce35aSJung-uk Kim 		if ((sdio_cfg & RTSX_SDIOCFG_SDIO_ONLY) ||
3713926ce35aSJung-uk Kim 		    (sdio_cfg & RTSX_SDIOCFG_HAVE_SDIO))
3714926ce35aSJung-uk Kim 			sc->rtsx_flags |= RTSX_F_SDIO_SUPPORT;
3715926ce35aSJung-uk Kim 	}
3716926ce35aSJung-uk Kim 
3717926ce35aSJung-uk Kim #ifdef MMCCAM
3718926ce35aSJung-uk Kim 	sc->rtsx_ccb = NULL;
3719926ce35aSJung-uk Kim 	sc->rtsx_cam_status = 0;
3720926ce35aSJung-uk Kim 
3721926ce35aSJung-uk Kim 	SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "cam_status", CTLFLAG_RD,
3722926ce35aSJung-uk Kim 		      &sc->rtsx_cam_status, 0, "driver cam card present");
37238e9740b6SHenri Hennebert 
37248e9740b6SHenri Hennebert 	if (mmc_cam_sim_alloc(dev, "rtsx_mmc", &sc->rtsx_mmc_sim) != 0) {
3725926ce35aSJung-uk Kim 		device_printf(dev, "Can't allocate CAM SIM\n");
3726926ce35aSJung-uk Kim 		goto destroy_rtsx_irq;
3727926ce35aSJung-uk Kim 	}
3728926ce35aSJung-uk Kim #endif /* MMCCAM */
3729926ce35aSJung-uk Kim 
3730926ce35aSJung-uk Kim 	/* Initialize device. */
37319b261d2eSHenri Hennebert 	error = rtsx_init(sc);
37329b261d2eSHenri Hennebert 	if (error) {
37339b261d2eSHenri Hennebert 		device_printf(dev, "Error %d during rtsx_init()\n", error);
3734926ce35aSJung-uk Kim 		goto destroy_rtsx_irq;
3735926ce35aSJung-uk Kim 	}
3736926ce35aSJung-uk Kim 
3737926ce35aSJung-uk Kim 	/*
3738926ce35aSJung-uk Kim 	 * Schedule a card detection as we won't get an interrupt
37399d3bc163SHenri Hennebert 	 * if the card is inserted when we attach. We wait a quarter
37409d3bc163SHenri Hennebert 	 * of a second to allow for a "spontaneous" interrupt which may
37419d3bc163SHenri Hennebert 	 * change the card presence state. This delay avoid a panic
37429d3bc163SHenri Hennebert 	 * on some configuration (e.g. Lenovo T540p).
3743926ce35aSJung-uk Kim 	 */
37449d3bc163SHenri Hennebert 	DELAY(250000);
3745926ce35aSJung-uk Kim 	if (rtsx_is_card_present(sc))
37469d3bc163SHenri Hennebert 		device_printf(sc->rtsx_dev, "A card is detected\n");
3747926ce35aSJung-uk Kim 	else
37489d3bc163SHenri Hennebert 		device_printf(sc->rtsx_dev, "No card is detected\n");
3749926ce35aSJung-uk Kim 	rtsx_card_task(sc, 0);
3750926ce35aSJung-uk Kim 
3751926ce35aSJung-uk Kim 	if (bootverbose)
3752926ce35aSJung-uk Kim 		device_printf(dev, "Device attached\n");
3753926ce35aSJung-uk Kim 
3754926ce35aSJung-uk Kim 	return (0);
3755926ce35aSJung-uk Kim 
3756926ce35aSJung-uk Kim  destroy_rtsx_irq:
3757926ce35aSJung-uk Kim 	bus_teardown_intr(dev, sc->rtsx_irq_res, sc->rtsx_irq_cookie);
37582e883067SHenri Hennebert  destroy_rtsx_mem_res:
37592e883067SHenri Hennebert 	bus_release_resource(dev, SYS_RES_MEMORY, sc->rtsx_mem_res_id,
37602e883067SHenri Hennebert 			     sc->rtsx_mem_res);
37619d3bc163SHenri Hennebert 	rtsx_dma_free(sc);
3762926ce35aSJung-uk Kim  destroy_rtsx_irq_res:
3763926ce35aSJung-uk Kim 	callout_drain(&sc->rtsx_timeout_callout);
3764926ce35aSJung-uk Kim 	bus_release_resource(dev, SYS_RES_IRQ, sc->rtsx_irq_res_id,
3765926ce35aSJung-uk Kim 			     sc->rtsx_irq_res);
3766926ce35aSJung-uk Kim 	pci_release_msi(dev);
3767926ce35aSJung-uk Kim 	RTSX_LOCK_DESTROY(sc);
3768926ce35aSJung-uk Kim 
3769926ce35aSJung-uk Kim 	return (ENXIO);
3770926ce35aSJung-uk Kim }
3771926ce35aSJung-uk Kim 
3772926ce35aSJung-uk Kim static int
3773926ce35aSJung-uk Kim rtsx_detach(device_t dev)
3774926ce35aSJung-uk Kim {
3775926ce35aSJung-uk Kim 	struct rtsx_softc *sc = device_get_softc(dev);
3776926ce35aSJung-uk Kim 	int	error;
3777926ce35aSJung-uk Kim 
3778926ce35aSJung-uk Kim 	if (bootverbose)
3779926ce35aSJung-uk Kim 		device_printf(dev, "Detach - Vendor ID: 0x%x - Device ID: 0x%x\n",
37802e883067SHenri Hennebert 			      pci_get_vendor(dev), sc->rtsx_device_id);
3781926ce35aSJung-uk Kim 
3782926ce35aSJung-uk Kim 	/* Disable interrupts. */
3783926ce35aSJung-uk Kim 	sc->rtsx_intr_enabled = 0;
3784926ce35aSJung-uk Kim 	WRITE4(sc, RTSX_BIER, sc->rtsx_intr_enabled);
3785926ce35aSJung-uk Kim 
3786926ce35aSJung-uk Kim 	/* Stop device. */
3787*3ddaf820SJohn Baldwin 	error = bus_generic_detach(sc->rtsx_dev);
3788926ce35aSJung-uk Kim 	if (error)
3789926ce35aSJung-uk Kim 		return (error);
3790*3ddaf820SJohn Baldwin 	sc->rtsx_mmc_dev = NULL;
3791926ce35aSJung-uk Kim 
3792926ce35aSJung-uk Kim 	taskqueue_drain_timeout(taskqueue_swi_giant, &sc->rtsx_card_insert_task);
3793926ce35aSJung-uk Kim 	taskqueue_drain(taskqueue_swi_giant, &sc->rtsx_card_remove_task);
3794926ce35aSJung-uk Kim 
3795926ce35aSJung-uk Kim 	/* Teardown the state in our softc created in our attach routine. */
3796926ce35aSJung-uk Kim 	rtsx_dma_free(sc);
37972e883067SHenri Hennebert 	if (sc->rtsx_mem_res != NULL)
37982e883067SHenri Hennebert 		bus_release_resource(dev, SYS_RES_MEMORY, sc->rtsx_mem_res_id,
37992e883067SHenri Hennebert 				     sc->rtsx_mem_res);
3800926ce35aSJung-uk Kim 	if (sc->rtsx_irq_cookie != NULL)
3801926ce35aSJung-uk Kim 		bus_teardown_intr(dev, sc->rtsx_irq_res, sc->rtsx_irq_cookie);
3802926ce35aSJung-uk Kim 	if (sc->rtsx_irq_res != NULL) {
3803926ce35aSJung-uk Kim 		callout_drain(&sc->rtsx_timeout_callout);
3804926ce35aSJung-uk Kim 		bus_release_resource(dev, SYS_RES_IRQ, sc->rtsx_irq_res_id,
3805926ce35aSJung-uk Kim 				     sc->rtsx_irq_res);
3806926ce35aSJung-uk Kim 		pci_release_msi(dev);
3807926ce35aSJung-uk Kim 	}
3808926ce35aSJung-uk Kim 	RTSX_LOCK_DESTROY(sc);
3809926ce35aSJung-uk Kim #ifdef MMCCAM
38108e9740b6SHenri Hennebert 	mmc_cam_sim_free(&sc->rtsx_mmc_sim);
3811926ce35aSJung-uk Kim #endif /* MMCCAM */
3812926ce35aSJung-uk Kim 
3813926ce35aSJung-uk Kim 	return (0);
3814926ce35aSJung-uk Kim }
3815926ce35aSJung-uk Kim 
3816926ce35aSJung-uk Kim static int
3817926ce35aSJung-uk Kim rtsx_shutdown(device_t dev)
3818926ce35aSJung-uk Kim {
3819926ce35aSJung-uk Kim 	if (bootverbose)
3820926ce35aSJung-uk Kim 		device_printf(dev, "Shutdown\n");
3821926ce35aSJung-uk Kim 
3822926ce35aSJung-uk Kim 	return (0);
3823926ce35aSJung-uk Kim }
3824926ce35aSJung-uk Kim 
3825926ce35aSJung-uk Kim /*
3826926ce35aSJung-uk Kim  * Device suspend routine.
3827926ce35aSJung-uk Kim  */
3828926ce35aSJung-uk Kim static int
3829926ce35aSJung-uk Kim rtsx_suspend(device_t dev)
3830926ce35aSJung-uk Kim {
3831926ce35aSJung-uk Kim 	struct rtsx_softc *sc = device_get_softc(dev);
3832926ce35aSJung-uk Kim 
3833926ce35aSJung-uk Kim 	device_printf(dev, "Suspend\n");
3834926ce35aSJung-uk Kim 
3835926ce35aSJung-uk Kim #ifdef MMCCAM
3836926ce35aSJung-uk Kim 	if (sc->rtsx_ccb != NULL) {
3837926ce35aSJung-uk Kim 		device_printf(dev, "Request in progress: CMD%u, rtsr_intr_status: 0x%08x\n",
3838926ce35aSJung-uk Kim 			      sc->rtsx_ccb->mmcio.cmd.opcode, sc->rtsx_intr_status);
3839926ce35aSJung-uk Kim 	}
38409d3bc163SHenri Hennebert #else  /* !MMCCAM */
3841926ce35aSJung-uk Kim 	if (sc->rtsx_req != NULL) {
3842926ce35aSJung-uk Kim 		device_printf(dev, "Request in progress: CMD%u, rtsr_intr_status: 0x%08x\n",
3843926ce35aSJung-uk Kim 			      sc->rtsx_req->cmd->opcode, sc->rtsx_intr_status);
3844926ce35aSJung-uk Kim 	}
3845926ce35aSJung-uk Kim #endif /* MMCCAM */
3846926ce35aSJung-uk Kim 
3847926ce35aSJung-uk Kim 	bus_generic_suspend(dev);
3848926ce35aSJung-uk Kim 
3849926ce35aSJung-uk Kim 	return (0);
3850926ce35aSJung-uk Kim }
3851926ce35aSJung-uk Kim 
3852926ce35aSJung-uk Kim /*
3853926ce35aSJung-uk Kim  * Device resume routine.
3854926ce35aSJung-uk Kim  */
3855926ce35aSJung-uk Kim static int
3856926ce35aSJung-uk Kim rtsx_resume(device_t dev)
3857926ce35aSJung-uk Kim {
3858926ce35aSJung-uk Kim 	device_printf(dev, "Resume\n");
3859926ce35aSJung-uk Kim 
38601b1bab00Shlh-restart 	rtsx_init(device_get_softc(dev));
38611b1bab00Shlh-restart 
3862926ce35aSJung-uk Kim 	bus_generic_resume(dev);
3863926ce35aSJung-uk Kim 
3864926ce35aSJung-uk Kim 	return (0);
3865926ce35aSJung-uk Kim }
3866926ce35aSJung-uk Kim 
3867926ce35aSJung-uk Kim static device_method_t rtsx_methods[] = {
3868926ce35aSJung-uk Kim 	/* Device interface */
3869926ce35aSJung-uk Kim 	DEVMETHOD(device_probe,		rtsx_probe),
3870926ce35aSJung-uk Kim 	DEVMETHOD(device_attach,	rtsx_attach),
3871926ce35aSJung-uk Kim 	DEVMETHOD(device_detach,	rtsx_detach),
3872926ce35aSJung-uk Kim 	DEVMETHOD(device_shutdown,	rtsx_shutdown),
3873926ce35aSJung-uk Kim 	DEVMETHOD(device_suspend,	rtsx_suspend),
3874926ce35aSJung-uk Kim 	DEVMETHOD(device_resume,	rtsx_resume),
3875926ce35aSJung-uk Kim 
3876926ce35aSJung-uk Kim 	/* Bus interface */
3877926ce35aSJung-uk Kim 	DEVMETHOD(bus_read_ivar,	rtsx_read_ivar),
3878926ce35aSJung-uk Kim 	DEVMETHOD(bus_write_ivar,	rtsx_write_ivar),
3879926ce35aSJung-uk Kim 
38808e9740b6SHenri Hennebert #ifndef MMCCAM
3881926ce35aSJung-uk Kim 	/* MMC bridge interface */
3882926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_update_ios,	rtsx_mmcbr_update_ios),
3883926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_switch_vccq,	rtsx_mmcbr_switch_vccq),
3884926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_tune,		rtsx_mmcbr_tune),
3885926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_retune,		rtsx_mmcbr_retune),
3886926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_request,	rtsx_mmcbr_request),
3887926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_get_ro,		rtsx_mmcbr_get_ro),
3888926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_acquire_host,	rtsx_mmcbr_acquire_host),
3889926ce35aSJung-uk Kim 	DEVMETHOD(mmcbr_release_host,	rtsx_mmcbr_release_host),
38908e9740b6SHenri Hennebert #endif /* !MMCCAM */
38918e9740b6SHenri Hennebert 
38928e9740b6SHenri Hennebert #ifdef MMCCAM
38938e9740b6SHenri Hennebert 	/* MMCCAM interface */
38948e9740b6SHenri Hennebert 	DEVMETHOD(mmc_sim_get_tran_settings,	rtsx_get_tran_settings),
38958e9740b6SHenri Hennebert 	DEVMETHOD(mmc_sim_set_tran_settings,	rtsx_set_tran_settings),
38968e9740b6SHenri Hennebert 	DEVMETHOD(mmc_sim_cam_request,		rtsx_cam_request),
38978e9740b6SHenri Hennebert #endif /* MMCCAM */
3898926ce35aSJung-uk Kim 
3899926ce35aSJung-uk Kim 	DEVMETHOD_END
3900926ce35aSJung-uk Kim };
3901926ce35aSJung-uk Kim 
3902926ce35aSJung-uk Kim DEFINE_CLASS_0(rtsx, rtsx_driver, rtsx_methods, sizeof(struct rtsx_softc));
390303cfce6fSJohn Baldwin DRIVER_MODULE(rtsx, pci, rtsx_driver, NULL, NULL);
390471883128SHenri Hennebert 
390571883128SHenri Hennebert /* For Plug and Play */
390671883128SHenri Hennebert MODULE_PNP_INFO("U16:device;D:#;T:vendor=0x10ec", pci, rtsx,
390771883128SHenri Hennebert 		rtsx_ids, nitems(rtsx_ids));
390871883128SHenri Hennebert 
3909926ce35aSJung-uk Kim #ifndef MMCCAM
3910926ce35aSJung-uk Kim MMC_DECLARE_BRIDGE(rtsx);
39118e9740b6SHenri Hennebert #endif /* !MMCCAM */
3912