1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2017, Intel Corporation 4 */ 5 #include <linux/slab.h> 6 #include <linux/clk-provider.h> 7 #include <linux/of.h> 8 #include <linux/platform_device.h> 9 10 #include <dt-bindings/clock/stratix10-clock.h> 11 12 #include "stratix10-clk.h" 13 14 static const struct clk_parent_data pll_mux[] = { 15 { .fw_name = "osc1", 16 .name = "osc1" }, 17 { .fw_name = "cb-intosc-hs-div2-clk", 18 .name = "cb-intosc-hs-div2-clk" }, 19 { .fw_name = "f2s-free-clk", 20 .name = "f2s-free-clk" }, 21 }; 22 23 static const struct clk_parent_data cntr_mux[] = { 24 { .fw_name = "main_pll", 25 .name = "main_pll", }, 26 { .fw_name = "periph_pll", 27 .name = "periph_pll", }, 28 { .fw_name = "osc1", 29 .name = "osc1", }, 30 { .fw_name = "cb-intosc-hs-div2-clk", 31 .name = "cb-intosc-hs-div2-clk", }, 32 { .fw_name = "f2s-free-clk", 33 .name = "f2s-free-clk", }, 34 }; 35 36 static const struct clk_parent_data boot_mux[] = { 37 { .fw_name = "osc1", 38 .name = "osc1" }, 39 { .fw_name = "cb-intosc-hs-div2-clk", 40 .name = "cb-intosc-hs-div2-clk" }, 41 }; 42 43 static const struct clk_parent_data noc_free_mux[] = { 44 { .fw_name = "main_noc_base_clk", 45 .name = "main_noc_base_clk", }, 46 { .fw_name = "peri_noc_base_clk", 47 .name = "peri_noc_base_clk", }, 48 { .fw_name = "osc1", 49 .name = "osc1", }, 50 { .fw_name = "cb-intosc-hs-div2-clk", 51 .name = "cb-intosc-hs-div2-clk", }, 52 { .fw_name = "f2s-free-clk", 53 .name = "f2s-free-clk", }, 54 }; 55 56 static const struct clk_parent_data emaca_free_mux[] = { 57 { .fw_name = "peri_emaca_clk", 58 .name = "peri_emaca_clk", }, 59 { .fw_name = "boot_clk", 60 .name = "boot_clk", }, 61 }; 62 63 static const struct clk_parent_data emacb_free_mux[] = { 64 { .fw_name = "peri_emacb_clk", 65 .name = "peri_emacb_clk", }, 66 { .fw_name = "boot_clk", 67 .name = "boot_clk", }, 68 }; 69 70 static const struct clk_parent_data emac_ptp_free_mux[] = { 71 { .fw_name = "peri_emac_ptp_clk", 72 .name = "peri_emac_ptp_clk", }, 73 { .fw_name = "boot_clk", 74 .name = "boot_clk", }, 75 }; 76 77 static const struct clk_parent_data gpio_db_free_mux[] = { 78 { .fw_name = "peri_gpio_db_clk", 79 .name = "peri_gpio_db_clk", }, 80 { .fw_name = "boot_clk", 81 .name = "boot_clk", }, 82 }; 83 84 static const struct clk_parent_data sdmmc_free_mux[] = { 85 { .fw_name = "main_sdmmc_clk", 86 .name = "main_sdmmc_clk", }, 87 { .fw_name = "boot_clk", 88 .name = "boot_clk", }, 89 }; 90 91 static const struct clk_parent_data s2f_usr1_free_mux[] = { 92 { .fw_name = "peri_s2f_usr1_clk", 93 .name = "peri_s2f_usr1_clk", }, 94 { .fw_name = "boot_clk", 95 .name = "boot_clk", }, 96 }; 97 98 static const struct clk_parent_data psi_ref_free_mux[] = { 99 { .fw_name = "peri_psi_ref_clk", 100 .name = "peri_psi_ref_clk", }, 101 { .fw_name = "boot_clk", 102 .name = "boot_clk", }, 103 }; 104 105 static const struct clk_parent_data mpu_mux[] = { 106 { .fw_name = "mpu_free_clk", 107 .name = "mpu_free_clk", }, 108 { .fw_name = "boot_clk", 109 .name = "boot_clk", }, 110 }; 111 112 static const struct clk_parent_data s2f_usr0_mux[] = { 113 { .fw_name = "f2s-free-clk", 114 .name = "f2s-free-clk", }, 115 { .fw_name = "boot_clk", 116 .name = "boot_clk", }, 117 }; 118 119 static const struct clk_parent_data emac_mux[] = { 120 { .fw_name = "emaca_free_clk", 121 .name = "emaca_free_clk", }, 122 { .fw_name = "emacb_free_clk", 123 .name = "emacb_free_clk", }, 124 }; 125 126 static const struct clk_parent_data noc_mux[] = { 127 { .fw_name = "noc_free_clk", 128 .name = "noc_free_clk", }, 129 { .fw_name = "boot_clk", 130 .name = "boot_clk", }, 131 }; 132 133 static const struct clk_parent_data mpu_free_mux[] = { 134 { .fw_name = "main_mpu_base_clk", 135 .name = "main_mpu_base_clk", }, 136 { .fw_name = "peri_mpu_base_clk", 137 .name = "peri_mpu_base_clk", }, 138 { .fw_name = "osc1", 139 .name = "osc1", }, 140 { .fw_name = "cb-intosc-hs-div2-clk", 141 .name = "cb-intosc-hs-div2-clk", }, 142 { .fw_name = "f2s-free-clk", 143 .name = "f2s-free-clk", }, 144 }; 145 146 static const struct clk_parent_data sdmmc_mux[] = { 147 { .fw_name = "sdmmc_free_clk", 148 .name = "sdmmc_free_clk", }, 149 { .fw_name = "boot_clk", 150 .name = "boot_clk", }, 151 }; 152 153 static const struct clk_parent_data s2f_user1_mux[] = { 154 { .fw_name = "s2f_user1_free_clk", 155 .name = "s2f_user1_free_clk", }, 156 { .fw_name = "boot_clk", 157 .name = "boot_clk", }, 158 }; 159 160 static const struct clk_parent_data psi_mux[] = { 161 { .fw_name = "psi_ref_free_clk", 162 .name = "psi_ref_free_clk", }, 163 { .fw_name = "boot_clk", 164 .name = "boot_clk", }, 165 }; 166 167 static const struct clk_parent_data gpio_db_mux[] = { 168 { .fw_name = "gpio_db_free_clk", 169 .name = "gpio_db_free_clk", }, 170 { .fw_name = "boot_clk", 171 .name = "boot_clk", }, 172 }; 173 174 static const struct clk_parent_data emac_ptp_mux[] = { 175 { .fw_name = "emac_ptp_free_clk", 176 .name = "emac_ptp_free_clk", }, 177 { .fw_name = "boot_clk", 178 .name = "boot_clk", }, 179 }; 180 181 /* clocks in AO (always on) controller */ 182 static const struct stratix10_pll_clock s10_pll_clks[] = { 183 { STRATIX10_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0, 184 0x0}, 185 { STRATIX10_MAIN_PLL_CLK, "main_pll", pll_mux, ARRAY_SIZE(pll_mux), 186 0, 0x74}, 187 { STRATIX10_PERIPH_PLL_CLK, "periph_pll", pll_mux, ARRAY_SIZE(pll_mux), 188 0, 0xe4}, 189 }; 190 191 static const struct stratix10_perip_c_clock s10_main_perip_c_clks[] = { 192 { STRATIX10_MAIN_MPU_BASE_CLK, "main_mpu_base_clk", "main_pll", NULL, 1, 0, 0x84}, 193 { STRATIX10_MAIN_NOC_BASE_CLK, "main_noc_base_clk", "main_pll", NULL, 1, 0, 0x88}, 194 { STRATIX10_PERI_MPU_BASE_CLK, "peri_mpu_base_clk", "periph_pll", NULL, 1, 0, 195 0xF4}, 196 { STRATIX10_PERI_NOC_BASE_CLK, "peri_noc_base_clk", "periph_pll", NULL, 1, 0, 197 0xF8}, 198 }; 199 200 static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = { 201 { STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, mpu_free_mux, ARRAY_SIZE(mpu_free_mux), 202 0, 0x48, 0, 0, 0}, 203 { STRATIX10_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux), 204 0, 0x4C, 0, 0x3C, 1}, 205 { STRATIX10_MAIN_EMACA_CLK, "main_emaca_clk", "main_noc_base_clk", NULL, 1, 0, 206 0x50, 0, 0, 0}, 207 { STRATIX10_MAIN_EMACB_CLK, "main_emacb_clk", "main_noc_base_clk", NULL, 1, 0, 208 0x54, 0, 0, 0}, 209 { STRATIX10_MAIN_EMAC_PTP_CLK, "main_emac_ptp_clk", "main_noc_base_clk", NULL, 1, 0, 210 0x58, 0, 0, 0}, 211 { STRATIX10_MAIN_GPIO_DB_CLK, "main_gpio_db_clk", "main_noc_base_clk", NULL, 1, 0, 212 0x5C, 0, 0, 0}, 213 { STRATIX10_MAIN_SDMMC_CLK, "main_sdmmc_clk", "main_noc_base_clk", NULL, 1, 0, 214 0x60, 0, 0, 0}, 215 { STRATIX10_MAIN_S2F_USR0_CLK, "main_s2f_usr0_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 216 0, 0x64, 0, 0, 0}, 217 { STRATIX10_MAIN_S2F_USR1_CLK, "main_s2f_usr1_clk", "main_noc_base_clk", NULL, 1, 0, 218 0x68, 0, 0, 0}, 219 { STRATIX10_MAIN_PSI_REF_CLK, "main_psi_ref_clk", "main_noc_base_clk", NULL, 1, 0, 220 0x6C, 0, 0, 0}, 221 { STRATIX10_PERI_EMACA_CLK, "peri_emaca_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 222 0, 0xBC, 0, 0, 0}, 223 { STRATIX10_PERI_EMACB_CLK, "peri_emacb_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 224 0, 0xC0, 0, 0, 0}, 225 { STRATIX10_PERI_EMAC_PTP_CLK, "peri_emac_ptp_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 226 0, 0xC4, 0, 0, 0}, 227 { STRATIX10_PERI_GPIO_DB_CLK, "peri_gpio_db_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 228 0, 0xC8, 0, 0, 0}, 229 { STRATIX10_PERI_SDMMC_CLK, "peri_sdmmc_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 230 0, 0xCC, 0, 0, 0}, 231 { STRATIX10_PERI_S2F_USR0_CLK, "peri_s2f_usr0_clk", "peri_noc_base_clk", NULL, 1, 0, 232 0xD0, 0, 0, 0}, 233 { STRATIX10_PERI_S2F_USR1_CLK, "peri_s2f_usr1_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), 234 0, 0xD4, 0, 0, 0}, 235 { STRATIX10_PERI_PSI_REF_CLK, "peri_psi_ref_clk", "peri_noc_base_clk", NULL, 1, 0, 236 0xD8, 0, 0, 0}, 237 { STRATIX10_L4_SYS_FREE_CLK, "l4_sys_free_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 238 0, 4, 0x3C, 1}, 239 { STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux), 240 0, 0, 2, 0xB0, 0}, 241 { STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux), 242 0, 0, 2, 0xB0, 1}, 243 { STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux, 244 ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 2, 0xB0, 2}, 245 { STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux, 246 ARRAY_SIZE(gpio_db_free_mux), 0, 0, 0, 0xB0, 3}, 247 { STRATIX10_SDMMC_FREE_CLK, "sdmmc_free_clk", NULL, sdmmc_free_mux, 248 ARRAY_SIZE(sdmmc_free_mux), 0, 0, 0, 0xB0, 4}, 249 { STRATIX10_S2F_USER1_FREE_CLK, "s2f_user1_free_clk", NULL, s2f_usr1_free_mux, 250 ARRAY_SIZE(s2f_usr1_free_mux), 0, 0, 0, 0xB0, 5}, 251 { STRATIX10_PSI_REF_FREE_CLK, "psi_ref_free_clk", NULL, psi_ref_free_mux, 252 ARRAY_SIZE(psi_ref_free_mux), 0, 0, 0, 0xB0, 6}, 253 }; 254 255 static const struct stratix10_gate_clock s10_gate_clks[] = { 256 { STRATIX10_MPU_CLK, "mpu_clk", NULL, mpu_mux, ARRAY_SIZE(mpu_mux), 0, 0x30, 257 0, 0, 0, 0, 0x3C, 0, 0}, 258 { STRATIX10_MPU_PERIPH_CLK, "mpu_periph_clk", "mpu_clk", NULL, 1, 0, 0x30, 259 0, 0, 0, 0, 0, 0, 4}, 260 { STRATIX10_MPU_L2RAM_CLK, "mpu_l2ram_clk", "mpu_clk", NULL, 1, 0, 0x30, 261 0, 0, 0, 0, 0, 0, 2}, 262 { STRATIX10_L4_MAIN_CLK, "l4_main_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30, 263 1, 0x70, 0, 2, 0x3C, 1, 0}, 264 { STRATIX10_L4_MP_CLK, "l4_mp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30, 265 2, 0x70, 8, 2, 0x3C, 1, 0}, 266 { STRATIX10_L4_SP_CLK, "l4_sp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), CLK_IS_CRITICAL, 0x30, 267 3, 0x70, 16, 2, 0x3C, 1, 0}, 268 { STRATIX10_CS_AT_CLK, "cs_at_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30, 269 4, 0x70, 24, 2, 0x3C, 1, 0}, 270 { STRATIX10_CS_TRACE_CLK, "cs_trace_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30, 271 4, 0x70, 26, 2, 0x3C, 1, 0}, 272 { STRATIX10_CS_PDBG_CLK, "cs_pdbg_clk", "cs_at_clk", NULL, 1, 0, 0x30, 273 4, 0x70, 28, 1, 0, 0, 0}, 274 { STRATIX10_CS_TIMER_CLK, "cs_timer_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30, 275 5, 0, 0, 0, 0x3C, 1, 0}, 276 { STRATIX10_S2F_USER0_CLK, "s2f_user0_clk", NULL, s2f_usr0_mux, ARRAY_SIZE(s2f_usr0_mux), 0, 0x30, 277 6, 0, 0, 0, 0, 0, 0}, 278 { STRATIX10_EMAC0_CLK, "emac0_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4, 279 0, 0, 0, 0, 0xDC, 26, 0}, 280 { STRATIX10_EMAC1_CLK, "emac1_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4, 281 1, 0, 0, 0, 0xDC, 27, 0}, 282 { STRATIX10_EMAC2_CLK, "emac2_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4, 283 2, 0, 0, 0, 0xDC, 28, 0}, 284 { STRATIX10_EMAC_PTP_CLK, "emac_ptp_clk", NULL, emac_ptp_mux, ARRAY_SIZE(emac_ptp_mux), 0, 0xA4, 285 3, 0, 0, 0, 0xB0, 2, 0}, 286 { STRATIX10_GPIO_DB_CLK, "gpio_db_clk", NULL, gpio_db_mux, ARRAY_SIZE(gpio_db_mux), 0, 0xA4, 287 4, 0xE0, 0, 16, 0xB0, 3, 0}, 288 { STRATIX10_SDMMC_CLK, "sdmmc_clk", NULL, sdmmc_mux, ARRAY_SIZE(sdmmc_mux), 0, 0xA4, 289 5, 0, 0, 0, 0xB0, 4, 4}, 290 { STRATIX10_S2F_USER1_CLK, "s2f_user1_clk", NULL, s2f_user1_mux, ARRAY_SIZE(s2f_user1_mux), 0, 0xA4, 291 6, 0, 0, 0, 0xB0, 5, 0}, 292 { STRATIX10_PSI_REF_CLK, "psi_ref_clk", NULL, psi_mux, ARRAY_SIZE(psi_mux), 0, 0xA4, 293 7, 0, 0, 0, 0xB0, 6, 0}, 294 { STRATIX10_USB_CLK, "usb_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, 295 8, 0, 0, 0, 0, 0, 0}, 296 { STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, 297 9, 0, 0, 0, 0, 0, 0}, 298 { STRATIX10_NAND_X_CLK, "nand_x_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, 299 10, 0, 0, 0, 0, 0, 0}, 300 { STRATIX10_NAND_CLK, "nand_clk", "nand_x_clk", NULL, 1, 0, 0xA4, 301 10, 0, 0, 0, 0, 0, 4}, 302 { STRATIX10_NAND_ECC_CLK, "nand_ecc_clk", "nand_x_clk", NULL, 1, 0, 0xA4, 303 10, 0, 0, 0, 0, 0, 4}, 304 }; 305 306 static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks, 307 int nums, struct stratix10_clock_data *data) 308 { 309 struct clk_hw *hw_clk; 310 void __iomem *base = data->base; 311 int i; 312 313 for (i = 0; i < nums; i++) { 314 hw_clk = s10_register_periph(&clks[i], base); 315 if (IS_ERR(hw_clk)) { 316 pr_err("%s: failed to register clock %s\n", 317 __func__, clks[i].name); 318 continue; 319 } 320 data->clk_data.hws[clks[i].id] = hw_clk; 321 } 322 return 0; 323 } 324 325 static int s10_clk_register_cnt_perip(const struct stratix10_perip_cnt_clock *clks, 326 int nums, struct stratix10_clock_data *data) 327 { 328 struct clk_hw *hw_clk; 329 void __iomem *base = data->base; 330 int i; 331 332 for (i = 0; i < nums; i++) { 333 hw_clk = s10_register_cnt_periph(&clks[i], base); 334 if (IS_ERR(hw_clk)) { 335 pr_err("%s: failed to register clock %s\n", 336 __func__, clks[i].name); 337 continue; 338 } 339 data->clk_data.hws[clks[i].id] = hw_clk; 340 } 341 342 return 0; 343 } 344 345 static int s10_clk_register_gate(const struct stratix10_gate_clock *clks, 346 int nums, struct stratix10_clock_data *data) 347 { 348 struct clk_hw *hw_clk; 349 void __iomem *base = data->base; 350 int i; 351 352 for (i = 0; i < nums; i++) { 353 hw_clk = s10_register_gate(&clks[i], base); 354 if (IS_ERR(hw_clk)) { 355 pr_err("%s: failed to register clock %s\n", 356 __func__, clks[i].name); 357 continue; 358 } 359 data->clk_data.hws[clks[i].id] = hw_clk; 360 } 361 362 return 0; 363 } 364 365 static int s10_clk_register_pll(const struct stratix10_pll_clock *clks, 366 int nums, struct stratix10_clock_data *data) 367 { 368 struct clk_hw *hw_clk; 369 void __iomem *base = data->base; 370 int i; 371 372 for (i = 0; i < nums; i++) { 373 hw_clk = s10_register_pll(&clks[i], base); 374 if (IS_ERR(hw_clk)) { 375 pr_err("%s: failed to register clock %s\n", 376 __func__, clks[i].name); 377 continue; 378 } 379 data->clk_data.hws[clks[i].id] = hw_clk; 380 } 381 382 return 0; 383 } 384 385 static int s10_clkmgr_init(struct platform_device *pdev) 386 { 387 struct device_node *np = pdev->dev.of_node; 388 struct device *dev = &pdev->dev; 389 struct stratix10_clock_data *clk_data; 390 void __iomem *base; 391 int i, num_clks; 392 393 base = devm_platform_ioremap_resource(pdev, 0); 394 if (IS_ERR(base)) { 395 pr_err("%s: failed to map clock registers\n", __func__); 396 return PTR_ERR(base); 397 } 398 399 num_clks = STRATIX10_NUM_CLKS; 400 clk_data = devm_kzalloc(dev, struct_size(clk_data, clk_data.hws, 401 num_clks), GFP_KERNEL); 402 if (!clk_data) 403 return -ENOMEM; 404 405 for (i = 0; i < num_clks; i++) 406 clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); 407 408 clk_data->base = base; 409 clk_data->clk_data.num = num_clks; 410 411 s10_clk_register_pll(s10_pll_clks, ARRAY_SIZE(s10_pll_clks), clk_data); 412 413 s10_clk_register_c_perip(s10_main_perip_c_clks, 414 ARRAY_SIZE(s10_main_perip_c_clks), clk_data); 415 416 s10_clk_register_cnt_perip(s10_main_perip_cnt_clks, 417 ARRAY_SIZE(s10_main_perip_cnt_clks), 418 clk_data); 419 420 s10_clk_register_gate(s10_gate_clks, ARRAY_SIZE(s10_gate_clks), 421 clk_data); 422 423 of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data->clk_data); 424 return 0; 425 } 426 427 static int s10_clkmgr_probe(struct platform_device *pdev) 428 { 429 return s10_clkmgr_init(pdev); 430 } 431 432 static const struct of_device_id stratix10_clkmgr_match_table[] = { 433 { .compatible = "intel,stratix10-clkmgr", 434 .data = s10_clkmgr_init }, 435 { } 436 }; 437 438 static struct platform_driver stratix10_clkmgr_driver = { 439 .probe = s10_clkmgr_probe, 440 .driver = { 441 .name = "stratix10-clkmgr", 442 .suppress_bind_attrs = true, 443 .of_match_table = stratix10_clkmgr_match_table, 444 }, 445 }; 446 447 static int __init s10_clk_init(void) 448 { 449 return platform_driver_register(&stratix10_clkmgr_driver); 450 } 451 core_initcall(s10_clk_init); 452