Author: manu
Date: Mon Feb 26 21:27:42 2018
New Revision: 330037
URL: https://svnweb.freebsd.org/changeset/base/330037

Log:
  dwmmc: Add clock support and other improvements
  
  * If compiled with EXT_RESOURCES look up the "biu" and "ciu" clocks in
    the DT
  * Don't use custom property "bus-frequency" but the standard one
    "clock-frequency"
  * Use the DT property max-frequency and fall back to 200Mhz if it don't exists
  * Add more mmc caps suported by the controller
  * Always ack all interrupts
  * Subclassed driver can supply an update_ios so they can handle update
    the clocks accordingly
  * Take care of the DDR bit in update_ios (no functional change since we
    do not support voltage change for now)
  * Make use of the FDT bus-width property

Modified:
  head/sys/dev/mmc/host/dwmmc.c
  head/sys/dev/mmc/host/dwmmc_var.h

Modified: head/sys/dev/mmc/host/dwmmc.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc.c       Mon Feb 26 21:25:50 2018        
(r330036)
+++ head/sys/dev/mmc/host/dwmmc.c       Mon Feb 26 21:27:42 2018        
(r330037)
@@ -56,6 +56,10 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpu.h>
 #include <machine/intr.h>
 
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#endif
+
 #include <dev/mmc/host/dwmmc_reg.h>
 #include <dev/mmc/host/dwmmc_var.h>
 
@@ -341,14 +345,12 @@ dwmmc_intr(void *arg)
                dprintf("%s 0x%08x\n", __func__, reg);
 
                if (reg & DWMMC_CMD_ERR_FLAGS) {
-                       WRITE4(sc, SDMMC_RINTSTS, DWMMC_CMD_ERR_FLAGS);
                        dprintf("cmd err 0x%08x cmd 0x%08x\n",
                                reg, cmd->opcode);
                        cmd->error = MMC_ERR_TIMEOUT;
                }
 
                if (reg & DWMMC_DATA_ERR_FLAGS) {
-                       WRITE4(sc, SDMMC_RINTSTS, DWMMC_DATA_ERR_FLAGS);
                        dprintf("data err 0x%08x cmd 0x%08x\n",
                                reg, cmd->opcode);
                        cmd->error = MMC_ERR_FAILED;
@@ -361,25 +363,22 @@ dwmmc_intr(void *arg)
                if (reg & SDMMC_INTMASK_CMD_DONE) {
                        dwmmc_cmd_done(sc);
                        sc->cmd_done = 1;
-                       WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_CMD_DONE);
                }
 
-               if (reg & SDMMC_INTMASK_ACD) {
+               if (reg & SDMMC_INTMASK_ACD)
                        sc->acd_rcvd = 1;
-                       WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_ACD);
-               }
 
-               if (reg & SDMMC_INTMASK_DTO) {
+               if (reg & SDMMC_INTMASK_DTO)
                        sc->dto_rcvd = 1;
-                       WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_DTO);
-               }
 
                if (reg & SDMMC_INTMASK_CD) {
                        /* XXX: Handle card detect */
-                       WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_CD);
                }
        }
 
