Index: user/nwhitehorn/rtsx/rtsx.c =================================================================== --- user/nwhitehorn/rtsx/rtsx.c (nonexistent) +++ user/nwhitehorn/rtsx/rtsx.c (revision 355229) @@ -0,0 +1,1582 @@ +/* $OpenBSD: rtsx.c,v 1.21 2017/10/09 20:06:36 stsp Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2012 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Realtek RTS52xx/RTL84xx Card Reader driver. + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rtsxreg.h" +#include "rtsxvar.h" +#include "mmcbr_if.h" + +/* + * We use three DMA buffers: a command buffer, a data buffer, and a buffer for + * ADMA transfer descriptors which describe scatter-gather (SG) I/O operations. + * + * 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 TRANS_OK 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 smmmc stack provides DMA-safe buffers with data transfer commands. + * In this case we write a list of descriptors to the ADMA descriptor buffer, + * instructing the chip to transfer data directly from/to mmc DMA buffers. + * + * Data transfer is controlled via the RTSX_HDBAR register + * and completion is signalled by the TRANS_OK interrupt. + * + * The chip is unable to perform DMA above 4GB. + */ + +#define RTSX_DMA_MAX_SEGSIZE 0x80000 +#define RTSX_HOSTCMD_MAX 256 +#define RTSX_HOSTCMD_BUFSIZE (sizeof(u_int32_t) * RTSX_HOSTCMD_MAX) +#define RTSX_DMA_DATA_BUFSIZE MAXPHYS +#define RTSX_ADMA_DESC_SIZE (sizeof(uint64_t) * ((MAXPHYS / PAGE_SIZE) + 1)) + +#define SDMMC_SDCLK_400KHZ 400000 +#define SDMMC_SDCLK_25MHZ 25000000 +#define SDMMC_SDCLK_50MHZ 50000000 + +#define READ4(sc, reg) \ + (bus_read_4((sc)->sc_mem, (reg))) +#define WRITE4(sc, reg, val) \ + bus_write_4((sc)->sc_mem, (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) + +int rtsx_host_reset(struct rtsx_softc *); +int rtsx_card_detect(struct rtsx_softc *); +int rtsx_bus_clock(struct rtsx_softc *, int); +int rtsx_bus_width(struct rtsx_softc *, int); +void rtsx_exec_command(struct rtsx_softc *, struct mmc_command *); +int rtsx_init(struct rtsx_softc *, int); +void rtsx_soft_reset(struct rtsx_softc *); +int rtsx_bus_power_off(struct rtsx_softc *); +int rtsx_bus_power_on(struct rtsx_softc *); +int rtsx_set_bus_width(struct rtsx_softc *, int); +int rtsx_stop_sd_clock(struct rtsx_softc *); +int rtsx_switch_sd_clock(struct rtsx_softc *, u_int8_t, int, int); +int rtsx_intr_status(struct rtsx_softc *, int, int); +int rtsx_read(struct rtsx_softc *, u_int16_t, u_int8_t *); +int rtsx_write(struct rtsx_softc *, u_int16_t, u_int8_t, u_int8_t); +static int rtsx_request2(device_t bus, device_t child, struct mmc_request *req); +static int rtsx_request3(device_t bus, device_t child, struct mmc_request *req); +#ifdef notyet +int rtsx_read_phy(struct rtsx_softc *, u_int8_t, u_int16_t *); +#endif +int rtsx_write_phy(struct rtsx_softc *, u_int8_t, u_int16_t); +int rtsx_read_cfg(struct rtsx_softc *, u_int8_t, u_int16_t, u_int32_t *); +#ifdef notyet +int rtsx_write_cfg(struct rtsx_softc *, u_int8_t, u_int16_t, u_int32_t, + u_int32_t); +#endif +void rtsx_hostcmd(u_int32_t *, int *, u_int8_t, u_int16_t, u_int8_t, + u_int8_t); +int rtsx_hostcmd_send(struct rtsx_softc *, int); +u_int8_t rtsx_response_type(u_int16_t); +int rtsx_xfer(struct rtsx_softc *, struct mmc_command *, u_int32_t *); +int rtsx_xfer_adma(struct rtsx_softc *, struct mmc_command *); +void rtsx_card_insert(struct rtsx_softc *); +void rtsx_card_eject(struct rtsx_softc *); +int rtsx_led_enable(struct rtsx_softc *); +int rtsx_led_disable(struct rtsx_softc *); +void rtsx_save_regs(struct rtsx_softc *); +void rtsx_restore_regs(struct rtsx_softc *); + +#define RTSX_DEBUG +#ifdef RTSX_DEBUG +int rtsxdebug = 3; +#define DPRINTF(n,...) \ + do { \ + if ((n) <= rtsxdebug) device_printf(sc->sc_dev, __VA_ARGS__); \ + } while (0) +#else +#define DPRINTF(n,...) do {} while(0) +#endif + +/* + * Called by attachment driver. + */ +static void +rtsx_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct rtsx_softc *sc = xsc; + + if (error != 0) + return; + if (nsegs != 1) + panic("%s: bad ADMA buffer segment count", __func__); + sc->adma_segs[0] = segs[0]; +} + +static void +rtsx_cmd_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct rtsx_softc *sc = xsc; + + if (error != 0) + return; + if (nsegs != 1) + panic("%s: bad CMD buffer segment count", __func__); + sc->cmd_segs[0] = segs[0]; +} + +int +rtsx_attach(struct rtsx_softc *sc, bus_dma_tag_t dmat, int flags) +{ + u_int32_t sdio_cfg; + + sc->flags = flags; + + if (rtsx_init(sc, 1)) + return 1; + + 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->flags |= RTSX_F_SDIO_SUPPORT; + } + + bus_dma_tag_create(dmat, 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, RTSX_HOSTCMD_BUFSIZE, 1, + RTSX_DMA_MAX_SEGSIZE, BUS_DMA_NOWAIT, NULL, NULL, &sc->cmd_tag); + if (bus_dmamem_alloc(sc->cmd_tag, &sc->cmdbuf, + BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->dmap_cmd)) + return 1; + if (bus_dmamap_load(sc->cmd_tag, sc->dmap_cmd, sc->cmdbuf, + RTSX_HOSTCMD_BUFSIZE, rtsx_cmd_dma_callback, sc, 0)) + goto destroy_cmd; + bus_dma_tag_create(dmat, 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, RTSX_DMA_DATA_BUFSIZE, 1, + RTSX_DMA_MAX_SEGSIZE, BUS_DMA_NOWAIT, NULL, NULL, &sc->data_tag); + if (bus_dmamap_create(sc->data_tag, 0, &sc->dmap_data) != 0) + goto free_cmd; + bus_dma_tag_create(dmat, 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, RTSX_ADMA_DESC_SIZE, 1, + RTSX_DMA_MAX_SEGSIZE, 0, NULL, NULL, &sc->adma_tag); + if (bus_dmamem_alloc(sc->adma_tag, &sc->admabuf, + BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->dmap_adma)) + goto destroy_data; + if (bus_dmamap_load(sc->adma_tag, sc->dmap_adma, sc->admabuf, + RTSX_ADMA_DESC_SIZE, rtsx_dma_callback, sc, 0)) + goto free_adma; + + mtx_init(&sc->sc_mtx, device_get_name(sc->sc_dev), NULL, MTX_DEF); + + /* Now handle cards discovered during attachment. */ + if (sc->flags & RTSX_F_CARD_PRESENT) + rtsx_card_insert(sc); + + return 0; + +free_adma: + bus_dmamem_free(sc->adma_tag, sc->admabuf, sc->dmap_adma); +destroy_data: + bus_dmamap_destroy(sc->data_tag, sc->dmap_data); +free_cmd: + bus_dmamem_free(sc->cmd_tag, sc->cmdbuf, sc->dmap_cmd); +destroy_cmd: + bus_dmamap_destroy(sc->cmd_tag, sc->dmap_cmd); + return 1; +} + +int +rtsx_detach(struct rtsx_softc *sc) +{ + mtx_lock(&sc->sc_mtx); + rtsx_card_eject(sc); + mtx_unlock(&sc->sc_mtx); + + mtx_destroy(&sc->sc_mtx); + + if (sc->dmap_adma) { + bus_dmamap_unload(sc->adma_tag, sc->dmap_adma); + bus_dmamem_free(sc->adma_tag, sc->admabuf, sc->dmap_adma); + } + + if (sc->dmap_data) + bus_dmamap_destroy(sc->data_tag, sc->dmap_data); + + if (sc->dmap_cmd) + bus_dmamap_destroy(sc->cmd_tag, sc->dmap_cmd); + + return (0); +} + +int +rtsx_init(struct rtsx_softc *sc, int attaching) +{ + u_int32_t status; + u_int8_t version; + int error; + + /* Read IC version from dummy register. */ + if (sc->flags & RTSX_F_5229) { + RTSX_READ(sc, RTSX_DUMMY_REG, &version); + switch (version & 0x0F) { + case RTSX_IC_VERSION_A: + case RTSX_IC_VERSION_B: + case RTSX_IC_VERSION_D: + break; + case RTSX_IC_VERSION_C: + sc->flags |= RTSX_F_5229_TYPE_C; + break; + default: + device_printf(sc->sc_dev, + "rtsx_init: unknown ic %02x\n", version); + return (1); + } + } + + /* Enable interrupt write-clear (default is read-clear). */ + RTSX_CLR(sc, RTSX_NFTS_TX_CTRL, RTSX_INT_READ_CLR); + + /* Clear any pending interrupts. */ + status = READ4(sc, RTSX_BIPR); + WRITE4(sc, RTSX_BIPR, status); + + /* Check for cards already inserted at attach time. */ + if (attaching && (status & RTSX_SD_EXIST)) + sc->flags |= RTSX_F_CARD_PRESENT; + + /* Enable interrupts. */ + WRITE4(sc, RTSX_BIER, + RTSX_TRANS_OK_INT_EN | RTSX_TRANS_FAIL_INT_EN | RTSX_SD_INT_EN); + + /* Power on SSC clock. */ + RTSX_CLR(sc, RTSX_FPDCTL, RTSX_SSC_POWER_DOWN); + DELAY(200); + + /* XXX magic numbers from linux driver */ + if (sc->flags & RTSX_F_5209) + error = rtsx_write_phy(sc, 0x00, 0xB966); + else + error = rtsx_write_phy(sc, 0x00, 0xBA42); + if (error) { + device_printf(sc->sc_dev, "cannot write phy register\n"); + return (1); + } + + RTSX_SET(sc, RTSX_CLK_DIV, 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); + + RTSX_CLR(sc, RTSX_CHANGE_LINK_STATE, + RTSX_FORCE_RST_CORE_EN | RTSX_NON_STICKY_RST_N_DBG | 0x04); + RTSX_WRITE(sc, RTSX_SD30_DRIVE_SEL, RTSX_SD30_DRIVE_SEL_3V3); + + /* Enable SSC clock. */ + RTSX_WRITE(sc, RTSX_SSC_CTL1, RTSX_SSC_8X_EN | RTSX_SSC_SEL_4M); + RTSX_WRITE(sc, RTSX_SSC_CTL2, 0x12); + + RTSX_SET(sc, RTSX_CHANGE_LINK_STATE, RTSX_MAC_PHY_RST_N_DBG); + RTSX_SET(sc, RTSX_IRQSTAT0, RTSX_LINK_READY_INT); + + RTSX_WRITE(sc, RTSX_PERST_GLITCH_WIDTH, 0x80); + + /* Set RC oscillator to 400K. */ + RTSX_CLR(sc, RTSX_RCCTL, RTSX_RCCTL_F_2M); + + /* Request clock by driving CLKREQ pin to zero. */ + RTSX_SET(sc, RTSX_PETXCFG, RTSX_PETXCFG_CLKREQ_PIN); + + /* Set up LED GPIO. */ + if (sc->flags & RTSX_F_5209) { + RTSX_WRITE(sc, RTSX_CARD_GPIO, 0x03); + RTSX_WRITE(sc, RTSX_CARD_GPIO_DIR, 0x03); + } else { + RTSX_SET(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON); + /* Switch LDO3318 source from DV33 to 3V3. */ + RTSX_CLR(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_DV33); + RTSX_SET(sc, RTSX_LDO_PWR_SEL, RTSX_LDO_PWR_SEL_3V3); + /* Set default OLT blink period. */ + RTSX_SET(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_PERIOD); + } + + return (0); +} + +int +rtsx_led_enable(struct rtsx_softc *sc) +{ + if (sc->flags & RTSX_F_5209) { + 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); + } else { + RTSX_SET(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON); + RTSX_SET(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_AUTOBLINK); + } + + return 0; +} + +int +rtsx_led_disable(struct rtsx_softc *sc) +{ + if (sc->flags & RTSX_F_5209) { + RTSX_CLR(sc, RTSX_CARD_AUTO_BLINK, RTSX_LED_BLINK_EN); + RTSX_WRITE(sc, RTSX_CARD_GPIO, RTSX_CARD_GPIO_LED_OFF); + } else { + RTSX_CLR(sc, RTSX_OLT_LED_CTL, RTSX_OLT_LED_AUTOBLINK); + RTSX_CLR(sc, RTSX_GPIO_CTL, RTSX_GPIO_LED_ON); + } + + return 0; +} + +/* + * Reset the host controller. Called during initialization, when + * cards are removed, upon resume, and during error recovery. + */ +int +rtsx_host_reset(struct rtsx_softc *sc) +{ + DPRINTF(1, "host reset\n"); + + if (sc->flags & RTSX_F_CARD_PRESENT) + rtsx_soft_reset(sc); + + if (rtsx_init(sc, 0)) + return 1; + + return 0; +} + +/* + * Return non-zero if the card is currently inserted. + */ +int +rtsx_card_detect(struct rtsx_softc *sc) +{ + + return (sc->flags & RTSX_F_CARD_PRESENT); +} + +/* + * 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. + */ + +int +rtsx_bus_power_off(struct rtsx_softc *sc) +{ + int error; + u_int8_t disable3; + + error = rtsx_stop_sd_clock(sc); + if (error) + return error; + + /* Disable SD output. */ + RTSX_CLR(sc, RTSX_CARD_OE, RTSX_CARD_OUTPUT_EN); + + /* Turn off power. */ + disable3 = RTSX_PULL_CTL_DISABLE3; + if (sc->flags & RTSX_F_5209) + RTSX_SET(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_OFF); + else { + RTSX_CLR(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_VCC1 | + RTSX_LDO3318_VCC2); + if (sc->flags & RTSX_F_5229_TYPE_C) + disable3 = RTSX_PULL_CTL_DISABLE3_TYPE_C; + } + + RTSX_SET(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_OFF); + RTSX_CLR(sc, RTSX_CARD_PWR_CTL, RTSX_PMOS_STRG_800mA); + + /* Disable pull control. */ + 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, disable3); + + return 0; +} + +int +rtsx_bus_power_on(struct rtsx_softc *sc) +{ + u_int8_t enable3; + int err; + + if (sc->flags & RTSX_F_525A) { + err = rtsx_write(sc, RTSX_LDO_VCC_CFG1, RTSX_LDO_VCC_TUNE_MASK, + RTSX_LDO_VCC_3V3); + if (err) + return (err); + } + + /* Select SD card. */ + RTSX_WRITE(sc, RTSX_CARD_SELECT, RTSX_SD_MOD_SEL); + RTSX_WRITE(sc, RTSX_CARD_SHARE_MODE, RTSX_CARD_SHARE_48_SD); + RTSX_SET(sc, RTSX_CARD_CLK_EN, RTSX_SD_CLK_EN); + + /* Enable pull control. */ + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL1, RTSX_PULL_CTL_ENABLE12); + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL2, RTSX_PULL_CTL_ENABLE12); + if (sc->flags & RTSX_F_5229_TYPE_C) + enable3 = RTSX_PULL_CTL_ENABLE3_TYPE_C; + else + enable3 = RTSX_PULL_CTL_ENABLE3; + RTSX_WRITE(sc, RTSX_CARD_PULL_CTL3, enable3); + + /* + * To avoid a current peak, enable card power in two phases with a + * delay in between. + */ + + /* Partial power. */ + RTSX_SET(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PARTIAL_PWR_ON); + if (sc->flags & RTSX_F_5209) + RTSX_SET(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_SUSPEND); + else + RTSX_SET(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_VCC1); + + DELAY(200); + + /* Full power. */ + RTSX_CLR(sc, RTSX_CARD_PWR_CTL, RTSX_SD_PWR_OFF); + if (sc->flags & RTSX_F_5209) + RTSX_CLR(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_OFF); + else + RTSX_SET(sc, RTSX_PWR_GATE_CTRL, RTSX_LDO3318_VCC2); + + /* Enable SD card output. */ + RTSX_WRITE(sc, RTSX_CARD_OE, RTSX_SD_OUTPUT_EN); + + return 0; +} + +int +rtsx_set_bus_width(struct rtsx_softc *sc, int w) +{ + u_int32_t bus_width; + int error; + + switch (w) { + case 8: + bus_width = RTSX_BUS_WIDTH_8; + break; + case 4: + bus_width = RTSX_BUS_WIDTH_4; + break; + case 1: + default: + bus_width = RTSX_BUS_WIDTH_1; + break; + } + + error = rtsx_write(sc, RTSX_SD_CFG1, RTSX_BUS_WIDTH_MASK, bus_width); + return error; +} + +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; +} + +int +rtsx_switch_sd_clock(struct rtsx_softc *sc, u_int8_t n, int div, int mcu) +{ + /* Enable SD 2.0 mode. */ + RTSX_CLR(sc, RTSX_SD_CFG1, RTSX_SD_MODE_MASK); + + RTSX_SET(sc, RTSX_CLK_CTL, 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_SD_SAMPLE_POINT_CTL, RTSX_SD20_RX_SEL_MASK); + RTSX_WRITE(sc, RTSX_SD_PUSH_POINT_CTL, RTSX_SD20_TX_NEG_EDGE); + RTSX_WRITE(sc, RTSX_CLK_DIV, (div << 4) | mcu); + RTSX_CLR(sc, RTSX_SSC_CTL1, RTSX_RSTB); + RTSX_CLR(sc, RTSX_SSC_CTL2, RTSX_SSC_DEPTH_MASK); + RTSX_WRITE(sc, RTSX_SSC_DIV_N_0, n); + RTSX_SET(sc, RTSX_SSC_CTL1, RTSX_RSTB); + DELAY(100); + + RTSX_CLR(sc, RTSX_CLK_CTL, RTSX_CLK_LOW_FREQ); + + return 0; +} + +/* + * Set or change SDCLK frequency or disable the SD clock. + * Return zero on success. + */ +int +rtsx_bus_clock(struct rtsx_softc *sc, int freq) +{ + u_int8_t n; + int div; + int mcu; + int error = 0; + + if (freq == 0) { + error = rtsx_stop_sd_clock(sc); + goto ret; + } + + /* Round down to a supported frequency. */ + if (freq >= SDMMC_SDCLK_50MHZ) + freq = SDMMC_SDCLK_50MHZ; + else if (freq >= SDMMC_SDCLK_25MHZ) + freq = SDMMC_SDCLK_25MHZ; + else + freq = SDMMC_SDCLK_400KHZ; + + /* + * Configure the clock frequency. + */ + switch (freq) { + case SDMMC_SDCLK_400KHZ: + n = 80; /* minimum */ + div = RTSX_CLK_DIV_8; + mcu = 7; + RTSX_SET(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_128); + break; + case SDMMC_SDCLK_25MHZ: + n = 100; + div = RTSX_CLK_DIV_4; + mcu = 7; + RTSX_CLR(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK); + break; + case SDMMC_SDCLK_50MHZ: + n = 100; + div = RTSX_CLK_DIV_2; + mcu = 7; + RTSX_CLR(sc, RTSX_SD_CFG1, RTSX_CLK_DIVIDE_MASK); + break; + default: + error = EINVAL; + goto ret; + } + + /* + * Enable SD clock. + */ + error = rtsx_switch_sd_clock(sc, n, div, mcu); +ret: + return error; +} + +int +rtsx_read(struct rtsx_softc *sc, u_int16_t addr, u_int8_t *val) +{ + int tries = 1024; + u_int32_t reg; + + WRITE4(sc, RTSX_HAIMR, RTSX_HAIMR_BUSY | + (u_int32_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; +} + +int +rtsx_write(struct rtsx_softc *sc, u_int16_t addr, u_int8_t mask, u_int8_t val) +{ + int tries = 1024; + u_int32_t reg; + + WRITE4(sc, RTSX_HAIMR, + RTSX_HAIMR_BUSY | RTSX_HAIMR_WRITE | + (u_int32_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; +} + +#ifdef notyet +int +rtsx_read_phy(struct rtsx_softc *sc, u_int8_t addr, u_int16_t *val) +{ + int timeout = 100000; + u_int8_t data0; + u_int8_t data1; + u_int8_t rwctl; + + RTSX_WRITE(sc, RTSX_PHY_ADDR, addr); + RTSX_WRITE(sc, RTSX_PHY_RWCTL, RTSX_PHY_BUSY|RTSX_PHY_READ); + + while (timeout--) { + RTSX_READ(sc, RTSX_PHY_RWCTL, &rwctl); + if (!(rwctl & RTSX_PHY_BUSY)) + break; + } + + if (timeout == 0) + return ETIMEDOUT; + + RTSX_READ(sc, RTSX_PHY_DATA0, &data0); + RTSX_READ(sc, RTSX_PHY_DATA1, &data1); + *val = data0 | (data1 << 8); + + return 0; +} +#endif + +int +rtsx_write_phy(struct rtsx_softc *sc, u_int8_t addr, u_int16_t val) +{ + int timeout = 100000; + u_int8_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 (timeout--) { + RTSX_READ(sc, RTSX_PHY_RWCTL, &rwctl); + if (!(rwctl & RTSX_PHY_BUSY)) + break; + } + + if (timeout == 0) + return ETIMEDOUT; + + return 0; +} + +int +rtsx_read_cfg(struct rtsx_softc *sc, u_int8_t func, u_int16_t addr, + u_int32_t *val) +{ + int tries = 1024; + u_int8_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 EIO; + + 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; +} + +#ifdef notyet +int +rtsx_write_cfg(struct rtsx_softc *sc, u_int8_t func, u_int16_t addr, + u_int32_t mask, u_int32_t val) +{ + int i, writemask = 0, tries = 1024; + u_int8_t rwctl; + + for (i = 0; i < 4; i++) { + if (mask & 0xff) { + RTSX_WRITE(sc, RTSX_CFGDATA0 + i, val & mask & 0xff); + writemask |= (1 << i); + } + mask >>= 8; + val >>= 8; + } + + if (writemask) { + RTSX_WRITE(sc, RTSX_CFGADDR0, addr); + RTSX_WRITE(sc, RTSX_CFGADDR1, addr >> 8); + RTSX_WRITE(sc, RTSX_CFGRWCTL, + RTSX_CFG_BUSY | writemask | (func & 0x03 << 4)); + } + + while (tries--) { + RTSX_READ(sc, RTSX_CFGRWCTL, &rwctl); + if (!(rwctl & RTSX_CFG_BUSY)) + break; + } + + if (tries == 0) + return EIO; + + return 0; +} +#endif + +/* Append a properly encoded host command to the host command buffer. */ +void +rtsx_hostcmd(u_int32_t *cmdbuf, int *n, u_int8_t cmd, u_int16_t reg, + u_int8_t mask, u_int8_t data) +{ + KASSERT(*n < RTSX_HOSTCMD_MAX, + ("too many commands (%d vs. %d)", *n, RTSX_HOSTCMD_MAX)); + + cmdbuf[(*n)++] = htole32((u_int32_t)(cmd & 0x3) << 30) | + ((u_int32_t)(reg & 0x3fff) << 16) | + ((u_int32_t)(mask) << 8) | + ((u_int32_t)data); +} + +void +rtsx_save_regs(struct rtsx_softc *sc) +{ + int i; + u_int16_t reg; + + i = 0; + for (reg = 0xFDA0; reg < 0xFDAE; reg++) + (void)rtsx_read(sc, reg, &sc->regs[i++]); + for (reg = 0xFD52; reg < 0xFD69; reg++) + (void)rtsx_read(sc, reg, &sc->regs[i++]); + for (reg = 0xFE20; reg < 0xFE34; reg++) + (void)rtsx_read(sc, reg, &sc->regs[i++]); + + sc->regs4[0] = READ4(sc, RTSX_HCBAR); + sc->regs4[1] = READ4(sc, RTSX_HCBCTLR); + sc->regs4[2] = READ4(sc, RTSX_HDBAR); + sc->regs4[3] = READ4(sc, RTSX_HDBCTLR); + sc->regs4[4] = READ4(sc, RTSX_HAIMR); + sc->regs4[5] = READ4(sc, RTSX_BIER); + /* Not saving RTSX_BIPR. */ +} + +void +rtsx_restore_regs(struct rtsx_softc *sc) +{ + int i; + u_int16_t reg; + + WRITE4(sc, RTSX_HCBAR, sc->regs4[0]); + WRITE4(sc, RTSX_HCBCTLR, sc->regs4[1]); + WRITE4(sc, RTSX_HDBAR, sc->regs4[2]); + WRITE4(sc, RTSX_HDBCTLR, sc->regs4[3]); + WRITE4(sc, RTSX_HAIMR, sc->regs4[4]); + WRITE4(sc, RTSX_BIER, sc->regs4[5]); + /* Not writing RTSX_BIPR since doing so would clear it. */ + + i = 0; + for (reg = 0xFDA0; reg < 0xFDAE; reg++) + (void)rtsx_write(sc, reg, 0xff, sc->regs[i++]); + for (reg = 0xFD52; reg < 0xFD69; reg++) + (void)rtsx_write(sc, reg, 0xff, sc->regs[i++]); + for (reg = 0xFE20; reg < 0xFE34; reg++) + (void)rtsx_write(sc, reg, 0xff, sc->regs[i++]); +} + +u_int8_t +rtsx_response_type(u_int16_t sdmmc_rsp) +{ + int i; + struct rsp_type { + u_int16_t sdmmc_rsp; + u_int8_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 (sdmmc_rsp == rsp_types[i].sdmmc_rsp) + return rsp_types[i].rtsx_rsp; + } + + return 0; +} + +int +rtsx_hostcmd_send(struct rtsx_softc *sc, int ncmd) +{ + + /* Tell the chip where the command buffer is and run the commands. */ + WRITE4(sc, RTSX_HCBAR, sc->cmd_segs[0].ds_addr); + WRITE4(sc, RTSX_HCBCTLR, + ((ncmd * 4) & 0x00ffffff) | RTSX_START_CMD | RTSX_HW_AUTO_RSP); + + return 0; +} + +int +rtsx_xfer(struct rtsx_softc *sc, struct mmc_command *cmd, u_int32_t *cmdbuf) +{ + int ncmd, dma_dir, error, tmode; + int read = !!(cmd->data->flags & MMC_DATA_READ); + u_int8_t cfg2; + + DPRINTF(3, "%s xfer: %zd bytes with block size %zd\n", + read ? "read" : "write", + cmd->data->len, cmd->data->xfer_len); + + if (cmd->data->len > RTSX_DMA_DATA_BUFSIZE) { + DPRINTF(3, "cmd->data->len too large: %zd > %d\n", + cmd->data->len, RTSX_DMA_DATA_BUFSIZE); + return ENOMEM; + } + + /* Configure DMA transfer mode parameters. */ + cfg2 = RTSX_SD_NO_CHECK_WAIT_CRC_TO | 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_READ3, which assumes we've already + * sent the read command and gotten the response, and will + * send CMD 12 manually after reading multiple blocks. */ + tmode = RTSX_TM_AUTO_READ3; + cfg2 |= RTSX_SD_CALCULATE_CRC7 | RTSX_SD_CHECK_CRC7; + } else { + dma_dir = RTSX_DMA_DIR_TO_CARD; + /* Use transfer mode AUTO_WRITE3, which assumes we've already + * sent the write command and gotten the response, and will + * send CMD 12 manually after writing multiple blocks. */ + tmode = RTSX_TM_AUTO_WRITE3; + cfg2 |= RTSX_SD_NO_CALCULATE_CRC7 | RTSX_SD_NO_CHECK_CRC7; + } + + ncmd = 0; + + rtsx_hostcmd(cmdbuf, &ncmd, RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, + 0xff, cfg2); + + /* Queue commands to configure data transfer size. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_L, 0xff, + (cmd->data->xfer_len & 0xff)); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_H, 0xff, + (cmd->data->xfer_len >> 8)); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_L, 0xff, + ((cmd->data->len / cmd->data->xfer_len) & 0xff)); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_H, 0xff, + ((cmd->data->len / cmd->data->xfer_len) >> 8)); + + /* Use the DMA ring buffer for commands which transfer data. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE, 0x01, RTSX_RING_BUFFER); + + /* Configure DMA controller. */ + rtsx_hostcmd(cmdbuf, &ncmd, RTSX_WRITE_REG_CMD, RTSX_IRQSTAT0, + RTSX_DMA_DONE_INT, RTSX_DMA_DONE_INT); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_DMATC3, 0xff, cmd->data->len >> 24); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_DMATC2, 0xff, cmd->data->len >> 16); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_DMATC1, 0xff, cmd->data->len >> 8); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_DMATC0, 0xff, cmd->data->len); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_DMACTL, + 0x03 | RTSX_DMA_PACK_SIZE_MASK, + dma_dir | RTSX_DMA_EN | RTSX_DMA_512); + + /* Queue commands to perform SD transfer. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, + 0xff, tmode | RTSX_SD_TRANSFER_START); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END, RTSX_SD_TRANSFER_END); + + error = rtsx_hostcmd_send(sc, ncmd); + if (error) + goto ret; + + error = rtsx_xfer_adma(sc, cmd); +ret: + DPRINTF(3, "xfer done, error=%d\n", error); + return error; +} + +static void +rtsx_xfer_adma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct rtsx_softc *sc = xsc; + uint64_t *descp; + int i; + + if (error != 0) { + sc->cur_req->cmd->error = error; + return; + } + + /* Initialize scatter-gather transfer descriptors. */ + descp = (uint64_t *)sc->admabuf; + for (i = 0; i < nsegs; i++) { + uint64_t paddr = segs[i].ds_addr; + uint64_t len = segs[i].ds_len; + uint8_t sgflags = RTSX_SG_VALID | RTSX_SG_TRANS_DATA; + uint64_t desc; + + if (i == nsegs - 1) + sgflags |= RTSX_SG_END; + len &= 0x00ffffff; + desc = htole64((paddr << 32) | (len << 12) | sgflags); + memcpy(descp, &desc, sizeof(*descp)); + descp++; + } +} + +int +rtsx_xfer_adma(struct rtsx_softc *sc, struct mmc_command *cmd) +{ + int error; + int read = !!(cmd->data->flags & MMC_DATA_READ); + + error = bus_dmamap_load(sc->data_tag, sc->dmap_data, cmd->data->data, + cmd->data->len, rtsx_xfer_adma_callback, sc, BUS_DMA_WAITOK); + if (error) { + DPRINTF(3, "could not load DMA map\n"); + return error; + } + if (cmd->error) { + DPRINTF(3, "could not load DMA map\n"); + return cmd->error; + } + bus_dmamap_sync(sc->adma_tag, sc->dmap_adma, BUS_DMASYNC_PREWRITE); + + /* Tell the chip where the data buffer is and run the transfer. */ + WRITE4(sc, RTSX_HDBAR, sc->adma_segs[0].ds_addr); + WRITE4(sc, RTSX_HDBCTLR, RTSX_ADMA_MODE | RTSX_TRIG_DMA | + (read ? RTSX_DMA_READ : 0)); + + return (0); +} + +int +rtsx_request(device_t bus, device_t child, struct mmc_request *req) +{ + struct rtsx_softc *sc = device_get_softc(bus); + struct mmc_command *cmd = req->cmd; + u_int32_t *cmdbuf; + u_int8_t rsp_type; + u_int16_t r; + int ncmd; + int error = 0; + + DPRINTF(3, "executing cmd %u\n", cmd->opcode); + + mtx_lock(&sc->sc_mtx); + + /* Only one command at a time */ + if (sc->cur_req) { + mtx_unlock(&sc->sc_mtx); + return (EBUSY); + } + sc->cur_req = req; + + /* Refuse SDIO probe if the chip doesn't support SDIO. */ + if (cmd->opcode == IO_SEND_OP_COND && + !(sc->flags & RTSX_F_SDIO_SUPPORT)) { + error = ENOTSUP; + goto ret; + } + + rsp_type = rtsx_response_type(cmd->flags & 0xff00); + if (rsp_type == 0) { + device_printf(sc->sc_dev, "unknown response type 0x%x\n", + (cmd->flags & 0xff00)); + error = EINVAL; + goto ret; + } + + /* The command buffer queues commands the host controller will + * run asynchronously. */ + cmdbuf = (u_int32_t *)sc->cmdbuf; + ncmd = 0; + + /* Queue commands to set SD command index and argument. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_CMD0, 0xff, 0x40 | cmd->opcode); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_CMD1, 0xff, cmd->arg >> 24); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_CMD2, 0xff, cmd->arg >> 16); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_CMD3, 0xff, cmd->arg >> 8); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_CMD4, 0xff, cmd->arg); + + /* Queue command to set response type. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_CFG2, 0xff, rsp_type); + + /* Use the ping-pong buffer for commands which do not transfer data. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_CARD_DATA_SOURCE, + 0x01, RTSX_PINGPONG_BUFFER); + + /* Queue commands to perform SD transfer. */ + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_WRITE_REG_CMD, RTSX_SD_TRANSFER, + 0xff, RTSX_TM_CMD_RSP | RTSX_SD_TRANSFER_START); + rtsx_hostcmd(cmdbuf, &ncmd, + RTSX_CHECK_REG_CMD, RTSX_SD_TRANSFER, + RTSX_SD_TRANSFER_END|RTSX_SD_STAT_IDLE, + RTSX_SD_TRANSFER_END|RTSX_SD_STAT_IDLE); + + /* Queue commands to read back card status response.*/ + if (rsp_type == RTSX_SD_RSP_TYPE_R2) { + for (r = RTSX_PPBUF_BASE2 + 15; r > RTSX_PPBUF_BASE2; r--) + rtsx_hostcmd(cmdbuf, &ncmd, RTSX_READ_REG_CMD, r, 0, 0); + rtsx_hostcmd(cmdbuf, &ncmd, RTSX_READ_REG_CMD, RTSX_SD_CMD5, + 0, 0); + } else if (rsp_type != RTSX_SD_RSP_TYPE_R0) { + for (r = RTSX_SD_CMD0; r <= RTSX_SD_CMD4; r++) + rtsx_hostcmd(cmdbuf, &ncmd, RTSX_READ_REG_CMD, r, 0, 0); + } + + /* Load and sync command DMA buffer. */ + bus_dmamap_sync(sc->cmd_tag, sc->dmap_cmd, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->cmd_tag, sc->dmap_cmd, BUS_DMASYNC_PREWRITE); + + /* Run the command queue and wait for completion. */ + error = rtsx_hostcmd_send(sc, ncmd); + if (error == 0) { + sc->next_req_func = rtsx_request2; + mtx_unlock(&sc->sc_mtx); + return (0); + } + +ret: + sc->cur_req = NULL; + sc->next_req_func = NULL; + mtx_unlock(&sc->sc_mtx); + + cmd->flags |= MMC_REQ_DONE; + cmd->error = error; + req->done(req); + + return (0); +} + +static int +rtsx_request2(device_t bus, device_t child, struct mmc_request *req) +{ + struct rtsx_softc *sc = device_get_softc(bus); + struct mmc_command *cmd = req->cmd; + u_int32_t *cmdbuf = (u_int32_t *)sc->cmdbuf; + int error; + + mtx_assert(&sc->sc_mtx, MA_LOCKED); + + error = rtsx_intr_status(sc, RTSX_TRANS_OK_INT, hz); + if (error) { + sc->cur_req = NULL; + sc->next_req_func = NULL; + + cmd->flags |= MMC_REQ_DONE; + cmd->error = error; + req->done(req); + return (0); + } + + bus_dmamap_sync(sc->cmd_tag, sc->dmap_cmd, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->cmd_tag, sc->dmap_cmd, BUS_DMASYNC_POSTWRITE); + + /* Copy card response into mmc response buffer. */ + if (cmd->flags & MMC_RSP_PRESENT) { + /* Copy bytes like sdhci(4), which on little-endian uses + * different byte order for short and long responses... */ + if (cmd->flags & MMC_RSP_136) { + memcpy(cmd->resp, (caddr_t)sc->cmdbuf + 1, + sizeof(cmd->resp)); + } else { + /* First byte is CHECK_REG_CMD return value, second + * one is the command op code -- we skip those. */ + cmd->resp[0] = + ((be32toh(cmdbuf[0]) & 0x0000ffff) << 16) | + ((be32toh(cmdbuf[1]) & 0xffff0000) >> 16); + } + } + + if (cmd->data) { + error = rtsx_xfer(sc, cmd, cmdbuf); + + sc->next_req_func = rtsx_request3; + return (0); + } else { + sc->cur_req = NULL; + sc->next_req_func = NULL; + + cmd->flags |= MMC_REQ_DONE; + cmd->error = error; + req->done(req); + } + + return (0); +} + +static int +rtsx_request3(device_t bus, device_t child, struct mmc_request *req) +{ + struct rtsx_softc *sc = device_get_softc(bus); + struct mmc_command *cmd = req->cmd; + int error; + + mtx_assert(&sc->sc_mtx, MA_LOCKED); + + error = rtsx_intr_status(sc, RTSX_TRANS_OK_INT, 10*hz); + + bus_dmamap_sync(sc->adma_tag, sc->dmap_adma, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->data_tag, sc->dmap_data); + + if (error) { + u_int8_t stat1; + + if (rtsx_read(sc, RTSX_SD_STAT1, &stat1) == 0 && + (stat1 & RTSX_SD_CRC_ERR)) + device_printf(sc->sc_dev, "CRC error\n"); + } + + sc->cur_req = NULL; + sc->next_req_func = NULL; + + cmd->flags |= MMC_REQ_DONE; + cmd->error = error; + req->done(req); + + return (0); +} + +/* Prepare for another command. */ +void +rtsx_soft_reset(struct rtsx_softc *sc) +{ + DPRINTF(1, "soft reset\n"); + + /* Stop command transfer. */ + WRITE4(sc, RTSX_HCBCTLR, RTSX_STOP_CMD); + + (void)rtsx_write(sc, RTSX_CARD_STOP, RTSX_SD_STOP|RTSX_SD_CLR_ERR, + RTSX_SD_STOP|RTSX_SD_CLR_ERR); + + /* Stop DMA transfer. */ + WRITE4(sc, RTSX_HDBCTLR, RTSX_STOP_DMA); + (void)rtsx_write(sc, RTSX_DMACTL, RTSX_DMA_RST, RTSX_DMA_RST); + + (void)rtsx_write(sc, RTSX_RBCTL, RTSX_RB_FLUSH, RTSX_RB_FLUSH); +} + +int +rtsx_intr_status(struct rtsx_softc *sc, int mask, int timo) +{ + int status; + int error = 0; + + mask |= RTSX_TRANS_FAIL_INT; + + status = sc->intr_status & mask; +#if 0 /* XXX TIMEOUT */ + while (status == 0) { + if (tsleep(&sc->intr_status, PRIBIO, "rtsxintr", timo) + == EWOULDBLOCK) { + rtsx_soft_reset(sc); + error = ETIMEDOUT; + break; + } + status = sc->intr_status & mask; + } +#endif + sc->intr_status &= ~status; + + /* Has the card disappeared? */ + if (!(sc->flags & RTSX_F_CARD_PRESENT)) + error = ENODEV; + + if (error == 0 && (status & RTSX_TRANS_FAIL_INT)) + error = EIO; + + return error; +} + +void +rtsx_card_insert(struct rtsx_softc *sc) +{ + DPRINTF(1, "card inserted\n"); + + sc->flags |= RTSX_F_CARD_PRESENT; + (void)rtsx_led_enable(sc); + + /* Attach child MMC bus */ + if (sc->mmc_dev) + return; + + /* XXX: taskqueue w/ Giant */ + sc->mmc_dev = device_add_child(sc->sc_dev, "mmc", -1); + if (sc->mmc_dev) + (void)device_probe_and_attach(sc->mmc_dev); +} + +void +rtsx_card_eject(struct rtsx_softc *sc) +{ + DPRINTF(1, "card ejected\n"); + + sc->flags &= ~RTSX_F_CARD_PRESENT; + (void)rtsx_led_disable(sc); + + /* Destroy child bus if it exists */ + if (sc->mmc_dev) { + device_delete_child(sc->sc_dev, sc->mmc_dev); + sc->mmc_dev = NULL; + } +} + +void +rtsx_intr(void *arg) +{ + struct rtsx_softc *sc = arg; + u_int32_t enabled, status; + + mtx_lock(&sc->sc_mtx); + + enabled = READ4(sc, RTSX_BIER); + status = READ4(sc, RTSX_BIPR); + + /* Ack interrupts. */ + WRITE4(sc, RTSX_BIPR, status); + + if (((enabled & status) == 0) || status == 0xffffffff) { + mtx_unlock(&sc->sc_mtx); + return; + } + + if (status & RTSX_SD_INT) { + if (status & RTSX_SD_EXIST) { + if (!(sc->flags & RTSX_F_CARD_PRESENT)) + rtsx_card_insert(sc); + } else { + rtsx_card_eject(sc); + } + } + + if (status & (RTSX_TRANS_OK_INT | RTSX_TRANS_FAIL_INT)) { + sc->intr_status |= status; + if (sc->next_req_func) + sc->next_req_func(sc->sc_dev, NULL, sc->cur_req); + } + + mtx_unlock(&sc->sc_mtx); +} + +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) { + default: + return (EINVAL); + case MMCBR_IVAR_BUS_MODE: + *(int *)result = sc->mmc_host.ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: + *(int *)result = sc->mmc_host.ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: + *(int *)result = sc->mmc_host.ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: + *(int *)result = sc->mmc_host.ios.clock; + break; + case MMCBR_IVAR_F_MIN: + *(int *)result = sc->mmc_host.f_min; + break; + case MMCBR_IVAR_F_MAX: + *(int *)result = sc->mmc_host.f_max; + break; + case MMCBR_IVAR_HOST_OCR: + *(int *)result = RTSX_SUPPORT_VOLTAGE; + break; + case MMCBR_IVAR_MODE: + *(int *)result = sc->mmc_host.mode; + break; + case MMCBR_IVAR_OCR: + *(int *)result = sc->mmc_host.ocr; + break; + case MMCBR_IVAR_POWER_MODE: + *(int *)result = sc->mmc_host.ios.power_mode; + break; + case MMCBR_IVAR_VDD: + *(int *)result = sc->mmc_host.ios.vdd; + break; + case MMCBR_IVAR_VCCQ: + *(int *)result = sc->mmc_host.ios.vccq; + break; + case MMCBR_IVAR_CAPS: + *(int *)result = sc->mmc_host.caps; + break; + case MMCBR_IVAR_TIMING: + *(int *)result = sc->mmc_host.ios.timing; + break; + case MMCBR_IVAR_MAX_DATA: + *(int *)result = RTSX_DMA_DATA_BUFSIZE / MMC_SECTOR_SIZE; + break; + case MMCBR_IVAR_RETUNE_REQ: + *(int *)result = retune_req_none; + break; + } + + return (0); +} + +int +rtsx_write_ivar(device_t bus, device_t child, int which, + uintptr_t value) +{ + struct rtsx_softc *sc; + + sc = device_get_softc(bus); + switch (which) { + default: + return (EINVAL); + case MMCBR_IVAR_BUS_MODE: + sc->mmc_host.ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: + sc->mmc_host.ios.bus_width = value; + break; + case MMCBR_IVAR_CHIP_SELECT: + sc->mmc_host.ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: + sc->mmc_host.ios.clock = value; + break; + case MMCBR_IVAR_MODE: + sc->mmc_host.mode = value; + break; + case MMCBR_IVAR_OCR: + sc->mmc_host.ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: + sc->mmc_host.ios.power_mode = value; + break; + case MMCBR_IVAR_VDD: + sc->mmc_host.ios.vdd = value; + break; + case MMCBR_IVAR_VCCQ: + sc->mmc_host.ios.vccq = value; + break; + case MMCBR_IVAR_TIMING: + sc->mmc_host.ios.timing = value; + break; + /* These are read-only */ + case MMCBR_IVAR_CAPS: + case MMCBR_IVAR_HOST_OCR: + case MMCBR_IVAR_F_MIN: + case MMCBR_IVAR_F_MAX: + case MMCBR_IVAR_MAX_DATA: + return (EINVAL); + } + + return (0); +} + +int +rtsx_update_ios(device_t bus, device_t dev) +{ + int error; + struct rtsx_softc *sc; + struct mmc_ios *ios; + + sc = device_get_softc(bus); + + ios = &sc->mmc_host.ios; + + mtx_lock(&sc->sc_mtx); + + switch (ios->power_mode) { + case power_on: + break; + case power_off: + if (bootverbose) + device_printf(sc->sc_dev, "Powering down sd/mmc\n"); + + error = rtsx_bus_power_off(sc); + if (error) + goto ret; + + (void)rtsx_host_reset(sc); + break; + case power_up: + if (bootverbose) + device_printf(sc->sc_dev, "Powering up sd/mmc\n"); + + error = rtsx_bus_power_on(sc); + if (error) + goto ret; + break; + }; + + /* Set the bus width. */ + switch (ios->bus_width) { + case bus_width_1: + rtsx_set_bus_width(sc, 1); + break; + case bus_width_4: + rtsx_set_bus_width(sc, 4); + break; + case bus_width_8: + rtsx_set_bus_width(sc, 8); + break; + } + + error = rtsx_bus_clock(sc, ios->clock); + +ret: + mtx_unlock(&sc->sc_mtx); + return (error); +} + +int +rtsx_switch_vccq(device_t brdev, device_t reqdev) +{ + device_printf(brdev, "%s\n", __func__); + return (ENXIO); +} + +int +rtsx_get_ro(device_t brdev, device_t reqdev) +{ + + return (0); +} + +int +rtsx_acquire_host(device_t brdev, device_t reqdev) +{ + struct rtsx_softc *sc; + int error; + + sc = device_get_softc(brdev); + mtx_lock(&sc->sc_mtx); + while (sc->bus_busy) { + error = msleep(sc, &sc->sc_mtx, PCATCH, "mmchw", 0); + if (error != 0) { + mtx_unlock(&sc->sc_mtx); + return (error); + } + } + sc->bus_busy++; + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +int +rtsx_release_host(device_t brdev, device_t reqdev) +{ + struct rtsx_softc *sc; + + sc = device_get_softc(brdev); + mtx_lock(&sc->sc_mtx); + sc->bus_busy--; + wakeup(sc); + mtx_unlock(&sc->sc_mtx); + + return (0); +} + Property changes on: user/nwhitehorn/rtsx/rtsx.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/nwhitehorn/rtsx/rtsx_pci.c =================================================================== --- user/nwhitehorn/rtsx/rtsx_pci.c (nonexistent) +++ user/nwhitehorn/rtsx/rtsx_pci.c (revision 355229) @@ -0,0 +1,231 @@ +/* $OpenBSD: rtsx_pci.c,v 1.14 2017/09/06 13:07:38 jcs Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2012 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "rtsxreg.h" +#include "rtsxvar.h" +#include "mmcbr_if.h" + +#define PCI_VENDOR_REALTEK 0x10ec /* Realtek */ + +#define PCI_PRODUCT_REALTEK_RTS5208 0x5208 /* RTS5208 Card Reader */ +#define PCI_PRODUCT_REALTEK_RTS5209 0x5209 /* RTS5209 Card Reader */ +#define PCI_PRODUCT_REALTEK_RTS5227 0x5227 /* RTS5227 Card Reader */ +#define PCI_PRODUCT_REALTEK_RTS5229 0x5229 /* RTS5229 Card Reader */ +#define PCI_PRODUCT_REALTEK_RTS522A 0x522a /* RTS522A Card Reader */ +#define PCI_PRODUCT_REALTEK_RTS5249 0x5249 /* RTS5249 Card Reader */ +#define PCI_PRODUCT_REALTEK_RTS525A 0x525A /* RTS525A Card Reader */ +#define PCI_PRODUCT_REALTEK_RTL8402 0x5286 /* RTL8402 Card Reader */ +#define PCI_PRODUCT_REALTEK_RTL8411B 0x5287 /* RTL8411B Card Reader */ +#define PCI_PRODUCT_REALTEK_RTL8411 0x5289 /* RTL8411 Card Reader */ + +#define RTSX_PCI_BAR 0x10 +#define RTSX_PCI_BAR_525A 0x14 + +int rtsx_pci_probe(device_t); +int rtsx_pci_attach(device_t); +int rtsx_pci_detach(device_t); + +static device_method_t sdhci_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, rtsx_pci_probe), + DEVMETHOD(device_attach, rtsx_pci_attach), + DEVMETHOD(device_detach, rtsx_pci_detach), +#if 0 + DEVMETHOD(device_shutdown, rtsx_pci_shutdown), + DEVMETHOD(device_suspend, rtsx_pci_suspend), + DEVMETHOD(device_resume, rtsx_pci_resume), +#endif + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, rtsx_read_ivar), + DEVMETHOD(bus_write_ivar, rtsx_write_ivar), + + /* mmcbr_if */ + DEVMETHOD(mmcbr_update_ios, rtsx_update_ios), + DEVMETHOD(mmcbr_switch_vccq, rtsx_switch_vccq), + DEVMETHOD(mmcbr_request, rtsx_request), + DEVMETHOD(mmcbr_get_ro, rtsx_get_ro), + DEVMETHOD(mmcbr_acquire_host, rtsx_acquire_host), + DEVMETHOD(mmcbr_release_host, rtsx_release_host), + + DEVMETHOD_END +}; + +static driver_t rtsx_pci_driver = { + "rtsx", + sdhci_methods, + sizeof(struct rtsx_softc), +}; +static devclass_t rtsx_pci_devclass; + +DRIVER_MODULE(rtsx, pci, rtsx_pci_driver, rtsx_pci_devclass, NULL, + NULL); +MMC_DECLARE_BRIDGE(rtsx); + +struct pci_device_table rtsx_devs[] = { + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTS5209), + PCI_DESCR("Realtek 5209 Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTS5227), + PCI_DESCR("Realtek 5227 Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTS5229), + PCI_DESCR("Realtek 5229 Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTS522A), + PCI_DESCR("Realtek 522A Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTS5249), + PCI_DESCR("Realtek 5249 Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTS525A), + PCI_DESCR("Realtek 525A Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8402), + PCI_DESCR("Realtek 8402 Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8411), + PCI_DESCR("Realtek 8411 Memory Card Reader") }, + { PCI_DEV(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8411B), + PCI_DESCR("Realtek 8411B Memory Card Reader") }, +}; + +int +rtsx_pci_probe(device_t dev) +{ + uint8_t class = pci_get_class(dev); + const struct pci_device_table *tbl; + + /* + * Explicitly match the OTHER device class only. Some RTS5209 + * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED + * device class. Let sdhci(4) handle the SYSTEM/SDHC ones. + * XXX: maybe just set to low priority? sdhci(4) is already + * BUS_PROBE_GENERIC + */ + if (class != PCIC_OTHER) + return (ENXIO); + + tbl = PCI_MATCH(dev, rtsx_devs); + if (tbl == NULL) + return (ENXIO); + device_set_desc(dev, tbl->descr); +printf("AHOY\n"); + + return (BUS_PROBE_DEFAULT); +} + +int +rtsx_pci_attach(device_t dev) +{ + struct rtsx_softc *sc = device_get_softc(dev); + uint16_t devid = pci_get_device(dev); + int flags; + int bar = RTSX_PCI_BAR; + int err, i; + + sc->sc_dev = dev; + + if ((pci_read_config(dev, RTSX_CFG_PCI, 4) & RTSX_CFG_ASIC) != 0) { + device_printf(dev, "no asic\n"); + return (ENXIO); + } + + sc->irq_rid = 0; + i = 1; + if (pci_alloc_msi(dev, &i) == 0) + sc->irq_rid = 1; + sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, + RF_ACTIVE | (sc->irq_rid != 0 ? 0 : RF_SHAREABLE)); + if (sc->irq_res == NULL) { + device_printf(dev, "can't map interrupt\n"); + pci_release_msi(dev); + return (ENXIO); + } + + err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, rtsx_intr, sc, &sc->sc_intr); + if (err) { + device_printf(dev, "can't establish interrupt\n"); + return (ENXIO); + } + err = 0; + + switch (devid) { + case PCI_PRODUCT_REALTEK_RTS5209: + flags = RTSX_F_5209; + break; + case PCI_PRODUCT_REALTEK_RTS5229: + case PCI_PRODUCT_REALTEK_RTS5249: + flags = RTSX_F_5229; + break; + case PCI_PRODUCT_REALTEK_RTS525A: + flags = RTSX_F_525A; + bar = RTSX_PCI_BAR_525A; + break; + default: + flags = 0; + break; + } + + sc->mem_rid = bar; + sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, + RF_ACTIVE); + if (sc->sc_mem == NULL) { + device_printf(dev, "can't find registers\n"); + return (ENXIO); + } + + pci_enable_busmaster(dev); + + if (rtsx_attach(sc, bus_get_dma_tag(dev), flags) != 0) { + device_printf(dev, "can't initialize chip\n"); + return (ENXIO); + } + + return (0); +} + +int +rtsx_pci_detach(device_t dev) +{ + struct rtsx_softc *sc = device_get_softc(dev); + + rtsx_detach(sc); + + if (sc->sc_mem) + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, + sc->sc_mem); + if (sc->irq_res) { + bus_teardown_intr(dev, sc->irq_res, sc->sc_intr); + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, + sc->irq_res); + } + pci_release_msi(dev); + + return (0); +} + Property changes on: user/nwhitehorn/rtsx/rtsx_pci.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/nwhitehorn/rtsx/rtsxreg.h =================================================================== --- user/nwhitehorn/rtsx/rtsxreg.h (nonexistent) +++ user/nwhitehorn/rtsx/rtsxreg.h (revision 355229) @@ -0,0 +1,529 @@ +/* $OpenBSD: rtsxreg.h,v 1.4 2017/09/06 13:07:38 jcs Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2012 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _RTSXREG_H_ +#define _RTSXREG_H_ + +/* 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_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_MS_PWR_OFF 0x0C +#define RTSX_MS_PWR_ON 0x00 +#define RTSX_MS_PARTIAL_PWR_ON 0x04 + +#define RTSX_CARD_SHARE_MODE 0xFD52 +#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 0xFE53 + +/* 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 + +/* Internal clock. */ +#define RTSX_CLK_CTL 0xFC02 +#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 + +/* RC oscillator, default is 2M */ +#define RTSX_RCCTL 0xFC14 +#define RTSX_RCCTL_F_400K 0x0 +#define RTSX_RCCTL_F_2M 0x1 + +/* RTS5229-only. */ +#define RTSX_OLT_LED_CTL 0xFC1E +#define RTSX_OLT_LED_PERIOD 0x02 +#define RTSX_OLT_LED_AUTOBLINK 0x08 + +#define RTSX_GPIO_CTL 0xFC1F +#define RTSX_GPIO_LED_ON 0x02 + +/* 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_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_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_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_SD_CMD0 0xFDA9 +#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_DATA_STATE 0xFDB6 + +#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_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_CARD_GPIO_DIR 0xFD57 +#define RTSX_CARD_GPIO 0xFD58 +#define RTSX_CARD_GPIO_LED_OFF 0x01 + +/* ping-pong buffer 2 */ +#define RTSX_PPBUF_BASE2 0xFA00 +#define RTSX_PPBUF_SIZE 256 + +#if 0 +#define RTSX_SUPPORT_VOLTAGE (MMC_OCR_3_3V_3_4V|MMC_OCR_3_2V_3_3V|\ + MMC_OCR_3_1V_3_2V|MMC_OCR_3_0V_3_1V|\ + SD_OCR_SDHC_CAP) +#else +#define RTSX_SUPPORT_VOLTAGE 0 +#endif + +#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_DIR_TO_CARD 0x00 +#define RTSX_DMA_EN 0x01 +#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_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_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_VOLTAGE 0x08 +#define RTSX_PHY_VOLTAGE_MASK 0x3F + +#define RTSX_PETXCFG 0xFE49 +#define RTSX_PETXCFG_CLKREQ_PIN 0x08 + +#define RTSX_CARD_AUTO_BLINK 0xFD56 +#define RTSX_LED_BLINK_EN 0x08 +#define RTSX_LED_BLINK_SPEED 0x05 + +#define RTSX_WAKE_SEL_CTL 0xFE54 +#define RTSX_PME_FORCE_CTL 0xFE56 + +#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_SD30_DRIVE_SEL 0xFE5E +#define RTSX_SD30_DRIVE_SEL_3V3 0x01 +#define RTSX_SD30_DRIVE_SEL_1V8 0x03 +#define RTSX_SD30_DRIVE_SEL_MASK 0x07 + +#define RTSX_DUMMY_REG 0xFE90 + +#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_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 + +#endif Property changes on: user/nwhitehorn/rtsx/rtsxreg.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/nwhitehorn/rtsx/rtsxvar.h =================================================================== --- user/nwhitehorn/rtsx/rtsxvar.h (nonexistent) +++ user/nwhitehorn/rtsx/rtsxvar.h (revision 355229) @@ -0,0 +1,86 @@ +/* $OpenBSD: rtsxvar.h,v 1.6 2017/10/09 16:12:20 stsp Exp $ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2012 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _RTSXVAR_H_ +#define _RTSXVAR_H_ + +#include + +/* Number of registers to save for suspend/resume in terms of their ranges. */ +#define RTSX_NREG ((0XFDAE - 0XFDA0) + (0xFD69 - 0xFD32) + (0xFE34 - 0xFE20)) + +struct rtsx_softc { + device_t sc_dev; + + struct mtx sc_mtx; + + struct resource *irq_res, *sc_mem; + int irq_rid, mem_rid; + void *sc_intr; + + bus_dmamap_t dmap_cmd; /* DMA map for command transfer */ + bus_dma_tag_t cmd_tag; /* Tag for commands */ + void *cmdbuf; /* buffer for commands */ + bus_dma_segment_t cmd_segs[1]; /* segments for command buffer */ + bus_dmamap_t dmap_data; /* DMA map for data transfer */ + bus_dma_tag_t data_tag; /* Tag for data */ + bus_dmamap_t dmap_adma; /* DMA map for ADMA SG descriptors */ + void *admabuf; /* buffer for ADMA SG descriptors */ + bus_dma_segment_t adma_segs[1]; /* segments for ADMA SG buffer */ + bus_dma_tag_t adma_tag; /* Tag for ADMA */ + int flags; + u_int32_t intr_status; /* soft interrupt status */ + u_int8_t regs[RTSX_NREG];/* host controller state */ + u_int32_t regs4[6]; /* host controller state */ + + struct mmc_request *cur_req; + int (*next_req_func)(device_t, device_t, struct mmc_request *); + + struct mmc_host mmc_host; + + device_t mmc_dev; + int bus_busy; +}; + +/* Host controller functions called by the attachment driver. */ +int rtsx_attach(struct rtsx_softc *, bus_dma_tag_t, int); +int rtsx_detach(struct rtsx_softc *); +int rtsx_activate(struct device *, int); +void rtsx_intr(void *); + +int rtsx_write_ivar(device_t bus, device_t child, int which, uintptr_t); +int rtsx_read_ivar(device_t bus, device_t child, int which, uintptr_t *); + +int rtsx_update_ios(device_t brdev, device_t reqdev); +int rtsx_switch_vccq(device_t brdev, device_t reqdev); +int rtsx_request(device_t brdev, device_t reqdev, struct mmc_request *req); +int rtsx_get_ro(device_t brdev, device_t reqdev); +int rtsx_acquire_host(device_t brdev, device_t reqdev); +int rtsx_release_host(device_t brdev, device_t reqdev); + + +/* flag values */ +#define RTSX_F_CARD_PRESENT 0x01 +#define RTSX_F_SDIO_SUPPORT 0x02 +#define RTSX_F_5209 0x04 +#define RTSX_F_5229 0x08 +#define RTSX_F_5229_TYPE_C 0x10 +#define RTSX_F_525A 0x20 + +#endif Property changes on: user/nwhitehorn/rtsx/rtsxvar.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property