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