Index: user/nwhitehorn/rtsx/rtsx.c =================================================================== --- user/nwhitehorn/rtsx/rtsx.c (revision 355258) +++ user/nwhitehorn/rtsx/rtsx.c (revision 355259) @@ -1,1582 +1,1603 @@ /* $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); + cmd->data->len, cmd->data->block_size); 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)); + (cmd->data->block_size & 0xff)); rtsx_hostcmd(cmdbuf, &ncmd, RTSX_WRITE_REG_CMD, RTSX_SD_BYTE_CNT_H, 0xff, - (cmd->data->xfer_len >> 8)); + (cmd->data->block_size >> 8)); rtsx_hostcmd(cmdbuf, &ncmd, RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_L, 0xff, - ((cmd->data->len / cmd->data->xfer_len) & 0xff)); + (cmd->data->block_count & 0xff)); rtsx_hostcmd(cmdbuf, &ncmd, RTSX_WRITE_REG_CMD, RTSX_SD_BLOCK_CNT_H, 0xff, - ((cmd->data->len / cmd->data->xfer_len) >> 8)); + (cmd->data->block_count >> 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); + /* 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); + 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; +printf("Mapping DMA for %d segments, error %d\n", nsegs, error); 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; +printf("\tSeg %d at %#lx (%zd bytes)\n", i, paddr, 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); + if (read) + bus_dmamap_sync(sc->data_tag, sc->dmap_data, + BUS_DMASYNC_PREREAD); + else + bus_dmamap_sync(sc->data_tag, sc->dmap_data, + 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); + rsp_type = rtsx_response_type(MMC_RSP(cmd->flags)); if (rsp_type == 0) { - device_printf(sc->sc_dev, "unknown response type 0x%x\n", - (cmd->flags & 0xff00)); + device_printf(sc->sc_dev, "unknown response type 0x%lx\n", + MMC_RSP(cmd->flags)); 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; +printf("Error @ %d: %d\n", __LINE__, 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; + int i, 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; +printf("Error @ %d: %d\n", __LINE__, 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. */ + /* + * Copy card response into mmc response buffer, + * First byte is CHECK_REG_CMD return value, second is a check code + */ if (cmd->flags & MMC_RSP_PRESENT) { - /* Copy bytes like sdhci(4), which on little-endian uses - * different byte order for short and long responses... */ + caddr_t rspbuf = (caddr_t)sc->cmdbuf + 2; /* skip status */ if (cmd->flags & MMC_RSP_136) { - memcpy(cmd->resp, (caddr_t)sc->cmdbuf + 1, - sizeof(cmd->resp)); + rspbuf[15] = 1; + for (i = 0; i < 4; i++) { + memcpy(&cmd->resp[i], + rspbuf + i*sizeof(cmd->resp[i]), + sizeof(cmd->resp[i])); + cmd->resp[i] = be32toh(cmd->resp[i]); + } } 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); + memcpy(&cmd->resp[0], rspbuf, sizeof(cmd->resp[0])); + cmd->resp[0] = be32toh(cmd->resp[0]); } } 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; +printf("Error @ %d: %d\n", __LINE__, 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_sync(sc->data_tag, sc->dmap_data, 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; +printf("Error @ %d: %d\n", __LINE__, 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); + struct rtsx_softc *sc; + + sc = device_get_softc(brdev); + return (rtsx_bus_power_on(sc)); } 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); } Index: user/nwhitehorn/rtsx/rtsx_pci.c =================================================================== --- user/nwhitehorn/rtsx/rtsx_pci.c (revision 355258) +++ user/nwhitehorn/rtsx/rtsx_pci.c (revision 355259) @@ -1,231 +1,230 @@ /* $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); }