summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2023-06-24 18:27:00 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2023-06-24 18:27:00 +0000
commit4b57fdc8405c969abbb8cbb7dddbbac44d9ee33f (patch)
tree21fca09243edb8dadd43004b5626759bd2f7cd27 /sys/arch
parent08a3840f58dc4a05fd64e16e8ced78e6a67e2d16 (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.c379
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);
}