1add5ca2cSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
24ed37394SMagnus Damm /*
34ed37394SMagnus Damm  * arch/sh/kernel/cpu/sh4a/clock-sh7366.c
44ed37394SMagnus Damm  *
54ed37394SMagnus Damm  * SH7366 clock framework support
64ed37394SMagnus Damm  *
74ed37394SMagnus Damm  * Copyright (C) 2009 Magnus Damm
84ed37394SMagnus Damm  */
94ed37394SMagnus Damm #include <linux/init.h>
104ed37394SMagnus Damm #include <linux/kernel.h>
114ed37394SMagnus Damm #include <linux/io.h>
126d803ba7SJean-Christop PLAGNIOL-VILLARD #include <linux/clkdev.h>
134ed37394SMagnus Damm #include <asm/clock.h>
144ed37394SMagnus Damm 
154ed37394SMagnus Damm /* SH7366 registers */
164ed37394SMagnus Damm #define FRQCR		0xa4150000
174ed37394SMagnus Damm #define VCLKCR		0xa4150004
184ed37394SMagnus Damm #define SCLKACR		0xa4150008
194ed37394SMagnus Damm #define SCLKBCR		0xa415000c
204ed37394SMagnus Damm #define PLLCR		0xa4150024
214ed37394SMagnus Damm #define MSTPCR0		0xa4150030
224ed37394SMagnus Damm #define MSTPCR1		0xa4150034
234ed37394SMagnus Damm #define MSTPCR2		0xa4150038
244ed37394SMagnus Damm #define DLLFRQ		0xa4150050
254ed37394SMagnus Damm 
264ed37394SMagnus Damm /* Fixed 32 KHz root clock for RTC and Power Management purposes */
274ed37394SMagnus Damm static struct clk r_clk = {
284ed37394SMagnus Damm 	.rate           = 32768,
294ed37394SMagnus Damm };
304ed37394SMagnus Damm 
314ed37394SMagnus Damm /*
324ed37394SMagnus Damm  * Default rate for the root input clock, reset this with clk_set_rate()
334ed37394SMagnus Damm  * from the platform code.
344ed37394SMagnus Damm  */
354ed37394SMagnus Damm struct clk extal_clk = {
364ed37394SMagnus Damm 	.rate		= 33333333,
374ed37394SMagnus Damm };
384ed37394SMagnus Damm 
394ed37394SMagnus Damm /* The dll block multiplies the 32khz r_clk, may be used instead of extal */
dll_recalc(struct clk * clk)404ed37394SMagnus Damm static unsigned long dll_recalc(struct clk *clk)
414ed37394SMagnus Damm {
424ed37394SMagnus Damm 	unsigned long mult;
434ed37394SMagnus Damm 
444ed37394SMagnus Damm 	if (__raw_readl(PLLCR) & 0x1000)
454ed37394SMagnus Damm 		mult = __raw_readl(DLLFRQ);
464ed37394SMagnus Damm 	else
474ed37394SMagnus Damm 		mult = 0;
484ed37394SMagnus Damm 
494ed37394SMagnus Damm 	return clk->parent->rate * mult;
504ed37394SMagnus Damm }
514ed37394SMagnus Damm 
5233cb61a4SMagnus Damm static struct sh_clk_ops dll_clk_ops = {
534ed37394SMagnus Damm 	.recalc		= dll_recalc,
544ed37394SMagnus Damm };
554ed37394SMagnus Damm 
564ed37394SMagnus Damm static struct clk dll_clk = {
574ed37394SMagnus Damm 	.ops		= &dll_clk_ops,
584ed37394SMagnus Damm 	.parent		= &r_clk,
594ed37394SMagnus Damm 	.flags		= CLK_ENABLE_ON_INIT,
604ed37394SMagnus Damm };
614ed37394SMagnus Damm 
pll_recalc(struct clk * clk)624ed37394SMagnus Damm static unsigned long pll_recalc(struct clk *clk)
634ed37394SMagnus Damm {
644ed37394SMagnus Damm 	unsigned long mult = 1;
654ed37394SMagnus Damm 	unsigned long div = 1;
664ed37394SMagnus Damm 
674ed37394SMagnus Damm 	if (__raw_readl(PLLCR) & 0x4000)
684ed37394SMagnus Damm 		mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
694ed37394SMagnus Damm 	else
704ed37394SMagnus Damm 		div = 2;
714ed37394SMagnus Damm 
724ed37394SMagnus Damm 	return (clk->parent->rate * mult) / div;
734ed37394SMagnus Damm }
744ed37394SMagnus Damm 
7533cb61a4SMagnus Damm static struct sh_clk_ops pll_clk_ops = {
764ed37394SMagnus Damm 	.recalc		= pll_recalc,
774ed37394SMagnus Damm };
784ed37394SMagnus Damm 
794ed37394SMagnus Damm static struct clk pll_clk = {
804ed37394SMagnus Damm 	.ops		= &pll_clk_ops,
814ed37394SMagnus Damm 	.flags		= CLK_ENABLE_ON_INIT,
824ed37394SMagnus Damm };
834ed37394SMagnus Damm 
844ed37394SMagnus Damm struct clk *main_clks[] = {
854ed37394SMagnus Damm 	&r_clk,
864ed37394SMagnus Damm 	&extal_clk,
874ed37394SMagnus Damm 	&dll_clk,
884ed37394SMagnus Damm 	&pll_clk,
894ed37394SMagnus Damm };
904ed37394SMagnus Damm 
914ed37394SMagnus Damm static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
924ed37394SMagnus Damm static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
934ed37394SMagnus Damm 
940a5f337eSMagnus Damm static struct clk_div_mult_table div4_div_mult_table = {
954ed37394SMagnus Damm 	.divisors = divisors,
964ed37394SMagnus Damm 	.nr_divisors = ARRAY_SIZE(divisors),
974ed37394SMagnus Damm 	.multipliers = multipliers,
984ed37394SMagnus Damm 	.nr_multipliers = ARRAY_SIZE(multipliers),
994ed37394SMagnus Damm };
1004ed37394SMagnus Damm 
1010a5f337eSMagnus Damm static struct clk_div4_table div4_table = {
1020a5f337eSMagnus Damm 	.div_mult_table = &div4_div_mult_table,
1030a5f337eSMagnus Damm };
1040a5f337eSMagnus Damm 
1054ed37394SMagnus Damm enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
1064ed37394SMagnus Damm        DIV4_SIUA, DIV4_SIUB, DIV4_NR };
1074ed37394SMagnus Damm 
108914ebf0bSMagnus Damm #define DIV4(_reg, _bit, _mask, _flags) \
109914ebf0bSMagnus Damm   SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
1104ed37394SMagnus Damm 
1114ed37394SMagnus Damm struct clk div4_clks[DIV4_NR] = {
112914ebf0bSMagnus Damm 	[DIV4_I] = DIV4(FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
113914ebf0bSMagnus Damm 	[DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
114914ebf0bSMagnus Damm 	[DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
115914ebf0bSMagnus Damm 	[DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
116914ebf0bSMagnus Damm 	[DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
117914ebf0bSMagnus Damm 	[DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0),
118914ebf0bSMagnus Damm 	[DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0),
119914ebf0bSMagnus Damm 	[DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0),
1204ed37394SMagnus Damm };
1214ed37394SMagnus Damm 
122098ec49bSMagnus Damm enum { DIV6_V, DIV6_NR };
123098ec49bSMagnus Damm 
124098ec49bSMagnus Damm struct clk div6_clks[DIV6_NR] = {
1259e1985e1SMagnus Damm 	[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
1264ed37394SMagnus Damm };
1274ed37394SMagnus Damm 
128c77a9c3eSMagnus Damm #define MSTP(_parent, _reg, _bit, _flags) \
129c77a9c3eSMagnus Damm   SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
1304ed37394SMagnus Damm 
1314780683aSMagnus Damm enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
1324780683aSMagnus Damm        MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
1334780683aSMagnus Damm        MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
1344780683aSMagnus Damm        MSTP007, MSTP006, MSTP005, MSTP002, MSTP001,
1354780683aSMagnus Damm        MSTP109, MSTP100,
1364780683aSMagnus Damm        MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217,
1374780683aSMagnus Damm        MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
1384780683aSMagnus Damm        MSTP_NR };
1394780683aSMagnus Damm 
1404780683aSMagnus Damm static struct clk mstp_clks[MSTP_NR] = {
1414ed37394SMagnus Damm 	/* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
142c77a9c3eSMagnus Damm 	[MSTP031] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
143c77a9c3eSMagnus Damm 	[MSTP030] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
144c77a9c3eSMagnus Damm 	[MSTP029] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
145c77a9c3eSMagnus Damm 	[MSTP028] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
146c77a9c3eSMagnus Damm 	[MSTP026] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
147c77a9c3eSMagnus Damm 	[MSTP023] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
148c77a9c3eSMagnus Damm 	[MSTP022] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
149c77a9c3eSMagnus Damm 	[MSTP021] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
150c77a9c3eSMagnus Damm 	[MSTP020] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
151c77a9c3eSMagnus Damm 	[MSTP019] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
152c77a9c3eSMagnus Damm 	[MSTP017] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
153c77a9c3eSMagnus Damm 	[MSTP015] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
154c77a9c3eSMagnus Damm 	[MSTP014] = MSTP(&r_clk, MSTPCR0, 14, 0),
155c77a9c3eSMagnus Damm 	[MSTP013] = MSTP(&r_clk, MSTPCR0, 13, 0),
156c77a9c3eSMagnus Damm 	[MSTP011] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
157c77a9c3eSMagnus Damm 	[MSTP010] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
158c77a9c3eSMagnus Damm 	[MSTP007] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
159c77a9c3eSMagnus Damm 	[MSTP006] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
160c77a9c3eSMagnus Damm 	[MSTP005] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
161c77a9c3eSMagnus Damm 	[MSTP002] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
162c77a9c3eSMagnus Damm 	[MSTP001] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
1634ed37394SMagnus Damm 
164c77a9c3eSMagnus Damm 	[MSTP109] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
1654ed37394SMagnus Damm 
166c77a9c3eSMagnus Damm 	[MSTP227] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 27, 0),
167c77a9c3eSMagnus Damm 	[MSTP226] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 26, 0),
168c77a9c3eSMagnus Damm 	[MSTP224] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
169c77a9c3eSMagnus Damm 	[MSTP223] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 23, 0),
170c77a9c3eSMagnus Damm 	[MSTP222] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 22, 0),
171c77a9c3eSMagnus Damm 	[MSTP218] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
172c77a9c3eSMagnus Damm 	[MSTP217] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 17, 0),
173c77a9c3eSMagnus Damm 	[MSTP211] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
174c77a9c3eSMagnus Damm 	[MSTP207] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT),
175c77a9c3eSMagnus Damm 	[MSTP205] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
176c77a9c3eSMagnus Damm 	[MSTP204] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
177c77a9c3eSMagnus Damm 	[MSTP203] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
178c77a9c3eSMagnus Damm 	[MSTP202] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
179c77a9c3eSMagnus Damm 	[MSTP201] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
180c77a9c3eSMagnus Damm 	[MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
1814ed37394SMagnus Damm };
1824ed37394SMagnus Damm 
183098ec49bSMagnus Damm static struct clk_lookup lookups[] = {
18459aa69d9SMagnus Damm 	/* main clocks */
18559aa69d9SMagnus Damm 	CLKDEV_CON_ID("rclk", &r_clk),
18659aa69d9SMagnus Damm 	CLKDEV_CON_ID("extal", &extal_clk),
18759aa69d9SMagnus Damm 	CLKDEV_CON_ID("dll_clk", &dll_clk),
18859aa69d9SMagnus Damm 	CLKDEV_CON_ID("pll_clk", &pll_clk),
18959aa69d9SMagnus Damm 
19040956e75SMagnus Damm 	/* DIV4 clocks */
19140956e75SMagnus Damm 	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
19240956e75SMagnus Damm 	CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
19340956e75SMagnus Damm 	CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
19440956e75SMagnus Damm 	CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
19540956e75SMagnus Damm 	CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
19640956e75SMagnus Damm 	CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
19740956e75SMagnus Damm 	CLKDEV_CON_ID("siua_clk", &div4_clks[DIV4_SIUA]),
19840956e75SMagnus Damm 	CLKDEV_CON_ID("siub_clk", &div4_clks[DIV4_SIUB]),
19940956e75SMagnus Damm 
200098ec49bSMagnus Damm 	/* DIV6 clocks */
201098ec49bSMagnus Damm 	CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
202b87cecefSMagnus Damm 
203b87cecefSMagnus Damm 	/* MSTP32 clocks */
204b87cecefSMagnus Damm 	CLKDEV_CON_ID("tlb0", &mstp_clks[MSTP031]),
205b87cecefSMagnus Damm 	CLKDEV_CON_ID("ic0", &mstp_clks[MSTP030]),
206b87cecefSMagnus Damm 	CLKDEV_CON_ID("oc0", &mstp_clks[MSTP029]),
207b87cecefSMagnus Damm 	CLKDEV_CON_ID("rsmem0", &mstp_clks[MSTP028]),
208b87cecefSMagnus Damm 	CLKDEV_CON_ID("xymem0", &mstp_clks[MSTP026]),
209b87cecefSMagnus Damm 	CLKDEV_CON_ID("intc3", &mstp_clks[MSTP023]),
210b87cecefSMagnus Damm 	CLKDEV_CON_ID("intc0", &mstp_clks[MSTP022]),
211b87cecefSMagnus Damm 	CLKDEV_CON_ID("dmac0", &mstp_clks[MSTP021]),
212b87cecefSMagnus Damm 	CLKDEV_CON_ID("sh0", &mstp_clks[MSTP020]),
213b87cecefSMagnus Damm 	CLKDEV_CON_ID("hudi0", &mstp_clks[MSTP019]),
214b87cecefSMagnus Damm 	CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP017]),
215b87cecefSMagnus Damm 	CLKDEV_CON_ID("tmu_fck", &mstp_clks[MSTP015]),
2169b17e48cSLaurent Pinchart 	CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[MSTP014]),
217b87cecefSMagnus Damm 	CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
218b87cecefSMagnus Damm 	CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
219b87cecefSMagnus Damm 	CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
220ee0c2effSKuninori Morimoto 
221fa3d39bfSLaurent Pinchart 	CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
222fa3d39bfSLaurent Pinchart 	CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
223fa3d39bfSLaurent Pinchart 	CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
224ee0c2effSKuninori Morimoto 
225b87cecefSMagnus Damm 	CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
226b87cecefSMagnus Damm 	CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
22754f7c116SKuninori Morimoto 	CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
228b87cecefSMagnus Damm 	CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]),
229b87cecefSMagnus Damm 	CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]),
230b87cecefSMagnus Damm 	CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]),
231b87cecefSMagnus Damm 	CLKDEV_CON_ID("dacy0", &mstp_clks[MSTP223]),
232b87cecefSMagnus Damm 	CLKDEV_CON_ID("tsif0", &mstp_clks[MSTP222]),
233b87cecefSMagnus Damm 	CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
234b87cecefSMagnus Damm 	CLKDEV_CON_ID("mmcif0", &mstp_clks[MSTP217]),
235b87cecefSMagnus Damm 	CLKDEV_CON_ID("usbf0", &mstp_clks[MSTP211]),
236b87cecefSMagnus Damm 	CLKDEV_CON_ID("veu1", &mstp_clks[MSTP207]),
237b87cecefSMagnus Damm 	CLKDEV_CON_ID("vou0", &mstp_clks[MSTP205]),
238b87cecefSMagnus Damm 	CLKDEV_CON_ID("beu0", &mstp_clks[MSTP204]),
239b87cecefSMagnus Damm 	CLKDEV_CON_ID("ceu0", &mstp_clks[MSTP203]),
240b87cecefSMagnus Damm 	CLKDEV_CON_ID("veu0", &mstp_clks[MSTP202]),
241b87cecefSMagnus Damm 	CLKDEV_CON_ID("vpu0", &mstp_clks[MSTP201]),
242b87cecefSMagnus Damm 	CLKDEV_CON_ID("lcdc0", &mstp_clks[MSTP200]),
243098ec49bSMagnus Damm };
244098ec49bSMagnus Damm 
arch_clk_init(void)2454ed37394SMagnus Damm int __init arch_clk_init(void)
2464ed37394SMagnus Damm {
2474ed37394SMagnus Damm 	int k, ret = 0;
2484ed37394SMagnus Damm 
2494ed37394SMagnus Damm 	/* autodetect extal or dll configuration */
2504ed37394SMagnus Damm 	if (__raw_readl(PLLCR) & 0x1000)
2514ed37394SMagnus Damm 		pll_clk.parent = &dll_clk;
2524ed37394SMagnus Damm 	else
2534ed37394SMagnus Damm 		pll_clk.parent = &extal_clk;
2544ed37394SMagnus Damm 
2554ed37394SMagnus Damm 	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
2564ed37394SMagnus Damm 		ret = clk_register(main_clks[k]);
2574ed37394SMagnus Damm 
258098ec49bSMagnus Damm 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
259098ec49bSMagnus Damm 
2604ed37394SMagnus Damm 	if (!ret)
2614ed37394SMagnus Damm 		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
2624ed37394SMagnus Damm 
2634ed37394SMagnus Damm 	if (!ret)
264098ec49bSMagnus Damm 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
2654ed37394SMagnus Damm 
2664ed37394SMagnus Damm 	if (!ret)
267ad3337cbSNobuhiro Iwamatsu 		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
2684ed37394SMagnus Damm 
2694ed37394SMagnus Damm 	return ret;
2704ed37394SMagnus Damm }
271