Implement A10/A20 CPU clock.
authorkettenis <kettenis@openbsd.org>
Sun, 24 Dec 2017 18:24:06 +0000 (18:24 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 24 Dec 2017 18:24:06 +0000 (18:24 +0000)
sys/dev/fdt/sxiccmu.c
sys/dev/fdt/sxiccmu_clocks.h

index 6612929..2386418 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sxiccmu.c,v 1.11 2017/12/15 09:15:36 kettenis Exp $   */
+/*     $OpenBSD: sxiccmu.c,v 1.12 2017/12/24 18:24:06 kettenis Exp $   */
 /*
  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
  * Copyright (c) 2013 Artturi Alm
@@ -755,27 +755,58 @@ sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells)
        return sc->sc_get_frequency(sc, idx);
 }
 
-/* Allwinner H3/A64 */
-#define CCU_AHB1_APB1_CFG_REG          0x0054
-#define CCU_AHB1_CLK_SRC_SEL           (3 << 12)
-#define CCU_AHB1_CLK_SRC_SEL_LOSC      (0 << 12)
-#define CCU_AHB1_CLK_SRC_SEL_OSC24M    (1 << 12)
-#define CCU_AHB1_CLK_SRC_SEL_AXI       (2 << 12)
-#define CCU_AHB1_CLK_SRC_SEL_PERIPH0   (3 << 12)
-#define CCU_AHB1_PRE_DIV(x)            ((((x) >> 6) & 3) + 1)
-#define CCU_AHB1_CLK_DIV_RATIO(x)      (1 << (((x) >> 4) & 3))
-#define CCU_AHB2_CFG_REG               0x005c
-#define CCU_AHB2_CLK_CFG               (3 << 0)
+/* Allwinner A10/A20 */
+#define A10_PLL1_CFG_REG               0x0000
+#define A10_PLL1_OUT_EXT_DIVP(x)       (((x) >> 16) & 0x3)
+#define A10_PLL1_FACTOR_N(x)           (((x) >> 8) & 0x1f)
+#define A10_PLL1_FACTOR_K(x)           (((x) >> 4) & 0x3)
+#define A10_PLL1_FACTOR_M(x)           (((x) >> 0) & 0x3)
+#define A10_CPU_AHB_APB0_CFG_REG       0x0054
+#define A10_CPU_CLK_SRC_SEL            (0x3 << 16)
+#define A10_CPU_CLK_SRC_SEL_LOSC       (0x0 << 16)
+#define A10_CPU_CLK_SRC_SEL_OSC24M     (0x1 << 16)
+#define A10_CPU_CLK_SRC_SEL_PLL1       (0x2 << 16)
+#define A10_CPU_CLK_SRC_SEL_200MHZ     (0x3 << 16)
 
 uint32_t
 sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
+       uint32_t parent;
+       uint32_t reg, k, m, n, p;
+
        switch (idx) {
+       case A10_CLK_LOSC:
+               return clock_get_frequency(sc->sc_node, "losc");
+       case A10_CLK_HOSC:
+               return clock_get_frequency(sc->sc_node, "hosc");
+       case A10_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 A10_CLK_PLL_PERIPH_BASE:
                /* Not hardcoded, but recommended. */
                return 600000000;
        case A10_CLK_PLL_PERIPH:
                return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2;
+       case A10_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 = A10_CLK_LOSC;
+                       break;
+               case A10_CPU_CLK_SRC_SEL_OSC24M:
+                       parent = A10_CLK_HOSC;
+                       break;
+               case A10_CPU_CLK_SRC_SEL_PLL1:
+                       parent = A10_CLK_PLL_CORE;
+                       break;
+               case A10_CPU_CLK_SRC_SEL_200MHZ:
+                       return 200000000;
+               }
+               return sxiccmu_ccu_get_frequency(sc, &parent);
        case A10_CLK_APB1:
                /* XXX Controlled by a MUX. */
                return 24000000;
@@ -785,6 +816,18 @@ sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
        return 0;
 }
 
+/* Allwinner H3/A64 */
+#define CCU_AHB1_APB1_CFG_REG          0x0054
+#define CCU_AHB1_CLK_SRC_SEL           (3 << 12)
+#define CCU_AHB1_CLK_SRC_SEL_LOSC      (0 << 12)
+#define CCU_AHB1_CLK_SRC_SEL_OSC24M    (1 << 12)
+#define CCU_AHB1_CLK_SRC_SEL_AXI       (2 << 12)
+#define CCU_AHB1_CLK_SRC_SEL_PERIPH0   (3 << 12)
+#define CCU_AHB1_PRE_DIV(x)            ((((x) >> 6) & 3) + 1)
+#define CCU_AHB1_CLK_DIV_RATIO(x)      (1 << (((x) >> 4) & 3))
+#define CCU_AHB2_CFG_REG               0x005c
+#define CCU_AHB2_CLK_CFG               (3 << 0)
+
 uint32_t
 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
index 74bed95..58800aa 100644 (file)
@@ -7,9 +7,12 @@
 
 /* A10/A20 */
 
+#define A10_CLK_HOSC           1
+#define A10_CLK_PLL_CORE       2
 #define A10_CLK_PLL_PERIPH_BASE        14
 #define A10_CLK_PLL_PERIPH     15
 
+#define A10_CLK_CPU            20
 #define A10_CLK_APB1           25
 
 #define A10_CLK_AHB_EHCI0      27
@@ -43,6 +46,8 @@
 #define A10_CLK_SATA           122
 #define A10_CLK_USB_PHY                125
 
+#define A10_CLK_LOSC           254
+
 struct sxiccmu_ccu_bit sun4i_a10_gates[] = {
        [A10_CLK_AHB_EHCI0] =  { 0x0060, 1 },
        [A10_CLK_AHB_EHCI1] =  { 0x0060, 3 },