1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2019 Christoph Hellwig.
4 * Copyright (c) 2019 Western Digital Corporation or its affiliates.
5 */
6#include <linux/types.h>
7#include <linux/io.h>
8#include <linux/of.h>
9#include <linux/platform_device.h>
10#include <linux/clk-provider.h>
11#include <linux/clkdev.h>
12#include <linux/bitfield.h>
13#include <asm/soc.h>
14
15#define K210_SYSCTL_CLK0_FREQ		26000000UL
16
17/* Registers base address */
18#define K210_SYSCTL_SYSCTL_BASE_ADDR	0x50440000ULL
19
20/* Registers */
21#define K210_SYSCTL_PLL0		0x08
22#define K210_SYSCTL_PLL1		0x0c
23/* clkr: 4bits, clkf1: 6bits, clkod: 4bits, bwadj: 4bits */
24#define   PLL_RESET		(1 << 20)
25#define   PLL_PWR		(1 << 21)
26#define   PLL_INTFB		(1 << 22)
27#define   PLL_BYPASS		(1 << 23)
28#define   PLL_TEST		(1 << 24)
29#define   PLL_OUT_EN		(1 << 25)
30#define   PLL_TEST_EN		(1 << 26)
31#define K210_SYSCTL_PLL_LOCK		0x18
32#define   PLL0_LOCK1		(1 << 0)
33#define   PLL0_LOCK2		(1 << 1)
34#define   PLL0_SLIP_CLEAR	(1 << 2)
35#define   PLL0_TEST_CLK_OUT	(1 << 3)
36#define   PLL1_LOCK1		(1 << 8)
37#define   PLL1_LOCK2		(1 << 9)
38#define   PLL1_SLIP_CLEAR	(1 << 10)
39#define   PLL1_TEST_CLK_OUT	(1 << 11)
40#define   PLL2_LOCK1		(1 << 16)
41#define   PLL2_LOCK2		(1 << 16)
42#define   PLL2_SLIP_CLEAR	(1 << 18)
43#define   PLL2_TEST_CLK_OUT	(1 << 19)
44#define K210_SYSCTL_CLKSEL0	0x20
45#define   CLKSEL_ACLK		(1 << 0)
46#define K210_SYSCTL_CLKEN_CENT		0x28
47#define   CLKEN_CPU		(1 << 0)
48#define   CLKEN_SRAM0		(1 << 1)
49#define   CLKEN_SRAM1		(1 << 2)
50#define   CLKEN_APB0		(1 << 3)
51#define   CLKEN_APB1		(1 << 4)
52#define   CLKEN_APB2		(1 << 5)
53#define K210_SYSCTL_CLKEN_PERI		0x2c
54#define   CLKEN_ROM		(1 << 0)
55#define   CLKEN_DMA		(1 << 1)
56#define   CLKEN_AI		(1 << 2)
57#define   CLKEN_DVP		(1 << 3)
58#define   CLKEN_FFT		(1 << 4)
59#define   CLKEN_GPIO		(1 << 5)
60#define   CLKEN_SPI0		(1 << 6)
61#define   CLKEN_SPI1		(1 << 7)
62#define   CLKEN_SPI2		(1 << 8)
63#define   CLKEN_SPI3		(1 << 9)
64#define   CLKEN_I2S0		(1 << 10)
65#define   CLKEN_I2S1		(1 << 11)
66#define   CLKEN_I2S2		(1 << 12)
67#define   CLKEN_I2C0		(1 << 13)
68#define   CLKEN_I2C1		(1 << 14)
69#define   CLKEN_I2C2		(1 << 15)
70#define   CLKEN_UART1		(1 << 16)
71#define   CLKEN_UART2		(1 << 17)
72#define   CLKEN_UART3		(1 << 18)
73#define   CLKEN_AES		(1 << 19)
74#define   CLKEN_FPIO		(1 << 20)
75#define   CLKEN_TIMER0		(1 << 21)
76#define   CLKEN_TIMER1		(1 << 22)
77#define   CLKEN_TIMER2		(1 << 23)
78#define   CLKEN_WDT0		(1 << 24)
79#define   CLKEN_WDT1		(1 << 25)
80#define   CLKEN_SHA		(1 << 26)
81#define   CLKEN_OTP		(1 << 27)
82#define   CLKEN_RTC		(1 << 29)
83
84struct k210_sysctl {
85	void __iomem		*regs;
86	struct clk_hw		hw;
87};
88
89static void k210_set_bits(u32 val, void __iomem *reg)
90{
91	writel(readl(reg) | val, reg);
92}
93
94static void k210_clear_bits(u32 val, void __iomem *reg)
95{
96	writel(readl(reg) & ~val, reg);
97}
98
99static void k210_pll1_enable(void __iomem *regs)
100{
101	u32 val;
102
103	val = readl(regs + K210_SYSCTL_PLL1);
104	val &= ~GENMASK(19, 0);				/* clkr1 = 0 */
105	val |= FIELD_PREP(GENMASK(9, 4), 0x3B);		/* clkf1 = 59 */
106	val |= FIELD_PREP(GENMASK(13, 10), 0x3);	/* clkod1 = 3 */
107	val |= FIELD_PREP(GENMASK(19, 14), 0x3B);	/* bwadj1 = 59 */
108	writel(val, regs + K210_SYSCTL_PLL1);
109
110	k210_clear_bits(PLL_BYPASS, regs + K210_SYSCTL_PLL1);
111	k210_set_bits(PLL_PWR, regs + K210_SYSCTL_PLL1);
112
113	/*
114	 * Reset the pll. The magic NOPs come from the Kendryte reference SDK.
115	 */
116	k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
117	k210_set_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
118	nop();
119	nop();
120	k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
121
122	for (;;) {
123		val = readl(regs + K210_SYSCTL_PLL_LOCK);
124		if (val & PLL1_LOCK2)
125			break;
126		writel(val | PLL1_SLIP_CLEAR, regs + K210_SYSCTL_PLL_LOCK);
127	}
128
129	k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL1);
130}
131
132static unsigned long k210_sysctl_clk_recalc_rate(struct clk_hw *hw,
133		unsigned long parent_rate)
134{
135	struct k210_sysctl *s = container_of(hw, struct k210_sysctl, hw);
136	u32 clksel0, pll0;
137	u64 pll0_freq, clkr0, clkf0, clkod0;
138
139	/*
140	 * If the clock selector is not set, use the base frequency.
141	 * Otherwise, use PLL0 frequency with a frequency divisor.
142	 */
143	clksel0 = readl(s->regs + K210_SYSCTL_CLKSEL0);
144	if (!(clksel0 & CLKSEL_ACLK))
145		return K210_SYSCTL_CLK0_FREQ;
146
147	/*
148	 * Get PLL0 frequency:
149	 * freq = base frequency * clkf0 / (clkr0 * clkod0)
150	 */
151	pll0 = readl(s->regs + K210_SYSCTL_PLL0);
152	clkr0 = 1 + FIELD_GET(GENMASK(3, 0), pll0);
153	clkf0 = 1 + FIELD_GET(GENMASK(9, 4), pll0);
154	clkod0 = 1 + FIELD_GET(GENMASK(13, 10), pll0);
155	pll0_freq = clkf0 * K210_SYSCTL_CLK0_FREQ / (clkr0 * clkod0);
156
157	/* Get the frequency divisor from the clock selector */
158	return pll0_freq / (2ULL << FIELD_GET(0x00000006, clksel0));
159}
160
161static const struct clk_ops k210_sysctl_clk_ops = {
162	.recalc_rate	= k210_sysctl_clk_recalc_rate,
163};
164
165static const struct clk_init_data k210_clk_init_data = {
166	.name		= "k210-sysctl-pll1",
167	.ops		= &k210_sysctl_clk_ops,
168};
169
170static int k210_sysctl_probe(struct platform_device *pdev)
171{
172	struct k210_sysctl *s;
173	int error;
174
175	pr_info("Kendryte K210 SoC sysctl\n");
176
177	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
178	if (!s)
179		return -ENOMEM;
180
181	s->regs = devm_ioremap_resource(&pdev->dev,
182			platform_get_resource(pdev, IORESOURCE_MEM, 0));
183	if (IS_ERR(s->regs))
184		return PTR_ERR(s->regs);
185
186	s->hw.init = &k210_clk_init_data;
187	error = devm_clk_hw_register(&pdev->dev, &s->hw);
188	if (error) {
189		dev_err(&pdev->dev, "failed to register clk");
190		return error;
191	}
192
193	error = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
194					    &s->hw);
195	if (error) {
196		dev_err(&pdev->dev, "adding clk provider failed\n");
197		return error;
198	}
199
200	return 0;
201}
202
203static const struct of_device_id k210_sysctl_of_match[] = {
204	{ .compatible = "kendryte,k210-sysctl", },
205	{}
206};
207
208static struct platform_driver k210_sysctl_driver = {
209	.driver	= {
210		.name		= "k210-sysctl",
211		.of_match_table	= k210_sysctl_of_match,
212	},
213	.probe			= k210_sysctl_probe,
214};
215
216static int __init k210_sysctl_init(void)
217{
218	return platform_driver_register(&k210_sysctl_driver);
219}
220core_initcall(k210_sysctl_init);
221
222/*
223 * This needs to be called very early during initialization, given that
224 * PLL1 needs to be enabled to be able to use all SRAM.
225 */
226static void __init k210_soc_early_init(const void *fdt)
227{
228	void __iomem *regs;
229
230	regs = ioremap(K210_SYSCTL_SYSCTL_BASE_ADDR, 0x1000);
231	if (!regs)
232		panic("K210 sysctl ioremap");
233
234	/* Enable PLL1 to make the KPU SRAM useable */
235	k210_pll1_enable(regs);
236
237	k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL0);
238
239	k210_set_bits(CLKEN_CPU | CLKEN_SRAM0 | CLKEN_SRAM1,
240		      regs + K210_SYSCTL_CLKEN_CENT);
241	k210_set_bits(CLKEN_ROM | CLKEN_TIMER0 | CLKEN_RTC,
242		      regs + K210_SYSCTL_CLKEN_PERI);
243
244	k210_set_bits(CLKSEL_ACLK, regs + K210_SYSCTL_CLKSEL0);
245
246	iounmap(regs);
247}
248SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
249
250#ifdef CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN
251/*
252 * Generic entry for the default k210.dtb embedded DTB for boards with:
253 *   - Vendor ID: 0x4B5
254 *   - Arch ID: 0xE59889E6A5A04149 (= "Canaan AI" in UTF-8 encoded Chinese)
255 *   - Impl ID:	0x4D41495832303030 (= "MAIX2000")
256 * These values are reported by the SiPEED MAXDUINO, SiPEED MAIX GO and
257 * SiPEED Dan dock boards.
258 */
259SOC_BUILTIN_DTB_DECLARE(k210, 0x4B5, 0xE59889E6A5A04149, 0x4D41495832303030);
260#endif
261