Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168125375
D58630.id183348.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D58630.id183348.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58630: sdhci_fsl_fdt: Add support for T2080 eSDHC controller
Attached
Detach File
Event Timeline
Log In to Comment