Commit | Line | Data |
---|---|---|
4210be66 GU |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * StarFive JH7100 Clock Generator Driver | |
4 | * | |
5 | * Copyright 2021 Ahmad Fatoum, Pengutronix | |
6 | * Copyright (C) 2021 Glider bv | |
7 | * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk> | |
8 | */ | |
9 | ||
10 | #include <linux/bits.h> | |
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/debugfs.h> | |
13 | #include <linux/device.h> | |
14 | #include <linux/init.h> | |
15 | #include <linux/io.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/mod_devicetable.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/platform_device.h> | |
20 | ||
21 | #include <dt-bindings/clock/starfive-jh7100.h> | |
22 | ||
26ad971f ERB |
23 | #include "clk-starfive-jh7100.h" |
24 | ||
4210be66 GU |
25 | /* external clocks */ |
26 | #define JH7100_CLK_OSC_SYS (JH7100_CLK_END + 0) | |
27 | #define JH7100_CLK_OSC_AUD (JH7100_CLK_END + 1) | |
28 | #define JH7100_CLK_GMAC_RMII_REF (JH7100_CLK_END + 2) | |
29 | #define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3) | |
30 | ||
26ad971f | 31 | static const struct jh7100_clk_data jh7100_clk_data[] __initconst = { |
4210be66 GU |
32 | JH7100__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, |
33 | JH7100_CLK_OSC_SYS, | |
34 | JH7100_CLK_PLL0_OUT, | |
35 | JH7100_CLK_PLL1_OUT, | |
36 | JH7100_CLK_PLL2_OUT), | |
37 | JH7100__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, | |
38 | JH7100_CLK_OSC_SYS, | |
39 | JH7100_CLK_PLL1_OUT, | |
40 | JH7100_CLK_PLL2_OUT), | |
41 | JH7100__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, | |
42 | JH7100_CLK_OSC_SYS, | |
43 | JH7100_CLK_PLL0_OUT, | |
44 | JH7100_CLK_PLL1_OUT, | |
45 | JH7100_CLK_PLL2_OUT), | |
46 | JH7100__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, | |
47 | JH7100_CLK_OSC_SYS, | |
48 | JH7100_CLK_PLL0_OUT, | |
49 | JH7100_CLK_PLL2_OUT), | |
50 | JH7100__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, | |
51 | JH7100_CLK_OSC_SYS, | |
52 | JH7100_CLK_PLL0_OUT), | |
53 | JH7100__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, | |
54 | JH7100_CLK_OSC_SYS, | |
55 | JH7100_CLK_PLL2_OUT), | |
56 | JH7100__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, | |
57 | JH7100_CLK_OSC_SYS, | |
58 | JH7100_CLK_PLL1_OUT, | |
59 | JH7100_CLK_PLL2_OUT), | |
60 | JH7100__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, | |
61 | JH7100_CLK_OSC_AUD, | |
62 | JH7100_CLK_PLL0_OUT, | |
63 | JH7100_CLK_PLL2_OUT), | |
64 | JH7100_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), | |
65 | JH7100__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, | |
66 | JH7100_CLK_OSC_SYS, | |
67 | JH7100_CLK_PLL1_OUT, | |
68 | JH7100_CLK_PLL2_OUT), | |
69 | JH7100__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, | |
70 | JH7100_CLK_OSC_SYS, | |
71 | JH7100_CLK_PLL0_OUT, | |
72 | JH7100_CLK_PLL1_OUT), | |
73 | JH7100__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, | |
74 | JH7100_CLK_OSC_AUD, | |
75 | JH7100_CLK_PLL0_OUT, | |
76 | JH7100_CLK_PLL2_OUT), | |
77 | JH7100__DIV(JH7100_CLK_CPUNBUS_ROOT_DIV, "cpunbus_root_div", 2, JH7100_CLK_CPUNDBUS_ROOT), | |
78 | JH7100__DIV(JH7100_CLK_DSP_ROOT_DIV, "dsp_root_div", 4, JH7100_CLK_DSP_ROOT), | |
79 | JH7100__DIV(JH7100_CLK_PERH0_SRC, "perh0_src", 4, JH7100_CLK_PERH0_ROOT), | |
80 | JH7100__DIV(JH7100_CLK_PERH1_SRC, "perh1_src", 4, JH7100_CLK_PERH1_ROOT), | |
81 | JH7100_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), | |
82 | JH7100_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), | |
83 | JH7100_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), | |
84 | JH7100__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, | |
85 | JH7100_CLK_OSC_SYS, | |
86 | JH7100_CLK_OSC_AUD), | |
87 | JH7100__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
88 | JH7100__DIV(JH7100_CLK_CPU_AXI, "cpu_axi", 8, JH7100_CLK_CPU_CORE), | |
89 | JH7100__DIV(JH7100_CLK_AHB_BUS, "ahb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
90 | JH7100__DIV(JH7100_CLK_APB1_BUS, "apb1_bus", 8, JH7100_CLK_AHB_BUS), | |
91 | JH7100__DIV(JH7100_CLK_APB2_BUS, "apb2_bus", 8, JH7100_CLK_AHB_BUS), | |
92 | JH7100_GATE(JH7100_CLK_DOM3AHB_BUS, "dom3ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), | |
93 | JH7100_GATE(JH7100_CLK_DOM7AHB_BUS, "dom7ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), | |
94 | JH7100_GATE(JH7100_CLK_U74_CORE0, "u74_core0", CLK_IS_CRITICAL, JH7100_CLK_CPU_CORE), | |
95 | JH7100_GDIV(JH7100_CLK_U74_CORE1, "u74_core1", CLK_IS_CRITICAL, 8, JH7100_CLK_CPU_CORE), | |
96 | JH7100_GATE(JH7100_CLK_U74_AXI, "u74_axi", CLK_IS_CRITICAL, JH7100_CLK_CPU_AXI), | |
97 | JH7100_GATE(JH7100_CLK_U74RTC_TOGGLE, "u74rtc_toggle", CLK_IS_CRITICAL, JH7100_CLK_OSC_SYS), | |
98 | JH7100_GATE(JH7100_CLK_SGDMA2P_AXI, "sgdma2p_axi", 0, JH7100_CLK_CPU_AXI), | |
99 | JH7100_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI), | |
100 | JH7100_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS), | |
101 | JH7100__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT), | |
102 | JH7100_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS), | |
103 | JH7100_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS), | |
104 | JH7100_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS), | |
105 | JH7100_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV), | |
106 | JH7100__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT), | |
107 | JH7100_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC), | |
108 | JH7100__DIV(JH7100_CLK_VCDECBUS_SRC, "vcdecbus_src", 4, JH7100_CLK_CDECHIFI4_ROOT), | |
109 | JH7100__DIV(JH7100_CLK_VDEC_BUS, "vdec_bus", 8, JH7100_CLK_VCDECBUS_SRC), | |
110 | JH7100_GATE(JH7100_CLK_VDEC_AXI, "vdec_axi", 0, JH7100_CLK_VDEC_BUS), | |
111 | JH7100_GATE(JH7100_CLK_VDECBRG_MAIN, "vdecbrg_mainclk", 0, JH7100_CLK_VDEC_BUS), | |
112 | JH7100_GDIV(JH7100_CLK_VDEC_BCLK, "vdec_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), | |
113 | JH7100_GDIV(JH7100_CLK_VDEC_CCLK, "vdec_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), | |
114 | JH7100_GATE(JH7100_CLK_VDEC_APB, "vdec_apb", 0, JH7100_CLK_APB1_BUS), | |
115 | JH7100_GDIV(JH7100_CLK_JPEG_AXI, "jpeg_axi", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
116 | JH7100_GDIV(JH7100_CLK_JPEG_CCLK, "jpeg_cclk", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
117 | JH7100_GATE(JH7100_CLK_JPEG_APB, "jpeg_apb", 0, JH7100_CLK_APB1_BUS), | |
118 | JH7100_GDIV(JH7100_CLK_GC300_2X, "gc300_2x", 0, 8, JH7100_CLK_CDECHIFI4_ROOT), | |
119 | JH7100_GATE(JH7100_CLK_GC300_AHB, "gc300_ahb", 0, JH7100_CLK_AHB_BUS), | |
120 | JH7100__DIV(JH7100_CLK_JPCGC300_AXIBUS, "jpcgc300_axibus", 8, JH7100_CLK_VCDECBUS_SRC), | |
121 | JH7100_GATE(JH7100_CLK_GC300_AXI, "gc300_axi", 0, JH7100_CLK_JPCGC300_AXIBUS), | |
122 | JH7100_GATE(JH7100_CLK_JPCGC300_MAIN, "jpcgc300_mainclk", 0, JH7100_CLK_JPCGC300_AXIBUS), | |
123 | JH7100__DIV(JH7100_CLK_VENC_BUS, "venc_bus", 8, JH7100_CLK_VCDECBUS_SRC), | |
124 | JH7100_GATE(JH7100_CLK_VENC_AXI, "venc_axi", 0, JH7100_CLK_VENC_BUS), | |
125 | JH7100_GATE(JH7100_CLK_VENCBRG_MAIN, "vencbrg_mainclk", 0, JH7100_CLK_VENC_BUS), | |
126 | JH7100_GDIV(JH7100_CLK_VENC_BCLK, "venc_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), | |
127 | JH7100_GDIV(JH7100_CLK_VENC_CCLK, "venc_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), | |
128 | JH7100_GATE(JH7100_CLK_VENC_APB, "venc_apb", 0, JH7100_CLK_APB1_BUS), | |
129 | JH7100_GDIV(JH7100_CLK_DDRPLL_DIV2, "ddrpll_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_PLL1_OUT), | |
130 | JH7100_GDIV(JH7100_CLK_DDRPLL_DIV4, "ddrpll_div4", CLK_IS_CRITICAL, 2, JH7100_CLK_DDRPLL_DIV2), | |
131 | JH7100_GDIV(JH7100_CLK_DDRPLL_DIV8, "ddrpll_div8", CLK_IS_CRITICAL, 2, JH7100_CLK_DDRPLL_DIV4), | |
132 | JH7100_GDIV(JH7100_CLK_DDROSC_DIV2, "ddrosc_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_OSC_SYS), | |
133 | JH7100_GMUX(JH7100_CLK_DDRC0, "ddrc0", CLK_IS_CRITICAL, 4, | |
134 | JH7100_CLK_DDROSC_DIV2, | |
135 | JH7100_CLK_DDRPLL_DIV2, | |
136 | JH7100_CLK_DDRPLL_DIV4, | |
137 | JH7100_CLK_DDRPLL_DIV8), | |
138 | JH7100_GMUX(JH7100_CLK_DDRC1, "ddrc1", CLK_IS_CRITICAL, 4, | |
139 | JH7100_CLK_DDROSC_DIV2, | |
140 | JH7100_CLK_DDRPLL_DIV2, | |
141 | JH7100_CLK_DDRPLL_DIV4, | |
142 | JH7100_CLK_DDRPLL_DIV8), | |
143 | JH7100_GATE(JH7100_CLK_DDRPHY_APB, "ddrphy_apb", 0, JH7100_CLK_APB1_BUS), | |
144 | JH7100__DIV(JH7100_CLK_NOC_ROB, "noc_rob", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
145 | JH7100__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), | |
146 | JH7100_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), | |
147 | JH7100__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), | |
148 | JH7100__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, | |
149 | JH7100_CLK_CPU_AXI, | |
150 | JH7100_CLK_NNEBUS_SRC1), | |
151 | JH7100_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), | |
152 | JH7100_GATE(JH7100_CLK_NNENOC_AXI, "nnenoc_axi", 0, JH7100_CLK_NNE_BUS), | |
153 | JH7100_GATE(JH7100_CLK_DLASLV_AXI, "dlaslv_axi", 0, JH7100_CLK_NNE_BUS), | |
154 | JH7100_GATE(JH7100_CLK_DSPX2C_AXI, "dspx2c_axi", CLK_IS_CRITICAL, JH7100_CLK_NNE_BUS), | |
155 | JH7100__DIV(JH7100_CLK_HIFI4_SRC, "hifi4_src", 4, JH7100_CLK_CDECHIFI4_ROOT), | |
156 | JH7100__DIV(JH7100_CLK_HIFI4_COREFREE, "hifi4_corefree", 8, JH7100_CLK_HIFI4_SRC), | |
157 | JH7100_GATE(JH7100_CLK_HIFI4_CORE, "hifi4_core", 0, JH7100_CLK_HIFI4_COREFREE), | |
158 | JH7100__DIV(JH7100_CLK_HIFI4_BUS, "hifi4_bus", 8, JH7100_CLK_HIFI4_COREFREE), | |
159 | JH7100_GATE(JH7100_CLK_HIFI4_AXI, "hifi4_axi", 0, JH7100_CLK_HIFI4_BUS), | |
160 | JH7100_GATE(JH7100_CLK_HIFI4NOC_AXI, "hifi4noc_axi", 0, JH7100_CLK_HIFI4_BUS), | |
161 | JH7100__DIV(JH7100_CLK_SGDMA1P_BUS, "sgdma1p_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
162 | JH7100_GATE(JH7100_CLK_SGDMA1P_AXI, "sgdma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), | |
163 | JH7100_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), | |
164 | JH7100_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
165 | JH7100__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), | |
166 | JH7100_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS), | |
167 | JH7100_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS), | |
168 | JH7100__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT), | |
169 | JH7100_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), | |
170 | JH7100_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, JH7100_CLK_USBPHY_ROOTDIV), | |
171 | JH7100__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, | |
172 | JH7100_CLK_OSC_SYS, | |
173 | JH7100_CLK_USBPHY_PLLDIV25M), | |
73bfc8d7 | 174 | JH7100_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), |
4210be66 GU |
175 | JH7100_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV), |
176 | JH7100_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD), | |
177 | JH7100_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT), | |
178 | JH7100__DIV(JH7100_CLK_ISP0_BUS, "isp0_bus", 8, JH7100_CLK_VIN_SRC), | |
179 | JH7100_GATE(JH7100_CLK_ISP0_AXI, "isp0_axi", 0, JH7100_CLK_ISP0_BUS), | |
180 | JH7100_GATE(JH7100_CLK_ISP0NOC_AXI, "isp0noc_axi", 0, JH7100_CLK_ISP0_BUS), | |
181 | JH7100_GATE(JH7100_CLK_ISPSLV_AXI, "ispslv_axi", 0, JH7100_CLK_ISP0_BUS), | |
182 | JH7100__DIV(JH7100_CLK_ISP1_BUS, "isp1_bus", 8, JH7100_CLK_VIN_SRC), | |
183 | JH7100_GATE(JH7100_CLK_ISP1_AXI, "isp1_axi", 0, JH7100_CLK_ISP1_BUS), | |
184 | JH7100_GATE(JH7100_CLK_ISP1NOC_AXI, "isp1noc_axi", 0, JH7100_CLK_ISP1_BUS), | |
185 | JH7100__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC), | |
186 | JH7100_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS), | |
187 | JH7100_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS), | |
188 | JH7100_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT), | |
189 | JH7100__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT), | |
190 | JH7100__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC), | |
191 | JH7100_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS), | |
192 | JH7100_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS), | |
193 | JH7100_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS), | |
194 | JH7100_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC), | |
195 | JH7100__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT), | |
196 | JH7100_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), | |
197 | JH7100_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), | |
198 | JH7100__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), | |
199 | JH7100_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), | |
200 | JH7100__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), | |
201 | JH7100_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), | |
202 | JH7100_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), | |
203 | JH7100_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), | |
204 | JH7100_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), | |
205 | JH7100__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, | |
206 | JH7100_CLK_GMAC_GTX, | |
207 | JH7100_CLK_GMAC_TX_INV, | |
208 | JH7100_CLK_GMAC_RMII_TX), | |
209 | JH7100__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), | |
210 | JH7100__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, | |
211 | JH7100_CLK_GMAC_GR_MII_RX, | |
212 | JH7100_CLK_GMAC_RMII_RX), | |
213 | JH7100__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), | |
214 | JH7100_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), | |
215 | JH7100_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), | |
216 | JH7100_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), | |
217 | JH7100_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), | |
218 | JH7100_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), | |
219 | JH7100_GATE(JH7100_CLK_E24_AHB, "e24_ahb", 0, JH7100_CLK_AHB_BUS), | |
220 | JH7100_GATE(JH7100_CLK_E24RTC_TOGGLE, "e24rtc_toggle", 0, JH7100_CLK_OSC_SYS), | |
221 | JH7100_GATE(JH7100_CLK_QSPI_AHB, "qspi_ahb", 0, JH7100_CLK_AHB_BUS), | |
222 | JH7100_GATE(JH7100_CLK_QSPI_APB, "qspi_apb", 0, JH7100_CLK_APB1_BUS), | |
223 | JH7100_GDIV(JH7100_CLK_QSPI_REF, "qspi_refclk", 0, 31, JH7100_CLK_PERH0_SRC), | |
224 | JH7100_GATE(JH7100_CLK_SEC_AHB, "sec_ahb", 0, JH7100_CLK_AHB_BUS), | |
225 | JH7100_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB), | |
226 | JH7100_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB), | |
227 | JH7100_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB), | |
228 | JH7100_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS), | |
229 | JH7100_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS), | |
230 | JH7100_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS), | |
231 | JH7100_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC), | |
232 | JH7100_GATE(JH7100_CLK_UART1_APB, "uart1_apb", 0, JH7100_CLK_APB1_BUS), | |
233 | JH7100_GDIV(JH7100_CLK_UART1_CORE, "uart1_core", 0, 63, JH7100_CLK_PERH1_SRC), | |
234 | JH7100_GATE(JH7100_CLK_SPI0_APB, "spi0_apb", 0, JH7100_CLK_APB1_BUS), | |
235 | JH7100_GDIV(JH7100_CLK_SPI0_CORE, "spi0_core", 0, 63, JH7100_CLK_PERH1_SRC), | |
236 | JH7100_GATE(JH7100_CLK_SPI1_APB, "spi1_apb", 0, JH7100_CLK_APB1_BUS), | |
237 | JH7100_GDIV(JH7100_CLK_SPI1_CORE, "spi1_core", 0, 63, JH7100_CLK_PERH1_SRC), | |
238 | JH7100_GATE(JH7100_CLK_I2C0_APB, "i2c0_apb", 0, JH7100_CLK_APB1_BUS), | |
239 | JH7100_GDIV(JH7100_CLK_I2C0_CORE, "i2c0_core", 0, 63, JH7100_CLK_PERH1_SRC), | |
240 | JH7100_GATE(JH7100_CLK_I2C1_APB, "i2c1_apb", 0, JH7100_CLK_APB1_BUS), | |
241 | JH7100_GDIV(JH7100_CLK_I2C1_CORE, "i2c1_core", 0, 63, JH7100_CLK_PERH1_SRC), | |
242 | JH7100_GATE(JH7100_CLK_GPIO_APB, "gpio_apb", 0, JH7100_CLK_APB1_BUS), | |
243 | JH7100_GATE(JH7100_CLK_UART2_APB, "uart2_apb", 0, JH7100_CLK_APB2_BUS), | |
244 | JH7100_GDIV(JH7100_CLK_UART2_CORE, "uart2_core", 0, 63, JH7100_CLK_PERH0_SRC), | |
245 | JH7100_GATE(JH7100_CLK_UART3_APB, "uart3_apb", 0, JH7100_CLK_APB2_BUS), | |
246 | JH7100_GDIV(JH7100_CLK_UART3_CORE, "uart3_core", 0, 63, JH7100_CLK_PERH0_SRC), | |
247 | JH7100_GATE(JH7100_CLK_SPI2_APB, "spi2_apb", 0, JH7100_CLK_APB2_BUS), | |
248 | JH7100_GDIV(JH7100_CLK_SPI2_CORE, "spi2_core", 0, 63, JH7100_CLK_PERH0_SRC), | |
249 | JH7100_GATE(JH7100_CLK_SPI3_APB, "spi3_apb", 0, JH7100_CLK_APB2_BUS), | |
250 | JH7100_GDIV(JH7100_CLK_SPI3_CORE, "spi3_core", 0, 63, JH7100_CLK_PERH0_SRC), | |
251 | JH7100_GATE(JH7100_CLK_I2C2_APB, "i2c2_apb", 0, JH7100_CLK_APB2_BUS), | |
252 | JH7100_GDIV(JH7100_CLK_I2C2_CORE, "i2c2_core", 0, 63, JH7100_CLK_PERH0_SRC), | |
253 | JH7100_GATE(JH7100_CLK_I2C3_APB, "i2c3_apb", 0, JH7100_CLK_APB2_BUS), | |
254 | JH7100_GDIV(JH7100_CLK_I2C3_CORE, "i2c3_core", 0, 63, JH7100_CLK_PERH0_SRC), | |
255 | JH7100_GATE(JH7100_CLK_WDTIMER_APB, "wdtimer_apb", 0, JH7100_CLK_APB2_BUS), | |
256 | JH7100_GDIV(JH7100_CLK_WDT_CORE, "wdt_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
257 | JH7100_GDIV(JH7100_CLK_TIMER0_CORE, "timer0_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
258 | JH7100_GDIV(JH7100_CLK_TIMER1_CORE, "timer1_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
259 | JH7100_GDIV(JH7100_CLK_TIMER2_CORE, "timer2_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
260 | JH7100_GDIV(JH7100_CLK_TIMER3_CORE, "timer3_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
261 | JH7100_GDIV(JH7100_CLK_TIMER4_CORE, "timer4_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
262 | JH7100_GDIV(JH7100_CLK_TIMER5_CORE, "timer5_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
263 | JH7100_GDIV(JH7100_CLK_TIMER6_CORE, "timer6_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), | |
264 | JH7100_GATE(JH7100_CLK_VP6INTC_APB, "vp6intc_apb", 0, JH7100_CLK_APB2_BUS), | |
265 | JH7100_GATE(JH7100_CLK_PWM_APB, "pwm_apb", 0, JH7100_CLK_APB2_BUS), | |
266 | JH7100_GATE(JH7100_CLK_MSI_APB, "msi_apb", 0, JH7100_CLK_APB2_BUS), | |
267 | JH7100_GATE(JH7100_CLK_TEMP_APB, "temp_apb", 0, JH7100_CLK_APB2_BUS), | |
268 | JH7100_GDIV(JH7100_CLK_TEMP_SENSE, "temp_sense", 0, 31, JH7100_CLK_OSC_SYS), | |
269 | JH7100_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), | |
270 | }; | |
271 | ||
4210be66 GU |
272 | static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw) |
273 | { | |
274 | return container_of(hw, struct jh7100_clk, hw); | |
275 | } | |
276 | ||
277 | static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk) | |
278 | { | |
279 | return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]); | |
280 | } | |
281 | ||
282 | static u32 jh7100_clk_reg_get(struct jh7100_clk *clk) | |
283 | { | |
284 | struct jh7100_clk_priv *priv = jh7100_priv_from(clk); | |
285 | void __iomem *reg = priv->base + 4 * clk->idx; | |
286 | ||
287 | return readl_relaxed(reg); | |
288 | } | |
289 | ||
290 | static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value) | |
291 | { | |
292 | struct jh7100_clk_priv *priv = jh7100_priv_from(clk); | |
293 | void __iomem *reg = priv->base + 4 * clk->idx; | |
294 | unsigned long flags; | |
295 | ||
296 | spin_lock_irqsave(&priv->rmw_lock, flags); | |
297 | value |= readl_relaxed(reg) & ~mask; | |
298 | writel_relaxed(value, reg); | |
299 | spin_unlock_irqrestore(&priv->rmw_lock, flags); | |
300 | } | |
301 | ||
302 | static int jh7100_clk_enable(struct clk_hw *hw) | |
303 | { | |
304 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
305 | ||
306 | jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE); | |
307 | return 0; | |
308 | } | |
309 | ||
310 | static void jh7100_clk_disable(struct clk_hw *hw) | |
311 | { | |
312 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
313 | ||
314 | jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0); | |
315 | } | |
316 | ||
317 | static int jh7100_clk_is_enabled(struct clk_hw *hw) | |
318 | { | |
319 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
320 | ||
321 | return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE); | |
322 | } | |
323 | ||
324 | static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw, | |
325 | unsigned long parent_rate) | |
326 | { | |
327 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
328 | u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK; | |
329 | ||
330 | return div ? parent_rate / div : 0; | |
331 | } | |
332 | ||
4210be66 GU |
333 | static int jh7100_clk_determine_rate(struct clk_hw *hw, |
334 | struct clk_rate_request *req) | |
335 | { | |
336 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
337 | unsigned long parent = req->best_parent_rate; | |
338 | unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); | |
40dda353 | 339 | unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); |
4210be66 GU |
340 | unsigned long result = parent / div; |
341 | ||
342 | /* | |
343 | * we want the result clamped by min_rate and max_rate if possible: | |
344 | * case 1: div hits the max divider value, which means it's less than | |
345 | * parent / rate, so the result is greater than rate and min_rate in | |
346 | * particular. we can't do anything about result > max_rate because the | |
347 | * divider doesn't go any further. | |
348 | * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is | |
349 | * always lower or equal to rate and max_rate. however the result may | |
350 | * turn out lower than min_rate, but then the next higher rate is fine: | |
351 | * div - 1 = ceil(parent / rate) - 1 < parent / rate | |
352 | * and thus | |
353 | * min_rate <= rate < parent / (div - 1) | |
354 | */ | |
355 | if (result < req->min_rate && div > 1) | |
356 | result = parent / (div - 1); | |
357 | ||
358 | req->rate = result; | |
359 | return 0; | |
360 | } | |
361 | ||
362 | static int jh7100_clk_set_rate(struct clk_hw *hw, | |
363 | unsigned long rate, | |
364 | unsigned long parent_rate) | |
365 | { | |
366 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
40dda353 ERB |
367 | unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), |
368 | 1UL, (unsigned long)clk->max_div); | |
4210be66 GU |
369 | |
370 | jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div); | |
371 | return 0; | |
372 | } | |
373 | ||
73bfc8d7 ERB |
374 | static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw, |
375 | unsigned long parent_rate) | |
376 | { | |
377 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
378 | u32 reg = jh7100_clk_reg_get(clk); | |
379 | unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) + | |
380 | ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT); | |
381 | ||
382 | return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; | |
383 | } | |
384 | ||
385 | static int jh7100_clk_frac_determine_rate(struct clk_hw *hw, | |
386 | struct clk_rate_request *req) | |
387 | { | |
388 | unsigned long parent100 = 100 * req->best_parent_rate; | |
389 | unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); | |
390 | unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), | |
391 | JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); | |
392 | unsigned long result = parent100 / div100; | |
393 | ||
394 | /* clamp the result as in jh7100_clk_determine_rate() above */ | |
395 | if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX) | |
396 | result = parent100 / (div100 + 1); | |
397 | if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN) | |
398 | result = parent100 / (div100 - 1); | |
399 | ||
400 | req->rate = result; | |
401 | return 0; | |
402 | } | |
403 | ||
404 | static int jh7100_clk_frac_set_rate(struct clk_hw *hw, | |
405 | unsigned long rate, | |
406 | unsigned long parent_rate) | |
407 | { | |
408 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
409 | unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), | |
410 | JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); | |
411 | u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100); | |
412 | ||
413 | jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value); | |
414 | return 0; | |
415 | } | |
416 | ||
4210be66 GU |
417 | static u8 jh7100_clk_get_parent(struct clk_hw *hw) |
418 | { | |
419 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
420 | u32 value = jh7100_clk_reg_get(clk); | |
421 | ||
422 | return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT; | |
423 | } | |
424 | ||
425 | static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index) | |
426 | { | |
427 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
428 | u32 value = (u32)index << JH7100_CLK_MUX_SHIFT; | |
429 | ||
430 | jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value); | |
431 | return 0; | |
432 | } | |
433 | ||
434 | static int jh7100_clk_mux_determine_rate(struct clk_hw *hw, | |
435 | struct clk_rate_request *req) | |
436 | { | |
437 | return clk_mux_determine_rate_flags(hw, req, 0); | |
438 | } | |
439 | ||
440 | static int jh7100_clk_get_phase(struct clk_hw *hw) | |
441 | { | |
442 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
443 | u32 value = jh7100_clk_reg_get(clk); | |
444 | ||
445 | return (value & JH7100_CLK_INVERT) ? 180 : 0; | |
446 | } | |
447 | ||
448 | static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees) | |
449 | { | |
450 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
451 | u32 value; | |
452 | ||
453 | if (degrees == 0) | |
454 | value = 0; | |
455 | else if (degrees == 180) | |
456 | value = JH7100_CLK_INVERT; | |
457 | else | |
458 | return -EINVAL; | |
459 | ||
460 | jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value); | |
461 | return 0; | |
462 | } | |
463 | ||
464 | #ifdef CONFIG_DEBUG_FS | |
465 | static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) | |
466 | { | |
467 | static const struct debugfs_reg32 jh7100_clk_reg = { | |
468 | .name = "CTRL", | |
469 | .offset = 0, | |
470 | }; | |
471 | struct jh7100_clk *clk = jh7100_clk_from(hw); | |
472 | struct jh7100_clk_priv *priv = jh7100_priv_from(clk); | |
473 | struct debugfs_regset32 *regset; | |
474 | ||
475 | regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); | |
476 | if (!regset) | |
477 | return; | |
478 | ||
479 | regset->regs = &jh7100_clk_reg; | |
480 | regset->nregs = 1; | |
481 | regset->base = priv->base + 4 * clk->idx; | |
482 | ||
483 | debugfs_create_regset32("registers", 0400, dentry, regset); | |
484 | } | |
485 | #else | |
486 | #define jh7100_clk_debug_init NULL | |
487 | #endif | |
488 | ||
489 | static const struct clk_ops jh7100_clk_gate_ops = { | |
490 | .enable = jh7100_clk_enable, | |
491 | .disable = jh7100_clk_disable, | |
492 | .is_enabled = jh7100_clk_is_enabled, | |
493 | .debug_init = jh7100_clk_debug_init, | |
494 | }; | |
495 | ||
496 | static const struct clk_ops jh7100_clk_div_ops = { | |
497 | .recalc_rate = jh7100_clk_recalc_rate, | |
498 | .determine_rate = jh7100_clk_determine_rate, | |
499 | .set_rate = jh7100_clk_set_rate, | |
500 | .debug_init = jh7100_clk_debug_init, | |
501 | }; | |
502 | ||
73bfc8d7 ERB |
503 | static const struct clk_ops jh7100_clk_fdiv_ops = { |
504 | .recalc_rate = jh7100_clk_frac_recalc_rate, | |
505 | .determine_rate = jh7100_clk_frac_determine_rate, | |
506 | .set_rate = jh7100_clk_frac_set_rate, | |
507 | .debug_init = jh7100_clk_debug_init, | |
508 | }; | |
509 | ||
4210be66 GU |
510 | static const struct clk_ops jh7100_clk_gdiv_ops = { |
511 | .enable = jh7100_clk_enable, | |
512 | .disable = jh7100_clk_disable, | |
513 | .is_enabled = jh7100_clk_is_enabled, | |
514 | .recalc_rate = jh7100_clk_recalc_rate, | |
515 | .determine_rate = jh7100_clk_determine_rate, | |
516 | .set_rate = jh7100_clk_set_rate, | |
517 | .debug_init = jh7100_clk_debug_init, | |
518 | }; | |
519 | ||
520 | static const struct clk_ops jh7100_clk_mux_ops = { | |
521 | .determine_rate = jh7100_clk_mux_determine_rate, | |
522 | .set_parent = jh7100_clk_set_parent, | |
523 | .get_parent = jh7100_clk_get_parent, | |
524 | .debug_init = jh7100_clk_debug_init, | |
525 | }; | |
526 | ||
527 | static const struct clk_ops jh7100_clk_gmux_ops = { | |
528 | .enable = jh7100_clk_enable, | |
529 | .disable = jh7100_clk_disable, | |
530 | .is_enabled = jh7100_clk_is_enabled, | |
531 | .determine_rate = jh7100_clk_mux_determine_rate, | |
532 | .set_parent = jh7100_clk_set_parent, | |
533 | .get_parent = jh7100_clk_get_parent, | |
534 | .debug_init = jh7100_clk_debug_init, | |
535 | }; | |
536 | ||
8c373f8c ERB |
537 | static const struct clk_ops jh7100_clk_mdiv_ops = { |
538 | .recalc_rate = jh7100_clk_recalc_rate, | |
539 | .determine_rate = jh7100_clk_determine_rate, | |
540 | .get_parent = jh7100_clk_get_parent, | |
541 | .set_parent = jh7100_clk_set_parent, | |
542 | .set_rate = jh7100_clk_set_rate, | |
543 | .debug_init = jh7100_clk_debug_init, | |
544 | }; | |
545 | ||
546 | static const struct clk_ops jh7100_clk_gmd_ops = { | |
547 | .enable = jh7100_clk_enable, | |
548 | .disable = jh7100_clk_disable, | |
549 | .is_enabled = jh7100_clk_is_enabled, | |
550 | .recalc_rate = jh7100_clk_recalc_rate, | |
551 | .determine_rate = jh7100_clk_determine_rate, | |
552 | .get_parent = jh7100_clk_get_parent, | |
553 | .set_parent = jh7100_clk_set_parent, | |
554 | .set_rate = jh7100_clk_set_rate, | |
555 | .debug_init = jh7100_clk_debug_init, | |
556 | }; | |
557 | ||
4210be66 GU |
558 | static const struct clk_ops jh7100_clk_inv_ops = { |
559 | .get_phase = jh7100_clk_get_phase, | |
560 | .set_phase = jh7100_clk_set_phase, | |
561 | .debug_init = jh7100_clk_debug_init, | |
562 | }; | |
563 | ||
26ad971f | 564 | const struct clk_ops *starfive_jh7100_clk_ops(u32 max) |
4210be66 GU |
565 | { |
566 | if (max & JH7100_CLK_DIV_MASK) { | |
8c373f8c ERB |
567 | if (max & JH7100_CLK_MUX_MASK) { |
568 | if (max & JH7100_CLK_ENABLE) | |
569 | return &jh7100_clk_gmd_ops; | |
570 | return &jh7100_clk_mdiv_ops; | |
571 | } | |
4210be66 GU |
572 | if (max & JH7100_CLK_ENABLE) |
573 | return &jh7100_clk_gdiv_ops; | |
73bfc8d7 ERB |
574 | if (max == JH7100_CLK_FRAC_MAX) |
575 | return &jh7100_clk_fdiv_ops; | |
4210be66 GU |
576 | return &jh7100_clk_div_ops; |
577 | } | |
578 | ||
579 | if (max & JH7100_CLK_MUX_MASK) { | |
580 | if (max & JH7100_CLK_ENABLE) | |
581 | return &jh7100_clk_gmux_ops; | |
582 | return &jh7100_clk_mux_ops; | |
583 | } | |
584 | ||
585 | if (max & JH7100_CLK_ENABLE) | |
586 | return &jh7100_clk_gate_ops; | |
587 | ||
588 | return &jh7100_clk_inv_ops; | |
589 | } | |
26ad971f | 590 | EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops); |
4210be66 GU |
591 | |
592 | static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data) | |
593 | { | |
594 | struct jh7100_clk_priv *priv = data; | |
595 | unsigned int idx = clkspec->args[0]; | |
596 | ||
597 | if (idx < JH7100_CLK_PLL0_OUT) | |
598 | return &priv->reg[idx].hw; | |
599 | ||
600 | if (idx < JH7100_CLK_END) | |
601 | return priv->pll[idx - JH7100_CLK_PLL0_OUT]; | |
602 | ||
603 | return ERR_PTR(-EINVAL); | |
604 | } | |
605 | ||
606 | static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) | |
607 | { | |
608 | struct jh7100_clk_priv *priv; | |
609 | unsigned int idx; | |
610 | int ret; | |
611 | ||
26ad971f | 612 | priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7100_CLK_PLL0_OUT), GFP_KERNEL); |
4210be66 GU |
613 | if (!priv) |
614 | return -ENOMEM; | |
615 | ||
616 | spin_lock_init(&priv->rmw_lock); | |
617 | priv->dev = &pdev->dev; | |
618 | priv->base = devm_platform_ioremap_resource(pdev, 0); | |
619 | if (IS_ERR(priv->base)) | |
620 | return PTR_ERR(priv->base); | |
621 | ||
622 | priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out", | |
623 | "osc_sys", 0, 40, 1); | |
624 | if (IS_ERR(priv->pll[0])) | |
625 | return PTR_ERR(priv->pll[0]); | |
626 | ||
627 | priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out", | |
628 | "osc_sys", 0, 64, 1); | |
629 | if (IS_ERR(priv->pll[1])) | |
630 | return PTR_ERR(priv->pll[1]); | |
631 | ||
632 | priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out", | |
633 | "pll2_refclk", 0, 55, 1); | |
634 | if (IS_ERR(priv->pll[2])) | |
635 | return PTR_ERR(priv->pll[2]); | |
636 | ||
637 | for (idx = 0; idx < JH7100_CLK_PLL0_OUT; idx++) { | |
638 | u32 max = jh7100_clk_data[idx].max; | |
639 | struct clk_parent_data parents[4] = {}; | |
640 | struct clk_init_data init = { | |
641 | .name = jh7100_clk_data[idx].name, | |
26ad971f | 642 | .ops = starfive_jh7100_clk_ops(max), |
4210be66 GU |
643 | .parent_data = parents, |
644 | .num_parents = ((max & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT) + 1, | |
645 | .flags = jh7100_clk_data[idx].flags, | |
646 | }; | |
647 | struct jh7100_clk *clk = &priv->reg[idx]; | |
648 | unsigned int i; | |
649 | ||
650 | for (i = 0; i < init.num_parents; i++) { | |
651 | unsigned int pidx = jh7100_clk_data[idx].parents[i]; | |
652 | ||
653 | if (pidx < JH7100_CLK_PLL0_OUT) | |
654 | parents[i].hw = &priv->reg[pidx].hw; | |
655 | else if (pidx < JH7100_CLK_END) | |
656 | parents[i].hw = priv->pll[pidx - JH7100_CLK_PLL0_OUT]; | |
657 | else if (pidx == JH7100_CLK_OSC_SYS) | |
658 | parents[i].fw_name = "osc_sys"; | |
659 | else if (pidx == JH7100_CLK_OSC_AUD) | |
660 | parents[i].fw_name = "osc_aud"; | |
661 | else if (pidx == JH7100_CLK_GMAC_RMII_REF) | |
662 | parents[i].fw_name = "gmac_rmii_ref"; | |
663 | else if (pidx == JH7100_CLK_GMAC_GR_MII_RX) | |
664 | parents[i].fw_name = "gmac_gr_mii_rxclk"; | |
665 | } | |
666 | ||
667 | clk->hw.init = &init; | |
668 | clk->idx = idx; | |
669 | clk->max_div = max & JH7100_CLK_DIV_MASK; | |
670 | ||
671 | ret = devm_clk_hw_register(priv->dev, &clk->hw); | |
672 | if (ret) | |
673 | return ret; | |
674 | } | |
675 | ||
676 | return devm_of_clk_add_hw_provider(priv->dev, jh7100_clk_get, priv); | |
677 | } | |
678 | ||
679 | static const struct of_device_id clk_starfive_jh7100_match[] = { | |
680 | { .compatible = "starfive,jh7100-clkgen" }, | |
681 | { /* sentinel */ } | |
682 | }; | |
683 | ||
684 | static struct platform_driver clk_starfive_jh7100_driver = { | |
685 | .driver = { | |
686 | .name = "clk-starfive-jh7100", | |
687 | .of_match_table = clk_starfive_jh7100_match, | |
688 | .suppress_bind_attrs = true, | |
689 | }, | |
690 | }; | |
691 | builtin_platform_driver_probe(clk_starfive_jh7100_driver, clk_starfive_jh7100_probe); |