diff options
author | 2019-09-08 16:45:21 +0000 | |
---|---|---|
committer | 2019-09-08 16:45:21 +0000 | |
commit | 8b22851bda0c871cbea009d5d4c3b64d7f3d198d (patch) | |
tree | 38cbf2170448093f9d64205c6a87762444d686e4 | |
parent | Have sm_install() use install -F (fsync). (diff) | |
download | wireguard-openbsd-8b22851bda0c871cbea009d5d4c3b64d7f3d198d.tar.xz wireguard-openbsd-8b22851bda0c871cbea009d5d4c3b64d7f3d198d.zip |
Add Allwinner H6 support.
-rw-r--r-- | sys/dev/fdt/sxiccmu.c | 138 | ||||
-rw-r--r-- | sys/dev/fdt/sxiccmu_clocks.h | 87 |
2 files changed, 220 insertions, 5 deletions
diff --git a/sys/dev/fdt/sxiccmu.c b/sys/dev/fdt/sxiccmu.c index a53e8562b8e..a19f505042c 100644 --- a/sys/dev/fdt/sxiccmu.c +++ b/sys/dev/fdt/sxiccmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sxiccmu.c,v 1.23 2019/09/02 13:08:49 kettenis Exp $ */ +/* $OpenBSD: sxiccmu.c,v 1.24 2019/09/08 16:45:21 kettenis Exp $ */ /* * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> * Copyright (c) 2013 Artturi Alm @@ -101,6 +101,9 @@ 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_h6_get_frequency(struct sxiccmu_softc *, uint32_t); +int sxiccmu_h6_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); +uint32_t sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *, uint32_t); uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t); int sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); uint32_t sxiccmu_v3s_get_frequency(struct sxiccmu_softc *, uint32_t); @@ -144,7 +147,9 @@ sxiccmu_match(struct device *parent, void *match, void *aux) OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") || OF_is_compatible(node, "allwinner,sun50i-a64-ccu") || OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") || - OF_is_compatible(node, "allwinner,sun50i-h5-ccu")); + OF_is_compatible(node, "allwinner,sun50i-h5-ccu") || + OF_is_compatible(node, "allwinner,sun50i-h6-ccu") || + OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu")); } void @@ -255,6 +260,22 @@ sxiccmu_attach(struct device *parent, struct device *self, void *aux) sc->sc_nresets = nitems(sun50i_a64_resets); sc->sc_get_frequency = sxiccmu_a64_get_frequency; sc->sc_set_frequency = sxiccmu_a64_set_frequency; + } else if (OF_is_compatible(node, "allwinner,sun50i-h6-ccu")) { + KASSERT(faa->fa_nreg > 0); + sc->sc_gates = sun50i_h6_gates; + sc->sc_ngates = nitems(sun50i_h6_gates); + sc->sc_resets = sun50i_h6_resets; + sc->sc_nresets = nitems(sun50i_h6_resets); + sc->sc_get_frequency = sxiccmu_h6_get_frequency; + sc->sc_set_frequency = sxiccmu_h6_set_frequency; + } else if (OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu")) { + KASSERT(faa->fa_nreg > 0); + sc->sc_gates = sun50i_h6_r_gates; + sc->sc_ngates = nitems(sun50i_h6_r_gates); + sc->sc_resets = sun50i_h6_r_resets; + sc->sc_nresets = nitems(sun50i_h6_r_resets); + sc->sc_get_frequency = sxiccmu_h6_r_get_frequency; + sc->sc_set_frequency = sxiccmu_nop_set_frequency; } else { for (node = OF_child(node); node; node = OF_peer(node)) sxiccmu_attach_clock(sc, node, faa->fa_nreg); @@ -975,13 +996,13 @@ sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) #define A64_PLL_CPUX_LOCK (1 << 28) #define A64_PLL_CPUX_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3) #define A64_PLL_CPUX_OUT_EXT_DIVP_MASK (0x3 << 16) -#define A64_PLL_CPUX_FACTOR_N(x) (((x) >> 8) & 0x1f) +#define A64_PLL_CPUX_FACTOR_N(x) (((x) >> 8) & 0x1f) #define A64_PLL_CPUX_FACTOR_N_MASK (0x1f << 8) #define A64_PLL_CPUX_FACTOR_N_SHIFT 8 -#define A64_PLL_CPUX_FACTOR_K(x) (((x) >> 4) & 0x3) +#define A64_PLL_CPUX_FACTOR_K(x) (((x) >> 4) & 0x3) #define A64_PLL_CPUX_FACTOR_K_MASK (0x3 << 4) #define A64_PLL_CPUX_FACTOR_K_SHIFT 4 -#define A64_PLL_CPUX_FACTOR_M(x) (((x) >> 0) & 0x3) +#define A64_PLL_CPUX_FACTOR_M(x) (((x) >> 0) & 0x3) #define A64_PLL_CPUX_FACTOR_M_MASK (0x3 << 0) #define A64_CPUX_AXI_CFG_REG 0x0050 #define A64_CPUX_CLK_SRC_SEL (0x3 << 16) @@ -1243,6 +1264,39 @@ sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) } uint32_t +sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) +{ + switch (idx) { + case H6_CLK_PLL_PERIPH0: + /* Not hardcoded, but recommended. */ + return 600000000; + case H6_CLK_PLL_PERIPH0_2X: + return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2; + case H6_CLK_APB2: + /* XXX Controlled by a MUX. */ + return 24000000; + break; + } + + printf("%s: 0x%08x\n", __func__, idx); + return 0; +} + +uint32_t +sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) +{ + switch (idx) { + case H6_R_CLK_APB2: + /* XXX Controlled by a MUX. */ + return 24000000; + break; + } + + printf("%s: 0x%08x\n", __func__, idx); + return 0; +} + +uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) { uint32_t parent; @@ -1553,6 +1607,76 @@ sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) return -1; } +#define H6_SMHC0_CLK_REG 0x0830 +#define H6_SMHC1_CLK_REG 0x0834 +#define H6_SMHC2_CLK_REG 0x0838 +#define H6_SMHC_CLK_SRC_SEL (0x3 << 24) +#define H6_SMHC_CLK_SRC_SEL_OSC24M (0x0 << 24) +#define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X (0x1 << 24) +#define H6_SMHC_FACTOR_N_MASK (0x3 << 8) +#define H6_SMHC_FACTOR_N_SHIFT 8 +#define H6_SMHC_FACTOR_M_MASK (0xf << 0) +#define H6_SMHC_FACTOR_M_SHIFT 0 + +int +sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset, + uint32_t freq) +{ + uint32_t parent_freq; + uint32_t reg, m, n; + uint32_t clk_src; + + switch (freq) { + case 400000: + n = 2, m = 15; + clk_src = H6_SMHC_CLK_SRC_SEL_OSC24M; + break; + case 20000000: + case 25000000: + case 26000000: + case 50000000: + case 52000000: + n = 0, m = 0; + clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X; + parent_freq = + sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X); + while ((parent_freq / (1 << n) / 16) > freq) + n++; + while ((parent_freq / (1 << n) / (m + 1)) > freq) + m++; + break; + default: + return -1; + } + + reg = SXIREAD4(sc, offset); + reg &= ~H6_SMHC_CLK_SRC_SEL; + reg |= clk_src; + reg &= ~H6_SMHC_FACTOR_N_MASK; + reg |= n << H6_SMHC_FACTOR_N_SHIFT; + reg &= ~H6_SMHC_FACTOR_M_MASK; + reg |= m << H6_SMHC_FACTOR_M_SHIFT; + SXIWRITE4(sc, offset, reg); + + return 0; +} + +int +sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) +{ + switch (idx) { + case H6_CLK_MMC0: + return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG, freq); + case H6_CLK_MMC1: + return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG, freq); + case H6_CLK_MMC2: + return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG, freq); + } + + printf("%s: 0x%08x\n", __func__, idx); + return -1; +} + int sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) { @@ -1620,6 +1744,10 @@ sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on) return; } + /* If the clock can't be gated, simply return. */ + if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff) + return; + reg = sc->sc_gates[idx].reg; bit = sc->sc_gates[idx].bit; diff --git a/sys/dev/fdt/sxiccmu_clocks.h b/sys/dev/fdt/sxiccmu_clocks.h index ebc83c1edba..558c9a66f32 100644 --- a/sys/dev/fdt/sxiccmu_clocks.h +++ b/sys/dev/fdt/sxiccmu_clocks.h @@ -387,6 +387,59 @@ struct sxiccmu_ccu_bit sun8i_h3_r_gates[] = { [H3_R_CLK_APB0_I2C] = { 0x0028, 6, H3_R_CLK_APB0 }, }; +/* H6 */ + +#define H6_CLK_PLL_PERIPH0 3 +#define H6_CLK_PLL_PERIPH0_2X 4 +#define H6_CLK_APB1 26 +#define H6_CLK_APB2 27 +#define H6_CLK_MMC0 64 +#define H6_CLK_MMC1 65 +#define H6_CLK_MMC2 66 +#define H6_CLK_BUS_MMC0 67 +#define H6_CLK_BUS_MMC1 68 +#define H6_CLK_BUS_MMC2 69 +#define H6_CLK_BUS_UART0 70 +#define H6_CLK_BUS_UART1 71 +#define H6_CLK_BUS_UART2 72 +#define H6_CLK_BUS_UART3 73 +#define H6_CLK_USB_OHCI0 104 +#define H6_CLK_USB_OHCI3 107 +#define H6_CLK_BUS_OHCI0 111 +#define H6_CLK_BUS_OHCI3 112 +#define H6_CLK_BUS_EHCI0 113 +#define H6_CLK_BUS_EHCI3 115 + +struct sxiccmu_ccu_bit sun50i_h6_gates[] = { + [H6_CLK_PLL_PERIPH0] = { 0x0020, 31 }, + [H6_CLK_APB1] = { 0xffff, 0xff }, + [H6_CLK_MMC0] = { 0x0830, 31 }, + [H6_CLK_MMC1] = { 0x0834, 31 }, + [H6_CLK_MMC2] = { 0x0838, 31 }, + [H6_CLK_BUS_MMC0] = { 0x084c, 0 }, + [H6_CLK_BUS_MMC1] = { 0x084c, 1 }, + [H6_CLK_BUS_MMC2] = { 0x084c, 2 }, + [H6_CLK_BUS_UART0] = { 0x090c, 0, H6_CLK_APB2 }, + [H6_CLK_BUS_UART1] = { 0x090c, 1, H6_CLK_APB2 }, + [H6_CLK_BUS_UART2] = { 0x090c, 2, H6_CLK_APB2 }, + [H6_CLK_BUS_UART3] = { 0x090c, 3, H6_CLK_APB2 }, + [H6_CLK_USB_OHCI0] = { 0x0a70, 31 }, + [H6_CLK_USB_OHCI3] = { 0x0a7c, 31 }, + [H6_CLK_BUS_OHCI0] = { 0x0a8c, 0 }, + [H6_CLK_BUS_OHCI3] = { 0x0a8c, 3 }, + [H6_CLK_BUS_EHCI0] = { 0x0a8c, 4 }, + [H6_CLK_BUS_EHCI3] = { 0x0a8c, 7 }, +}; + +#define H6_R_CLK_APB1 2 +#define H6_R_CLK_APB2 3 +#define H6_R_CLK_APB2_I2C 8 + +struct sxiccmu_ccu_bit sun50i_h6_r_gates[] = { + [H6_R_CLK_APB1] = { 0xffff, 0xff }, + [H6_R_CLK_APB2_I2C] = { 0x019c, 1, H6_R_CLK_APB2 }, +}; + /* R40 */ #define R40_CLK_PLL_PERIPH0 11 @@ -724,6 +777,40 @@ struct sxiccmu_ccu_bit sun8i_h3_r_resets[] = { [H3_R_RST_APB0_I2C] = { 0x00b0, 6 }, }; +/* H6 */ + +#define H6_RST_BUS_MMC0 18 +#define H6_RST_BUS_MMC1 19 +#define H6_RST_BUS_MMC2 20 +#define H6_RST_BUS_UART0 21 +#define H6_RST_BUS_UART1 22 +#define H6_RST_BUS_UART2 23 +#define H6_RST_BUS_UART3 24 +#define H6_RST_BUS_OHCI0 48 +#define H6_RST_BUS_OHCI3 49 +#define H6_RST_BUS_EHCI0 50 +#define H6_RST_BUS_EHCI3 52 + +struct sxiccmu_ccu_bit sun50i_h6_resets[] = { + [H6_RST_BUS_MMC0] = { 0x084c, 16 }, + [H6_RST_BUS_MMC1] = { 0x084c, 17 }, + [H6_RST_BUS_MMC2] = { 0x084c, 18 }, + [H6_RST_BUS_UART0] = { 0x090c, 16 }, + [H6_RST_BUS_UART1] = { 0x090c, 17 }, + [H6_RST_BUS_UART2] = { 0x090c, 18 }, + [H6_RST_BUS_UART3] = { 0x090c, 19 }, + [H6_RST_BUS_OHCI0] = { 0x0a8c, 16 }, + [H6_RST_BUS_OHCI3] = { 0x0a8c, 19 }, + [H6_RST_BUS_EHCI0] = { 0x0a8c, 20 }, + [H6_RST_BUS_EHCI3] = { 0x0a8c, 23 }, +}; + +#define H6_R_RST_APB2_I2C 4 + +struct sxiccmu_ccu_bit sun50i_h6_r_resets[] = { + [H6_R_RST_APB2_I2C] = { 0x019c, 16 }, +}; + /* R40 */ #define R40_RST_USB_PHY0 0 |