Gabriel Fernandez | 9bee94e | 2018-03-08 17:53:55 +0100 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Copyright (C) STMicroelectronics 2018 - All Rights Reserved |
| 4 | * Author: Olivier Bideau <olivier.bideau@st.com> for STMicroelectronics. |
| 5 | * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics. |
| 6 | */ |
| 7 | |
| 8 | #include <linux/clk.h> |
| 9 | #include <linux/clk-provider.h> |
| 10 | #include <linux/err.h> |
| 11 | #include <linux/io.h> |
| 12 | #include <linux/of.h> |
| 13 | #include <linux/of_address.h> |
| 14 | #include <linux/slab.h> |
| 15 | #include <linux/spinlock.h> |
| 16 | |
| 17 | #include <dt-bindings/clock/stm32mp1-clks.h> |
| 18 | |
| 19 | static DEFINE_SPINLOCK(rlock); |
| 20 | |
| 21 | #define RCC_OCENSETR 0x0C |
| 22 | #define RCC_HSICFGR 0x18 |
| 23 | #define RCC_RDLSICR 0x144 |
| 24 | #define RCC_PLL1CR 0x80 |
| 25 | #define RCC_PLL1CFGR1 0x84 |
| 26 | #define RCC_PLL1CFGR2 0x88 |
| 27 | #define RCC_PLL2CR 0x94 |
| 28 | #define RCC_PLL2CFGR1 0x98 |
| 29 | #define RCC_PLL2CFGR2 0x9C |
| 30 | #define RCC_PLL3CR 0x880 |
| 31 | #define RCC_PLL3CFGR1 0x884 |
| 32 | #define RCC_PLL3CFGR2 0x888 |
| 33 | #define RCC_PLL4CR 0x894 |
| 34 | #define RCC_PLL4CFGR1 0x898 |
| 35 | #define RCC_PLL4CFGR2 0x89C |
| 36 | #define RCC_APB1ENSETR 0xA00 |
| 37 | #define RCC_APB2ENSETR 0xA08 |
| 38 | #define RCC_APB3ENSETR 0xA10 |
| 39 | #define RCC_APB4ENSETR 0x200 |
| 40 | #define RCC_APB5ENSETR 0x208 |
| 41 | #define RCC_AHB2ENSETR 0xA18 |
| 42 | #define RCC_AHB3ENSETR 0xA20 |
| 43 | #define RCC_AHB4ENSETR 0xA28 |
| 44 | #define RCC_AHB5ENSETR 0x210 |
| 45 | #define RCC_AHB6ENSETR 0x218 |
| 46 | #define RCC_AHB6LPENSETR 0x318 |
| 47 | #define RCC_RCK12SELR 0x28 |
| 48 | #define RCC_RCK3SELR 0x820 |
| 49 | #define RCC_RCK4SELR 0x824 |
| 50 | #define RCC_MPCKSELR 0x20 |
| 51 | #define RCC_ASSCKSELR 0x24 |
| 52 | #define RCC_MSSCKSELR 0x48 |
| 53 | #define RCC_SPI6CKSELR 0xC4 |
| 54 | #define RCC_SDMMC12CKSELR 0x8F4 |
| 55 | #define RCC_SDMMC3CKSELR 0x8F8 |
| 56 | #define RCC_FMCCKSELR 0x904 |
| 57 | #define RCC_I2C46CKSELR 0xC0 |
| 58 | #define RCC_I2C12CKSELR 0x8C0 |
| 59 | #define RCC_I2C35CKSELR 0x8C4 |
| 60 | #define RCC_UART1CKSELR 0xC8 |
| 61 | #define RCC_QSPICKSELR 0x900 |
| 62 | #define RCC_ETHCKSELR 0x8FC |
| 63 | #define RCC_RNG1CKSELR 0xCC |
| 64 | #define RCC_RNG2CKSELR 0x920 |
| 65 | #define RCC_GPUCKSELR 0x938 |
| 66 | #define RCC_USBCKSELR 0x91C |
| 67 | #define RCC_STGENCKSELR 0xD4 |
| 68 | #define RCC_SPDIFCKSELR 0x914 |
| 69 | #define RCC_SPI2S1CKSELR 0x8D8 |
| 70 | #define RCC_SPI2S23CKSELR 0x8DC |
| 71 | #define RCC_SPI2S45CKSELR 0x8E0 |
| 72 | #define RCC_CECCKSELR 0x918 |
| 73 | #define RCC_LPTIM1CKSELR 0x934 |
| 74 | #define RCC_LPTIM23CKSELR 0x930 |
| 75 | #define RCC_LPTIM45CKSELR 0x92C |
| 76 | #define RCC_UART24CKSELR 0x8E8 |
| 77 | #define RCC_UART35CKSELR 0x8EC |
| 78 | #define RCC_UART6CKSELR 0x8E4 |
| 79 | #define RCC_UART78CKSELR 0x8F0 |
| 80 | #define RCC_FDCANCKSELR 0x90C |
| 81 | #define RCC_SAI1CKSELR 0x8C8 |
| 82 | #define RCC_SAI2CKSELR 0x8CC |
| 83 | #define RCC_SAI3CKSELR 0x8D0 |
| 84 | #define RCC_SAI4CKSELR 0x8D4 |
| 85 | #define RCC_ADCCKSELR 0x928 |
| 86 | #define RCC_MPCKDIVR 0x2C |
| 87 | #define RCC_DSICKSELR 0x924 |
| 88 | #define RCC_CPERCKSELR 0xD0 |
| 89 | #define RCC_MCO1CFGR 0x800 |
| 90 | #define RCC_MCO2CFGR 0x804 |
| 91 | #define RCC_BDCR 0x140 |
| 92 | #define RCC_AXIDIVR 0x30 |
| 93 | #define RCC_MCUDIVR 0x830 |
| 94 | #define RCC_APB1DIVR 0x834 |
| 95 | #define RCC_APB2DIVR 0x838 |
| 96 | #define RCC_APB3DIVR 0x83C |
| 97 | #define RCC_APB4DIVR 0x3C |
| 98 | #define RCC_APB5DIVR 0x40 |
| 99 | #define RCC_TIMG1PRER 0x828 |
| 100 | #define RCC_TIMG2PRER 0x82C |
| 101 | #define RCC_RTCDIVR 0x44 |
| 102 | #define RCC_DBGCFGR 0x80C |
| 103 | |
| 104 | #define RCC_CLR 0x4 |
| 105 | |
| 106 | struct clock_config { |
| 107 | u32 id; |
| 108 | const char *name; |
| 109 | union { |
| 110 | const char *parent_name; |
| 111 | const char * const *parent_names; |
| 112 | }; |
| 113 | int num_parents; |
| 114 | unsigned long flags; |
| 115 | void *cfg; |
| 116 | struct clk_hw * (*func)(struct device *dev, |
| 117 | struct clk_hw_onecell_data *clk_data, |
| 118 | void __iomem *base, spinlock_t *lock, |
| 119 | const struct clock_config *cfg); |
| 120 | }; |
| 121 | |
| 122 | #define NO_ID ~0 |
| 123 | |
| 124 | struct gate_cfg { |
| 125 | u32 reg_off; |
| 126 | u8 bit_idx; |
| 127 | u8 gate_flags; |
| 128 | }; |
| 129 | |
| 130 | struct fixed_factor_cfg { |
| 131 | unsigned int mult; |
| 132 | unsigned int div; |
| 133 | }; |
| 134 | |
| 135 | struct div_cfg { |
| 136 | u32 reg_off; |
| 137 | u8 shift; |
| 138 | u8 width; |
| 139 | u8 div_flags; |
| 140 | const struct clk_div_table *table; |
| 141 | }; |
| 142 | |
| 143 | static struct clk_hw * |
| 144 | _clk_hw_register_gate(struct device *dev, |
| 145 | struct clk_hw_onecell_data *clk_data, |
| 146 | void __iomem *base, spinlock_t *lock, |
| 147 | const struct clock_config *cfg) |
| 148 | { |
| 149 | struct gate_cfg *gate_cfg = cfg->cfg; |
| 150 | |
| 151 | return clk_hw_register_gate(dev, |
| 152 | cfg->name, |
| 153 | cfg->parent_name, |
| 154 | cfg->flags, |
| 155 | gate_cfg->reg_off + base, |
| 156 | gate_cfg->bit_idx, |
| 157 | gate_cfg->gate_flags, |
| 158 | lock); |
| 159 | } |
| 160 | |
| 161 | static struct clk_hw * |
| 162 | _clk_hw_register_fixed_factor(struct device *dev, |
| 163 | struct clk_hw_onecell_data *clk_data, |
| 164 | void __iomem *base, spinlock_t *lock, |
| 165 | const struct clock_config *cfg) |
| 166 | { |
| 167 | struct fixed_factor_cfg *ff_cfg = cfg->cfg; |
| 168 | |
| 169 | return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name, |
| 170 | cfg->flags, ff_cfg->mult, |
| 171 | ff_cfg->div); |
| 172 | } |
| 173 | |
| 174 | static struct clk_hw * |
| 175 | _clk_hw_register_divider_table(struct device *dev, |
| 176 | struct clk_hw_onecell_data *clk_data, |
| 177 | void __iomem *base, spinlock_t *lock, |
| 178 | const struct clock_config *cfg) |
| 179 | { |
| 180 | struct div_cfg *div_cfg = cfg->cfg; |
| 181 | |
| 182 | return clk_hw_register_divider_table(dev, |
| 183 | cfg->name, |
| 184 | cfg->parent_name, |
| 185 | cfg->flags, |
| 186 | div_cfg->reg_off + base, |
| 187 | div_cfg->shift, |
| 188 | div_cfg->width, |
| 189 | div_cfg->div_flags, |
| 190 | div_cfg->table, |
| 191 | lock); |
| 192 | } |
| 193 | |
| 194 | #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ |
| 195 | {\ |
| 196 | .id = _id,\ |
| 197 | .name = _name,\ |
| 198 | .parent_name = _parent,\ |
| 199 | .flags = _flags,\ |
| 200 | .cfg = &(struct gate_cfg) {\ |
| 201 | .reg_off = _offset,\ |
| 202 | .bit_idx = _bit_idx,\ |
| 203 | .gate_flags = _gate_flags,\ |
| 204 | },\ |
| 205 | .func = _clk_hw_register_gate,\ |
| 206 | } |
| 207 | |
| 208 | #define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\ |
| 209 | {\ |
| 210 | .id = _id,\ |
| 211 | .name = _name,\ |
| 212 | .parent_name = _parent,\ |
| 213 | .flags = _flags,\ |
| 214 | .cfg = &(struct fixed_factor_cfg) {\ |
| 215 | .mult = _mult,\ |
| 216 | .div = _div,\ |
| 217 | },\ |
| 218 | .func = _clk_hw_register_fixed_factor,\ |
| 219 | } |
| 220 | |
| 221 | #define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ |
| 222 | _div_flags, _div_table)\ |
| 223 | {\ |
| 224 | .id = _id,\ |
| 225 | .name = _name,\ |
| 226 | .parent_name = _parent,\ |
| 227 | .flags = _flags,\ |
| 228 | .cfg = &(struct div_cfg) {\ |
| 229 | .reg_off = _offset,\ |
| 230 | .shift = _shift,\ |
| 231 | .width = _width,\ |
| 232 | .div_flags = _div_flags,\ |
| 233 | .table = _div_table,\ |
| 234 | },\ |
| 235 | .func = _clk_hw_register_divider_table,\ |
| 236 | } |
| 237 | |
| 238 | #define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\ |
| 239 | DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ |
| 240 | _div_flags, NULL) |
| 241 | |
| 242 | static const struct clock_config stm32mp1_clock_cfg[] = { |
| 243 | /* Oscillator divider */ |
| 244 | DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, |
| 245 | CLK_DIVIDER_READ_ONLY), |
| 246 | |
| 247 | /* External / Internal Oscillators */ |
| 248 | GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), |
| 249 | GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), |
| 250 | |
| 251 | FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), |
| 252 | }; |
| 253 | |
| 254 | struct stm32_clock_match_data { |
| 255 | const struct clock_config *cfg; |
| 256 | unsigned int num; |
| 257 | unsigned int maxbinding; |
| 258 | }; |
| 259 | |
| 260 | static struct stm32_clock_match_data stm32mp1_data = { |
| 261 | .cfg = stm32mp1_clock_cfg, |
| 262 | .num = ARRAY_SIZE(stm32mp1_clock_cfg), |
| 263 | .maxbinding = STM32MP1_LAST_CLK, |
| 264 | }; |
| 265 | |
| 266 | static const struct of_device_id stm32mp1_match_data[] = { |
| 267 | { |
| 268 | .compatible = "st,stm32mp1-rcc", |
| 269 | .data = &stm32mp1_data, |
| 270 | }, |
| 271 | { } |
| 272 | }; |
| 273 | |
| 274 | static int stm32_register_hw_clk(struct device *dev, |
| 275 | struct clk_hw_onecell_data *clk_data, |
| 276 | void __iomem *base, spinlock_t *lock, |
| 277 | const struct clock_config *cfg) |
| 278 | { |
| 279 | static struct clk_hw **hws; |
| 280 | struct clk_hw *hw = ERR_PTR(-ENOENT); |
| 281 | |
| 282 | hws = clk_data->hws; |
| 283 | |
| 284 | if (cfg->func) |
| 285 | hw = (*cfg->func)(dev, clk_data, base, lock, cfg); |
| 286 | |
| 287 | if (IS_ERR(hw)) { |
| 288 | pr_err("Unable to register %s\n", cfg->name); |
| 289 | return PTR_ERR(hw); |
| 290 | } |
| 291 | |
| 292 | if (cfg->id != NO_ID) |
| 293 | hws[cfg->id] = hw; |
| 294 | |
| 295 | return 0; |
| 296 | } |
| 297 | |
| 298 | static int stm32_rcc_init(struct device_node *np, |
| 299 | void __iomem *base, |
| 300 | const struct of_device_id *match_data) |
| 301 | { |
| 302 | struct clk_hw_onecell_data *clk_data; |
| 303 | struct clk_hw **hws; |
| 304 | const struct of_device_id *match; |
| 305 | const struct stm32_clock_match_data *data; |
| 306 | int err, n, max_binding; |
| 307 | |
| 308 | match = of_match_node(match_data, np); |
| 309 | if (!match) { |
| 310 | pr_err("%s: match data not found\n", __func__); |
| 311 | return -ENODEV; |
| 312 | } |
| 313 | |
| 314 | data = match->data; |
| 315 | |
| 316 | max_binding = data->maxbinding; |
| 317 | |
| 318 | clk_data = kzalloc(sizeof(*clk_data) + |
| 319 | sizeof(*clk_data->hws) * max_binding, |
| 320 | GFP_KERNEL); |
| 321 | if (!clk_data) |
| 322 | return -ENOMEM; |
| 323 | |
| 324 | clk_data->num = max_binding; |
| 325 | |
| 326 | hws = clk_data->hws; |
| 327 | |
| 328 | for (n = 0; n < max_binding; n++) |
| 329 | hws[n] = ERR_PTR(-ENOENT); |
| 330 | |
| 331 | for (n = 0; n < data->num; n++) { |
| 332 | err = stm32_register_hw_clk(NULL, clk_data, base, &rlock, |
| 333 | &data->cfg[n]); |
| 334 | if (err) { |
| 335 | pr_err("%s: can't register %s\n", __func__, |
| 336 | data->cfg[n].name); |
| 337 | |
| 338 | kfree(clk_data); |
| 339 | |
| 340 | return err; |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); |
| 345 | } |
| 346 | |
| 347 | static void stm32mp1_rcc_init(struct device_node *np) |
| 348 | { |
| 349 | void __iomem *base; |
| 350 | |
| 351 | base = of_iomap(np, 0); |
| 352 | if (!base) { |
| 353 | pr_err("%s: unable to map resource", np->name); |
| 354 | of_node_put(np); |
| 355 | return; |
| 356 | } |
| 357 | |
| 358 | if (stm32_rcc_init(np, base, stm32mp1_match_data)) { |
| 359 | iounmap(base); |
| 360 | of_node_put(np); |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); |