1 /* 2 * Marvell Armada CP110 System Controller 3 * 4 * Copyright (C) 2016 Marvell 5 * 6 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13 /* 14 * CP110 has 6 core clocks: 15 * 16 * - APLL (1 Ghz) 17 * - PPv2 core (1/3 APLL) 18 * - EIP (1/2 APLL) 19 * - Core (1/2 EIP) 20 * - SDIO (2/5 APLL) 21 * 22 * - NAND clock, which is either: 23 * - Equal to SDIO clock 24 * - 2/5 APLL 25 * 26 * CP110 has 32 gatable clocks, for the various peripherals in the 27 * IP. They have fairly complicated parent/child relationships. 28 */ 29 30 #define pr_fmt(fmt) "cp110-system-controller: " fmt 31 32 #include <linux/clk-provider.h> 33 #include <linux/mfd/syscon.h> 34 #include <linux/init.h> 35 #include <linux/of.h> 36 #include <linux/of_address.h> 37 #include <linux/platform_device.h> 38 #include <linux/regmap.h> 39 #include <linux/slab.h> 40 41 #define CP110_PM_CLOCK_GATING_REG 0x220 42 #define CP110_NAND_FLASH_CLK_CTRL_REG 0x700 43 #define NF_CLOCK_SEL_400_MASK BIT(0) 44 45 enum { 46 CP110_CLK_TYPE_CORE, 47 CP110_CLK_TYPE_GATABLE, 48 }; 49 50 #define CP110_MAX_CORE_CLOCKS 6 51 #define CP110_MAX_GATABLE_CLOCKS 32 52 53 #define CP110_CLK_NUM \ 54 (CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS) 55 56 #define CP110_CORE_APLL 0 57 #define CP110_CORE_PPV2 1 58 #define CP110_CORE_EIP 2 59 #define CP110_CORE_CORE 3 60 #define CP110_CORE_NAND 4 61 #define CP110_CORE_SDIO 5 62 63 /* A number of gatable clocks need special handling */ 64 #define CP110_GATE_AUDIO 0 65 #define CP110_GATE_COMM_UNIT 1 66 #define CP110_GATE_NAND 2 67 #define CP110_GATE_PPV2 3 68 #define CP110_GATE_SDIO 4 69 #define CP110_GATE_MG 5 70 #define CP110_GATE_MG_CORE 6 71 #define CP110_GATE_XOR1 7 72 #define CP110_GATE_XOR0 8 73 #define CP110_GATE_GOP_DP 9 74 #define CP110_GATE_PCIE_X1_0 11 75 #define CP110_GATE_PCIE_X1_1 12 76 #define CP110_GATE_PCIE_X4 13 77 #define CP110_GATE_PCIE_XOR 14 78 #define CP110_GATE_SATA 15 79 #define CP110_GATE_SATA_USB 16 80 #define CP110_GATE_MAIN 17 81 #define CP110_GATE_SDMMC_GOP 18 82 #define CP110_GATE_SLOW_IO 21 83 #define CP110_GATE_USB3H0 22 84 #define CP110_GATE_USB3H1 23 85 #define CP110_GATE_USB3DEV 24 86 #define CP110_GATE_EIP150 25 87 #define CP110_GATE_EIP197 26 88 89 static const char * const gate_base_names[] = { 90 [CP110_GATE_AUDIO] = "audio", 91 [CP110_GATE_COMM_UNIT] = "communit", 92 [CP110_GATE_NAND] = "nand", 93 [CP110_GATE_PPV2] = "ppv2", 94 [CP110_GATE_SDIO] = "sdio", 95 [CP110_GATE_MG] = "mg-domain", 96 [CP110_GATE_MG_CORE] = "mg-core", 97 [CP110_GATE_XOR1] = "xor1", 98 [CP110_GATE_XOR0] = "xor0", 99 [CP110_GATE_GOP_DP] = "gop-dp", 100 [CP110_GATE_PCIE_X1_0] = "pcie_x10", 101 [CP110_GATE_PCIE_X1_1] = "pcie_x11", 102 [CP110_GATE_PCIE_X4] = "pcie_x4", 103 [CP110_GATE_PCIE_XOR] = "pcie-xor", 104 [CP110_GATE_SATA] = "sata", 105 [CP110_GATE_SATA_USB] = "sata-usb", 106 [CP110_GATE_MAIN] = "main", 107 [CP110_GATE_SDMMC_GOP] = "sd-mmc-gop", 108 [CP110_GATE_SLOW_IO] = "slow-io", 109 [CP110_GATE_USB3H0] = "usb3h0", 110 [CP110_GATE_USB3H1] = "usb3h1", 111 [CP110_GATE_USB3DEV] = "usb3dev", 112 [CP110_GATE_EIP150] = "eip150", 113 [CP110_GATE_EIP197] = "eip197" 114 }; 115 116 struct cp110_gate_clk { 117 struct clk_hw hw; 118 struct regmap *regmap; 119 u8 bit_idx; 120 }; 121 122 #define to_cp110_gate_clk(hw) container_of(hw, struct cp110_gate_clk, hw) 123 124 static int cp110_gate_enable(struct clk_hw *hw) 125 { 126 struct cp110_gate_clk *gate = to_cp110_gate_clk(hw); 127 128 regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG, 129 BIT(gate->bit_idx), BIT(gate->bit_idx)); 130 131 return 0; 132 } 133 134 static void cp110_gate_disable(struct clk_hw *hw) 135 { 136 struct cp110_gate_clk *gate = to_cp110_gate_clk(hw); 137 138 regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG, 139 BIT(gate->bit_idx), 0); 140 } 141 142 static int cp110_gate_is_enabled(struct clk_hw *hw) 143 { 144 struct cp110_gate_clk *gate = to_cp110_gate_clk(hw); 145 u32 val; 146 147 regmap_read(gate->regmap, CP110_PM_CLOCK_GATING_REG, &val); 148 149 return val & BIT(gate->bit_idx); 150 } 151 152 static const struct clk_ops cp110_gate_ops = { 153 .enable = cp110_gate_enable, 154 .disable = cp110_gate_disable, 155 .is_enabled = cp110_gate_is_enabled, 156 }; 157 158 static struct clk_hw *cp110_register_gate(const char *name, 159 const char *parent_name, 160 struct regmap *regmap, u8 bit_idx) 161 { 162 struct cp110_gate_clk *gate; 163 struct clk_hw *hw; 164 struct clk_init_data init; 165 int ret; 166 167 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 168 if (!gate) 169 return ERR_PTR(-ENOMEM); 170 171 memset(&init, 0, sizeof(init)); 172 173 init.name = name; 174 init.ops = &cp110_gate_ops; 175 init.parent_names = &parent_name; 176 init.num_parents = 1; 177 178 gate->regmap = regmap; 179 gate->bit_idx = bit_idx; 180 gate->hw.init = &init; 181 182 hw = &gate->hw; 183 ret = clk_hw_register(NULL, hw); 184 if (ret) { 185 kfree(gate); 186 hw = ERR_PTR(ret); 187 } 188 189 return hw; 190 } 191 192 static void cp110_unregister_gate(struct clk_hw *hw) 193 { 194 clk_hw_unregister(hw); 195 kfree(to_cp110_gate_clk(hw)); 196 } 197 198 static struct clk_hw *cp110_of_clk_get(struct of_phandle_args *clkspec, 199 void *data) 200 { 201 struct clk_hw_onecell_data *clk_data = data; 202 unsigned int type = clkspec->args[0]; 203 unsigned int idx = clkspec->args[1]; 204 205 if (type == CP110_CLK_TYPE_CORE) { 206 if (idx > CP110_MAX_CORE_CLOCKS) 207 return ERR_PTR(-EINVAL); 208 return clk_data->hws[idx]; 209 } else if (type == CP110_CLK_TYPE_GATABLE) { 210 if (idx > CP110_MAX_GATABLE_CLOCKS) 211 return ERR_PTR(-EINVAL); 212 return clk_data->hws[CP110_MAX_CORE_CLOCKS + idx]; 213 } 214 215 return ERR_PTR(-EINVAL); 216 } 217 218 static char *cp110_unique_name(struct device *dev, struct device_node *np, 219 const char *name) 220 { 221 const __be32 *reg; 222 u64 addr; 223 224 /* Do not create a name if there is no clock */ 225 if (!name) 226 return NULL; 227 228 reg = of_get_property(np, "reg", NULL); 229 addr = of_translate_address(np, reg); 230 return devm_kasprintf(dev, GFP_KERNEL, "%llx-%s", 231 (unsigned long long)addr, name); 232 } 233 234 static int cp110_syscon_common_probe(struct platform_device *pdev, 235 struct device_node *syscon_node) 236 { 237 struct regmap *regmap; 238 struct device *dev = &pdev->dev; 239 struct device_node *np = dev->of_node; 240 const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name, 241 *sdio_name; 242 struct clk_hw_onecell_data *cp110_clk_data; 243 struct clk_hw *hw, **cp110_clks; 244 u32 nand_clk_ctrl; 245 int i, ret; 246 char *gate_name[ARRAY_SIZE(gate_base_names)]; 247 248 regmap = syscon_node_to_regmap(syscon_node); 249 if (IS_ERR(regmap)) 250 return PTR_ERR(regmap); 251 252 ret = regmap_read(regmap, CP110_NAND_FLASH_CLK_CTRL_REG, 253 &nand_clk_ctrl); 254 if (ret) 255 return ret; 256 257 cp110_clk_data = devm_kzalloc(dev, sizeof(*cp110_clk_data) + 258 sizeof(struct clk_hw *) * CP110_CLK_NUM, 259 GFP_KERNEL); 260 if (!cp110_clk_data) 261 return -ENOMEM; 262 263 cp110_clks = cp110_clk_data->hws; 264 cp110_clk_data->num = CP110_CLK_NUM; 265 266 /* Register the APLL which is the root of the hw tree */ 267 apll_name = cp110_unique_name(dev, syscon_node, "apll"); 268 hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0, 269 1000 * 1000 * 1000); 270 if (IS_ERR(hw)) { 271 ret = PTR_ERR(hw); 272 goto fail_apll; 273 } 274 275 cp110_clks[CP110_CORE_APLL] = hw; 276 277 /* PPv2 is APLL/3 */ 278 ppv2_name = cp110_unique_name(dev, syscon_node, "ppv2-core"); 279 hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); 280 if (IS_ERR(hw)) { 281 ret = PTR_ERR(hw); 282 goto fail_ppv2; 283 } 284 285 cp110_clks[CP110_CORE_PPV2] = hw; 286 287 /* EIP clock is APLL/2 */ 288 eip_name = cp110_unique_name(dev, syscon_node, "eip"); 289 hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); 290 if (IS_ERR(hw)) { 291 ret = PTR_ERR(hw); 292 goto fail_eip; 293 } 294 295 cp110_clks[CP110_CORE_EIP] = hw; 296 297 /* Core clock is EIP/2 */ 298 core_name = cp110_unique_name(dev, syscon_node, "core"); 299 hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); 300 if (IS_ERR(hw)) { 301 ret = PTR_ERR(hw); 302 goto fail_core; 303 } 304 305 cp110_clks[CP110_CORE_CORE] = hw; 306 /* NAND can be either APLL/2.5 or core clock */ 307 nand_name = cp110_unique_name(dev, syscon_node, "nand-core"); 308 if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) 309 hw = clk_hw_register_fixed_factor(NULL, nand_name, 310 apll_name, 0, 2, 5); 311 else 312 hw = clk_hw_register_fixed_factor(NULL, nand_name, 313 core_name, 0, 1, 1); 314 if (IS_ERR(hw)) { 315 ret = PTR_ERR(hw); 316 goto fail_nand; 317 } 318 319 cp110_clks[CP110_CORE_NAND] = hw; 320 321 /* SDIO clock is APLL/2.5 */ 322 sdio_name = cp110_unique_name(dev, syscon_node, "sdio-core"); 323 hw = clk_hw_register_fixed_factor(NULL, sdio_name, 324 apll_name, 0, 2, 5); 325 if (IS_ERR(hw)) { 326 ret = PTR_ERR(hw); 327 goto fail_sdio; 328 } 329 330 cp110_clks[CP110_CORE_SDIO] = hw; 331 332 /* create the unique name for all the gate clocks */ 333 for (i = 0; i < ARRAY_SIZE(gate_base_names); i++) 334 gate_name[i] = cp110_unique_name(dev, syscon_node, 335 gate_base_names[i]); 336 337 for (i = 0; i < ARRAY_SIZE(gate_base_names); i++) { 338 const char *parent; 339 340 if (gate_name[i] == NULL) 341 continue; 342 343 switch (i) { 344 case CP110_GATE_AUDIO: 345 case CP110_GATE_COMM_UNIT: 346 case CP110_GATE_EIP150: 347 case CP110_GATE_EIP197: 348 case CP110_GATE_SLOW_IO: 349 parent = gate_name[CP110_GATE_MAIN]; 350 break; 351 case CP110_GATE_MG: 352 parent = gate_name[CP110_GATE_MG_CORE]; 353 break; 354 case CP110_GATE_NAND: 355 parent = nand_name; 356 break; 357 case CP110_GATE_PPV2: 358 parent = ppv2_name; 359 break; 360 case CP110_GATE_SDIO: 361 parent = sdio_name; 362 break; 363 case CP110_GATE_GOP_DP: 364 parent = gate_name[CP110_GATE_SDMMC_GOP]; 365 break; 366 case CP110_GATE_XOR1: 367 case CP110_GATE_XOR0: 368 case CP110_GATE_PCIE_X1_0: 369 case CP110_GATE_PCIE_X1_1: 370 case CP110_GATE_PCIE_X4: 371 parent = gate_name[CP110_GATE_PCIE_XOR]; 372 break; 373 case CP110_GATE_SATA: 374 case CP110_GATE_USB3H0: 375 case CP110_GATE_USB3H1: 376 case CP110_GATE_USB3DEV: 377 parent = gate_name[CP110_GATE_SATA_USB]; 378 break; 379 default: 380 parent = core_name; 381 break; 382 } 383 hw = cp110_register_gate(gate_name[i], parent, regmap, i); 384 385 if (IS_ERR(hw)) { 386 ret = PTR_ERR(hw); 387 goto fail_gate; 388 } 389 390 cp110_clks[CP110_MAX_CORE_CLOCKS + i] = hw; 391 } 392 393 ret = of_clk_add_hw_provider(np, cp110_of_clk_get, cp110_clk_data); 394 if (ret) 395 goto fail_clk_add; 396 397 platform_set_drvdata(pdev, cp110_clks); 398 399 return 0; 400 401 fail_clk_add: 402 fail_gate: 403 for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { 404 hw = cp110_clks[CP110_MAX_CORE_CLOCKS + i]; 405 406 if (hw) 407 cp110_unregister_gate(hw); 408 } 409 410 clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_SDIO]); 411 fail_sdio: 412 clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); 413 fail_nand: 414 clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); 415 fail_core: 416 clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); 417 fail_eip: 418 clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); 419 fail_ppv2: 420 clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); 421 fail_apll: 422 return ret; 423 } 424 425 static int cp110_syscon_legacy_clk_probe(struct platform_device *pdev) 426 { 427 dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n"); 428 dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n"); 429 dev_warn(&pdev->dev, FW_WARN 430 "This binding won't be supported in future kernels\n"); 431 432 return cp110_syscon_common_probe(pdev, pdev->dev.of_node); 433 } 434 435 static int cp110_clk_probe(struct platform_device *pdev) 436 { 437 return cp110_syscon_common_probe(pdev, pdev->dev.of_node->parent); 438 } 439 440 static const struct of_device_id cp110_syscon_legacy_of_match[] = { 441 { .compatible = "marvell,cp110-system-controller0", }, 442 { } 443 }; 444 445 static struct platform_driver cp110_syscon_legacy_driver = { 446 .probe = cp110_syscon_legacy_clk_probe, 447 .driver = { 448 .name = "marvell-cp110-system-controller0", 449 .of_match_table = cp110_syscon_legacy_of_match, 450 .suppress_bind_attrs = true, 451 }, 452 }; 453 builtin_platform_driver(cp110_syscon_legacy_driver); 454 455 static const struct of_device_id cp110_clock_of_match[] = { 456 { .compatible = "marvell,cp110-clock", }, 457 { } 458 }; 459 460 static struct platform_driver cp110_clock_driver = { 461 .probe = cp110_clk_probe, 462 .driver = { 463 .name = "marvell-cp110-clock", 464 .of_match_table = cp110_clock_of_match, 465 .suppress_bind_attrs = true, 466 }, 467 }; 468 builtin_platform_driver(cp110_clock_driver); 469