> Date: Fri, 06 Sep 2019 23:08:18 +0900
> From: SASANO Takayoshi <u...@mx5.nisiq.net>
> 
> Hi,
> 
> > Here is a start for H6 support in sxiccmu(4).  Can you try this and
> > send me new console output?
> 
> here is the log,

Some progress, as now the USB controllers initialize properly.  Below
is a new diff that should help with the SD/MMC devices.

> ---
> 
> And, I have a question about previous sxipio(4) diff.
> 
> Allwinner H6 datasheet says that GPIO port C, D, F, G, H, L and M are
> configuable. Your diff codes port A and B, are they required?

I don't know.  The tables are generated by a bit of code that directly
uses the mainline Linux code:

  https://github.com/kettenis/sxipins

the port A and B pins aren't used anywhere in the device trees so
they're currently unused.


Index: dev/fdt/sxiccmu.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu.c,v
retrieving revision 1.23
diff -u -p -r1.23 sxiccmu.c
--- dev/fdt/sxiccmu.c   2 Sep 2019 13:08:49 -0000       1.23
+++ dev/fdt/sxiccmu.c   7 Sep 2019 11:33:18 -0000
@@ -101,6 +101,9 @@ int sxiccmu_a80_set_frequency(struct sxi
 uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t);
 int    sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
 uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t);
+uint32_t sxiccmu_h6_get_frequency(struct sxiccmu_softc *, uint32_t);
+int    sxiccmu_h6_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
+uint32_t sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *, uint32_t);
 uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t);
 int    sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
 uint32_t sxiccmu_v3s_get_frequency(struct sxiccmu_softc *, uint32_t);
@@ -144,7 +147,9 @@ sxiccmu_match(struct device *parent, voi
            OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") ||
            OF_is_compatible(node, "allwinner,sun50i-a64-ccu") ||
            OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") ||
-           OF_is_compatible(node, "allwinner,sun50i-h5-ccu"));
+           OF_is_compatible(node, "allwinner,sun50i-h5-ccu") ||
+           OF_is_compatible(node, "allwinner,sun50i-h6-ccu") ||
+           OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu"));
 }
 
 void
