summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2017-12-31 10:54:40 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2017-12-31 10:54:40 +0000
commit727b13c5e68ad4e3ae0562534acfa04d92ae0c33 (patch)
treea76aa1b1f7baa3fa666670c2834231ab7bb0aa42 /sys
parentaa6ff457ffd8edf5ece5a625a6198fbeea2741dc (diff)
Implement H3/H5 CPU clock.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/fdt/sxiccmu.c38
-rw-r--r--sys/dev/fdt/sxiccmu_clocks.h2
2 files changed, 39 insertions, 1 deletions
diff --git a/sys/dev/fdt/sxiccmu.c b/sys/dev/fdt/sxiccmu.c
index 43c9ff91c83..560adf6884c 100644
--- a/sys/dev/fdt/sxiccmu.c
+++ b/sys/dev/fdt/sxiccmu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sxiccmu.c,v 1.16 2017/12/30 16:30:37 kettenis Exp $ */
+/* $OpenBSD: sxiccmu.c,v 1.17 2017/12/31 10:54:39 kettenis Exp $ */
/*
* Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
* Copyright (c) 2013 Artturi Alm
@@ -1020,20 +1020,56 @@ sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
return 0;
}
+/* Allwinner H3/H5 */
+#define H3_PLL_CPUX_CTRL_REG 0x0000
+#define H3_PLL_CPUX_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3)
+#define H3_PLL_CPUX_FACTOR_N(x) (((x) >> 8) & 0x1f)
+#define H3_PLL_CPUX_FACTOR_K(x) (((x) >> 4) & 0x3)
+#define H3_PLL_CPUX_FACTOR_M(x) (((x) >> 0) & 0x3)
+#define H3_CPUX_AXI_CFG_REG 0x0050
+#define H3_CPUX_CLK_SRC_SEL (0x3 << 16)
+#define H3_CPUX_CLK_SRC_SEL_LOSC (0x0 << 16)
+#define H3_CPUX_CLK_SRC_SEL_OSC24M (0x1 << 16)
+#define H3_CPUX_CLK_SRC_SEL_PLL_CPUX (0x2 << 16)
+
uint32_t
sxiccmu_h3_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 H3_CLK_LOSC:
return clock_get_frequency(sc->sc_node, "losc");
case H3_CLK_HOSC:
return clock_get_frequency(sc->sc_node, "hosc");
+ case H3_CLK_PLL_CPUX:
+ reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
+ k = H3_PLL_CPUX_FACTOR_K(reg) + 1;
+ m = H3_PLL_CPUX_FACTOR_M(reg) + 1;
+ n = H3_PLL_CPUX_FACTOR_N(reg) + 1;
+ p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg);
+ return (24000000 * n * k) / (m * p);
case H3_CLK_PLL_PERIPH0:
/* Not hardcoded, but recommended. */
return 600000000;
+ case H3_CLK_CPUX:
+ reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
+ switch (reg & H3_CPUX_CLK_SRC_SEL) {
+ case H3_CPUX_CLK_SRC_SEL_LOSC:
+ parent = H3_CLK_LOSC;
+ break;
+ case H3_CPUX_CLK_SRC_SEL_OSC24M:
+ parent = H3_CLK_HOSC;
+ break;
+ case H3_CPUX_CLK_SRC_SEL_PLL_CPUX:
+ parent = H3_CLK_PLL_CPUX;
+ break;
+ default:
+ return 0;
+ }
+ return sxiccmu_ccu_get_frequency(sc, &parent);
case H3_CLK_APB2:
/* XXX Controlled by a MUX. */
return 24000000;
diff --git a/sys/dev/fdt/sxiccmu_clocks.h b/sys/dev/fdt/sxiccmu_clocks.h
index f71a54e7bc1..12ff9b9dfae 100644
--- a/sys/dev/fdt/sxiccmu_clocks.h
+++ b/sys/dev/fdt/sxiccmu_clocks.h
@@ -269,8 +269,10 @@ struct sxiccmu_ccu_bit sun9i_a80_mmc_gates[] = {
/* H3/H5 */
+#define H3_CLK_PLL_CPUX 0
#define H3_CLK_PLL_PERIPH0 9
+#define H3_CLK_CPUX 14
#define H3_CLK_AXI 15
#define H3_CLK_AHB1 16
#define H3_CLK_APB1 17