From d526c0ed0dd4cab69fd76bcd9059ae5e57bf9fb1 Mon Sep 17 00:00:00 2001 From: kettenis Date: Mon, 11 Dec 2017 23:24:58 +0000 Subject: [PATCH] Implement support for the "next-generation" clock bindings for the Allwinner A80. --- sys/dev/fdt/sxiccmu.c | 69 ++++++++++++++++++++++++++++++------ sys/dev/fdt/sxiccmu_clocks.h | 51 ++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/sys/dev/fdt/sxiccmu.c b/sys/dev/fdt/sxiccmu.c index d27c4bd0c5c..212f4479edd 100644 --- a/sys/dev/fdt/sxiccmu.c +++ b/sys/dev/fdt/sxiccmu.c @@ -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 * Copyright (c) 2013 Artturi Alm - * Copyright (c) 2016 Mark Kettenis + * Copyright (c) 2016,2017 Mark Kettenis * * 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) { diff --git a/sys/dev/fdt/sxiccmu_clocks.h b/sys/dev/fdt/sxiccmu_clocks.h index 7a6be1f83c4..25accb93f6f 100644 --- a/sys/dev/fdt/sxiccmu_clocks.h +++ b/sys/dev/fdt/sxiccmu_clocks.h @@ -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 -- 2.20.1