Source-Changes-HG archive

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

[src/perseant-stdc-iso10646]: src/sys/arch/arm/sunxi 2360922



details:   https://anonhg.NetBSD.org/src/rev/ec7b4ed5f9ff
branches:  perseant-stdc-iso10646
changeset: 850668:ec7b4ed5f9ff
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Jul 17 23:31:06 2017 +0000

description:
2360922

diffstat:

 sys/arch/arm/sunxi/sunxi_mmc.c |  967 +++++++++++++++++++++++++++++++++++++++++
 sys/arch/arm/sunxi/sunxi_mmc.h |  183 +++++++
 2 files changed, 1150 insertions(+), 0 deletions(-)

diffs (truncated from 1158 to 300 lines):

diff -r 5ecf68914b47 -r ec7b4ed5f9ff sys/arch/arm/sunxi/sunxi_mmc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/sunxi/sunxi_mmc.c    Mon Jul 17 23:31:06 2017 +0000
@@ -0,0 +1,967 @@
+/* $NetBSD: sunxi_mmc.c,v 1.3.2.2 2017/07/17 23:31:06 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2014-2017 Jared 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 <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.3.2.2 2017/07/17 23:31:06 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/gpio.h>
+
+#include <dev/sdmmc/sdmmcvar.h>
+#include <dev/sdmmc/sdmmcchip.h>
+#include <dev/sdmmc/sdmmc_ioreg.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <arm/sunxi/sunxi_mmc.h>
+
+enum sunxi_mmc_timing {
+       SUNXI_MMC_TIMING_400K,
+       SUNXI_MMC_TIMING_25M,
+       SUNXI_MMC_TIMING_50M,
+       SUNXI_MMC_TIMING_50M_DDR,
+       SUNXI_MMC_TIMING_50M_DDR_8BIT,
+};
+
+struct sunxi_mmc_delay {
+       u_int   output_phase;
+       u_int   sample_phase;
+};
+
+static const struct sunxi_mmc_delay sunxi_mmc_delays[] = {
+       [SUNXI_MMC_TIMING_400K]         = { 180,        180 },
+       [SUNXI_MMC_TIMING_25M]          = { 180,         75 },
+       [SUNXI_MMC_TIMING_50M]          = {  90,        120 },
+       [SUNXI_MMC_TIMING_50M_DDR]      = {  60,        120 },
+       [SUNXI_MMC_TIMING_50M_DDR_8BIT] = {  90,        180 },
+};
+
+#define SUNXI_MMC_NDESC                16
+#define        SUNXI_MMC_DMA_XFERLEN   0x10000
+#define        SUNXI_MMC_DMA_FTRGLEVEL 0x20070008
+
+struct sunxi_mmc_softc;
+
+static int     sunxi_mmc_match(device_t, cfdata_t, void *);
+static void    sunxi_mmc_attach(device_t, device_t, void *);
+static void    sunxi_mmc_attach_i(device_t);
+
+static int     sunxi_mmc_intr(void *);
+static int     sunxi_mmc_idma_setup(struct sunxi_mmc_softc *);
+
+static int     sunxi_mmc_host_reset(sdmmc_chipset_handle_t);
+static uint32_t        sunxi_mmc_host_ocr(sdmmc_chipset_handle_t);
+static int     sunxi_mmc_host_maxblklen(sdmmc_chipset_handle_t);
+static int     sunxi_mmc_card_detect(sdmmc_chipset_handle_t);
+static int     sunxi_mmc_write_protect(sdmmc_chipset_handle_t);
+static int     sunxi_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
+static int     sunxi_mmc_bus_clock(sdmmc_chipset_handle_t, int, bool);
+static int     sunxi_mmc_bus_width(sdmmc_chipset_handle_t, int);
+static int     sunxi_mmc_bus_rod(sdmmc_chipset_handle_t, int);
+static int     sunxi_mmc_signal_voltage(sdmmc_chipset_handle_t, int);
+static void    sunxi_mmc_exec_command(sdmmc_chipset_handle_t,
+                                     struct sdmmc_command *);
+static void    sunxi_mmc_card_enable_intr(sdmmc_chipset_handle_t, int);
+static void    sunxi_mmc_card_intr_ack(sdmmc_chipset_handle_t);
+
+static struct sdmmc_chip_functions sunxi_mmc_chip_functions = {
+       .host_reset = sunxi_mmc_host_reset,
+       .host_ocr = sunxi_mmc_host_ocr,
+       .host_maxblklen = sunxi_mmc_host_maxblklen,
+       .card_detect = sunxi_mmc_card_detect,
+       .write_protect = sunxi_mmc_write_protect,
+       .bus_power = sunxi_mmc_bus_power,
+       .bus_clock_ddr = sunxi_mmc_bus_clock,
+       .bus_width = sunxi_mmc_bus_width,
+       .bus_rod = sunxi_mmc_bus_rod,
+       .signal_voltage = sunxi_mmc_signal_voltage,
+       .exec_command = sunxi_mmc_exec_command,
+       .card_enable_intr = sunxi_mmc_card_enable_intr,
+       .card_intr_ack = sunxi_mmc_card_intr_ack,
+};
+
+struct sunxi_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_phandle;
+
+       void *sc_ih;
+       kmutex_t sc_intr_lock;
+       kcondvar_t sc_intr_cv;
+       kcondvar_t sc_idst_cv;
+
+       int sc_mmc_width;
+       int sc_mmc_present;
+
+       device_t sc_sdmmc_dev;
+
+       uint32_t sc_dma_ftrglevel;
+
+       uint32_t sc_idma_xferlen;
+       bus_dma_segment_t sc_idma_segs[1];
+       int sc_idma_nsegs;
+       bus_size_t sc_idma_size;
+       bus_dmamap_t sc_idma_map;
+       int sc_idma_ndesc;
+       void *sc_idma_desc;
+
+       uint32_t sc_intr_rint;
+       uint32_t sc_intr_mint;
+       uint32_t sc_idma_idst;
+
+       struct clk *sc_clk_ahb;
+       struct clk *sc_clk_mmc;
+       struct clk *sc_clk_output;
+       struct clk *sc_clk_sample;
+
+       struct fdtbus_reset *sc_rst_ahb;
+
+       struct fdtbus_gpio_pin *sc_gpio_cd;
+       int sc_gpio_cd_inverted;
+       struct fdtbus_gpio_pin *sc_gpio_wp;
+       int sc_gpio_wp_inverted;
+
+       struct fdtbus_regulator *sc_reg_vqmmc;
+};
+
+CFATTACH_DECL_NEW(sunxi_mmc, sizeof(struct sunxi_mmc_softc),
+       sunxi_mmc_match, sunxi_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 const char * const compatible[] = {
+       "allwinner,sun7i-a20-mmc",
+       NULL
+};
+
+static int
+sunxi_mmc_match(device_t parent, cfdata_t cf, void *aux)
+{
+       struct fdt_attach_args * const faa = aux;
+
+       return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+sunxi_mmc_attach(device_t parent, device_t self, void *aux)
+{
+       struct sunxi_mmc_softc * const sc = device_private(self);
+       struct fdt_attach_args * const faa = aux;
+       const int phandle = faa->faa_phandle;
+       char intrstr[128];
+       bus_addr_t addr;
+       bus_size_t size;
+
+       if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+               aprint_error(": couldn't get registers\n");
+               return;
+       }
+
+       sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
+       sc->sc_clk_mmc = fdtbus_clock_get(phandle, "mmc");
+       sc->sc_clk_output = fdtbus_clock_get(phandle, "output");
+       sc->sc_clk_sample = fdtbus_clock_get(phandle, "sample");
+
+#if notyet
+       if (sc->sc_clk_ahb == NULL || sc->sc_clk_mmc == NULL ||
+           sc->sc_clk_output == NULL || sc->sc_clk_sample == NULL) {
+#else
+       if (sc->sc_clk_ahb == NULL || sc->sc_clk_mmc == NULL) {
+#endif
+               aprint_error(": couldn't get clocks\n");
+               return;
+       }
+
+       sc->sc_rst_ahb = fdtbus_reset_get(phandle, "ahb");
+       if (sc->sc_rst_ahb == NULL) {
+               aprint_error(": couldn't get resets\n");
+               return;
+       }
+
+       sc->sc_reg_vqmmc = fdtbus_regulator_acquire(phandle, "vqmmc-supply");
+
+       if (clk_enable(sc->sc_clk_ahb) != 0 ||
+           clk_enable(sc->sc_clk_mmc) != 0) {
+               aprint_error(": couldn't enable clocks\n");
+               return;
+       }
+
+       if (fdtbus_reset_deassert(sc->sc_rst_ahb) != 0) {
+               aprint_error(": couldn't de-assert resets\n");
+               return;
+       }
+
+       sc->sc_dev = self;
+       sc->sc_phandle = phandle;
+       sc->sc_bst = faa->faa_bst;
+       sc->sc_dmat = faa->faa_dmat;
+       mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
+       cv_init(&sc->sc_intr_cv, "awinmmcirq");
+       cv_init(&sc->sc_idst_cv, "awinmmcdma");
+
+       if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+               aprint_error(": couldn't map registers\n");
+               return;
+       }
+
+       aprint_naive("\n");
+       aprint_normal(": SD/MMC controller\n");
+
+       sc->sc_gpio_cd = fdtbus_gpio_acquire(phandle, "cd-gpios",
+           GPIO_PIN_INPUT);
+       sc->sc_gpio_wp = fdtbus_gpio_acquire(phandle, "wp-gpios",
+           GPIO_PIN_INPUT);
+
+       sc->sc_gpio_cd_inverted = of_hasprop(phandle, "cd-inverted") ? 0 : 1;
+       sc->sc_gpio_wp_inverted = of_hasprop(phandle, "wp-inverted") ? 0 : 1;
+
+       sc->sc_dma_ftrglevel = SUNXI_MMC_DMA_FTRGLEVEL;
+
+       if (sunxi_mmc_idma_setup(sc) != 0) {
+               aprint_error_dev(self, "failed to setup DMA\n");
+               return;
+       }
+
+       if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+               aprint_error_dev(self, "failed to decode interrupt\n");
+               return;
+       }
+
+       sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_BIO, FDT_INTR_MPSAFE,
+           sunxi_mmc_intr, sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error_dev(self, "failed to establish interrupt on %s\n",
+                   intrstr);
+               return;
+       }
+       aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
+       config_interrupts(self, sunxi_mmc_attach_i);
+}
+
+static int
+sunxi_mmc_idma_setup(struct sunxi_mmc_softc *sc)
+{
+       int error;
+
+       sc->sc_idma_xferlen = SUNXI_MMC_DMA_XFERLEN;
+
+       sc->sc_idma_ndesc = SUNXI_MMC_NDESC;
+       sc->sc_idma_size = sizeof(struct sunxi_mmc_idma_descriptor) *
+           sc->sc_idma_ndesc;
+       error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_idma_size, 0,
+           sc->sc_idma_size, sc->sc_idma_segs, 1,
+           &sc->sc_idma_nsegs, BUS_DMA_WAITOK);
+       if (error)
+               return error;
+       error = bus_dmamem_map(sc->sc_dmat, sc->sc_idma_segs,
+           sc->sc_idma_nsegs, sc->sc_idma_size,
+           &sc->sc_idma_desc, BUS_DMA_WAITOK);
+       if (error)
+               goto free;



Home | Main Index | Thread Index | Old Index