+       /* Ack interrupts */
+       WRITE4(sc, SDMMC_RINTSTS, reg);
+
        if (sc->use_pio) {
                if (reg & (SDMMC_INTMASK_RXDR|SDMMC_INTMASK_DTO)) {
                        pio_read(sc, cmd);
@@ -411,37 +410,88 @@ parse_fdt(struct dwmmc_softc *sc)
 {
        pcell_t dts_value[3];
        phandle_t node;
+       uint32_t bus_hz = 0, bus_width;
        int len;
+#ifdef EXT_RESOURCES
+       int error;
+#endif
 
        if ((node = ofw_bus_get_node(sc->dev)) == -1)
                return (ENXIO);
 
+       /* bus-width */
+       if (OF_getencprop(node, "bus-width", &bus_width, sizeof(uint32_t)) <= 0)
+               bus_width = 4;
+       if (bus_width >= 4)
+               sc->host.caps |= MMC_CAP_4_BIT_DATA;
+       if (bus_width >= 8)
+               sc->host.caps |= MMC_CAP_8_BIT_DATA;
+
+       /* max-frequency */
+       if (OF_getencprop(node, "max-frequency", &sc->max_hz, sizeof(uint32_t)) 
<= 0)
+               sc->max_hz = 200000000;
+
        /* fifo-depth */
        if ((len = OF_getproplen(node, "fifo-depth")) > 0) {
                OF_getencprop(node, "fifo-depth", dts_value, len);
                sc->fifo_depth = dts_value[0];
        }
 
-       /* num-slots */
+       /* num-slots (Deprecated) */
        sc->num_slots = 1;
        if ((len = OF_getproplen(node, "num-slots")) > 0) {
+               device_printf(sc->dev, "num-slots property is deprecated\n");
                OF_getencprop(node, "num-slots", dts_value, len);
                sc->num_slots = dts_value[0];
        }
 
+       /* clock-frequency */
+       if ((len = OF_getproplen(node, "clock-frequency")) > 0) {
+               OF_getencprop(node, "clock-frequency", dts_value, len);
+               bus_hz = dts_value[0];
+       }
+
+#ifdef EXT_RESOURCES
+       /* BIU (Bus Interface Unit clock) is optional */
+       error = clk_get_by_ofw_name(sc->dev, 0, "biu", &sc->biu);
+       if (sc->biu) {
+               error = clk_enable(sc->biu);
+               if (error != 0) {
+                       device_printf(sc->dev, "cannot enable biu clock\n");
+                       goto fail;
+               }
+       }
+
        /*
-        * We need some platform-specific code to know
-        * what the clock is supplied for our device.
-        * For now rely on the value specified in FDT.
+        * CIU (Controller Interface Unit clock) is mandatory
+        * if no clock-frequency property is given
         */
+       error = clk_get_by_ofw_name(sc->dev, 0, "ciu", &sc->ciu);
+       if (sc->ciu) {
+               error = clk_enable(sc->ciu);
+               if (error != 0) {
+                       device_printf(sc->dev, "cannot enable ciu clock\n");
+                       goto fail;
+               }
+               if (bus_hz != 0) {
+                       error = clk_set_freq(sc->ciu, bus_hz, 0);
+                       if (error != 0)
+                               device_printf(sc->dev,
+                                   "cannot set ciu clock to %u\n", bus_hz);
+               }
+               clk_get_freq(sc->ciu, &sc->bus_hz);
+       }
+#endif /* EXT_RESOURCES */
+
        if (sc->bus_hz == 0) {
-               if ((len = OF_getproplen(node, "bus-frequency")) <= 0)
-                       return (ENXIO);
-               OF_getencprop(node, "bus-frequency", dts_value, len);
-               sc->bus_hz = dts_value[0];
+               device_printf(sc->dev, "No bus speed provided\n");
+               goto fail;
        }
 
        return (0);
+
+fail:
+       return (ENXIO);
 }
 
 int
@@ -541,9 +591,10 @@ dwmmc_attach(device_t dev)
        WRITE4(sc, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE);
 
        sc->host.f_min = 400000;
-       sc->host.f_max = min(200000000, sc->bus_hz);
+       sc->host.f_max = sc->max_hz;
        sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
-       sc->host.caps = MMC_CAP_4_BIT_DATA;
+       sc->host.caps |= MMC_CAP_HSPEED;
+       sc->host.caps |= MMC_CAP_SIGNALING_330;
 
        device_add_child(dev, "mmc", -1);
        return (bus_generic_attach(dev));
@@ -608,6 +659,8 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
 {
        struct dwmmc_softc *sc;
        struct mmc_ios *ios;
+       uint32_t reg;
+       int ret = 0;
 
        sc = device_get_softc(brdev);
        ios = &sc->host.ios;
@@ -615,8 +668,6 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
        dprintf("Setting up clk %u bus_width %d\n",
                ios->clock, ios->bus_width);
 
-       dwmmc_setup_bus(sc, ios->clock);
-
        if (ios->bus_width == bus_width_8)
                WRITE4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT);
        else if (ios->bus_width == bus_width_4)
@@ -629,15 +680,22 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
                WRITE4(sc, SDMMC_CLKSEL, sc->sdr_timing);
        }
 
-       /*
-        * XXX: take care about DDR bit
-        *
-        * reg = READ4(sc, SDMMC_UHS_REG);
-        * reg |= (SDMMC_UHS_REG_DDR);
-        * WRITE4(sc, SDMMC_UHS_REG, reg);
-        */
+       /* Set DDR mode */
+       reg = READ4(sc, SDMMC_UHS_REG);
+       if (ios->timing == bus_timing_uhs_ddr50 ||
+           ios->timing == bus_timing_mmc_ddr52 ||
+           ios->timing == bus_timing_mmc_hs400)
+               reg |= (SDMMC_UHS_REG_DDR);
+       else
+               reg &= ~(SDMMC_UHS_REG_DDR);
+       WRITE4(sc, SDMMC_UHS_REG, reg);
 
-       return (0);
+       if (sc->update_ios)
+               ret = sc->update_ios(sc, ios);
+
+       dwmmc_setup_bus(sc, ios->clock);
+
+       return (ret);
 }
 
 static int
@@ -1032,7 +1090,6 @@ dwmmc_read_ivar(device_t bus, device_t child, int whic
                *(int *)result = sc->host.ios.vdd;
                break;
        case MMCBR_IVAR_CAPS:
-               sc->host.caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
                *(int *)result = sc->host.caps;
                break;
        case MMCBR_IVAR_MAX_DATA:

Modified: head/sys/dev/mmc/host/dwmmc_var.h
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_var.h   Mon Feb 26 21:25:50 2018        
(r330036)
+++ head/sys/dev/mmc/host/dwmmc_var.h   Mon Feb 26 21:27:42 2018        
(r330037)
@@ -33,6 +33,10 @@
 #ifndef DEV_MMC_HOST_DWMMC_VAR_H
 #define DEV_MMC_HOST_DWMMC_VAR_H
 
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#endif
+
 enum {
        HWTYPE_NONE,
        HWTYPE_ALTERA,
@@ -56,6 +60,8 @@ struct dwmmc_softc {
        uint32_t                pwren_inverted;
        u_int                   desc_count;
 
+       int                     (*update_ios)(struct dwmmc_softc *sc, struct 
mmc_ios *ios);
+
        bus_dma_tag_t           desc_tag;
        bus_dmamap_t            desc_map;
        struct idmac_desc       *desc_ring;
@@ -67,11 +73,17 @@ struct dwmmc_softc {
        uint32_t                dto_rcvd;
        uint32_t                acd_rcvd;
        uint32_t                cmd_done;
-       uint32_t                bus_hz;
+       uint64_t                bus_hz;
+       uint32_t                max_hz;
        uint32_t                fifo_depth;
        uint32_t                num_slots;
        uint32_t                sdr_timing;
        uint32_t                ddr_timing;
+
+#ifdef EXT_RESOURCES
+       clk_t                   biu;
+       clk_t                   ciu;
+#endif
 };
 
 DECLARE_CLASS(dwmmc_driver);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to