@@ -255,6 +260,22 @@ sxiccmu_attach(struct device *parent, st
                sc->sc_nresets = nitems(sun50i_a64_resets);
                sc->sc_get_frequency = sxiccmu_a64_get_frequency;
                sc->sc_set_frequency = sxiccmu_a64_set_frequency;
+       } else if (OF_is_compatible(node, "allwinner,sun50i-h6-ccu")) {
+               KASSERT(faa->fa_nreg > 0);
+               sc->sc_gates = sun50i_h6_gates;
+               sc->sc_ngates = nitems(sun50i_h6_gates);
+               sc->sc_resets = sun50i_h6_resets;
+               sc->sc_nresets = nitems(sun50i_h6_resets);
+               sc->sc_get_frequency = sxiccmu_h6_get_frequency;
+               sc->sc_set_frequency = sxiccmu_h6_set_frequency;
+       } else if (OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu")) {
+               KASSERT(faa->fa_nreg > 0);
+               sc->sc_gates = sun50i_h6_r_gates;
+               sc->sc_ngates = nitems(sun50i_h6_r_gates);
+               sc->sc_resets = sun50i_h6_r_resets;
+               sc->sc_nresets = nitems(sun50i_h6_r_resets);
+               sc->sc_get_frequency = sxiccmu_h6_r_get_frequency;
+               sc->sc_set_frequency = sxiccmu_nop_set_frequency;
        } else {
                for (node = OF_child(node); node; node = OF_peer(node))
                        sxiccmu_attach_clock(sc, node, faa->fa_nreg);
@@ -975,13 +996,13 @@ sxiccmu_a23_get_frequency(struct sxiccmu
 #define A64_PLL_CPUX_LOCK              (1 << 28)
 #define A64_PLL_CPUX_OUT_EXT_DIVP(x)   (((x) >> 16) & 0x3)
 #define A64_PLL_CPUX_OUT_EXT_DIVP_MASK (0x3 << 16)
-#define A64_PLL_CPUX_FACTOR_N(x)               (((x) >> 8) & 0x1f)
+#define A64_PLL_CPUX_FACTOR_N(x)       (((x) >> 8) & 0x1f)
 #define A64_PLL_CPUX_FACTOR_N_MASK     (0x1f << 8)
 #define A64_PLL_CPUX_FACTOR_N_SHIFT    8
-#define A64_PLL_CPUX_FACTOR_K(x)               (((x) >> 4) & 0x3)
+#define A64_PLL_CPUX_FACTOR_K(x)       (((x) >> 4) & 0x3)
 #define A64_PLL_CPUX_FACTOR_K_MASK     (0x3 << 4)
 #define A64_PLL_CPUX_FACTOR_K_SHIFT    4
-#define A64_PLL_CPUX_FACTOR_M(x)               (((x) >> 0) & 0x3)
+#define A64_PLL_CPUX_FACTOR_M(x)       (((x) >> 0) & 0x3)
 #define A64_PLL_CPUX_FACTOR_M_MASK     (0x3 << 0)
 #define A64_CPUX_AXI_CFG_REG           0x0050
 #define A64_CPUX_CLK_SRC_SEL           (0x3 << 16)
@@ -1243,6 +1264,39 @@ sxiccmu_h3_r_get_frequency(struct sxiccm
 }
 
 uint32_t
+sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
+{
+       switch (idx) {
+       case H6_CLK_PLL_PERIPH0:
+               /* Not hardcoded, but recommended. */
+               return 600000000;
+       case H6_CLK_PLL_PERIPH0_2X:
+               return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2;
+       case H6_CLK_APB2:
+               /* XXX Controlled by a MUX. */
+               return 24000000;
+               break;
+       }
+
+       printf("%s: 0x%08x\n", __func__, idx);
+       return 0;
+}
+
+uint32_t
+sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
+{
+       switch (idx) {
+       case H6_R_CLK_APB2:
+               /* XXX Controlled by a MUX. */
+               return 24000000;
+               break;
+       }
+
+       printf("%s: 0x%08x\n", __func__, idx);
+       return 0;
+}
+
+uint32_t
 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
        uint32_t parent;
@@ -1553,6 +1607,76 @@ sxiccmu_h3_set_frequency(struct sxiccmu_
        return -1;
 }
 
+#define H6_SMHC0_CLK_REG               0x0830
+#define H6_SMHC1_CLK_REG               0x0834
+#define H6_SMHC2_CLK_REG               0x0838
+#define H6_SMHC_CLK_SRC_SEL                    (0x3 << 24)
+#define H6_SMHC_CLK_SRC_SEL_OSC24M             (0x0 << 16)
+#define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X     (0x1 << 16)
+#define H6_SMHC_FACTOR_N_MASK                  (0x3 << 8)
+#define H6_SMHC_FACTOR_N_SHIFT                 8
+#define H6_SMHC_FACTOR_M_MASK                  (0xf << 0)
+#define H6_SMHC_FACTOR_M_SHIFT                 0
+
+int
+sxiccmu_h6_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 = H6_SMHC_CLK_SRC_SEL_OSC24M;
+               break;
+       case 20000000:
+       case 25000000:
+       case 26000000:
+       case 50000000:
+       case 52000000:
+               n = 0, m = 0;
+               clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X;
+               parent_freq =
+                   sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X);
+               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 &= ~H6_SMHC_CLK_SRC_SEL;
+       reg |= clk_src;
+       reg &= ~H6_SMHC_FACTOR_N_MASK;
+       reg |= n << H6_SMHC_FACTOR_N_SHIFT;
+       reg &= ~H6_SMHC_FACTOR_M_MASK;
+       reg |= m << H6_SMHC_FACTOR_M_SHIFT;
+       SXIWRITE4(sc, offset, reg);
+
+       return 0;
+}
+
+int
+sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
+{
+       switch (idx) {
+       case H6_CLK_MMC0:
+               return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG, freq);
+       case H6_CLK_MMC1:
+               return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG, freq);
+       case H6_CLK_MMC2:
+               return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG, freq);
+       }
+
+       printf("%s: 0x%08x\n", __func__, idx);
+       return -1;
+}
+
 int
 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t 
freq)
 {
@@ -1619,6 +1743,10 @@ sxiccmu_ccu_enable(void *cookie, uint32_
                printf("%s: 0x%08x\n", __func__, cells[0]);
                return;
        }
+
+       /* If the clock can't be gated, simply return. */
+       if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff)
+               return;
 
        reg = sc->sc_gates[idx].reg;
        bit = sc->sc_gates[idx].bit;
Index: dev/fdt/sxiccmu_clocks.h
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu_clocks.h,v
retrieving revision 1.26
diff -u -p -r1.26 sxiccmu_clocks.h
--- dev/fdt/sxiccmu_clocks.h    2 Sep 2019 15:24:39 -0000       1.26
+++ dev/fdt/sxiccmu_clocks.h    7 Sep 2019 11:33:18 -0000
@@ -387,6 +387,59 @@ struct sxiccmu_ccu_bit sun8i_h3_r_gates[
        [H3_R_CLK_APB0_I2C] = { 0x0028, 6, H3_R_CLK_APB0 },
 };
 
