Author: jhibbits
Date: Wed Nov  2 00:57:04 2016
New Revision: 308188
URL: https://svnweb.freebsd.org/changeset/base/308188

Log:
  Merge i.MX and PowerPC SDHCI drivers
  
  Summary:
  i.MX5 and PowerPC use a very similar eSDHC controller, which is also
  similar to the uSDHC controller used by i.MX6.  The imx_sdhci driver works
  almost completely with PowerPC, with some minor tweaks.
  
  There is one caveat with this: reset currently does not work on PowerPC, so 
has
  been #ifdef'd out until this can be tracked down and fixed.  If resets are 
done
  the controller will timeout all data transactions.  Without a reset, it 
appears
  to work just fine.
  
  This is part 3, following up r308186 and r308187.
  
  Test Plan:
  This has been tested on a PowerPC QorIQ P1022 board.  It has not been
  tested on i.MX, but no regressions are expected.
  
  Reviewed By: imp
  Differential Revision: https://reviews.freebsd.org/D8407

Deleted:
  head/sys/powerpc/mpc85xx/fsl_sdhc.c
  head/sys/powerpc/mpc85xx/fsl_sdhc.h
Modified:
  head/sys/conf/files.powerpc
  head/sys/dev/sdhci/fsl_sdhci.c

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc Wed Nov  2 00:54:39 2016        (r308187)
+++ head/sys/conf/files.powerpc Wed Nov  2 00:57:04 2016        (r308188)
@@ -63,6 +63,7 @@ dev/ofw/ofw_subr.c            optional        aim powerpc
 dev/powermac_nvram/powermac_nvram.c optional   powermac_nvram powermac
 dev/quicc/quicc_bfe_fdt.c      optional        quicc mpc85xx
 dev/scc/scc_bfe_macio.c                optional        scc powermac
+dev/sdhci/fsl_sdhci.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
@@ -137,7 +138,6 @@ powerpc/mpc85xx/atpic.c             optional        mpc85x
 powerpc/mpc85xx/ds1553_bus_fdt.c       optional        ds1553 fdt
 powerpc/mpc85xx/ds1553_core.c  optional        ds1553
 powerpc/mpc85xx/fsl_diu.c      optional        mpc85xx diu
-powerpc/mpc85xx/fsl_sdhc.c     optional        mpc85xx sdhc
 powerpc/mpc85xx/i2c.c          optional        iicbus fdt
 powerpc/mpc85xx/isa.c          optional        mpc85xx isa
 powerpc/mpc85xx/lbc.c          optional        mpc85xx

Modified: head/sys/dev/sdhci/fsl_sdhci.c
==============================================================================
--- head/sys/dev/sdhci/fsl_sdhci.c      Wed Nov  2 00:54:39 2016        
(r308187)
+++ head/sys/dev/sdhci/fsl_sdhci.c      Wed Nov  2 00:57:04 2016        
(r308188)
@@ -28,7 +28,7 @@
 __FBSDID("$FreeBSD$");
 
 /*
- * SDHCI driver glue for Freescale i.MX SoC family.
+ * SDHCI driver glue for Freescale i.MX SoC and QorIQ families.
  *
  * This supports both eSDHC (earlier SoCs) and uSDHC (more recent SoCs).
  */
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/types.h>
 #include <sys/bus.h>
 #include <sys/callout.h>
+#include <sys/endian.h>
 #include <sys/kernel.h>
 #include <sys/libkern.h>
 #include <sys/lock.h>
@@ -52,9 +53,11 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/bus.h>
 #include <machine/resource.h>
+#ifdef __arm__
 #include <machine/intr.h>
 
 #include <arm/freescale/imx/imx_ccmvar.h>
