Index: share/man/man4/Makefile =================================================================== --- share/man/man4/Makefile +++ share/man/man4/Makefile @@ -443,6 +443,7 @@ rl.4 \ rndtest.4 \ route.4 \ + rtsx.4 \ rtwn.4 \ rtwnfw.4 \ rtwn_pci.4 \ Index: share/man/man4/rtsx.4 =================================================================== --- /dev/null +++ share/man/man4/rtsx.4 @@ -0,0 +1,120 @@ +.\" +.\" Copyright (c) 2020 Henri Hennebert +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd May 27, 2020 +.Dt RTSX 4 +.Os +.Sh NAME +.Nm rtsx +.Nd Realtek SD card reader +.Sh SYNOPSIS +To compile this driver into the kernel, place the following +lines in your kernel configuration file: +.Bd -ragged -offset indent +.Cd "device mmc" +.Cd "device mmcsd" +.Cd "device rtsx" +.Ed +.Pp +Alternatively, to load the driver as a module at boot time, +place the following lines in +.Xr loader.conf 5 : +.Bd -literal -offset indent +mmc_load="YES" +mmcsd_load="YES" +rtsx_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for Realtek SD card reader. Driver attaches mmc +bus on card insertion and detaches it on card removing. +.Sh HARDWARE +The +.Nm +driver supports different specification compatible chips. +The following chips have been verified to work: +.Pp +.Bl -bullet -compact +.It +RTS5209 +.It +RTS5227 +.It +RTS5229 +.It +RTS522A +.It +RTS525A +.It +RTL8411B +.El +.Pp +It should also work for: +.Pp +.Bl -bullet -compact +.It +RTS5249 +.It +RTL8402 +.It +RTL8411 +.El +.Sh HISTORY +The +.Nm +driver was ported from OpenBSD with modifications found in Linux and OpenBSD. +.Sh SEE ALSO +.Xr mmc 4 , +.Xr mmcsd 4 +.Rs +.%T "SD Specifications, Part 2, SD Host Controller, Simplified Specification" +.%T "SanDisk Secure Digital Card" +.Re +.Sh AUTHORS +.An Henri Hennebert Aq Mt hlh@restart.be +.An Gary Jennejohn Aq Mt gj@freebsd.org +.An Jesper Schmitz Mouridsen Aq Mt jsm@FreeBSD.org +.Sh CONTRIBUTORS +.An Lutz Bichler Aq Mt Lutz.Bichler@gmail.com +.Sh BUGS +.Bl -bullet +.It +The timeouts experienced during card insert and during I/O are solved in version 1.0g. +.It +RTS522A on Lenovo P50s and Lenovo T470p, card detection and read-only switch are reversed. +This is sovled with: +.Bd -ragged +.Cd options RTSX_INVERSION +.Ed +.Pp +Or with: +.Bd -ragged +.Cd sysctl dev.rtsx.0.inversion=1 +.Ed +.It +Mounting a filesystem with write access on a card write protected may involve a kernel crash. +.El Index: sys/amd64/conf/GENERIC =================================================================== --- sys/amd64/conf/GENERIC +++ sys/amd64/conf/GENERIC @@ -353,6 +353,9 @@ device mmc # MMC/SD bus device mmcsd # MMC/SD memory card device sdhci # Generic PCI SD Host Controller +device rtsx # Realtek SD card reader +# options RTSX_INVERSION # Reverse card detection and read-only switch + # VirtIO support device virtio # Generic VirtIO bus (required) Index: sys/conf/NOTES =================================================================== --- sys/conf/NOTES +++ sys/conf/NOTES @@ -2212,10 +2212,12 @@ # mmc MMC/SD bus # mmcsd MMC/SD memory card # sdhci Generic PCI SD Host Controller -# +# rtsx Realtek SD card reader (RTS5209, RTS5227, ...) device mmc device mmcsd device sdhci +device rtsx +options RTSX_INVERSION # Reverse card detection and read-only switch # # SMB bus Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -2824,6 +2824,8 @@ dev/rl/if_rl.c optional rl pci dev/rndtest/rndtest.c optional rndtest # +dev/rtsx/rtsx.c optional rtsx pci +# dev/rtwn/if_rtwn.c optional rtwn dev/rtwn/if_rtwn_beacon.c optional rtwn dev/rtwn/if_rtwn_calib.c optional rtwn Index: sys/conf/options =================================================================== --- sys/conf/options +++ sys/conf/options @@ -1009,3 +1009,6 @@ # gcov support GCOV opt_global.h LINDEBUGFS + +# rtsx(4) driver +RTSX_INVERSION Index: sys/dev/rtsx/rtsx.c =================================================================== --- /dev/null +++ sys/dev/rtsx/rtsx.c @@ -0,0 +1,3867 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2012 Stefan Sperling + * Copyright (c) 2020 Henri Hennebert + * Copyright (c) 2020 Gary Jennejohn + * Copyright (c) 2020 Jesper Schmitz Mouridsen + * All rights reserved. + * + * Patch from: + * - Lutz Bichler + * + * Base on OpenBSD /sys/dev/pci/rtsx_pci.c & /dev/ic/rtsx.c + * on Linux /drivers/mmc/host/rtsx_pci_sdmmc.c, + * /include/linux/rtsx_pci.h & + * /drivers/misc/cardreader/rtsx_pcr.c + * on NetBSD /sys/dev/ic/rtsx.c + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include /* For FreeBSD 11 */ +#include /* For FreeBSD 11 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MMCCAM +#include +#include +#include +#include +#include +#endif /* MMCCAM */ + +#include "rtsxreg.h" + +/* The softc holds our per-instance data. */ +struct rtsx_softc { + struct mtx rtsx_mtx; /* device mutex */ + device_t rtsx_dev; /* device */ + uint16_t rtsx_flags; /* device flags */ + uint16_t rtsx_device_id; /* device ID */ + device_t rtsx_mmc_dev; /* device of mmc bus */ + uint32_t rtsx_intr_enabled; /* enabled interrupts */ + uint32_t rtsx_intr_status; /* soft interrupt status */ + int rtsx_irq_res_id; /* bus IRQ resource id */ + struct resource *rtsx_irq_res; /* bus IRQ resource */ + void *rtsx_irq_cookie; /* bus IRQ resource cookie */ + struct callout rtsx_timeout_callout; /* callout for timeout */ + int rtsx_timeout; /* interrupt timeout value */ + void (*rtsx_intr_trans_ok)(struct rtsx_softc *sc); + /* function to call if transfer succeed */ + void (*rtsx_intr_trans_ko)(struct rtsx_softc *sc); + /* function to call if transfer fail */ + struct timeout_task + rtsx_card_insert_task; /* card insert delayed task */ + struct task rtsx_card_remove_task; /* card remove task */ + + int rtsx_res_id; /* bus memory resource id */ + struct resource *rtsx_res; /* bus memory resource */ + int rtsx_res_type; /* bus memory resource type */ + bus_space_tag_t rtsx_btag; /* host register set tag */ + bus_space_handle_t rtsx_bhandle; /* host register set handle */ + + bus_dma_tag_t rtsx_cmd_dma_tag; /* DMA tag for command transfer */ + bus_dmamap_t rtsx_cmd_dmamap; /* DMA map for command transfer */ + void *rtsx_cmd_dmamem; /* DMA mem for command transfer */ + bus_addr_t rtsx_cmd_buffer; /* device visible address of the DMA segment */ + int rtsx_cmd_index; /* index in rtsx_cmd_buffer */ + + bus_dma_tag_t rtsx_data_dma_tag; /* DMA tag for data transfer */ + bus_dmamap_t rtsx_data_dmamap; /* DMA map for data transfer */ + void *rtsx_data_dmamem; /* DMA mem for data transfer */ + bus_addr_t rtsx_data_buffer; /* device visible address of the DMA segment */ + +#ifdef MMCCAM + struct cam_devq *rtsx_devq; /* CAM queue of requests */ + struct cam_sim *rtsx_sim; /* descriptor of our SCSI Interface Modules (SIM) */ + struct mtx rtsx_sim_mtx; /* SIM mutex */ + union ccb *rtsx_ccb; /* CAM control block */ + struct mmc_request rtsx_cam_req; /* CAM MMC request */ +#endif /* MMCCAM */ + + struct mmc_request *rtsx_req; /* MMC request */ + struct mmc_host rtsx_host; /* host parameters */ + int rtsx_pcie_cap; /* PCIe capability offset */ + int8_t rtsx_bus_busy; /* bus busy status */ + int8_t rtsx_ios_bus_width; /* current host.ios.bus_width */ + int32_t rtsx_ios_clock; /* current host.ios.clock */ + int8_t rtsx_ios_power_mode; /* current host.ios.power mode */ + int8_t rtsx_ios_timing; /* current host.ios.timing */ + uint8_t rtsx_read_only; /* card read only status */ + uint8_t rtsx_inversion; /* inversion of card detection and read only status */ + uint8_t rtsx_force_timing; /* force bus_timing_uhs_sdr50 */ + uint8_t rtsx_debug; /* print debugging */ +#ifdef MMCCAM + uint8_t rtsx_cam_status; /* CAM status - 1 if card in use */ +#endif /* MMCCAM */ + uint64_t rtsx_read_count; /* count of read operations */ + uint64_t rtsx_write_count; /* count of write operations */ + bool rtsx_discovery_mode; /* are we in discovery mode? */ + bool rtsx_tuning_mode; /* are we tuning */ + bool rtsx_double_clk; /* double clock freqency */ + bool rtsx_vpclk; /* voltage at Pulse-width Modulation(PWM) clock? */ + uint8_t rtsx_ssc_depth; /* Spread spectrum clocking depth */ + uint8_t rtsx_card_drive_sel; /* value for RTSX_CARD_DRIVE_SEL */ + uint8_t rtsx_sd30_drive_sel_3v3;/* value for RTSX_SD30_DRIVE_SEL */ +}; + +/* rtsx_flags values */ +#define RTSX_F_DEFAULT 0x0000 +#define RTSX_F_CARD_PRESENT 0x0001 +#define RTSX_F_SDIO_SUPPORT 0x0002 +#define RTSX_F_VERSION_A 0x0004 +#define RTSX_F_VERSION_B 0x0008 +#define RTSX_F_VERSION_C 0x0010 +#define RTSX_F_VERSION_D 0x0020 +#define RTSX_F_8411B_QFN48 0x0040 +#define RTSX_F_REVERSE_SOCKET 0x0080 + +#define RTSX_REALTEK 0x10ec +#define RTSX_RTS5209 0x5209 +#define RTSX_RTS5227 0x5227 +#define RTSX_RTS5229 0x5229 +#define RTSX_RTS522A 0x522a +#define RTSX_RTS525A 0x525a +#define RTSX_RTS5249 0x5249 +#define RTSX_RTL8402 0x5286 +#define RTSX_RTL8411 0x5289 +#define RTSX_RTL8411B 0x5287 + +#define RTSX_VERSION "2.0a" + +static const struct rtsx_device { + uint16_t vendor_id; + uint16_t device_id; + const char *desc; +} rtsx_devices[] = { + { RTSX_REALTEK, RTSX_RTS5209, RTSX_VERSION " Realtek RTS5209 PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTS5227, RTSX_VERSION " Realtek RTS5227 PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTS5229, RTSX_VERSION " Realtek RTS5229 PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTS522A, RTSX_VERSION " Realtek RTS522A PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTS525A, RTSX_VERSION " Realtek RTS525A PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTS5249, RTSX_VERSION " Realtek RTS5249 PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTL8402, RTSX_VERSION " Realtek RTL8402 PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTL8411, RTSX_VERSION " Realtek RTL8411 PCI MMC/SD Card Reader"}, + { RTSX_REALTEK, RTSX_RTL8411B, RTSX_VERSION " Realtek RTL8411B PCI MMC/SD Card Reader"}, + { 0, 0, NULL} +}; + +static int rtsx_dma_alloc(struct rtsx_softc *sc); +static void rtsx_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error); +static void rtsx_dma_free(struct rtsx_softc *sc); +static void rtsx_intr(void *arg); +static void rtsx_handle_card_present(struct rtsx_softc *sc); +static void rtsx_card_task(void *arg, int pending __unused); +static bool rtsx_is_card_present(struct rtsx_softc *sc); +static int rtsx_init(struct rtsx_softc *sc); +static int rtsx_map_sd_drive(int index); +static int rtsx_rts5227_fill_driving(struct rtsx_softc *sc); +static int rtsx_rts5249_fill_driving(struct rtsx_softc *sc); +static int rtsx_read(struct rtsx_softc *, uint16_t, uint8_t *); +static int rtsx_read_cfg(struct rtsx_softc *sc, uint8_t func, uint16_t addr, uint32_t *val); +static int rtsx_write(struct rtsx_softc *sc, uint16_t addr, uint8_t mask, uint8_t val); +static int rtsx_read_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t *val); +static int rtsx_write_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t val); +static int rtsx_bus_power_off(struct rtsx_softc *sc); +static int rtsx_bus_power_on(struct rtsx_softc *sc); +static int rtsx_set_bus_width(struct rtsx_softc *sc, enum mmc_bus_width width); +static int rtsx_set_sd_timing(struct rtsx_softc *sc, enum mmc_bus_timing timing); +static int rtsx_set_sd_clock(struct rtsx_softc *sc, uint32_t freq); +static int rtsx_stop_sd_clock(struct rtsx_softc *sc); +static int rtsx_switch_sd_clock(struct rtsx_softc *sc, uint8_t clk, uint8_t n, uint8_t div, uint8_t mcu); +static void rtsx_sd_change_tx_phase(struct rtsx_softc *sc, uint8_t sample_point); +static void rtsx_sd_change_rx_phase(struct rtsx_softc *sc, uint8_t sample_point); +static void rtsx_sd_tuning_rx_phase(struct rtsx_softc *sc, uint32_t *phase_map); +static int rtsx_sd_tuning_rx_cmd(struct rtsx_softc *sc, uint8_t sample_point); +static int rtsx_sd_tuning_rx_cmd_wait(struct rtsx_softc *sc, struct mmc_command *cmd); +static void rtsx_sd_tuning_rx_cmd_wakeup(struct rtsx_softc *sc); +static void rtsx_sd_wait_data_idle(struct rtsx_softc *sc); +static uint8_t rtsx_sd_search_final_rx_phase(struct rtsx_softc *sc, uint32_t phase_map); +static int rtsx_sd_get_rx_phase_len(uint32_t phase_map, int start_bit); +#if 0 /* For led */ +static int rtsx_led_enable(struct rtsx_softc *sc); +static int rtsx_led_disable(struct rtsx_softc *sc); +#endif /* For led */ +static uint8_t rtsx_response_type(uint16_t mmc_rsp); +static void rtsx_init_cmd(struct rtsx_softc *sc, struct mmc_command *cmd); +static void rtsx_push_cmd(struct rtsx_softc *sc, uint8_t cmd, uint16_t reg, + uint8_t mask, uint8_t data); +static void rtsx_set_cmd_data_len(struct rtsx_softc *sc, uint16_t block_cnt, uint16_t byte_cnt); +static void rtsx_send_cmd(struct rtsx_softc *sc); +static void rtsx_ret_resp(struct rtsx_softc *sc); +static void rtsx_set_resp(struct rtsx_softc *sc, struct mmc_command *cmd); +static void rtsx_stop_cmd(struct rtsx_softc *sc); +static void rtsx_clear_error(struct rtsx_softc *sc); +static void rtsx_req_done(struct rtsx_softc *sc); +static int rtsx_send_req(struct rtsx_softc *sc, struct mmc_command *cmd); +static int rtsx_xfer_short(struct rtsx_softc *sc, struct mmc_command *cmd); +static void rtsx_ask_ppbuf_part1(struct rtsx_softc *sc); +static void rtsx_get_ppbuf_part1(struct rtsx_softc *sc); +static void rtsx_get_ppbuf_part2(struct rtsx_softc *sc); +static void rtsx_put_ppbuf_part1(struct rtsx_softc *sc); +static void rtsx_put_ppbuf_part2(struct rtsx_softc *sc); +static void rtsx_write_ppbuf(struct rtsx_softc *sc); +static int rtsx_xfer(struct rtsx_softc *sc, struct mmc_command *cmd); +static void rtsx_xfer_begin(struct rtsx_softc *sc); +static void rtsx_xfer_start(struct rtsx_softc *sc); +static void rtsx_xfer_finish(struct rtsx_softc *sc); +static void rtsx_timeout(void *arg); + +#ifdef MMCCAM +static void rtsx_cam_action(struct cam_sim *sim, union ccb *ccb); +static void rtsx_cam_poll(struct cam_sim *sim); +static int rtsx_cam_set_tran_settings(struct rtsx_softc *sc, union ccb *ccb); +static int rtsx_cam_request(struct rtsx_softc *sc, union ccb *ccb); +#endif /* MMCCAM */ + +static int rtsx_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); +static int rtsx_write_ivar(device_t bus, device_t child, int which, uintptr_t value); + +static int rtsx_mmcbr_update_ios(device_t bus, device_t child __unused); +static int rtsx_mmcbr_switch_vccq(device_t bus, device_t child __unused); +static int rtsx_mmcbr_tune(device_t bus, device_t child __unused, bool hs400 __unused); +static int rtsx_mmcbr_retune(device_t bus, device_t child __unused, bool reset __unused); +static int rtsx_mmcbr_request(device_t bus, device_t child __unused, struct mmc_request *req); +static int rtsx_mmcbr_get_ro(device_t bus, device_t child __unused); +static int rtsx_mmcbr_acquire_host(device_t bus, device_t child __unused); +static int rtsx_mmcbr_release_host(device_t bus, device_t child __unused); + +static int rtsx_probe(device_t dev); +static int rtsx_attach(device_t dev); +static int rtsx_detach(device_t dev); +static int rtsx_shutdown(device_t dev); +static int rtsx_suspend(device_t dev); +static int rtsx_resume(device_t dev); + +#define RTSX_LOCK_INIT(_sc) mtx_init(&(_sc)->rtsx_mtx, \ + device_get_nameunit(sc->rtsx_dev), "rtsx", MTX_DEF) +#define RTSX_LOCK(_sc) mtx_lock(&(_sc)->rtsx_mtx) +#define RTSX_UNLOCK(_sc) mtx_unlock(&(_sc)->rtsx_mtx) +#define RTSX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rtsx_mtx) + +#define RTSX_SDCLK_OFF 0 +#define RTSX_SDCLK_250KHZ 250000 +#define RTSX_SDCLK_400KHZ 400000 +#define RTSX_SDCLK_25MHZ 25000000 +#define RTSX_SDCLK_50MHZ 50000000 +#define RTSX_SDCLK_100MHZ 100000000 +#define RTSX_SDCLK_208MHZ 208000000 + +#define RTSX_MIN_DIV_N 80 +#define RTSX_MAX_DIV_N 208 + +#define RTSX_MAX_DATA_BLKLEN 512 + +#define RTSX_DMA_ALIGN 4 +#define RTSX_HOSTCMD_MAX 256 +#define RTSX_DMA_CMD_BIFSIZE (sizeof(uint32_t) * RTSX_HOSTCMD_MAX) +#define RTSX_DMA_DATA_BUFSIZE MAXPHYS + +#define ISSET(t, f) ((t) & (f)) + +#define READ4(sc, reg) \ + (bus_space_read_4((sc)->rtsx_btag, (sc)->rtsx_bhandle, (reg))) +#define WRITE4(sc, reg, val) \ + (bus_space_write_4((sc)->rtsx_btag, (sc)->rtsx_bhandle, (reg), (val))) + +#define RTSX_READ(sc, reg, val) \ + do { \ + int err = rtsx_read((sc), (reg), (val)); \ + if (err) \ + return (err); \ + } while (0) + +#define RTSX_WRITE(sc, reg, val) \ + do { \ + int err = rtsx_write((sc), (reg), 0xff, (val)); \ + if (err) \ + return (err); \ + } while (0) +#define RTSX_CLR(sc, reg, bits) \ + do { \ + int err = rtsx_write((sc), (reg), (bits), 0); \ + if (err) \ + return (err); \ + } while (0) + +#define RTSX_SET(sc, reg, bits) \ + do { \ + int err = rtsx_write((sc), (reg), (bits), 0xff);\ + if (err) \ + return (err); \ + } while (0) + +#define RTSX_BITOP(sc, reg, mask, bits) \ + do { \ + int err = rtsx_write((sc), (reg), (mask), (bits)); \ + if (err) \ + return (err); \ + } while (0) + +/* + * We use two DMA buffers: a command buffer and a data buffer. + * + * The command buffer contains a command queue for the host controller, + * which describes SD/MMC commands to run, and other parameters. The chip + * runs the command queue when a special bit in the RTSX_HCBAR register is + * set and signals completion with the RTSX_TRANS_OK_INT interrupt. + * Each command is encoded as a 4 byte sequence containing command number + * (read, write, or check a host controller register), a register address, + * and a data bit-mask and value. + * SD/MMC commands which do not transfer any data from/to the card only use + * the command buffer. + * + * The data buffer is used for transfer longer than 512. Data transfer is + * controlled via the RTSX_HDBAR register and completion is signalled by + * the RTSX_TRANS_OK_INT interrupt. + * + * The chip is unable to perform DMA above 4GB. + */ + +/* + * Main commands in the usual seqence used: + * + * CMD0 Go idle state + * CMD8 Send interface condition + * CMD55 Application Command for next ACMD + * ACMD41 Send Operation Conditions Register (OCR: voltage profile of the card) + * CMD2 Send Card Identification (CID) Register + * CMD3 Send relative address + * CMD9 Send Card Specific Data (CSD) + * CMD13 Send status (32 bits - bit 25: card password protected) + * CMD7 Select card (before Get card SCR) + * ACMD51 Send SCR (SD CARD Configuration Register - [51:48]: Bus widths supported) + * CMD6 SD switch function + * ACMD13 Send SD status (512 bits) + * ACMD42 Set/Clear card detect + * ACMD6 Set bus width + * CMD19 Send tuning block + * CMD12 Stop transmission + * + * CMD17 Read single block (<=512) + * CMD18 Read multiple blocks (>512) + * CMD24 Write single block (<=512) + * CMD25 Write multiple blocks (>512) + * + * CMD52 IO R/W direct + * CMD5 Send Operation Conditions + */ +static int +rtsx_dma_alloc(struct rtsx_softc *sc) { + int error = 0; + + error = bus_dma_tag_create(bus_get_dma_tag(sc->rtsx_dev), /* inherit from parent */ + RTSX_DMA_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + RTSX_DMA_CMD_BIFSIZE, 1, /* maxsize, nsegments */ + RTSX_DMA_CMD_BIFSIZE, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->rtsx_cmd_dma_tag); + if (error) { + device_printf(sc->rtsx_dev, + "Can't create cmd parent DMA tag\n"); + return (error); + } + error = bus_dmamem_alloc(sc->rtsx_cmd_dma_tag, /* DMA tag */ + &sc->rtsx_cmd_dmamem, /* will hold the KVA pointer */ + BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, /* flags */ + &sc->rtsx_cmd_dmamap); /* DMA map */ + if (error) { + device_printf(sc->rtsx_dev, + "Can't create DMA map for command transfer\n"); + goto destroy_cmd_dma_tag; + + } + error = bus_dmamap_load(sc->rtsx_cmd_dma_tag, /* DMA tag */ + sc->rtsx_cmd_dmamap, /* DMA map */ + sc->rtsx_cmd_dmamem, /* KVA pointer to be mapped */ + RTSX_DMA_CMD_BIFSIZE, /* size of buffer */ + rtsx_dmamap_cb, /* callback */ + &sc->rtsx_cmd_buffer, /* first arg of callback */ + 0); /* flags */ + if (error || sc->rtsx_cmd_buffer == 0) { + device_printf(sc->rtsx_dev, + "Can't load DMA memory for command transfer\n"); + error = (error) ? error : EFAULT; + goto destroy_cmd_dmamem_alloc; + } + + error = bus_dma_tag_create(bus_get_dma_tag(sc->rtsx_dev), /* inherit from parent */ + RTSX_DMA_DATA_BUFSIZE, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + RTSX_DMA_DATA_BUFSIZE, 1, /* maxsize, nsegments */ + RTSX_DMA_DATA_BUFSIZE, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->rtsx_data_dma_tag); + if (error) { + device_printf(sc->rtsx_dev, + "Can't create data parent DMA tag\n"); + goto destroy_cmd_dmamap_load; + } + error = bus_dmamem_alloc(sc->rtsx_data_dma_tag, /* DMA tag */ + &sc->rtsx_data_dmamem, /* will hold the KVA pointer */ + BUS_DMA_WAITOK | BUS_DMA_ZERO, /* flags */ + &sc->rtsx_data_dmamap); /* DMA map */ + if (error) { + device_printf(sc->rtsx_dev, + "Can't create DMA map for data transfer\n"); + goto destroy_data_dma_tag; + } + error = bus_dmamap_load(sc->rtsx_data_dma_tag, /* DMA tag */ + sc->rtsx_data_dmamap, /* DMA map */ + sc->rtsx_data_dmamem, /* KVA pointer to be mapped */ + RTSX_DMA_DATA_BUFSIZE, /* size of buffer */ + rtsx_dmamap_cb, /* callback */ + &sc->rtsx_data_buffer, /* first arg of callback */ + 0); /* flags */ + if (error || sc->rtsx_data_buffer == 0) { + device_printf(sc->rtsx_dev, + "Can't load DMA memory for data transfer\n"); + error = (error) ? error : EFAULT; + goto destroy_data_dmamem_alloc; + } + return (error); + + destroy_data_dmamem_alloc: + bus_dmamem_free(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamem, sc->rtsx_data_dmamap); + destroy_data_dma_tag: + bus_dma_tag_destroy(sc->rtsx_data_dma_tag); + destroy_cmd_dmamap_load: + bus_dmamap_unload(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap); + destroy_cmd_dmamem_alloc: + bus_dmamem_free(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamem, sc->rtsx_cmd_dmamap); + destroy_cmd_dma_tag: + bus_dma_tag_destroy(sc->rtsx_cmd_dma_tag); + + return (error); +} + +static void +rtsx_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + if (error) { + printf("rtsx_dmamap_cb: error %d\n", error); + return; + } + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +static void +rtsx_dma_free(struct rtsx_softc *sc) { + + if (sc->rtsx_cmd_dma_tag != NULL) { + if (sc->rtsx_cmd_dmamap != NULL) + bus_dmamap_unload(sc->rtsx_cmd_dma_tag, + sc->rtsx_cmd_dmamap); + if (sc->rtsx_cmd_dmamem != NULL) + bus_dmamem_free(sc->rtsx_cmd_dma_tag, + sc->rtsx_cmd_dmamem, + sc->rtsx_cmd_dmamap); + sc->rtsx_cmd_dmamap = NULL; + sc->rtsx_cmd_dmamem = NULL; + sc->rtsx_cmd_buffer = 0; + bus_dma_tag_destroy(sc->rtsx_cmd_dma_tag); + sc->rtsx_cmd_dma_tag = NULL; + } + if (sc->rtsx_data_dma_tag != NULL) { + if (sc->rtsx_data_dmamap != NULL) + bus_dmamap_unload(sc->rtsx_data_dma_tag, + sc->rtsx_data_dmamap); + if (sc->rtsx_data_dmamem != NULL) + bus_dmamem_free(sc->rtsx_data_dma_tag, + sc->rtsx_data_dmamem, + sc->rtsx_data_dmamap); + sc->rtsx_data_dmamap = NULL; + sc->rtsx_data_dmamem = NULL; + sc->rtsx_data_buffer = 0; + bus_dma_tag_destroy(sc->rtsx_data_dma_tag); + sc->rtsx_data_dma_tag = NULL; + } +} + +static void +rtsx_intr(void *arg) +{ + struct rtsx_softc *sc = arg; + uint32_t enabled; + uint32_t status; + + RTSX_LOCK(sc); + + enabled = sc->rtsx_intr_enabled; + status = READ4(sc, RTSX_BIPR); /* read Bus Interrupt Pending Register */ + sc->rtsx_intr_status = status; + + if (bootverbose) + device_printf(sc->rtsx_dev, "Interrupt handler - enabled: 0x%08x, status: 0x%08x\n", enabled, status); + + /* Ack interrupts. */ + WRITE4(sc, RTSX_BIPR, status); + + if (((enabled & status) == 0) || status == 0xffffffff) { + device_printf(sc->rtsx_dev, "Spurious interrupt - enabled: 0x%08x, status: 0x%08x\n", enabled, status); + RTSX_UNLOCK(sc); + return; + } + + /* Detect write protect. */ + if (status & RTSX_SD_WRITE_PROTECT) + sc->rtsx_read_only = 1; + else + sc->rtsx_read_only = 0; + + /* Start task to handle SD card status change (from dwmmc.c). */ + if (status & RTSX_SD_INT) { + device_printf(sc->rtsx_dev, "Interrupt card inserted/removed\n"); + rtsx_handle_card_present(sc); + } + + if (sc->rtsx_req == NULL) { + RTSX_UNLOCK(sc); + return; + } + + if (status & RTSX_TRANS_OK_INT) { + sc->rtsx_req->cmd->error = MMC_ERR_NONE; + if (sc->rtsx_intr_trans_ok != NULL) + sc->rtsx_intr_trans_ok(sc); + } else if (status & RTSX_TRANS_FAIL_INT) { + uint8_t stat1; + sc->rtsx_req->cmd->error = MMC_ERR_FAILED; + if (rtsx_read(sc, RTSX_SD_STAT1, &stat1) == 0 && + (stat1 & RTSX_SD_CRC_ERR)) { + device_printf(sc->rtsx_dev, "CRC error\n"); + sc->rtsx_req->cmd->error = MMC_ERR_BADCRC; + } + if (!sc->rtsx_tuning_mode) + device_printf(sc->rtsx_dev, "Transfer fail - status: 0x%08x\n", status); + rtsx_stop_cmd(sc); + if (sc->rtsx_intr_trans_ko != NULL) + sc->rtsx_intr_trans_ko(sc); + } + + RTSX_UNLOCK(sc); +} + +/* + * Function called from the IRQ handler (from dwmmc.c). + */ +static void +rtsx_handle_card_present(struct rtsx_softc *sc) +{ + bool was_present; + bool is_present; + +#ifdef MMCCAM + was_present = sc->rtsx_cam_status; +#else + was_present = sc->rtsx_mmc_dev != NULL; +#endif /* MMCCAM */ + is_present = rtsx_is_card_present(sc); + if (is_present) + device_printf(sc->rtsx_dev, "Card present\n"); + else + device_printf(sc->rtsx_dev, "Card absent\n"); + + if (!was_present && is_present) { + /* + * The delay is to debounce the card insert + * (sometimes the card detect pin stabilizes + * before the other pins have made good contact). + */ + taskqueue_enqueue_timeout(taskqueue_swi_giant, + &sc->rtsx_card_insert_task, -hz); + } else if (was_present && !is_present) { + taskqueue_enqueue(taskqueue_swi_giant, &sc->rtsx_card_remove_task); + } +} + +/* + * This funtion is called at startup. + */ +static void +rtsx_card_task(void *arg, int pending __unused) +{ + struct rtsx_softc *sc = arg; + + RTSX_LOCK(sc); + + if (rtsx_is_card_present(sc)) { + sc->rtsx_flags |= RTSX_F_CARD_PRESENT; + /* Card is present, attach if necessary. */ +#ifdef MMCCAM + if (sc->rtsx_cam_status == 0) { + union ccb *ccb; + uint32_t pathid; +#else + if (sc->rtsx_mmc_dev == NULL) { +#endif /* MMCCAM */ + if (bootverbose) + device_printf(sc->rtsx_dev, "Card inserted\n"); + + sc->rtsx_read_count = sc->rtsx_write_count = 0; +#ifdef MMCCAM + sc->rtsx_cam_status = 1; + pathid = cam_sim_path(sc->rtsx_sim); + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + device_printf(sc->rtsx_dev, "Unable to alloc CCB for rescan\n"); + RTSX_UNLOCK(sc); + return; + } + /* + * We create a rescan request for BUS:0:0, since the card + * will be at lun 0. + */ + if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, + /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) { + device_printf(sc->rtsx_dev, "Unable to create path for rescan\n"); + RTSX_UNLOCK(sc); + xpt_free_ccb(ccb); + return; + } + RTSX_UNLOCK(sc); + xpt_rescan(ccb); +#else + sc->rtsx_mmc_dev = device_add_child(sc->rtsx_dev, "mmc", -1); + RTSX_UNLOCK(sc); + if (sc->rtsx_mmc_dev == NULL) { + device_printf(sc->rtsx_dev, "Adding MMC bus failed\n"); + } else { + device_set_ivars(sc->rtsx_mmc_dev, sc); + device_probe_and_attach(sc->rtsx_mmc_dev); + } +#endif /* MMCCAM */ + } else + RTSX_UNLOCK(sc); + } else { + sc->rtsx_flags &= ~RTSX_F_CARD_PRESENT; + /* Card isn't present, detach if necessary. */ +#ifdef MMCCAM + if (sc->rtsx_cam_status != 0) { + union ccb *ccb; + uint32_t pathid; +#else + if (sc->rtsx_mmc_dev != NULL) { +#endif /* MMCCAM */ + if (bootverbose) + device_printf(sc->rtsx_dev, "Card removed\n"); + + if (sc->rtsx_debug) + device_printf(sc->rtsx_dev, "Read count: %" PRIu64 ", write count: %" PRIu64 "\n", + sc->rtsx_read_count, sc->rtsx_write_count); +#ifdef MMCCAM + sc->rtsx_cam_status = 0; + pathid = cam_sim_path(sc->rtsx_sim); + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + device_printf(sc->rtsx_dev, "Unable to alloc CCB for rescan\n"); + RTSX_UNLOCK(sc); + return; + } + /* + * We create a rescan request for BUS:0:0, since the card + * will be at lun 0. + */ + if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, + /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) { + device_printf(sc->rtsx_dev, "Unable to create path for rescan\n"); + RTSX_UNLOCK(sc); + xpt_free_ccb(ccb); + return; + } + RTSX_UNLOCK(sc); + xpt_rescan(ccb); +#else + RTSX_UNLOCK(sc); + if (device_delete_child(sc->rtsx_dev, sc->rtsx_mmc_dev)) + device_printf(sc->rtsx_dev, "Detaching MMC bus failed\n"); + sc->rtsx_mmc_dev = NULL; +#endif /* MMCCAM */ + } else + RTSX_UNLOCK(sc); + } +} + +static bool +rtsx_is_card_present(struct rtsx_softc *sc) +{ + uint32_t status; + + status = READ4(sc, RTSX_BIPR); + if (sc->rtsx_inversion == 0) + return (status & RTSX_SD_EXIST); + else + return !(status & RTSX_SD_EXIST); +} + +static int +rtsx_init(struct rtsx_softc *sc) +{ + bool rtsx_init_debug = false; + uint8_t version; + uint8_t val; + int error; + + sc->rtsx_host.host_ocr = RTSX_SUPPORTED_VOLTAGE; + sc->rtsx_host.f_min = RTSX_SDCLK_250KHZ; + sc->rtsx_host.f_max = RTSX_SDCLK_208MHZ; + sc->rtsx_host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED | + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; + + sc->rtsx_host.caps |= MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104; + if (sc->rtsx_device_id == RTSX_RTS5209) + sc->rtsx_host.caps |= MMC_CAP_8_BIT_DATA; + pci_find_cap(sc->rtsx_dev, PCIY_EXPRESS, &(sc->rtsx_pcie_cap)); + + /* + * Check IC version. + */ + switch (sc->rtsx_device_id) { + case RTSX_RTS5229: + /* Read IC version from dummy register. */ + RTSX_READ(sc, RTSX_DUMMY_REG, &version); + if ((version & 0x0F) == RTSX_IC_VERSION_C) + sc->rtsx_flags |= RTSX_F_VERSION_C; + break; + case RTSX_RTS522A: + /* Read IC version from dummy register. */ + RTSX_READ(sc, RTSX_DUMMY_REG, &version); + if ((version & 0x0F) == RTSX_IC_VERSION_A) + sc->rtsx_flags |= RTSX_F_VERSION_A; + break; + case RTSX_RTS525A: + /* Read IC version from dummy register. */ + RTSX_READ(sc, RTSX_DUMMY_REG, &version); + if ((version & 0x0F) == RTSX_IC_VERSION_A) + sc->rtsx_flags |= RTSX_F_VERSION_A; + break; + case RTSX_RTL8411B: + RTSX_READ(sc, RTSX_RTL8411B_PACKAGE, &version); + if (version & RTSX_RTL8411B_QFN48) + sc->rtsx_flags |= RTSX_F_8411B_QFN48; + break; + } + + /* + * Fetch vendor settings. + */ + /* + * Normally OEMs will set vendor setting to the config space + * of Realtek card reader in BIOS stage. This statement reads + * the setting and configure the internal registers according + * to it, to improve card reader's compatibility condition. + */ + sc->rtsx_card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + switch (sc->rtsx_device_id) { + uint32_t reg; + uint32_t reg1; + uint8_t reg3; + case RTSX_RTS5209: + sc->rtsx_card_drive_sel = RTSX_RTS5209_CARD_DRIVE_DEFAULT; + sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4); + if (!(reg & 0x80)) { + sc->rtsx_card_drive_sel = (reg >> 8) & 0x3F; + sc->rtsx_sd30_drive_sel_3v3 = reg & 0x07; + } else { + device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg); + } + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n", + sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3); + break; + case RTSX_RTS5227: + case RTSX_RTS522A: + sc->rtsx_sd30_drive_sel_3v3 = RTSX_CFG_DRIVER_TYPE_B; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4); + if (!(reg & 0x1000000)) { + sc->rtsx_card_drive_sel &= 0x3F; + sc->rtsx_card_drive_sel |= ((reg >> 25) & 0x01) << 6; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4); + sc->rtsx_sd30_drive_sel_3v3 = (reg >> 5) & 0x03; + if (reg & 0x4000) + sc->rtsx_flags |= RTSX_F_REVERSE_SOCKET; + } else { + device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg); + } + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, + "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x, reverse_socket is %s\n", + sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3, + (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) ? "true" : "false"); + break; + case RTSX_RTS5229: + sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4); + if (!(reg & 0x1000000)) { + sc->rtsx_card_drive_sel &= 0x3F; + sc->rtsx_card_drive_sel |= ((reg >> 25) & 0x01) << 6; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4); + sc->rtsx_sd30_drive_sel_3v3 = rtsx_map_sd_drive((reg >> 5) & 0x03); + } else { + device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg); + } + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n", + sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3); + break; + case RTSX_RTS525A: + case RTSX_RTS5249: + sc->rtsx_sd30_drive_sel_3v3 = RTSX_CFG_DRIVER_TYPE_B; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4); + if ((reg & 0x1000000)) { + sc->rtsx_card_drive_sel &= 0x3F; + sc->rtsx_card_drive_sel |= ((reg >> 25) & 0x01) << 6; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG2, 4); + sc->rtsx_sd30_drive_sel_3v3 = (reg >> 5) & 0x03; + if (reg & 0x4000) + sc->rtsx_flags |= RTSX_F_REVERSE_SOCKET; + } else { + device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg); + } + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, + "card_drive_sel = 0x%02x, sd30_drive_sel_3v3: 0x%02x, reverse_socket is %s\n", + sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3, + (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) ? "true" : "false"); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + sc->rtsx_card_drive_sel = RTSX_RTL8411_CARD_DRIVE_DEFAULT; + sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D; + reg1 = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4); + if (reg1 & 0x1000000) { + sc->rtsx_card_drive_sel &= 0x3F; + sc->rtsx_card_drive_sel |= ((reg1 >> 25) & 0x01) << 6; + reg3 = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG3, 1); + sc->rtsx_sd30_drive_sel_3v3 = (reg3 >> 5) & 0x07; + } else { + device_printf(sc->rtsx_dev, "pci_read_config() error - reg1: 0x%08x\n", reg1); + } + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, + "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n", + sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3); + break; + case RTSX_RTL8411B: + sc->rtsx_card_drive_sel = RTSX_RTL8411_CARD_DRIVE_DEFAULT; + sc->rtsx_sd30_drive_sel_3v3 = RTSX_DRIVER_TYPE_D; + reg = pci_read_config(sc->rtsx_dev, RTSX_PCR_SETTING_REG1, 4); + if (!(reg & 0x1000000)) { + sc->rtsx_sd30_drive_sel_3v3 = rtsx_map_sd_drive(reg & 0x03); + } else { + device_printf(sc->rtsx_dev, "pci_read_config() error - reg: 0x%08x\n", reg); + } + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, + "card_drive_sel: 0x%02x, sd30_drive_sel_3v3: 0x%02x\n", + sc->rtsx_card_drive_sel, sc->rtsx_sd30_drive_sel_3v3); + break; + } + + if (bootverbose || rtsx_init_debug) + device_printf(sc->rtsx_dev, "rtsx_init() rtsx_flags: 0x%04x\n", sc->rtsx_flags); + + /* Enable interrupts. */ + sc->rtsx_intr_enabled = RTSX_TRANS_OK_INT_EN | RTSX_TRANS_FAIL_INT_EN | RTSX_SD_INT_EN | RTSX_MS_INT_EN; + WRITE4(sc, RTSX_BIER, sc->rtsx_intr_enabled); + + /* Power on SSC clock. */ + RTSX_CLR(sc, RTSX_FPDCTL, RTSX_SSC_POWER_DOWN); + /* Wait SSC power stable. */ + DELAY(200); + + /* Disable ASPM */ + val = pci_read_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_LINK_CTL, 1); + pci_write_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_LINK_CTL, val & 0xfc, 1); + + /* + * Optimize phy. + */ + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + /* Some magic numbers from Linux driver. */ + if ((error = rtsx_write_phy(sc, 0x00, 0xB966))) + return (error); + break; + case RTSX_RTS5227: + RTSX_CLR(sc, RTSX_PM_CTRL3, RTSX_D3_DELINK_MODE_EN); + + /* Optimize RX sensitivity. */ + if ((error = rtsx_write_phy(sc, 0x00, 0xBA42))) + return (error); + break; + case RTSX_RTS5229: + /* Optimize RX sensitivity. */ + if ((error = rtsx_write_phy(sc, 0x00, 0xBA42))) + return (error); + break; + case RTSX_RTS522A: + RTSX_CLR(sc, RTSX_RTS522A_PM_CTRL3, RTSX_D3_DELINK_MODE_EN); + if (sc->rtsx_flags & RTSX_F_VERSION_A) { + if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR2, RTSX_PHY_RCR2_INIT_27S))) + return (error); + } + if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR1, RTSX_PHY_RCR1_INIT_27S))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD0, RTSX_PHY_FLD0_INIT_27S))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD3, RTSX_PHY_FLD3_INIT_27S))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD4, RTSX_PHY_FLD4_INIT_27S))) + return (error); + break; + case RTSX_RTS525A: + if ((error = rtsx_write_phy(sc, RTSX__PHY_FLD0, + RTSX__PHY_FLD0_CLK_REQ_20C | RTSX__PHY_FLD0_RX_IDLE_EN | + RTSX__PHY_FLD0_BIT_ERR_RSTN | RTSX__PHY_FLD0_BER_COUNT | + RTSX__PHY_FLD0_BER_TIMER | RTSX__PHY_FLD0_CHECK_EN))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX__PHY_ANA03, + RTSX__PHY_ANA03_TIMER_MAX | RTSX__PHY_ANA03_OOBS_DEB_EN | + RTSX__PHY_CMU_DEBUG_EN))) + return (error); + if (sc->rtsx_flags & RTSX_F_VERSION_A) + if ((error = rtsx_write_phy(sc, RTSX__PHY_REV0, + RTSX__PHY_REV0_FILTER_OUT | RTSX__PHY_REV0_CDR_BYPASS_PFD | + RTSX__PHY_REV0_CDR_RX_IDLE_BYPASS))) + return (error); + break; + case RTSX_RTS5249: + RTSX_CLR(sc, RTSX_PM_CTRL3, RTSX_D3_DELINK_MODE_EN); + if ((error = rtsx_write_phy(sc, RTSX_PHY_REV, + RTSX_PHY_REV_RESV | RTSX_PHY_REV_RXIDLE_LATCHED | + RTSX_PHY_REV_P1_EN | RTSX_PHY_REV_RXIDLE_EN | + RTSX_PHY_REV_CLKREQ_TX_EN | RTSX_PHY_REV_RX_PWST | + RTSX_PHY_REV_CLKREQ_DT_1_0 | RTSX_PHY_REV_STOP_CLKRD | + RTSX_PHY_REV_STOP_CLKWR))) + return (error); + DELAY(10); + if ((error = rtsx_write_phy(sc, RTSX_PHY_BPCR, + RTSX_PHY_BPCR_IBRXSEL | RTSX_PHY_BPCR_IBTXSEL | + RTSX_PHY_BPCR_IB_FILTER | RTSX_PHY_BPCR_CMIRROR_EN))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_PCR, + RTSX_PHY_PCR_FORCE_CODE | RTSX_PHY_PCR_OOBS_CALI_50 | + RTSX_PHY_PCR_OOBS_VCM_08 | RTSX_PHY_PCR_OOBS_SEN_90 | + RTSX_PHY_PCR_RSSI_EN | RTSX_PHY_PCR_RX10K))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR2, + RTSX_PHY_RCR2_EMPHASE_EN | RTSX_PHY_RCR2_NADJR | + RTSX_PHY_RCR2_CDR_SR_2 | RTSX_PHY_RCR2_FREQSEL_12 | + RTSX_PHY_RCR2_CDR_SC_12P | RTSX_PHY_RCR2_CALIB_LATE))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD4, + RTSX_PHY_FLD4_FLDEN_SEL | RTSX_PHY_FLD4_REQ_REF | + RTSX_PHY_FLD4_RXAMP_OFF | RTSX_PHY_FLD4_REQ_ADDA | + RTSX_PHY_FLD4_BER_COUNT | RTSX_PHY_FLD4_BER_TIMER | + RTSX_PHY_FLD4_BER_CHK_EN))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_RDR, + RTSX_PHY_RDR_RXDSEL_1_9 | RTSX_PHY_SSC_AUTO_PWD))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_RCR1, + RTSX_PHY_RCR1_ADP_TIME_4 | RTSX_PHY_RCR1_VCO_COARSE))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_FLD3, + RTSX_PHY_FLD3_TIMER_4 | RTSX_PHY_FLD3_TIMER_6 | + RTSX_PHY_FLD3_RXDELINK))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_TUNE, + RTSX_PHY_TUNE_TUNEREF_1_0 | RTSX_PHY_TUNE_VBGSEL_1252 | + RTSX_PHY_TUNE_SDBUS_33 | RTSX_PHY_TUNE_TUNED18 | + RTSX_PHY_TUNE_TUNED12 | RTSX_PHY_TUNE_TUNEA12))) + return (error); + break; + } + + /* Set mcu_cnt to 7 to ensure data can be sampled properly. */ + RTSX_BITOP(sc, RTSX_CLK_DIV, 0x07, 0x07); + + /* Disable sleep mode. */ + RTSX_CLR(sc, RTSX_HOST_SLEEP_STATE, + RTSX_HOST_ENTER_S1 | RTSX_HOST_ENTER_S3); + + /* Disable card clock. */ + RTSX_CLR(sc, RTSX_CARD_CLK_EN, RTSX_CARD_CLK_EN_ALL); + + /* Reset delink mode. */ + RTSX_CLR(sc, RTSX_CHANGE_LINK_STATE, + RTSX_FORCE_RST_CORE_EN | RTSX_NON_STICKY_RST_N_DBG); + + /* Card driving select. */ + RTSX_WRITE(sc, RTSX_CARD_DRIVE_SEL, sc->rtsx_card_drive_sel); + + /* Enable SSC clock. */ + RTSX_WRITE(sc, RTSX_SSC_CTL1, RTSX_SSC_8X_EN | RTSX_SSC_SEL_4M); + RTSX_WRITE(sc, RTSX_SSC_CTL2, 0x12); + + /* Disable cd_pwr_save. */ + RTSX_BITOP(sc, RTSX_CHANGE_LINK_STATE, 0x16, RTSX_MAC_PHY_RST_N_DBG); + + /* Clear Link Ready Interrupt. */ + RTSX_BITOP(sc, RTSX_IRQSTAT0, RTSX_LINK_READY_INT, RTSX_LINK_READY_INT); + + /* Enlarge the estimation window of PERST# glitch + * to reduce the chance of invalid card interrupt. */ + RTSX_WRITE(sc, RTSX_PERST_GLITCH_WIDTH, 0x80); + + /* Set RC oscillator to 400K. */ + RTSX_CLR(sc, RTSX_RCCTL, RTSX_RCCTL_F_2M); + + /* Enable interrupt write-clear (default is read-clear). */ + RTSX_CLR(sc, RTSX_NFTS_TX_CTRL, RTSX_INT_READ_CLR); + + if (sc->rtsx_device_id == RTSX_RTS525A) + RTSX_BITOP(sc, RTSX_PM_CLK_FORCE_CTL, 1, 1); + + /* OC power down. */ + RTSX_BITOP(sc, RTSX_FPDCTL, RTSX_SD_OC_POWER_DOWN, RTSX_SD_OC_POWER_DOWN); + + /* Enable clk_request_n to enable clock power management */ + pci_write_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_LINK_CTL + 1, 1, 1); + + /* Enter L1 when host tx idle */ + pci_write_config(sc->rtsx_dev, 0x70F, 0x5B, 1); + + /* + * Specific extra init. + */ + switch (sc->rtsx_device_id) { + uint16_t cap; + case RTSX_RTS5209: + /* Turn off LED. */ + RTSX_WRITE(sc, RTSX_CARD_GPIO, 0x03); + /* Reset ASPM state to default value. */ + RTSX_CLR(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK); + /* Force CLKREQ# PIN to drive 0 to request clock. */ + RTSX_BITOP(sc, RTSX_PETXCFG, 0x08, 0x08); + /* Configure GPIO as output. */ + RTSX_WRITE(sc, RTSX_CARD_GPIO_DIR, 0x03); + /* Configure driving. */ + RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3); + break; + case RTSX_RTS5227: + /* Configure GPIO as output. */ + RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON); + /* Reset ASPM state to default value. */ + RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM); + /* Switch LDO3318 source from DV33 to 3V3. */ + RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33); + RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3); + /* Set default OLT blink period. */ + RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD); + /* Configure LTR. */ + cap = pci_read_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_DEVICE_CTL2, 2); + if (cap & PCIEM_CTL2_LTR_ENABLE) + RTSX_WRITE(sc, RTSX_LTR_CTL, 0xa3); + /* Configure OBFF. */ + RTSX_BITOP(sc, RTSX_OBFF_CFG, RTSX_OBFF_EN_MASK, RTSX_OBFF_ENABLE); + /* Configure driving. */ + if ((error = rtsx_rts5227_fill_driving(sc))) + return (error); + /* Configure force_clock_req. */ + if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0xB8); + else + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0x88); + RTSX_CLR(sc, RTSX_PM_CTRL3, RTSX_D3_DELINK_MODE_EN); + /*!!! Added for reboot after Windows. */ + RTSX_BITOP(sc, RTSX_PM_CTRL3, RTSX_PM_WAKE_EN, RTSX_PM_WAKE_EN); + break; + case RTSX_RTS5229: + /* Configure GPIO as output. */ + RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON); + /* Reset ASPM state to default value. */ + /* With this reset: dd if=/dev/random of=/dev/mmcsd0 encounter a timeout. */ +//!!! RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM); + /* Force CLKREQ# PIN to drive 0 to request clock. */ + RTSX_BITOP(sc, RTSX_PETXCFG, 0x08, 0x08); + /* Switch LDO3318 source from DV33 to card_3v3. */ + RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33); + RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3); + /* Set default OLT blink period. */ + RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD); + /* Configure driving. */ + RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3); + break; + case RTSX_RTS522A: + /* Add specific init from RTS5227. */ + /* Configure GPIO as output. */ + RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON); + /* Reset ASPM state to default value. */ + RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM); + /* Switch LDO3318 source from DV33 to 3V3. */ + RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33); + RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3); + /* Set default OLT blink period. */ + RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD); + /* Configure LTR. */ + cap = pci_read_config(sc->rtsx_dev, sc->rtsx_pcie_cap + PCIER_DEVICE_CTL2, 2); + if (cap & PCIEM_CTL2_LTR_ENABLE) + RTSX_WRITE(sc, RTSX_LTR_CTL, 0xa3); + /* Configure OBFF. */ + RTSX_BITOP(sc, RTSX_OBFF_CFG, RTSX_OBFF_EN_MASK, RTSX_OBFF_ENABLE); + /* Configure driving. */ + if ((error = rtsx_rts5227_fill_driving(sc))) + return (error); + /* Configure force_clock_req. */ + if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0xB8); + else + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB8, 0x88); + RTSX_CLR(sc, RTSX_RTS522A_PM_CTRL3, 0x10); + + /* specific for RTS522A. */ + RTSX_BITOP(sc, RTSX_FUNC_FORCE_CTL, + RTSX_FUNC_FORCE_UPME_XMT_DBG, RTSX_FUNC_FORCE_UPME_XMT_DBG); + RTSX_BITOP(sc, RTSX_PCLK_CTL, 0x04, 0x04); + RTSX_BITOP(sc, RTSX_PM_EVENT_DEBUG, + RTSX_PME_DEBUG_0, RTSX_PME_DEBUG_0); + RTSX_WRITE(sc, RTSX_PM_CLK_FORCE_CTL, 0x11); + break; + case RTSX_RTS525A: + /* Add specific init from RTS5249. */ + /* Rest L1SUB Config. */ + RTSX_CLR(sc, RTSX_L1SUB_CONFIG3, 0xff); + /* Configure GPIO as output. */ + RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON); + /* Reset ASPM state to default value. */ + RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM); + /* Switch LDO3318 source from DV33 to 3V3. */ + RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33); + RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3); + /* Set default OLT blink period. */ + RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD); + /* Configure driving. */ + if ((error = rtsx_rts5249_fill_driving(sc))) + return (error); + /* Configure force_clock_req. */ + if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0xB0); + else + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0x80); + + /* Specifc for RTS525A. */ + RTSX_BITOP(sc, RTSX_PCLK_CTL, RTSX_PCLK_MODE_SEL, RTSX_PCLK_MODE_SEL); + if (sc->rtsx_flags & RTSX_F_VERSION_A) { + RTSX_WRITE(sc, RTSX_L1SUB_CONFIG2, RTSX_L1SUB_AUTO_CFG); + RTSX_BITOP(sc, RTSX_RREF_CFG, + RTSX_RREF_VBGSEL_MASK, RTSX_RREF_VBGSEL_1V25); + RTSX_BITOP(sc, RTSX_LDO_VIO_CFG, + RTSX_LDO_VIO_TUNE_MASK, RTSX_LDO_VIO_1V7); + RTSX_BITOP(sc, RTSX_LDO_DV12S_CFG, + RTSX_LDO_D12_TUNE_MASK, RTSX_LDO_D12_TUNE_DF); + RTSX_BITOP(sc, RTSX_LDO_AV12S_CFG, + RTSX_LDO_AV12S_TUNE_MASK, RTSX_LDO_AV12S_TUNE_DF); + RTSX_BITOP(sc, RTSX_LDO_VCC_CFG0, + RTSX_LDO_VCC_LMTVTH_MASK, RTSX_LDO_VCC_LMTVTH_2A); + RTSX_BITOP(sc, RTSX_OOBS_CONFIG, + RTSX_OOBS_AUTOK_DIS | RTSX_OOBS_VAL_MASK, 0x89); + } + break; + case RTSX_RTS5249: + /* Rest L1SUB Config. */ + RTSX_CLR(sc, RTSX_L1SUB_CONFIG3, 0xff); + /* Configure GPIO as output. */ + RTSX_BITOP(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON, RTSX_GPIO_LED_ON); + /* Reset ASPM state to default value. */ + RTSX_BITOP(sc, RTSX_ASPM_FORCE_CTL, RTSX_ASPM_FORCE_MASK, RTSX_FORCE_ASPM_NO_ASPM); + /* Switch LDO3318 source from DV33 to 3V3. */ + RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33); + RTSX_BITOP(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33, RTSX_LDO_PWR_SEL_3V3); + /* Set default OLT blink period. */ + RTSX_BITOP(sc, RTSX_OLT_LED_CTL, 0x0F, RTSX_OLT_LED_PERIOD); + /* Configure driving. */ + if ((error = rtsx_rts5249_fill_driving(sc))) + return (error); + /* Configure force_clock_req. */ + if (sc->rtsx_flags & RTSX_F_REVERSE_SOCKET) + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0xB0); + else + RTSX_BITOP(sc, RTSX_PETXCFG, 0xB0, 0x80); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3); + RTSX_BITOP(sc, RTSX_CARD_PAD_CTL, RTSX_CD_DISABLE_MASK | RTSX_CD_AUTO_DISABLE, + RTSX_CD_ENABLE); + break; + case RTSX_RTL8411B: + if (sc->rtsx_flags & RTSX_F_8411B_QFN48) + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xf5); + RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, sc->rtsx_sd30_drive_sel_3v3); + /* Enable SD interrupt. */ + RTSX_BITOP(sc, RTSX_CARD_PAD_CTL, RTSX_CD_DISABLE_MASK | RTSX_CD_AUTO_DISABLE, + RTSX_CD_ENABLE); + /* Clear hw_pfm_en to disable hardware PFM mode. */ + RTSX_BITOP(sc, RTSX_FUNC_FORCE_CTL, 0x06, 0x00); + break; + } + + /*!!! Added for reboot after Windows. */ + rtsx_bus_power_off(sc); + rtsx_set_sd_timing(sc, bus_timing_normal); + rtsx_set_sd_clock(sc, 0); + /*!!! Added for reboot after Windows. */ + + return (0); +} + +static int +rtsx_map_sd_drive(int index) +{ + uint8_t sd_drive[4] = + { + 0x01, /* Type D */ + 0x02, /* Type C */ + 0x05, /* Type A */ + 0x03 /* Type B */ + }; + return (sd_drive[index]); +} + +/* For voltage 3v3. */ +static int +rtsx_rts5227_fill_driving(struct rtsx_softc *sc) +{ + u_char driving_3v3[4][3] = { + {0x13, 0x13, 0x13}, + {0x96, 0x96, 0x96}, + {0x7F, 0x7F, 0x7F}, + {0x96, 0x96, 0x96}, + }; + RTSX_WRITE(sc, RTSX_SD30_CLK_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][0]); + RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][1]); + RTSX_WRITE(sc, RTSX_SD30_DAT_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][2]); + + return (0); +} + +/* For voltage 3v3. */ +static int +rtsx_rts5249_fill_driving(struct rtsx_softc *sc) +{ + u_char driving_3v3[4][3] = { + {0x11, 0x11, 0x18}, + {0x55, 0x55, 0x5C}, + {0xFF, 0xFF, 0xFF}, + {0x96, 0x96, 0x96}, + }; + RTSX_WRITE(sc, RTSX_SD30_CLK_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][0]); + RTSX_WRITE(sc, RTSX_SD30_CMD_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][1]); + RTSX_WRITE(sc, RTSX_SD30_DAT_DRIVE_SEL, driving_3v3[sc->rtsx_sd30_drive_sel_3v3][2]); + + return (0); +} + +static int +rtsx_read(struct rtsx_softc *sc, uint16_t addr, uint8_t *val) +{ + int tries = 1024; + uint32_t reg; + + WRITE4(sc, RTSX_HAIMR, RTSX_HAIMR_BUSY | + (uint32_t)((addr & 0x3FFF) << 16)); + + while (tries--) { + reg = READ4(sc, RTSX_HAIMR); + if (!(reg & RTSX_HAIMR_BUSY)) + break; + } + *val = (reg & 0xff); + + return ((tries == 0) ? ETIMEDOUT : 0); +} + +static int +rtsx_read_cfg(struct rtsx_softc *sc, uint8_t func, uint16_t addr, uint32_t *val) +{ + int tries = 1024; + uint8_t data0, data1, data2, data3, rwctl; + + RTSX_WRITE(sc, RTSX_CFGADDR0, addr); + RTSX_WRITE(sc, RTSX_CFGADDR1, addr >> 8); + RTSX_WRITE(sc, RTSX_CFGRWCTL, RTSX_CFG_BUSY | (func & 0x03 << 4)); + + while (tries--) { + RTSX_READ(sc, RTSX_CFGRWCTL, &rwctl); + if (!(rwctl & RTSX_CFG_BUSY)) + break; + } + + if (tries == 0) + return (ETIMEDOUT); + + RTSX_READ(sc, RTSX_CFGDATA0, &data0); + RTSX_READ(sc, RTSX_CFGDATA1, &data1); + RTSX_READ(sc, RTSX_CFGDATA2, &data2); + RTSX_READ(sc, RTSX_CFGDATA3, &data3); + + *val = (data3 << 24) | (data2 << 16) | (data1 << 8) | data0; + + return (0); +} + +static int +rtsx_write(struct rtsx_softc *sc, uint16_t addr, uint8_t mask, uint8_t val) +{ + int tries = 1024; + uint32_t reg; + + WRITE4(sc, RTSX_HAIMR, + RTSX_HAIMR_BUSY | RTSX_HAIMR_WRITE | + (uint32_t)(((addr & 0x3FFF) << 16) | + (mask << 8) | val)); + + while (tries--) { + reg = READ4(sc, RTSX_HAIMR); + if (!(reg & RTSX_HAIMR_BUSY)) { + if (val != (reg & 0xff)) + return (EIO); + return (0); + } + } + + return (ETIMEDOUT); +} + +static int +rtsx_read_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t *val) +{ + int tries = 100000; + uint8_t data0, data1, rwctl; + + RTSX_WRITE(sc, RTSX_PHY_ADDR, addr); + RTSX_WRITE(sc, RTSX_PHY_RWCTL, RTSX_PHY_BUSY | RTSX_PHY_READ); + + while (tries--) { + RTSX_READ(sc, RTSX_PHY_RWCTL, &rwctl); + if (!(rwctl & RTSX_PHY_BUSY)) + break; + } + if (tries == 0) + return (ETIMEDOUT); + + RTSX_READ(sc, RTSX_PHY_DATA0, &data0); + RTSX_READ(sc, RTSX_PHY_DATA1, &data1); + *val = data1 << 8 | data0; + + return (0); +} + +static int +rtsx_write_phy(struct rtsx_softc *sc, uint8_t addr, uint16_t val) +{ + int tries = 100000; + uint8_t rwctl; + + RTSX_WRITE(sc, RTSX_PHY_DATA0, val); + RTSX_WRITE(sc, RTSX_PHY_DATA1, val >> 8); + RTSX_WRITE(sc, RTSX_PHY_ADDR, addr); + RTSX_WRITE(sc, RTSX_PHY_RWCTL, RTSX_PHY_BUSY | RTSX_PHY_WRITE); + + while (tries--) { + RTSX_READ(sc, RTSX_PHY_RWCTL, &rwctl); + if (!(rwctl & RTSX_PHY_BUSY)) + break; + } + + return ((tries == 0) ? ETIMEDOUT : 0); +} + +/* + * Notice that the meaning of RTSX_PWR_GATE_CTRL changes between RTS5209 and + * RTS5229. In RTS5209 it is a mask of disabled power gates, while in RTS5229 + * it is a mask of *enabled* gates. + */ +static int +rtsx_bus_power_off(struct rtsx_softc *sc) +{ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_bus_power_off()\n"); + + /* Disable SD clock. */ + RTSX_CLR(sc, RTSX_CARD_CLK_EN, RTSX_SD_CLK_EN); + + /* Disable SD output. */ + RTSX_CLR(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN); + + /* Turn off power. */ + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK | RTSX_PMOS_STRG_MASK, + RTSX_SD_PWR_OFF | RTSX_PMOS_STRG_400mA); + RTSX_SET(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_OFF); + break; + case RTSX_RTS5227: + case RTSX_RTS5229: + case RTSX_RTS522A: + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK | RTSX_PMOS_STRG_MASK, + RTSX_SD_PWR_OFF | RTSX_PMOS_STRG_400mA); + RTSX_CLR(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + case RTSX_RTL8411B: + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK, + RTSX_BPP_POWER_OFF); + RTSX_BITOP(sc, RTSX_LDO_CTL, RTSX_BPP_LDO_POWB, + RTSX_BPP_LDO_SUSPEND); + break; + default: + RTSX_CLR(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK); + RTSX_SET(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_OFF); + RTSX_CLR(sc, RTSX_CARD_PWR_CTL, RTSX_PMOS_STRG_800mA); + break; + } + + /* Disable pull control. */ + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, RTSX_PULL_CTL_DISABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3); + break; + case RTSX_RTS5227: + case RTSX_RTS522A: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3); + break; + case RTSX_RTS5229: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12); + if (sc->rtsx_flags & RTSX_F_VERSION_C) + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3_TYPE_C); + else + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3); + break; + case RTSX_RTS525A: + case RTSX_RTS5249: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x66); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_DISABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_DISABLE3); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x55); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x65); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0x55); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0x95); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x09); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x05); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x04); + break; + case RTSX_RTL8411B: + if (sc->rtsx_flags & RTSX_F_8411B_QFN48) { + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0x55); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xf5); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x15); + } else { + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x65); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0x55); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xd5); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x59); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x55); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x15); + } + break; + } + + return (0); +} + +static int +rtsx_bus_power_on(struct rtsx_softc *sc) +{ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_bus_power_on()\n"); + + /* Select SD card. */ + RTSX_BITOP(sc, RTSX_CARD_SELECT, 0x07, RTSX_SD_MOD_SEL); + RTSX_BITOP(sc, RTSX_CARD_SHARE_MODE, RTSX_CARD_SHARE_MASK, RTSX_CARD_SHARE_48_SD); + + /* Enable SD clock. */ + RTSX_BITOP(sc, RTSX_CARD_CLK_EN, RTSX_SD_CLK_EN, RTSX_SD_CLK_EN); + + /* Enable pull control. */ + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, RTSX_PULL_CTL_ENABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3); + break; + case RTSX_RTS5227: + case RTSX_RTS522A: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3); + break; + case RTSX_RTS5229: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12); + if (sc->rtsx_flags & RTSX_F_VERSION_C) + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3_TYPE_C); + else + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3); + break; + case RTSX_RTS525A: + case RTSX_RTS5249: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0x66); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, RTSX_PULL_CTL_ENABLE3); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0xaa); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0xaa); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0xaa); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xa9); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x09); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x09); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x04); + break; + case RTSX_RTL8411B: + if (sc->rtsx_flags & RTSX_F_8411B_QFN48) { + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0xaa); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xf9); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x19); + } else { + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, 0xaa); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, 0xaa); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, 0xd9); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL4, 0x59); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL5, 0x55); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL6, 0x15); + } + break; + } + + /* + * To avoid a current peak, enable card power in two phases + * with a delay in between. + */ + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + /* Partial power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC2); + + DELAY(200); + + /* Full power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_ON); + break; + case RTSX_RTS5227: + case RTSX_RTS522A: + /* Partial power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC1); + + DELAY(200); + + /* Full power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, + RTSX_LDO3318_VCC1 | RTSX_LDO3318_VCC2); + RTSX_BITOP(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN, RTSX_SD_OUTPUT_EN); + RTSX_BITOP(sc, RTSX_CARD_OE, RTSX_MS_OUTPUT_EN, RTSX_MS_OUTPUT_EN); + break; + case RTSX_RTS5229: + /* Partial power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC1); + + DELAY(200); + + /* Full power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, + RTSX_LDO3318_VCC1 | RTSX_LDO3318_VCC2); + break; + case RTSX_RTS525A: + RTSX_BITOP(sc, RTSX_LDO_VCC_CFG1, RTSX_LDO_VCC_TUNE_MASK, RTSX_LDO_VCC_3V3); + case RTSX_RTS5249: + /* Partial power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PARTIAL_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, RTSX_LDO3318_VCC1); + + DELAY(200); + + /* Full power. */ + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_MASK, RTSX_SD_PWR_ON); + RTSX_BITOP(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_PWR_MASK, + RTSX_LDO3318_VCC1 | RTSX_LDO3318_VCC2); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + case RTSX_RTL8411B: + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK, + RTSX_BPP_POWER_5_PERCENT_ON); + RTSX_BITOP(sc, RTSX_LDO_CTL, RTSX_BPP_LDO_POWB, + RTSX_BPP_LDO_SUSPEND); + DELAY(150); + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK, + RTSX_BPP_POWER_10_PERCENT_ON); + DELAY(150); + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK, + RTSX_BPP_POWER_15_PERCENT_ON); + DELAY(150); + RTSX_BITOP(sc, RTSX_CARD_PWR_CTL, RTSX_BPP_POWER_MASK, + RTSX_BPP_POWER_ON); + RTSX_BITOP(sc, RTSX_LDO_CTL, RTSX_BPP_LDO_POWB, + RTSX_BPP_LDO_ON); + break; + } + + /* Enable SD card output. */ + RTSX_WRITE(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN); + + DELAY(200); + + return (0); +} + +/* + * Set but width. + */ +static int +rtsx_set_bus_width(struct rtsx_softc *sc, enum mmc_bus_width width) +{ + uint32_t bus_width; + + switch (width) { + case bus_width_1: + bus_width = RTSX_BUS_WIDTH_1; + break; + case bus_width_4: + bus_width = RTSX_BUS_WIDTH_4; + break; + case bus_width_8: + bus_width = RTSX_BUS_WIDTH_8; + break; + default: + return (MMC_ERR_INVALID); + } + RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_BUS_WIDTH_MASK, bus_width); + + if (bootverbose || sc->rtsx_debug) { + char *busw[] = { + "1 bit", + "4 bits", + "8 bits" + }; + device_printf(sc->rtsx_dev, "Setting bus width to %s\n", busw[bus_width]); + } + return (0); +} + +static int +rtsx_set_sd_timing(struct rtsx_softc *sc, enum mmc_bus_timing timing) +{ + + if (timing == bus_timing_hs && sc->rtsx_force_timing) { + timing = bus_timing_uhs_sdr50; + sc->rtsx_ios_timing = timing; + } + + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_set_sd_timing(%u)\n", timing); + + switch (timing) { + case bus_timing_uhs_sdr50: + case bus_timing_uhs_sdr104: + sc->rtsx_double_clk = false; + sc->rtsx_vpclk = true; + RTSX_BITOP(sc, RTSX_SD_CFG1, 0x0c | RTSX_SD_ASYNC_FIFO_NOT_RST, + RTSX_SD30_MODE | RTSX_SD_ASYNC_FIFO_NOT_RST); + RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ); + RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE, + RTSX_CRC_VAR_CLK0 | RTSX_SD30_FIX_CLK | RTSX_SAMPLE_VAR_CLK1); + RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ); + break; + case bus_timing_hs: + RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_SD_MODE_MASK, RTSX_SD20_MODE); + RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ); + RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE, + RTSX_CRC_FIX_CLK | RTSX_SD30_VAR_CLK0 | RTSX_SAMPLE_VAR_CLK1); + RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ); + + RTSX_BITOP(sc, RTSX_SD_PUSH_POINT_CTL, + RTSX_SD20_TX_SEL_MASK, RTSX_SD20_TX_14_AHEAD); + RTSX_BITOP(sc, RTSX_SD_SAMPLE_POINT_CTL, + RTSX_SD20_RX_SEL_MASK, RTSX_SD20_RX_14_DELAY); + break; + default: + RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_SD_MODE_MASK, RTSX_SD20_MODE); + RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ); + RTSX_WRITE(sc, RTSX_CARD_CLK_SOURCE, + RTSX_CRC_FIX_CLK | RTSX_SD30_VAR_CLK0 | RTSX_SAMPLE_VAR_CLK1); + RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ); + + RTSX_WRITE(sc, RTSX_SD_PUSH_POINT_CTL, RTSX_SD20_TX_NEG_EDGE); + RTSX_BITOP(sc, RTSX_SD_SAMPLE_POINT_CTL, + RTSX_SD20_RX_SEL_MASK, RTSX_SD20_RX_POS_EDGE); + break; + } + + return (0); +} + +/* + * Set or change SDCLK frequency or disable the SD clock. + * Return zero on success. + */ +static int +rtsx_set_sd_clock(struct rtsx_softc *sc, uint32_t freq) +{ + uint8_t clk; + uint8_t clk_divider, n, div, mcu; + int error = 0; + + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_set_sd_clock(%u)\n", freq); + + if (freq == RTSX_SDCLK_OFF) { + error = rtsx_stop_sd_clock(sc); + return error; + } + + sc->rtsx_ssc_depth = RTSX_SSC_DEPTH_500K; + sc->rtsx_discovery_mode = (freq <= 1000000) ? true : false; + + if (sc->rtsx_discovery_mode) { + /* We use 250k(around) here, in discovery stage. */ + clk_divider = RTSX_CLK_DIVIDE_128; + freq = 30000000; + } else { + clk_divider = RTSX_CLK_DIVIDE_0; + } + RTSX_BITOP(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, clk_divider); + + freq /= 1000000; + if (sc->rtsx_discovery_mode || !sc->rtsx_double_clk) + clk = freq; + else + clk = freq * 2; + + switch (sc->rtsx_device_id) { + case RTSX_RTL8402: + case RTSX_RTL8411: + case RTSX_RTL8411B: + n = clk * 4 / 5 - 2; + break; + default: + n = clk - 2; + break; + } + if ((clk <= 2) || (n > RTSX_MAX_DIV_N)) + return (MMC_ERR_INVALID); + + mcu = 125 / clk + 3; + if (mcu > 15) + mcu = 15; + + /* Make sure that the SSC clock div_n is not less than RTSX_MIN_DIV_N. */ + div = RTSX_CLK_DIV_1; + while ((n < RTSX_MIN_DIV_N) && (div < RTSX_CLK_DIV_8)) { + switch (sc->rtsx_device_id) { + case RTSX_RTL8402: + case RTSX_RTL8411: + case RTSX_RTL8411B: + n = (((n + 2) * 5 / 4) * 2) * 4 / 5 - 2; + break; + default: + n = (n + 2) * 2 - 2; + break; + } + div++; + } + + if (sc->rtsx_double_clk && sc->rtsx_ssc_depth > 1) + sc->rtsx_ssc_depth -= 1; + + if (div > RTSX_CLK_DIV_1) { + if (sc->rtsx_ssc_depth > (div - 1)) + sc->rtsx_ssc_depth -= (div - 1); + else + sc->rtsx_ssc_depth = RTSX_SSC_DEPTH_4M; + } + + /* Enable SD clock. */ + error = rtsx_switch_sd_clock(sc, clk, n, div, mcu); + + return (error); +} + +static int +rtsx_stop_sd_clock(struct rtsx_softc *sc) +{ + + RTSX_CLR(sc, RTSX_CARD_CLK_EN, RTSX_CARD_CLK_EN_ALL); + RTSX_SET(sc, RTSX_SD_BUS_STAT, RTSX_SD_CLK_FORCE_STOP); + + return (0); +} + +static int +rtsx_switch_sd_clock(struct rtsx_softc *sc, uint8_t clk, uint8_t n, uint8_t div, uint8_t mcu) +{ + if (bootverbose || sc->rtsx_debug) { + device_printf(sc->rtsx_dev, "rtsx_switch_sd_clock() - discovery-mode is %s, ssc_depth: %d\n", + (sc->rtsx_discovery_mode) ? "true" : "false", sc->rtsx_ssc_depth); + device_printf(sc->rtsx_dev, "rtsx_switch_sd_clock() - clk: %d, n: %d, div: %d, mcu: %d\n", + clk, n, div, mcu); + } + + RTSX_BITOP(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ, RTSX_CLK_LOW_FREQ); + RTSX_WRITE(sc, RTSX_CLK_DIV, (div << 4) | mcu); + RTSX_CLR(sc, RTSX_SSC_CTL1, RTSX_RSTB); + RTSX_BITOP(sc, RTSX_SSC_CTL2, RTSX_SSC_DEPTH_MASK, sc->rtsx_ssc_depth); + RTSX_WRITE(sc, RTSX_SSC_DIV_N_0, n); + RTSX_BITOP(sc, RTSX_SSC_CTL1, RTSX_RSTB, RTSX_RSTB); + if (sc->rtsx_vpclk) { + RTSX_CLR(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET); + RTSX_BITOP(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET, RTSX_PHASE_NOT_RESET); + } + + /* Wait SSC clock stable. */ + DELAY(200); + + RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ); + + return (0); +} + +static void +rtsx_sd_change_tx_phase(struct rtsx_softc *sc, uint8_t sample_point) +{ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_sd_change_tx_phase() - sample_point: %d\n", sample_point); + + rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, RTSX_CHANGE_CLK); + rtsx_write(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_SELECT_MASK, sample_point); + rtsx_write(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET, 0); + rtsx_write(sc, RTSX_SD_VPCLK0_CTL, RTSX_PHASE_NOT_RESET, RTSX_PHASE_NOT_RESET); + rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, 0); + rtsx_write(sc, RTSX_SD_CFG1, RTSX_SD_ASYNC_FIFO_NOT_RST, 0); +} + +static void +rtsx_sd_change_rx_phase(struct rtsx_softc *sc, uint8_t sample_point) +{ + if (bootverbose || sc->rtsx_debug == 2) + device_printf(sc->rtsx_dev, "rtsx_sd_change_rx_phase() - sample_point: %d\n", sample_point); + + rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, RTSX_CHANGE_CLK); + rtsx_write(sc, RTSX_SD_VPCLK1_CTL, RTSX_PHASE_SELECT_MASK, sample_point); + rtsx_write(sc, RTSX_SD_VPCLK1_CTL, RTSX_PHASE_NOT_RESET, 0); + rtsx_write(sc, RTSX_SD_VPCLK1_CTL, RTSX_PHASE_NOT_RESET, RTSX_PHASE_NOT_RESET); + rtsx_write(sc, RTSX_CLK_CTL, RTSX_CHANGE_CLK, 0); + rtsx_write(sc, RTSX_SD_CFG1, RTSX_SD_ASYNC_FIFO_NOT_RST, 0); +} + +static void +rtsx_sd_tuning_rx_phase(struct rtsx_softc *sc, uint32_t *phase_map) +{ + uint32_t raw_phase_map = 0; + int i; + int error; + + for (i = 0; i < RTSX_RX_PHASE_MAX; i++) { + error = rtsx_sd_tuning_rx_cmd(sc, (uint8_t)i); + if (error == 0) + raw_phase_map |= 1 << i; + } + if (phase_map != NULL) + *phase_map = raw_phase_map; +} + +static int +rtsx_sd_tuning_rx_cmd(struct rtsx_softc *sc, uint8_t sample_point) +{ + struct mmc_request req = {}; + struct mmc_command cmd = {}; + int error = 0; + + cmd.opcode = MMC_SEND_TUNING_BLOCK; + cmd.arg = 0; + req.cmd = &cmd; + + RTSX_LOCK(sc); + + sc->rtsx_req = &req; + + rtsx_sd_change_rx_phase(sc, sample_point); + + rtsx_write(sc, RTSX_SD_CFG3, RTSX_SD_RSP_80CLK_TIMEOUT_EN, + RTSX_SD_RSP_80CLK_TIMEOUT_EN); + + rtsx_init_cmd(sc, &cmd); + rtsx_set_cmd_data_len(sc, 1, 0x40); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, + RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC16 | + RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_CHECK_CRC7 | RTSX_SD_RSP_LEN_6); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, + 0xff, RTSX_TM_AUTO_TUNING | RTSX_SD_TRANSFER_START); + rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END); + + /* Set interrupt post processing */ + sc->rtsx_intr_trans_ok = rtsx_sd_tuning_rx_cmd_wakeup; + sc->rtsx_intr_trans_ko = rtsx_sd_tuning_rx_cmd_wakeup; + + /* Run the command queue. */ + rtsx_send_cmd(sc); + + error = rtsx_sd_tuning_rx_cmd_wait(sc, &cmd); + + if (error) { + if (bootverbose || sc->rtsx_debug == 2) + device_printf(sc->rtsx_dev, "rtsx_sd_tuning_rx_cmd() - error: %d\n", error); + rtsx_sd_wait_data_idle(sc); + rtsx_clear_error(sc); + } + rtsx_write(sc, RTSX_SD_CFG3, RTSX_SD_RSP_80CLK_TIMEOUT_EN, 0); + + sc->rtsx_req = NULL; + + RTSX_UNLOCK(sc); + + return (error); +} + +static int +rtsx_sd_tuning_rx_cmd_wait(struct rtsx_softc *sc, struct mmc_command *cmd) +{ + int status; + int mask = RTSX_TRANS_OK_INT | RTSX_TRANS_FAIL_INT; + + status = sc->rtsx_intr_status & mask; + while (status == 0) { + if (msleep(&sc->rtsx_intr_status, &sc->rtsx_mtx, 0, "rtsxintr", sc->rtsx_timeout) == EWOULDBLOCK) { + cmd->error = MMC_ERR_TIMEOUT; + return (MMC_ERR_TIMEOUT); + } + status = sc->rtsx_intr_status & mask; + } + return (cmd->error); +} + +static void +rtsx_sd_tuning_rx_cmd_wakeup(struct rtsx_softc *sc) +{ + wakeup(&sc->rtsx_intr_status); +} + +static void +rtsx_sd_wait_data_idle(struct rtsx_softc *sc) +{ + int i; + uint8_t val; + + for (i = 0; i < 100; i++) { + rtsx_read(sc, RTSX_SD_DATA_STATE, &val); + if (val & RTSX_SD_DATA_IDLE) + return; + DELAY(100); + } +} + +static uint8_t +rtsx_sd_search_final_rx_phase(struct rtsx_softc *sc, uint32_t phase_map) +{ + int start = 0, len = 0; + int start_final = 0, len_final = 0; + uint8_t final_phase = 0xff; + + while (start < RTSX_RX_PHASE_MAX) { + len = rtsx_sd_get_rx_phase_len(phase_map, start); + if (len_final < len) { + start_final = start; + len_final = len; + } + start += len ? len : 1; + } + + final_phase = (start_final + len_final / 2) % RTSX_RX_PHASE_MAX; + + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, + "rtsx_sd_search_final_rx_phase() - phase_map: %x, start_final: %d, len_final: %d, final_phase: %d\n", + phase_map, start_final, len_final, final_phase); + + return final_phase; +} + +static int +rtsx_sd_get_rx_phase_len(uint32_t phase_map, int start_bit) +{ + int i; + + for (i = 0; i < RTSX_RX_PHASE_MAX; i++) { + if ((phase_map & (1 << (start_bit + i) % RTSX_RX_PHASE_MAX)) == 0) + return i; + } + return RTSX_RX_PHASE_MAX; +} + +#if 0 /* For led */ +static int +rtsx_led_enable(struct rtsx_softc *sc) +{ + + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + RTSX_CLR(sc, RTSX_CARD_GPIO, RTSX_CARD_GPIO_LED_OFF); + RTSX_WRITE(sc, RTSX_CARD_AUTO_BLINK, + RTSX_LED_BLINK_EN | RTSX_LED_BLINK_SPEED); + break; + case RTSX_RTL8411B: + RTSX_CLR(sc, RTSX_GPIO_CTL, 0x01); + RTSX_WRITE(sc, RTSX_CARD_AUTO_BLINK, + RTSX_LED_BLINK_EN | RTSX_LED_BLINK_SPEED); + break; + default: + RTSX_SET(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON); + RTSX_SET(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_AUTOBLINK); + break; + } + + return (0); +} + +static int +rtsx_led_disable(struct rtsx_softc *sc) +{ + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + RTSX_CLR(sc, RTSX_CARD_AUTO_BLINK, RTSX_LED_BLINK_EN); + RTSX_WRITE(sc, RTSX_CARD_GPIO, RTSX_CARD_GPIO_LED_OFF); + break; + case RTSX_RTL8411B: + RTSX_CLR(sc, RTSX_CARD_AUTO_BLINK, RTSX_LED_BLINK_EN); + RTSX_SET(sc, RTSX_GPIO_CTL, 0x01); + break; + default: + RTSX_CLR(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_AUTOBLINK); + RTSX_CLR(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON); + break; + } + + return (0); +} +#endif /* For led */ + +static uint8_t +rtsx_response_type(uint16_t mmc_rsp) +{ + int i; + struct rsp_type { + uint16_t mmc_rsp; + uint8_t rtsx_rsp; + } rsp_types[] = { + { MMC_RSP_NONE, RTSX_SD_RSP_TYPE_R0 }, + { MMC_RSP_R1, RTSX_SD_RSP_TYPE_R1 }, + { MMC_RSP_R1B, RTSX_SD_RSP_TYPE_R1B }, + { MMC_RSP_R2, RTSX_SD_RSP_TYPE_R2 }, + { MMC_RSP_R3, RTSX_SD_RSP_TYPE_R3 }, + { MMC_RSP_R4, RTSX_SD_RSP_TYPE_R4 }, + { MMC_RSP_R5, RTSX_SD_RSP_TYPE_R5 }, + { MMC_RSP_R6, RTSX_SD_RSP_TYPE_R6 }, + { MMC_RSP_R7, RTSX_SD_RSP_TYPE_R7 } + }; + + for (i = 0; i < nitems(rsp_types); i++) { + if (mmc_rsp == rsp_types[i].mmc_rsp) + return (rsp_types[i].rtsx_rsp); + } + + return (0); +} + +/* + * Init command buffer with SD command index and argument. + */ +static void +rtsx_init_cmd(struct rtsx_softc *sc, struct mmc_command *cmd) +{ + sc->rtsx_cmd_index = 0; + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD0, + 0xff, RTSX_SD_CMD_START | cmd->opcode); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD1, + 0xff, cmd->arg >> 24); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD2, + 0xff, cmd->arg >> 16); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD3, + 0xff, cmd->arg >> 8); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CMD4, + 0xff, cmd->arg); +} + +/* + * Append a properly encoded host command to the host command buffer. + */ +static void +rtsx_push_cmd(struct rtsx_softc *sc, uint8_t cmd, uint16_t reg, + uint8_t mask, uint8_t data) +{ + KASSERT(sc->rtsx_cmd_index < RTSX_HOSTCMD_MAX, + ("rtsx: Too many host commands (%d)\n", sc->rtsx_cmd_index)); + + uint32_t *cmd_buffer = (uint32_t *)(sc->rtsx_cmd_dmamem); + cmd_buffer[sc->rtsx_cmd_index++] = + htole32((uint32_t)(cmd & 0x3) << 30) | + ((uint32_t)(reg & 0x3fff) << 16) | + ((uint32_t)(mask) << 8) | + ((uint32_t)data); +} + +/* + * Queue commands to configure data transfer size. + */ +static void +rtsx_set_cmd_data_len(struct rtsx_softc *sc, uint16_t block_cnt, uint16_t byte_cnt) { + + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_L, + 0xff, block_cnt & 0xff); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_H, + 0xff, block_cnt >> 8); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_L, + 0xff, byte_cnt & 0xff); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_H, + 0xff, byte_cnt >> 8); + +} + +/* + * Run the command queue. + */ +static void +rtsx_send_cmd(struct rtsx_softc *sc) +{ + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_send_cmd()\n"); + + sc->rtsx_intr_status = 0; + + /* Sync command DMA buffer. */ + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_PREWRITE); + + /* Tell the chip where the command buffer is and run the commands. */ + WRITE4(sc, RTSX_HCBAR, (uint32_t)sc->rtsx_cmd_buffer); + WRITE4(sc, RTSX_HCBCTLR, + ((sc->rtsx_cmd_index * 4) & 0x00ffffff) | RTSX_START_CMD | RTSX_HW_AUTO_RSP); +} + +/* + * Stop previous command. + */ +static void +rtsx_stop_cmd(struct rtsx_softc *sc) { + + /* Stop command transfer. */ + WRITE4(sc, RTSX_HCBCTLR, RTSX_STOP_CMD); + + /* Stop DMA transfer. */ + WRITE4(sc, RTSX_HDBCTLR, RTSX_STOP_DMA); + + rtsx_write(sc, RTSX_DMACTL, RTSX_DMA_RST, RTSX_DMA_RST); + + rtsx_write(sc, RTSX_RBCTL, RTSX_RB_FLUSH, RTSX_RB_FLUSH); +} + +/* + * Clear error. + */ +static void +rtsx_clear_error(struct rtsx_softc *sc) +{ + /* Clear error. */ + rtsx_write(sc, RTSX_CARD_STOP, RTSX_SD_STOP | RTSX_SD_CLR_ERR, + RTSX_SD_STOP | RTSX_SD_CLR_ERR); +} + +/* + * Signal end of request to mmc/mmcsd. + */ +static void +rtsx_req_done(struct rtsx_softc *sc) +{ +#ifdef MMCCAM + union ccb *ccb; +#endif /* MMCCAM */ + struct mmc_request *req; + + req = sc->rtsx_req; + if (req->cmd->error == MMC_ERR_NONE) { + if (req->cmd->opcode == MMC_READ_SINGLE_BLOCK || + req->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) + sc->rtsx_read_count++; + else if (req->cmd->opcode == MMC_WRITE_BLOCK || + req->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) + sc->rtsx_write_count++; + } else { + rtsx_clear_error(sc); + } + callout_stop(&sc->rtsx_timeout_callout); + sc->rtsx_req = NULL; +#ifdef MMCCAM + ccb = sc->rtsx_ccb; + sc->rtsx_ccb = NULL; + ccb->ccb_h.status = (req->cmd->error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR); + xpt_done(ccb); +#else + req->done(req); +#endif /* MMCCAM */ +} + +/* + * Send request. + */ +static int +rtsx_send_req(struct rtsx_softc *sc, struct mmc_command *cmd) { + uint8_t rsp_type; + uint16_t reg; + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_send_req() - CMD%d\n", cmd->opcode); + + /* Convert response type. */ + rsp_type = rtsx_response_type(cmd->flags & MMC_RSP_MASK); + if (rsp_type == 0) { + device_printf(sc->rtsx_dev, "Unknown rsp_type: 0x%lx\n", (cmd->flags & MMC_RSP_MASK)); + cmd->error = MMC_ERR_INVALID; + return (MMC_ERR_INVALID); + } + + rtsx_init_cmd(sc, cmd); + + /* Queue command to set response type. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, rsp_type); + + /* Use the ping-pong buffer (cmd buffer) for commands which do not transfer data. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE, + 0x01, RTSX_PINGPONG_BUFFER); + + /* Queue commands to perform SD transfer. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, + 0xff, RTSX_TM_CMD_RSP | RTSX_SD_TRANSFER_START); + rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END|RTSX_SD_STAT_IDLE, + RTSX_SD_TRANSFER_END|RTSX_SD_STAT_IDLE); + + /* If needed queue commands to read back card status response. */ + if (rsp_type == RTSX_SD_RSP_TYPE_R2) { + /* Read data from ping-pong buffer. */ + for (reg = RTSX_PPBUF_BASE2; reg < RTSX_PPBUF_BASE2 + 16; reg++) + rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg, 0, 0); + } else if (rsp_type != RTSX_SD_RSP_TYPE_R0) { + /* Read data from SD_CMDx registers. */ + for (reg = RTSX_SD_CMD0; reg <= RTSX_SD_CMD4; reg++) + rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg, 0, 0); + } + rtsx_push_cmd(sc, RTSX_READ_REG_CMD, RTSX_SD_STAT1, 0, 0); + + /* Set transfer OK function. */ + if (sc->rtsx_intr_trans_ok == NULL) + sc->rtsx_intr_trans_ok = rtsx_ret_resp; + + /* Run the command queue. */ + rtsx_send_cmd(sc); + + return (0); +} + +/* + * Return response of previous command (case cmd->data == NULL) and complete resquest. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_ret_resp(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->rtsx_req->cmd; + rtsx_set_resp(sc, cmd); + rtsx_req_done(sc); +} + +/* + * Set response of previous command. + */ +static void +rtsx_set_resp(struct rtsx_softc *sc, struct mmc_command *cmd) +{ + uint8_t rsp_type; + + rsp_type = rtsx_response_type(cmd->flags & MMC_RSP_MASK); + + /* Sync command DMA buffer. */ + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTWRITE); + + /* Copy card response into mmc response buffer. */ + if (ISSET(cmd->flags, MMC_RSP_PRESENT)) { + uint32_t *cmd_buffer = (uint32_t *)(sc->rtsx_cmd_dmamem); + + if (bootverbose) { + device_printf(sc->rtsx_dev, "cmd_buffer: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + cmd_buffer[0], cmd_buffer[1], cmd_buffer[2], cmd_buffer[3], cmd_buffer[4]); + } + + if (rsp_type == RTSX_SD_RSP_TYPE_R2) { + /* First byte is CHECK_REG_CMD return value, skip it. */ + unsigned char *ptr = (unsigned char *)cmd_buffer + 1; + int i; + + /* + * The controller offloads the last byte {CRC-7, end bit 1} + * of response type R2. Assign dummy CRC, 0, and end bit to this + * byte (ptr[16], goes into the LSB of resp[3] later). + */ + ptr[16] = 0x01; + /* The second byte is the status of response, skip it. */ + for (i = 0; i < 4; i++) + cmd->resp[i] = be32dec(ptr + 1 + i * 4); + } else { + /* + * First byte is CHECK_REG_CMD return value, second + * one is the command op code -- we skip those. + */ + cmd->resp[0] = + ((be32toh(cmd_buffer[0]) & 0x0000ffff) << 16) | + ((be32toh(cmd_buffer[1]) & 0xffff0000) >> 16); + } + + if (bootverbose) + device_printf(sc->rtsx_dev, "cmd->resp: 0x%08x 0x%08x 0x%08x 0x%08x\n", + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + } +} + +/* + * Use the ping-pong buffer (cmd buffer) for transfer <= 512 bytes. + */ +static int +rtsx_xfer_short(struct rtsx_softc *sc, struct mmc_command *cmd) +{ + int read; + + if (cmd->data == NULL || cmd->data->len == 0) { + cmd->error = MMC_ERR_INVALID; + return (MMC_ERR_INVALID); + } + cmd->data->xfer_len = (cmd->data->len > RTSX_MAX_DATA_BLKLEN) ? + RTSX_MAX_DATA_BLKLEN : cmd->data->len; + + read = ISSET(cmd->data->flags, MMC_DATA_READ); + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_xfer_short() - %s xfer: %ld bytes with block size %ld\n", + read ? "Read" : "Write", + (unsigned long)cmd->data->len, (unsigned long)cmd->data->xfer_len); + + if (cmd->data->len > 512) { + device_printf(sc->rtsx_dev, "rtsx_xfer_short() - length too large: %ld > 512\n", + (unsigned long)cmd->data->len); + cmd->error = MMC_ERR_INVALID; + return (MMC_ERR_INVALID); + } + + if (read) { + if (sc->rtsx_discovery_mode) + rtsx_write(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, RTSX_CLK_DIVIDE_0); + + rtsx_init_cmd(sc, cmd); + + /* Queue commands to configure data transfer size. */ + rtsx_set_cmd_data_len(sc, cmd->data->len / cmd->data->xfer_len, cmd->data->xfer_len); + + /* From Linux: rtsx_pci_sdmmc.c sd_read_data(). */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, + RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC16 | + RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_CHECK_CRC7 | RTSX_SD_RSP_LEN_6); + + /* Use the ping-pong buffer (cmd buffer). */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE, + 0x01, RTSX_PINGPONG_BUFFER); + + /* Queue commands to perform SD transfer. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, + 0xff, RTSX_TM_NORMAL_READ | RTSX_SD_TRANSFER_START); + rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END); + + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_ask_ppbuf_part1; + + /* Run the command queue. */ + rtsx_send_cmd(sc); + } else { + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_put_ppbuf_part1; + + /* Run the command queue. */ + rtsx_send_req(sc, cmd); + } + + return (0); +} + +/* + * Use the ping-pong buffer (cmd buffer) for the transfer - first part <= 256 bytes. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_ask_ppbuf_part1(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + uint16_t reg = RTSX_PPBUF_BASE2; + int len; + int i; + + cmd = sc->rtsx_req->cmd; + len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? RTSX_HOSTCMD_MAX : cmd->data->len; + + sc->rtsx_cmd_index = 0; + for (i = 0; i < len; i++) { + rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg++, 0, 0); + } + + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_get_ppbuf_part1; + + /* Run the command queue. */ + rtsx_send_cmd(sc); +} + +/* + * Get the data from the ping-pong buffer (cmd buffer) - first part <= 256 bytes. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_get_ppbuf_part1(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + uint8_t *ptr; + int len; + + cmd = sc->rtsx_req->cmd; + ptr = cmd->data->data; + len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? RTSX_HOSTCMD_MAX : cmd->data->len; + + /* Sync command DMA buffer. */ + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTWRITE); + + memcpy(ptr, sc->rtsx_cmd_dmamem, len); + + len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? cmd->data->len - RTSX_HOSTCMD_MAX : 0; + + /* Use the ping-pong buffer (cmd buffer) for the transfer - second part > 256 bytes. */ + if (len > 0) { + uint16_t reg = RTSX_PPBUF_BASE2 + RTSX_HOSTCMD_MAX; + int i; + + sc->rtsx_cmd_index = 0; + for (i = 0; i < len; i++) { + rtsx_push_cmd(sc, RTSX_READ_REG_CMD, reg++, 0, 0); + } + + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_get_ppbuf_part2; + + /* Run the command queue. */ + rtsx_send_cmd(sc); + } else { + if (bootverbose && cmd->opcode == ACMD_SEND_SCR) { + uint8_t *ptr = cmd->data->data; + device_printf(sc->rtsx_dev, "SCR: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + ptr[0], ptr[1], ptr[2], ptr[3], + ptr[4], ptr[5], ptr[6], ptr[7]); + } + + if (sc->rtsx_discovery_mode) + rtsx_write(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, RTSX_CLK_DIVIDE_128); + + rtsx_req_done(sc); + } +} + +/* + * Get the data from the ping-pong buffer (cmd buffer) - second part > 256 bytes. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_get_ppbuf_part2(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + uint8_t *ptr; + int len; + + cmd = sc->rtsx_req->cmd; + ptr = cmd->data->data; + ptr += RTSX_HOSTCMD_MAX; + len = cmd->data->len - RTSX_HOSTCMD_MAX; + + /* Sync command DMA buffer. */ + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->rtsx_cmd_dma_tag, sc->rtsx_cmd_dmamap, BUS_DMASYNC_POSTWRITE); + + memcpy(ptr, sc->rtsx_cmd_dmamem, len); + + if (sc->rtsx_discovery_mode) + rtsx_write(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK, RTSX_CLK_DIVIDE_128); + + rtsx_req_done(sc); +} + +/* + * Use the ping-pong buffer (cmd buffer) for transfer - first part <= 256 bytes. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_put_ppbuf_part1(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + uint16_t reg = RTSX_PPBUF_BASE2; + uint8_t *ptr; + int len; + int i; + + cmd = sc->rtsx_req->cmd; + ptr = cmd->data->data; + len = (cmd->data->len > RTSX_HOSTCMD_MAX) ? RTSX_HOSTCMD_MAX : cmd->data->len; + + rtsx_set_resp(sc, cmd); + + sc->rtsx_cmd_index = 0; + for (i = 0; i < len; i++) { + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, reg++, 0xff, *ptr); + ptr++; + } + + /* Set transfer OK function. */ + if (cmd->data->len > RTSX_HOSTCMD_MAX) + sc->rtsx_intr_trans_ok = rtsx_put_ppbuf_part2; + else + sc->rtsx_intr_trans_ok = rtsx_write_ppbuf; + + /* Run the command queue. */ + rtsx_send_cmd(sc); +} + +/* + * Use the ping-pong buffer (cmd buffer) for transfer - second part > 256 bytes. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_put_ppbuf_part2(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + uint16_t reg = RTSX_PPBUF_BASE2 + RTSX_HOSTCMD_MAX; + uint8_t *ptr; + int len; + int i; + + cmd = sc->rtsx_req->cmd; + ptr = cmd->data->data; + ptr += RTSX_HOSTCMD_MAX; + len = cmd->data->len - RTSX_HOSTCMD_MAX; + + sc->rtsx_cmd_index = 0; + for (i = 0; i < len; i++) { + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, reg++, 0xff, *ptr); + ptr++; + } + + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_write_ppbuf; + + /* Run the command queue. */ + rtsx_send_cmd(sc); +} + +/* + * Write the data previously given via the ping-pong buffer on the card. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_write_ppbuf(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->rtsx_req->cmd; + + sc->rtsx_cmd_index = 0; + + /* Queue commands to configure data transfer size. */ + rtsx_set_cmd_data_len(sc, cmd->data->len / cmd->data->xfer_len, cmd->data->xfer_len); + + /* From Linux: rtsx_pci_sdmmc.c sd_write_data(). */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, + RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC16 | + RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_CHECK_CRC7 | RTSX_SD_RSP_LEN_0); + + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, 0xff, + RTSX_TM_AUTO_WRITE3 | RTSX_SD_TRANSFER_START); + rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END); + + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_req_done; + + /* Run the command queue. */ + rtsx_send_cmd(sc); +} + +/* + * Use the data buffer for transfer > 512 bytes. + */ +static int +rtsx_xfer(struct rtsx_softc *sc, struct mmc_command *cmd) +{ + int read = ISSET(cmd->data->flags, MMC_DATA_READ); + + cmd->data->xfer_len = (cmd->data->len > RTSX_MAX_DATA_BLKLEN) ? + RTSX_MAX_DATA_BLKLEN : cmd->data->len; + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_xfer() - %s xfer: %ld bytes with block size %ld\n", + read ? "Read" : "Write", + (unsigned long)cmd->data->len, (unsigned long)cmd->data->xfer_len); + + if (cmd->data->len > RTSX_DMA_DATA_BUFSIZE) { + device_printf(sc->rtsx_dev, "rtsx_xfer() length too large: %ld > %d\n", + (unsigned long)cmd->data->len, RTSX_DMA_DATA_BUFSIZE); + cmd->error = MMC_ERR_INVALID; + return (MMC_ERR_INVALID); + } + + if (!read) { + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_xfer_begin; + + /* Run the command queue. */ + rtsx_send_req(sc, cmd); + } else { + rtsx_xfer_start(sc); + } + + return (0); +} + +/* + * Get request response and start dma data transfer (write command). + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_xfer_begin(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->rtsx_req->cmd; + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_xfer_begin() - CMD%d\n", cmd->opcode); + + rtsx_set_resp(sc, cmd); + rtsx_xfer_start(sc); +} + +/* + * Start dma data transfer. + */ +static void +rtsx_xfer_start(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + int read; + uint8_t cfg2; + int dma_dir; + int tmode; + + cmd = sc->rtsx_req->cmd; + read = ISSET(cmd->data->flags, MMC_DATA_READ); + + /* Configure DMA transfer mode parameters. */ + if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK) + cfg2 = RTSX_SD_CHECK_CRC16 | RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_RSP_LEN_6; + else + cfg2 = RTSX_SD_CHECK_CRC16 | RTSX_SD_NO_WAIT_BUSY_END | RTSX_SD_RSP_LEN_0; + if (read) { + dma_dir = RTSX_DMA_DIR_FROM_CARD; + /* + * Use transfer mode AUTO_READ1, which assume we not + * already send the read command and don't need to send + * CMD 12 manually after read. + */ + tmode = RTSX_TM_AUTO_READ1; + cfg2 |= RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC7; + + rtsx_init_cmd(sc, cmd); + } else { + dma_dir = RTSX_DMA_DIR_TO_CARD; + /* + * Use transfer mode AUTO_WRITE3, wich assumes we've already + * sent the write command and gotten the response, and will + * send CMD 12 manually after writing. + */ + tmode = RTSX_TM_AUTO_WRITE3; + cfg2 |= RTSX_SD_NO_CALCULATE_CRC7 | RTSX_SD_NO_CHECK_CRC7; + + sc->rtsx_cmd_index = 0; + } + + /* Queue commands to configure data transfer size. */ + rtsx_set_cmd_data_len(sc, cmd->data->len / cmd->data->xfer_len, cmd->data->xfer_len); + + /* Configure DMA controller. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_IRQSTAT0, + RTSX_DMA_DONE_INT, RTSX_DMA_DONE_INT); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC3, + 0xff, cmd->data->len >> 24); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC2, + 0xff, cmd->data->len >> 16); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC1, + 0xff, cmd->data->len >> 8); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMATC0, + 0xff, cmd->data->len); + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_DMACTL, + RTSX_DMA_EN | RTSX_DMA_DIR | RTSX_DMA_PACK_SIZE_MASK, + RTSX_DMA_EN | dma_dir | RTSX_DMA_512); + + /* Use the DMA ring buffer for commands which transfer data. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE, + 0x01, RTSX_RING_BUFFER); + + /* Queue command to set response type. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, cfg2); + + /* Queue commands to perform SD transfer. */ + rtsx_push_cmd(sc, RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, + 0xff, tmode | RTSX_SD_TRANSFER_START); + rtsx_push_cmd(sc, RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END); + + /* Run the command queue. */ + rtsx_send_cmd(sc); + + if (!read) + memcpy(sc->rtsx_data_dmamem, cmd->data->data, cmd->data->len); + + /* Sync data DMA buffer. */ + bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_PREWRITE); + + /* Set transfer OK function. */ + sc->rtsx_intr_trans_ok = rtsx_xfer_finish; + + /* Tell the chip where the data buffer is and run the transfer. */ + WRITE4(sc, RTSX_HDBAR, sc->rtsx_data_buffer); + WRITE4(sc, RTSX_HDBCTLR, RTSX_TRIG_DMA | (read ? RTSX_DMA_READ : 0) | + (cmd->data->len & 0x00ffffff)); +} + +/* + * Finish dma data transfer. + * This Function is called by the interrupt handler via sc->rtsx_intr_trans_ok. + */ +static void +rtsx_xfer_finish(struct rtsx_softc *sc) +{ + struct mmc_command *cmd; + int read; + + cmd = sc->rtsx_req->cmd; + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_xfer_finish() - CMD%d\n", cmd->opcode); + + read = ISSET(cmd->data->flags, MMC_DATA_READ); + + /* Sync data DMA buffer. */ + bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->rtsx_data_dma_tag, sc->rtsx_data_dmamap, BUS_DMASYNC_POSTWRITE); + + if (read) { + memcpy(cmd->data->data, sc->rtsx_data_dmamem, cmd->data->len); + rtsx_req_done(sc); + } else { + /* Send CMD12 after AUTO_WRITE3 (see mmcsd_rw() in mmcsd.c) */ + /* and complete request. */ + sc->rtsx_intr_trans_ok = NULL; + rtsx_send_req(sc, sc->rtsx_req->stop); + } +} + +/* + * Manage request timeout. + */ +static void +rtsx_timeout(void *arg) +{ + struct rtsx_softc *sc; + + sc = (struct rtsx_softc *)arg; + if (sc->rtsx_req != NULL) { + device_printf(sc->rtsx_dev, "Controller timeout for CMD%u\n", + sc->rtsx_req->cmd->opcode); + sc->rtsx_req->cmd->error = MMC_ERR_TIMEOUT; + rtsx_stop_cmd(sc); + rtsx_req_done(sc); + } else { + device_printf(sc->rtsx_dev, "Controller timeout!\n"); + } +} + +#ifdef MMCCAM +static void +rtsx_cam_action(struct cam_sim *sim, union ccb *ccb) +{ + struct rtsx_softc *sc; + + sc = cam_sim_softc(sim); + if (sc == NULL) { + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + xpt_done(ccb); + return; + } + switch (ccb->ccb_h.func_code) { + case XPT_PATH_INQ: + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; /* SIM driver version number - now all drivers use 1 */ + cpi->hba_inquiry = 0; /* bitmask of features supported by the controller */ + cpi->target_sprt = 0; /* flags for target mode support */ + cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; + cpi->hba_eng_cnt = 0; /* HBA engine count - always set to 0 */ + cpi->max_target = 0; /* maximal supported target ID */ + cpi->max_lun = 0; /* maximal supported LUN ID */ + cpi->initiator_id = 1; /* the SCSI ID of the controller itself */ + cpi->maxio = MAXPHYS; /* maximum io size */ + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); /* vendor ID of the SIM */ + strncpy(cpi->hba_vid, "Realtek", HBA_IDLEN); /* vendor ID of the HBA */ + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); /* device name for SIM */ + cpi->unit_number = cam_sim_unit(sim); /* controller unit number */ + cpi->bus_id = cam_sim_bus(sim); /* bus number */ + cpi->protocol = PROTO_MMCSD; + cpi->protocol_version = SCSI_REV_0; + cpi->transport = XPORT_MMCSD; + cpi->transport_version = 1; + + cpi->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts = &ccb->cts; + + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_action() - got XPT_GET_TRAN_SETTINGS\n"); + + cts->protocol = PROTO_MMCSD; + cts->protocol_version = 1; + cts->transport = XPORT_MMCSD; + cts->transport_version = 1; + cts->xport_specific.valid = 0; + cts->proto_specific.mmc.host_ocr = sc->rtsx_host.host_ocr; + cts->proto_specific.mmc.host_f_min = sc->rtsx_host.f_min; + cts->proto_specific.mmc.host_f_max = sc->rtsx_host.f_max; + cts->proto_specific.mmc.host_caps = sc->rtsx_host.caps; + memcpy(&cts->proto_specific.mmc.ios, &sc->rtsx_host.ios, sizeof(struct mmc_ios)); + + ccb->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_SET_TRAN_SETTINGS: + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_action() - got XPT_SET_TRAN_SETTINGS\n"); + + rtsx_cam_set_tran_settings(sc, ccb); + + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_RESET_BUS: + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "got XPT_RESET_BUS, ACK it...\n"); + + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_MMC_IO: + /* + * Here is the HW-dependent part of sending + * the command to the underlying h/w. + * At some point in the future an interrupt comes + * and the request will be marked as completed. + */ + ccb->ccb_h.status = CAM_REQ_INPROG; + + rtsx_cam_request(sc, ccb); + return; + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + } + xpt_done(ccb); + return; +} + +static void +rtsx_cam_poll(struct cam_sim *sim){ + return; +} + +static int +rtsx_cam_set_tran_settings(struct rtsx_softc *sc, union ccb *ccb) +{ + struct mmc_ios *ios; + struct mmc_ios *new_ios; + struct ccb_trans_settings_mmc *cts; + + ios = &sc->rtsx_host.ios; + cts = &ccb->cts.proto_specific.mmc; + new_ios = &cts->ios; + + /* Update only requested fields */ + if (cts->ios_valid & MMC_CLK) { + ios->clock = new_ios->clock; + sc->rtsx_ios_clock = -1; /* To be updated by rtsx_mmcbr_update_ios(). */ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - clock: %u\n", ios->clock); + } + if (cts->ios_valid & MMC_VDD) { + ios->vdd = new_ios->vdd; + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - vdd: %d\n", ios->vdd); + } + if (cts->ios_valid & MMC_CS) { + ios->chip_select = new_ios->chip_select; + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - chip_select: %d\n", ios->chip_select); + } + if (cts->ios_valid & MMC_BW) { + ios->bus_width = new_ios->bus_width; + sc->rtsx_ios_bus_width = -1; /* To be updated by rtsx_mmcbr_update_ios(). */ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - bus width: %d\n", ios->bus_width); + } + if (cts->ios_valid & MMC_PM) { + ios->power_mode = new_ios->power_mode; + sc->rtsx_ios_power_mode = -1; /* To be updated by rtsx_mmcbr_update_ios(). */ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - power mode: %d\n", ios->power_mode); + } + if (cts->ios_valid & MMC_BT) { + ios->timing = new_ios->timing; + sc->rtsx_ios_timing = -1; /* To be updated by rtsx_mmcbr_update_ios(). */ + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - timing: %d\n", ios->timing); + } + if (cts->ios_valid & MMC_BM) { + ios->bus_mode = new_ios->bus_mode; + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_cam_set_tran_settings() - bus mode: %d\n", ios->bus_mode); + } + + return (rtsx_mmcbr_update_ios(sc->rtsx_dev, NULL)); +} + +static int +rtsx_cam_request(struct rtsx_softc *sc, union ccb *ccb) +{ + RTSX_LOCK(sc); + if (sc->rtsx_ccb != NULL) { + RTSX_UNLOCK(sc); + return (EBUSY); + } + sc->rtsx_ccb = ccb; + sc->rtsx_cam_req.cmd = &ccb->mmcio.cmd; + sc->rtsx_cam_req.stop = &ccb->mmcio.stop; + RTSX_UNLOCK(sc); + + rtsx_mmcbr_request(sc->rtsx_dev, NULL, &sc->rtsx_cam_req); + + return (0); +} +#endif /* MMCCAM */ + +static int +rtsx_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) +{ + struct rtsx_softc *sc; + + sc = device_get_softc(bus); + switch (which) { + case MMCBR_IVAR_BUS_MODE: /* ivar 0 - 1 = opendrain, 2 = pushpull */ + *result = sc->rtsx_host.ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: /* ivar 1 - 0 = 1b 2 = 4b, 3 = 8b */ + *result = sc->rtsx_host.ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: /* ivar 2 - O = dontcare, 1 = cs_high, 2 = cs_low */ + *result = sc->rtsx_host.ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: /* ivar 3 - clock in Hz */ + *result = sc->rtsx_host.ios.clock; + break; + case MMCBR_IVAR_F_MIN: /* ivar 4 */ + *result = sc->rtsx_host.f_min; + break; + case MMCBR_IVAR_F_MAX: /* ivar 5 */ + *result = sc->rtsx_host.f_max; + break; + case MMCBR_IVAR_HOST_OCR: /* ivar 6 - host operation conditions register */ + *result = sc->rtsx_host.host_ocr; + break; + case MMCBR_IVAR_MODE: /* ivar 7 - 0 = mode_mmc, 1 = mode_sd */ + *result = sc->rtsx_host.mode; + break; + case MMCBR_IVAR_OCR: /* ivar 8 - operation conditions register */ + *result = sc->rtsx_host.ocr; + break; + case MMCBR_IVAR_POWER_MODE: /* ivar 9 - 0 = off, 1 = up, 2 = on */ + *result = sc->rtsx_host.ios.power_mode; + break; + case MMCBR_IVAR_VDD: /* ivar 11 - voltage power pin */ + *result = sc->rtsx_host.ios.vdd; + break; + case MMCBR_IVAR_VCCQ: /* ivar 12 - signaling: 0 = 1.20V, 1 = 1.80V, 2 = 3.30V */ + *result = sc->rtsx_host.ios.vccq; + break; + case MMCBR_IVAR_CAPS: /* ivar 13 */ + *result = sc->rtsx_host.caps; + break; + case MMCBR_IVAR_TIMING: /* ivar 14 - 0 = normal, 1 = timing_hs, ... */ + *result = sc->rtsx_host.ios.timing; + break; + case MMCBR_IVAR_MAX_DATA: /* ivar 15 */ + *result = MAXPHYS / MMC_SECTOR_SIZE; + break; + case MMCBR_IVAR_RETUNE_REQ: /* ivar 10 */ + case MMCBR_IVAR_MAX_BUSY_TIMEOUT: /* ivar 16 */ + default: + return (EINVAL); + } + + if (bootverbose) + device_printf(bus, "Read ivar #%d, value %#x / #%d\n", + which, *(int *)result, *(int *)result); + + return (0); +} + +static int +rtsx_write_ivar(device_t bus, device_t child, int which, uintptr_t value) +{ + struct rtsx_softc *sc; + + if (bootverbose) + device_printf(bus, "Write ivar #%d, value %#x / #%d\n", + which, (int)value, (int)value); + + sc = device_get_softc(bus); + switch (which) { + case MMCBR_IVAR_BUS_MODE: /* ivar 0 - 1 = opendrain, 2 = pushpull */ + sc->rtsx_host.ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: /* ivar 1 - 0 = 1b 2 = 4b, 3 = 8b */ + sc->rtsx_host.ios.bus_width = value; + sc->rtsx_ios_bus_width = -1; /* To be updated on next rtsx_mmcbr_update_ios(). */ + break; + case MMCBR_IVAR_CHIP_SELECT: /* ivar 2 - O = dontcare, 1 = cs_high, 2 = cs_low */ + sc->rtsx_host.ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: /* ivar 3 - clock in Hz */ + sc->rtsx_host.ios.clock = value; + sc->rtsx_ios_clock = -1; /* To be updated on next rtsx_mmcbr_update_ios(). */ + break; + case MMCBR_IVAR_MODE: /* ivar 7 - 0 = mode_mmc, 1 = mode_sd */ + sc->rtsx_host.mode = value; + break; + case MMCBR_IVAR_OCR: /* ivar 8 - operation conditions register */ + sc->rtsx_host.ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: /* ivar 9 - 0 = off, 1 = up, 2 = on */ + sc->rtsx_host.ios.power_mode = value; + sc->rtsx_ios_power_mode = -1; /* To be updated on next rtsx_mmcbr_update_ios(). */ + break; + case MMCBR_IVAR_VDD: /* ivar 11 - voltage power pin */ + sc->rtsx_host.ios.vdd = value; + break; + case MMCBR_IVAR_VCCQ: /* ivar 12 - signaling: 0 = 1.20V, 1 = 1.80V, 2 = 3.30V */ + sc->rtsx_host.ios.vccq = value; /* rtsx_mmcbr_switch_vccq() will be called by mmc.c. */ + break; + case MMCBR_IVAR_TIMING: /* ivar 14 - 0 = normal, 1 = timing_hs, ... */ + sc->rtsx_host.ios.timing = value; + sc->rtsx_ios_timing = -1; /* To be updated on next rtsx_mmcbr_update_ios(). */ + break; + /* These are read-only. */ + case MMCBR_IVAR_F_MIN: /* ivar 4 */ + case MMCBR_IVAR_F_MAX: /* ivar 5 */ + case MMCBR_IVAR_HOST_OCR: /* ivar 6 - host operation conditions register */ + case MMCBR_IVAR_RETUNE_REQ: /* ivar 10 */ + case MMCBR_IVAR_CAPS: /* ivar 13 */ + case MMCBR_IVAR_MAX_DATA: /* ivar 15 */ + case MMCBR_IVAR_MAX_BUSY_TIMEOUT: /* ivar 16 */ + default: + return (EINVAL); + } + + return (0); +} + +static int +rtsx_mmcbr_update_ios(device_t bus, device_t child__unused) +{ + struct rtsx_softc *sc; + struct mmc_ios *ios; + int error; + + sc = device_get_softc(bus); + ios = &sc->rtsx_host.ios; + + if (bootverbose) + device_printf(bus, "rtsx_mmcbr_update_ios()\n"); + + /* if MMCBR_IVAR_BUS_WIDTH updated. */ + if (sc->rtsx_ios_bus_width < 0) { + sc->rtsx_ios_bus_width = ios->bus_width; + if ((error = rtsx_set_bus_width(sc, ios->bus_width))) + return (error); + } + + /* if MMCBR_IVAR_POWER_MODE updated. */ + if (sc->rtsx_ios_power_mode < 0) { + sc->rtsx_ios_power_mode = ios->power_mode; + switch (ios->power_mode) { + case power_off: + if ((error = rtsx_bus_power_off(sc))) + return (error); + break; + case power_up: + if ((error = rtsx_bus_power_on(sc))) + return (error); + break; + case power_on: + if ((error = rtsx_bus_power_on(sc))) + return (error); + break; + } + } + + sc->rtsx_double_clk = true; + sc->rtsx_vpclk = false; + + /* if MMCBR_IVAR_TIMING updated. */ + if (sc->rtsx_ios_timing < 0) { + sc->rtsx_ios_timing = ios->timing; + if ((error = rtsx_set_sd_timing(sc, ios->timing))) + return (error); + } + + /* if MMCBR_IVAR_CLOCK updated, must be after rtsx_set_sd_timing() */ + if (sc->rtsx_ios_clock < 0) { + sc->rtsx_ios_clock = ios->clock; + if ((error = rtsx_set_sd_clock(sc, ios->clock))) + return (error); + } + + return (0); +} + +/* + * Set output stage logic power voltage. + */ +static int +rtsx_mmcbr_switch_vccq(device_t bus, device_t child __unused) +{ + struct rtsx_softc *sc; + int vccq = 0; + int error; + + sc = device_get_softc(bus); + + switch (sc->rtsx_host.ios.vccq) { + case vccq_120: + vccq = 120; + break; + case vccq_180: + vccq = 180; + break; + case vccq_330: + vccq = 330; + break; + }; + /* It seems it is always vccq_330. */ + if (vccq == 330) { + switch (sc->rtsx_device_id) { + uint16_t val; + case RTSX_RTS5227: + if ((error = rtsx_write_phy(sc, 0x08, 0x4FE4))) + return (error); + if ((error = rtsx_rts5227_fill_driving(sc))) + return (error); + break; + case RTSX_RTS5209: + case RTSX_RTS5229: + RTSX_BITOP(sc, RTSX_SD30_CMD_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_MASK, sc->rtsx_sd30_drive_sel_3v3); + if ((error = rtsx_write_phy(sc, 0x08, 0x4FE4))) + return (error); + break; + case RTSX_RTS522A: + if ((error = rtsx_write_phy(sc, 0x08, 0x57E4))) + return (error); + if ((error = rtsx_rts5227_fill_driving(sc))) + return (error); + break; + case RTSX_RTS525A: + RTSX_BITOP(sc, RTSX_LDO_CONFIG2, RTSX_LDO_D3318_MASK, RTSX_LDO_D3318_33V); + RTSX_BITOP(sc, RTSX_SD_PAD_CTL, RTSX_SD_IO_USING_1V8, 0); + if ((error = rtsx_rts5249_fill_driving(sc))) + return (error); + break; + case RTSX_RTS5249: + if ((error = rtsx_read_phy(sc, RTSX_PHY_TUNE, &val))) + return (error); + if ((error = rtsx_write_phy(sc, RTSX_PHY_TUNE, + (val & RTSX_PHY_TUNE_VOLTAGE_MASK) | RTSX_PHY_TUNE_VOLTAGE_3V3))) + return (error); + if ((error = rtsx_rts5249_fill_driving(sc))) + return (error); + break; + case RTSX_RTL8402: + RTSX_BITOP(sc, RTSX_SD30_CMD_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_MASK, sc->rtsx_sd30_drive_sel_3v3); + RTSX_BITOP(sc, RTSX_LDO_CTL, + (RTSX_BPP_ASIC_MASK << RTSX_BPP_SHIFT_8402) | RTSX_BPP_PAD_MASK, + (RTSX_BPP_ASIC_3V3 << RTSX_BPP_SHIFT_8402) | RTSX_BPP_PAD_3V3); + break; + case RTSX_RTL8411: + case RTSX_RTL8411B: + RTSX_BITOP(sc, RTSX_SD30_CMD_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_MASK, sc->rtsx_sd30_drive_sel_3v3); + RTSX_BITOP(sc, RTSX_LDO_CTL, + (RTSX_BPP_ASIC_MASK << RTSX_BPP_SHIFT_8411) | RTSX_BPP_PAD_MASK, + (RTSX_BPP_ASIC_3V3 << RTSX_BPP_SHIFT_8411) | RTSX_BPP_PAD_3V3); + break; + } + DELAY(300); + } + + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_mmcbr_switch_vccq(%d)\n", vccq); + + return (0); +} + +/* + * Tune card if bus_timing_uhs_sdr50. + */ +static int +rtsx_mmcbr_tune(device_t bus, device_t child __unused, bool hs400) +{ + struct rtsx_softc *sc; + uint32_t raw_phase_map[RTSX_RX_TUNING_CNT] = {0}; + uint32_t phase_map; + uint8_t final_phase; + int i; + + sc = device_get_softc(bus); + + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_mmcbr_tune() - hs400 is %s\n", + (hs400) ? "true" : "false"); + + if (sc->rtsx_ios_timing != bus_timing_uhs_sdr50) + return (0); + + sc->rtsx_tuning_mode = true; + + switch (sc->rtsx_device_id) { + case RTSX_RTS5209: + case RTSX_RTS5227: + rtsx_sd_change_tx_phase(sc, 27); + break; + case RTSX_RTS522A: + rtsx_sd_change_tx_phase(sc, 20); + break; + case RTSX_RTS5229: + rtsx_sd_change_tx_phase(sc, 27); + break; + case RTSX_RTS525A: + case RTSX_RTS5249: + rtsx_sd_change_tx_phase(sc, 29); + break; + case RTSX_RTL8402: + case RTSX_RTL8411: + case RTSX_RTL8411B: + rtsx_sd_change_tx_phase(sc, 7); + break; + } + + /* trying rx tuning for bus_timing_uhs_sdr50. */ + for (i = 0; i < RTSX_RX_TUNING_CNT; i++) { + rtsx_sd_tuning_rx_phase(sc, &(raw_phase_map[i])); + if (raw_phase_map[i] == 0) + break; + } + + phase_map = 0xffffffff; + for (i = 0; i < RTSX_RX_TUNING_CNT; i++) { + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_mmcbr_tune() - RX raw_phase_map[%d]: 0x%08x\n", + i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + if (bootverbose || sc->rtsx_debug) + device_printf(sc->rtsx_dev, "rtsx_mmcbr_tune() - RX phase_map: 0x%08x\n", phase_map); + + if (phase_map) { + final_phase = rtsx_sd_search_final_rx_phase(sc, phase_map); + if (final_phase != 0xff) { + if (sc->rtsx_debug == 1) { + sc->rtsx_debug = 2; + rtsx_sd_change_rx_phase(sc, final_phase); + sc->rtsx_debug = 1; + } else { + rtsx_sd_change_rx_phase(sc, final_phase); + } + } + } + + sc->rtsx_tuning_mode = false; + + return (0); +} + +static int +rtsx_mmcbr_retune(device_t bus, device_t child __unused, bool reset __unused) +{ + struct rtsx_softc *sc; + + sc = device_get_softc(bus); + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_mmcbr_retune()\n"); + + return (0); +} + +static int +rtsx_mmcbr_request(device_t bus, device_t child __unused, struct mmc_request *req) +{ + struct rtsx_softc *sc; + struct mmc_command *cmd; + int error; + + sc = device_get_softc(bus); + + RTSX_LOCK(sc); + if (sc->rtsx_req != NULL) { + RTSX_UNLOCK(sc); + return (EBUSY); + } + sc->rtsx_req = req; + cmd = req->cmd; + cmd->error = error = MMC_ERR_NONE; + sc->rtsx_intr_status = 0; + sc->rtsx_intr_trans_ok = NULL; + sc->rtsx_intr_trans_ko = rtsx_req_done; + + if (bootverbose) + device_printf(sc->rtsx_dev, "rtsx_mmcbr_request(CMD%u arg %#x, flags %#x, dlen %u, dflags %#x)\n", + cmd->opcode, cmd->arg, cmd->flags, + cmd->data != NULL ? (unsigned int)cmd->data->len : 0, + cmd->data != NULL ? cmd->data->flags : 0); + + /* Check if card present. */ + if (!ISSET(sc->rtsx_flags, RTSX_F_CARD_PRESENT)) { + cmd->error = error = MMC_ERR_FAILED; + goto end; + } + + /* Refuse SDIO probe if the chip doesn't support SDIO. */ + if (cmd->opcode == IO_SEND_OP_COND && + !ISSET(sc->rtsx_flags, RTSX_F_SDIO_SUPPORT)) { + cmd->error = error = MMC_ERR_INVALID; + goto end; + } + + /* Return MMC_ERR_TIMEOUT for SD_IO_RW_DIRECT and IO_SEND_OP_COND. */ + if (cmd->opcode == SD_IO_RW_DIRECT || cmd->opcode == IO_SEND_OP_COND) { + cmd->error = error = MMC_ERR_TIMEOUT; + goto end; + } + + /* Select SD card. */ + RTSX_BITOP(sc, RTSX_CARD_SELECT, 0x07, RTSX_SD_MOD_SEL); + RTSX_BITOP(sc, RTSX_CARD_SHARE_MODE, RTSX_CARD_SHARE_MASK, RTSX_CARD_SHARE_48_SD); + + if (cmd->data == NULL) { + DELAY(200); + error = rtsx_send_req(sc, cmd); + } else if (cmd->data->len <= 512) { + error = rtsx_xfer_short(sc, cmd); + } else { + error = rtsx_xfer(sc, cmd); + } + end: + if (error == MMC_ERR_NONE) { + callout_reset(&sc->rtsx_timeout_callout, sc->rtsx_timeout * hz, rtsx_timeout, sc); + } else { + rtsx_req_done(sc); + } + RTSX_UNLOCK(sc); + + return (error); +} + +static int +rtsx_mmcbr_get_ro(device_t bus, device_t child __unused) +{ + struct rtsx_softc *sc; + + sc = device_get_softc(bus); + + if (sc->rtsx_inversion == 0) + return (sc->rtsx_read_only); + else + return !(sc->rtsx_read_only); +} + +static int +rtsx_mmcbr_acquire_host(device_t bus, device_t child __unused) +{ + struct rtsx_softc *sc; + + if (bootverbose) + device_printf(bus, "rtsx_mmcbr_acquire_host()\n"); + + sc = device_get_softc(bus); + RTSX_LOCK(sc); + while (sc->rtsx_bus_busy) + msleep(&sc->rtsx_bus_busy, &sc->rtsx_mtx, 0, "rtsxah", 0); + sc->rtsx_bus_busy++; + RTSX_UNLOCK(sc); + + return (0); +} + +static int +rtsx_mmcbr_release_host(device_t bus, device_t child __unused) +{ + struct rtsx_softc *sc; + + if (bootverbose) + device_printf(bus, "rtsx_mmcbr_release_host()\n"); + + sc = device_get_softc(bus); + RTSX_LOCK(sc); + sc->rtsx_bus_busy--; + RTSX_UNLOCK(sc); + wakeup(&sc->rtsx_bus_busy); + + return (0); +} + +/* + * + * PCI Support Functions + * + */ + +/* + * Compare the device ID (chip) of this device against the IDs that this driver + * supports. If there is a match, set the description and return success. + */ +static int +rtsx_probe(device_t dev) +{ + struct rtsx_softc *sc; + uint16_t vendor_id; + uint16_t device_id; + int i; + int result; + + vendor_id = pci_get_vendor(dev); + device_id = pci_get_device(dev); + + result = ENXIO; + for (i = 0; rtsx_devices[i].vendor_id != 0; i++) { + if (rtsx_devices[i].vendor_id == vendor_id && + rtsx_devices[i].device_id == device_id) { + device_set_desc(dev, rtsx_devices[i].desc); + sc = device_get_softc(dev); + sc->rtsx_device_id = device_id; + result = BUS_PROBE_DEFAULT; + break; + } + } + + return (result); +} + +/* + * Attach function is only called if the probe is successful. + */ +static int +rtsx_attach(device_t dev) +{ + struct rtsx_softc *sc = device_get_softc(dev); + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *tree; + int msi_count = 1; + uint32_t sdio_cfg; + int error; + + if (bootverbose) + device_printf(dev, "Attach - Vendor ID: 0x%x - Device ID: 0x%x\n", + pci_get_vendor(dev), pci_get_device(dev)); + + sc->rtsx_dev = dev; + sc->rtsx_timeout = 10; + sc->rtsx_read_only = 0; +#ifdef RTSX_INVERSION + sc->rtsx_inversion = 1; +#else + sc->rtsx_inversion = 0; +#endif /* RTSX_INVERSION */ + sc->rtsx_force_timing = 0; + sc->rtsx_debug = 0; + sc->rtsx_read_count = 0; + sc->rtsx_write_count = 0; + + RTSX_LOCK_INIT(sc); + + ctx = device_get_sysctl_ctx(dev); + tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); + SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "req_timeout", CTLFLAG_RW, + &sc->rtsx_timeout, 0, "Request timeout in seconds"); + SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "read_only", CTLFLAG_RD, + &sc->rtsx_read_only, 0, "Card is write protected"); + SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "inversion", CTLFLAG_RW, + &sc->rtsx_inversion, 0, "Inversion of card detection and read only status"); + SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "force_timing", CTLFLAG_RW, + &sc->rtsx_force_timing, 0, "Force bus_timing_uhs_sdr50"); + SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "debug", CTLFLAG_RW, + &sc->rtsx_debug, 0, "Debugging flag"); + SYSCTL_ADD_U64(ctx, tree, OID_AUTO, "read_count", CTLFLAG_RD, + &sc->rtsx_read_count, 0, "Count of read operations"); + SYSCTL_ADD_U64(ctx, tree, OID_AUTO, "write_count", CTLFLAG_RD, + &sc->rtsx_write_count, 0, "Count of write operations"); + + /* Allocate IRQ. */ + sc->rtsx_irq_res_id = 0; + if (pci_alloc_msi(dev, &msi_count) == 0) + sc->rtsx_irq_res_id = 1; + sc->rtsx_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rtsx_irq_res_id, + RF_ACTIVE | (sc->rtsx_irq_res_id != 0 ? 0 : RF_SHAREABLE)); + if (sc->rtsx_irq_res == NULL) { + device_printf(dev, "Can't allocate IRQ resources for %d\n", sc->rtsx_irq_res_id); + pci_release_msi(dev); + return (ENXIO); + } + + callout_init_mtx(&sc->rtsx_timeout_callout, &sc->rtsx_mtx, 0); + + /* Allocate memory resource. */ + if (sc->rtsx_device_id == RTSX_RTS525A) + sc->rtsx_res_id = PCIR_BAR(1); + else + sc->rtsx_res_id = PCIR_BAR(0); + sc->rtsx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rtsx_res_id, RF_ACTIVE); + if (sc->rtsx_res == NULL) { + device_printf(dev, "Can't allocate memory resource for %d\n", sc->rtsx_res_id); + goto destroy_rtsx_irq_res; + } + + if (bootverbose) + device_printf(dev, "rtsx_irq_res_id: %d, rtsx_res_id: %d\n", + sc->rtsx_irq_res_id, sc->rtsx_res_id); + + sc->rtsx_btag = rman_get_bustag(sc->rtsx_res); + sc->rtsx_bhandle = rman_get_bushandle(sc->rtsx_res); + + /* Activate the interrupt. */ + error = bus_setup_intr(dev, sc->rtsx_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, rtsx_intr, sc, &sc->rtsx_irq_cookie); + if (error) { + device_printf(dev, "Can't set up irq [0x%x]!\n", error); + goto destroy_rtsx_res; + } + pci_enable_busmaster(dev); + + if (rtsx_read_cfg(sc, 0, RTSX_SDIOCFG_REG, &sdio_cfg) == 0) { + if ((sdio_cfg & RTSX_SDIOCFG_SDIO_ONLY) || + (sdio_cfg & RTSX_SDIOCFG_HAVE_SDIO)) + sc->rtsx_flags |= RTSX_F_SDIO_SUPPORT; + } + + /* Allocate two DMA buffers: a command buffer and a data buffer. */ + error = rtsx_dma_alloc(sc); + if (error) { + goto destroy_rtsx_irq; + } + + /* From dwmmc.c. */ + TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->rtsx_card_insert_task, 0, + rtsx_card_task, sc); + TASK_INIT(&sc->rtsx_card_remove_task, 0, rtsx_card_task, sc); + +#ifdef MMCCAM + sc->rtsx_ccb = NULL; + sc->rtsx_cam_status = 0; + SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "cam_status", CTLFLAG_RD, + &sc->rtsx_cam_status, 0, "driver cam card present"); + if ((sc->rtsx_devq = cam_simq_alloc(1)) == NULL) { + device_printf(dev, "Error during CAM queue allocation\n"); + goto destroy_rtsx_irq; + } + mtx_init(&sc->rtsx_sim_mtx, "rtsxsim", NULL, MTX_DEF); + sc->rtsx_sim = cam_sim_alloc(rtsx_cam_action, rtsx_cam_poll, + "rtsx", sc, device_get_unit(dev), + &sc->rtsx_sim_mtx, 1, 1, sc->rtsx_devq); + if (sc->rtsx_sim == NULL) { + device_printf(dev, "Can't allocate CAM SIM\n"); + goto destroy_rtsx_irq; + } + mtx_lock(&sc->rtsx_sim_mtx); + if (xpt_bus_register(sc->rtsx_sim, dev, 0) != 0) { + device_printf(dev, "Can't register SCSI pass-through bus\n"); + mtx_unlock(&sc->rtsx_sim_mtx); + goto destroy_rtsx_irq; + } + mtx_unlock(&sc->rtsx_sim_mtx); +#endif /* MMCCAM */ + + /* Initialize device. */ + if (rtsx_init(sc)) { + device_printf(dev, "Error during rtsx_init()\n"); + goto destroy_rtsx_irq; + } + + /* + * Schedule a card detection as we won't get an interrupt + * if the card is inserted when we attach + */ + DELAY(500); + if (rtsx_is_card_present(sc)) + device_printf(sc->rtsx_dev, "Card present\n"); + else + device_printf(sc->rtsx_dev, "Card absent\n"); + rtsx_card_task(sc, 0); + + if (bootverbose) + device_printf(dev, "Device attached\n"); + + return (0); + + destroy_rtsx_irq: + bus_teardown_intr(dev, sc->rtsx_irq_res, sc->rtsx_irq_cookie); + destroy_rtsx_res: + bus_release_resource(dev, SYS_RES_MEMORY, sc->rtsx_res_id, + sc->rtsx_res); + destroy_rtsx_irq_res: + callout_drain(&sc->rtsx_timeout_callout); + bus_release_resource(dev, SYS_RES_IRQ, sc->rtsx_irq_res_id, + sc->rtsx_irq_res); + pci_release_msi(dev); + RTSX_LOCK_DESTROY(sc); +#ifdef MMCCAM + if (sc->rtsx_sim != NULL) { + mtx_lock(&sc->rtsx_sim_mtx); + xpt_bus_deregister(cam_sim_path(sc->rtsx_sim)); + cam_sim_free(sc->rtsx_sim, FALSE); + mtx_unlock(&sc->rtsx_sim_mtx); + } + if (sc->rtsx_devq != NULL) { + mtx_destroy(&sc->rtsx_sim_mtx); + cam_simq_free(sc->rtsx_devq); + } +#endif /* MMCCAM */ + + return (ENXIO); +} + +static int +rtsx_detach(device_t dev) +{ + struct rtsx_softc *sc = device_get_softc(dev); + int error; + + if (bootverbose) + device_printf(dev, "Detach - Vendor ID: 0x%x - Device ID: 0x%x\n", + pci_get_vendor(dev), pci_get_device(dev)); + + /* Disable interrupts. */ + sc->rtsx_intr_enabled = 0; + WRITE4(sc, RTSX_BIER, sc->rtsx_intr_enabled); + + /* Stop device. */ + error = device_delete_children(sc->rtsx_dev); + sc->rtsx_mmc_dev = NULL; + if (error) + return (error); + + taskqueue_drain_timeout(taskqueue_swi_giant, &sc->rtsx_card_insert_task); + taskqueue_drain(taskqueue_swi_giant, &sc->rtsx_card_remove_task); + + /* Teardown the state in our softc created in our attach routine. */ + rtsx_dma_free(sc); + if (sc->rtsx_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rtsx_res_id, + sc->rtsx_res); + if (sc->rtsx_irq_cookie != NULL) + bus_teardown_intr(dev, sc->rtsx_irq_res, sc->rtsx_irq_cookie); + if (sc->rtsx_irq_res != NULL) { + callout_drain(&sc->rtsx_timeout_callout); + bus_release_resource(dev, SYS_RES_IRQ, sc->rtsx_irq_res_id, + sc->rtsx_irq_res); + pci_release_msi(dev); + } + RTSX_LOCK_DESTROY(sc); +#ifdef MMCCAM + if (sc->rtsx_sim != NULL) { + mtx_lock(&sc->rtsx_sim_mtx); + xpt_bus_deregister(cam_sim_path(sc->rtsx_sim)); + cam_sim_free(sc->rtsx_sim, FALSE); + mtx_unlock(&sc->rtsx_sim_mtx); + } + if (sc->rtsx_devq != NULL) { + mtx_destroy(&sc->rtsx_sim_mtx); + cam_simq_free(sc->rtsx_devq); + } +#endif /* MMCCAM */ + + return (0); +} + +static int +rtsx_shutdown(device_t dev) +{ + + if (bootverbose) + device_printf(dev, "Shutdown\n"); + + rtsx_detach(dev); + + return (0); +} + +/* + * Device suspend routine. + */ +static int +rtsx_suspend(device_t dev) +{ + struct rtsx_softc *sc = device_get_softc(dev); + + device_printf(dev, "Suspend\n"); + +#ifdef MMCCAM + if (sc->rtsx_ccb != NULL) { + device_printf(dev, "Request in progress: CMD%u, rtsr_intr_status: 0x%08x\n", + sc->rtsx_ccb->mmcio.cmd.opcode, sc->rtsx_intr_status); + } +#else + if (sc->rtsx_req != NULL) { + device_printf(dev, "Request in progress: CMD%u, rtsr_intr_status: 0x%08x\n", + sc->rtsx_req->cmd->opcode, sc->rtsx_intr_status); + } +#endif /* MMCCAM */ + + bus_generic_suspend(dev); + + return (0); +} + +/* + * Device resume routine. + */ +static int +rtsx_resume(device_t dev) +{ + + device_printf(dev, "Resume\n"); + + bus_generic_resume(dev); + + return (0); +} + +static device_method_t rtsx_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtsx_probe), + DEVMETHOD(device_attach, rtsx_attach), + DEVMETHOD(device_detach, rtsx_detach), + DEVMETHOD(device_shutdown, rtsx_shutdown), + DEVMETHOD(device_suspend, rtsx_suspend), + DEVMETHOD(device_resume, rtsx_resume), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, rtsx_read_ivar), + DEVMETHOD(bus_write_ivar, rtsx_write_ivar), + + /* MMC bridge interface */ + DEVMETHOD(mmcbr_update_ios, rtsx_mmcbr_update_ios), + DEVMETHOD(mmcbr_switch_vccq, rtsx_mmcbr_switch_vccq), + DEVMETHOD(mmcbr_tune, rtsx_mmcbr_tune), + DEVMETHOD(mmcbr_retune, rtsx_mmcbr_retune), + DEVMETHOD(mmcbr_request, rtsx_mmcbr_request), + DEVMETHOD(mmcbr_get_ro, rtsx_mmcbr_get_ro), + DEVMETHOD(mmcbr_acquire_host, rtsx_mmcbr_acquire_host), + DEVMETHOD(mmcbr_release_host, rtsx_mmcbr_release_host), + + DEVMETHOD_END +}; + +static devclass_t rtsx_devclass; + +DEFINE_CLASS_0(rtsx, rtsx_driver, rtsx_methods, sizeof(struct rtsx_softc)); +DRIVER_MODULE(rtsx, pci, rtsx_driver, rtsx_devclass, NULL, NULL); +#ifndef MMCCAM +MMC_DECLARE_BRIDGE(rtsx); +#endif /* MMCCAM */ Index: sys/dev/rtsx/rtsxreg.h =================================================================== --- /dev/null +++ sys/dev/rtsx/rtsxreg.h @@ -0,0 +1,778 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2012 Stefan Sperling + * Copyright (c) 2020 Henri Hennebert + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $$FreeBSD$ + */ + +#ifndef _RTSXREG_H_ +#define _RTSXREG_H_ + +#if __FreeBSD__ < 12 +#define IO_SEND_OP_COND 5 +#endif + +/* Host command buffer control register. */ +#define RTSX_HCBAR 0x00 +#define RTSX_HCBCTLR 0x04 +#define RTSX_START_CMD (1U << 31) +#define RTSX_HW_AUTO_RSP (1U << 30) +#define RTSX_STOP_CMD (1U << 28) + +/* Host data buffer control register. */ +#define RTSX_HDBAR 0x08 +#define RTSX_HDBCTLR 0x0C +#define RTSX_TRIG_DMA (1U << 31) +#define RTSX_DMA_READ (1U << 29) +#define RTSX_STOP_DMA (1U << 28) +#define RTSX_ADMA_MODE (2U << 26) + +/* Interrupt pending register. */ +#define RTSX_BIPR 0x14 +#define RTSX_CMD_DONE_INT (1U << 31) +#define RTSX_DATA_DONE_INT (1U << 30) +#define RTSX_TRANS_OK_INT (1U << 29) +#define RTSX_TRANS_FAIL_INT (1U << 28) +#define RTSX_XD_INT (1U << 27) +#define RTSX_MS_INT (1U << 26) +#define RTSX_SD_INT (1U << 25) +#define RTSX_DELINK_INT (1U << 24) +#define RTSX_SD_WRITE_PROTECT (1U << 19) +#define RTSX_XD_EXIST (1U << 18) +#define RTSX_MS_EXIST (1U << 17) +#define RTSX_SD_EXIST (1U << 16) +#define RTSX_CARD_EXIST (RTSX_XD_EXIST|RTSX_MS_EXIST|RTSX_SD_EXIST) +#define RTSX_CARD_INT (RTSX_XD_INT|RTSX_MS_INT|RTSX_SD_INT) + +/* Chip register access. */ +#define RTSX_HAIMR 0x10 +#define RTSX_HAIMR_WRITE 0x40000000 +#define RTSX_HAIMR_BUSY 0x80000000 + +/* Interrupt enable register. */ +#define RTSX_BIER 0x18 +#define RTSX_CMD_DONE_INT_EN (1U << 31) +#define RTSX_DATA_DONE_INT_EN (1U << 30) +#define RTSX_TRANS_OK_INT_EN (1U << 29) +#define RTSX_TRANS_FAIL_INT_EN (1U << 28) +#define RTSX_XD_INT_EN (1U << 27) +#define RTSX_MS_INT_EN (1U << 26) +#define RTSX_SD_INT_EN (1U << 25) +#define RTSX_GPIO0_INT_EN (1U << 24) +#define RTSX_MS_OC_INT_EN (1U << 23) +#define RTSX_SD_OC_INT_EN (1U << 22) + +/* Power on/off. */ +#define RTSX_FPDCTL 0xFC00 +#define RTSX_SSC_POWER_DOWN 0x01 +#define RTSX_SD_OC_POWER_DOWN 0x02 +#define RTSX_MS_OC_POWER_DOWN 0x04 +#define RTSX_ALL_POWER_DOWN 0x07 +#define RTSX_OC_POWER_DOWN 0x06 + +/* Card power control register. */ +#define RTSX_CARD_PWR_CTL 0xFD50 +#define RTSX_SD_PWR_ON 0x00 +#define RTSX_SD_PARTIAL_PWR_ON 0x01 +#define RTSX_SD_PWR_OFF 0x03 +#define RTSX_SD_PWR_MASK 0x03 + +#define RTSX_PMOS_STRG_MASK 0x10 +#define RTSX_PMOS_STRG_400mA 0x00 +#define RTSX_PMOS_STRG_800mA 0x10 + +#define RTSX_BPP_POWER_MASK 0x0F +#define RTSX_BPP_POWER_OFF 0x0F +#define RTSX_BPP_POWER_5_PERCENT_ON 0x0E +#define RTSX_BPP_POWER_10_PERCENT_ON 0x0C +#define RTSX_BPP_POWER_15_PERCENT_ON 0x08 +#define RTSX_BPP_POWER_ON 0x00 + +#define RTSX_MS_PWR_OFF 0x0C +#define RTSX_MS_PWR_ON 0x00 +#define RTSX_MS_PARTIAL_PWR_ON 0x04 + +#define RTSX_RTL8411B_PACKAGE 0xFD51 +#define RTSX_RTL8411B_QFN48 0x02 + +#define RTSX_CARD_SHARE_MODE 0xFD52 +#define RTSX_CARD_SHARE_MASK 0x0F +#define RTSX_CARD_SHARE_48_XD 0x02 +#define RTSX_CARD_SHARE_48_SD 0x04 +#define RTSX_CARD_SHARE_48_MS 0x08 + +#define RTSX_CARD_DRIVE_SEL 0xFD53 +#define RTSX_MS_DRIVE_8mA (0x01 << 6) +#define RTSX_MMC_DRIVE_8mA (0x01 << 4) +#define RTSX_XD_DRIVE_8mA (0x01 << 2) +#define RTSX_GPIO_DRIVE_8mA 0x01 +#define RTSX_CARD_DRIVE_DEFAULT (RTSX_MS_DRIVE_8mA | RTSX_GPIO_DRIVE_8mA) +#define RTSX_RTS5209_CARD_DRIVE_DEFAULT (RTSX_MS_DRIVE_8mA | RTSX_MMC_DRIVE_8mA | \ + RTSX_XD_DRIVE_8mA | RTSX_GPIO_DRIVE_8mA) +#define RTSX_RTL8411_CARD_DRIVE_DEFAULT (RTSX_MS_DRIVE_8mA | RTSX_MMC_DRIVE_8mA | \ + RTSX_XD_DRIVE_8mA) + +#define RTSX_CARD_STOP 0xFD54 +#define RTSX_SPI_STOP 0x01 +#define RTSX_XD_STOP 0x02 +#define RTSX_SD_STOP 0x04 +#define RTSX_MS_STOP 0x08 +#define RTSX_SPI_CLR_ERR 0x10 +#define RTSX_XD_CLR_ERR 0x20 +#define RTSX_SD_CLR_ERR 0x40 +#define RTSX_MS_CLR_ERR 0x80 +#define RTSX_ALL_STOP 0x0F +#define RTSX_ALL_CLR_ERR 0xF0 + +#define RTSX_CARD_OE 0xFD55 +#define RTSX_XD_OUTPUT_EN 0x02 +#define RTSX_SD_OUTPUT_EN 0x04 +#define RTSX_MS_OUTPUT_EN 0x08 +#define RTSX_SPI_OUTPUT_EN 0x10 +#define RTSX_CARD_OUTPUT_EN (RTSX_XD_OUTPUT_EN|RTSX_SD_OUTPUT_EN|\ + RTSX_MS_OUTPUT_EN) + +#define RTSX_CARD_GPIO_DIR 0xFD57 +#define RTSX_CARD_GPIO 0xFD58 +#define RTSX_CARD_GPIO_LED_OFF 0x01 + +#define RTSX_SD30_CLK_DRIVE_SEL 0xFD5A +#define RTSX_DRIVER_TYPE_A 0x05 +#define RTSX_DRIVER_TYPE_B 0x03 +#define RTSX_DRIVER_TYPE_C 0x02 +#define RTSX_DRIVER_TYPE_D 0x01 + +#define RTSX_CARD_DATA_SOURCE 0xFD5B +#define RTSX_RING_BUFFER 0x00 +#define RTSX_PINGPONG_BUFFER 0x01 + +#define RTSX_CARD_SELECT 0xFD5C +#define RTSX_XD_MOD_SEL 0x01 +#define RTSX_SD_MOD_SEL 0x02 +#define RTSX_MS_MOD_SEL 0x03 +#define RTSX_SPI_MOD_SEL 0x04 + +#define RTSX_SD30_CMD_DRIVE_SEL 0xFD5E /* was 0xFE5E in OpenBSD */ +#define RTSX_CFG_DRIVER_TYPE_A 0x02 +#define RTSX_CFG_DRIVER_TYPE_B 0x03 +#define RTSX_CFG_DRIVER_TYPE_C 0x01 +#define RTSX_CFG_DRIVER_TYPE_D 0x00 +#define RTSX_SD30_DRIVE_SEL_MASK 0x07 + +#define RTSX_SD30_DAT_DRIVE_SEL 0xFD5F + +/* Card clock. */ +#define RTSX_CARD_CLK_EN 0xFD69 +#define RTSX_XD_CLK_EN 0x02 +#define RTSX_SD_CLK_EN 0x04 +#define RTSX_MS_CLK_EN 0x08 +#define RTSX_SPI_CLK_EN 0x10 +#define RTSX_CARD_CLK_EN_ALL (RTSX_XD_CLK_EN|RTSX_SD_CLK_EN|\ + RTSX_MS_CLK_EN|RTSX_SPI_CLK_EN) + +#define RTSX_SDIO_CTRL 0xFD6B +#define RTSX_SDIO_BUS_CTRL 0x01 +#define RTSX_SDIO_CD_CTRL 0x02 + +#define RTSX_CARD_PAD_CTL 0xFD73 +#define RTSX_CD_DISABLE_MASK 0x07 +#define RTSX_CD_AUTO_DISABLE 0x40 +#define RTSX_CD_ENABLE 0x00 + +/* Internal clock. */ +#define RTSX_CLK_CTL 0xFC02 +#define RTSX_CHANGE_CLK 0x01 +#define RTSX_CLK_LOW_FREQ 0x01 + +/* Internal clock divisor values. */ +#define RTSX_CLK_DIV 0xFC03 +#define RTSX_CLK_DIV_1 0x01 +#define RTSX_CLK_DIV_2 0x02 +#define RTSX_CLK_DIV_4 0x03 +#define RTSX_CLK_DIV_8 0x04 + +/* Internal clock selection. */ +#define RTSX_CLK_SEL 0xFC04 +#define RTSX_SSC_80 0 +#define RTSX_SSC_100 1 +#define RTSX_SSC_120 2 +#define RTSX_SSC_150 3 +#define RTSX_SSC_200 4 + +#define RTSX_SSC_DIV_N_0 0xFC0F + +#define RTSX_SSC_CTL1 0xFC11 +#define RTSX_RSTB 0x80 +#define RTSX_SSC_8X_EN 0x40 +#define RTSX_SSC_FIX_FRAC 0x20 +#define RTSX_SSC_SEL_1M 0x00 +#define RTSX_SSC_SEL_2M 0x08 +#define RTSX_SSC_SEL_2M 0x08 +#define RTSX_SSC_SEL_4M 0x10 +#define RTSX_SSC_SEL_8M 0x18 + +#define RTSX_SSC_CTL2 0xFC12 +#define RTSX_SSC_DEPTH_MASK 0x07 +#define RTSX_SSC_DEPTH_4M 0x01 +#define RTSX_SSC_DEPTH_2M 0x02 +#define RTSX_SSC_DEPTH_1M 0x03 +#define RTSX_SSC_DEPTH_500K 0x04 +#define RTSX_SSC_DEPTH_250K 0x05 + +/* RC oscillator, default is 2M */ +#define RTSX_RCCTL 0xFC14 +#define RTSX_RCCTL_F_400K 0x00 +#define RTSX_RCCTL_F_2M 0x01 + +/* RTS5229-only. */ +#define RTSX_OLT_LED_CTL 0xFC1E +#define RTSX_OLT_LED_PERIOD 0x02 +#define RTSX_OLT_LED_AUTOBLINK 0x08 + +#define RTSX_LDO_CTL 0xFC1E +#define RTSX_BPP_ASIC_3V3 0x07 +#define RTSX_BPP_ASIC_MASK 0x07 +#define RTSX_BPP_PAD_3V3 0x04 +#define RTSX_BPP_PAD_1V8 0x00 +#define RTSX_BPP_PAD_MASK 0x04 +#define RTSX_BPP_LDO_POWB 0x03 +#define RTSX_BPP_LDO_ON 0x00 +#define RTSX_BPP_LDO_SUSPEND 0x02 +#define RTSX_BPP_LDO_OFF 0x03 +#define RTSX_BPP_SHIFT_8402 5 +#define RTSX_BPP_SHIFT_8411 4 + +#define RTSX_GPIO_CTL 0xFC1F +#define RTSX_GPIO_LED_ON 0x02 + +#define RTSX_SD_VPCLK0_CTL 0xFC2A +#define RTSX_SD_VPCLK1_CTL 0xFC2B +#define RTSX_PHASE_SELECT_MASK 0x1F +#define RTSX_PHASE_NOT_RESET 0x40 + +/* Host controller commands. */ +#define RTSX_READ_REG_CMD 0 +#define RTSX_WRITE_REG_CMD 1 +#define RTSX_CHECK_REG_CMD 2 + +#define RTSX_OCPCTL 0xFC15 +#define RTSX_OCPSTAT 0xFC16 +#define RTSX_OCPGLITCH 0xFC17 +#define RTSX_OCPPARA1 0xFC18 +#define RTSX_OCPPARA2 0xFC19 + +/* FPGA */ +#define RTSX_FPGA_PULL_CTL 0xFC1D +#define RTSX_FPGA_MS_PULL_CTL_BIT 0x10 +#define RTSX_FPGA_SD_PULL_CTL_BIT 0x08 + +/* Clock source configuration register. */ +#define RTSX_CARD_CLK_SOURCE 0xFC2E +#define RTSX_CRC_FIX_CLK (0x00 << 0) +#define RTSX_CRC_VAR_CLK0 (0x01 << 0) +#define RTSX_CRC_VAR_CLK1 (0x02 << 0) +#define RTSX_SD30_FIX_CLK (0x00 << 2) +#define RTSX_SD30_VAR_CLK0 (0x01 << 2) +#define RTSX_SD30_VAR_CLK1 (0x02 << 2) +#define RTSX_SAMPLE_FIX_CLK (0x00 << 4) +#define RTSX_SAMPLE_VAR_CLK0 (0x01 << 4) +#define RTSX_SAMPLE_VAR_CLK1 (0x02 << 4) + + +/* ASIC */ +#define RTSX_CARD_PULL_CTL1 0xFD60 +#define RTSX_CARD_PULL_CTL2 0xFD61 +#define RTSX_CARD_PULL_CTL3 0xFD62 +#define RTSX_CARD_PULL_CTL4 0xFD63 +#define RTSX_CARD_PULL_CTL5 0xFD64 +#define RTSX_CARD_PULL_CTL6 0xFD65 + +#define RTSX_PULL_CTL_DISABLE12 0x55 +#define RTSX_PULL_CTL_DISABLE3 0xD5 +#define RTSX_PULL_CTL_DISABLE3_TYPE_C 0xE5 +#define RTSX_PULL_CTL_ENABLE12 0xAA +#define RTSX_PULL_CTL_ENABLE3 0xE9 +#define RTSX_PULL_CTL_ENABLE3_TYPE_C 0xD9 + +/* SD configuration register 1 (clock divider, bus mode and width). */ +#define RTSX_SD_CFG1 0xFDA0 +#define RTSX_CLK_DIVIDE_0 0x00 +#define RTSX_CLK_DIVIDE_128 0x80 +#define RTSX_CLK_DIVIDE_256 0xC0 +#define RTSX_CLK_DIVIDE_MASK 0xC0 +#define RTSX_SD20_MODE 0x00 +#define RTSX_SDDDR_MODE 0x04 +#define RTSX_SD30_MODE 0x08 +#define RTSX_SD_MODE_MASK 0x0C +#define RTSX_BUS_WIDTH_1 0x00 +#define RTSX_BUS_WIDTH_4 0x01 +#define RTSX_BUS_WIDTH_8 0x02 +#define RTSX_SD_ASYNC_FIFO_NOT_RST 0x10 +#define RTSX_BUS_WIDTH_MASK 0x03 + +/* SD configuration register 2 (SD command response flags). */ +#define RTSX_SD_CFG2 0xFDA1 +#define RTSX_SD_CALCULATE_CRC7 0x00 +#define RTSX_SD_NO_CALCULATE_CRC7 0x80 +#define RTSX_SD_CHECK_CRC16 0x00 +#define RTSX_SD_NO_CHECK_CRC16 0x40 +#define RTSX_SD_NO_CHECK_WAIT_CRC_TO 0x20 +#define RTSX_SD_WAIT_BUSY_END 0x08 +#define RTSX_SD_NO_WAIT_BUSY_END 0x00 +#define RTSX_SD_CHECK_CRC7 0x00 +#define RTSX_SD_NO_CHECK_CRC7 0x04 +#define RTSX_SD_RSP_LEN_0 0x00 +#define RTSX_SD_RSP_LEN_6 0x01 +#define RTSX_SD_RSP_LEN_17 0x02 +/* SD command response types. */ +#define RTSX_SD_RSP_TYPE_R0 0x04 +#define RTSX_SD_RSP_TYPE_R1 0x01 +#define RTSX_SD_RSP_TYPE_R1B 0x09 +#define RTSX_SD_RSP_TYPE_R2 0x02 +#define RTSX_SD_RSP_TYPE_R3 0x05 +#define RTSX_SD_RSP_TYPE_R4 0x05 +#define RTSX_SD_RSP_TYPE_R5 0x01 +#define RTSX_SD_RSP_TYPE_R6 0x01 +#define RTSX_SD_RSP_TYPE_R7 0x01 + +#define RTSX_SD_CFG3 0xFDA2 +#define RTSX_SD_RSP_80CLK_TIMEOUT_EN 0x01 + +#define RTSX_SD_STAT1 0xFDA3 +#define RTSX_SD_CRC7_ERR 0x80 +#define RTSX_SD_CRC16_ERR 0x40 +#define RTSX_SD_CRC_WRITE_ERR 0x20 +#define RTSX_SD_CRC_WRITE_ERR_MASK 0x1C +#define RTSX_GET_CRC_TIME_OUT 0x02 +#define RTSX_SD_TUNING_COMPARE_ERR 0x01 + +#define RTSX_SD_STAT2 0xFDA4 +#define RTSX_SD_RSP_80CLK_TIMEOUT 0x01 + +#define RTSX_SD_CRC_ERR (RTSX_SD_CRC7_ERR|RTSX_SD_CRC16_ERR|RTSX_SD_CRC_WRITE_ERR) + +/* SD bus status register. */ +#define RTSX_SD_BUS_STAT 0xFDA5 +#define RTSX_SD_CLK_TOGGLE_EN 0x80 +#define RTSX_SD_CLK_FORCE_STOP 0x40 +#define RTSX_SD_DAT3_STATUS 0x10 +#define RTSX_SD_DAT2_STATUS 0x08 +#define RTSX_SD_DAT1_STATUS 0x04 +#define RTSX_SD_DAT0_STATUS 0x02 +#define RTSX_SD_CMD_STATUS 0x01 + +#define RTSX_SD_PAD_CTL 0xFDA6 +#define RTSX_SD_IO_USING_1V8 0x80 + +/* Sample point control register. */ +#define RTSX_SD_SAMPLE_POINT_CTL 0xFDA7 +#define RTSX_DDR_FIX_RX_DAT 0x00 +#define RTSX_DDR_VAR_RX_DAT 0x80 +#define RTSX_DDR_FIX_RX_DAT_EDGE 0x00 +#define RTSX_DDR_FIX_RX_DAT_14_DELAY 0x40 +#define RTSX_DDR_FIX_RX_CMD 0x00 +#define RTSX_DDR_VAR_RX_CMD 0x20 +#define RTSX_DDR_FIX_RX_CMD_POS_EDGE 0x00 +#define RTSX_DDR_FIX_RX_CMD_14_DELAY 0x10 +#define RTSX_SD20_RX_POS_EDGE 0x00 +#define RTSX_SD20_RX_14_DELAY 0x08 +#define RTSX_SD20_RX_SEL_MASK 0x08 + +#define RTSX_SD_PUSH_POINT_CTL 0xFDA8 +#define RTSX_SD20_TX_NEG_EDGE 0x00 +#define RTSX_SD20_TX_SEL_MASK 0x10 +#define RTSX_SD20_TX_14_AHEAD 0x10 + +#define RTSX_SD_CMD0 0xFDA9 +#define RTSX_SD_CMD_START 0x40 +#define RTSX_SD_CMD1 0xFDAA +#define RTSX_SD_CMD2 0xFDAB +#define RTSX_SD_CMD3 0xFDAC +#define RTSX_SD_CMD4 0xFDAD + +#define RTSX_SD_CMD5 0xFDAE +#define RTSX_SD_BYTE_CNT_L 0xFDAF +#define RTSX_SD_BYTE_CNT_H 0xFDB0 +#define RTSX_SD_BLOCK_CNT_L 0xFDB1 +#define RTSX_SD_BLOCK_CNT_H 0xFDB2 + +/* + * Transfer modes. + */ +#define RTSX_SD_TRANSFER 0xFDB3 + +/* Write one or two bytes from SD_CMD2 and SD_CMD3 to the card. */ +#define RTSX_TM_NORMAL_WRITE 0x00 + +/* Write (SD_BYTE_CNT * SD_BLOCK_COUNTS) bytes from ring buffer to card. */ +#define RTSX_TM_AUTO_WRITE3 0x01 + +/* Like AUTO_WRITE3, plus automatically send CMD 12 when done. + * The response to CMD 12 is written to SD_CMD{0,1,2,3,4}. */ +#define RTSX_TM_AUTO_WRITE4 0x02 + +/* Read (SD_BYTE_CNT * SD_BLOCK_CNT) bytes from card into ring buffer. */ +#define RTSX_TM_AUTO_READ3 0x05 + +/* Like AUTO_READ3, plus automatically send CMD 12 when done. + * The response to CMD 12 is written to SD_CMD{0,1,2,3,4}. */ +#define RTSX_TM_AUTO_READ4 0x06 + +/* Send an SD command described in SD_CMD{0,1,2,3,4} to the card and put + * the response into SD_CMD{0,1,2,3,4}. Long responses (17 byte) are put + * into ping-pong buffer 2 instead. */ +#define RTSX_TM_CMD_RSP 0x08 + +/* Send write command, get response from the card, write data from ring + * buffer to card, and send CMD 12 when done. + * The response to CMD 12 is written to SD_CMD{0,1,2,3,4}. */ +#define RTSX_TM_AUTO_WRITE1 0x09 + +/* Like AUTO_WRITE1 except no CMD 12 is sent. */ +#define RTSX_TM_AUTO_WRITE2 0x0A + +/* Send read command, read up to 512 bytes (SD_BYTE_CNT * SD_BLOCK_CNT) + * from the card into the ring buffer or ping-pong buffer 2. */ +#define RTSX_TM_NORMAL_READ 0x0C + +/* Same as WRITE1, except data is read from the card to the ring buffer. */ +#define RTSX_TM_AUTO_READ1 0x0D + +/* Same as WRITE2, except data is read from the card to the ring buffer. */ +#define RTSX_TM_AUTO_READ2 0x0E + +/* Send CMD 19 and receive response and tuning pattern from card and + * report the result. */ +#define RTSX_TM_AUTO_TUNING 0x0F + +/* transfer control */ +#define RTSX_SD_TRANSFER_START 0x80 +#define RTSX_SD_TRANSFER_END 0x40 +#define RTSX_SD_STAT_IDLE 0x20 +#define RTSX_SD_TRANSFER_ERR 0x10 + +#define RTSX_SD_CMD_STATE 0xFDB5 +#define RTSX_SD_CMD_IDLE 0x80 + +#define RTSX_SD_DATA_STATE 0xFDB6 +#define RTSX_SD_DATA_IDLE 0x80 + +/* ping-pong buffer 2 */ +#define RTSX_PPBUF_BASE2 0xFA00 +#define RTSX_PPBUF_SIZE 256 + +#define RTSX_SUPPORTED_VOLTAGE (MMC_OCR_300_310|MMC_OCR_310_320|\ + MMC_OCR_320_330|MMC_OCR_330_340) + +#define RTSX_CFG_PCI 0x1C +#define RTSX_CFG_ASIC 0x10 + +#define RTSX_IRQEN0 0xFE20 +#define RTSX_LINK_DOWN_INT_EN 0x10 +#define RTSX_LINK_READY_INT_EN 0x20 +#define RTSX_SUSPEND_INT_EN 0x40 +#define RTSX_DMA_DONE_INT_EN 0x80 + +#define RTSX_IRQSTAT0 0xFE21 +#define RTSX_LINK_DOWN_INT 0x10 +#define RTSX_LINK_READY_INT 0x20 +#define RTSX_SUSPEND_INT 0x40 +#define RTSX_DMA_DONE_INT 0x80 + +#define RTSX_DMATC0 0xFE28 +#define RTSX_DMATC1 0xFE29 +#define RTSX_DMATC2 0xFE2A +#define RTSX_DMATC3 0xFE2B + +#define RTSX_DMACTL 0xFE2C +#define RTSX_DMA_EN 0x01 +#define RTSX_DMA_DIR 0x02 +#define RTSX_DMA_DIR_TO_CARD 0x00 +#define RTSX_DMA_DIR_FROM_CARD 0x02 +#define RTSX_DMA_BUSY 0x04 +#define RTSX_DMA_RST 0x80 +#define RTSX_DMA_128 (0 << 4) +#define RTSX_DMA_256 (1 << 4) +#define RTSX_DMA_512 (2 << 4) +#define RTSX_DMA_1024 (3 << 4) +#define RTSX_DMA_PACK_SIZE_MASK 0x30 + +#define RTSX_RBCTL 0xFE34 +#define RTSX_RB_FLUSH 0x80 + +#define RTSX_CFGADDR0 0xFE35 +#define RTSX_CFGADDR1 0xFE36 +#define RTSX_CFGDATA0 0xFE37 +#define RTSX_CFGDATA1 0xFE38 +#define RTSX_CFGDATA2 0xFE39 +#define RTSX_CFGDATA3 0xFE3A +#define RTSX_CFGRWCTL 0xFE3B +#define RTSX_CFG_WRITE_DATA0 0x01 +#define RTSX_CFG_WRITE_DATA1 0x02 +#define RTSX_CFG_WRITE_DATA2 0x04 +#define RTSX_CFG_WRITE_DATA3 0x08 +#define RTSX_CFG_BUSY 0x80 + +#define RTSX_LTR_CTL 0xFE4A + +#define RTSX_OBFF_CFG 0xFE4C +#define RTSX_OBFF_EN_MASK 0x03 +#define RTSX_OBFF_DISABLE 0x00 +#define RTSX_OBFF_ENABLE 0x03 + +#define RTSX_SDIOCFG_REG 0x724 +#define RTSX_SDIOCFG_NO_BYPASS_SDIO 0x02 +#define RTSX_SDIOCFG_HAVE_SDIO 0x04 +#define RTSX_SDIOCFG_SINGLE_LUN 0x08 +#define RTSX_SDIOCFG_SDIO_ONLY 0x80 + +#define RTSX_HOST_SLEEP_STATE 0xFE60 +#define RTSX_HOST_ENTER_S1 0x01 +#define RTSX_HOST_ENTER_S3 0x02 + +#define RTSX_SDIO_CFG 0xFE70 +#define RTSX_SDIO_BUS_AUTO_SWITCH 0x10 + +#define RTSX_NFTS_TX_CTRL 0xFE72 +#define RTSX_INT_READ_CLR 0x02 + +#define RTSX_PWR_GATE_CTRL 0xFE75 +#define RTSX_PWR_GATE_EN 0x01 +#define RTSX_LDO3318_PWR_MASK 0x06 +#define RTSX_LDO3318_ON 0x00 +#define RTSX_LDO3318_SUSPEND 0x04 +#define RTSX_LDO3318_OFF 0x06 +#define RTSX_LDO3318_VCC1 0x02 +#define RTSX_LDO3318_VCC2 0x04 +#define RTSX_PWD_SUSPEND_EN 0xFE76 +#define RTSX_LDO_PWR_SEL 0xFE78 +#define RTSX_LDO_PWR_SEL_3V3 0x01 +#define RTSX_LDO_PWR_SEL_DV33 0x03 + +#define RTSX_PHY_RWCTL 0xFE3C +#define RTSX_PHY_READ 0x00 +#define RTSX_PHY_WRITE 0x01 +#define RTSX_PHY_BUSY 0x80 +#define RTSX_PHY_DATA0 0xFE3D +#define RTSX_PHY_DATA1 0xFE3E +#define RTSX_PHY_ADDR 0xFE3F + +#define RTSX_PHY_PCR 0x00 +#define RTSX_PHY_PCR_FORCE_CODE 0xB000 +#define RTSX_PHY_PCR_OOBS_CALI_50 0x0800 +#define RTSX_PHY_PCR_OOBS_VCM_08 0x0200 +#define RTSX_PHY_PCR_OOBS_SEN_90 0x0040 +#define RTSX_PHY_PCR_RSSI_EN 0x0002 +#define RTSX_PHY_PCR_RX10K 0x0001 + +#define RTSX_PHY_RCR1 0x02 +#define RTSX_PHY_RCR1_ADP_TIME_4 0x0400 +#define RTSX_PHY_RCR1_VCO_COARSE 0x001F +#define RTSX_PHY_RCR1_INIT_27S 0x0A1F + +#define RTSX_PHY_RCR2 0x03 +#define RTSX_PHY_RCR2_EMPHASE_EN 0x8000 +#define RTSX_PHY_RCR2_NADJR 0x4000 +#define RTSX_PHY_RCR2_CDR_SR_2 0x0100 +#define RTSX_PHY_RCR2_FREQSEL_12 0x0040 +#define RTSX_PHY_RCR2_CDR_SC_12P 0x0010 +#define RTSX_PHY_RCR2_CALIB_LATE 0x0002 +#define RTSX_PHY_RCR2_INIT_27S 0xC152 + +#define RTSX__PHY_ANA03 0x03 +#define RTSX__PHY_ANA03_TIMER_MAX 0x2700 +#define RTSX__PHY_ANA03_OOBS_DEB_EN 0x0040 +#define RTSX__PHY_CMU_DEBUG_EN 0x0008 + +#define RTSX_PHY_RDR 0x05 +#define RTSX_PHY_RDR_RXDSEL_1_9 0x4000 +#define RTSX_PHY_SSC_AUTO_PWD 0x0600 + +#define RTSX_PHY_TUNE 0x08 +#define RTSX_PHY_TUNE_TUNEREF_1_0 0x4000 +#define RTSX_PHY_TUNE_VBGSEL_1252 0x0C00 +#define RTSX_PHY_TUNE_SDBUS_33 0x0200 +#define RTSX_PHY_TUNE_TUNED18 0x01C0 +#define RTSX_PHY_TUNE_TUNED12 0X0020 +#define RTSX_PHY_TUNE_TUNEA12 0x0004 +#define RTSX_PHY_TUNE_VOLTAGE_MASK 0xFC3F +#define RTSX_PHY_TUNE_VOLTAGE_3V3 0x03C0 +#define RTSX_PHY_TUNE_D18_1V8 0x0100 +#define RTSX_PHY_TUNE_D18_1V7 0x0080 + +#define RTSX_PHY_BPCR 0x0A +#define RTSX_PHY_BPCR_IBRXSEL 0x0400 +#define RTSX_PHY_BPCR_IBTXSEL 0x0100 +#define RTSX_PHY_BPCR_IB_FILTER 0x0080 +#define RTSX_PHY_BPCR_CMIRROR_EN 0x0040 + +#define RTSX_PHY_REV 0x19 +#define RTSX_PHY_REV_RESV 0xE000 +#define RTSX_PHY_REV_RXIDLE_LATCHED 0x1000 +#define RTSX_PHY_REV_P1_EN 0x0800 +#define RTSX_PHY_REV_RXIDLE_EN 0x0400 +#define RTSX_PHY_REV_CLKREQ_TX_EN 0x0200 +#define RTSX_PHY_REV_CLKREQ_RX_EN 0x0100 +#define RTSX_PHY_REV_CLKREQ_DT_1_0 0x0040 +#define RTSX_PHY_REV_STOP_CLKRD 0x0020 +#define RTSX_PHY_REV_RX_PWST 0x0008 +#define RTSX_PHY_REV_STOP_CLKWR 0x0004 + + +#define RTSX__PHY_REV0 0x19 +#define RTSX__PHY_REV0_FILTER_OUT 0x3800 +#define RTSX__PHY_REV0_CDR_BYPASS_PFD 0x0100 +#define RTSX__PHY_REV0_CDR_RX_IDLE_BYPASS 0x0002 + +#define RTSX_PHY_FLD0 0x1A +#define RTSX_PHY_FLD0_INIT_27S 0x2546 + +#define RTSX_PHY_FLD3 0x1D +#define RTSX_PHY_FLD3_TIMER_4 0x0800 +#define RTSX_PHY_FLD3_TIMER_6 0x0020 +#define RTSX_PHY_FLD3_RXDELINK 0x0004 +#define RTSX_PHY_FLD3_INIT_27S 0x0004 + +#define RTSX__PHY_FLD0 0x1D +#define RTSX__PHY_FLD0_CLK_REQ_20C 0x8000 +#define RTSX__PHY_FLD0_RX_IDLE_EN 0x1000 +#define RTSX__PHY_FLD0_BIT_ERR_RSTN 0x0800 +#define RTSX__PHY_FLD0_BER_COUNT 0x01E0 +#define RTSX__PHY_FLD0_BER_TIMER 0x001E +#define RTSX__PHY_FLD0_CHECK_EN 0x0001 + +#define RTSX_PHY_FLD4 0x1E +#define RTSX_PHY_FLD4_FLDEN_SEL 0x4000 +#define RTSX_PHY_FLD4_REQ_REF 0x2000 +#define RTSX_PHY_FLD4_RXAMP_OFF 0x1000 +#define RTSX_PHY_FLD4_REQ_ADDA 0x0800 +#define RTSX_PHY_FLD4_BER_COUNT 0x00E0 +#define RTSX_PHY_FLD4_BER_TIMER 0x000A +#define RTSX_PHY_FLD4_BER_CHK_EN 0x0001 +#define RTSX_PHY_FLD4_INIT_27S 0x5C7F + +#define RTSX_CARD_AUTO_BLINK 0xFD56 +#define RTSX_LED_BLINK_EN 0x08 +#define RTSX_LED_BLINK_SPEED 0x05 + +#define RTSX_PCLK_CTL 0xFE55 +#define RTSX_PCLK_MODE_SEL 0x20 + +#define RTSX_PME_FORCE_CTL 0xFE56 + +#define RTSX_ASPM_FORCE_CTL 0xFE57 +#define RTSX_ASPM_FORCE_MASK 0x3F +#define RTSX_FORCE_ASPM_NO_ASPM 0x00 + +#define RTSX_PM_CLK_FORCE_CTL 0xFE58 +#define RTSX_FUNC_FORCE_CTL 0xFE59 +#define RTSX_FUNC_FORCE_UPME_XMT_DBG 0x02 + +#define RTSX_CHANGE_LINK_STATE 0xFE5B +#define RTSX_CD_RST_CORE_EN 0x01 +#define RTSX_FORCE_RST_CORE_EN 0x02 +#define RTSX_NON_STICKY_RST_N_DBG 0x08 +#define RTSX_MAC_PHY_RST_N_DBG 0x10 + +#define RTSX_PERST_GLITCH_WIDTH 0xFE5C + +#define RTSX_EFUSE_CONTENT 0xFE5F + +#define RTSX_PM_EVENT_DEBUG 0xFE71 +#define RTSX_PME_DEBUG_0 0x08 + +#define RTSX_L1SUB_CONFIG2 0xFE8E +#define RTSX_L1SUB_AUTO_CFG 0x02 + +#define RTSX_L1SUB_CONFIG3 0xFE8F + +#define RTSX_DUMMY_REG 0xFE90 + +#define RTSX_PETXCFG 0xFF03 /* was 0xFE49 in OpenBSD */ +#define RTSX_PETXCFG_CLKREQ_PIN 0x08 + +#define RTSX_RREF_CFG 0xFF6C +#define RTSX_RREF_VBGSEL_MASK 0x38 +#define RTSX_RREF_VBGSEL_1V25 0x28 + +#define RTSX_PM_CTRL3 0xFF46 +#define RTSX_RTS522A_PM_CTRL3 0xFF7E +#define RTSX_D3_DELINK_MODE_EN 0x10 +#define RTSX_PM_WAKE_EN 0x01 + +#define RTSX_OOBS_CONFIG 0xFF6E +#define RTSX_OOBS_AUTOK_DIS 0x80 +#define RTSX_OOBS_VAL_MASK 0x1F + +#define RTSX_LDO_CONFIG2 0xFF71 +#define RTSX_LDO_D3318_MASK 0x07 +#define RTSX_LDO_D3318_33V 0x07 +#define RTSX_LDO_D3318_18V 0x02 +#define RTSX_DV331812_VDD1 0x04 +#define RTSX_DV331812_POWERON 0x08 +#define RTSX_DV331812_POWEROFF 0x00 + +#define RTSX_LDO_VCC_CFG0 0xFF72 +#define RTSX_LDO_VCC_LMTVTH_MASK 0x30 +#define RTSX_LDO_VCC_LMTVTH_2A 0x10 + +#define RTSX_LDO_VCC_CFG1 0xFF73 +#define RTSX_LDO_VCC_REF_TUNE_MASK 0x30 +#define RTSX_LDO_VCC_REF_1V2 0x20 +#define RTSX_LDO_VCC_TUNE_MASK 0x07 +#define RTSX_LDO_VCC_1V8 0x04 +#define RTSX_LDO_VCC_3V3 0x07 +#define RTSX_LDO_VCC_LMT_EN 0x08 + +#define RTSX_LDO_VIO_CFG 0xFF75 +#define RTSX_LDO_VIO_TUNE_MASK 0x07 +#define RTSX_LDO_VIO_1V7 0x03 + +#define RTSX_LDO_DV12S_CFG 0xFF76 +#define RTSX_LDO_D12_TUNE_MASK 0x07 +#define RTSX_LDO_D12_TUNE_DF 0x04 + +#define RTSX_LDO_AV12S_CFG 0xFF77 +#define RTSX_LDO_AV12S_TUNE_MASK 0x07 +#define RTSX_LDO_AV12S_TUNE_DF 0x04 + +#define RTSX_SG_INT 0x04 +#define RTSX_SG_END 0x02 +#define RTSX_SG_VALID 0x01 + +#define RTSX_SG_NO_OP 0x00 +#define RTSX_SG_TRANS_DATA (0x02 << 4) +#define RTSX_SG_LINK_DESC (0x03 << 4) + +#define RTSX_IC_VERSION_A 0x00 +#define RTSX_IC_VERSION_B 0x01 +#define RTSX_IC_VERSION_C 0x02 +#define RTSX_IC_VERSION_D 0x03 + +#define RTSX_PCR_SETTING_REG1 0x724 +#define RTSX_PCR_SETTING_REG2 0x814 +#define RTSX_PCR_SETTING_REG3 0x747 + +#define RTSX_RX_PHASE_MAX 32 +#define RTSX_RX_TUNING_CNT 3 +#endif Index: sys/i386/conf/GENERIC =================================================================== --- sys/i386/conf/GENERIC +++ sys/i386/conf/GENERIC @@ -329,6 +329,8 @@ device mmc # MMC/SD bus device mmcsd # MMC/SD memory card device sdhci # Generic PCI SD Host Controller +device rtsx # Realtek SD card reader +# options RTSX_INVERSION # Reverse card detection and read-only switch # VirtIO support device virtio # Generic VirtIO bus (required) Index: sys/modules/Makefile =================================================================== --- sys/modules/Makefile +++ sys/modules/Makefile @@ -311,6 +311,7 @@ re \ rl \ ${_rockchip} \ + rtsx \ rtwn \ rtwn_pci \ rtwn_usb \ Index: sys/modules/rtsx/Makefile =================================================================== --- /dev/null +++ sys/modules/rtsx/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/rtsx + +KMOD= rtsx +SRCS= rtsx.c +SRCS+= device_if.h bus_if.h pci_if.h mmcbr_if.h + +.include