1*dcec61dcSmiod /* $OpenBSD: amlclock.c,v 1.15 2023/08/15 08:27:29 miod Exp $ */
29e02bd04Skettenis /*
39e02bd04Skettenis * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
49e02bd04Skettenis *
59e02bd04Skettenis * Permission to use, copy, modify, and distribute this software for any
69e02bd04Skettenis * purpose with or without fee is hereby granted, provided that the above
79e02bd04Skettenis * copyright notice and this permission notice appear in all copies.
89e02bd04Skettenis *
99e02bd04Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109e02bd04Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119e02bd04Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129e02bd04Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139e02bd04Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149e02bd04Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159e02bd04Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169e02bd04Skettenis */
179e02bd04Skettenis
189e02bd04Skettenis #include <sys/param.h>
199e02bd04Skettenis #include <sys/systm.h>
209e02bd04Skettenis #include <sys/device.h>
219e02bd04Skettenis
229e02bd04Skettenis #include <machine/intr.h>
239e02bd04Skettenis #include <machine/bus.h>
249e02bd04Skettenis #include <machine/fdt.h>
259e02bd04Skettenis
269e02bd04Skettenis #include <dev/ofw/openfirm.h>
279e02bd04Skettenis #include <dev/ofw/ofw_clock.h>
289e02bd04Skettenis #include <dev/ofw/ofw_misc.h>
299e02bd04Skettenis #include <dev/ofw/fdt.h>
309e02bd04Skettenis
31321fe8e0Skettenis /* Clock IDs */
32da1aed44Skettenis #define G12A_SYS_PLL 0
337c095818Skettenis #define G12A_FCLK_DIV2 2
34348b64d7Skettenis #define G12A_FCLK_DIV3 3
35348b64d7Skettenis #define G12A_FCLK_DIV4 4
36348b64d7Skettenis #define G12A_FCLK_DIV5 5
37348b64d7Skettenis #define G12A_FCLK_DIV7 6
38cfffe3f7Skettenis #define G12A_MPLL1 12
39cfffe3f7Skettenis #define G12A_MPLL2 13
40cfffe3f7Skettenis #define G12A_I2C 24
417c095818Skettenis #define G12A_SD_EMMC_A 33
427c095818Skettenis #define G12A_SD_EMMC_B 34
437c095818Skettenis #define G12A_SD_EMMC_C 35
4485b1c98aSkettenis #define G12A_PCIE_COMB 45
4585b1c98aSkettenis #define G12A_PCIE_PHY 48
467c095818Skettenis #define G12A_SD_EMMC_A_CLK0 60
477c095818Skettenis #define G12A_SD_EMMC_B_CLK0 61
487c095818Skettenis #define G12A_SD_EMMC_C_CLK0 62
499e02bd04Skettenis #define G12A_USB 47
50348b64d7Skettenis #define G12A_FCLK_DIV2P5 99
51da1aed44Skettenis #define G12A_CPU_CLK 187
529e02bd04Skettenis #define G12A_PCIE_PLL 201
53ada9f61eSkettenis #define G12A_TS 212
541fa553c5Skettenis #define G12B_SYS1_PLL 214
551fa553c5Skettenis #define G12B_CPUB_CLK 224
569e02bd04Skettenis
57321fe8e0Skettenis /* Registers */
589e02bd04Skettenis #define HHI_PCIE_PLL_CNTL0 0x26
599e02bd04Skettenis #define HHI_PCIE_PLL_CNTL1 0x27
609e02bd04Skettenis #define HHI_PCIE_PLL_CNTL2 0x28
619e02bd04Skettenis #define HHI_PCIE_PLL_CNTL3 0x29
629e02bd04Skettenis #define HHI_PCIE_PLL_CNTL4 0x2a
639e02bd04Skettenis #define HHI_PCIE_PLL_CNTL5 0x2b
647c095818Skettenis #define HHI_GCLK_MPEG0 0x50
659e02bd04Skettenis #define HHI_GCLK_MPEG1 0x51
66cfffe3f7Skettenis #define HHI_MPEG_CLK_CNTL 0x5d
67ada9f61eSkettenis #define HHI_TS_CLK_CNTL 0x64
68da1aed44Skettenis #define HHI_SYS_CPU_CLK_CNTL0 0x67
698245c0faSkettenis #define HHI_SYS_CPU_CLK_DYN_ENABLE (1 << 26)
708245c0faSkettenis #define HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT(x) (((x) >> 20) & 0x3f)
718245c0faSkettenis #define HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_MASK (0x3f << 20)
728245c0faSkettenis #define HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_SHIFT 20
738245c0faSkettenis #define HHI_SYS_CPU_CLK_POSTMUX1 (1 << 18)
748245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX1(x) (((x) >> 16) & 0x3)
758245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX1_MASK (0x3 << 16)
768245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV2 (0x1 << 16)
778245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV3 (0x2 << 16)
788245c0faSkettenis #define HHI_SYS_CPU_CLK_FINAL_MUX_SEL (1 << 11)
798245c0faSkettenis #define HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL (1 << 10)
808245c0faSkettenis #define HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT(x) (((x) >> 4) & 0x3f)
818245c0faSkettenis #define HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_MASK (0x3f << 4)
828245c0faSkettenis #define HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_SHIFT 4
838245c0faSkettenis #define HHI_SYS_CPU_CLK_POSTMUX0 (1 << 2)
848245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX0(x) (((x) >> 0) & 0x3)
858245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX0_MASK (0x3 << 0)
868245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV2 (0x1 << 0)
878245c0faSkettenis #define HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV3 (0x2 << 0)
88da1aed44Skettenis #define HHI_SYS_CPUB_CLK_CNTL 0x82
897c095818Skettenis #define HHI_NAND_CLK_CNTL 0x97
907c095818Skettenis #define HHI_SD_EMMC_CLK_CNTL 0x99
91da1aed44Skettenis #define HHI_SYS_PLL_CNTL0 0xbd
92*dcec61dcSmiod #define HHI_SYS_DPLL_LOCK (1U << 31)
938245c0faSkettenis #define HHI_SYS_DPLL_RESET (1 << 29)
948245c0faSkettenis #define HHI_SYS_DPLL_EN (1 << 28)
958245c0faSkettenis #define HHI_SYS_DPLL_OD(x) (((x) >> 16) & 0x7)
968245c0faSkettenis #define HHI_SYS_DPLL_OD_MASK (0x7 << 16)
978245c0faSkettenis #define HHI_SYS_DPLL_OD_SHIFT 16
988245c0faSkettenis #define HHI_SYS_DPLL_N(x) (((x) >> 10) & 0x1f)
998245c0faSkettenis #define HHI_SYS_DPLL_N_MASK (0x1f << 10)
1008245c0faSkettenis #define HHI_SYS_DPLL_N_SHIFT 10
1018245c0faSkettenis #define HHI_SYS_DPLL_M(x) (((x) >> 0) & 0xff)
1028245c0faSkettenis #define HHI_SYS_DPLL_M_MASK (0xff << 0)
1038245c0faSkettenis #define HHI_SYS_DPLL_M_SHIFT 0
104da1aed44Skettenis #define HHI_SYS1_PLL_CNTL0 0xe0
1059e02bd04Skettenis
1069e02bd04Skettenis #define HREAD4(sc, reg) \
1079e02bd04Skettenis (regmap_read_4((sc)->sc_rm, (reg) << 2))
1089e02bd04Skettenis #define HWRITE4(sc, reg, val) \
1099e02bd04Skettenis regmap_write_4((sc)->sc_rm, (reg) << 2, (val))
1109e02bd04Skettenis #define HSET4(sc, reg, bits) \
111490ed0b3Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
1129e02bd04Skettenis #define HCLR4(sc, reg, bits) \
113490ed0b3Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
1149e02bd04Skettenis
1157c095818Skettenis struct amlclock_gate {
1167c095818Skettenis uint8_t reg;
1177c095818Skettenis uint8_t bit;
1187c095818Skettenis };
1197c095818Skettenis
12037c734d3Snaddy const struct amlclock_gate aml_g12a_gates[] = {
121cfffe3f7Skettenis [G12A_I2C] = { HHI_GCLK_MPEG0, 9 },
1227c095818Skettenis [G12A_SD_EMMC_A] = { HHI_GCLK_MPEG0, 24 },
1237c095818Skettenis [G12A_SD_EMMC_B] = { HHI_GCLK_MPEG0, 25 },
1247c095818Skettenis [G12A_SD_EMMC_C] = { HHI_GCLK_MPEG0, 26 },
12585b1c98aSkettenis [G12A_PCIE_COMB] = { HHI_GCLK_MPEG1, 24 },
1267c095818Skettenis [G12A_USB] = { HHI_GCLK_MPEG1, 26 },
12785b1c98aSkettenis [G12A_PCIE_PHY] = { HHI_GCLK_MPEG1, 27 },
1287c095818Skettenis
1297c095818Skettenis [G12A_SD_EMMC_A_CLK0] = { HHI_SD_EMMC_CLK_CNTL, 7 },
1307c095818Skettenis [G12A_SD_EMMC_B_CLK0] = { HHI_SD_EMMC_CLK_CNTL, 23 },
1317c095818Skettenis [G12A_SD_EMMC_C_CLK0] = { HHI_NAND_CLK_CNTL, 7 },
132ada9f61eSkettenis
133ada9f61eSkettenis [G12A_TS] = { HHI_TS_CLK_CNTL, 8 },
1347c095818Skettenis };
1357c095818Skettenis
1369e02bd04Skettenis struct amlclock_softc {
1379e02bd04Skettenis struct device sc_dev;
1389e02bd04Skettenis struct regmap *sc_rm;
139348b64d7Skettenis int sc_node;
1401fa553c5Skettenis uint32_t sc_g12b;
1419e02bd04Skettenis
14237c734d3Snaddy const struct amlclock_gate *sc_gates;
1437c095818Skettenis int sc_ngates;
1447c095818Skettenis
1459e02bd04Skettenis struct clock_device sc_cd;
146da1aed44Skettenis uint32_t sc_xtal;
1479e02bd04Skettenis };
1489e02bd04Skettenis
1499e02bd04Skettenis int amlclock_match(struct device *, void *, void *);
1509e02bd04Skettenis void amlclock_attach(struct device *, struct device *, void *);
1519e02bd04Skettenis
1529fdf0c62Smpi const struct cfattach amlclock_ca = {
1539e02bd04Skettenis sizeof (struct amlclock_softc), amlclock_match, amlclock_attach
1549e02bd04Skettenis };
1559e02bd04Skettenis
1569e02bd04Skettenis struct cfdriver amlclock_cd = {
1579e02bd04Skettenis NULL, "amlclock", DV_DULL
1589e02bd04Skettenis };
1599e02bd04Skettenis
1609e02bd04Skettenis uint32_t amlclock_get_frequency(void *, uint32_t *);
1619e02bd04Skettenis int amlclock_set_frequency(void *, uint32_t *, uint32_t);
1629e02bd04Skettenis void amlclock_enable(void *, uint32_t *, int);
1639e02bd04Skettenis
1649e02bd04Skettenis int
amlclock_match(struct device * parent,void * match,void * aux)1659e02bd04Skettenis amlclock_match(struct device *parent, void *match, void *aux)
1669e02bd04Skettenis {
1679e02bd04Skettenis struct fdt_attach_args *faa = aux;
1689e02bd04Skettenis
1699e02bd04Skettenis return (OF_is_compatible(faa->fa_node, "amlogic,g12a-clkc") ||
1701fa553c5Skettenis OF_is_compatible(faa->fa_node, "amlogic,g12b-clkc") ||
1711fa553c5Skettenis OF_is_compatible(faa->fa_node, "amlogic,sm1-clkc"));
1729e02bd04Skettenis }
1739e02bd04Skettenis
1749e02bd04Skettenis void
amlclock_attach(struct device * parent,struct device * self,void * aux)1759e02bd04Skettenis amlclock_attach(struct device *parent, struct device *self, void *aux)
1769e02bd04Skettenis {
1779e02bd04Skettenis struct amlclock_softc *sc = (struct amlclock_softc *)self;
1789e02bd04Skettenis struct fdt_attach_args *faa = aux;
1799e02bd04Skettenis
1809e02bd04Skettenis sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
1819e02bd04Skettenis if (sc->sc_rm == NULL) {
1829e02bd04Skettenis printf(": no registers\n");
1839e02bd04Skettenis return;
1849e02bd04Skettenis }
1859e02bd04Skettenis
186348b64d7Skettenis sc->sc_node = faa->fa_node;
1879e02bd04Skettenis printf("\n");
1889e02bd04Skettenis
1891fa553c5Skettenis if (OF_is_compatible(faa->fa_node, "amlogic,g12b-clkc"))
1901fa553c5Skettenis sc->sc_g12b = 1;
1911fa553c5Skettenis
1927c095818Skettenis sc->sc_gates = aml_g12a_gates;
1937c095818Skettenis sc->sc_ngates = nitems(aml_g12a_gates);
1947c095818Skettenis
195da1aed44Skettenis sc->sc_xtal = clock_get_frequency(sc->sc_node, "xtal");
196da1aed44Skettenis
1979e02bd04Skettenis sc->sc_cd.cd_node = faa->fa_node;
1989e02bd04Skettenis sc->sc_cd.cd_cookie = sc;
1999e02bd04Skettenis sc->sc_cd.cd_get_frequency = amlclock_get_frequency;
2009e02bd04Skettenis sc->sc_cd.cd_set_frequency = amlclock_set_frequency;
2019e02bd04Skettenis sc->sc_cd.cd_enable = amlclock_enable;
2029e02bd04Skettenis clock_register(&sc->sc_cd);
2039e02bd04Skettenis }
2049e02bd04Skettenis
2059e02bd04Skettenis uint32_t
amlclock_get_cpu_freq(struct amlclock_softc * sc,bus_size_t offset)2068245c0faSkettenis amlclock_get_cpu_freq(struct amlclock_softc *sc, bus_size_t offset)
207da1aed44Skettenis {
208da1aed44Skettenis uint32_t reg, mux, div;
209da1aed44Skettenis uint32_t idx;
210da1aed44Skettenis
211da1aed44Skettenis reg = HREAD4(sc, offset);
2128245c0faSkettenis if (reg & HHI_SYS_CPU_CLK_FINAL_MUX_SEL) {
2131fa553c5Skettenis if (sc->sc_g12b && offset == HHI_SYS_CPU_CLK_CNTL0)
2141fa553c5Skettenis idx = G12B_SYS1_PLL;
215da1aed44Skettenis else
216da1aed44Skettenis idx = G12A_SYS_PLL;
217da1aed44Skettenis return amlclock_get_frequency(sc, &idx);
218da1aed44Skettenis }
2198245c0faSkettenis if (reg & HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL) {
2208245c0faSkettenis div = (reg & HHI_SYS_CPU_CLK_POSTMUX1) ?
2218245c0faSkettenis (HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT(reg) + 1) : 1;
2228245c0faSkettenis mux = HHI_SYS_CPU_CLK_PREMUX1(reg);
223da1aed44Skettenis } else {
2248245c0faSkettenis div = (reg & HHI_SYS_CPU_CLK_POSTMUX0) ?
2258245c0faSkettenis (HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT(reg) + 1) : 1;
2268245c0faSkettenis mux = HHI_SYS_CPU_CLK_PREMUX0(reg);
227da1aed44Skettenis }
228da1aed44Skettenis switch (mux) {
229da1aed44Skettenis case 0:
230da1aed44Skettenis return sc->sc_xtal / div;
231da1aed44Skettenis case 1:
232da1aed44Skettenis idx = G12A_FCLK_DIV2;
233da1aed44Skettenis break;
234da1aed44Skettenis case 2:
235da1aed44Skettenis idx = G12A_FCLK_DIV3;
236da1aed44Skettenis break;
237da1aed44Skettenis case 3:
238da1aed44Skettenis return 0;
239da1aed44Skettenis }
240da1aed44Skettenis return amlclock_get_frequency(sc, &idx) / div;
241da1aed44Skettenis }
242da1aed44Skettenis
2438245c0faSkettenis int
amlclock_set_cpu_freq(struct amlclock_softc * sc,bus_size_t offset,uint32_t freq)2448245c0faSkettenis amlclock_set_cpu_freq(struct amlclock_softc *sc, bus_size_t offset,
2458245c0faSkettenis uint32_t freq)
2468245c0faSkettenis {
2478245c0faSkettenis uint32_t reg, div;
2488245c0faSkettenis uint32_t parent_freq;
2498245c0faSkettenis uint32_t idx;
2508245c0faSkettenis
2518245c0faSkettenis /*
2528245c0faSkettenis * For clock frequencies above 1GHz we have to use
2538245c0faSkettenis * SYS_PLL/SYS1_PLL.
2548245c0faSkettenis */
2558245c0faSkettenis reg = HREAD4(sc, offset);
2568245c0faSkettenis if (freq > 1000000000) {
2578245c0faSkettenis /*
2588245c0faSkettenis * Switch to a fixed clock if we're currently using
2598245c0faSkettenis * SYS_PLL/SYS1_PLL. Doesn't really matter which one.
2608245c0faSkettenis */
2618245c0faSkettenis if (reg & HHI_SYS_CPU_CLK_FINAL_MUX_SEL) {
2628245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
2638245c0faSkettenis HWRITE4(sc, offset, reg);
2648245c0faSkettenis delay(100);
2658245c0faSkettenis }
2668245c0faSkettenis
2671fa553c5Skettenis if (sc->sc_g12b && offset == HHI_SYS_CPU_CLK_CNTL0)
2681fa553c5Skettenis idx = G12B_SYS1_PLL;
2698245c0faSkettenis else
2708245c0faSkettenis idx = G12A_SYS_PLL;
2718245c0faSkettenis amlclock_set_frequency(sc, &idx, freq);
2728245c0faSkettenis
2738245c0faSkettenis /* Switch to SYS_PLL/SYS1_PLL. */
2748245c0faSkettenis reg |= HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
2758245c0faSkettenis HWRITE4(sc, offset, reg);
2768245c0faSkettenis delay(100);
2778245c0faSkettenis
2788245c0faSkettenis return 0;
2798245c0faSkettenis }
2808245c0faSkettenis
2818245c0faSkettenis /*
2828245c0faSkettenis * There are two signal paths for frequencies up to 1GHz. If
2838245c0faSkettenis * we're using one, we can program the dividers for the other
2848245c0faSkettenis * one and switch to it. The pre-divider can be either 2 or 3
2858245c0faSkettenis * and can't be bypassed, so take this into account and only
2868245c0faSkettenis * allow frequencies that include such a divider.
2878245c0faSkettenis */
2888245c0faSkettenis div = 2;
2898245c0faSkettenis parent_freq = 2000000000;
2908245c0faSkettenis while (parent_freq / div > freq)
2918245c0faSkettenis div++;
2928245c0faSkettenis while ((div % 2) != 0 && (div % 3) != 0)
2938245c0faSkettenis div++;
2948245c0faSkettenis if (div > 32)
2958245c0faSkettenis return EINVAL;
2968245c0faSkettenis if ((div % 2) == 0) {
2978245c0faSkettenis parent_freq /= 2;
2988245c0faSkettenis div /= 2;
2998245c0faSkettenis } else {
3008245c0faSkettenis parent_freq /= 3;
3018245c0faSkettenis div /= 3;
3028245c0faSkettenis }
3038245c0faSkettenis
3048245c0faSkettenis if (reg & HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL) {
3058245c0faSkettenis /* premux0 */
3068245c0faSkettenis reg = HREAD4(sc, offset);
3078245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_PREMUX0_MASK;
3088245c0faSkettenis if (parent_freq == 1000000000)
3098245c0faSkettenis reg |= HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV2;
3108245c0faSkettenis else
3118245c0faSkettenis reg |= HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV3;
3128245c0faSkettenis HWRITE4(sc, offset, reg);
3138245c0faSkettenis delay(100);
3148245c0faSkettenis
3158245c0faSkettenis /* mux0 divider */
3168245c0faSkettenis HSET4(sc, offset, HHI_SYS_CPU_CLK_DYN_ENABLE);
3178245c0faSkettenis reg = HREAD4(sc, offset);
3188245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_DYN_ENABLE;
3198245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_MASK;
3208245c0faSkettenis reg |= ((div - 1) << HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_SHIFT);
3218245c0faSkettenis HWRITE4(sc, offset, reg);
3228245c0faSkettenis
3238245c0faSkettenis /* postmux0 */
3248245c0faSkettenis if (div != 1)
3258245c0faSkettenis HSET4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX0);
3268245c0faSkettenis else
3278245c0faSkettenis HCLR4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX0);
3288245c0faSkettenis
3298245c0faSkettenis /* final_dyn_mux_sel and final_mux_sel */
3308245c0faSkettenis reg = HREAD4(sc, offset);
3318245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL;
3328245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
3338245c0faSkettenis HWRITE4(sc, offset, reg);
3348245c0faSkettenis delay(100);
3358245c0faSkettenis } else {
3368245c0faSkettenis /* premux1 */
3378245c0faSkettenis reg = HREAD4(sc, offset);
3388245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_PREMUX1_MASK;
3398245c0faSkettenis if (parent_freq == 1000000000)
3408245c0faSkettenis reg |= HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV2;
3418245c0faSkettenis else
3428245c0faSkettenis reg |= HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV3;
3438245c0faSkettenis HWRITE4(sc, offset, reg);
3448245c0faSkettenis delay(100);
3458245c0faSkettenis
3468245c0faSkettenis /* mux1 divider */
3478245c0faSkettenis HSET4(sc, offset, HHI_SYS_CPU_CLK_DYN_ENABLE);
3488245c0faSkettenis reg = HREAD4(sc, offset);
3498245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_DYN_ENABLE;
3508245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_MASK;
3518245c0faSkettenis reg |= ((div - 1) << HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_SHIFT);
3528245c0faSkettenis HWRITE4(sc, offset, reg);
3538245c0faSkettenis
3548245c0faSkettenis /* postmux1 */
3558245c0faSkettenis if (div != 1)
3568245c0faSkettenis HSET4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX1);
3578245c0faSkettenis else
3588245c0faSkettenis HCLR4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX1);
3598245c0faSkettenis
3608245c0faSkettenis /* final_dyn_mux_sel and final_mux_sel */
3618245c0faSkettenis reg = HREAD4(sc, offset);
3628245c0faSkettenis reg |= HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL;
3638245c0faSkettenis reg &= ~HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
3648245c0faSkettenis HWRITE4(sc, offset, reg);
3658245c0faSkettenis delay(100);
3668245c0faSkettenis }
3678245c0faSkettenis
3688245c0faSkettenis return 0;
3698245c0faSkettenis }
3708245c0faSkettenis
3718245c0faSkettenis int
amlclock_set_pll_freq(struct amlclock_softc * sc,bus_size_t offset,uint32_t freq)3728245c0faSkettenis amlclock_set_pll_freq(struct amlclock_softc *sc, bus_size_t offset,
3738245c0faSkettenis uint32_t freq)
3748245c0faSkettenis {
3758245c0faSkettenis uint32_t reg, div;
3768245c0faSkettenis uint32_t m, n = 1;
3778245c0faSkettenis int timo;
3788245c0faSkettenis
3798245c0faSkettenis /*
3808245c0faSkettenis * The multiplier should be between 128 and 255. If
3818245c0faSkettenis * necessary, adjust the divider to achieve this.
3828245c0faSkettenis */
3838245c0faSkettenis div = 1;
3848245c0faSkettenis while ((div * (uint64_t)freq) / sc->sc_xtal < 128)
3858245c0faSkettenis div *= 2;
3868245c0faSkettenis if (div > 128)
3878245c0faSkettenis return EINVAL;
3888245c0faSkettenis m = (div * (uint64_t)freq) / sc->sc_xtal;
3898245c0faSkettenis if (m > 255)
3908245c0faSkettenis return EINVAL;
3918245c0faSkettenis
3928245c0faSkettenis HSET4(sc, offset, HHI_SYS_DPLL_RESET);
3938245c0faSkettenis HCLR4(sc, offset, HHI_SYS_DPLL_EN);
3948245c0faSkettenis
3958245c0faSkettenis reg = HREAD4(sc, offset);
3968245c0faSkettenis reg &= ~HHI_SYS_DPLL_OD_MASK;
3978245c0faSkettenis reg |= ((fls(div) - 1) << HHI_SYS_DPLL_OD_SHIFT);
3988245c0faSkettenis reg &= ~(HHI_SYS_DPLL_M_MASK | HHI_SYS_DPLL_N_MASK);
3998245c0faSkettenis reg |= (m << HHI_SYS_DPLL_M_SHIFT);
4008245c0faSkettenis reg |= (n << HHI_SYS_DPLL_N_SHIFT);
4018245c0faSkettenis HWRITE4(sc, offset, reg);
4028245c0faSkettenis
4038245c0faSkettenis HSET4(sc, offset, HHI_SYS_DPLL_RESET);
4048245c0faSkettenis HSET4(sc, offset, HHI_SYS_DPLL_EN);
4058245c0faSkettenis HCLR4(sc, offset, HHI_SYS_DPLL_RESET);
4068245c0faSkettenis
4078245c0faSkettenis for (timo = 24000000; timo > 0; timo--) {
4088245c0faSkettenis if (HREAD4(sc, offset) & HHI_SYS_DPLL_LOCK)
4098245c0faSkettenis return 0;
4108245c0faSkettenis }
4118245c0faSkettenis
4128245c0faSkettenis return ETIMEDOUT;
4138245c0faSkettenis }
4148245c0faSkettenis
415da1aed44Skettenis uint32_t
amlclock_get_frequency(void * cookie,uint32_t * cells)4169e02bd04Skettenis amlclock_get_frequency(void *cookie, uint32_t *cells)
4179e02bd04Skettenis {
418348b64d7Skettenis struct amlclock_softc *sc = cookie;
4199e02bd04Skettenis uint32_t idx = cells[0];
420348b64d7Skettenis uint32_t reg, mux, div;
421da1aed44Skettenis uint32_t m, n;
4229e02bd04Skettenis
423348b64d7Skettenis switch (idx) {
424da1aed44Skettenis case G12A_SYS_PLL:
425da1aed44Skettenis reg = HREAD4(sc, HHI_SYS_PLL_CNTL0);
4268245c0faSkettenis div = 1 << HHI_SYS_DPLL_OD(reg);
4278245c0faSkettenis m = HHI_SYS_DPLL_M(reg);
4288245c0faSkettenis n = HHI_SYS_DPLL_N(reg);
429da1aed44Skettenis return (((uint64_t)sc->sc_xtal * m) / n) / div;
4301fa553c5Skettenis case G12B_SYS1_PLL:
431da1aed44Skettenis reg = HREAD4(sc, HHI_SYS1_PLL_CNTL0);
4328245c0faSkettenis div = 1 << HHI_SYS_DPLL_OD(reg);
4338245c0faSkettenis m = HHI_SYS_DPLL_M(reg);
4348245c0faSkettenis n = HHI_SYS_DPLL_N(reg);
435da1aed44Skettenis return (((uint64_t)sc->sc_xtal * m) / n) / div;
436348b64d7Skettenis case G12A_FCLK_DIV2:
437348b64d7Skettenis return 1000000000;
438348b64d7Skettenis case G12A_FCLK_DIV3:
439348b64d7Skettenis return 666666666;
440348b64d7Skettenis case G12A_FCLK_DIV4:
441348b64d7Skettenis return 500000000;
442348b64d7Skettenis case G12A_FCLK_DIV5:
443348b64d7Skettenis return 400000000;
444348b64d7Skettenis case G12A_FCLK_DIV7:
445348b64d7Skettenis return 285714285;
446348b64d7Skettenis case G12A_FCLK_DIV2P5:
447348b64d7Skettenis return 800000000;
448348b64d7Skettenis
449cfffe3f7Skettenis case G12A_I2C:
450cfffe3f7Skettenis reg = HREAD4(sc, HHI_MPEG_CLK_CNTL);
451cfffe3f7Skettenis mux = (reg >> 12) & 0x7;
452cfffe3f7Skettenis div = ((reg >> 0) & 0x7f) + 1;
453cfffe3f7Skettenis switch (mux) {
454cfffe3f7Skettenis case 0:
455cfffe3f7Skettenis return sc->sc_xtal / div;
456cfffe3f7Skettenis case 2:
457cfffe3f7Skettenis idx = G12A_FCLK_DIV7;
458cfffe3f7Skettenis break;
459cfffe3f7Skettenis case 3:
460cfffe3f7Skettenis idx = G12A_MPLL1;
461cfffe3f7Skettenis break;
462cfffe3f7Skettenis case 4:
463cfffe3f7Skettenis idx = G12A_MPLL2;
464cfffe3f7Skettenis break;
465cfffe3f7Skettenis case 5:
466cfffe3f7Skettenis idx = G12A_FCLK_DIV4;
467cfffe3f7Skettenis break;
468cfffe3f7Skettenis case 6:
469cfffe3f7Skettenis idx = G12A_FCLK_DIV3;
470cfffe3f7Skettenis break;
471cfffe3f7Skettenis case 7:
472cfffe3f7Skettenis idx = G12A_FCLK_DIV5;
473cfffe3f7Skettenis break;
474cfffe3f7Skettenis default:
475cfffe3f7Skettenis goto fail;
476cfffe3f7Skettenis }
477cfffe3f7Skettenis return amlclock_get_frequency(sc, &idx) / div;
478348b64d7Skettenis case G12A_SD_EMMC_A_CLK0:
479348b64d7Skettenis reg = HREAD4(sc, HHI_SD_EMMC_CLK_CNTL);
480348b64d7Skettenis mux = (reg >> 9) & 0x7;
481348b64d7Skettenis div = ((reg >> 0) & 0x7f) + 1;
482348b64d7Skettenis switch (mux) {
483348b64d7Skettenis case 0:
484da1aed44Skettenis return sc->sc_xtal / div;
485348b64d7Skettenis case 1:
486348b64d7Skettenis idx = G12A_FCLK_DIV2;
487348b64d7Skettenis break;
488348b64d7Skettenis case 2:
489348b64d7Skettenis idx = G12A_FCLK_DIV3;
490348b64d7Skettenis break;
491348b64d7Skettenis case 3:
492348b64d7Skettenis idx = G12A_FCLK_DIV5;
493348b64d7Skettenis break;
494348b64d7Skettenis case 4:
495348b64d7Skettenis idx = G12A_FCLK_DIV7;
496348b64d7Skettenis break;
497348b64d7Skettenis default:
498348b64d7Skettenis goto fail;
499348b64d7Skettenis }
500348b64d7Skettenis return amlclock_get_frequency(sc, &idx) / div;
501348b64d7Skettenis case G12A_SD_EMMC_B_CLK0:
502348b64d7Skettenis reg = HREAD4(sc, HHI_SD_EMMC_CLK_CNTL);
503348b64d7Skettenis mux = (reg >> 25) & 0x7;
504348b64d7Skettenis div = ((reg >> 16) & 0x7f) + 1;
505348b64d7Skettenis switch (mux) {
506348b64d7Skettenis case 0:
507da1aed44Skettenis return sc->sc_xtal / div;
508348b64d7Skettenis case 1:
509348b64d7Skettenis idx = G12A_FCLK_DIV2;
510348b64d7Skettenis break;
511348b64d7Skettenis case 2:
512348b64d7Skettenis idx = G12A_FCLK_DIV3;
513348b64d7Skettenis break;
514348b64d7Skettenis case 3:
515348b64d7Skettenis idx = G12A_FCLK_DIV5;
516348b64d7Skettenis break;
517348b64d7Skettenis case 4:
518348b64d7Skettenis idx = G12A_FCLK_DIV7;
519348b64d7Skettenis break;
520348b64d7Skettenis default:
521348b64d7Skettenis goto fail;
522348b64d7Skettenis }
523348b64d7Skettenis return amlclock_get_frequency(sc, &idx) / div;
524348b64d7Skettenis case G12A_SD_EMMC_C_CLK0:
525348b64d7Skettenis reg = HREAD4(sc, HHI_NAND_CLK_CNTL);
526348b64d7Skettenis mux = (reg >> 9) & 0x7;
527348b64d7Skettenis div = ((reg >> 0) & 0x7f) + 1;
528348b64d7Skettenis switch (mux) {
529348b64d7Skettenis case 0:
530da1aed44Skettenis return sc->sc_xtal / div;
531348b64d7Skettenis case 1:
532348b64d7Skettenis idx = G12A_FCLK_DIV2;
533348b64d7Skettenis break;
534348b64d7Skettenis case 2:
535348b64d7Skettenis idx = G12A_FCLK_DIV3;
536348b64d7Skettenis break;
537348b64d7Skettenis case 3:
538348b64d7Skettenis idx = G12A_FCLK_DIV5;
539348b64d7Skettenis break;
540348b64d7Skettenis case 4:
541348b64d7Skettenis idx = G12A_FCLK_DIV7;
542348b64d7Skettenis break;
543348b64d7Skettenis default:
544348b64d7Skettenis goto fail;
545348b64d7Skettenis }
546348b64d7Skettenis return amlclock_get_frequency(sc, &idx) / div;
547da1aed44Skettenis case G12A_CPU_CLK:
5488245c0faSkettenis return amlclock_get_cpu_freq(sc, HHI_SYS_CPU_CLK_CNTL0);
5491fa553c5Skettenis case G12B_CPUB_CLK:
5508245c0faSkettenis return amlclock_get_cpu_freq(sc, HHI_SYS_CPUB_CLK_CNTL);
551348b64d7Skettenis }
552348b64d7Skettenis
553348b64d7Skettenis fail:
5549e02bd04Skettenis printf("%s: 0x%08x\n", __func__, idx);
5559e02bd04Skettenis return 0;
5569e02bd04Skettenis }
5579e02bd04Skettenis
5589e02bd04Skettenis int
amlclock_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)5599e02bd04Skettenis amlclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
5609e02bd04Skettenis {
5619e02bd04Skettenis struct amlclock_softc *sc = cookie;
5629e02bd04Skettenis uint32_t idx = cells[0];
5639e02bd04Skettenis
5649e02bd04Skettenis switch (idx) {
5658245c0faSkettenis case G12A_SYS_PLL:
5668245c0faSkettenis return amlclock_set_pll_freq(sc, HHI_SYS_PLL_CNTL0, freq);
5671fa553c5Skettenis case G12B_SYS1_PLL:
5688245c0faSkettenis return amlclock_set_pll_freq(sc, HHI_SYS1_PLL_CNTL0, freq);
5699e02bd04Skettenis case G12A_PCIE_PLL:
5709e02bd04Skettenis /* Fixed at 100 MHz. */
5719e02bd04Skettenis if (freq != 100000000)
5729e02bd04Skettenis return -1;
5739e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x20090496);
5749e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x30090496);
5759e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL1, 0x00000000);
5769e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL2, 0x00001100);
5779e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL3, 0x10058e00);
5789e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL4, 0x000100c0);
5799e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL5, 0x68000048);
5809e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL5, 0x68000068);
5819e02bd04Skettenis delay(20);
5829e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL4, 0x008100c0);
5839e02bd04Skettenis delay(10);
5849e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x34090496);
5859e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x14090496);
5869e02bd04Skettenis delay(10);
5879e02bd04Skettenis HWRITE4(sc, HHI_PCIE_PLL_CNTL2, 0x00001000);
5889e02bd04Skettenis return 0;
5898245c0faSkettenis case G12A_CPU_CLK:
5908245c0faSkettenis return amlclock_set_cpu_freq(sc, HHI_SYS_CPU_CLK_CNTL0, freq);
5911fa553c5Skettenis case G12B_CPUB_CLK:
5928245c0faSkettenis return amlclock_set_cpu_freq(sc, HHI_SYS_CPUB_CLK_CNTL, freq);
5938245c0faSkettenis }
5949e02bd04Skettenis
5959e02bd04Skettenis printf("%s: 0x%08x\n", __func__, idx);
5969e02bd04Skettenis return -1;
5979e02bd04Skettenis }
5989e02bd04Skettenis
5999e02bd04Skettenis void
amlclock_enable(void * cookie,uint32_t * cells,int on)6009e02bd04Skettenis amlclock_enable(void *cookie, uint32_t *cells, int on)
6019e02bd04Skettenis {
6029e02bd04Skettenis struct amlclock_softc *sc = cookie;
6039e02bd04Skettenis uint32_t idx = cells[0];
6049e02bd04Skettenis
6057c095818Skettenis if (idx < sc->sc_ngates && sc->sc_gates[idx].reg != 0) {
6069e02bd04Skettenis if (on)
6077c095818Skettenis HSET4(sc, sc->sc_gates[idx].reg,
6087c095818Skettenis (1U << sc->sc_gates[idx].bit));
6099e02bd04Skettenis else
6107c095818Skettenis HCLR4(sc, sc->sc_gates[idx].reg,
6117c095818Skettenis (1U << sc->sc_gates[idx].bit));
6129e02bd04Skettenis return;
6137c095818Skettenis }
6147c095818Skettenis
6157c095818Skettenis switch (idx) {
6167c095818Skettenis case G12A_FCLK_DIV2:
6179e02bd04Skettenis case G12A_PCIE_PLL:
6189e02bd04Skettenis /* Already enabled. */
6199e02bd04Skettenis return;
6209e02bd04Skettenis }
6219e02bd04Skettenis
6229e02bd04Skettenis printf("%s: 0x%08x\n", __func__, idx);
6239e02bd04Skettenis }
624