k210-sysctl.c (802fee26d8afd073c630a74dbe1a996970f3fd90) | k210-sysctl.c (c6ca7616f7d5c2ce166280107ba74db1d528fcb7) |
---|---|
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 */ | 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> | 6#include <linux/io.h> |
8#include <linux/of.h> | |
9#include <linux/platform_device.h> | 7#include <linux/platform_device.h> |
10#include <linux/clk-provider.h> 11#include <linux/clkdev.h> 12#include <linux/bitfield.h> | 8#include <linux/of_platform.h> 9#include <linux/clk.h> |
13#include <asm/soc.h> 14 15#include <soc/canaan/k210-sysctl.h> 16 | 10#include <asm/soc.h> 11 12#include <soc/canaan/k210-sysctl.h> 13 |
17#define K210_SYSCTL_CLK0_FREQ 26000000UL 18 19/* Registers base address */ 20#define K210_SYSCTL_SYSCTL_BASE_ADDR 0x50440000ULL 21 22/* Register bits */ 23/* K210_SYSCTL_PLL1: clkr: 4bits, clkf1: 6bits, clkod: 4bits, bwadj: 4bits */ 24#define PLL_RESET (1 << 20) 25#define PLL_PWR (1 << 21) 26#define PLL_BYPASS (1 << 23) 27#define PLL_OUT_EN (1 << 25) 28/* K210_SYSCTL_PLL_LOCK */ 29#define PLL1_LOCK1 (1 << 8) 30#define PLL1_LOCK2 (1 << 9) 31#define PLL1_SLIP_CLEAR (1 << 10) 32/* K210_SYSCTL_SEL0 */ 33#define CLKSEL_ACLK (1 << 0) 34/* K210_SYSCTL_CLKEN_CENT */ 35#define CLKEN_CPU (1 << 0) 36#define CLKEN_SRAM0 (1 << 1) 37#define CLKEN_SRAM1 (1 << 2) 38/* K210_SYSCTL_EN_PERI */ 39#define CLKEN_ROM (1 << 0) 40#define CLKEN_TIMER0 (1 << 21) 41#define CLKEN_RTC (1 << 29) 42 43struct k210_sysctl { 44 void __iomem *regs; 45 struct clk_hw hw; 46}; 47 48static void k210_set_bits(u32 val, void __iomem *reg) 49{ 50 writel(readl(reg) | val, reg); 51} 52 53static void k210_clear_bits(u32 val, void __iomem *reg) 54{ 55 writel(readl(reg) & ~val, reg); 56} 57 58static void k210_pll1_enable(void __iomem *regs) 59{ 60 u32 val; 61 62 val = readl(regs + K210_SYSCTL_PLL1); 63 val &= ~GENMASK(19, 0); /* clkr1 = 0 */ 64 val |= FIELD_PREP(GENMASK(9, 4), 0x3B); /* clkf1 = 59 */ 65 val |= FIELD_PREP(GENMASK(13, 10), 0x3); /* clkod1 = 3 */ 66 val |= FIELD_PREP(GENMASK(19, 14), 0x3B); /* bwadj1 = 59 */ 67 writel(val, regs + K210_SYSCTL_PLL1); 68 69 k210_clear_bits(PLL_BYPASS, regs + K210_SYSCTL_PLL1); 70 k210_set_bits(PLL_PWR, regs + K210_SYSCTL_PLL1); 71 72 /* 73 * Reset the pll. The magic NOPs come from the Kendryte reference SDK. 74 */ 75 k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1); 76 k210_set_bits(PLL_RESET, regs + K210_SYSCTL_PLL1); 77 nop(); 78 nop(); 79 k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1); 80 81 for (;;) { 82 val = readl(regs + K210_SYSCTL_PLL_LOCK); 83 if (val & PLL1_LOCK2) 84 break; 85 writel(val | PLL1_SLIP_CLEAR, regs + K210_SYSCTL_PLL_LOCK); 86 } 87 88 k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL1); 89} 90 91static unsigned long k210_sysctl_clk_recalc_rate(struct clk_hw *hw, 92 unsigned long parent_rate) 93{ 94 struct k210_sysctl *s = container_of(hw, struct k210_sysctl, hw); 95 u32 clksel0, pll0; 96 u64 pll0_freq, clkr0, clkf0, clkod0; 97 98 /* 99 * If the clock selector is not set, use the base frequency. 100 * Otherwise, use PLL0 frequency with a frequency divisor. 101 */ 102 clksel0 = readl(s->regs + K210_SYSCTL_SEL0); 103 if (!(clksel0 & CLKSEL_ACLK)) 104 return K210_SYSCTL_CLK0_FREQ; 105 106 /* 107 * Get PLL0 frequency: 108 * freq = base frequency * clkf0 / (clkr0 * clkod0) 109 */ 110 pll0 = readl(s->regs + K210_SYSCTL_PLL0); 111 clkr0 = 1 + FIELD_GET(GENMASK(3, 0), pll0); 112 clkf0 = 1 + FIELD_GET(GENMASK(9, 4), pll0); 113 clkod0 = 1 + FIELD_GET(GENMASK(13, 10), pll0); 114 pll0_freq = clkf0 * K210_SYSCTL_CLK0_FREQ / (clkr0 * clkod0); 115 116 /* Get the frequency divisor from the clock selector */ 117 return pll0_freq / (2ULL << FIELD_GET(0x00000006, clksel0)); 118} 119 120static const struct clk_ops k210_sysctl_clk_ops = { 121 .recalc_rate = k210_sysctl_clk_recalc_rate, 122}; 123 124static const struct clk_init_data k210_clk_init_data = { 125 .name = "k210-sysctl-pll1", 126 .ops = &k210_sysctl_clk_ops, 127}; 128 | |
129static int k210_sysctl_probe(struct platform_device *pdev) 130{ | 14static int k210_sysctl_probe(struct platform_device *pdev) 15{ |
131 struct k210_sysctl *s; 132 int error; | 16 struct device *dev = &pdev->dev; 17 struct clk *pclk; 18 int ret; |
133 | 19 |
134 pr_info("Kendryte K210 SoC sysctl\n"); | 20 dev_info(dev, "K210 system controller\n"); |
135 | 21 |
136 s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); 137 if (!s) 138 return -ENOMEM; | 22 /* Get power bus clock */ 23 pclk = devm_clk_get(dev, NULL); 24 if (IS_ERR(pclk)) 25 return dev_err_probe(dev, PTR_ERR(pclk), 26 "Get bus clock failed\n"); |
139 | 27 |
140 s->regs = devm_ioremap_resource(&pdev->dev, 141 platform_get_resource(pdev, IORESOURCE_MEM, 0)); 142 if (IS_ERR(s->regs)) 143 return PTR_ERR(s->regs); 144 145 s->hw.init = &k210_clk_init_data; 146 error = devm_clk_hw_register(&pdev->dev, &s->hw); 147 if (error) { 148 dev_err(&pdev->dev, "failed to register clk"); 149 return error; | 28 ret = clk_prepare_enable(pclk); 29 if (ret) { 30 dev_err(dev, "Enable bus clock failed\n"); 31 return ret; |
150 } 151 | 32 } 33 |
152 error = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, 153 &s->hw); 154 if (error) { 155 dev_err(&pdev->dev, "adding clk provider failed\n"); 156 return error; 157 } | 34 /* Populate children */ 35 ret = devm_of_platform_populate(dev); 36 if (ret) 37 dev_err(dev, "Populate platform failed %d\n", ret); |
158 | 38 |
159 return 0; | 39 return ret; |
160} 161 162static const struct of_device_id k210_sysctl_of_match[] = { | 40} 41 42static const struct of_device_id k210_sysctl_of_match[] = { |
163 { .compatible = "kendryte,k210-sysctl", }, 164 {} | 43 { .compatible = "canaan,k210-sysctl", }, 44 { /* sentinel */ }, |
165}; 166 167static struct platform_driver k210_sysctl_driver = { 168 .driver = { 169 .name = "k210-sysctl", 170 .of_match_table = k210_sysctl_of_match, 171 }, 172 .probe = k210_sysctl_probe, 173}; | 45}; 46 47static struct platform_driver k210_sysctl_driver = { 48 .driver = { 49 .name = "k210-sysctl", 50 .of_match_table = k210_sysctl_of_match, 51 }, 52 .probe = k210_sysctl_probe, 53}; |
54builtin_platform_driver(k210_sysctl_driver); |
|
174 | 55 |
175static int __init k210_sysctl_init(void) 176{ 177 return platform_driver_register(&k210_sysctl_driver); 178} 179core_initcall(k210_sysctl_init); | 56/* 57 * System controller registers base address and size. 58 */ 59#define K210_SYSCTL_BASE_ADDR 0x50440000ULL 60#define K210_SYSCTL_BASE_SIZE 0x1000 |
180 181/* 182 * This needs to be called very early during initialization, given that 183 * PLL1 needs to be enabled to be able to use all SRAM. 184 */ 185static void __init k210_soc_early_init(const void *fdt) 186{ | 61 62/* 63 * This needs to be called very early during initialization, given that 64 * PLL1 needs to be enabled to be able to use all SRAM. 65 */ 66static void __init k210_soc_early_init(const void *fdt) 67{ |
187 void __iomem *regs; | 68 void __iomem *sysctl_base; |
188 | 69 |
189 regs = ioremap(K210_SYSCTL_SYSCTL_BASE_ADDR, 0x1000); 190 if (!regs) 191 panic("K210 sysctl ioremap"); | 70 sysctl_base = ioremap(K210_SYSCTL_BASE_ADDR, K210_SYSCTL_BASE_SIZE); 71 if (!sysctl_base) 72 panic("k210-sysctl: ioremap failed"); |
192 | 73 |
193 /* Enable PLL1 to make the KPU SRAM useable */ 194 k210_pll1_enable(regs); | 74 k210_clk_early_init(sysctl_base); |
195 | 75 |
196 k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL0); 197 198 k210_set_bits(CLKEN_CPU | CLKEN_SRAM0 | CLKEN_SRAM1, 199 regs + K210_SYSCTL_EN_CENT); 200 k210_set_bits(CLKEN_ROM | CLKEN_TIMER0 | CLKEN_RTC, 201 regs + K210_SYSCTL_EN_PERI); 202 203 k210_set_bits(CLKSEL_ACLK, regs + K210_SYSCTL_SEL0); 204 205 iounmap(regs); | 76 iounmap(sysctl_base); |
206} | 77} |
207SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init); | 78SOC_EARLY_INIT_DECLARE(k210_soc, "canaan,kendryte-k210", k210_soc_early_init); |