Implement support for the "next-generation" clock bindings for the
authorkettenis <kettenis@openbsd.org>
Mon, 11 Dec 2017 23:24:58 +0000 (23:24 +0000)
committerkettenis <kettenis@openbsd.org>
Mon, 11 Dec 2017 23:24:58 +0000 (23:24 +0000)
Allwinner A80.

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

index d27c4bd..212f447 100644 (file)
@@ -1,8 +1,8 @@
-/*     $OpenBSD: sxiccmu.c,v 1.8 2017/11/19 15:42:07 kettenis Exp $    */
+/*     $OpenBSD: sxiccmu.c,v 1.9 2017/12/11 23:24:58 kettenis Exp $    */
 /*
  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
  * Copyright (c) 2013 Artturi Alm
- * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org>
+ * Copyright (c) 2016,2017 Mark Kettenis <kettenis@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -90,6 +90,8 @@ uint32_t sxiccmu_a10_get_frequency(struct sxiccmu_softc *, uint32_t);
 int    sxiccmu_a10_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
 uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t);
 int    sxiccmu_a64_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
+uint32_t sxiccmu_a80_get_frequency(struct sxiccmu_softc *, uint32_t);
+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);
 
@@ -114,6 +116,7 @@ sxiccmu_match(struct device *parent, void *match, void *aux)
        return (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ccu") ||
            OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-ccu") ||
            OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-ccu") ||
+           OF_is_compatible(faa->fa_node, "allwinner,sun9i-a80-ccu") ||
            OF_is_compatible(faa->fa_node, "allwinner,sun50i-a64-ccu") ||
            OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-ccu"));
 }
@@ -142,14 +145,6 @@ sxiccmu_attach(struct device *parent, struct device *self, void *aux)
                sc->sc_nresets = nitems(sun4i_a10_resets);
                sc->sc_get_frequency = sxiccmu_a10_get_frequency;
                sc->sc_set_frequency = sxiccmu_a10_set_frequency;
-       } else if (OF_is_compatible(sc->sc_node, "allwinner,sun50i-a64-ccu")) {
-               KASSERT(faa->fa_nreg > 0);
-               sc->sc_gates = sun50i_a64_gates;
-               sc->sc_ngates = nitems(sun50i_a64_gates);
-               sc->sc_resets = sun50i_a64_resets;
-               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(sc->sc_node, "allwinner,sun8i-h3-ccu") ||
            OF_is_compatible(sc->sc_node, "allwinner,sun50i-h5-ccu")) {
                KASSERT(faa->fa_nreg > 0);
@@ -159,6 +154,22 @@ sxiccmu_attach(struct device *parent, struct device *self, void *aux)
                sc->sc_nresets = nitems(sun8i_h3_resets);
                sc->sc_get_frequency = sxiccmu_h3_get_frequency;
                sc->sc_set_frequency = sxiccmu_h3_set_frequency;
+       } else if (OF_is_compatible(sc->sc_node, "allwinner,sun9i-a80-ccu")) {
+               KASSERT(faa->fa_nreg > 0);
+               sc->sc_gates = sun9i_a80_gates;
+               sc->sc_ngates = nitems(sun9i_a80_gates);
+               sc->sc_resets = sun9i_a80_resets;
+               sc->sc_nresets = nitems(sun9i_a80_resets);
+               sc->sc_get_frequency = sxiccmu_a80_get_frequency;
+               sc->sc_set_frequency = sxiccmu_a80_set_frequency;
+       } else if (OF_is_compatible(sc->sc_node, "allwinner,sun50i-a64-ccu")) {
+               KASSERT(faa->fa_nreg > 0);
+               sc->sc_gates = sun50i_a64_gates;
+               sc->sc_ngates = nitems(sun50i_a64_gates);
+               sc->sc_resets = sun50i_a64_resets;
+               sc->sc_nresets = nitems(sun50i_a64_resets);
+               sc->sc_get_frequency = sxiccmu_a64_get_frequency;
+               sc->sc_set_frequency = sxiccmu_a64_set_frequency;
        } else {
                for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
                        sxiccmu_attach_clock(sc, node);
@@ -771,6 +782,22 @@ sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
        return 0;
 }
 
+uint32_t
+sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
+{
+       switch (idx) {
+       case A80_CLK_PLL_PERIPH0:
+               /* Not hardcoded, but recommended. */
+               return 960000000;
+       case A80_CLK_APB1:
+               /* XXX Controlled by a MUX. */
+               return 24000000;
+       }
+
+       printf("%s: 0x%08x\n", __func__, idx);
+       return 0;
+}
+
 uint32_t
 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
 {
@@ -884,6 +911,28 @@ sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
        return -1;
 }
 