+#endif
 
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
@@ -146,7 +149,6 @@ struct fsl_sdhci_softc {
 #define         SDHC_PROT_CDSS         (1 << 7)
 
 #define        SDHC_SYS_CTRL           0x2c
-#define        SDHC_INT_STATUS         0x30
 
 /*
  * The clock enable bits exist in different registers for ESDHC vs USDHC, but
@@ -169,6 +171,7 @@ static struct ofw_compat_data compat_dat
        {"fsl,imx6sl-usdhc",    HWTYPE_USDHC},
        {"fsl,imx53-esdhc",     HWTYPE_ESDHC},
        {"fsl,imx51-esdhc",     HWTYPE_ESDHC},
+       {"fsl,esdhc",           HWTYPE_ESDHC},
        {NULL,                  HWTYPE_NONE},
 };
 
@@ -397,6 +400,11 @@ fsl_sdhci_write_1(device_t dev, struct s
        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);
@@ -531,17 +539,20 @@ fsl_sdhc_get_clock(struct fsl_sdhci_soft
            val |= SDHCI_CLOCK_INT_STABLE;
 
        /*
-        * On ESDHC hardware the card bus clock enable is in the usual sdhci
-        * register but it's a different bit, so transcribe it (note the
+        * 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 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 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.
         * 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;
@@ -565,15 +576,18 @@ fsl_sdhc_set_clock(struct fsl_sdhci_soft
        sc->sdclockreg_freq_bits = val & SDHCI_DIVIDERS_MASK;
        if (sc->hwtype == HWTYPE_ESDHC) {
                /*
-                * The ESDHC hardware requires the driver to manually start and
-                * stop the sd bus clock.  If the enable bit is not set, turn
-                * off the clock in hardware and we're done, otherwise decode
-                * the requested frequency.  ESDHC hardware is sdhci 2.0; the
-                * sdhci driver will use the original 8-bit divisor field and
-                * the "base / 2^N" divisor scheme.
+                * The i.MX5 ESDHC hardware requires the driver to manually
+                * start and stop the sd bus clock.  If the enable bit is not
+                * set, turn off the clock in hardware and we're done, otherwise
+                * decode the requested frequency.  ESDHC hardware is sdhci 2.0;
+                * the sdhci driver will use the original 8-bit divisor field
+                * 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;
 
                }
@@ -625,6 +639,7 @@ fsl_sdhc_set_clock(struct fsl_sdhci_soft
        val32 &= ~(SDHC_CLK_DIVISOR_MASK | SDHC_CLK_PRESCALE_MASK);
        val32 |= divisor << SDHC_CLK_DIVISOR_SHIFT;
        val32 |= prescale << SDHC_CLK_PRESCALE_SHIFT;
+       val32 |= SDHC_CLK_IPGEN;
        WR4(sc, SDHCI_CLOCK_CONTROL, val32);
 }
 
@@ -710,10 +725,10 @@ fsl_sdhci_intr(void *arg)
         */
        switch (sc->r1bfix_type) {
        case R1BFIX_NODATA:
-               intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_RESPONSE;
+               intmask = RD4(sc, SDHCI_INT_STATUS) & SDHCI_INT_RESPONSE;
                break;
        case R1BFIX_AC12:
-               intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_DATA_END;
+               intmask = RD4(sc, SDHCI_INT_STATUS) & SDHCI_INT_DATA_END;
                break;
        default:
                intmask = 0;
@@ -722,8 +737,8 @@ fsl_sdhci_intr(void *arg)
        if (intmask) {
                sc->r1bfix_timeout_at = getsbinuptime() + 250 * SBT_1MS;
                if (!fsl_sdhci_r1bfix_is_wait_done(sc)) {
-                       WR4(sc, SDHC_INT_STATUS, intmask);
-                       bus_barrier(sc->mem_res, SDHC_INT_STATUS, 4, 
+                       WR4(sc, SDHCI_INT_STATUS, intmask);
+                       bus_barrier(sc->mem_res, SDHCI_INT_STATUS, 4, 
                            BUS_SPACE_BARRIER_WRITE);
                }
        }
@@ -735,9 +750,53 @@ fsl_sdhci_intr(void *arg)
 static int
 fsl_sdhci_get_ro(device_t bus, device_t child)
 {
+       struct fsl_sdhci_softc *sc = device_get_softc(bus);
+
+       if (RD4(sc, SDHCI_PRESENT_STATE) & SDHC_PRES_WPSPL)
+               return (false);
+       return (true);
+}
+
+#ifdef __powerpc__
+static uint32_t
+fsl_sdhci_get_platform_clock(device_t dev)
+{
+       device_t parent;
+       phandle_t node;
+       uint32_t clock;
+
+       node = ofw_bus_get_node(dev);
 
-       return (false);
+       /* Get sdhci node properties */
+       if((OF_getprop(node, "clock-frequency", (void *)&clock,
+           sizeof(clock)) <= 0) || (clock == 0)) {
+
+               /*
+                * Trying to get clock from parent device (soc) if correct
+                * clock cannot be acquired from sdhci node.
+                */
+               parent = device_get_parent(dev);
+               node = ofw_bus_get_node(parent);
+
+               /* Get soc properties */
+               if ((OF_getprop(node, "bus-frequency", (void *)&clock,
+                   sizeof(clock)) <= 0) || (clock == 0)) {
+                       device_printf(dev,"Cannot acquire correct sdhci "
+                           "frequency from DTS.\n");
+
+                       return (0);
+               }
+               /* eSDHC clock is 1/2 platform clock. */
+               clock /= 2;
+       }
+
+       if (bootverbose)
+               device_printf(dev, "Acquired clock: %d from DTS\n", clock);
+
+       return (clock);
 }
+#endif
+
 
 static int
 fsl_sdhci_detach(device_t dev)
@@ -752,6 +811,7 @@ fsl_sdhci_attach(device_t dev)
        struct fsl_sdhci_softc *sc = device_get_softc(dev);
        int rid, err;
        phandle_t node;
+       uint32_t protctl;
 
        sc->dev = dev;
 
@@ -807,9 +867,23 @@ fsl_sdhci_attach(device_t dev)
         *
         * XXX need named constants for this stuff.
         */
-       WR4(sc, SDHC_WTMK_LVL, 0x08800880);
+#ifdef __powerpc__
+       /* P1022 has the '*_BRST_LEN' fields as reserved, always reading 0x10 */
+       if ((SVR_VER(mfspr(SPR_SVR)) & 0xfff6) == SVR_P1022 )
+               WR4(sc, SDHC_WTMK_LVL, 0x10801080);
+       else
+#endif
+               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;
 
        /*
@@ -830,6 +904,16 @@ fsl_sdhci_attach(device_t dev)
                /* XXX put real gpio hookup here. */
                sc->force_card_present = true;
        }
+#ifdef __powerpc__
+       /* 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
 
        callout_init(&sc->r1bfix_callout, 1);
        sdhci_init_slot(dev, &sc->slot, 0);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to