svn commit: r296093 - in head/sys: arm/allwinner arm/allwinner/a20 arm/allwinner/a31 dev/iicbus/twsi

Andrew Turner andrew at FreeBSD.org
Fri Feb 26 13:53:11 UTC 2016


Author: andrew
Date: Fri Feb 26 13:53:09 2016
New Revision: 296093
URL: https://svnweb.freebsd.org/changeset/base/296093

Log:
  Add the start of support for the Allwinner A31 clocks. It only adds
  support for the i2c, mmc, and gmac clocks. Further clocks can be added as
  needed.
  
  Submitted by:	Emmanuel Vadot <manu at bidouilliste.com>
  Reviewed by:	jmcneill
  Differential Revision:	https://reviews.freebsd.org/D5339

Added:
  head/sys/arm/allwinner/a31/a31_clk.c   (contents, props changed)
  head/sys/arm/allwinner/a31/a31_clk.h   (contents, props changed)
Modified:
  head/sys/arm/allwinner/a10_mmc.c
  head/sys/arm/allwinner/a20/a20_if_dwc.c
  head/sys/dev/iicbus/twsi/a10_twsi.c

Modified: head/sys/arm/allwinner/a10_mmc.c
==============================================================================
--- head/sys/arm/allwinner/a10_mmc.c	Fri Feb 26 12:46:34 2016	(r296092)
+++ head/sys/arm/allwinner/a10_mmc.c	Fri Feb 26 13:53:09 2016	(r296093)
@@ -48,8 +48,10 @@ __FBSDID("$FreeBSD$");
 #include <dev/mmc/mmcreg.h>
 #include <dev/mmc/mmcbrvar.h>
 
+#include <arm/allwinner/allwinner_machdep.h>
 #include <arm/allwinner/a10_clk.h>
 #include <arm/allwinner/a10_mmc.h>
+#include <arm/allwinner/a31/a31_clk.h>
 
 #define	A10_MMC_MEMRES		0
 #define	A10_MMC_IRQRES		1
@@ -144,6 +146,7 @@ a10_mmc_attach(device_t dev)
 	struct a10_mmc_softc *sc;
 	struct sysctl_ctx_list *ctx;
 	struct sysctl_oid_list *tree;
+	int clk;
 
 	sc = device_get_softc(dev);
 	sc->a10_dev = dev;
@@ -168,7 +171,24 @@ a10_mmc_attach(device_t dev)
 	}
 
 	/* Activate the module clock. */
