Implement Allwinner A40/V40 support.
authorkettenis <kettenis@openbsd.org>
Sat, 30 Dec 2017 16:30:37 +0000 (16:30 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 30 Dec 2017 16:30:37 +0000 (16:30 +0000)
sys/dev/fdt/sxiccmu.c
sys/dev/fdt/sxiccmu_clocks.h

index 8e9f3aa..43c9ff9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sxiccmu.c,v 1.15 2017/12/30 12:45:36 kettenis Exp $   */
+/*     $OpenBSD: sxiccmu.c,v 1.16 2017/12/30 16:30:37 kettenis Exp $   */
 /*
  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
  * Copyright (c) 2013 Artturi Alm
@@ -97,6 +97,8 @@ int   sxiccmu_a80_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
 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_r40_get_frequency(struct sxiccmu_softc *, uint32_t);
+int    sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
 uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t);
 int    sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
 
@@ -128,6 +130,7 @@ sxiccmu_match(struct device *parent, void *match, void *aux)
            OF_is_compatible(node, "allwinner,sun8i-a33-ccu") ||
            OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
            OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
+           OF_is_compatible(node, "allwinner,sun8i-r40-ccu") ||
            OF_is_compatible(node, "allwinner,sun9i-a80-ccu") ||
            OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") ||
            OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") ||
@@ -185,6 +188,14 @@ sxiccmu_attach(struct device *parent, struct device *self, void *aux)
                sc->sc_nresets = nitems(sun8i_h3_r_resets);
                sc->sc_get_frequency = sxiccmu_h3_r_get_frequency;
                sc->sc_set_frequency = sxiccmu_nop_set_frequency;
+       } else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
+               KASSERT(faa->fa_nreg > 0);
+               sc->sc_gates = sun8i_r40_gates;
+               sc->sc_ngates = nitems(sun8i_r40_gates);
+               sc->sc_resets = sun8i_r40_resets;
+               sc->sc_nresets = nitems(sun8i_r40_resets);
+               sc->sc_get_frequency = sxiccmu_r40_get_frequency;
+               sc->sc_set_frequency = sxiccmu_r40_set_frequency;
        } else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) {
                KASSERT(faa->fa_nreg > 0);
                sc->sc_gates = sun9i_a80_gates;
@@ -1116,6 +1127,24 @@ sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
        return 0;
 }
 
+uint32_t
+sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
+{
+       switch (idx) {
+       case R40_CLK_PLL_PERIPH0:
+               /* Not hardcoded, but recommended. */
+               return 600000000;
+       case R40_CLK_PLL_PERIPH0_2X:
+               return sxiccmu_r40_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2;
+       case R40_CLK_APB2:
+               /* XXX Controlled by a MUX. */
+               return 24000000;
+       }
+
+       printf("%s: 0x%08x\n", __func__, idx);
+       return 0;
+}
+
 uint32_t
 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
@@ -1243,6 +1272,29 @@ sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
        return -1;
 }
 
