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@bidouilliste.com>
Reviewed by:	jmcneill
Differential Revision:	https://reviews.freebsd.org/D5339
This commit is contained in:
Andrew Turner 2016-02-26 13:53:09 +00:00
parent afc055d90f
commit 461a7671c7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296093
5 changed files with 574 additions and 5 deletions

View File

@ -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_t child)
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);

View File

@ -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);
}

View File

@ -0,0 +1,295 @@
/*-
* Copyright (c) 2013 Ganbold Tsagaankhuu <ganbold@freebsd.org>
* Copyright (c) 2016 Emmanuel Vadot <manu@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);
}

View File

@ -0,0 +1,189 @@
/*-
* Copyright (c) 2013 Ganbold Tsagaankhuu <ganbold@freebsd.org>
* Copyright (c) 2016 Emmanuel Vadot <manu@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_ */

View File

@ -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;