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