From 322e71d889175c1517253ce65f74e7a233d837e0 Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 28 Dec 2017 18:11:13 +0000 Subject: [PATCH] Add support for the 2nd clock control module on the Allwinner H3/H5. --- sys/dev/fdt/sxiccmu.c | 60 +++++++++++++++++++++++++++++++++++- sys/dev/fdt/sxiccmu_clocks.h | 19 ++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/sys/dev/fdt/sxiccmu.c b/sys/dev/fdt/sxiccmu.c index f84fb44e7f2..107f45404b8 100644 --- a/sys/dev/fdt/sxiccmu.c +++ b/sys/dev/fdt/sxiccmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sxiccmu.c,v 1.13 2017/12/26 09:31:51 kevlo Exp $ */ +/* $OpenBSD: sxiccmu.c,v 1.14 2017/12/28 18:11:13 kettenis Exp $ */ /* * Copyright (c) 2007,2009 Dale Rahn * Copyright (c) 2013 Artturi Alm @@ -96,6 +96,7 @@ uint32_t sxiccmu_a80_get_frequency(struct sxiccmu_softc *, uint32_t); int sxiccmu_a80_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t); int sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); +uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t); uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t); int sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); @@ -125,6 +126,7 @@ sxiccmu_match(struct device *parent, void *match, void *aux) OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || OF_is_compatible(node, "allwinner,sun8i-a33-ccu") || OF_is_compatible(node, "allwinner,sun8i-h3-ccu") || + OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") || OF_is_compatible(node, "allwinner,sun9i-a80-ccu") || OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") || OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") || @@ -174,6 +176,14 @@ sxiccmu_attach(struct device *parent, struct device *self, void *aux) sc->sc_nresets = nitems(sun8i_h3_resets); sc->sc_get_frequency = sxiccmu_h3_get_frequency; sc->sc_set_frequency = sxiccmu_h3_set_frequency; + } else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu")) { + KASSERT(faa->fa_nreg > 0); + sc->sc_gates = sun8i_h3_r_gates; + sc->sc_ngates = nitems(sun8i_h3_r_gates); + sc->sc_resets = sun8i_h3_r_resets; + sc->sc_nresets = nitems(sun8i_h3_r_resets); + sc->sc_get_frequency = sxiccmu_h3_r_get_frequency; + sc->sc_set_frequency = sxiccmu_nop_set_frequency; } else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) { KASSERT(faa->fa_nreg > 0); sc->sc_gates = sun9i_a80_gates; @@ -1049,6 +1059,54 @@ sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) return 0; } +#define H3_AHB0_CLK_REG 0x0000 +#define H3_AHB0_CLK_SRC_SEL (0x3 << 16) +#define H3_AHB0_CLK_SRC_SEL_OSC32K (0x0 << 16) +#define H3_AHB0_CLK_SRC_SEL_OSC24M (0x1 << 16) +#define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0 (0x2 << 16) +#define H3_AHB0_CLK_SRC_SEL_IOSC (0x3 << 16) +#define H3_AHB0_CLK_PRE_DIV(x) ((((x) >> 8) & 0x1f) + 1) +#define H3_AHB0_CLK_RATIO(x) (1 << (((x) >> 4) & 3)) +#define H3_APB0_CFG_REG 0x000c +#define H3_APB0_CLK_RATIO(x) (1 << ((x) & 1)) + +uint32_t +sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) +{ + uint32_t parent; + uint32_t reg, div; + uint32_t freq; + + switch (idx) { + case H3_R_CLK_AHB0: + reg = SXIREAD4(sc, H3_AHB0_CLK_REG); + switch (reg & H3_AHB0_CLK_SRC_SEL) { + case H3_AHB0_CLK_SRC_SEL_OSC32K: + freq = clock_get_frequency(sc->sc_node, "losc"); + break; + case H3_AHB0_CLK_SRC_SEL_OSC24M: + freq = clock_get_frequency(sc->sc_node, "hosc"); + break; + case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0: + freq = clock_get_frequency(sc->sc_node, "pll-periph"); + break; + case H3_AHB0_CLK_SRC_SEL_IOSC: + freq = clock_get_frequency(sc->sc_node, "iosc"); + break; + } + div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg); + return freq / div; + case H3_R_CLK_APB0: + reg = SXIREAD4(sc, H3_APB0_CFG_REG); + div = H3_APB0_CLK_RATIO(reg); + parent = H3_R_CLK_AHB0; + return sxiccmu_ccu_get_frequency(sc, &parent) / div; + } + + printf("%s: 0x%08x\n", __func__, idx); + return 0; +} + uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) { diff --git a/sys/dev/fdt/sxiccmu_clocks.h b/sys/dev/fdt/sxiccmu_clocks.h index 7b25fb625e9..11bae0047bc 100644 --- a/sys/dev/fdt/sxiccmu_clocks.h +++ b/sys/dev/fdt/sxiccmu_clocks.h @@ -311,6 +311,7 @@ struct sxiccmu_ccu_bit sun9i_a80_mmc_gates[] = { #define H3_CLK_HOSC 253 struct sxiccmu_ccu_bit sun8i_h3_gates[] = { + [H3_CLK_PLL_PERIPH0] = { 0x0028, 31 }, [H3_CLK_BUS_MMC0] = { 0x0060, 8 }, [H3_CLK_BUS_MMC1] = { 0x0060, 9 }, [H3_CLK_BUS_MMC2] = { 0x0060, 10 }, @@ -341,6 +342,18 @@ struct sxiccmu_ccu_bit sun8i_h3_gates[] = { [H3_CLK_USB_PHY3] = { 0x00cc, 11 }, }; +#define H3_R_CLK_AHB0 1 +#define H3_R_CLK_APB0 2 + +#define H3_R_CLK_APB0_PIO 3 +#define H3_R_CLK_APB0_I2C 9 + + +struct sxiccmu_ccu_bit sun8i_h3_r_gates[] = { + [H3_R_CLK_APB0_PIO] = { 0x0028, 0 }, + [H3_R_CLK_APB0_I2C] = { 0x0028, 6, H3_R_CLK_APB0 }, +}; + /* * Reset Signals */ @@ -523,3 +536,9 @@ struct sxiccmu_ccu_bit sun8i_h3_resets[] = { [H3_RST_BUS_I2C1] = { 0x02d8, 1 }, [H3_RST_BUS_I2C2] = { 0x02d8, 2 }, }; + +#define H3_R_RST_APB0_I2C 5 + +struct sxiccmu_ccu_bit sun8i_h3_r_resets[] = { + [H3_R_RST_APB0_I2C] = { 0x00b0, 6 }, +}; -- 2.20.1