-/* $OpenBSD: sxiccmu.c,v 1.12 2017/12/24 18:24:06 kettenis Exp $ */
+/* $OpenBSD: sxiccmu.c,v 1.13 2017/12/26 09:31:51 kevlo Exp $ */
/*
* Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
* Copyright (c) 2013 Artturi Alm
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_a23_get_frequency(struct sxiccmu_softc *, uint32_t);
+int sxiccmu_a23_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);
OF_is_compatible(node, "allwinner,sun5i-a10s") ||
OF_is_compatible(node, "allwinner,sun5i-r8") ||
OF_is_compatible(node, "allwinner,sun7i-a20") ||
+ OF_is_compatible(node, "allwinner,sun8i-a23") ||
+ OF_is_compatible(node, "allwinner,sun8i-a33") ||
OF_is_compatible(node, "allwinner,sun8i-h3") ||
OF_is_compatible(node, "allwinner,sun9i-a80") ||
OF_is_compatible(node, "allwinner,sun50i-a64") ||
return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
OF_is_compatible(node, "allwinner,sun7i-a20-ccu") ||
+ OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
+ OF_is_compatible(node, "allwinner,sun8i-a33-ccu") ||
OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
OF_is_compatible(node, "allwinner,sun9i-a80-ccu") ||
OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") ||
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(node, "allwinner,sun8i-a23-ccu") ||
+ OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) {
+ KASSERT(faa->fa_nreg > 0);
+ sc->sc_gates = sun8i_a23_gates;
+ sc->sc_ngates = nitems(sun8i_a23_gates);
+ sc->sc_resets = sun8i_a23_resets;
+ sc->sc_nresets = nitems(sun8i_a23_resets);
+ sc->sc_get_frequency = sxiccmu_a23_get_frequency;
+ sc->sc_set_frequency = sxiccmu_a23_set_frequency;
} else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) {
KASSERT(faa->fa_nreg > 0);
.compat = "allwinner,sun8i-a23-apb0-clk",
.get_frequency = sxiccmu_apbs_get_frequency
},
+ {
+ .compat = "allwinner,sun8i-a23-ahb1-gates-clk",
+ .get_frequency = sxiccmu_gen_get_frequency,
+ .enable = sxiccmu_gate_enable
+ },
+ {
+ .compat = "allwinner,sun8i-a23-apb0-gates-clk",
+ .get_frequency = sxiccmu_gen_get_frequency,
+ .enable = sxiccmu_gate_enable
+ },
+ {
+ .compat = "allwinner,sun8i-a23-apb1-gates-clk",
+ .get_frequency = sxiccmu_gen_get_frequency,
+ .enable = sxiccmu_gate_enable
+ },
+ {
+ .compat = "allwinner,sun8i-a23-apb2-gates-clk",
+ .get_frequency = sxiccmu_gen_get_frequency,
+ .enable = sxiccmu_gate_enable
+ },
+ {
+ .compat = "allwinner,sun8i-a23-usb-clk",
+ .get_frequency = sxiccmu_gen_get_frequency,
+ .enable = sxiccmu_gate_enable,
+ .reset = sxiccmu_reset
+ },
{
.compat = "allwinner,sun8i-h3-apb0-gates-clk",
.get_frequency = sxiccmu_gen_get_frequency,
#define CCU_AHB2_CFG_REG 0x005c
#define CCU_AHB2_CLK_CFG (3 << 0)
+uint32_t
+sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
+{
+ uint32_t parent;
+ uint32_t reg, div;
+
+ switch (idx) {
+ case A23_CLK_LOSC:
+ return clock_get_frequency(sc->sc_node, "losc");
+ case A23_CLK_HOSC:
+ return clock_get_frequency(sc->sc_node, "hosc");
+ case A23_CLK_PLL_PERIPH:
+ /* Not hardcoded, but recommended. */
+ return 600000000;
+ case A23_CLK_APB2:
+ /* XXX Controlled by a MUX. */
+ return 24000000;
+ case A23_CLK_AHB1:
+ reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
+ div = CCU_AHB1_CLK_DIV_RATIO(reg);
+ switch (reg & CCU_AHB1_CLK_SRC_SEL) {
+ case CCU_AHB1_CLK_SRC_SEL_LOSC:
+ parent = A23_CLK_LOSC;
+ break;
+ case CCU_AHB1_CLK_SRC_SEL_OSC24M:
+ parent = A23_CLK_HOSC;
+ break;
+ case CCU_AHB1_CLK_SRC_SEL_AXI:
+ parent = A23_CLK_AXI;
+ break;
+ case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
+ parent = A23_CLK_PLL_PERIPH;
+ div *= CCU_AHB1_PRE_DIV(reg);
+ break;
+ default:
+ return 0;
+ }
+ return sxiccmu_ccu_get_frequency(sc, &parent) / div;
+ }
+
+ printf("%s: 0x%08x\n", __func__, idx);
+ return 0;
+}
+
uint32_t
sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
{
return -1;
}
+int
+sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
+{
+ struct sxiccmu_clock clock;
+ uint32_t parent, parent_freq;
+
+ switch (idx) {
+ case A23_CLK_MMC0:
+ case A23_CLK_MMC1:
+ case A23_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 = A23_CLK_PLL_PERIPH;
+ 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_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
{
[A10_CLK_USB_PHY] = { 0x00cc, 8 },
};
+/* A23/A33 */
+
+#define A23_CLK_PLL_PERIPH 10
+
+#define A23_CLK_AXI 19
+#define A23_CLK_AHB1 20
+#define A23_CLK_APB1 21
+#define A23_CLK_APB2 22
+
+#define A23_CLK_BUS_MMC0 26
+#define A23_CLK_BUS_MMC1 27
+#define A23_CLK_BUS_MMC2 28
+#define A23_CLK_BUS_EHCI 35
+#define A23_CLK_BUS_OHCI 36
+#define A23_CLK_BUS_PIO 48
+#define A23_CLK_BUS_I2C0 51
+#define A23_CLK_BUS_I2C1 52
+#define A23_CLK_BUS_I2C2 53
+#define A23_CLK_BUS_UART0 54
+#define A23_CLK_BUS_UART1 55
+#define A23_CLK_BUS_UART2 56
+#define A23_CLK_BUS_UART3 57
+#define A23_CLK_BUS_UART4 58
+
+#define A23_CLK_MMC0 60
+#define A23_CLK_MMC1 63
+#define A23_CLK_MMC2 66
+
+struct sxiccmu_ccu_bit sun8i_a23_gates[] = {
+ [A23_CLK_BUS_MMC0] = { 0x0060, 8 },
+ [A23_CLK_BUS_MMC1] = { 0x0060, 9 },
+ [A23_CLK_BUS_MMC2] = { 0x0060, 10 },
+ [A23_CLK_BUS_EHCI] = { 0x0060, 26 },
+ [A23_CLK_BUS_OHCI] = { 0x0060, 29 },
+ [A23_CLK_BUS_PIO] = { 0x0068, 5 },
+ [A23_CLK_BUS_I2C0] = { 0x006c, 0, A23_CLK_APB2 },
+ [A23_CLK_BUS_I2C1] = { 0x006c, 1, A23_CLK_APB2 },
+ [A23_CLK_BUS_I2C2] = { 0x006c, 2, A23_CLK_APB2 },
+ [A23_CLK_BUS_UART0] = { 0x006c, 16, A23_CLK_APB2 },
+ [A23_CLK_BUS_UART1] = { 0x006c, 17, A23_CLK_APB2 },
+ [A23_CLK_BUS_UART2] = { 0x006c, 18, A23_CLK_APB2 },
+ [A23_CLK_BUS_UART3] = { 0x006c, 19, A23_CLK_APB2 },
+ [A23_CLK_BUS_UART4] = { 0x006c, 20, A23_CLK_APB2 },
+ [A23_CLK_MMC0] = { 0x0088, 31 },
+ [A23_CLK_MMC1] = { 0x008c, 31 },
+ [A23_CLK_MMC2] = { 0x0090, 31 },
+};
+
/* A64 */
#define A64_CLK_PLL_PERIPH0 11
[A10_RST_USB_PHY2] = { 0x00cc, 2 },
};
+/* A23/A33 */
+
+#define A23_RST_USB_PHY0 0
+#define A23_RST_USB_PHY1 1
+
+#define A23_RST_BUS_MMC0 7
+#define A23_RST_BUS_MMC1 8
+#define A23_RST_BUS_MMC2 9
+
+#define A23_RST_BUS_EHCI 16
+#define A23_RST_BUS_OHCI 17
+
+#define A23_RST_BUS_I2C0 32
+#define A23_RST_BUS_I2C1 33
+#define A23_RST_BUS_I2C2 34
+
+#define A23_CLK_HOSC 253
+#define A23_CLK_LOSC 254
+
+struct sxiccmu_ccu_bit sun8i_a23_resets[] = {
+ [A23_RST_USB_PHY0] = { 0x00cc, 0 },
+ [A23_RST_USB_PHY1] = { 0x00cc, 1 },
+ [A23_RST_BUS_MMC0] = { 0x02c0, 8 },
+ [A23_RST_BUS_MMC1] = { 0x02c0, 9 },
+ [A23_RST_BUS_MMC2] = { 0x02c0, 10 },
+ [A23_RST_BUS_EHCI] = { 0x02c0, 26 },
+ [A23_RST_BUS_OHCI] = { 0x02c0, 29 },
+ [A23_RST_BUS_I2C0] = { 0x02d8, 0 },
+ [A23_RST_BUS_I2C1] = { 0x02d8, 1 },
+ [A23_RST_BUS_I2C2] = { 0x02d8, 2 },
+};
+
/* A64 */
#define A64_RST_USB_PHY0 0