1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Nuvoton NPCM8xx Clock Generator 4 * All the clocks are initialized by the bootloader, so this driver allows only 5 * reading of current settings directly from the hardware. 6 * 7 * Copyright (C) 2020 Nuvoton Technologies 8 * Author: Tomer Maimon <tomer.maimon@nuvoton.com> 9 */ 10 11 #define pr_fmt(fmt) "npcm8xx_clk: " fmt 12 13 #include <linux/auxiliary_bus.h> 14 #include <linux/bitfield.h> 15 #include <linux/clk-provider.h> 16 #include <linux/err.h> 17 #include <linux/io.h> 18 #include <linux/kernel.h> 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 #include <linux/slab.h> 22 23 #include <dt-bindings/clock/nuvoton,npcm845-clk.h> 24 #include <soc/nuvoton/clock-npcm8xx.h> 25 26 /* npcm8xx clock registers*/ 27 #define NPCM8XX_CLKSEL 0x04 28 #define NPCM8XX_CLKDIV1 0x08 29 #define NPCM8XX_CLKDIV2 0x2C 30 #define NPCM8XX_CLKDIV3 0x58 31 #define NPCM8XX_CLKDIV4 0x7C 32 #define NPCM8XX_PLLCON0 0x0C 33 #define NPCM8XX_PLLCON1 0x10 34 #define NPCM8XX_PLLCON2 0x54 35 #define NPCM8XX_PLLCONG 0x60 36 #define NPCM8XX_THRTL_CNT 0xC0 37 38 #define PLLCON_LOKI BIT(31) 39 #define PLLCON_LOKS BIT(30) 40 #define PLLCON_FBDV GENMASK(27, 16) 41 #define PLLCON_OTDV2 GENMASK(15, 13) 42 #define PLLCON_PWDEN BIT(12) 43 #define PLLCON_OTDV1 GENMASK(10, 8) 44 #define PLLCON_INDV GENMASK(5, 0) 45 46 static void __iomem *clk_base; 47 48 struct npcm8xx_clk_pll { 49 void __iomem *pllcon; 50 unsigned int id; 51 const char *name; 52 unsigned long flags; 53 struct clk_hw hw; 54 }; 55 56 #define to_npcm8xx_clk_pll(_hw) container_of(_hw, struct npcm8xx_clk_pll, hw) 57 58 struct npcm8xx_clk_pll_data { 59 const char *name; 60 struct clk_parent_data parent; 61 unsigned int reg; 62 unsigned long flags; 63 struct clk_hw hw; 64 }; 65 66 struct npcm8xx_clk_div_data { 67 u32 reg; 68 u8 shift; 69 u8 width; 70 const char *name; 71 const struct clk_hw *parent_hw; 72 unsigned long clk_divider_flags; 73 unsigned long flags; 74 int onecell_idx; 75 struct clk_hw hw; 76 }; 77 78 struct npcm8xx_clk_mux_data { 79 u8 shift; 80 u32 mask; 81 const u32 *table; 82 const char *name; 83 const struct clk_parent_data *parent_data; 84 u8 num_parents; 85 unsigned long flags; 86 struct clk_hw hw; 87 }; 88 89 static struct clk_hw hw_pll1_div2, hw_pll2_div2, hw_gfx_div2, hw_pre_clk; 90 static struct npcm8xx_clk_pll_data npcm8xx_pll_clks[] = { 91 { "pll0", { .index = 0 }, NPCM8XX_PLLCON0, 0 }, 92 { "pll1", { .index = 0 }, NPCM8XX_PLLCON1, 0 }, 93 { "pll2", { .index = 0 }, NPCM8XX_PLLCON2, 0 }, 94 { "pll_gfx", { .index = 0 }, NPCM8XX_PLLCONG, 0 }, 95 }; 96 97 static const u32 cpuck_mux_table[] = { 0, 1, 2, 7 }; 98 static const struct clk_parent_data cpuck_mux_parents[] = { 99 { .hw = &npcm8xx_pll_clks[0].hw }, 100 { .hw = &npcm8xx_pll_clks[1].hw }, 101 { .index = 0 }, 102 { .hw = &npcm8xx_pll_clks[2].hw } 103 }; 104 105 static const u32 pixcksel_mux_table[] = { 0, 2 }; 106 static const struct clk_parent_data pixcksel_mux_parents[] = { 107 { .hw = &npcm8xx_pll_clks[3].hw }, 108 { .index = 0 } 109 }; 110 111 static const u32 default_mux_table[] = { 0, 1, 2, 3 }; 112 static const struct clk_parent_data default_mux_parents[] = { 113 { .hw = &npcm8xx_pll_clks[0].hw }, 114 { .hw = &npcm8xx_pll_clks[1].hw }, 115 { .index = 0 }, 116 { .hw = &hw_pll2_div2 } 117 }; 118 119 static const u32 sucksel_mux_table[] = { 2, 3 }; 120 static const struct clk_parent_data sucksel_mux_parents[] = { 121 { .index = 0 }, 122 { .hw = &hw_pll2_div2 } 123 }; 124 125 static const u32 mccksel_mux_table[] = { 0, 2 }; 126 static const struct clk_parent_data mccksel_mux_parents[] = { 127 { .hw = &hw_pll1_div2 }, 128 { .index = 0 } 129 }; 130 131 static const u32 clkoutsel_mux_table[] = { 0, 1, 2, 3, 4 }; 132 static const struct clk_parent_data clkoutsel_mux_parents[] = { 133 { .hw = &npcm8xx_pll_clks[0].hw }, 134 { .hw = &npcm8xx_pll_clks[1].hw }, 135 { .index = 0 }, 136 { .hw = &hw_gfx_div2 }, 137 { .hw = &hw_pll2_div2 } 138 }; 139 140 static const u32 gfxmsel_mux_table[] = { 2, 3 }; 141 static const struct clk_parent_data gfxmsel_mux_parents[] = { 142 { .index = 0 }, 143 { .hw = &npcm8xx_pll_clks[2].hw } 144 }; 145 146 static const u32 dvcssel_mux_table[] = { 2, 3 }; 147 static const struct clk_parent_data dvcssel_mux_parents[] = { 148 { .index = 0 }, 149 { .hw = &npcm8xx_pll_clks[2].hw } 150 }; 151 152 static const u32 default3_mux_table[] = { 0, 1, 2 }; 153 static const struct clk_parent_data default3_mux_parents[] = { 154 { .hw = &npcm8xx_pll_clks[0].hw }, 155 { .hw = &npcm8xx_pll_clks[1].hw }, 156 { .index = 0 } 157 }; 158 159 static struct npcm8xx_clk_mux_data npcm8xx_muxes[] = { 160 { 0, 3, cpuck_mux_table, "cpu_mux", cpuck_mux_parents, 161 ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL }, 162 { 4, 2, pixcksel_mux_table, "gfx_pixel_mux", pixcksel_mux_parents, 163 ARRAY_SIZE(pixcksel_mux_parents), 0 }, 164 { 6, 2, default_mux_table, "sd_mux", default_mux_parents, 165 ARRAY_SIZE(default_mux_parents), 0 }, 166 { 8, 2, default_mux_table, "uart_mux", default_mux_parents, 167 ARRAY_SIZE(default_mux_parents), 0 }, 168 { 10, 2, sucksel_mux_table, "serial_usb_mux", sucksel_mux_parents, 169 ARRAY_SIZE(sucksel_mux_parents), 0 }, 170 { 12, 2, mccksel_mux_table, "mc_mux", mccksel_mux_parents, 171 ARRAY_SIZE(mccksel_mux_parents), 0 }, 172 { 14, 2, default_mux_table, "adc_mux", default_mux_parents, 173 ARRAY_SIZE(default_mux_parents), 0 }, 174 { 16, 2, default_mux_table, "gfx_mux", default_mux_parents, 175 ARRAY_SIZE(default_mux_parents), 0 }, 176 { 18, 3, clkoutsel_mux_table, "clkout_mux", clkoutsel_mux_parents, 177 ARRAY_SIZE(clkoutsel_mux_parents), 0 }, 178 { 21, 2, gfxmsel_mux_table, "gfxm_mux", gfxmsel_mux_parents, 179 ARRAY_SIZE(gfxmsel_mux_parents), 0 }, 180 { 23, 2, dvcssel_mux_table, "dvc_mux", dvcssel_mux_parents, 181 ARRAY_SIZE(dvcssel_mux_parents), 0 }, 182 { 25, 2, default3_mux_table, "rg_mux", default3_mux_parents, 183 ARRAY_SIZE(default3_mux_parents), 0 }, 184 { 27, 2, default3_mux_table, "rcp_mux", default3_mux_parents, 185 ARRAY_SIZE(default3_mux_parents), 0 }, 186 }; 187 188 /* configurable pre dividers: */ 189 static struct npcm8xx_clk_div_data npcm8xx_pre_divs[] = { 190 { NPCM8XX_CLKDIV1, 21, 5, "pre_adc", &npcm8xx_muxes[6].hw, CLK_DIVIDER_READ_ONLY, 0, -1 }, 191 { NPCM8XX_CLKDIV1, 26, 2, "ahb", &hw_pre_clk, CLK_DIVIDER_READ_ONLY, CLK_IS_CRITICAL, NPCM8XX_CLK_AHB }, 192 }; 193 194 /* configurable dividers: */ 195 static struct npcm8xx_clk_div_data npcm8xx_divs[] = { 196 { NPCM8XX_CLKDIV1, 28, 3, "adc", &npcm8xx_pre_divs[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_ADC }, 197 { NPCM8XX_CLKDIV1, 16, 5, "uart", &npcm8xx_muxes[3].hw, 0, 0, NPCM8XX_CLK_UART }, 198 { NPCM8XX_CLKDIV1, 11, 5, "mmc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_MMC }, 199 { NPCM8XX_CLKDIV1, 6, 5, "spi3", &npcm8xx_pre_divs[1].hw, 0, 0, NPCM8XX_CLK_SPI3 }, 200 { NPCM8XX_CLKDIV1, 2, 4, "pci", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_PCI }, 201 202 { NPCM8XX_CLKDIV2, 30, 2, "apb4", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB4 }, 203 { NPCM8XX_CLKDIV2, 28, 2, "apb3", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB3 }, 204 { NPCM8XX_CLKDIV2, 26, 2, "apb2", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB2 }, 205 { NPCM8XX_CLKDIV2, 24, 2, "apb1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB1 }, 206 { NPCM8XX_CLKDIV2, 22, 2, "apb5", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB5 }, 207 { NPCM8XX_CLKDIV2, 16, 5, "clkout", &npcm8xx_muxes[8].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_CLKOUT }, 208 { NPCM8XX_CLKDIV2, 13, 3, "gfx", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_GFX }, 209 { NPCM8XX_CLKDIV2, 8, 5, "usb_bridge", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU }, 210 { NPCM8XX_CLKDIV2, 4, 4, "usb_host", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU48 }, 211 { NPCM8XX_CLKDIV2, 0, 4, "sdhc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SDHC }, 212 213 { NPCM8XX_CLKDIV3, 16, 8, "spi1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI1 }, 214 { NPCM8XX_CLKDIV3, 11, 5, "uart2", &npcm8xx_muxes[3].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_UART2 }, 215 { NPCM8XX_CLKDIV3, 6, 5, "spi0", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI0 }, 216 { NPCM8XX_CLKDIV3, 1, 5, "spix", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPIX }, 217 218 { NPCM8XX_CLKDIV4, 28, 4, "rg", &npcm8xx_muxes[11].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RG }, 219 { NPCM8XX_CLKDIV4, 12, 4, "rcp", &npcm8xx_muxes[12].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RCP }, 220 221 { NPCM8XX_THRTL_CNT, 0, 2, "th", &npcm8xx_muxes[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_TH }, 222 }; 223 224 static unsigned long npcm8xx_clk_pll_recalc_rate(struct clk_hw *hw, 225 unsigned long parent_rate) 226 { 227 struct npcm8xx_clk_pll *pll = to_npcm8xx_clk_pll(hw); 228 unsigned long fbdv, indv, otdv1, otdv2; 229 unsigned int val; 230 u64 ret; 231 232 if (parent_rate == 0) { 233 pr_debug("%s: parent rate is zero\n", __func__); 234 return 0; 235 } 236 237 val = readl_relaxed(pll->pllcon); 238 239 indv = FIELD_GET(PLLCON_INDV, val); 240 fbdv = FIELD_GET(PLLCON_FBDV, val); 241 otdv1 = FIELD_GET(PLLCON_OTDV1, val); 242 otdv2 = FIELD_GET(PLLCON_OTDV2, val); 243 244 ret = (u64)parent_rate * fbdv; 245 do_div(ret, indv * otdv1 * otdv2); 246 247 return ret; 248 } 249 250 static const struct clk_ops npcm8xx_clk_pll_ops = { 251 .recalc_rate = npcm8xx_clk_pll_recalc_rate, 252 }; 253 254 static struct clk_hw * 255 npcm8xx_clk_register_pll(struct device *dev, void __iomem *pllcon, 256 const char *name, const struct clk_parent_data *parent, 257 unsigned long flags) 258 { 259 struct npcm8xx_clk_pll *pll; 260 struct clk_init_data init = {}; 261 int ret; 262 263 pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); 264 if (!pll) 265 return ERR_PTR(-ENOMEM); 266 267 init.name = name; 268 init.ops = &npcm8xx_clk_pll_ops; 269 init.parent_data = parent; 270 init.num_parents = 1; 271 init.flags = flags; 272 273 pll->pllcon = pllcon; 274 pll->hw.init = &init; 275 276 ret = devm_clk_hw_register(dev, &pll->hw); 277 if (ret) 278 return ERR_PTR(ret); 279 280 return &pll->hw; 281 } 282 283 static DEFINE_SPINLOCK(npcm8xx_clk_lock); 284 285 static int npcm8xx_clk_probe(struct auxiliary_device *adev, 286 const struct auxiliary_device_id *id) 287 { 288 struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev); 289 struct clk_hw_onecell_data *npcm8xx_clk_data; 290 struct device *dev = &adev->dev; 291 struct clk_hw *hw; 292 unsigned int i; 293 294 npcm8xx_clk_data = devm_kzalloc(dev, struct_size(npcm8xx_clk_data, hws, 295 NPCM8XX_NUM_CLOCKS), 296 GFP_KERNEL); 297 if (!npcm8xx_clk_data) 298 return -ENOMEM; 299 300 clk_base = rdev->base; 301 302 npcm8xx_clk_data->num = NPCM8XX_NUM_CLOCKS; 303 304 for (i = 0; i < NPCM8XX_NUM_CLOCKS; i++) 305 npcm8xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); 306 307 /* Register plls */ 308 for (i = 0; i < ARRAY_SIZE(npcm8xx_pll_clks); i++) { 309 struct npcm8xx_clk_pll_data *pll_clk = &npcm8xx_pll_clks[i]; 310 311 hw = npcm8xx_clk_register_pll(dev, clk_base + pll_clk->reg, 312 pll_clk->name, &pll_clk->parent, 313 pll_clk->flags); 314 if (IS_ERR(hw)) 315 return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll\n"); 316 pll_clk->hw = *hw; 317 } 318 319 /* Register fixed dividers */ 320 hw = devm_clk_hw_register_fixed_factor(dev, "pll1_div2", "pll1", 0, 1, 2); 321 if (IS_ERR(hw)) 322 return dev_err_probe(dev, PTR_ERR(hw), "Can't register fixed div\n"); 323 hw_pll1_div2 = *hw; 324 325 hw = devm_clk_hw_register_fixed_factor(dev, "pll2_div2", "pll2", 0, 1, 2); 326 if (IS_ERR(hw)) 327 return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll2 div2\n"); 328 hw_pll2_div2 = *hw; 329 330 hw = devm_clk_hw_register_fixed_factor(dev, "pll_gfx_div2", "pll_gfx", 0, 1, 2); 331 if (IS_ERR(hw)) 332 return dev_err_probe(dev, PTR_ERR(hw), "Can't register gfx div2\n"); 333 hw_gfx_div2 = *hw; 334 335 /* Register muxes */ 336 for (i = 0; i < ARRAY_SIZE(npcm8xx_muxes); i++) { 337 struct npcm8xx_clk_mux_data *mux_data = &npcm8xx_muxes[i]; 338 339 hw = devm_clk_hw_register_mux_parent_data_table(dev, 340 mux_data->name, 341 mux_data->parent_data, 342 mux_data->num_parents, 343 mux_data->flags, 344 clk_base + NPCM8XX_CLKSEL, 345 mux_data->shift, 346 mux_data->mask, 347 0, 348 mux_data->table, 349 &npcm8xx_clk_lock); 350 if (IS_ERR(hw)) 351 return dev_err_probe(dev, PTR_ERR(hw), "Can't register mux\n"); 352 mux_data->hw = *hw; 353 } 354 355 hw = devm_clk_hw_register_fixed_factor(dev, "pre_clk", "cpu_mux", 0, 1, 2); 356 if (IS_ERR(hw)) 357 return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre clk div2\n"); 358 hw_pre_clk = *hw; 359 360 hw = devm_clk_hw_register_fixed_factor(dev, "axi", "th", 0, 1, 2); 361 if (IS_ERR(hw)) 362 return dev_err_probe(dev, PTR_ERR(hw), "Can't register axi div2\n"); 363 npcm8xx_clk_data->hws[NPCM8XX_CLK_AXI] = hw; 364 365 hw = devm_clk_hw_register_fixed_factor(dev, "atb", "axi", 0, 1, 2); 366 if (IS_ERR(hw)) 367 return dev_err_probe(dev, PTR_ERR(hw), "Can't register atb div2\n"); 368 npcm8xx_clk_data->hws[NPCM8XX_CLK_ATB] = hw; 369 370 /* Register pre dividers */ 371 for (i = 0; i < ARRAY_SIZE(npcm8xx_pre_divs); i++) { 372 struct npcm8xx_clk_div_data *div_data = &npcm8xx_pre_divs[i]; 373 374 hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name, 375 div_data->parent_hw, 376 div_data->flags, 377 clk_base + div_data->reg, 378 div_data->shift, 379 div_data->width, 380 div_data->clk_divider_flags, 381 &npcm8xx_clk_lock); 382 if (IS_ERR(hw)) 383 return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre div\n"); 384 div_data->hw = *hw; 385 386 if (div_data->onecell_idx >= 0) 387 npcm8xx_clk_data->hws[div_data->onecell_idx] = hw; 388 } 389 390 /* Register dividers */ 391 for (i = 0; i < ARRAY_SIZE(npcm8xx_divs); i++) { 392 struct npcm8xx_clk_div_data *div_data = &npcm8xx_divs[i]; 393 394 hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name, 395 div_data->parent_hw, 396 div_data->flags, 397 clk_base + div_data->reg, 398 div_data->shift, 399 div_data->width, 400 div_data->clk_divider_flags, 401 &npcm8xx_clk_lock); 402 if (IS_ERR(hw)) 403 return dev_err_probe(dev, PTR_ERR(hw), "Can't register div\n"); 404 405 if (div_data->onecell_idx >= 0) 406 npcm8xx_clk_data->hws[div_data->onecell_idx] = hw; 407 } 408 409 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 410 npcm8xx_clk_data); 411 } 412 413 static const struct auxiliary_device_id npcm8xx_clock_ids[] = { 414 { 415 .name = "reset_npcm.clk-npcm8xx", 416 }, 417 { } 418 }; 419 MODULE_DEVICE_TABLE(auxiliary, npcm8xx_clock_ids); 420 421 static struct auxiliary_driver npcm8xx_clock_driver = { 422 .probe = npcm8xx_clk_probe, 423 .id_table = npcm8xx_clock_ids, 424 }; 425 module_auxiliary_driver(npcm8xx_clock_driver); 426 427 MODULE_DESCRIPTION("Clock driver for Nuvoton NPCM8XX BMC SoC"); 428 MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); 429 MODULE_LICENSE("GPL v2"); 430 431