File Index
Files and directories
Sign in
FILE

r9a09g077-cpg.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/renesas/r9a09g077-cpg.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * r9a09g077 Clock Pulse Generator / Module Standby and Software Reset
  4 *
  5 * Copyright (C) 2025 Renesas Electronics Corp.
  6 *
  7 */
  8
  9#include <linux/bitfield.h>
 10#include <linux/clk-provider.h>
 11#include <linux/device.h>
 12#include <linux/init.h>
 13#include <linux/kernel.h>
 14
 15#include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
 16#include <dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h>
 17#include "renesas-cpg-mssr.h"
 18
 19#define RZT2H_REG_BLOCK_SHIFT	11
 20#define RZT2H_REG_OFFSET_MASK	GENMASK(10, 0)
 21#define RZT2H_REG_CONF(block, offset)	(((block) << RZT2H_REG_BLOCK_SHIFT) | \
 22					((offset) & RZT2H_REG_OFFSET_MASK))
 23
 24#define RZT2H_REG_BLOCK(x)		((x) >> RZT2H_REG_BLOCK_SHIFT)
 25#define RZT2H_REG_OFFSET(x)		((x) & RZT2H_REG_OFFSET_MASK)
 26
 27#define SCKCR		RZT2H_REG_CONF(0, 0x00)
 28#define SCKCR2		RZT2H_REG_CONF(1, 0x04)
 29#define SCKCR3		RZT2H_REG_CONF(0, 0x08)
 30
 31#define OFFSET_MASK	GENMASK(31, 20)
 32#define SHIFT_MASK	GENMASK(19, 12)
 33#define WIDTH_MASK	GENMASK(11, 8)
 34
 35#define CONF_PACK(offset, shift, width)  \
 36	(FIELD_PREP_CONST(OFFSET_MASK, (offset)) | \
 37	FIELD_PREP_CONST(SHIFT_MASK, (shift)) | \
 38	FIELD_PREP_CONST(WIDTH_MASK, (width)))
 39
 40#define GET_SHIFT(val)         FIELD_GET(SHIFT_MASK, val)
 41#define GET_WIDTH(val)         FIELD_GET(WIDTH_MASK, val)
 42#define GET_REG_OFFSET(val)    FIELD_GET(OFFSET_MASK, val)
 43
 44#define DIVCA55C0	CONF_PACK(SCKCR2, 8, 1)
 45#define DIVCA55C1	CONF_PACK(SCKCR2, 9, 1)
 46#define DIVCA55C2	CONF_PACK(SCKCR2, 10, 1)
 47#define DIVCA55C3	CONF_PACK(SCKCR2, 11, 1)
 48#define DIVCA55S	CONF_PACK(SCKCR2, 12, 1)
 49#define DIVSPI3ASYNC	CONF_PACK(SCKCR2, 16, 2)
 50#define DIVSCI5ASYNC	CONF_PACK(SCKCR2, 18, 2)
 51
 52#define DIVSPI0ASYNC	CONF_PACK(SCKCR3, 0, 2)
 53#define DIVSPI1ASYNC	CONF_PACK(SCKCR3, 2, 2)
 54#define DIVSPI2ASYNC	CONF_PACK(SCKCR3, 4, 2)
 55#define DIVSCI0ASYNC	CONF_PACK(SCKCR3, 6, 2)
 56#define DIVSCI1ASYNC	CONF_PACK(SCKCR3, 8, 2)
 57#define DIVSCI2ASYNC	CONF_PACK(SCKCR3, 10, 2)
 58#define DIVSCI3ASYNC	CONF_PACK(SCKCR3, 12, 2)
 59#define DIVSCI4ASYNC	CONF_PACK(SCKCR3, 14, 2)
 60
 61#define SEL_PLL		CONF_PACK(SCKCR, 22, 1)
 62
 63enum rzt2h_clk_types {
 64	CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM,	/* Clock with divider */
 65	CLK_TYPE_RZT2H_MUX,			/* Clock with clock source selector */
 66};
 67
 68#define DEF_DIV(_name, _id, _parent, _conf, _dtable) \
 69	DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \
 70		 .parent = _parent, .dtable = _dtable, .flag = 0)
 71#define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \
 72	DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \
 73		 .parent_names = _parent_names, .num_parents = _num_parents, \
 74		 .flag = 0, .mux_flags = _mux_flags)
 75
 76enum clk_ids {
 77	/* Core Clock Outputs exported to DT */
 78	LAST_DT_CORE_CLK = R9A09G077_ETCLKE,
 79
 80	/* External Input Clocks */
 81	CLK_EXTAL,
 82
 83	/* Internal Core Clocks */
 84	CLK_LOCO,
 85	CLK_PLL0,
 86	CLK_PLL1,
 87	CLK_PLL2,
 88	CLK_PLL4,
 89	CLK_SEL_CLK_PLL0,
 90	CLK_SEL_CLK_PLL1,
 91	CLK_SEL_CLK_PLL2,
 92	CLK_SEL_CLK_PLL4,
 93	CLK_PLL4D1,
 94	CLK_SCI0ASYNC,
 95	CLK_SCI1ASYNC,
 96	CLK_SCI2ASYNC,
 97	CLK_SCI3ASYNC,
 98	CLK_SCI4ASYNC,
 99	CLK_SCI5ASYNC,
100	CLK_SPI0ASYNC,
101	CLK_SPI1ASYNC,
102	CLK_SPI2ASYNC,
103	CLK_SPI3ASYNC,
104
105	/* Module Clocks */
106	MOD_CLK_BASE,
107};
108
109static const struct clk_div_table dtable_1_2[] = {
110	{0, 2},
111	{1, 1},
112	{0, 0},
113};
114
115static const struct clk_div_table dtable_24_25_30_32[] = {
116	{0, 32},
117	{1, 30},
118	{2, 25},
119	{3, 24},
120	{0, 0},
121};
122
123/* Mux clock tables */
124
125static const char * const sel_clk_pll0[] = { ".loco", ".pll0" };
126static const char * const sel_clk_pll1[] = { ".loco", ".pll1" };
127static const char * const sel_clk_pll2[] = { ".loco", ".pll2" };
128static const char * const sel_clk_pll4[] = { ".loco", ".pll4" };
129
130static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
131	/* External Clock Inputs */
132	DEF_INPUT("extal", CLK_EXTAL),
133
134	/* Internal Core Clocks */
135	DEF_RATE(".loco", CLK_LOCO, 1000 * 1000),
136	DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48),
137	DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40),
138	DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 1, 32),
139	DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96),
140
141	DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL,
142		sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY),
143	DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL,
144		sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY),
145	DEF_MUX(".sel_clk_pll2", CLK_SEL_CLK_PLL2, SEL_PLL,
146		sel_clk_pll2, ARRAY_SIZE(sel_clk_pll2), CLK_MUX_READ_ONLY),
147	DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL,
148		sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY),
149
150	DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1),
151	DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC,
152		dtable_24_25_30_32),
153	DEF_DIV(".sci1async", CLK_SCI1ASYNC, CLK_PLL4D1, DIVSCI1ASYNC,
154		dtable_24_25_30_32),
155	DEF_DIV(".sci2async", CLK_SCI2ASYNC, CLK_PLL4D1, DIVSCI2ASYNC,
156		dtable_24_25_30_32),
157	DEF_DIV(".sci3async", CLK_SCI3ASYNC, CLK_PLL4D1, DIVSCI3ASYNC,
158		dtable_24_25_30_32),
159	DEF_DIV(".sci4async", CLK_SCI4ASYNC, CLK_PLL4D1, DIVSCI4ASYNC,
160		dtable_24_25_30_32),
161	DEF_DIV(".sci5async", CLK_SCI5ASYNC, CLK_PLL4D1, DIVSCI5ASYNC,
162		dtable_24_25_30_32),
163
164	DEF_DIV(".spi0async", CLK_SPI0ASYNC, CLK_PLL4D1, DIVSPI0ASYNC,
165		dtable_24_25_30_32),
166	DEF_DIV(".spi1async", CLK_SPI1ASYNC, CLK_PLL4D1, DIVSPI1ASYNC,
167		dtable_24_25_30_32),
168	DEF_DIV(".spi2async", CLK_SPI2ASYNC, CLK_PLL4D1, DIVSPI2ASYNC,
169		dtable_24_25_30_32),
170	DEF_DIV(".spi3async", CLK_SPI3ASYNC, CLK_PLL4D1, DIVSPI3ASYNC,
171		dtable_24_25_30_32),
172
173	/* Core output clk */
174	DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0,
175		dtable_1_2),
176	DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1,
177		dtable_1_2),
178	DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2,
179		dtable_1_2),
180	DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3,
181		dtable_1_2),
182	DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S,
183		dtable_1_2),
184	DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1),
185	DEF_FIXED("PCLKH", R9A09G077_CLK_PCLKH, CLK_SEL_CLK_PLL1, 4, 1),
186	DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1),
187	DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1),
188	DEF_FIXED("PCLKAH", R9A09G077_CLK_PCLKAH, CLK_PLL4D1, 6, 1),
189	DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1),
190	DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1),
191	DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1),
192	DEF_FIXED("ETCLKA", R9A09G077_ETCLKA, CLK_SEL_CLK_PLL1, 5, 1),
193	DEF_FIXED("ETCLKB", R9A09G077_ETCLKB, CLK_SEL_CLK_PLL1, 8, 1),
194	DEF_FIXED("ETCLKC", R9A09G077_ETCLKC, CLK_SEL_CLK_PLL1, 10, 1),
195	DEF_FIXED("ETCLKD", R9A09G077_ETCLKD, CLK_SEL_CLK_PLL1, 20, 1),
196	DEF_FIXED("ETCLKE", R9A09G077_ETCLKE, CLK_SEL_CLK_PLL1, 40, 1),
197};
198
199static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
200	DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC),
201	DEF_MOD("sci1fck", 9, CLK_SCI1ASYNC),
202	DEF_MOD("sci2fck", 10, CLK_SCI2ASYNC),
203	DEF_MOD("sci3fck", 11, CLK_SCI3ASYNC),
204	DEF_MOD("sci4fck", 12, CLK_SCI4ASYNC),
205	DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL),
206	DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL),
207	DEF_MOD("spi0", 104, CLK_SPI0ASYNC),
208	DEF_MOD("spi1", 105, CLK_SPI1ASYNC),
209	DEF_MOD("spi2", 106, CLK_SPI2ASYNC),
210	DEF_MOD("adc0", 206, R9A09G077_CLK_PCLKH),
211	DEF_MOD("adc1", 207, R9A09G077_CLK_PCLKH),
212	DEF_MOD("adc2", 225, R9A09G077_CLK_PCLKM),
213	DEF_MOD("tsu", 307, R9A09G077_CLK_PCLKL),
214	DEF_MOD("gmac0", 400, R9A09G077_CLK_PCLKM),
215	DEF_MOD("ethsw", 401, R9A09G077_CLK_PCLKM),
216	DEF_MOD("ethss", 403, R9A09G077_CLK_PCLKM),
217	DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM),
218	DEF_MOD("gmac1", 416, R9A09G077_CLK_PCLKAM),
219	DEF_MOD("gmac2", 417, R9A09G077_CLK_PCLKAM),
220	DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC),
221	DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL),
222	DEF_MOD("spi3", 602, CLK_SPI3ASYNC),
223	DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM),
224	DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM),
225};
226
227static struct clk * __init
228r9a09g077_cpg_div_clk_register(struct device *dev,
229			       const struct cpg_core_clk *core,
230			       void __iomem *addr, struct cpg_mssr_pub *pub)
231{
232	const struct clk *parent;
233	const char *parent_name;
234	struct clk_hw *clk_hw;
235
236	parent = pub->clks[core->parent];
237	if (IS_ERR(parent))
238		return ERR_CAST(parent);
239
240	parent_name = __clk_get_name(parent);
241
242	if (core->dtable)
243		clk_hw = devm_clk_hw_register_divider_table(dev, core->name,
244							    parent_name,
245							    CLK_SET_RATE_PARENT,
246							    addr,
247							    GET_SHIFT(core->conf),
248							    GET_WIDTH(core->conf),
249							    core->flag,
250							    core->dtable,
251							    &pub->rmw_lock);
252	else
253		clk_hw = devm_clk_hw_register_divider(dev, core->name,
254						      parent_name,
255						      CLK_SET_RATE_PARENT,
256						      addr,
257						      GET_SHIFT(core->conf),
258						      GET_WIDTH(core->conf),
259						      core->flag, &pub->rmw_lock);
260
261	if (IS_ERR(clk_hw))
262		return ERR_CAST(clk_hw);
263
264	return clk_hw->clk;
265}
266
267static struct clk * __init
268r9a09g077_cpg_mux_clk_register(struct device *dev,
269			       const struct cpg_core_clk *core,
270			       void __iomem *addr, struct cpg_mssr_pub *pub)
271{
272	struct clk_hw *clk_hw;
273
274	clk_hw = devm_clk_hw_register_mux(dev, core->name,
275					  core->parent_names, core->num_parents,
276					  core->flag,
277					  addr,
278					  GET_SHIFT(core->conf),
279					  GET_WIDTH(core->conf),
280					  core->mux_flags, &pub->rmw_lock);
281	if (IS_ERR(clk_hw))
282		return ERR_CAST(clk_hw);
283
284	return clk_hw->clk;
285}
286
287static struct clk * __init
288r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
289			   const struct cpg_mssr_info *info,
290			   struct cpg_mssr_pub *pub)
291{
292	u32 offset = GET_REG_OFFSET(core->conf);
293	void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0;
294	void __iomem *addr = base + RZT2H_REG_OFFSET(offset);
295
296	switch (core->type) {
297	case CLK_TYPE_RZT2H_DIV:
298		return r9a09g077_cpg_div_clk_register(dev, core, addr, pub);
299	case CLK_TYPE_RZT2H_MUX:
300		return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub);
301	default:
302		return ERR_PTR(-EINVAL);
303	}
304}
305
306const struct cpg_mssr_info r9a09g077_cpg_mssr_info = {
307	/* Core Clocks */
308	.core_clks = r9a09g077_core_clks,
309	.num_core_clks = ARRAY_SIZE(r9a09g077_core_clks),
310	.last_dt_core_clk = LAST_DT_CORE_CLK,
311	.num_total_core_clks = MOD_CLK_BASE,
312
313	/* Module Clocks */
314	.mod_clks = r9a09g077_mod_clks,
315	.num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks),
316	.num_hw_mod_clks = 14 * 32,
317
318	.reg_layout = CLK_REG_LAYOUT_RZ_T2H,
319	.cpg_clk_register = r9a09g077_cpg_clk_register,
320};
~/ Read-only file preview.