Add a few more Allwinner D1 clocks.
authorkettenis <kettenis@openbsd.org>
Fri, 2 Feb 2024 12:01:49 +0000 (12:01 +0000)
committerkettenis <kettenis@openbsd.org>
Fri, 2 Feb 2024 12:01:49 +0000 (12:01 +0000)
ok patrick@

sys/dev/fdt/sxiccmu.c
sys/dev/fdt/sxiccmu_clocks.h

index 0707009..d64ba10 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sxiccmu.c,v 1.33 2024/01/26 17:50:00 kettenis Exp $   */
+/*     $OpenBSD: sxiccmu.c,v 1.34 2024/02/02 12:01:49 kettenis Exp $   */
 /*
  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
  * Copyright (c) 2013 Artturi Alm
@@ -1168,14 +1168,50 @@ sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 }
 
 /* Allwinner D1 */
+#define D1_PLL_CPU_CTRL_REG            0x0000
+#define D1_PLL_CPU_FACTOR_M(x)         (((x) >> 0) & 0x3)
+#define D1_PLL_CPU_FACTOR_N(x)         (((x) >> 8) & 0xff)
+#define D1_RISCV_CLK_REG               0x0d00
+#define D1_RISCV_CLK_SEL               (7 << 24)
+#define D1_RISCV_CLK_SEL_HOSC          (0 << 24)
+#define D1_RISCV_CLK_SEL_PLL_CPU       (5 << 24)
+#define D1_RISCV_DIV_CFG_FACTOR_M(x)   (((x) >> 0) & 0x1f)
 
 uint32_t
 sxiccmu_d1_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
+       uint32_t parent;
+       uint32_t reg;
+       uint32_t m, n;
+
        switch (idx) {
+       case D1_CLK_HOSC:
+               return clock_get_frequency(sc->sc_node, "hosc");
+       case D1_CLK_PLL_CPU:
+               reg = SXIREAD4(sc, D1_PLL_CPU_CTRL_REG);
+               m = D1_PLL_CPU_FACTOR_M(reg) + 1;
+               n = D1_PLL_CPU_FACTOR_N(reg) + 1;
+               return (24000000 * n) / m;
+       case D1_CLK_PLL_PERIPH0:
+               /* Not hardcoded, but recommended. */
+               return 600000000;
        case D1_CLK_APB1:
                /* XXX Controlled by a MUX. */
                return 24000000;
+       case D1_CLK_RISCV:
+               reg = SXIREAD4(sc, D1_RISCV_CLK_REG);
+               switch (reg & D1_RISCV_CLK_SEL) {
+               case D1_RISCV_CLK_SEL_HOSC:
+                       parent = D1_CLK_HOSC;
+                       break;
+               case D1_RISCV_CLK_SEL_PLL_CPU:
+                       parent = D1_CLK_PLL_CPU;
+                       break;
+               default:
+                       return 0;
+               }
+               m = D1_RISCV_DIV_CFG_FACTOR_M(reg) + 1;
+               return sxiccmu_ccu_get_frequency(sc, &parent) / m;
        }
 
        printf("%s: 0x%08x\n", __func__, idx);
@@ -1671,9 +1707,72 @@ sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
        return -1;
 }
 
+#define D1_SMHC0_CLK_REG               0x0830
+#define D1_SMHC1_CLK_REG               0x0834
+#define D1_SMHC2_CLK_REG               0x0838
+#define D1_SMHC_CLK_SRC_SEL                    (0x3 << 24)
+#define D1_SMHC_CLK_SRC_SEL_HOSC               (0x0 << 24)
+#define D1_SMHC_CLK_SRC_SEL_PLL_PERIPH0                (0x1 << 24)
+#define D1_SMHC_FACTOR_N_MASK                  (0x3 << 8)
+#define D1_SMHC_FACTOR_N_SHIFT                 8
+#define D1_SMHC_FACTOR_M_MASK                  (0xf << 0)
+#define D1_SMHC_FACTOR_M_SHIFT                 0
+
+int
+sxiccmu_d1_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 = D1_SMHC_CLK_SRC_SEL_HOSC;
+               break;
+       case 20000000:
+       case 25000000:
+       case 26000000:
+       case 50000000:
+       case 52000000:
+               n = 0, m = 0;
+               clk_src = D1_SMHC_CLK_SRC_SEL_PLL_PERIPH0;
+               parent_freq =
+                   sxiccmu_d1_get_frequency(sc, D1_CLK_PLL_PERIPH0);
+               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 &= ~D1_SMHC_CLK_SRC_SEL;
+       reg |= clk_src;
+       reg &= ~D1_SMHC_FACTOR_N_MASK;
+       reg |= n << D1_SMHC_FACTOR_N_SHIFT;
+       reg &= ~D1_SMHC_FACTOR_M_MASK;
+       reg |= m << D1_SMHC_FACTOR_M_SHIFT;
+       SXIWRITE4(sc, offset, reg);
+
+       return 0;
+}
+
 int
 sxiccmu_d1_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
 {
+       switch (idx) {
+       case D1_CLK_MMC0:
+               return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC0_CLK_REG, freq);
+       case D1_CLK_MMC1:
+               return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC1_CLK_REG, freq);
+       case D1_CLK_MMC2:
+               return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC2_CLK_REG, freq);
+       }
+
        printf("%s: 0x%08x\n", __func__, idx);
        return -1;
 }
