From 199786d98d7a19c22602e2bc88526b8d5da47e67 Mon Sep 17 00:00:00 2001 From: kettenis Date: Sun, 3 Mar 2024 21:42:41 +0000 Subject: [PATCH] Add support for the "NG" clock bindings for sun5i SoCs. ok patrick@ --- sys/dev/fdt/sxiccmu.c | 132 ++++++++++++++++++++++++++++++++++- sys/dev/fdt/sxiccmu_clocks.h | 68 ++++++++++++++++++ 2 files changed, 198 insertions(+), 2 deletions(-) diff --git a/sys/dev/fdt/sxiccmu.c b/sys/dev/fdt/sxiccmu.c index 31d4c7eebd3..afb3966ef66 100644 --- a/sys/dev/fdt/sxiccmu.c +++ b/sys/dev/fdt/sxiccmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sxiccmu.c,v 1.35 2024/02/07 22:00:38 uaa Exp $ */ +/* $OpenBSD: sxiccmu.c,v 1.36 2024/03/03 21:42:41 kettenis Exp $ */ /* * Copyright (c) 2007,2009 Dale Rahn * Copyright (c) 2013 Artturi Alm @@ -92,6 +92,8 @@ void sxiccmu_ccu_reset(void *, uint32_t *, int); uint32_t sxiccmu_a10_get_frequency(struct sxiccmu_softc *, uint32_t); int sxiccmu_a10_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); +uint32_t sxiccmu_a10s_get_frequency(struct sxiccmu_softc *, uint32_t); +int sxiccmu_a10s_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); uint32_t sxiccmu_a23_get_frequency(struct sxiccmu_softc *, uint32_t); int sxiccmu_a23_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t); @@ -139,6 +141,8 @@ sxiccmu_match(struct device *parent, void *match, void *aux) } return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") || + OF_is_compatible(node, "allwinner,sun5i-a10s-ccu") || + OF_is_compatible(node, "allwinner,sun5i-a13-ccu") || OF_is_compatible(node, "allwinner,sun7i-a20-ccu") || OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || OF_is_compatible(node, "allwinner,sun8i-a23-prcm") || @@ -193,6 +197,14 @@ sxiccmu_attach(struct device *parent, struct device *self, void *aux) sc->sc_nresets = nitems(sun4i_a10_resets); sc->sc_get_frequency = sxiccmu_a10_get_frequency; sc->sc_set_frequency = sxiccmu_a10_set_frequency; + } else if (OF_is_compatible(node, "allwinner,sun5i-a10s-ccu")) { + KASSERT(faa->fa_nreg > 0); + sc->sc_gates = sun5i_a10s_gates; + sc->sc_ngates = nitems(sun5i_a10s_gates); + sc->sc_resets = sun5i_a10s_resets; + sc->sc_nresets = nitems(sun5i_a10s_resets); + sc->sc_get_frequency = sxiccmu_a10s_get_frequency; + sc->sc_set_frequency = sxiccmu_a10s_set_frequency; } else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) { KASSERT(faa->fa_nreg > 0); @@ -907,7 +919,7 @@ sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells) return sc->sc_get_frequency(sc, idx); } -/* Allwinner A10/A20 */ +/* Allwinner A10/A10s/A13/A20 */ #define A10_PLL1_CFG_REG 0x0000 #define A10_PLL1_OUT_EXT_DIVP_MASK (0x3 << 16) #define A10_PLL1_OUT_EXT_DIVP_SHIFT 16 @@ -989,6 +1001,62 @@ sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) return 0; } +uint32_t +sxiccmu_a10s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) +{ + uint32_t parent; + uint32_t reg, div; + uint32_t k, m, n, p; + + switch (idx) { + case A10S_CLK_LOSC: + return clock_get_frequency(sc->sc_node, "losc"); + case A10S_CLK_HOSC: + return clock_get_frequency(sc->sc_node, "hosc"); + case A10S_CLK_PLL_CORE: + reg = SXIREAD4(sc, A10_PLL1_CFG_REG); + k = A10_PLL1_FACTOR_K(reg) + 1; + m = A10_PLL1_FACTOR_M(reg) + 1; + n = A10_PLL1_FACTOR_N(reg); + p = 1 << A10_PLL1_OUT_EXT_DIVP(reg); + return (24000000 * n * k) / (m * p); + case A10S_CLK_PLL_PERIPH: + return 1200000000; + case A10S_CLK_CPU: + reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); + switch (reg & A10_CPU_CLK_SRC_SEL) { + case A10_CPU_CLK_SRC_SEL_LOSC: + parent = A10S_CLK_LOSC; + break; + case A10_CPU_CLK_SRC_SEL_OSC24M: + parent = A10S_CLK_HOSC; + break; + case A10_CPU_CLK_SRC_SEL_PLL1: + parent = A10S_CLK_PLL_CORE; + break; + case A10_CPU_CLK_SRC_SEL_200MHZ: + return 200000000; + } + return sxiccmu_ccu_get_frequency(sc, &parent); + case A10S_CLK_AXI: + reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); + div = 1 << A10_AXI_CLK_DIV_RATIO(reg); + parent = A10S_CLK_CPU; + return sxiccmu_ccu_get_frequency(sc, &parent) / div; + case A10S_CLK_AHB: + reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); + div = 1 << A10_AHB_CLK_DIV_RATIO(reg); + parent = A10S_CLK_AXI; + return sxiccmu_ccu_get_frequency(sc, &parent) / div; + case A10S_CLK_APB1: + /* XXX Controlled by a MUX. */ + return 24000000; + } + + printf("%s: 0x%08x\n", __func__, idx); + return 0; +} + /* Allwinner A23/A64/H3/H5/R40 */ #define CCU_AHB1_APB1_CFG_REG 0x0054 #define CCU_AHB1_CLK_SRC_SEL (3 << 12) @@ -1665,6 +1733,66 @@ sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) return -1; } +int +sxiccmu_a10s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, + int32_t freq) +{ + struct sxiccmu_clock clock; + uint32_t parent, parent_freq; + uint32_t reg; + int k, n; + int error; + + switch (idx) { + case A10S_CLK_PLL_CORE: + k = 1; n = 32; + while (k <= 4 && (24000000 * n * k) < freq) + k++; + while (n >= 1 && (24000000 * n * k) > freq) + n--; + + reg = SXIREAD4(sc, A10_PLL1_CFG_REG); + reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK; + reg &= ~A10_PLL1_FACTOR_N_MASK; + reg &= ~A10_PLL1_FACTOR_K_MASK; + reg &= ~A10_PLL1_FACTOR_M_MASK; + reg |= (n << A10_PLL1_FACTOR_N_SHIFT); + reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT); + SXIWRITE4(sc, A10_PLL1_CFG_REG, reg); + + /* No need to wait PLL to lock? */ + + return 0; + case A10S_CLK_CPU: + /* Switch to 24 MHz clock. */ + reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); + reg &= ~A10_CPU_CLK_SRC_SEL; + reg |= A10_CPU_CLK_SRC_SEL_OSC24M; + SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg); + + error = sxiccmu_a10s_set_frequency(sc, A10S_CLK_PLL_CORE, freq); + + /* Switch back to PLL. */ + reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); + reg &= ~A10_CPU_CLK_SRC_SEL; + reg |= A10_CPU_CLK_SRC_SEL_PLL1; + SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg); + return error; + case A10S_CLK_MMC0: + case A10S_CLK_MMC1: + case A10S_CLK_MMC2: + clock.sc_iot = sc->sc_iot; + bus_space_subregion(sc->sc_iot, sc->sc_ioh, + sc->sc_gates[idx].reg, 4, &clock.sc_ioh); + parent = A10S_CLK_PLL_PERIPH; + parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); + return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); + } + + printf("%s: 0x%08x\n", __func__, idx); + return -1; +} + int sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) { diff --git a/sys/dev/fdt/sxiccmu_clocks.h b/sys/dev/fdt/sxiccmu_clocks.h index bda6855fef7..cce1be6183f 100644 --- a/sys/dev/fdt/sxiccmu_clocks.h +++ b/sys/dev/fdt/sxiccmu_clocks.h @@ -90,6 +90,64 @@ const struct sxiccmu_ccu_bit sun4i_a10_gates[] = { [A10_CLK_USB_PHY] = { 0x00cc, 8 }, }; +/* A10s */ + +#define A10S_CLK_HOSC 1 +#define A10S_CLK_PLL_CORE 2 +#define A10S_CLK_PLL_PERIPH 14 + +#define A10S_CLK_CPU 17 +#define A10S_CLK_AXI 18 +#define A10S_CLK_AHB 19 +#define A10S_CLK_APB1 21 + +#define A10S_CLK_AHB_EHCI0 24 +#define A10S_CLK_AHB_OHCI0 25 +#define A10S_CLK_AHB_MMC0 29 +#define A10S_CLK_AHB_MMC1 30 +#define A10S_CLK_AHB_MMC2 31 +#define A10S_CLK_AHB_EMAC 34 +#define A10S_CLK_APB0_PIO 53 +#define A10S_CLK_APB1_I2C0 56 +#define A10S_CLK_APB1_I2C1 57 +#define A10S_CLK_APB1_I2C2 58 +#define A10S_CLK_APB1_UART0 59 +#define A10S_CLK_APB1_UART1 60 +#define A10S_CLK_APB1_UART2 61 +#define A10S_CLK_APB1_UART3 62 + +#define A10S_CLK_MMC0 64 +#define A10S_CLK_MMC1 65 +#define A10S_CLK_MMC2 66 +#define A10S_CLK_USB_OHCI0 76 +#define A10S_CLK_USB_PHY0 77 +#define A10S_CLK_USB_PHY1 78 + +#define A10S_CLK_LOSC 254 + +const struct sxiccmu_ccu_bit sun5i_a10s_gates[] = { + [A10S_CLK_AHB_EHCI0] = { 0x0060, 1 }, + [A10S_CLK_AHB_OHCI0] = { 0x0060, 2 }, + [A10S_CLK_AHB_MMC0] = { 0x0060, 8 }, + [A10S_CLK_AHB_MMC1] = { 0x0060, 9 }, + [A10S_CLK_AHB_MMC2] = { 0x0060, 10 }, + [A10S_CLK_AHB_EMAC] = { 0x0060, 17 }, + [A10S_CLK_APB0_PIO] = { 0x0068, 5 }, + [A10S_CLK_APB1_I2C0] = { 0x006c, 0, A10S_CLK_APB1 }, + [A10S_CLK_APB1_I2C1] = { 0x006c, 1, A10S_CLK_APB1 }, + [A10S_CLK_APB1_I2C2] = { 0x006c, 2, A10S_CLK_APB1 }, + [A10S_CLK_APB1_UART0] = { 0x006c, 16, A10S_CLK_APB1 }, + [A10S_CLK_APB1_UART1] = { 0x006c, 17, A10S_CLK_APB1 }, + [A10S_CLK_APB1_UART2] = { 0x006c, 18, A10S_CLK_APB1 }, + [A10S_CLK_APB1_UART3] = { 0x006c, 19, A10S_CLK_APB1 }, + [A10S_CLK_MMC0] = { 0x0088, 31 }, + [A10S_CLK_MMC1] = { 0x008c, 31 }, + [A10S_CLK_MMC2] = { 0x0090, 31 }, + [A10S_CLK_USB_OHCI0] = { 0x00cc, 6 }, + [A10S_CLK_USB_PHY0] = { 0x00cc, 8 }, + [A10S_CLK_USB_PHY1] = { 0x00cc, 9 }, +}; + /* A23/A33 */ #define A23_CLK_PLL_PERIPH 10 @@ -773,6 +831,16 @@ const struct sxiccmu_ccu_bit sun4i_a10_resets[] = { [A10_RST_USB_PHY2] = { 0x00cc, 2 }, }; +/* A10s */ + +#define A10S_RST_USB_PHY0 0 +#define A10S_RST_USB_PHY1 1 + +const struct sxiccmu_ccu_bit sun5i_a10s_resets[] = { + [A10S_RST_USB_PHY0] = { 0x00cc, 0 }, + [A10S_RST_USB_PHY1] = { 0x00cc, 1 }, +}; + /* A23/A33 */ #define A23_RST_USB_PHY0 0 -- 2.20.1