1*a0fe19daSjmcneill /* $NetBSD: zynq7000_clkc.c,v 1.5 2022/11/11 20:29:47 jmcneill Exp $ */
204c770d6Sjmcneill
304c770d6Sjmcneill /*-
404c770d6Sjmcneill * Copyright (c) 2022 Jared McNeill <jmcneill@invisible.ca>
504c770d6Sjmcneill * All rights reserved.
604c770d6Sjmcneill *
704c770d6Sjmcneill * Redistribution and use in source and binary forms, with or without
804c770d6Sjmcneill * modification, are permitted provided that the following conditions
904c770d6Sjmcneill * are met:
1004c770d6Sjmcneill * 1. Redistributions of source code must retain the above copyright
1104c770d6Sjmcneill * notice, this list of conditions and the following disclaimer.
1204c770d6Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
1304c770d6Sjmcneill * notice, this list of conditions and the following disclaimer in the
1404c770d6Sjmcneill * documentation and/or other materials provided with the distribution.
1504c770d6Sjmcneill *
1604c770d6Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1704c770d6Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1804c770d6Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1904c770d6Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2004c770d6Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2104c770d6Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2204c770d6Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2304c770d6Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2404c770d6Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2504c770d6Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2604c770d6Sjmcneill * POSSIBILITY OF SUCH DAMAGE.
2704c770d6Sjmcneill */
2804c770d6Sjmcneill
2904c770d6Sjmcneill #include <sys/cdefs.h>
3004c770d6Sjmcneill
31*a0fe19daSjmcneill __KERNEL_RCSID(0, "$NetBSD: zynq7000_clkc.c,v 1.5 2022/11/11 20:29:47 jmcneill Exp $");
3204c770d6Sjmcneill
3304c770d6Sjmcneill #include <sys/param.h>
3404c770d6Sjmcneill #include <sys/bus.h>
3504c770d6Sjmcneill #include <sys/device.h>
3604c770d6Sjmcneill #include <sys/intr.h>
3704c770d6Sjmcneill #include <sys/systm.h>
3804c770d6Sjmcneill #include <sys/time.h>
3904c770d6Sjmcneill #include <sys/kmem.h>
4004c770d6Sjmcneill
4104c770d6Sjmcneill #include <dev/clk/clk_backend.h>
4204c770d6Sjmcneill
4304c770d6Sjmcneill #include <dev/fdt/fdtvar.h>
44a60aa55cSjmcneill #include <dev/fdt/syscon.h>
4504c770d6Sjmcneill
46a60aa55cSjmcneill #define ARM_PLL_CTRL 0x100
47a60aa55cSjmcneill #define DDR_PLL_CTRL 0x104
48a60aa55cSjmcneill #define IO_PLL_CTRL 0x108
4904c770d6Sjmcneill #define PLL_FDIV __BITS(18,12)
50a60aa55cSjmcneill #define ARM_CLK_CTRL 0x120
5104c770d6Sjmcneill #define ARM_CLK_CTRL_CPU_1XCLKACT __BIT(27)
5204c770d6Sjmcneill #define ARM_CLK_CTRL_CPU_2XCLKACT __BIT(26)
5304c770d6Sjmcneill #define ARM_CLK_CTRL_CPU_3OR2XCLKACT __BIT(25)
5404c770d6Sjmcneill #define ARM_CLK_CTRL_CPU_6OR4XCLKACT __BIT(24)
55a60aa55cSjmcneill #define ARM_CLK_CTRL_DIVISOR __BITS(13,8)
56a60aa55cSjmcneill #define APER_CLK_CTRL 0x12c
5704c770d6Sjmcneill #define UART1_CPU_1XCLKACT __BIT(21)
5804c770d6Sjmcneill #define UART0_CPU_1XCLKACT __BIT(20)
5988c82104Sjmcneill #define I2C1_CPU_1XCLKACT __BIT(19)
6088c82104Sjmcneill #define I2C0_CPU_1XCLKACT __BIT(18)
61350c3bceSjmcneill #define SDI1_CPU_1XCLKACT __BIT(11)
62350c3bceSjmcneill #define SDI0_CPU_1XCLKACT __BIT(10)
63a60aa55cSjmcneill #define SDIO_CLK_CTRL 0x150
64a60aa55cSjmcneill #define UART_CLK_CTRL 0x154
65*a0fe19daSjmcneill #define PCAP_CLK_CTRL 0x168
66350c3bceSjmcneill #define CLK_CTRL_DIVISOR __BITS(13,8)
67350c3bceSjmcneill #define CLK_CTRL_SRCSEL __BITS(5,4)
68350c3bceSjmcneill #define CLK_CTRL_CLKACT1 __BIT(1)
69350c3bceSjmcneill #define CLK_CTRL_CLKACT0 __BIT(0)
70a60aa55cSjmcneill #define CLK_621_TRUE 0x1C4
7104c770d6Sjmcneill #define CLK_621_TRUE_EN __BIT(0)
7204c770d6Sjmcneill
7304c770d6Sjmcneill enum xynq7000_clkid {
7404c770d6Sjmcneill clkid_armpll,
7504c770d6Sjmcneill clkid_ddrpll,
7604c770d6Sjmcneill clkid_iopll,
7704c770d6Sjmcneill clkid_cpu_6or4x,
7804c770d6Sjmcneill clkid_cpu_3or2x,
7904c770d6Sjmcneill clkid_cpu_2x,
8004c770d6Sjmcneill clkid_cpu_1x,
8104c770d6Sjmcneill clkid_ddr2x,
8204c770d6Sjmcneill clkid_ddr3x,
8304c770d6Sjmcneill clkid_dci,
8404c770d6Sjmcneill clkid_lqspi,
8504c770d6Sjmcneill clkid_smc,
8604c770d6Sjmcneill clkid_pcap,
8704c770d6Sjmcneill clkid_gem0,
8804c770d6Sjmcneill clkid_gem1,
8904c770d6Sjmcneill clkid_fclk0,
9004c770d6Sjmcneill clkid_fclk1,
9104c770d6Sjmcneill clkid_fclk2,
9204c770d6Sjmcneill clkid_fclk3,
9304c770d6Sjmcneill clkid_can0,
9404c770d6Sjmcneill clkid_can1,
9504c770d6Sjmcneill clkid_sdio0,
9604c770d6Sjmcneill clkid_sdio1,
9704c770d6Sjmcneill clkid_uart0,
9804c770d6Sjmcneill clkid_uart1,
9904c770d6Sjmcneill clkid_spi0,
10004c770d6Sjmcneill clkid_spi1,
10104c770d6Sjmcneill clkid_dma,
10204c770d6Sjmcneill clkid_usb0_aper,
10304c770d6Sjmcneill clkid_usb1_aper,
10404c770d6Sjmcneill clkid_gem0_aper,
10504c770d6Sjmcneill clkid_gem1_aper,
10604c770d6Sjmcneill clkid_sdio0_aper,
10704c770d6Sjmcneill clkid_sdio1_aper,
10804c770d6Sjmcneill clkid_spi0_aper,
10904c770d6Sjmcneill clkid_spi1_aper,
11004c770d6Sjmcneill clkid_can0_aper,
11104c770d6Sjmcneill clkid_can1_aper,
11204c770d6Sjmcneill clkid_i2c0_aper,
11304c770d6Sjmcneill clkid_i2c1_aper,
11404c770d6Sjmcneill clkid_uart0_aper,
11504c770d6Sjmcneill clkid_uart1_aper,
11604c770d6Sjmcneill clkid_gpio_aper,
11704c770d6Sjmcneill clkid_lqspi_aper,
11804c770d6Sjmcneill clkid_smc_aper,
11904c770d6Sjmcneill clkid_swdt,
12004c770d6Sjmcneill clkid_dbg_trc,
12104c770d6Sjmcneill clkid_dbg_apb,
12204c770d6Sjmcneill num_clkid
12304c770d6Sjmcneill };
12404c770d6Sjmcneill CTASSERT(clkid_dbg_apb == 47);
12504c770d6Sjmcneill
12604c770d6Sjmcneill static int zynq7000_clkc_match(device_t, cfdata_t, void *);
12704c770d6Sjmcneill static void zynq7000_clkc_attach(device_t, device_t, void *);
12804c770d6Sjmcneill
129350c3bceSjmcneill static u_int zynq7000_clkc_clk_get_rate(void *, struct clk *);
130350c3bceSjmcneill
13104c770d6Sjmcneill static const struct device_compatible_entry compat_data[] = {
13204c770d6Sjmcneill { .compat = "xlnx,ps7-clkc" },
13304c770d6Sjmcneill DEVICE_COMPAT_EOL
13404c770d6Sjmcneill };
13504c770d6Sjmcneill
13604c770d6Sjmcneill struct zynq7000_clkc_softc {
13704c770d6Sjmcneill device_t sc_dev;
13804c770d6Sjmcneill struct clk_domain sc_clkdom;
13904c770d6Sjmcneill struct clk sc_clk[num_clkid];
14004c770d6Sjmcneill
14104c770d6Sjmcneill u_int sc_ps_clk_frequency;
142a60aa55cSjmcneill struct syscon *sc_syscon;
14304c770d6Sjmcneill };
14404c770d6Sjmcneill
14504c770d6Sjmcneill CFATTACH_DECL_NEW(zynq7000_clkc, sizeof(struct zynq7000_clkc_softc),
14604c770d6Sjmcneill zynq7000_clkc_match, zynq7000_clkc_attach, NULL, NULL);
14704c770d6Sjmcneill
14804c770d6Sjmcneill static struct clk *
zynq7000_clkc_clk_get(void * priv,const char * name)14904c770d6Sjmcneill zynq7000_clkc_clk_get(void *priv, const char *name)
15004c770d6Sjmcneill {
15104c770d6Sjmcneill struct zynq7000_clkc_softc * const sc = priv;
15204c770d6Sjmcneill u_int clkid;
15304c770d6Sjmcneill
15404c770d6Sjmcneill for (clkid = 0; clkid < num_clkid; clkid++) {
15504c770d6Sjmcneill if (strcmp(name, sc->sc_clk[clkid].name) == 0) {
15604c770d6Sjmcneill return &sc->sc_clk[clkid];
15704c770d6Sjmcneill }
15804c770d6Sjmcneill }
15904c770d6Sjmcneill
16004c770d6Sjmcneill return NULL;
16104c770d6Sjmcneill }
16204c770d6Sjmcneill
16304c770d6Sjmcneill static void
zynq7000_clkc_clk_put(void * priv,struct clk * clk)16404c770d6Sjmcneill zynq7000_clkc_clk_put(void *priv, struct clk *clk)
16504c770d6Sjmcneill {
16604c770d6Sjmcneill }
16704c770d6Sjmcneill
16804c770d6Sjmcneill static u_int
zynq7000_clkc_get_rate_pll(struct zynq7000_clkc_softc * sc,bus_addr_t reg)16904c770d6Sjmcneill zynq7000_clkc_get_rate_pll(struct zynq7000_clkc_softc *sc,
17004c770d6Sjmcneill bus_addr_t reg)
17104c770d6Sjmcneill {
17204c770d6Sjmcneill uint32_t val;
17304c770d6Sjmcneill
174a60aa55cSjmcneill syscon_lock(sc->sc_syscon);
175a60aa55cSjmcneill val = syscon_read_4(sc->sc_syscon, reg);
176a60aa55cSjmcneill syscon_unlock(sc->sc_syscon);
17704c770d6Sjmcneill
17804c770d6Sjmcneill return sc->sc_ps_clk_frequency * __SHIFTOUT(val, PLL_FDIV);
17904c770d6Sjmcneill }
18004c770d6Sjmcneill
18104c770d6Sjmcneill static u_int
zynq7000_clkc_get_rate_iop(struct zynq7000_clkc_softc * sc,bus_addr_t reg)182350c3bceSjmcneill zynq7000_clkc_get_rate_iop(struct zynq7000_clkc_softc *sc,
183350c3bceSjmcneill bus_addr_t reg)
184350c3bceSjmcneill {
185350c3bceSjmcneill uint32_t val;
186350c3bceSjmcneill u_int prate, sel;
187350c3bceSjmcneill
188a60aa55cSjmcneill syscon_lock(sc->sc_syscon);
189a60aa55cSjmcneill val = syscon_read_4(sc->sc_syscon, reg);
190a60aa55cSjmcneill syscon_unlock(sc->sc_syscon);
191a60aa55cSjmcneill
192350c3bceSjmcneill sel = __SHIFTOUT(val, CLK_CTRL_SRCSEL);
193350c3bceSjmcneill if (sel == 2) {
194350c3bceSjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
195350c3bceSjmcneill &sc->sc_clk[clkid_armpll]);
196350c3bceSjmcneill } else if (sel == 3) {
197350c3bceSjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
198350c3bceSjmcneill &sc->sc_clk[clkid_ddrpll]);
199350c3bceSjmcneill } else {
200350c3bceSjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
201350c3bceSjmcneill &sc->sc_clk[clkid_iopll]);
202350c3bceSjmcneill }
203350c3bceSjmcneill
204350c3bceSjmcneill return prate / __SHIFTOUT(val, CLK_CTRL_DIVISOR);
205350c3bceSjmcneill }
206350c3bceSjmcneill
207350c3bceSjmcneill static u_int
zynq7000_clkc_clk_get_rate(void * priv,struct clk * clk)20804c770d6Sjmcneill zynq7000_clkc_clk_get_rate(void *priv, struct clk *clk)
20904c770d6Sjmcneill {
21004c770d6Sjmcneill struct zynq7000_clkc_softc * const sc = priv;
21104c770d6Sjmcneill uint32_t val;
212350c3bceSjmcneill u_int prate;
21304c770d6Sjmcneill
21404c770d6Sjmcneill if (clk == &sc->sc_clk[clkid_armpll]) {
21504c770d6Sjmcneill return zynq7000_clkc_get_rate_pll(sc, ARM_PLL_CTRL);
21604c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_iopll]) {
21704c770d6Sjmcneill return zynq7000_clkc_get_rate_pll(sc, IO_PLL_CTRL);
21804c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_6or4x]) {
21904c770d6Sjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
22004c770d6Sjmcneill &sc->sc_clk[clkid_cpu_1x]);
221a60aa55cSjmcneill syscon_lock(sc->sc_syscon);
222a60aa55cSjmcneill val = syscon_read_4(sc->sc_syscon, CLK_621_TRUE);
223a60aa55cSjmcneill syscon_unlock(sc->sc_syscon);
22404c770d6Sjmcneill return (val & CLK_621_TRUE_EN) != 0 ?
22504c770d6Sjmcneill prate * 6 : prate * 4;
22604c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_3or2x]) {
22704c770d6Sjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
22804c770d6Sjmcneill &sc->sc_clk[clkid_cpu_1x]);
229a60aa55cSjmcneill syscon_lock(sc->sc_syscon);
230a60aa55cSjmcneill val = syscon_read_4(sc->sc_syscon, CLK_621_TRUE);
231a60aa55cSjmcneill syscon_unlock(sc->sc_syscon);
23204c770d6Sjmcneill return (val & CLK_621_TRUE_EN) != 0 ?
23304c770d6Sjmcneill prate * 3 : prate * 2;
23404c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_2x]) {
23504c770d6Sjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
23604c770d6Sjmcneill &sc->sc_clk[clkid_cpu_1x]);
23704c770d6Sjmcneill return prate * 2;
23804c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_1x]) {
23904c770d6Sjmcneill prate = zynq7000_clkc_clk_get_rate(sc,
24004c770d6Sjmcneill &sc->sc_clk[clkid_armpll]);
241a60aa55cSjmcneill syscon_lock(sc->sc_syscon);
242a60aa55cSjmcneill val = syscon_read_4(sc->sc_syscon, ARM_CLK_CTRL);
243a60aa55cSjmcneill syscon_unlock(sc->sc_syscon);
244a60aa55cSjmcneill return prate / __SHIFTOUT(val, ARM_CLK_CTRL_DIVISOR) / 6;
245350c3bceSjmcneill } else if (clk == &sc->sc_clk[clkid_sdio0] ||
246350c3bceSjmcneill clk == &sc->sc_clk[clkid_sdio1]) {
247350c3bceSjmcneill return zynq7000_clkc_get_rate_iop(sc, SDIO_CLK_CTRL);
24804c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_uart0] ||
24904c770d6Sjmcneill clk == &sc->sc_clk[clkid_uart1]) {
250350c3bceSjmcneill return zynq7000_clkc_get_rate_iop(sc, UART_CLK_CTRL);
251*a0fe19daSjmcneill } else if (clk == &sc->sc_clk[clkid_pcap]) {
252*a0fe19daSjmcneill return zynq7000_clkc_get_rate_iop(sc, PCAP_CLK_CTRL);
25304c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_uart0_aper] ||
25488c82104Sjmcneill clk == &sc->sc_clk[clkid_uart1_aper] ||
25588c82104Sjmcneill clk == &sc->sc_clk[clkid_i2c0_aper] ||
25688c82104Sjmcneill clk == &sc->sc_clk[clkid_i2c1_aper]) {
25704c770d6Sjmcneill return zynq7000_clkc_clk_get_rate(sc,
25804c770d6Sjmcneill &sc->sc_clk[clkid_cpu_1x]);
25904c770d6Sjmcneill } else {
26004c770d6Sjmcneill /* Not implemented. */
26104c770d6Sjmcneill return 0;
26204c770d6Sjmcneill }
26304c770d6Sjmcneill }
26404c770d6Sjmcneill
26504c770d6Sjmcneill static int
zynq7000_clkc_clk_enable(void * priv,struct clk * clk)26604c770d6Sjmcneill zynq7000_clkc_clk_enable(void *priv, struct clk *clk)
26704c770d6Sjmcneill {
26804c770d6Sjmcneill struct zynq7000_clkc_softc * const sc = priv;
26904c770d6Sjmcneill uint32_t val, mask;
27004c770d6Sjmcneill bus_addr_t reg;
27104c770d6Sjmcneill
27204c770d6Sjmcneill if (clk == &sc->sc_clk[clkid_cpu_1x]) {
27304c770d6Sjmcneill reg = ARM_CLK_CTRL;
27404c770d6Sjmcneill mask = ARM_CLK_CTRL_CPU_1XCLKACT;
27504c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_2x]) {
27604c770d6Sjmcneill reg = ARM_CLK_CTRL;
27704c770d6Sjmcneill mask = ARM_CLK_CTRL_CPU_2XCLKACT;
27804c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_3or2x]) {
27904c770d6Sjmcneill reg = ARM_CLK_CTRL;
28004c770d6Sjmcneill mask = ARM_CLK_CTRL_CPU_3OR2XCLKACT;
28104c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_cpu_6or4x]) {
28204c770d6Sjmcneill reg = ARM_CLK_CTRL;
28304c770d6Sjmcneill mask = ARM_CLK_CTRL_CPU_6OR4XCLKACT;
284350c3bceSjmcneill } else if (clk == &sc->sc_clk[clkid_sdio0]) {
285350c3bceSjmcneill reg = SDIO_CLK_CTRL;
286350c3bceSjmcneill mask = CLK_CTRL_CLKACT0;
287350c3bceSjmcneill } else if (clk == &sc->sc_clk[clkid_sdio1]) {
288350c3bceSjmcneill reg = SDIO_CLK_CTRL;
289350c3bceSjmcneill mask = CLK_CTRL_CLKACT1;
29004c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_uart0]) {
29104c770d6Sjmcneill reg = UART_CLK_CTRL;
292350c3bceSjmcneill mask = CLK_CTRL_CLKACT0;
29304c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_uart1]) {
29404c770d6Sjmcneill reg = UART_CLK_CTRL;
295350c3bceSjmcneill mask = CLK_CTRL_CLKACT1;
296*a0fe19daSjmcneill } else if (clk == &sc->sc_clk[clkid_pcap]) {
297*a0fe19daSjmcneill reg = PCAP_CLK_CTRL;
298*a0fe19daSjmcneill mask = CLK_CTRL_CLKACT0;
299350c3bceSjmcneill } else if (clk == &sc->sc_clk[clkid_sdio0_aper]) {
300350c3bceSjmcneill reg = APER_CLK_CTRL;
301350c3bceSjmcneill mask = SDI0_CPU_1XCLKACT;
302350c3bceSjmcneill } else if (clk == &sc->sc_clk[clkid_sdio1_aper]) {
303350c3bceSjmcneill reg = APER_CLK_CTRL;
304350c3bceSjmcneill mask = SDI1_CPU_1XCLKACT;
30504c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_uart0_aper]) {
30604c770d6Sjmcneill reg = APER_CLK_CTRL;
30704c770d6Sjmcneill mask = UART0_CPU_1XCLKACT;
30804c770d6Sjmcneill } else if (clk == &sc->sc_clk[clkid_uart1_aper]) {
30904c770d6Sjmcneill reg = APER_CLK_CTRL;
31004c770d6Sjmcneill mask = UART1_CPU_1XCLKACT;
31188c82104Sjmcneill } else if (clk == &sc->sc_clk[clkid_i2c0_aper]) {
31288c82104Sjmcneill reg = APER_CLK_CTRL;
31388c82104Sjmcneill mask = I2C0_CPU_1XCLKACT;
31488c82104Sjmcneill } else if (clk == &sc->sc_clk[clkid_i2c1_aper]) {
31588c82104Sjmcneill reg = APER_CLK_CTRL;
31688c82104Sjmcneill mask = I2C1_CPU_1XCLKACT;
31704c770d6Sjmcneill } else {
31804c770d6Sjmcneill return ENXIO;
31904c770d6Sjmcneill }
32004c770d6Sjmcneill
321a60aa55cSjmcneill syscon_lock(sc->sc_syscon);
322a60aa55cSjmcneill val = syscon_read_4(sc->sc_syscon, reg);
323a60aa55cSjmcneill syscon_write_4(sc->sc_syscon, reg, val | mask);
324a60aa55cSjmcneill syscon_unlock(sc->sc_syscon);
32504c770d6Sjmcneill
32604c770d6Sjmcneill return 0;
32704c770d6Sjmcneill }
32804c770d6Sjmcneill
32904c770d6Sjmcneill static int
zynq7000_clkc_clk_disable(void * priv,struct clk * clk)33004c770d6Sjmcneill zynq7000_clkc_clk_disable(void *priv, struct clk *clk)
33104c770d6Sjmcneill {
33204c770d6Sjmcneill return ENXIO;
33304c770d6Sjmcneill }
33404c770d6Sjmcneill
33504c770d6Sjmcneill static const struct clk_funcs zynq7000_clkc_clk_funcs = {
33604c770d6Sjmcneill .get = zynq7000_clkc_clk_get,
33704c770d6Sjmcneill .put = zynq7000_clkc_clk_put,
33804c770d6Sjmcneill .get_rate = zynq7000_clkc_clk_get_rate,
33904c770d6Sjmcneill .enable = zynq7000_clkc_clk_enable,
34004c770d6Sjmcneill .disable = zynq7000_clkc_clk_disable,
34104c770d6Sjmcneill };
34204c770d6Sjmcneill
34304c770d6Sjmcneill static struct clk *
zynq7000_clkc_fdt_decode(device_t dev,int cc_phandle,const void * data,size_t len)34404c770d6Sjmcneill zynq7000_clkc_fdt_decode(device_t dev, int cc_phandle, const void *data, size_t len)
34504c770d6Sjmcneill {
34604c770d6Sjmcneill struct zynq7000_clkc_softc * const sc = device_private(dev);
34704c770d6Sjmcneill u_int clkid;
34804c770d6Sjmcneill
34904c770d6Sjmcneill if (len != 4) {
35004c770d6Sjmcneill return NULL;
35104c770d6Sjmcneill }
35204c770d6Sjmcneill
35304c770d6Sjmcneill clkid = be32dec(data);
35404c770d6Sjmcneill if (clkid >= num_clkid) {
35504c770d6Sjmcneill return NULL;
35604c770d6Sjmcneill }
35704c770d6Sjmcneill
35804c770d6Sjmcneill return &sc->sc_clk[clkid];
35904c770d6Sjmcneill }
36004c770d6Sjmcneill
36104c770d6Sjmcneill static const struct fdtbus_clock_controller_func zynq7000_clkc_fdt_funcs = {
36204c770d6Sjmcneill .decode = zynq7000_clkc_fdt_decode
36304c770d6Sjmcneill };
36404c770d6Sjmcneill
36504c770d6Sjmcneill static int
zynq7000_clkc_match(device_t parent,cfdata_t cf,void * aux)36604c770d6Sjmcneill zynq7000_clkc_match(device_t parent, cfdata_t cf, void *aux)
36704c770d6Sjmcneill {
36804c770d6Sjmcneill struct fdt_attach_args * const faa = aux;
36904c770d6Sjmcneill
37004c770d6Sjmcneill return of_compatible_match(faa->faa_phandle, compat_data);
37104c770d6Sjmcneill }
37204c770d6Sjmcneill
37304c770d6Sjmcneill static void
zynq7000_clkc_attach(device_t parent,device_t self,void * aux)37404c770d6Sjmcneill zynq7000_clkc_attach(device_t parent, device_t self, void *aux)
37504c770d6Sjmcneill {
37604c770d6Sjmcneill struct zynq7000_clkc_softc * const sc = device_private(self);
37704c770d6Sjmcneill struct fdt_attach_args * const faa = aux;
37804c770d6Sjmcneill const int phandle = faa->faa_phandle;
37904c770d6Sjmcneill const char *clkname;
38004c770d6Sjmcneill bus_addr_t addr;
38104c770d6Sjmcneill bus_size_t size;
38204c770d6Sjmcneill u_int clkid;
38304c770d6Sjmcneill int error;
38404c770d6Sjmcneill
38504c770d6Sjmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
38604c770d6Sjmcneill aprint_error(": couldn't get registers\n");
38704c770d6Sjmcneill return;
38804c770d6Sjmcneill }
38904c770d6Sjmcneill
39004c770d6Sjmcneill sc->sc_dev = self;
391a60aa55cSjmcneill sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(phandle));
392a60aa55cSjmcneill if (sc->sc_syscon == NULL) {
393a60aa55cSjmcneill aprint_error(": couldn't get syscon registers\n");
39404c770d6Sjmcneill return;
39504c770d6Sjmcneill }
39604c770d6Sjmcneill
39704c770d6Sjmcneill error = of_getprop_uint32(phandle, "ps-clk-frequency",
39804c770d6Sjmcneill &sc->sc_ps_clk_frequency);
39904c770d6Sjmcneill if (error != 0) {
40004c770d6Sjmcneill aprint_error(": couldn't get ps-clk-frequency\n");
40104c770d6Sjmcneill return;
40204c770d6Sjmcneill }
40304c770d6Sjmcneill
40404c770d6Sjmcneill sc->sc_clkdom.name = device_xname(self);
40504c770d6Sjmcneill sc->sc_clkdom.funcs = &zynq7000_clkc_clk_funcs;
40604c770d6Sjmcneill sc->sc_clkdom.priv = sc;
40704c770d6Sjmcneill for (clkid = 0; clkid < num_clkid; clkid++) {
40804c770d6Sjmcneill clkname = fdtbus_get_string_index(phandle,
40904c770d6Sjmcneill "clock-output-names", clkid);
41004c770d6Sjmcneill sc->sc_clk[clkid].domain = &sc->sc_clkdom;
41104c770d6Sjmcneill if (clkname != NULL) {
41204c770d6Sjmcneill sc->sc_clk[clkid].name = kmem_asprintf("%s", clkname);
41304c770d6Sjmcneill }
41404c770d6Sjmcneill clk_attach(&sc->sc_clk[clkid]);
41504c770d6Sjmcneill }
41604c770d6Sjmcneill
41704c770d6Sjmcneill aprint_naive("\n");
41804c770d6Sjmcneill aprint_normal(": Zynq-7000 PS clock subsystem (PS_CLK %u Hz)\n",
41904c770d6Sjmcneill sc->sc_ps_clk_frequency);
42004c770d6Sjmcneill
421a60aa55cSjmcneill for (clkid = 0; clkid < num_clkid; clkid++) {
422a60aa55cSjmcneill aprint_debug_dev(self, "clkid %u [%s]: %u Hz\n", clkid,
423a60aa55cSjmcneill sc->sc_clk[clkid].name ? sc->sc_clk[clkid].name : "<none>",
424a60aa55cSjmcneill clk_get_rate(&sc->sc_clk[clkid]));
425a60aa55cSjmcneill }
426a60aa55cSjmcneill
42704c770d6Sjmcneill fdtbus_register_clock_controller(self, phandle, &zynq7000_clkc_fdt_funcs);
42804c770d6Sjmcneill }
429