index 7dc5a90..f8b4a85 100644 (file)
@@ -304,7 +304,15 @@ const struct sxiccmu_ccu_bit sun9i_a80_mmc_gates[] = {
 
 /* D1 */
 
+#define D1_CLK_PLL_CPU         0
+#define D1_CLK_PLL_PERIPH0     5
 #define D1_CLK_APB1            25
+#define D1_CLK_MMC0            56
+#define D1_CLK_MMC1            57
+#define D1_CLK_MMC2            58
+#define D1_CLK_BUS_MMC0                59
+#define D1_CLK_BUS_MMC1                60
+#define D1_CLK_BUS_MMC2                61
 #define D1_CLK_BUS_UART0       62
 #define D1_CLK_BUS_UART1       63
 #define D1_CLK_BUS_UART2       64
@@ -317,8 +325,17 @@ const struct sxiccmu_ccu_bit sun9i_a80_mmc_gates[] = {
 #define D1_CLK_BUS_OHCI1       100
 #define D1_CLK_BUS_EHCI0       101
 #define D1_CLK_BUS_EHCI1       102
+#define D1_CLK_RISCV           132
+
+#define D1_CLK_HOSC            255
 
 const struct sxiccmu_ccu_bit sun20i_d1_gates[] = {
+       [D1_CLK_MMC0] =      { 0x0830, 31 },
+       [D1_CLK_MMC1] =      { 0x0834, 31 },
+       [D1_CLK_MMC2] =      { 0x0838, 31 },
+       [D1_CLK_BUS_MMC0] =  { 0x084c, 0 },
+       [D1_CLK_BUS_MMC1] =  { 0x084c, 1 },
+       [D1_CLK_BUS_MMC2] =  { 0x084c, 2 },
        [D1_CLK_BUS_UART0] = { 0x090c, 0, D1_CLK_APB1 },
        [D1_CLK_BUS_UART1] = { 0x090c, 1, D1_CLK_APB1 },
        [D1_CLK_BUS_UART2] = { 0x090c, 2, D1_CLK_APB1 },
@@ -801,6 +818,9 @@ const struct sxiccmu_ccu_bit sun9i_a80_mmc_resets[] = {
 
 /* D1 */
 
+#define D1_RST_BUS_MMC0                15
+#define D1_RST_BUS_MMC1                16
+#define D1_RST_BUS_MMC2                17
 #define D1_RST_BUS_UART0       18
 #define D1_RST_BUS_UART1       19
 #define D1_RST_BUS_UART2       20
@@ -815,6 +835,9 @@ const struct sxiccmu_ccu_bit sun9i_a80_mmc_resets[] = {
 #define D1_RST_BUS_EHCI1       45
 
 const struct sxiccmu_ccu_bit sun20i_d1_resets[] = {
+       [D1_RST_BUS_MMC0] =  { 0x084c, 16 },
+       [D1_RST_BUS_MMC1] =  { 0x084c, 17 },
+       [D1_RST_BUS_MMC2] =  { 0x084c, 18 },
        [D1_RST_BUS_UART0] = { 0x090c, 16 },
        [D1_RST_BUS_UART1] = { 0x090c, 17 },
        [D1_RST_BUS_UART2] = { 0x090c, 18 },