Page MenuHomeFreeBSD

D58630.id183348.diff
No OneTemporary

D58630.id183348.diff

diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -244,7 +244,7 @@
dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx
dev/random/darn.c optional powerpc64 !random_loadable | powerpc64le !random_loadable
dev/scc/scc_bfe_macio.c optional scc powermac
-dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci
+dev/sdhci/sdhci_fsl_fdt.c optional mpc85xx sdhci
dev/sec/sec.c optional sec mpc85xx
dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac
dev/sound/macio/davbus.c optional snd_davbus powermac
diff --git a/sys/dev/sdhci/fsl_sdhci.c b/sys/dev/sdhci/fsl_sdhci.c
--- a/sys/dev/sdhci/fsl_sdhci.c
+++ b/sys/dev/sdhci/fsl_sdhci.c
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
/*
- * SDHCI driver glue for Freescale i.MX SoC and QorIQ families.
+ * SDHCI driver glue for Freescale i.MX SoCs (eSDHC on i.MX5, uSDHC on i.MX6+).
*
* This supports both eSDHC (earlier SoCs) and uSDHC (more recent SoCs).
*/
@@ -52,15 +52,9 @@
#include <machine/bus.h>
#include <machine/resource.h>
-#ifdef __arm__
#include <machine/intr.h>
#include <arm/freescale/imx/imx_ccmvar.h>
-#endif
-
-#ifdef __powerpc__
-#include <powerpc/mpc85xx/mpc85xx.h>
-#endif
#include <dev/gpio/gpiobusvar.h>
@@ -178,7 +172,6 @@
{"fsl,imx6sl-usdhc", HWTYPE_USDHC},
{"fsl,imx53-esdhc", HWTYPE_ESDHC},
{"fsl,imx51-esdhc", HWTYPE_ESDHC},
- {"fsl,esdhc", HWTYPE_ESDHC},
{NULL, HWTYPE_NONE},
};
@@ -403,12 +396,6 @@
if (off == SDHCI_POWER_CONTROL) {
return;
}
-#ifdef __powerpc__
- /* XXX Reset doesn't seem to work as expected. Do nothing for now. */
- if (off == SDHCI_SOFTWARE_RESET)
- return;
-#endif
-
val32 = RD4(sc, off & ~3);
val32 &= ~(0xff << (off & 3) * 8);
val32 |= (val << (off & 3) * 8);
@@ -545,17 +532,14 @@
* On i.MX ESDHC hardware the card bus clock enable is in the usual
* sdhci register but it's a different bit, so transcribe it (note the
* difference between standard SDHCI_ and Freescale SDHC_ prefixes
- * here). On USDHC and QorIQ ESDHC hardware there is a force-on bit, but
- * no force-off for the card bus clock (the hardware runs the clock when
- * transfers are active no matter what), so we always say the clock is
- * on.
+ * here). On USDHC hardware there is a force-on bit, but no force-off
+ * for the card bus clock (the hardware runs the clock when transfers
+ * are active no matter what), so we always say the clock is on.
* XXX Maybe we should say it's in whatever state the sdhci driver last
* set it to.
*/
if (sc->hwtype == HWTYPE_ESDHC) {
-#ifdef __arm__
if (RD4(sc, SDHC_SYS_CTRL) & SDHC_CLK_SDCLKEN)
-#endif
val |= SDHCI_CLOCK_CARD_EN;
} else {
val |= SDHCI_CLOCK_CARD_EN;
@@ -587,10 +571,7 @@
* and the "base / 2^N" divisor scheme.
*/
if ((val & SDHCI_CLOCK_CARD_EN) == 0) {
-#ifdef __arm__
- /* On QorIQ, this is a reserved bit. */
WR4(sc, SDHCI_CLOCK_CONTROL, val32 & ~SDHC_CLK_SDCLKEN);
-#endif
return;
}
divisor = (val >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIVIDER_MASK;
@@ -765,35 +746,6 @@
return (sdhci_fdt_gpio_get_present(sc->gpio));
}
-#ifdef __powerpc__
-static uint32_t
-fsl_sdhci_get_platform_clock(device_t dev)
-{
- phandle_t node;
- uint32_t clock;
-
- node = ofw_bus_get_node(dev);
-
- /* Get sdhci node properties */
- if((OF_getprop(node, "clock-frequency", (void *)&clock,
- sizeof(clock)) <= 0) || (clock == 0)) {
- clock = mpc85xx_get_system_clock();
-
- if (clock == 0) {
- device_printf(dev,"Cannot acquire correct sdhci "
- "frequency from DTS.\n");
-
- return (0);
- }
- }
-
- if (bootverbose)
- device_printf(dev, "Acquired clock: %d from DTS\n", clock);
-
- return (clock);
-}
-#endif
-
static int
fsl_sdhci_detach(device_t dev)
{
@@ -826,10 +778,6 @@
{
struct fsl_sdhci_softc *sc = device_get_softc(dev);
int rid, err;
-#ifdef __powerpc__
- phandle_t node;
- uint32_t protctl;
-#endif
sc->dev = dev;
@@ -887,21 +835,13 @@
*
* XXX need named constants for this stuff.
*/
- /* P1022 has the '*_BRST_LEN' fields as reserved, always reading 0x10 */
- if (ofw_bus_is_compatible(dev, "fsl,p1022-esdhc"))
- WR4(sc, SDHC_WTMK_LVL, 0x10801080);
- else
- WR4(sc, SDHC_WTMK_LVL, 0x08800880);
+ WR4(sc, SDHC_WTMK_LVL, 0x08800880);
/*
* We read in native byte order in the main driver, but the register
* defaults to little endian.
*/
-#ifdef __powerpc__
- sc->baseclk_hz = fsl_sdhci_get_platform_clock(dev);
-#else
sc->baseclk_hz = imx_ccm_sdhci_hz();
-#endif
sc->slot.max_clk = sc->baseclk_hz;
/*
@@ -910,18 +850,6 @@
*/
sc->gpio = sdhci_fdt_gpio_setup(dev, &sc->slot);
-#ifdef __powerpc__
- node = ofw_bus_get_node(dev);
- /* Default to big-endian on powerpc */
- protctl = RD4(sc, SDHC_PROT_CTRL);
- protctl &= ~SDHC_PROT_EMODE_MASK;
- if (OF_hasprop(node, "little-endian"))
- protctl |= SDHC_PROT_EMODE_LITTLE;
- else
- protctl |= SDHC_PROT_EMODE_BIG;
- WR4(sc, SDHC_PROT_CTRL, protctl);
-#endif
-
sdhci_init_slot(dev, &sc->slot, 0);
sc->slot_init_done = true;
diff --git a/sys/dev/sdhci/sdhci_fsl_fdt.c b/sys/dev/sdhci/sdhci_fsl_fdt.c
--- a/sys/dev/sdhci/sdhci_fsl_fdt.c
+++ b/sys/dev/sdhci/sdhci_fsl_fdt.c
@@ -97,6 +97,7 @@
#define SDHCI_FSL_AUTOCERR_UHMS_SHIFT 16
#define SDHCI_FSL_HOST_VERSION 0xfc
+#define SDHCI_FSL_VENDOR_V22 0x12
#define SDHCI_FSL_VENDOR_V23 0x13
#define SDHCI_FSL_CAPABILITIES2 0x114
@@ -139,6 +140,10 @@
#define SDHCI_FSL_ESDHC_CTRL 0x40c
#define SDHCI_FSL_ESDHC_CTRL_SNOOP (1 << 6)
#define SDHCI_FSL_ESDHC_CTRL_FAF (1 << 18)
+/*
+ * Bit 19 is misnamed: per the T2080 RM (16.3.32) this is PCS (Peripheral
+ * Clock Select). Set = peripheral clock / 2, clear = platform clock.
+ */
#define SDHCI_FSL_ESDHC_CTRL_CLK_DIV2 (1 << 19)
#define SCFG_SDHCIOVSELCR 0x408
@@ -173,6 +178,26 @@
* requires special routine including syscon registers.
*/
#define SDHCI_FSL_MISSING_VCCQ_REG (1 << 5)
+/*
+ * Whether to route "peripheral clock / 2" into the eSDHC via ESDHCCTL[PCS].
+ * Layerscape parts and older SoCs feed the eSDHC through the peripheral clock
+ * and want the on-chip /2; some QorIQ parts (T-series) feed the eSDHC directly
+ * from the platform clock and must leave PCS clear.
+ */
+#define SDHCI_FSL_NO_PCS_SEL (1 << 6)
+/*
+ * Mask out UHS-I capability bits (SDR50/SDR104/DDR50 + HS400) reported by
+ * hardware. Boards without proper 1.8V regulator support can't perform the
+ * voltage switch these modes require; without masking, the MMC layer would
+ * try to switch and hang. Mirrors what Linux does in sdhci-of-esdhc.c.
+ */
+#define SDHCI_FSL_NO_UHS_CAPS (1 << 7)
+/*
+ * Enable ESDHCCTL[SNOOP] so DMA transfers participate in cache coherence.
+ * QorIQ CoreNet hardware supports snooped DMA; set this on any SoC where we
+ * want DMA-coherent operation regardless of the DTS "dma-coherent" property.
+ */
+#define SDHCI_FSL_DMA_SNOOP (1 << 8)
/*
* HS400 tuning is done in HS200 mode, but it has to be done using
@@ -200,6 +225,7 @@
uint32_t div_ratio;
uint8_t vendor_ver;
uint32_t flags;
+ uint32_t buf_order;
uint32_t (* read)(struct sdhci_fsl_fdt_softc *, bus_size_t);
void (* write)(struct sdhci_fsl_fdt_softc *, bus_size_t, uint32_t);
@@ -208,7 +234,8 @@
struct sdhci_fsl_fdt_soc_data {
int quirks;
int baseclk_div;
- uint8_t errata;
+ uint32_t errata;
+ uint32_t wml_value; /* SDHC_WTMK_LVL override; 0 = 512B/512B default. */
char *syscon_compat;
};
@@ -241,15 +268,42 @@
SDHCI_FSL_HS400_LIMITED_CLK_DIV,
};
+/*
+ * P1022: BRST_LEN fields in the watermark register are reserved and read back
+ * as 0x10; write a WML that matches to avoid a false "changed" mismatch and
+ * keep behavior consistent with the fsl_sdhci(4) legacy driver's handling.
+ */
+static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_p1022_soc_data = {
+ .quirks = SDHCI_QUIRK_DONT_SET_HISPD_BIT |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
+ .baseclk_div = 1,
+ .errata = SDHCI_FSL_NO_PCS_SEL | SDHCI_FSL_DMA_SNOOP,
+ .wml_value = 0x10801080,
+};
+
+/*
+ * Generic default targets PowerPC QorIQ eSDHC (T-series, P-series, MPC85xx),
+ * which is the common case for the "fsl,esdhc" compat fallback in-tree.
+ * - DONT_SET_HISPD_BIT: eSDHC has no HISPD bit at the SDHCI-standard offset.
+ * - DATA_TIMEOUT_USES_SDCLK: timeout counter runs off SDCLK, not TMCLK.
+ * - NO_PCS_SEL: eSDHC is fed directly from the platform clock; do not
+ * enable PCS. If a future Layerscape ARM SoC needs the /2 peripheral
+ * clock select, add a specific compat entry for it.
+ * R1B fix (SDHCI_QUIRK_NO_BUSY_IRQ) is applied at runtime from HOST_VERSION;
+ * no soc_data flag needed.
+ */
static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_gen_data = {
- .quirks = 0,
+ .quirks = SDHCI_QUIRK_DONT_SET_HISPD_BIT |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.baseclk_div = 1,
+ .errata = SDHCI_FSL_NO_PCS_SEL | SDHCI_FSL_DMA_SNOOP,
};
static const struct ofw_compat_data sdhci_fsl_fdt_compat_data[] = {
{"fsl,ls1012a-esdhc", (uintptr_t)&sdhci_fsl_fdt_ls1012a_soc_data},
{"fsl,ls1028a-esdhc", (uintptr_t)&sdhci_fsl_fdt_ls1028a_soc_data},
{"fsl,ls1046a-esdhc", (uintptr_t)&sdhci_fsl_fdt_ls1046a_soc_data},
+ {"fsl,p1022-esdhc", (uintptr_t)&sdhci_fsl_fdt_p1022_soc_data},
{"fsl,esdhc", (uintptr_t)&sdhci_fsl_fdt_gen_data},
{NULL, 0}
};
@@ -439,8 +493,14 @@
if (off == SDHCI_BUFFER)
return (bus_read_4(sc->mem_res, off));
- if (off == SDHCI_CAPABILITIES2)
- off = SDHCI_FSL_CAPABILITIES2;
+ if (off == SDHCI_CAPABILITIES2) {
+ val32 = RD4(sc, SDHCI_FSL_CAPABILITIES2);
+ if (sc->soc_data->errata & SDHCI_FSL_NO_UHS_CAPS)
+ val32 &= ~(SDHCI_CAN_SDR50 | SDHCI_CAN_SDR104 |
+ SDHCI_CAN_DDR50 | SDHCI_TUNE_SDR50 |
+ SDHCI_CAN_MMC_HS400);
+ return (val32);
+ }
val32 = RD4(sc, off);
@@ -864,7 +924,7 @@
{
struct sdhci_fsl_fdt_softc *sc;
struct mmc_host *host;
- uint32_t val, buf_order;
+ uint32_t val;
uintptr_t ocd_data;
uint64_t clk_hz;
phandle_t node;
@@ -920,16 +980,28 @@
}
ret = clk_get_by_ofw_index(dev, node, 0, &clk);
- if (ret != 0) {
- device_printf(dev, "Parent clock not found\n");
- goto err_free_irq;
- }
+ if (ret == 0) {
+ ret = clk_get_freq(clk, &clk_hz);
+ if (ret != 0) {
+ device_printf(dev,
+ "Could not get parent clock frequency\n");
+ goto err_free_irq;
+ }
+ } else {
+ pcell_t freq;
- ret = clk_get_freq(clk, &clk_hz);
- if (ret != 0) {
- device_printf(dev,
- "Could not get parent clock frequency\n");
- goto err_free_irq;
+ /*
+ * No clocks phandle; fall back to the "clock-frequency" DT
+ * property. Boards without a clock provider (e.g. PowerPC
+ * QorIQ) supply the eSDHC input clock this way.
+ */
+ if (OF_getencprop(node, "clock-frequency", &freq,
+ sizeof(freq)) <= 0) {
+ device_printf(dev, "no parent clock available\n");
+ ret = ENXIO;
+ goto err_free_irq;
+ }
+ clk_hz = freq;
}
sc->baseclk_hz = clk_hz / sc->soc_data->baseclk_div;
@@ -938,11 +1010,11 @@
if (OF_hasprop(node, "little-endian")) {
sc->read = read_le;
sc->write = write_le;
- buf_order = SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;
+ sc->buf_order = SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;
} else {
sc->read = read_be;
sc->write = write_be;
- buf_order = SDHCI_FSL_PROT_CTRL_BYTE_SWAP;
+ sc->buf_order = SDHCI_FSL_PROT_CTRL_BYTE_SWAP;
}
sc->vendor_ver = (RD4(sc, SDHCI_FSL_HOST_VERSION) &
@@ -961,7 +1033,7 @@
*/
val = RD4(sc, SDHCI_FSL_PROT_CTRL);
val &= ~SDHCI_FSL_PROT_CTRL_BYTE_MASK;
- WR4(sc, SDHCI_FSL_PROT_CTRL, val | buf_order);
+ WR4(sc, SDHCI_FSL_PROT_CTRL, val | sc->buf_order);
/*
* Gate the SD clock and set its source to
@@ -971,7 +1043,18 @@
val = RD4(sc, SDHCI_CLOCK_CONTROL);
WR4(sc, SDHCI_CLOCK_CONTROL, val & ~SDHCI_FSL_CLK_SDCLKEN);
val = RD4(sc, SDHCI_FSL_ESDHC_CTRL);
- WR4(sc, SDHCI_FSL_ESDHC_CTRL, val | SDHCI_FSL_ESDHC_CTRL_CLK_DIV2);
+ if (!(sc->soc_data->errata & SDHCI_FSL_NO_PCS_SEL))
+ val |= SDHCI_FSL_ESDHC_CTRL_CLK_DIV2;
+ /*
+ * Enable DMA snooping when the SoC is known to be cache-coherent
+ * (soc_data errata bit) or the DTS explicitly declares it. Without
+ * snoop the CPU cache holds stale copies of DMA'd data and reads
+ * return garbage even though bus_dmamap_sync completes cleanly.
+ */
+ if ((sc->soc_data->errata & SDHCI_FSL_DMA_SNOOP) ||
+ OF_hasprop(node, "dma-coherent"))
+ val |= SDHCI_FSL_ESDHC_CTRL_SNOOP;
+ WR4(sc, SDHCI_FSL_ESDHC_CTRL, val);
sc->slot.max_clk = sc->maxclk_hz;
sc->gpio = sdhci_fdt_gpio_setup(dev, &sc->slot);
@@ -988,8 +1071,9 @@
* watermark for different size blocks. However, 128 is the maximum
* allowed for the watermark, so PIO is limitted to 512 byte blocks.
*/
- WR4(sc, SDHCI_FSL_WTMK_LVL, SDHCI_FSL_WTMK_WR_512B |
- SDHCI_FSL_WTMK_RD_512B);
+ WR4(sc, SDHCI_FSL_WTMK_LVL,
+ sc->soc_data->wml_value != 0 ? sc->soc_data->wml_value :
+ (SDHCI_FSL_WTMK_WR_512B | SDHCI_FSL_WTMK_RD_512B));
ret = sdhci_init_slot(dev, &sc->slot, 0);
if (ret != 0)
@@ -1033,15 +1117,17 @@
static int
sdhci_fsl_fdt_probe(device_t dev)
{
+ const struct ofw_compat_data *ocd;
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_search_compatible(dev,
- sdhci_fsl_fdt_compat_data)->ocd_data)
+ ocd = ofw_bus_search_compatible(dev, sdhci_fsl_fdt_compat_data);
+ if (ocd->ocd_data == 0)
return (ENXIO);
device_set_desc(dev, "NXP QorIQ Layerscape eSDHC controller");
+
return (BUS_PROBE_DEFAULT);
}
@@ -1102,6 +1188,32 @@
sc = device_get_softc(dev);
+ /*
+ * RESET_ALL clears PROT_CTRL and WML. Re-apply the byte-order
+ * mode determined at attach and the block-size watermark so that
+ * SDHCI_BUFFER accesses continue to match host bus endianness and
+ * PIO reads/writes see BREN/BWEN asserted at 512-byte block
+ * boundaries. Neither is restored by the generic reset path.
+ */
+ val = RD4(sc, SDHCI_FSL_PROT_CTRL);
+ val &= ~SDHCI_FSL_PROT_CTRL_BYTE_MASK;
+ WR4(sc, SDHCI_FSL_PROT_CTRL, val | sc->buf_order);
+ WR4(sc, SDHCI_FSL_WTMK_LVL,
+ sc->soc_data->wml_value != 0 ? sc->soc_data->wml_value :
+ (SDHCI_FSL_WTMK_WR_512B | SDHCI_FSL_WTMK_RD_512B));
+
+ /*
+ * ESDHCCTL[SNOOP] also does not survive RESET_ALL. Re-enable it if
+ * the SoC needs cache-coherent DMA (see attach for the source of
+ * truth).
+ */
+ if ((sc->soc_data->errata & SDHCI_FSL_DMA_SNOOP) ||
+ OF_hasprop(ofw_bus_get_node(dev), "dma-coherent")) {
+ val = RD4(sc, SDHCI_FSL_ESDHC_CTRL);
+ val |= SDHCI_FSL_ESDHC_CTRL_SNOOP;
+ WR4(sc, SDHCI_FSL_ESDHC_CTRL, val);
+ }
+
/* Some registers have to be cleared by hand. */
if (slot->version >= SDHCI_SPEC_300) {
val = RD4(sc, SDHCI_FSL_TBCTL);
diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX
--- a/sys/powerpc/conf/MPC85XX
+++ b/sys/powerpc/conf/MPC85XX
@@ -128,6 +128,12 @@
device evdev # input event device support
device uinput # install /dev/uinput cdev
+# extres frameworks
+device clk
+device phy
+device regulator
+device syscon
+
# HID support
options HID_DEBUG # enable debug msgs
device hid # Generic HID support
diff --git a/sys/powerpc/conf/QORIQ64 b/sys/powerpc/conf/QORIQ64
--- a/sys/powerpc/conf/QORIQ64
+++ b/sys/powerpc/conf/QORIQ64
@@ -129,6 +129,12 @@
device evdev # input event device support
device uinput # install /dev/uinput cdev
+# extres frameworks
+device clk
+device phy
+device regulator
+device syscon
+
# HID support
options HID_DEBUG # enable debug msgs
device hid # Generic HID support

File Metadata

Mime Type
text/plain
Expires
Thu, Aug 27, 12:11 PM (3 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37383040
Default Alt Text
D58630.id183348.diff (15 KB)

Event Timeline