+/* H6 */
+
+#define H6_CLK_PLL_PERIPH0     3
+#define H6_CLK_PLL_PERIPH0_2X  4
+#define H6_CLK_APB1            26
+#define H6_CLK_APB2            27
+#define H6_CLK_MMC0            64
+#define H6_CLK_MMC1            65
+#define H6_CLK_MMC2            66
+#define H6_CLK_BUS_MMC0                67
+#define H6_CLK_BUS_MMC1                68
+#define H6_CLK_BUS_MMC2                69
+#define H6_CLK_BUS_UART0       70
+#define H6_CLK_BUS_UART1       71
+#define H6_CLK_BUS_UART2       72
+#define H6_CLK_BUS_UART3       73
+#define H6_CLK_USB_OHCI0       104
+#define H6_CLK_USB_OHCI3       107
+#define H6_CLK_BUS_OHCI0       111
+#define H6_CLK_BUS_OHCI3       112
+#define H6_CLK_BUS_EHCI0       113
+#define H6_CLK_BUS_EHCI3       115
+
+struct sxiccmu_ccu_bit sun50i_h6_gates[] = {
+       [H6_CLK_PLL_PERIPH0] = { 0x0020, 31 },
+       [H6_CLK_APB1] = { 0xffff, 0xff },
+       [H6_CLK_MMC0] = { 0x0830, 31 },
+       [H6_CLK_MMC1] = { 0x0834, 31 },
+       [H6_CLK_MMC2] = { 0x0838, 31 },
+       [H6_CLK_BUS_MMC0] = { 0x084c, 0 },
+       [H6_CLK_BUS_MMC1] = { 0x084c, 1 },
+       [H6_CLK_BUS_MMC2] = { 0x084c, 2 },
+       [H6_CLK_BUS_UART0] = { 0x090c, 0, H6_CLK_APB2 },
+       [H6_CLK_BUS_UART1] = { 0x090c, 1, H6_CLK_APB2 },
+       [H6_CLK_BUS_UART2] = { 0x090c, 2, H6_CLK_APB2 },
+       [H6_CLK_BUS_UART3] = { 0x090c, 3, H6_CLK_APB2 },
+       [H6_CLK_USB_OHCI0] = { 0x0a70, 31 },
+       [H6_CLK_USB_OHCI3] = { 0x0a7c, 31 },
+       [H6_CLK_BUS_OHCI0] = { 0x0a8c, 0 },
+       [H6_CLK_BUS_OHCI3] = { 0x0a8c, 3 },
+       [H6_CLK_BUS_EHCI0] = { 0x0a8c, 4 },
+       [H6_CLK_BUS_EHCI3] = { 0x0a8c, 7 },
+};
+
+#define H6_R_CLK_APB1          2
+#define H6_R_CLK_APB2          3
+#define H6_R_CLK_APB2_I2C      8
+
+struct sxiccmu_ccu_bit sun50i_h6_r_gates[] = {
+       [H6_R_CLK_APB1] = { 0xffff, 0xff },
+       [H6_R_CLK_APB2_I2C] = { 0x019c, 1, H6_R_CLK_APB2 },
+};
+
 /* R40 */
 
 #define R40_CLK_PLL_PERIPH0    11
@@ -722,6 +775,40 @@ struct sxiccmu_ccu_bit sun8i_h3_resets[]
 struct sxiccmu_ccu_bit sun8i_h3_r_resets[] = {
        [H3_R_RST_APB0_RSB] = { 0x00b0, 3 },
        [H3_R_RST_APB0_I2C] = { 0x00b0, 6 },
+};
+
+/* H6 */
+
+#define H6_RST_BUS_MMC0                18
+#define H6_RST_BUS_MMC1                19
+#define H6_RST_BUS_MMC2                20
+#define H6_RST_BUS_UART0       21
+#define H6_RST_BUS_UART1       22
+#define H6_RST_BUS_UART2       23
+#define H6_RST_BUS_UART3       24
+#define H6_RST_BUS_OHCI0       48
+#define H6_RST_BUS_OHCI3       49
+#define H6_RST_BUS_EHCI0       50
+#define H6_RST_BUS_EHCI3       52
+
+struct sxiccmu_ccu_bit sun50i_h6_resets[] = {
+       [H6_RST_BUS_MMC0] = { 0x084c, 16 },
+       [H6_RST_BUS_MMC1] = { 0x084c, 17 },
+       [H6_RST_BUS_MMC2] = { 0x084c, 18 },
+       [H6_RST_BUS_UART0] = { 0x090c, 16 },
+       [H6_RST_BUS_UART1] = { 0x090c, 17 },
+       [H6_RST_BUS_UART2] = { 0x090c, 18 },
+       [H6_RST_BUS_UART3] = { 0x090c, 19 },
+       [H6_RST_BUS_OHCI0] = { 0x0a8c, 16 },
+       [H6_RST_BUS_OHCI3] = { 0x0a8c, 19 },
+       [H6_RST_BUS_EHCI0] = { 0x0a8c, 20 },
+       [H6_RST_BUS_EHCI3] = { 0x0a8c, 23 },
+};
+
+#define H6_R_RST_APB2_I2C      4
+
+struct sxiccmu_ccu_bit sun50i_h6_r_resets[] = {
+       [H6_R_RST_APB2_I2C] = { 0x019c, 16 },
 };
 
 /* R40 */

Reply via email to