Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/allwinner Add Allwinner SD/MMC driver. No DMA yet.



details:   https://anonhg.NetBSD.org/src/rev/abe486968fe0
branches:  trunk
changeset: 326987:abe486968fe0
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Tue Feb 25 00:08:29 2014 +0000

description:
Add Allwinner SD/MMC driver. No DMA yet.

diffstat:

 sys/arch/arm/allwinner/awin_io.c   |   12 +-
 sys/arch/arm/allwinner/awin_mmc.c  |  565 +++++++++++++++++++++++++++++++++++++
 sys/arch/arm/allwinner/awin_reg.h  |   29 +
 sys/arch/arm/allwinner/awin_sdhc.c |  153 ----------
 sys/arch/arm/allwinner/awin_var.h  |    8 +-
 sys/arch/arm/allwinner/files.awin  |    9 +-
 6 files changed, 612 insertions(+), 164 deletions(-)

diffs (truncated from 839 to 300 lines):

diff -r 2915ebb94f47 -r abe486968fe0 sys/arch/arm/allwinner/awin_io.c
--- a/sys/arch/arm/allwinner/awin_io.c  Mon Feb 24 23:54:09 2014 +0000
+++ b/sys/arch/arm/allwinner/awin_io.c  Tue Feb 25 00:08:29 2014 +0000
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.6 2014/02/20 21:48:38 matt Exp $");
+__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.7 2014/02/25 00:08:29 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -104,11 +104,11 @@
        { "awinwdt", OFFANDSIZE(TMR), NOPORT, NOINTR, AANY },
        { "awinusb", OFFANDSIZE(USB1), 0, NOINTR, AANY },
        { "awinusb", OFFANDSIZE(USB2), 1, NOINTR, AANY },
-       { "sdhc", OFFANDSIZE(SDMMC0), 0, AWIN_IRQ_SDMMC0, AANY },
-       { "sdhc", OFFANDSIZE(SDMMC1), 1, AWIN_IRQ_SDMMC1, AANY },
-       { "sdhc", OFFANDSIZE(SDMMC2), 2, AWIN_IRQ_SDMMC2, AANY },
-       { "sdhc", OFFANDSIZE(SDMMC3), 3, AWIN_IRQ_SDMMC3, AANY },
-       { "sdhc", OFFANDSIZE(SDMMC1), 4, AWIN_IRQ_SDMMC1, AANY },
+       { "awinmmc", OFFANDSIZE(SDMMC0), 0, AWIN_IRQ_SDMMC0, AANY },
+       { "awinmmc", OFFANDSIZE(SDMMC1), 1, AWIN_IRQ_SDMMC1, AANY },
+       { "awinmmc", OFFANDSIZE(SDMMC2), 2, AWIN_IRQ_SDMMC2, AANY },
+       { "awinmmc", OFFANDSIZE(SDMMC3), 3, AWIN_IRQ_SDMMC3, AANY },
+       { "awinmmc", OFFANDSIZE(SDMMC1), 4, AWIN_IRQ_SDMMC1, AANY },
        { "ahcisata", OFFANDSIZE(SATA), NOPORT, AWIN_IRQ_SATA, AANY },
        { "awiniic", OFFANDSIZE(TWI0), 0, AWIN_IRQ_TWI0, AANY },
        { "awiniic", OFFANDSIZE(TWI1), 1, AWIN_IRQ_TWI1, AANY },
