diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2023-06-24 18:27:00 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2023-06-24 18:27:00 +0000 |
commit | 4b57fdc8405c969abbb8cbb7dddbbac44d9ee33f (patch) | |
tree | 21fca09243edb8dadd43004b5626759bd2f7cd27 /sys/arch | |
parent | 08a3840f58dc4a05fd64e16e8ced78e6a67e2d16 (diff) |
Add initial support for StarFive VisionFive V2 to stfclock(4).
This adds initial support for the syscrg and pll clocks on the StarFive
VisionFive V2 JH7110 SoC.
ok kettenis@
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/riscv64/dev/stfclock.c | 379 |
1 files changed, 342 insertions, 37 deletions
diff --git a/sys/arch/riscv64/dev/stfclock.c b/sys/arch/riscv64/dev/stfclock.c index 2fef8b689db..61667a5581c 100644 --- a/sys/arch/riscv64/dev/stfclock.c +++ b/sys/arch/riscv64/dev/stfclock.c @@ -1,6 +1,7 @@ -/* $OpenBSD: stfclock.c,v 1.3 2022/12/28 11:20:09 kettenis Exp $ */ +/* $OpenBSD: stfclock.c,v 1.4 2023/06/24 18:26:59 jsing Exp $ */ /* * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org> + * Copyright (c) 2023 Joel Sing <jsing@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,6 +19,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/malloc.h> #include <machine/intr.h> #include <machine/bus.h> @@ -25,9 +27,10 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_clock.h> +#include <dev/ofw/ofw_misc.h> #include <dev/ofw/fdt.h> -/* Clock IDs */ +/* JH7100 Clock IDs */ #define JH7100_CLK_CPUNDBUS_ROOT 0 #define JH7100_CLK_GMACUSB_ROOT 3 #define JH7100_CLK_PERH0_ROOT 4 @@ -57,6 +60,36 @@ #define JH7100_CLK_OSC_SYS 255 #define JH7100_CLK_OSC_AUD 254 +/* JH7110 Clock IDs */ +#define JH7110_CLK_PLL0_OUT 0 +#define JH7110_CLK_PLL1_OUT 1 +#define JH7110_CLK_PLL2_OUT 2 + +#define JH7110_SYSCLK_CPU_ROOT 0 +#define JH7110_SYSCLK_CPU_CORE 1 +#define JH7110_SYSCLK_CPU_BUS 2 +#define JH7110_SYSCLK_BUS_ROOT 5 +#define JH7110_SYSCLK_AXI_CFG0 7 +#define JH7110_SYSCLK_STG_AXIAHB 8 +#define JH7110_SYSCLK_AHB0 9 +#define JH7110_SYSCLK_AHB1 10 +#define JH7110_SYSCLK_APB_BUS 11 +#define JH7110_SYSCLK_SDIO0_AHB 91 +#define JH7110_SYSCLK_SDIO1_AHB 92 +#define JH7110_SYSCLK_SDIO0_SDCARD 93 +#define JH7110_SYSCLK_SDIO1_SDCARD 94 +#define JH7110_SYSCLK_TEMP_APB 129 +#define JH7110_SYSCLK_TEMP_CORE 130 +#define JH7110_SYSCLK_UART0_CORE 146 + +#define JH7110_SYSCLK_OSC 190 +#define JH7110_SYSCLK_PLL0_OUT 199 +#define JH7110_SYSCLK_PLL1_OUT 200 +#define JH7110_SYSCLK_PLL2_OUT 201 + +#define JH7110_SYSCLK_ASSERT_OFFSET 0x2f8 +#define JH7110_SYSCLK_STATUS_OFFSET 0x308 + /* Registers */ #define CLKMUX_MASK 0x03000000 #define CLKMUX_SHIFT 24 @@ -79,6 +112,7 @@ struct stfclock_softc { int sc_node; struct clock_device sc_cd; + struct reset_device sc_rd; }; int stfclock_match(struct device *, void *, void *); @@ -92,16 +126,27 @@ struct cfdriver stfclock_cd = { NULL, "stfclock", DV_DULL }; -uint32_t stfclock_get_frequency(void *, uint32_t *); -int stfclock_set_frequency(void *, uint32_t *, uint32_t); -void stfclock_enable(void *, uint32_t *, int); +uint32_t stfclock_get_frequency_jh7100(void *, uint32_t *); +int stfclock_set_frequency_jh7100(void *, uint32_t *, uint32_t); +void stfclock_enable_jh7100(void *, uint32_t *, int); + +uint32_t stfclock_get_frequency_jh7110_pll(void *, uint32_t *); +int stfclock_set_frequency_jh7110_pll(void *, uint32_t *, uint32_t); +void stfclock_enable_jh7110_pll(void *, uint32_t *, int); + +uint32_t stfclock_get_frequency_jh7110_sys(void *, uint32_t *); +int stfclock_set_frequency_jh7110_sys(void *, uint32_t *, uint32_t); +void stfclock_enable_jh7110_sys(void *, uint32_t *, int); +void stfclock_reset_jh7110_sys(void *, uint32_t *, int); int stfclock_match(struct device *parent, void *match, void *aux) { struct fdt_attach_args *faa = aux; - return OF_is_compatible(faa->fa_node, "starfive,jh7100-clkgen"); + return OF_is_compatible(faa->fa_node, "starfive,jh7100-clkgen") || + OF_is_compatible(faa->fa_node, "starfive,jh7110-pll") || + OF_is_compatible(faa->fa_node, "starfive,jh7110-syscrg"); } void @@ -110,32 +155,50 @@ stfclock_attach(struct device *parent, struct device *self, void *aux) struct stfclock_softc *sc = (struct stfclock_softc *)self; struct fdt_attach_args *faa = aux; - if (faa->fa_nreg < 1) { - printf(": no registers\n"); - return; - } - - sc->sc_iot = faa->fa_iot; - if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, - faa->fa_reg[0].size, 0, &sc->sc_ioh)) { - printf(": can't map registers\n"); - return; + if (faa->fa_nreg >= 1) { + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } } sc->sc_node = faa->fa_node; - printf("\n"); - sc->sc_cd.cd_node = faa->fa_node; sc->sc_cd.cd_cookie = sc; - sc->sc_cd.cd_get_frequency = stfclock_get_frequency; - sc->sc_cd.cd_set_frequency = stfclock_set_frequency; - sc->sc_cd.cd_enable = stfclock_enable; + + if (OF_is_compatible(faa->fa_node, "starfive,jh7100-clkgen")) { + sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7100; + sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7100; + sc->sc_cd.cd_enable = stfclock_enable_jh7100; + printf("\n"); + } else if (OF_is_compatible(faa->fa_node, "starfive,jh7110-pll")) { + sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7110_pll; + sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7110_pll; + sc->sc_cd.cd_enable = stfclock_enable_jh7110_pll; + printf(": pll\n"); + } else if (OF_is_compatible(faa->fa_node, "starfive,jh7110-syscrg")) { + sc->sc_cd.cd_get_frequency = stfclock_get_frequency_jh7110_sys; + sc->sc_cd.cd_set_frequency = stfclock_set_frequency_jh7110_sys; + sc->sc_cd.cd_enable = stfclock_enable_jh7110_sys; + + sc->sc_rd.rd_node = sc->sc_node; + sc->sc_rd.rd_cookie = sc; + sc->sc_rd.rd_reset = stfclock_reset_jh7110_sys; + reset_register(&sc->sc_rd); + + printf(": syscrg\n"); + } + + KASSERT(sc->sc_cd.cd_get_frequency); + clock_register(&sc->sc_cd); } uint32_t -stfclock_get_frequency(void *cookie, uint32_t *cells) +stfclock_get_frequency_jh7100(void *cookie, uint32_t *cells) { struct stfclock_softc *sc = cookie; uint32_t idx = cells[0]; @@ -150,13 +213,13 @@ stfclock_get_frequency(void *cookie, uint32_t *cells) case JH7100_CLK_PLL0_OUT: parent = JH7100_CLK_OSC_SYS; - return 40 * stfclock_get_frequency(sc, &parent); + return 40 * stfclock_get_frequency_jh7100(sc, &parent); case JH7100_CLK_PLL1_OUT: parent = JH7100_CLK_OSC_SYS; - return 64 * stfclock_get_frequency(sc, &parent); + return 64 * stfclock_get_frequency_jh7100(sc, &parent); case JH7100_CLK_PLL2_OUT: parent = JH7100_CLK_PLL2_REF; - return 55 * stfclock_get_frequency(sc, &parent); + return 55 * stfclock_get_frequency_jh7100(sc, &parent); } reg = HREAD4(sc, idx * 4); @@ -179,7 +242,7 @@ stfclock_get_frequency(void *cookie, uint32_t *cells) parent = JH7100_CLK_PLL2_OUT; break; } - return stfclock_get_frequency(sc, &parent); + return stfclock_get_frequency_jh7100(sc, &parent); case JH7100_CLK_GMACUSB_ROOT: switch (mux) { default: @@ -192,18 +255,18 @@ stfclock_get_frequency(void *cookie, uint32_t *cells) parent = JH7100_CLK_PLL2_OUT; break; } - return stfclock_get_frequency(sc, &parent); + return stfclock_get_frequency_jh7100(sc, &parent); case JH7100_CLK_PERH0_ROOT: mux = (reg >> 24) & 1; parent = mux ? JH7100_CLK_PLL0_OUT : JH7100_CLK_OSC_SYS; - return stfclock_get_frequency(sc, &parent); + return stfclock_get_frequency_jh7100(sc, &parent); case JH7100_CLK_PERH1_ROOT: mux = (reg >> 24) & 1; parent = mux ? JH7100_CLK_PLL2_OUT : JH7100_CLK_OSC_SYS; - return stfclock_get_frequency(sc, &parent); + return stfclock_get_frequency_jh7100(sc, &parent); case JH7100_CLK_PLL2_REF: parent = mux ? JH7100_CLK_OSC_AUD : JH7100_CLK_OSC_SYS; - return stfclock_get_frequency(sc, &parent); + return stfclock_get_frequency_jh7100(sc, &parent); } switch (idx) { @@ -248,25 +311,26 @@ stfclock_get_frequency(void *cookie, uint32_t *cells) parent = JH7100_CLK_GMAC_ROOT_DIV; break; default: - printf("%s: 0x%08x\n", __func__, idx); + printf("%s: unknown clock 0x%08x\n", __func__, idx); return 0; } - freq = stfclock_get_frequency(sc, &parent); + freq = stfclock_get_frequency_jh7100(sc, &parent); return freq / div; } int -stfclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) +stfclock_set_frequency_jh7100(void *cookie, uint32_t *cells, uint32_t freq) { uint32_t idx = cells[0]; - printf("%s: 0x%08x\n", __func__, idx); + printf("%s: not handled 0x%08x (freq=0x%08x)\n", __func__, idx, freq); + return -1; } - + void -stfclock_enable(void *cookie, uint32_t *cells, int on) +stfclock_enable_jh7100(void *cookie, uint32_t *cells, int on) { struct stfclock_softc *sc = cookie; uint32_t idx = cells[0]; @@ -294,5 +358,246 @@ stfclock_enable(void *cookie, uint32_t *cells, int on) return; } - printf("%s: 0x%08x\n", __func__, idx); + printf("%s: unknown clock 0x%08x\n", __func__, idx); +} + +uint32_t +stfclock_get_frequency_jh7110_pll(void *cookie, uint32_t *cells) +{ + struct stfclock_softc *sc = cookie; + uint32_t idx = cells[0]; + uint32_t dacpd, dsmpd, fbdiv, frac, prediv, postdiv1, reg; + uint64_t frac_val, parent_freq; + struct regmap *pllrm; + int syscon_node; + bus_size_t base; + + parent_freq = clock_get_frequency_idx(sc->sc_node, 0); + if (parent_freq == 0) { + printf("%s: failed to get parent frequency\n", __func__); + return 0; + } + + switch (idx) { + case JH7110_CLK_PLL0_OUT: + base = 0x18; + break; + case JH7110_CLK_PLL1_OUT: + base = 0x24; + break; + case JH7110_CLK_PLL2_OUT: + base = 0x2c; + break; + default: + printf("%s: unknown clock 0x08%x\n", __func__, idx); + return 0; + } + + syscon_node = OF_parent(sc->sc_node); + if (syscon_node < 0) { + printf("%s: failed to find pll clock parent\n", __func__); + return 0; + } + pllrm = regmap_bynode(syscon_node); + if (pllrm == NULL) { + printf("%s: failed to get pll regmap\n", __func__); + return 0; + } + + switch (idx) { + case JH7110_CLK_PLL0_OUT: + reg = regmap_read_4(pllrm, base + 0); + dacpd = (reg >> 24) & 1; + dsmpd = (reg >> 25) & 1; + + reg = regmap_read_4(pllrm, base + 4); + fbdiv = (reg >> 0) & ((1UL << 12) - 1); + + reg = regmap_read_4(pllrm, base + 8); + frac = (reg >> 0) & ((1UL << 24) - 1); + postdiv1 = 1 << ((reg >> 28) & ((1UL << 2) - 1)); + + reg = regmap_read_4(pllrm, base + 12); + prediv = (reg >> 0) & ((1UL << 6) - 1); + break; + + case JH7110_CLK_PLL1_OUT: + case JH7110_CLK_PLL2_OUT: + reg = regmap_read_4(pllrm, base + 0); + dacpd = (reg >> 15) & 1; + dsmpd = (reg >> 16) & 1; + fbdiv = (reg >> 17) & ((1UL << 12) - 1); + + reg = regmap_read_4(pllrm, base + 4); + frac = (reg >> 0) & ((1UL << 24) - 1); + postdiv1 = 1 << ((reg >> 28) & ((1UL << 2) - 1)); + + reg = regmap_read_4(pllrm, base + 8); + prediv = (reg >> 0) & ((1UL << 6) - 1); + break; + } + + if (fbdiv == 0 || prediv == 0 || postdiv1 == 0) { + printf("%s: zero divisor\n", __func__); + return 0; + } + + if (dacpd != dsmpd) + return 0; + + /* Integer mode (dacpd/dsmpd both 0) or fraction mode (both 1). */ + frac_val = 0; + if (dacpd == 0 && dsmpd == 0) + frac_val = ((uint64_t)frac * 1000) / (1 << 24); + + return parent_freq / 1000 * (fbdiv * 1000 + frac_val) / prediv / postdiv1; +} + +int +stfclock_set_frequency_jh7110_pll(void *cookie, uint32_t *cells, uint32_t freq) +{ + uint32_t idx = cells[0]; + + printf("%s: not handled 0x%08x (freq=0x%08x)\n", __func__, idx, freq); + + return -1; +} + +void +stfclock_enable_jh7110_pll(void *cookie, uint32_t *cells, int on) +{ + uint32_t idx = cells[0]; + + printf("%s: not handled 0x%08x\n", __func__, idx); +} + +uint32_t +stfclock_get_frequency_jh7110_sys(void *cookie, uint32_t *cells) +{ + struct stfclock_softc *sc = cookie; + uint32_t idx = cells[0]; + uint32_t parent, freq; + uint32_t reg, div, mux; + + switch (idx) { + case JH7110_SYSCLK_OSC: + return clock_get_frequency(sc->sc_node, "osc"); + case JH7110_SYSCLK_PLL0_OUT: + return clock_get_frequency(sc->sc_node, "pll0_out"); + case JH7110_SYSCLK_PLL1_OUT: + return clock_get_frequency(sc->sc_node, "pll1_out"); + case JH7110_SYSCLK_PLL2_OUT: + return clock_get_frequency(sc->sc_node, "pll2_out"); + } + + reg = HREAD4(sc, idx * 4); + mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT; + div = (reg & CLKDIV_MASK) >> CLKDIV_SHIFT; + + switch (idx) { + case JH7110_SYSCLK_CPU_ROOT: + mux = (reg >> 24) & 1; + parent = mux ? JH7110_SYSCLK_PLL0_OUT : JH7110_SYSCLK_OSC; + return stfclock_get_frequency_jh7110_sys(sc, &parent); + case JH7110_SYSCLK_BUS_ROOT: + mux = (reg >> 24) & 1; + parent = mux ? JH7110_SYSCLK_PLL2_OUT : JH7110_SYSCLK_OSC; + return stfclock_get_frequency_jh7110_sys(sc, &parent); + } + + switch (idx) { + case JH7110_SYSCLK_CPU_CORE: + parent = JH7110_SYSCLK_CPU_ROOT; + break; + case JH7110_SYSCLK_AXI_CFG0: + parent = JH7110_SYSCLK_BUS_ROOT; + break; + case JH7110_SYSCLK_STG_AXIAHB: + parent = JH7110_SYSCLK_AXI_CFG0; + break; + case JH7110_SYSCLK_AHB0: + case JH7110_SYSCLK_AHB1: + case JH7110_SYSCLK_APB_BUS: + parent = JH7110_SYSCLK_STG_AXIAHB; + break; + case JH7110_SYSCLK_SDIO0_AHB: + case JH7110_SYSCLK_SDIO1_AHB: + parent = JH7110_SYSCLK_AHB0; + break; + case JH7110_SYSCLK_SDIO0_SDCARD: + case JH7110_SYSCLK_SDIO1_SDCARD: + parent = JH7110_SYSCLK_AXI_CFG0; + break; + case JH7110_SYSCLK_TEMP_APB: + parent = JH7110_SYSCLK_APB_BUS; + break; + case JH7110_SYSCLK_TEMP_CORE: + parent = JH7110_SYSCLK_OSC; + break; + case JH7110_SYSCLK_UART0_CORE: + parent = JH7110_SYSCLK_OSC; + div = 1; + break; + default: + printf("%s: unknown clock 0x%08x\n", __func__, idx); + return 0; + } + + if (div == 0) { + printf("%s: zero divisor for clock 0x%08x\n", __func__, idx); + return 0; + } + + freq = stfclock_get_frequency_jh7110_sys(sc, &parent); + return freq / div; +} + +int +stfclock_set_frequency_jh7110_sys(void *cookie, uint32_t *cells, uint32_t freq) +{ + uint32_t idx = cells[0]; + + printf("%s: not handled 0x%08x (freq=0x%08x)\n", __func__, idx, freq); + + return -1; +} + +void +stfclock_enable_jh7110_sys(void *cookie, uint32_t *cells, int on) +{ + struct stfclock_softc *sc = cookie; + uint32_t idx = cells[0]; + + switch (idx) { + case JH7110_SYSCLK_SDIO0_AHB: + case JH7110_SYSCLK_SDIO1_AHB: + case JH7110_SYSCLK_SDIO0_SDCARD: + case JH7110_SYSCLK_SDIO1_SDCARD: + case JH7110_SYSCLK_TEMP_APB: + case JH7110_SYSCLK_TEMP_CORE: + case JH7110_SYSCLK_UART0_CORE: + if (on) + HSET4(sc, idx * 4, 1U << 31); + else + HCLR4(sc, idx * 4, 1U << 31); + return; + } + + printf("%s: unknown clock 0x%08x\n", __func__, idx); +} + +void +stfclock_reset_jh7110_sys(void *cookie, uint32_t *cells, int assert) +{ + struct stfclock_softc *sc = cookie; + uint32_t idx = cells[0]; + uint32_t bits, offset; + + offset = JH7110_SYSCLK_ASSERT_OFFSET + (idx / 32) * 4; + bits = 1U << (idx % 32); + + if (assert) + HSET4(sc, offset, bits); + else + HCLR4(sc, offset, bits); } |