+int
+sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
+{
+       struct sxiccmu_clock clock;
+       uint32_t parent, parent_freq;
+
+       switch (idx) {
+       case R40_CLK_MMC0:
+       case R40_CLK_MMC1:
+       case R40_CLK_MMC2:
+       case R40_CLK_MMC3:
+               clock.sc_iot = sc->sc_iot;
+               bus_space_subregion(sc->sc_iot, sc->sc_ioh,
+                   sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
+               parent = R40_CLK_PLL_PERIPH0_2X;
+               parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
+               return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
+       }
+
+       printf("%s: 0x%08x\n", __func__, idx);
+       return -1;
+}
+
 int
 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
 {
index 11bae00..f71a54e 100644 (file)
@@ -348,12 +348,85 @@ struct sxiccmu_ccu_bit sun8i_h3_gates[] = {
 #define H3_R_CLK_APB0_PIO      3
 #define H3_R_CLK_APB0_I2C      9
 
-
 struct sxiccmu_ccu_bit sun8i_h3_r_gates[] = {
        [H3_R_CLK_APB0_PIO] = { 0x0028, 0 },
        [H3_R_CLK_APB0_I2C] = { 0x0028, 6, H3_R_CLK_APB0 },
 };
 
+/* R40 */
+
+#define R40_CLK_PLL_PERIPH0    11
+#define R40_CLK_PLL_PERIPH0_2X 13
+
+#define R40_CLK_APB2           28
+
+#define R40_CLK_BUS_MMC0       32
+#define R40_CLK_BUS_MMC1       33
+#define R40_CLK_BUS_MMC2       34
+#define R40_CLK_BUS_MMC3       35
+#define R40_CLK_BUS_EHCI0      47
+#define R40_CLK_BUS_EHCI1      48
+#define R40_CLK_BUS_EHCI2      49
+#define R40_CLK_BUS_OHCI0      50
+#define R40_CLK_BUS_OHCI1      51
+#define R40_CLK_BUS_OHCI2      52
+#define R40_CLK_BUS_PIO                79
+#define R40_CLK_BUS_I2C0       87
+#define R40_CLK_BUS_I2C1       88
+#define R40_CLK_BUS_I2C2       89
+#define R40_CLK_BUS_I2C3       90
+#define R40_CLK_BUS_I2C4       95
+#define R40_CLK_BUS_UART0      96
+#define R40_CLK_BUS_UART1      97
+#define R40_CLK_BUS_UART2      98
+#define R40_CLK_BUS_UART3      99
+#define R40_CLK_BUS_UART4      100
+#define R40_CLK_BUS_UART5      101
+#define R40_CLK_BUS_UART6      102
+#define R40_CLK_BUS_UART7      103
+
+#define R40_CLK_MMC0           107
+#define R40_CLK_MMC1           108
+#define R40_CLK_MMC2           109
+#define R40_CLK_MMC3           110
+#define R40_CLK_USB_PHY0       124
+#define R40_CLK_USB_PHY1       125
+#define R40_CLK_USB_PHY2       126
+
+struct sxiccmu_ccu_bit sun8i_r40_gates[] = {
+       [R40_CLK_BUS_MMC0] =  { 0x0060, 8 },
+       [R40_CLK_BUS_MMC1] =  { 0x0060, 9 },
+       [R40_CLK_BUS_MMC2] =  { 0x0060, 10 },
+       [R40_CLK_BUS_MMC3] =  { 0x0060, 11 },
+       [R40_CLK_BUS_EHCI0] = { 0x0060, 26 },
+       [R40_CLK_BUS_EHCI1] = { 0x0060, 27 },
+       [R40_CLK_BUS_EHCI2] = { 0x0060, 28 },
+       [R40_CLK_BUS_OHCI0] = { 0x0060, 29 },
+       [R40_CLK_BUS_OHCI1] = { 0x0060, 30 },
+       [R40_CLK_BUS_OHCI2] = { 0x0060, 31 },
+       [R40_CLK_BUS_PIO] =   { 0x0068, 5 },
+       [R40_CLK_BUS_I2C0] =  { 0x006c, 0, R40_CLK_APB2 },
+       [R40_CLK_BUS_I2C1] =  { 0x006c, 1, R40_CLK_APB2 },
+       [R40_CLK_BUS_I2C2] =  { 0x006c, 2, R40_CLK_APB2 },
+       [R40_CLK_BUS_I2C3] =  { 0x006c, 3, R40_CLK_APB2 },
+       [R40_CLK_BUS_I2C4] =  { 0x006c, 15, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART0] = { 0x006c, 16, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART1] = { 0x006c, 17, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART2] = { 0x006c, 18, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART3] = { 0x006c, 19, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART4] = { 0x006c, 20, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART5] = { 0x006c, 21, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART6] = { 0x006c, 22, R40_CLK_APB2 },
+       [R40_CLK_BUS_UART7] = { 0x006c, 23, R40_CLK_APB2 },
+       [R40_CLK_MMC0]      = { 0x0088, 31 },
+       [R40_CLK_MMC1]      = { 0x008c, 31 },
+       [R40_CLK_MMC2]      = { 0x0090, 31 },
+       [R40_CLK_MMC3]      = { 0x0094, 31 },
+       [R40_CLK_USB_PHY0]  = { 0x00cc, 8 },
+       [R40_CLK_USB_PHY1]  = { 0x00cc, 9 },
+       [R40_CLK_USB_PHY2]  = { 0x00cc, 10 },
+};
+
 /*
  * Reset Signals
  */
@@ -542,3 +615,62 @@ struct sxiccmu_ccu_bit sun8i_h3_resets[] = {
 struct sxiccmu_ccu_bit sun8i_h3_r_resets[] = {
        [H3_R_RST_APB0_I2C] = { 0x00b0, 6 },
 };
+
+/* R40 */
+
+#define R40_RST_USB_PHY0       0
+#define R40_RST_USB_PHY1       1
+#define R40_RST_USB_PHY2       2
+
+#define R40_RST_BUS_MMC0       8
+#define R40_RST_BUS_MMC1       9
+#define R40_RST_BUS_MMC2       10
+#define R40_RST_BUS_MMC3       11
+#define R40_RST_BUS_EHCI0      23
+#define R40_RST_BUS_EHCI1      24
+#define R40_RST_BUS_EHCI2      25
+#define R40_RST_BUS_OHCI0      26
+#define R40_RST_BUS_OHCI1      27
+#define R40_RST_BUS_OHCI2      28
+#define R40_RST_BUS_I2C0       64
+#define R40_RST_BUS_I2C1       65
+#define R40_RST_BUS_I2C2       66
+#define R40_RST_BUS_I2C3       67
+#define R40_RST_BUS_I2C4       72
+#define R40_RST_BUS_UART0      73
+#define R40_RST_BUS_UART1      74
+#define R40_RST_BUS_UART2      75
+#define R40_RST_BUS_UART3      76
+#define R40_RST_BUS_UART4      77
+#define R40_RST_BUS_UART5      78
+#define R40_RST_BUS_UART6      79
+#define R40_RST_BUS_UART7      80
+
+struct sxiccmu_ccu_bit sun8i_r40_resets[] = {
+       [R40_RST_USB_PHY0] =  { 0x00cc, 0 },
+       [R40_RST_USB_PHY1] =  { 0x00cc, 1 },
+       [R40_RST_USB_PHY2] =  { 0x00cc, 2 },
+       [R40_RST_BUS_MMC0] =  { 0x02c0, 8 },
+       [R40_RST_BUS_MMC1] =  { 0x02c0, 9 },
+       [R40_RST_BUS_MMC2] =  { 0x02c0, 10 },
+       [R40_RST_BUS_MMC3] =  { 0x02c0, 11 },
+       [R40_RST_BUS_EHCI0] = { 0x02c0, 26 },
+       [R40_RST_BUS_EHCI1] = { 0x02c0, 27 },
+       [R40_RST_BUS_EHCI2] = { 0x02c0, 28 },
+       [R40_RST_BUS_OHCI0] = { 0x02c0, 29 },
+       [R40_RST_BUS_OHCI1] = { 0x02c0, 30 },
+       [R40_RST_BUS_OHCI2] = { 0x02c0, 31 },
+       [R40_RST_BUS_I2C0] =  { 0x02d8, 0 },
+       [R40_RST_BUS_I2C1] =  { 0x02d8, 1 },
+       [R40_RST_BUS_I2C2] =  { 0x02d8, 2 },
+       [R40_RST_BUS_I2C3] =  { 0x02d8, 3 },
+       [R40_RST_BUS_I2C4] =  { 0x02d8, 15 },
+       [R40_RST_BUS_UART0] = { 0x02d8, 16 },
+       [R40_RST_BUS_UART1] = { 0x02d8, 17 },
+       [R40_RST_BUS_UART2] = { 0x02d8, 18 },
+       [R40_RST_BUS_UART3] = { 0x02d8, 19 },
+       [R40_RST_BUS_UART4] = { 0x02d8, 20 },
+       [R40_RST_BUS_UART5] = { 0x02d8, 21 },
+       [R40_RST_BUS_UART6] = { 0x02d8, 22 },
+       [R40_RST_BUS_UART7] = { 0x02d8, 23 },
+};