diff -r 2915ebb94f47 -r abe486968fe0 sys/arch/arm/allwinner/awin_mmc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/allwinner/awin_mmc.c Tue Feb 25 00:08:29 2014 +0000
@@ -0,0 +1,565 @@
+/* $NetBSD: awin_mmc.c,v 1.1 2014/02/25 00:08:29 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "locators.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: awin_mmc.c,v 1.1 2014/02/25 00:08:29 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+
+#include <dev/sdmmc/sdmmcvar.h>
+#include <dev/sdmmc/sdmmcchip.h>
+#include <dev/sdmmc/sdmmc_ioreg.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+
+static int     awin_mmc_match(device_t, cfdata_t, void *);
+static void    awin_mmc_attach(device_t, device_t, void *);
+
+static int     awin_mmc_host_reset(sdmmc_chipset_handle_t);
+static uint32_t        awin_mmc_host_ocr(sdmmc_chipset_handle_t);
+static int     awin_mmc_host_maxblklen(sdmmc_chipset_handle_t);
+static int     awin_mmc_card_detect(sdmmc_chipset_handle_t);
+static int     awin_mmc_write_protect(sdmmc_chipset_handle_t);
+static int     awin_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
+static int     awin_mmc_bus_clock(sdmmc_chipset_handle_t, int);
+static int     awin_mmc_bus_width(sdmmc_chipset_handle_t, int);
+static int     awin_mmc_bus_rod(sdmmc_chipset_handle_t, int);
+static void    awin_mmc_exec_command(sdmmc_chipset_handle_t,
+                                     struct sdmmc_command *);
+static void    awin_mmc_card_enable_intr(sdmmc_chipset_handle_t, int);
+static void    awin_mmc_card_intr_ack(sdmmc_chipset_handle_t);
+
+static struct sdmmc_chip_functions awin_mmc_chip_functions = {
+       .host_reset = awin_mmc_host_reset,
+       .host_ocr = awin_mmc_host_ocr,
+       .host_maxblklen = awin_mmc_host_maxblklen,
+       .card_detect = awin_mmc_card_detect,
+       .write_protect = awin_mmc_write_protect,
+       .bus_power = awin_mmc_bus_power,
+       .bus_clock = awin_mmc_bus_clock,
+       .bus_width = awin_mmc_bus_width,
+       .bus_rod = awin_mmc_bus_rod,
+       .exec_command = awin_mmc_exec_command,
+       .card_enable_intr = awin_mmc_card_enable_intr,
+       .card_intr_ack = awin_mmc_card_intr_ack,
+};
+
+struct awin_mmc_softc {
+       device_t sc_dev;
+       bus_space_tag_t sc_bst;
+       bus_space_handle_t sc_bsh;
+       bus_dma_tag_t sc_dmat;
+
+       int sc_mmc_number;
+       int sc_mmc_width;
+
+       device_t sc_sdmmc_dev;
+       unsigned int sc_pll5_freq;
+       unsigned int sc_mod_clk;
+
+       bool sc_has_gpio_detect;
+       struct awin_gpio_pindata sc_gpio_detect;        /* card detect */
+       bool sc_has_gpio_wp;
+       struct awin_gpio_pindata sc_gpio_wp;            /* write protect */
+};
+
+CFATTACH_DECL_NEW(awin_mmc, sizeof(struct awin_mmc_softc),
+       awin_mmc_match, awin_mmc_attach, NULL, NULL);
+
+#define MMC_WRITE(sc, reg, val)        \
+       bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define MMC_READ(sc, reg) \
+       bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+
+static int
+awin_mmc_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct awinio_attach_args * const aio = aux;
+       const struct awin_locators * const loc = &aio->aio_loc;
+       const int port = cf->cf_loc[AWINIOCF_PORT];
+
+       if (strcmp(cf->cf_name, loc->loc_name))
+               return 0;
+
+       if (port != AWINIOCF_PORT_DEFAULT && port != loc->loc_port)
+               return 0;
+
+       return 1;
+}
+
+static void
+awin_mmc_probe_clocks(struct awin_mmc_softc *sc, struct awinio_attach_args *aio)
+{
+       uint32_t val, freq;
+       int n, k, p, div;
+
+       val = bus_space_read_4(aio->aio_core_bst, aio->aio_ccm_bsh,
+           AWIN_PLL5_CFG_REG);
+
+       n = (val >> 8) & 0x1f;
+       k = ((val >> 4) & 3) + 1;
+       p = 1 << ((val >> 16) & 3);
+
+       freq = 24000000 * n * k / p;
+
+       sc->sc_pll5_freq = freq;
+       if (sc->sc_pll5_freq > 400000000) {
+               div = 4;
+       } else {
+               div = 3;
+       }
+       sc->sc_mod_clk = sc->sc_pll5_freq / (div + 1);
+
+       awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+           AWIN_SD0_CLK_REG + (sc->sc_mmc_number * 8),
+           AWIN_PLL_CFG_ENABLE | AWIN_PLL_CFG_EXG_MODE | div, 0);
+
+#ifdef AWIN_MMC_DEBUG
+       aprint_normal_dev(sc->sc_dev, "PLL5 @ %u Hz\n", freq);
+#endif
+}
+
+static void
+awin_mmc_attach(device_t parent, device_t self, void *aux)
+{
+       struct awin_mmc_softc * const sc = device_private(self);
+       struct awinio_attach_args * const aio = aux;
+       const struct awin_locators * const loc = &aio->aio_loc;
+       struct sdmmcbus_attach_args saa;
+       prop_dictionary_t cfg = device_properties(self);
+       const char *pin_name;
+
+       sc->sc_dev = self;
+       sc->sc_bst = aio->aio_core_bst;
+       sc->sc_dmat = aio->aio_dmat;
+       sc->sc_mmc_number = loc->loc_port;
+       bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
+           loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+
+       aprint_naive("\n");
+       aprint_normal(": SD/MMC interface\n");
+
+       awin_mmc_probe_clocks(sc, aio);
+
+       if (prop_dictionary_get_cstring_nocopy(cfg, "detect-gpio", &pin_name)) {
+               if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_detect)) {
+                       aprint_error_dev(self,
+                           "failed to reserve GPIO \"%s\"\n", pin_name);
+               } else {
+                       sc->sc_has_gpio_detect = true;
+               }
+       }
+       if (prop_dictionary_get_cstring_nocopy(cfg, "wp-gpio", &pin_name)) {
+               if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_wp)) {
+                       aprint_error_dev(self,
+                           "failed to reserve GPIO \"%s\"\n", pin_name);
+               } else {
+                       sc->sc_has_gpio_wp = true;
+               }
+       }
+
+       awin_mmc_host_reset(sc);
+       awin_mmc_bus_width(sc, 1);
+
+       memset(&saa, 0, sizeof(saa));
+       saa.saa_busname = "sdmmc";
+       saa.saa_sct = &awin_mmc_chip_functions;
+       saa.saa_sch = sc;
+       saa.saa_clkmin = 400;
+       saa.saa_clkmax = 52000;
+       saa.saa_caps = SMC_CAPS_4BIT_MODE|
+                      SMC_CAPS_8BIT_MODE|
+                      SMC_CAPS_SD_HIGHSPEED|
+                      SMC_CAPS_MMC_HIGHSPEED|
+                      SMC_CAPS_AUTO_STOP;
+
+       sc->sc_sdmmc_dev = config_found(self, &saa, NULL);
+}
+
+static int
+awin_mmc_host_reset(sdmmc_chipset_handle_t sch)
+{
+       struct awin_mmc_softc *sc = sch;
+
+#ifdef AWIN_MMC_DEBUG
+       aprint_normal_dev(sc->sc_dev, "host reset\n");
+#endif
+
+       MMC_WRITE(sc, AWIN_MMC_GCTRL,
+           MMC_READ(sc, AWIN_MMC_GCTRL) | __BITS(2,0));
+
+       return 0;
+}
+
+static uint32_t
+awin_mmc_host_ocr(sdmmc_chipset_handle_t sch)
+{
+       return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
+}
+
+static int
+awin_mmc_host_maxblklen(sdmmc_chipset_handle_t sch)
+{
+       return 4096;
+}
+
+static int
+awin_mmc_card_detect(sdmmc_chipset_handle_t sch)
+{
+       struct awin_mmc_softc *sc = sch;
+
+       if (sc->sc_has_gpio_detect == false) {
+               return 1;       /* no card detect pin, assume present */
+       } else {
+               return awin_gpio_pindata_read(&sc->sc_gpio_detect);
+       }
+}
+
+static int
+awin_mmc_write_protect(sdmmc_chipset_handle_t sch)
+{
+       struct awin_mmc_softc *sc = sch;
+
+       if (sc->sc_has_gpio_wp == false) {
+               return 0;       /* no write protect pin, assume rw */
+       } else {
+               return awin_gpio_pindata_read(&sc->sc_gpio_wp);
+       }
+}
+
+static int
+awin_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
+{
+       return 0;
+}
+



Home | Main Index | Thread Index | Old Index