+int
+sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
+{
+       struct sxiccmu_clock clock;
+       uint32_t parent, parent_freq;
+
+       switch (idx) {
+       case A80_CLK_MMC0:
+       case A80_CLK_MMC1:
+       case A80_CLK_MMC2:
+               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 = A80_CLK_PLL_PERIPH0;
+               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_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
 {
index 7a6be1f..25accb9 100644 (file)
@@ -143,6 +143,39 @@ struct sxiccmu_ccu_bit sun50i_a64_gates[] = {
        [A64_CLK_USB_PHY1] =  { 0x00cc,  9 },
 };
 
+/* A80 */
+
+#define A80_CLK_PLL_PERIPH0    3
+
+#define A80_CLK_APB1           23
+
+#define A80_CLK_MMC0           33
+#define A80_CLK_MMC1           36
+#define A80_CLK_MMC2           39
+#define A80_CLK_MMC3           42
+
+#define A80_CLK_BUS_PIO                111
+#define A80_CLK_BUS_UART0      124
+#define A80_CLK_BUS_UART1      125
+#define A80_CLK_BUS_UART2      126
+#define A80_CLK_BUS_UART3      127
+#define A80_CLK_BUS_UART4      128
+#define A80_CLK_BUS_UART5      129
+
+struct sxiccmu_ccu_bit sun9i_a80_gates[] = {
+       [A80_CLK_MMC0] =      { 0x0410, 31 },
+       [A80_CLK_MMC1] =      { 0x0414, 31 },
+       [A80_CLK_MMC2] =      { 0x0418, 31 },
+       [A80_CLK_MMC2] =      { 0x041c, 31 },
+       [A80_CLK_BUS_PIO] =   { 0x0590, 5 },
+       [A80_CLK_BUS_UART0] = { 0x0594, 16, A80_CLK_APB1 },
+       [A80_CLK_BUS_UART1] = { 0x0594, 17, A80_CLK_APB1 },
+       [A80_CLK_BUS_UART2] = { 0x0594, 18, A80_CLK_APB1 },
+       [A80_CLK_BUS_UART3] = { 0x0594, 19, A80_CLK_APB1 },
+       [A80_CLK_BUS_UART4] = { 0x0594, 20, A80_CLK_APB1 },
+       [A80_CLK_BUS_UART5] = { 0x0594, 21, A80_CLK_APB1 },
+};
+
 /* H3/H5 */
 
 #define H3_CLK_PLL_PERIPH0     9
@@ -269,6 +302,24 @@ struct sxiccmu_ccu_bit sun50i_a64_resets[] = {
        [A64_RST_BUS_I2C2] =  { 0x02d8, 2 },
 };
 
+/* A80 */
+
+#define A80_RST_BUS_UART0      45
+#define A80_RST_BUS_UART1      46
+#define A80_RST_BUS_UART2      47
+#define A80_RST_BUS_UART3      48
+#define A80_RST_BUS_UART4      49
+#define A80_RST_BUS_UART5      50
+
+struct sxiccmu_ccu_bit sun9i_a80_resets[] = {
+       [A80_CLK_BUS_UART0] = { 0x05b4, 16 },
+       [A80_CLK_BUS_UART1] = { 0x05b4, 17 },
+       [A80_CLK_BUS_UART2] = { 0x05b4, 18 },
+       [A80_CLK_BUS_UART3] = { 0x05b4, 19 },
+       [A80_CLK_BUS_UART4] = { 0x05b4, 20 },
+       [A80_CLK_BUS_UART5] = { 0x05b4, 21 },
+};
+
 /* H3/H5 */
 
 #define H3_RST_USB_PHY0                0