-	if (a10_clk_mmc_activate(sc->a10_id) != 0) {
+	switch (allwinner_soc_type()) {
+#if defined(SOC_ALLWINNER_A10) || defined(SOC_ALLWINNER_A20)
+	case ALLWINNERSOC_A10:
+	case ALLWINNERSOC_A10S:
+	case ALLWINNERSOC_A20:
+		clk = a10_clk_mmc_activate(sc->a10_id);
+		break;
+#endif
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+	case ALLWINNERSOC_A31:
+	case ALLWINNERSOC_A31S:
+		clk = a31_clk_mmc_activate(sc->a10_id);
+		break;
+#endif
+	default:
+		clk = -1;
+	}
+	if (clk != 0) {
 		bus_teardown_intr(dev, sc->a10_res[A10_MMC_IRQRES],
 		    sc->a10_intrhand);
 		bus_release_resources(dev, a10_mmc_res_spec, sc->a10_res);
@@ -790,7 +810,23 @@ a10_mmc_update_ios(device_t bus, device_
 			return (error);
 
 		/* Set the MMC clock. */
-		error = a10_clk_mmc_cfg(sc->a10_id, ios->clock);
+		switch (allwinner_soc_type()) {
+#if defined(SOC_ALLWINNER_A10) || defined(SOC_ALLWINNER_A20)
+		case ALLWINNERSOC_A10:
+		case ALLWINNERSOC_A10S:
+		case ALLWINNERSOC_A20:
+			error = a10_clk_mmc_cfg(sc->a10_id, ios->clock);
+			break;
+#endif
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+		case ALLWINNERSOC_A31:
+		case ALLWINNERSOC_A31S:
+			error = a31_clk_mmc_cfg(sc->a10_id, ios->clock);
+			break;
+#endif
+		default:
+			error = ENXIO;
+		}
 		if (error != 0)
 			return (error);
 

Modified: head/sys/arm/allwinner/a20/a20_if_dwc.c
==============================================================================
--- head/sys/arm/allwinner/a20/a20_if_dwc.c	Fri Feb 26 12:46:34 2016	(r296092)
+++ head/sys/arm/allwinner/a20/a20_if_dwc.c	Fri Feb 26 13:53:09 2016	(r296093)
@@ -40,7 +40,9 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <arm/allwinner/allwinner_machdep.h>
 #include <arm/allwinner/a10_clk.h>
+#include <arm/allwinner/a31/a31_clk.h>
 
 #include "if_dwc_if.h"
 
@@ -60,9 +62,27 @@ a20_if_dwc_probe(device_t dev)
 static int
 a20_if_dwc_init(device_t dev)
 {
+	int clk;
 
 	/* Activate GMAC clock and set the pin mux to rgmii. */
-	if (a10_clk_gmac_activate(ofw_bus_get_node(dev)) != 0) {
+	switch (allwinner_soc_type()) {
+#if defined(SOC_ALLWINNER_A10) || defined(SOC_ALLWINNER_A20)
+	case ALLWINNERSOC_A10:
+	case ALLWINNERSOC_A10S:
+	case ALLWINNERSOC_A20:
+		clk = a10_clk_gmac_activate(ofw_bus_get_node(dev));
+		break;
+#endif
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+	case ALLWINNERSOC_A31:
+	case ALLWINNERSOC_A31S:
+		clk = a31_clk_gmac_activate(ofw_bus_get_node(dev));
+		break;
+#endif
+	default:
+		clk = -1;
+	}
+	if (clk != 0) {
 		device_printf(dev, "could not activate gmac module\n");
 		return (ENXIO);
 	}

Added: head/sys/arm/allwinner/a31/a31_clk.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/allwinner/a31/a31_clk.c	Fri Feb 26 13:53:09 2016	(r296093)
@@ -0,0 +1,295 @@
+/*-
+ * Copyright (c) 2013 Ganbold Tsagaankhuu <ganbold at freebsd.org>
+ * Copyright (c) 2016 Emmanuel Vadot <manu at bidouilliste.com>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+/*
+ * Simple clock driver for Allwinner A31
+ * Adapted from a10_clk.c
+*/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/a31/a31_clk.h>
+
+struct a31_ccm_softc {
+	struct resource		*res;
+	int			pll6_enabled;
+};
+
+static struct a31_ccm_softc *a31_ccm_sc = NULL;
+
+#define ccm_read_4(sc, reg)		\
+	bus_read_4((sc)->res, (reg))
+#define ccm_write_4(sc, reg, val)	\
+	bus_write_4((sc)->res, (reg), (val))
+
+#define PLL6_TIMEOUT	10
+
+static int
+a31_ccm_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_is_compatible(dev, "allwinner,sun6i-a31-ccm")) {
+		device_set_desc(dev, "Allwinner Clock Control Module");
+		return(BUS_PROBE_DEFAULT);
+	}
+
+	return (ENXIO);
+}
+
+static int
+a31_ccm_attach(device_t dev)
+{
+	struct a31_ccm_softc *sc = device_get_softc(dev);
+	int rid = 0;
+
+	if (a31_ccm_sc)
+		return (ENXIO);
+
+	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!sc->res) {
+		device_printf(dev, "could not allocate resource\n");
+		return (ENXIO);
+	}
+
+	a31_ccm_sc = sc;
+
+	return (0);
+}
+
+static device_method_t a31_ccm_methods[] = {
+	DEVMETHOD(device_probe,		a31_ccm_probe),
+	DEVMETHOD(device_attach,	a31_ccm_attach),
+	{ 0, 0 }
+};
+
+static driver_t a31_ccm_driver = {
+	"a31_ccm",
+	a31_ccm_methods,
+	sizeof(struct a31_ccm_softc),
+};
+
+static devclass_t a31_ccm_devclass;
+
+EARLY_DRIVER_MODULE(a31_ccm, simplebus, a31_ccm_driver, a31_ccm_devclass, 0, 0,
+    BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
+
+static int
+a31_clk_pll6_enable(void)
+{
+	struct a31_ccm_softc *sc;
+	uint32_t reg_value;
+	int i;
+
+	/* Datasheet recommand to use the default 600Mhz value */
+	sc = a31_ccm_sc;
+	if (sc->pll6_enabled)
+		return (0);
+	reg_value = ccm_read_4(sc, A31_CCM_PLL6_CFG);
+	reg_value |= A31_CCM_PLL_CFG_ENABLE;
+	ccm_write_4(sc, A31_CCM_PLL6_CFG, reg_value);
+
+	/* Wait for PLL to be stable */
+	for (i = 0; i < PLL6_TIMEOUT; i++)
+		if (!(ccm_read_4(sc, A31_CCM_PLL6_CFG) &
+			A31_CCM_PLL6_CFG_REG_LOCK))
+			break;
+	if (i == PLL6_TIMEOUT)
+		return (ENXIO);
+	sc->pll6_enabled = 1;
+
+	return (0);
+}
+
+static unsigned int
+a31_clk_pll6_get_rate(void)
+{
+	struct a31_ccm_softc *sc;
+	uint32_t k, n, reg_value;
+
+	sc = a31_ccm_sc;
+	reg_value = ccm_read_4(sc, A31_CCM_PLL6_CFG);
+	n = ((reg_value & A31_CCM_PLL_CFG_FACTOR_N) >>
+	        A31_CCM_PLL_CFG_FACTOR_N_SHIFT);
+	k = ((reg_value & A31_CCM_PLL_CFG_FACTOR_K) >>
+	        A31_CCM_PLL_CFG_FACTOR_K_SHIFT) + 1;
+
+	return ((A31_CCM_CLK_REF_FREQ * n * k) / 2);
+}
+
+int
+a31_clk_gmac_activate(phandle_t node)
+{
+	char *phy_type;
+	struct a31_ccm_softc *sc;
+	uint32_t reg_value;
+
+	sc = a31_ccm_sc;
+	if (sc == NULL)
+		return (ENXIO);
+
+	if (a31_clk_pll6_enable())
+		return (ENXIO);
+
+	/* Gating AHB clock for GMAC */
+	reg_value = ccm_read_4(sc, A31_CCM_AHB_GATING0);
+	reg_value |= A31_CCM_AHB_GATING_GMAC;
+	ccm_write_4(sc, A31_CCM_AHB_GATING0, reg_value);
+
+	/* Set GMAC mode. */
+	reg_value = A31_CCM_GMAC_CLK_MII;
+	if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type) > 0) {
+		if (strcasecmp(phy_type, "rgmii") == 0)
+ 			reg_value = A31_CCM_GMAC_CLK_RGMII |
+				    A31_CCM_GMAC_MODE_RGMII;
+		free(phy_type, M_OFWPROP);
+	}
+	ccm_write_4(sc, A31_CCM_GMAC_CLK, reg_value);
+
+	/* Reset gmac */
+	reg_value = ccm_read_4(sc, A31_CCM_AHB1_RST_REG0);
+	reg_value |= A31_CCM_AHB1_RST_REG0_GMAC;
+	ccm_write_4(sc, A31_CCM_AHB1_RST_REG0, reg_value);
+
+	return (0);
+}
+
+int
+a31_clk_mmc_activate(int devid)
+{
+	struct a31_ccm_softc *sc;
+	uint32_t reg_value;
+
+	sc = a31_ccm_sc;
+	if (sc == NULL)
+		return (ENXIO);
+
+	if (a31_clk_pll6_enable())
+		return (ENXIO);
+
+	/* Gating AHB clock for SD/MMC */
+	reg_value = ccm_read_4(sc, A31_CCM_AHB_GATING0);
+	reg_value |= A31_CCM_AHB_GATING_SDMMC0 << devid;
+	ccm_write_4(sc, A31_CCM_AHB_GATING0, reg_value);
+
+	/* Soft reset */
+	reg_value = ccm_read_4(sc, A31_CCM_AHB1_RST_REG0);
+	reg_value |= A31_CCM_AHB1_RST_REG0_SDMMC << devid;
+	ccm_write_4(sc, A31_CCM_AHB1_RST_REG0, reg_value);
+
+	return (0);
+}
+
+int
+a31_clk_mmc_cfg(int devid, int freq)
+{
+	struct a31_ccm_softc *sc;
+	uint32_t clksrc, m, n, ophase, phase, reg_value;
+	unsigned int pll_freq;
+
+	sc = a31_ccm_sc;
+	if (sc == NULL)
+		return (ENXIO);
+
+	freq /= 1000;
+	if (freq <= 400) {
+		pll_freq = A31_CCM_CLK_REF_FREQ / 1000;
+		clksrc = A31_CCM_SD_CLK_SRC_SEL_OSC24M;
+		ophase = 0;
+		phase = 0;
+		n = 2;
+	} else if (freq <= 25000) {
+		pll_freq = a31_clk_pll6_get_rate() / 1000;
+		clksrc = A31_CCM_SD_CLK_SRC_SEL_PLL6;
+		ophase = 0;
+		phase = 5;
+		n = 2;
+	} else if (freq <= 50000) {
+		pll_freq = a31_clk_pll6_get_rate() / 1000;
+		clksrc = A31_CCM_SD_CLK_SRC_SEL_PLL6;
+		ophase = 3;
+		phase = 5;
+		n = 0;
+	} else
+		return (EINVAL);
+	m = ((pll_freq / (1 << n)) / (freq)) - 1;
+	reg_value = ccm_read_4(sc, A31_CCM_MMC0_SCLK_CFG + (devid * 4));
+	reg_value &= ~A31_CCM_SD_CLK_SRC_SEL;
+	reg_value |= (clksrc << A31_CCM_SD_CLK_SRC_SEL_SHIFT);
+	reg_value &= ~A31_CCM_SD_CLK_PHASE_CTR;
+	reg_value |= (phase << A31_CCM_SD_CLK_PHASE_CTR_SHIFT);
+	reg_value &= ~A31_CCM_SD_CLK_DIV_RATIO_N;
+	reg_value |= (n << A31_CCM_SD_CLK_DIV_RATIO_N_SHIFT);
+	reg_value &= ~A31_CCM_SD_CLK_OPHASE_CTR;
+	reg_value |= (ophase << A31_CCM_SD_CLK_OPHASE_CTR_SHIFT);
+	reg_value &= ~A31_CCM_SD_CLK_DIV_RATIO_M;
+	reg_value |= m;
+	reg_value |= A31_CCM_PLL_CFG_ENABLE;
+	ccm_write_4(sc, A31_CCM_MMC0_SCLK_CFG + (devid * 4), reg_value);
+
+	return (0);
+}
+
+int
+a31_clk_i2c_activate(int devid)
+{
+	struct a31_ccm_softc *sc;
+	uint32_t reg_value;
+
+	sc = a31_ccm_sc;
+	if (sc == NULL)
+		return (ENXIO);
+
+	if (a31_clk_pll6_enable())
+		return (ENXIO);
+
+	/* Gating APB clock for I2C/TWI */
+	reg_value = ccm_read_4(sc, A31_CCM_APB2_GATING);
+	reg_value |= A31_CCM_APB2_GATING_TWI << devid;
+	ccm_write_4(sc, A31_CCM_APB2_GATING, reg_value);
+
+	/* Soft reset */
+	reg_value = ccm_read_4(sc, A31_CCM_APB2_RST);
+	reg_value |= A31_CCM_APB2_RST_TWI << devid;
+	ccm_write_4(sc, A31_CCM_APB2_RST, reg_value);
+
+	return (0);
+}

Added: head/sys/arm/allwinner/a31/a31_clk.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/allwinner/a31/a31_clk.h	Fri Feb 26 13:53:09 2016	(r296093)
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 2013 Ganbold Tsagaankhuu <ganbold at freebsd.org>
+ * Copyright (c) 2016 Emmanuel Vadot <manu at bidouilliste.com>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_A31_CLK_H_
+#define	_A31_CLK_H_
+
+#define	A31_CCM_PLL1_CFG		0x0000
+#define	A31_CCM_PLL2_CFG		0x0008
+#define	A31_CCM_PLL3_CFG		0x0010
+#define	A31_CCM_PLL4_CFG		0x0018
+#define	A31_CCM_PLL5_CFG		0x0020
+#define	A31_CCM_PLL6_CFG		0x0028
+#define	A31_CCM_PLL7_CFG		0x0030
+#define	A31_CCM_PLL8_CFG		0x0038
+#define	A31_CCM_MIPI_PLL_CFG		0x0040
+#define	A31_CCM_PLL9_CFG		0x0044
+#define	A31_CCM_PLL10_CFG		0x0048
+#define	A31_CCM_AXI_CFG_REG		0x0050
+#define	A31_CCM_AHB1_APB1_CFG		0x0054
+#define	A31_CCM_APB2_CLK_DIV		0x0058
+#define	A31_CCM_AHB_GATING0		0x0060
+#define	A31_CCM_AHB_GATING1		0x0064
+#define	A31_CCM_APB1_GATING		0x0068
+#define	A31_CCM_APB2_GATING		0x006c
+#define	A31_CCM_NAND0_SCLK_CFG		0x0080
+#define	A31_CCM_NAND1_SCLK_CFG		0x0084
+#define	A31_CCM_MMC0_SCLK_CFG		0x0088
+#define	A31_CCM_MMC1_SCLK_CFG		0x008c
+#define	A31_CCM_MMC2_SCLK_CFG		0x0090
+#define	A31_CCM_MMC3_SCLK_CFG		0x0094
+#define	A31_CCM_TS_CLK			0x0098
+#define	A31_CCM_SS_CLK			0x009c
+#define	A31_CCM_SPI0_CLK		0x00a0
+#define	A31_CCM_SPI1_CLK		0x00a4
+#define	A31_CCM_SPI2_CLK		0x00a8
+#define	A31_CCM_SPI3_CLK		0x00ac
+#define	A31_CCM_DAUDIO0_CLK		0x00b0
+#define	A31_CCM_DAUDIO1_CLK		0x00b4
+#define	A31_CCM_USBPHY_CLK		0x00cc
+#define	A31_CCM_GMAC_CLK		0x00d0
+#define	A31_CCM_MDFS_CLK		0x00f0
+#define	A31_CCM_DRAM_CLK		0x00f4
+#define	A31_CCM_DRAM_GATING		0x0100
+#define	A31_CCM_BE0_SCLK		0x0104
+#define	A31_CCM_BE1_SCLK		0x0108
+#define	A31_CCM_FE0_CLK			0x010c
+#define	A31_CCM_FE1_CLK			0x0110
+#define	A31_CCM_MP_CLK			0x0114
+#define	A31_CCM_LCD0_CH0_CLK		0x0118
+#define	A31_CCM_LCD1_CH0_CLK		0x011c
+#define	A31_CCM_LCD0_CH1_CLK		0x012c
+#define	A31_CCM_LCD1_CH1_CLK		0x0130
+#define	A31_CCM_CSI0_CLK		0x0134
+#define	A31_CCM_CSI1_CLK		0x0138
+#define	A31_CCM_VE_CLK			0x013c
+#define	A31_CCM_AUDIO_CODEC_CLK		0x0140
+#define	A31_CCM_AVS_CLK			0x0144
+#define	A31_CCM_DIGITAL_MIC_CLK		0x0148
+#define	A31_CCM_HDMI_CLK		0x0150
+#define	A31_CCM_PS_CLK			0x0154
+#define	A31_CCM_MBUS_SCLK_CFG0		0x015c
+#define	A31_CCM_MBUS_SCLK_CFG1		0x0160
+#define	A31_CCM_MIPI_DSI_CLK		0x0168
+#define	A31_CCM_MIPI_CSI0_CLK		0x016c
+#define	A31_CCM_DRC0_SCLK_CFG		0x0180
+#define	A31_CCM_DRC1_SCLK_CFG		0x0184
+#define	A31_CCM_DEU0_SCLK_CFG		0x0188
+#define	A31_CCM_DEU1_SCLK_CFG		0x018c
+#define	A31_CCM_GPU_CORE_CLK		0x01a0
+#define	A31_CCM_GPU_MEM_CLK		0x01a4
+#define	A31_CCM_GPU_HYD_CLK		0x01a8
+#define	A31_CCM_ATS_CLK			0x01b0
+#define	A31_CCM_TRACE_CLK		0x01b4
+#define	A31_CCM_PLL_LOCK_CFG		0x0200
+#define	A31_CCM_PLL1_LOCK_CFG		0x0204
+#define	A31_CCM_PLL1_BIAS		0x0220
+#define	A31_CCM_PLL2_BIAS		0x0224
+#define	A31_CCM_PLL3_BIAS		0x0228
+#define	A31_CCM_PLL4_BIAS		0x022c
+#define	A31_CCM_PLL5_BIAS		0x0230
+#define	A31_CCM_PLL6_BIAS		0x0234
+#define	A31_CCM_PLL7_BIAS		0x0238
+#define	A31_CCM_PLL8_BIAS		0x023c
+#define	A31_CCM_PLL9_BIAS		0x0240
+#define	A31_CCM_MIPI_PLL_BIAS		0x0244
+#define	A31_CCM_PLL10_BIAS		0x0248
+#define	A31_CCM_PLL1_PAT_CFG		0x0280
+#define	A31_CCM_PLL2_PAT_CFG		0x0284
+#define	A31_CCM_PLL3_PAT_CFG		0x0288
+#define	A31_CCM_PLL4_PAT_CFG		0x028c
+#define	A31_CCM_PLL5_PAT_CFG		0x0290
+#define	A31_CCM_PLL6_PAT_CFG		0x0294
+#define	A31_CCM_PLL7_PAT_CFG		0x0298
+#define	A31_CCM_PLL8_PAT_CFG		0x029c
+#define	A31_CCM_MIPI_PLL_PAT_CFG	0x02a0
+#define	A31_CCM_PLL9_PAT_CFG		0x02a4
+#define	A31_CCM_PLL10_PAT_CFG		0x02a8
+#define	A31_CCM_AHB1_RST_REG0		0x02c0
+#define	A31_CCM_AHB1_RST_REG1		0x02c4
+#define	A31_CCM_AHB1_RST_REG2		0x02c8
+#define	A31_CCM_APB1_RST		0x02d0
+#define	A31_CCM_APB2_RST		0x02d8
+#define	A31_CCM_CLK_OUTA		0x0300
+#define	A31_CCM_CLK_OUTB		0x0304
+#define	A31_CCM_CLK_OUTC		0x0308
+
+/* PLL6_CFG_REG */
+#define	A31_CCM_PLL6_CFG_REG_LOCK	(1 << 28)
+
+/* AHB_GATING_REG0 */
+#define	A31_CCM_AHB_GATING_SDMMC0	(1 << 8)
+#define	A31_CCM_AHB_GATING_GMAC		(1 << 17)
+
+#define	A31_CCM_PLL_CFG_ENABLE		(1U << 31)
+#define	A31_CCM_PLL_CFG_BYPASS		(1U << 30)
+#define	A31_CCM_PLL_CFG_PLL5		(1U << 25)
+#define	A31_CCM_PLL_CFG_PLL6		(1U << 24)
+#define	A31_CCM_PLL_CFG_FACTOR_N	0x1f00
+#define	A31_CCM_PLL_CFG_FACTOR_N_SHIFT	8
+#define	A31_CCM_PLL_CFG_FACTOR_K	0x30
+#define	A31_CCM_PLL_CFG_FACTOR_K_SHIFT	4
+#define	A31_CCM_PLL_CFG_FACTOR_M	0x3
+
+/* APB2_GATING */
+#define	A31_CCM_APB2_GATING_TWI	(1 << 0)
+
+/* AHB1_RST_REG0 */
+#define	A31_CCM_AHB1_RST_REG0_GMAC	(1 << 17)
+#define	A31_CCM_AHB1_RST_REG0_SDMMC	(1 << 8)
+
+/* APB2_RST_REG */
+#define	A31_CCM_APB2_RST_TWI	(1 << 0)
+
+
+/* GMAC */
+#define	A31_CCM_GMAC_CLK_DELAY_SHIFT	10
+#define	A31_CCM_GMAC_CLK_MODE_MASK	0x7
+#define	A31_CCM_GMAC_MODE_RGMII		(1 << 2)
+#define	A31_CCM_GMAC_CLK_MII		0x0
+#define	A31_CCM_GMAC_CLK_EXT_RGMII	0x1
+#define	A31_CCM_GMAC_CLK_RGMII		0x2
+
+/* SD/MMC */
+#define	A31_CCM_SD_CLK_SRC_SEL		0x3000000
+#define	A31_CCM_SD_CLK_SRC_SEL_SHIFT	24
+#define	A31_CCM_SD_CLK_SRC_SEL_OSC24M	0
+#define	A31_CCM_SD_CLK_SRC_SEL_PLL6	1
+#define	A31_CCM_SD_CLK_PHASE_CTR	0x700000
+#define	A31_CCM_SD_CLK_PHASE_CTR_SHIFT	20
+#define	A31_CCM_SD_CLK_DIV_RATIO_N	0x30000
+#define	A31_CCM_SD_CLK_DIV_RATIO_N_SHIFT	16
+#define	A31_CCM_SD_CLK_OPHASE_CTR	0x700
+#define	A31_CCM_SD_CLK_OPHASE_CTR_SHIFT	8
+#define	A31_CCM_SD_CLK_DIV_RATIO_M	0xf
+
+#define	A31_CCM_CLK_REF_FREQ		24000000U
+
+int a31_clk_gmac_activate(phandle_t);
+int a31_clk_mmc_activate(int);
+int a31_clk_mmc_cfg(int, int);
+int a31_clk_i2c_activate(int);
+
+#endif /* _A31_CLK_H_ */

Modified: head/sys/dev/iicbus/twsi/a10_twsi.c
==============================================================================
--- head/sys/dev/iicbus/twsi/a10_twsi.c	Fri Feb 26 12:46:34 2016	(r296092)
+++ head/sys/dev/iicbus/twsi/a10_twsi.c	Fri Feb 26 13:53:09 2016	(r296093)
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus_subr.h>
 
 #include <arm/allwinner/a10_clk.h>
+#include <arm/allwinner/a31/a31_clk.h>
 
 #include "iicbus_if.h"
 
@@ -62,6 +63,15 @@ __FBSDID("$FreeBSD$");
 #define	TWI_EFR		0x1C
 #define	TWI_LCR		0x20
 
+#define	A10_I2C	1
+#define	A31_I2C	2
+
+static struct ofw_compat_data compat_data[] = {
+	{"allwinner,sun4i-a10-i2c", A10_I2C},
+	{"allwinner,sun6i-a31-i2c", A31_I2C},
+	{NULL, 0},
+};
+
 static int
 a10_twsi_probe(device_t dev)
 {
@@ -71,7 +81,7 @@ a10_twsi_probe(device_t dev)
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
-	if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-i2c"))
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
 		return (ENXIO);
 
 	device_set_desc(dev, "Allwinner Integrated I2C Bus Controller");
@@ -82,11 +92,30 @@ static int
 a10_twsi_attach(device_t dev)
 {
 	struct twsi_softc *sc;
+	int clk;
 
 	sc = device_get_softc(dev);
 
 	/* Activate clock */
-	a10_clk_i2c_activate(device_get_unit(dev));
+	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
+#if defined(SOC_ALLWINNER_A10) || defined(SOC_ALLWINNER_A20)
+	case A10_I2C:
+		clk = a10_clk_i2c_activate(device_get_unit(dev));
+		break;
+#endif
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+	case A31_I2C:
+		clk = a31_clk_i2c_activate(device_get_unit(dev));
+		break;
+#endif
+	default:
+		clk = -1;
+	}
+
+	if (clk != 0) {
+		device_printf(dev, "could not activate i2c clock\n");
+		return (ENXIO);
+	}
 
 	sc->reg_data = TWI_DATA;
 	sc->reg_slave_addr = TWI_ADDR;


More information about the svn-src-all mailing list