From ffc031ceb613b18d970372b61578f988d77e3233 Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 27 May 2014 15:30:24 +0000 Subject: MFC r264096, r264097, r264099 r264100, r264101, r264102, r264119: Fixes to the ti_sdhci and sdhci drivers (fix clock divisor calcs). Use the ti_sdhci driver instead of ti_mmchs for Pandaboard. --- sys/arm/conf/PANDABOARD | 1 + sys/arm/ti/omap4/files.omap4 | 3 +- sys/arm/ti/ti_sdhci.c | 77 ++++++++++++++++++++++++------- sys/boot/fdt/dts/arm/beaglebone-black.dts | 1 + sys/boot/fdt/dts/arm/pandaboard.dts | 1 + sys/dev/sdhci/sdhci.c | 3 +- 6 files changed, 67 insertions(+), 19 deletions(-) diff --git a/sys/arm/conf/PANDABOARD b/sys/arm/conf/PANDABOARD index 43d94f1..2a35b48 100644 --- a/sys/arm/conf/PANDABOARD +++ b/sys/arm/conf/PANDABOARD @@ -76,6 +76,7 @@ options PREEMPTION # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards +device sdhci # mmc/sd host controller # I2C support device iicbus diff --git a/sys/arm/ti/omap4/files.omap4 b/sys/arm/ti/omap4/files.omap4 index d9c043d..8f40095 100644 --- a/sys/arm/ti/omap4/files.omap4 +++ b/sys/arm/ti/omap4/files.omap4 @@ -6,7 +6,8 @@ arm/ti/ti_smc.S standard arm/ti/usb/omap_ehci.c optional usb ehci arm/ti/ti_sdma.c optional ti_sdma -arm/ti/ti_mmchs.c optional mmc +arm/ti/ti_sdhci.c optional sdhci +#arm/ti/ti_mmchs.c optional mmc arm/ti/omap4/omap4_l2cache.c optional pl310 arm/ti/omap4/omap4_prcm_clks.c standard diff --git a/sys/arm/ti/ti_sdhci.c b/sys/arm/ti/ti_sdhci.c index ee044f5..451a9b8 100644 --- a/sys/arm/ti/ti_sdhci.c +++ b/sys/arm/ti/ti_sdhci.c @@ -72,6 +72,8 @@ struct ti_sdhci_softc { uint32_t wp_gpio_pin; uint32_t cmd_and_mode; uint32_t sdhci_clkdiv; + boolean_t disable_highspeed; + boolean_t force_card_present; }; /* @@ -105,9 +107,13 @@ static struct ofw_compat_data compat_data[] = { #define MMCHS_SYSCONFIG 0x010 #define MMCHS_SYSCONFIG_RESET (1 << 1) #define MMCHS_SYSSTATUS 0x014 +#define MMCHS_SYSSTATUS_RESETDONE (1 << 0) #define MMCHS_CON 0x02C #define MMCHS_CON_DW8 (1 << 5) #define MMCHS_CON_DVAL_8_4MS (3 << 9) +#define MMCHS_SYSCTL 0x12C +#define MMCHS_SYSCTL_CLKD_MASK 0x3FF +#define MMCHS_SYSCTL_CLKD_SHIFT 6 #define MMCHS_SD_CAPA 0x140 #define MMCHS_SD_CAPA_VS18 (1 << 26) #define MMCHS_SD_CAPA_VS30 (1 << 25) @@ -161,19 +167,22 @@ ti_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) * but doesn't split them into low:high fields. Instead they're a * single number in the range 0..1023 and the number is exactly the * clock divisor (with 0 and 1 both meaning divide by 1). The SDHCI - * driver code expects a v2.0 divisor (value N is power of two in the - * range 0..128 and clock is divided by 2N). The shifting and masking + * driver code expects a v2.0 or v3.0 divisor. The shifting and masking * here extracts the MMCHS representation from the hardware word, cleans - * those bits out, applies the 2N adjustment, and plugs that into the - * bit positions for the 2.0 divisor in the returned register value. The - * ti_sdhci_write_2() routine performs the opposite transformation when - * the SDHCI driver writes to the register. + * those bits out, applies the 2N adjustment, and plugs the result into + * the bit positions for the 2.0 or 3.0 divisor in the returned register + * value. The ti_sdhci_write_2() routine performs the opposite + * transformation when the SDHCI driver writes to the register. */ if (off == SDHCI_CLOCK_CONTROL) { val32 = RD4(sc, SDHCI_CLOCK_CONTROL); - clkdiv = (val32 >> SDHCI_DIVIDER_HI_SHIFT) & 0xff; - val32 &= ~(0xff << SDHCI_DIVIDER_HI_SHIFT); - val32 |= (clkdiv / 2) << SDHCI_DIVIDER_SHIFT; + clkdiv = ((val32 >> MMCHS_SYSCTL_CLKD_SHIFT) & + MMCHS_SYSCTL_CLKD_MASK) / 2; + val32 &= ~(MMCHS_SYSCTL_CLKD_MASK << MMCHS_SYSCTL_CLKD_SHIFT); + val32 |= (clkdiv & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT; + if (slot->version >= SDHCI_SPEC_300) + val32 |= ((clkdiv >> SDHCI_DIVIDER_MASK_LEN) & + SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_HI_SHIFT; return (val32 & 0xffff); } @@ -193,8 +202,24 @@ static uint32_t ti_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct ti_sdhci_softc *sc = device_get_softc(dev); + uint32_t val32; + + val32 = RD4(sc, off); + + /* + * If we need to disallow highspeed mode due to the OMAP4 erratum, strip + * that flag from the returned capabilities. + */ + if (off == SDHCI_CAPABILITIES && sc->disable_highspeed) + val32 &= ~SDHCI_CAN_DO_HISPD; + + /* + * Force the card-present state if necessary. + */ + if (off == SDHCI_PRESENT_STATE && sc->force_card_present) + val32 |= SDHCI_CARD_PRESENT; - return (RD4(sc, off)); + return (val32); } static void @@ -228,15 +253,23 @@ ti_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t clkdiv, val32; /* - * Translate between the hardware and SDHCI 2.0 representations of the - * clock divisor. See the comments in ti_sdhci_read_2() for details. + * Translate between the hardware and SDHCI 2.0 or 3.0 representations + * of the clock divisor. See the comments in ti_sdhci_read_2() for + * details. */ if (off == SDHCI_CLOCK_CONTROL) { clkdiv = (val >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIVIDER_MASK; + if (slot->version >= SDHCI_SPEC_300) + clkdiv |= ((val >> SDHCI_DIVIDER_HI_SHIFT) & + SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_MASK_LEN; + clkdiv *= 2; + if (clkdiv > MMCHS_SYSCTL_CLKD_MASK) + clkdiv = MMCHS_SYSCTL_CLKD_MASK; val32 = RD4(sc, SDHCI_CLOCK_CONTROL); val32 &= 0xffff0000; - val32 |= val & ~(SDHCI_DIVIDER_MASK << SDHCI_DIVIDER_SHIFT); - val32 |= (clkdiv * 2) << SDHCI_DIVIDER_HI_SHIFT; + val32 |= val & ~(MMCHS_SYSCTL_CLKD_MASK << + MMCHS_SYSCTL_CLKD_SHIFT); + val32 |= clkdiv << MMCHS_SYSCTL_CLKD_SHIFT; WR4(sc, SDHCI_CLOCK_CONTROL, val32); return; } @@ -358,7 +391,7 @@ ti_sdhci_hw_init(device_t dev) /* Issue a softreset to the controller */ ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, MMCHS_SYSCONFIG_RESET); timeout = 1000; - while ((ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & MMCHS_SYSCONFIG_RESET)) { + while (!(ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & MMCHS_SYSSTATUS_RESETDONE)) { if (--timeout == 0) { device_printf(dev, "Error: Controller reset operation timed out\n"); break; @@ -458,12 +491,14 @@ ti_sdhci_attach(device_t dev) /* * Set the offset from the device's memory start to the MMCHS registers. + * Also for OMAP4 disable high speed mode due to erratum ID i626. */ if (ti_chip() == CHIP_OMAP_3) sc->mmchs_reg_off = OMAP3_MMCHS_REG_OFFSET; - else if (ti_chip() == CHIP_OMAP_4) + else if (ti_chip() == CHIP_OMAP_4) { sc->mmchs_reg_off = OMAP4_MMCHS_REG_OFFSET; - else if (ti_chip() == CHIP_AM335X) + sc->disable_highspeed = true; + } else if (ti_chip() == CHIP_AM335X) sc->mmchs_reg_off = AM335X_MMCHS_REG_OFFSET; else panic("Unknown OMAP device\n"); @@ -560,6 +595,14 @@ ti_sdhci_attach(device_t dev) } } + /* + * If the slot is flagged with the non-removable property, set our flag + * to always force the SDHCI_CARD_PRESENT bit on. + */ + node = ofw_bus_get_node(dev); + if (OF_hasprop(node, "non-removable")) + sc->force_card_present = true; + bus_generic_probe(dev); bus_generic_attach(dev); diff --git a/sys/boot/fdt/dts/arm/beaglebone-black.dts b/sys/boot/fdt/dts/arm/beaglebone-black.dts index 1833ec5..0efae4d 100644 --- a/sys/boot/fdt/dts/arm/beaglebone-black.dts +++ b/sys/boot/fdt/dts/arm/beaglebone-black.dts @@ -142,6 +142,7 @@ mmchs1@481D8000 { bus-width = <8>; status = "okay"; + non-removable; }; diff --git a/sys/boot/fdt/dts/arm/pandaboard.dts b/sys/boot/fdt/dts/arm/pandaboard.dts index 5544dc5..c89bf88 100644 --- a/sys/boot/fdt/dts/arm/pandaboard.dts +++ b/sys/boot/fdt/dts/arm/pandaboard.dts @@ -174,6 +174,7 @@ interrupts = <115>; interrupt-parent = <&GIC>; mmchs-device-id = <1>; + non-removable; /* XXX need real solution */ }; }; diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c index 92a9b4f..b8e03be 100644 --- a/sys/dev/sdhci/sdhci.c +++ b/sys/dev/sdhci/sdhci.c @@ -235,7 +235,8 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) slot->clock = clock; /* Turn off the clock. */ - WR2(slot, SDHCI_CLOCK_CONTROL, 0); + clk = RD2(slot, SDHCI_CLOCK_CONTROL); + WR2(slot, SDHCI_CLOCK_CONTROL, clk & ~SDHCI_CLOCK_CARD_EN); /* If no clock requested - left it so. */ if (clock == 0) return; -- cgit v1.1