1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC 4 * 5 * Authors: 6 * Serge Semin <Sergey.Semin@baikalelectronics.ru> 7 * Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru> 8 * 9 * Baikal-T1 CCU Dividers clock driver 10 */ 11 12 #define pr_fmt(fmt) "bt1-ccu-div: " fmt 13 14 #include <linux/kernel.h> 15 #include <linux/platform_device.h> 16 #include <linux/printk.h> 17 #include <linux/slab.h> 18 #include <linux/clk-provider.h> 19 #include <linux/reset-controller.h> 20 #include <linux/mfd/syscon.h> 21 #include <linux/of.h> 22 #include <linux/of_address.h> 23 #include <linux/of_platform.h> 24 #include <linux/ioport.h> 25 #include <linux/regmap.h> 26 27 #include <dt-bindings/clock/bt1-ccu.h> 28 29 #include "ccu-div.h" 30 #include "ccu-rst.h" 31 32 #define CCU_AXI_MAIN_BASE 0x030 33 #define CCU_AXI_DDR_BASE 0x034 34 #define CCU_AXI_SATA_BASE 0x038 35 #define CCU_AXI_GMAC0_BASE 0x03C 36 #define CCU_AXI_GMAC1_BASE 0x040 37 #define CCU_AXI_XGMAC_BASE 0x044 38 #define CCU_AXI_PCIE_M_BASE 0x048 39 #define CCU_AXI_PCIE_S_BASE 0x04C 40 #define CCU_AXI_USB_BASE 0x050 41 #define CCU_AXI_HWA_BASE 0x054 42 #define CCU_AXI_SRAM_BASE 0x058 43 44 #define CCU_SYS_SATA_REF_BASE 0x060 45 #define CCU_SYS_APB_BASE 0x064 46 #define CCU_SYS_GMAC0_BASE 0x068 47 #define CCU_SYS_GMAC1_BASE 0x06C 48 #define CCU_SYS_XGMAC_BASE 0x070 49 #define CCU_SYS_USB_BASE 0x074 50 #define CCU_SYS_PVT_BASE 0x078 51 #define CCU_SYS_HWA_BASE 0x07C 52 #define CCU_SYS_UART_BASE 0x084 53 #define CCU_SYS_TIMER0_BASE 0x088 54 #define CCU_SYS_TIMER1_BASE 0x08C 55 #define CCU_SYS_TIMER2_BASE 0x090 56 #define CCU_SYS_WDT_BASE 0x150 57 58 #define CCU_DIV_VAR_INFO(_id, _name, _pname, _base, _width, _flags, _features) \ 59 { \ 60 .id = _id, \ 61 .name = _name, \ 62 .parent_name = _pname, \ 63 .base = _base, \ 64 .type = CCU_DIV_VAR, \ 65 .width = _width, \ 66 .flags = _flags, \ 67 .features = _features \ 68 } 69 70 #define CCU_DIV_GATE_INFO(_id, _name, _pname, _base, _divider) \ 71 { \ 72 .id = _id, \ 73 .name = _name, \ 74 .parent_name = _pname, \ 75 .base = _base, \ 76 .type = CCU_DIV_GATE, \ 77 .divider = _divider \ 78 } 79 80 #define CCU_DIV_BUF_INFO(_id, _name, _pname, _base, _flags) \ 81 { \ 82 .id = _id, \ 83 .name = _name, \ 84 .parent_name = _pname, \ 85 .base = _base, \ 86 .type = CCU_DIV_BUF, \ 87 .flags = _flags \ 88 } 89 90 #define CCU_DIV_FIXED_INFO(_id, _name, _pname, _divider) \ 91 { \ 92 .id = _id, \ 93 .name = _name, \ 94 .parent_name = _pname, \ 95 .type = CCU_DIV_FIXED, \ 96 .divider = _divider \ 97 } 98 99 struct ccu_div_info { 100 unsigned int id; 101 const char *name; 102 const char *parent_name; 103 unsigned int base; 104 enum ccu_div_type type; 105 union { 106 unsigned int width; 107 unsigned int divider; 108 }; 109 unsigned long flags; 110 unsigned long features; 111 }; 112 113 struct ccu_div_data { 114 struct device_node *np; 115 struct regmap *sys_regs; 116 117 unsigned int divs_num; 118 const struct ccu_div_info *divs_info; 119 struct ccu_div **divs; 120 121 struct ccu_rst *rsts; 122 }; 123 124 /* 125 * AXI Main Interconnect (axi_main_clk) and DDR AXI-bus (axi_ddr_clk) clocks 126 * must be left enabled in any case, since former one is responsible for 127 * clocking a bus between CPU cores and the rest of the SoC components, while 128 * the later is clocking the AXI-bus between DDR controller and the Main 129 * Interconnect. So should any of these clocks get to be disabled, the system 130 * will literally stop working. That's why we marked them as critical. 131 */ 132 static const struct ccu_div_info axi_info[] = { 133 CCU_DIV_VAR_INFO(CCU_AXI_MAIN_CLK, "axi_main_clk", "pcie_clk", 134 CCU_AXI_MAIN_BASE, 4, 135 CLK_IS_CRITICAL, CCU_DIV_RESET_DOMAIN), 136 CCU_DIV_VAR_INFO(CCU_AXI_DDR_CLK, "axi_ddr_clk", "sata_clk", 137 CCU_AXI_DDR_BASE, 4, 138 CLK_IS_CRITICAL | CLK_SET_RATE_GATE, 139 CCU_DIV_RESET_DOMAIN), 140 CCU_DIV_VAR_INFO(CCU_AXI_SATA_CLK, "axi_sata_clk", "sata_clk", 141 CCU_AXI_SATA_BASE, 4, 142 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 143 CCU_DIV_VAR_INFO(CCU_AXI_GMAC0_CLK, "axi_gmac0_clk", "eth_clk", 144 CCU_AXI_GMAC0_BASE, 4, 145 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 146 CCU_DIV_VAR_INFO(CCU_AXI_GMAC1_CLK, "axi_gmac1_clk", "eth_clk", 147 CCU_AXI_GMAC1_BASE, 4, 148 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 149 CCU_DIV_VAR_INFO(CCU_AXI_XGMAC_CLK, "axi_xgmac_clk", "eth_clk", 150 CCU_AXI_XGMAC_BASE, 4, 151 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 152 CCU_DIV_VAR_INFO(CCU_AXI_PCIE_M_CLK, "axi_pcie_m_clk", "pcie_clk", 153 CCU_AXI_PCIE_M_BASE, 4, 154 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 155 CCU_DIV_VAR_INFO(CCU_AXI_PCIE_S_CLK, "axi_pcie_s_clk", "pcie_clk", 156 CCU_AXI_PCIE_S_BASE, 4, 157 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 158 CCU_DIV_VAR_INFO(CCU_AXI_USB_CLK, "axi_usb_clk", "sata_clk", 159 CCU_AXI_USB_BASE, 4, 160 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 161 CCU_DIV_VAR_INFO(CCU_AXI_HWA_CLK, "axi_hwa_clk", "sata_clk", 162 CCU_AXI_HWA_BASE, 4, 163 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN), 164 CCU_DIV_VAR_INFO(CCU_AXI_SRAM_CLK, "axi_sram_clk", "eth_clk", 165 CCU_AXI_SRAM_BASE, 4, 166 CLK_SET_RATE_GATE, CCU_DIV_RESET_DOMAIN) 167 }; 168 169 /* 170 * APB-bus clock is marked as critical since it's a main communication bus 171 * for the SoC devices registers IO-operations. 172 */ 173 static const struct ccu_div_info sys_info[] = { 174 CCU_DIV_VAR_INFO(CCU_SYS_SATA_CLK, "sys_sata_clk", 175 "sata_clk", CCU_SYS_SATA_REF_BASE, 4, 176 CLK_SET_RATE_GATE, 177 CCU_DIV_SKIP_ONE | CCU_DIV_LOCK_SHIFTED | 178 CCU_DIV_RESET_DOMAIN), 179 CCU_DIV_BUF_INFO(CCU_SYS_SATA_REF_CLK, "sys_sata_ref_clk", 180 "sys_sata_clk", CCU_SYS_SATA_REF_BASE, 181 CLK_SET_RATE_PARENT), 182 CCU_DIV_VAR_INFO(CCU_SYS_APB_CLK, "sys_apb_clk", 183 "pcie_clk", CCU_SYS_APB_BASE, 5, 184 CLK_IS_CRITICAL, CCU_DIV_BASIC | CCU_DIV_RESET_DOMAIN), 185 CCU_DIV_GATE_INFO(CCU_SYS_GMAC0_TX_CLK, "sys_gmac0_tx_clk", 186 "eth_clk", CCU_SYS_GMAC0_BASE, 5), 187 CCU_DIV_FIXED_INFO(CCU_SYS_GMAC0_PTP_CLK, "sys_gmac0_ptp_clk", 188 "eth_clk", 10), 189 CCU_DIV_GATE_INFO(CCU_SYS_GMAC1_TX_CLK, "sys_gmac1_tx_clk", 190 "eth_clk", CCU_SYS_GMAC1_BASE, 5), 191 CCU_DIV_FIXED_INFO(CCU_SYS_GMAC1_PTP_CLK, "sys_gmac1_ptp_clk", 192 "eth_clk", 10), 193 CCU_DIV_GATE_INFO(CCU_SYS_XGMAC_CLK, "sys_xgmac_clk", 194 "eth_clk", CCU_SYS_XGMAC_BASE, 1), 195 CCU_DIV_FIXED_INFO(CCU_SYS_XGMAC_REF_CLK, "sys_xgmac_ref_clk", 196 "sys_xgmac_clk", 8), 197 CCU_DIV_FIXED_INFO(CCU_SYS_XGMAC_PTP_CLK, "sys_xgmac_ptp_clk", 198 "sys_xgmac_clk", 8), 199 CCU_DIV_GATE_INFO(CCU_SYS_USB_CLK, "sys_usb_clk", 200 "eth_clk", CCU_SYS_USB_BASE, 10), 201 CCU_DIV_VAR_INFO(CCU_SYS_PVT_CLK, "sys_pvt_clk", 202 "ref_clk", CCU_SYS_PVT_BASE, 5, 203 CLK_SET_RATE_GATE, 0), 204 CCU_DIV_VAR_INFO(CCU_SYS_HWA_CLK, "sys_hwa_clk", 205 "sata_clk", CCU_SYS_HWA_BASE, 4, 206 CLK_SET_RATE_GATE, 0), 207 CCU_DIV_VAR_INFO(CCU_SYS_UART_CLK, "sys_uart_clk", 208 "eth_clk", CCU_SYS_UART_BASE, 17, 209 CLK_SET_RATE_GATE, 0), 210 CCU_DIV_FIXED_INFO(CCU_SYS_I2C1_CLK, "sys_i2c1_clk", 211 "eth_clk", 10), 212 CCU_DIV_FIXED_INFO(CCU_SYS_I2C2_CLK, "sys_i2c2_clk", 213 "eth_clk", 10), 214 CCU_DIV_FIXED_INFO(CCU_SYS_GPIO_CLK, "sys_gpio_clk", 215 "ref_clk", 25), 216 CCU_DIV_VAR_INFO(CCU_SYS_TIMER0_CLK, "sys_timer0_clk", 217 "ref_clk", CCU_SYS_TIMER0_BASE, 17, 218 CLK_SET_RATE_GATE, CCU_DIV_BASIC), 219 CCU_DIV_VAR_INFO(CCU_SYS_TIMER1_CLK, "sys_timer1_clk", 220 "ref_clk", CCU_SYS_TIMER1_BASE, 17, 221 CLK_SET_RATE_GATE, CCU_DIV_BASIC), 222 CCU_DIV_VAR_INFO(CCU_SYS_TIMER2_CLK, "sys_timer2_clk", 223 "ref_clk", CCU_SYS_TIMER2_BASE, 17, 224 CLK_SET_RATE_GATE, CCU_DIV_BASIC), 225 CCU_DIV_VAR_INFO(CCU_SYS_WDT_CLK, "sys_wdt_clk", 226 "eth_clk", CCU_SYS_WDT_BASE, 17, 227 CLK_SET_RATE_GATE, CCU_DIV_SKIP_ONE_TO_THREE) 228 }; 229 230 static struct ccu_div_data *axi_data; 231 static struct ccu_div_data *sys_data; 232 233 static void ccu_div_set_data(struct ccu_div_data *data) 234 { 235 struct device_node *np = data->np; 236 237 if (of_device_is_compatible(np, "baikal,bt1-ccu-axi")) 238 axi_data = data; 239 else if (of_device_is_compatible(np, "baikal,bt1-ccu-sys")) 240 sys_data = data; 241 else 242 pr_err("Invalid DT node '%s' specified\n", of_node_full_name(np)); 243 } 244 245 static struct ccu_div_data *ccu_div_get_data(struct device_node *np) 246 { 247 if (of_device_is_compatible(np, "baikal,bt1-ccu-axi")) 248 return axi_data; 249 else if (of_device_is_compatible(np, "baikal,bt1-ccu-sys")) 250 return sys_data; 251 252 pr_err("Invalid DT node '%s' specified\n", of_node_full_name(np)); 253 254 return NULL; 255 } 256 257 static struct ccu_div *ccu_div_find_desc(struct ccu_div_data *data, 258 unsigned int clk_id) 259 { 260 int idx; 261 262 for (idx = 0; idx < data->divs_num; ++idx) { 263 if (data->divs_info[idx].id == clk_id) 264 return data->divs[idx]; 265 } 266 267 return ERR_PTR(-EINVAL); 268 } 269 270 static struct ccu_div_data *ccu_div_create_data(struct device_node *np) 271 { 272 struct ccu_div_data *data; 273 int ret; 274 275 data = kzalloc(sizeof(*data), GFP_KERNEL); 276 if (!data) 277 return ERR_PTR(-ENOMEM); 278 279 data->np = np; 280 if (of_device_is_compatible(np, "baikal,bt1-ccu-axi")) { 281 data->divs_num = ARRAY_SIZE(axi_info); 282 data->divs_info = axi_info; 283 } else if (of_device_is_compatible(np, "baikal,bt1-ccu-sys")) { 284 data->divs_num = ARRAY_SIZE(sys_info); 285 data->divs_info = sys_info; 286 } else { 287 pr_err("Incompatible DT node '%s' specified\n", 288 of_node_full_name(np)); 289 ret = -EINVAL; 290 goto err_kfree_data; 291 } 292 293 data->divs = kcalloc(data->divs_num, sizeof(*data->divs), GFP_KERNEL); 294 if (!data->divs) { 295 ret = -ENOMEM; 296 goto err_kfree_data; 297 } 298 299 return data; 300 301 err_kfree_data: 302 kfree(data); 303 304 return ERR_PTR(ret); 305 } 306 307 static void ccu_div_free_data(struct ccu_div_data *data) 308 { 309 kfree(data->divs); 310 311 kfree(data); 312 } 313 314 static int ccu_div_find_sys_regs(struct ccu_div_data *data) 315 { 316 data->sys_regs = syscon_node_to_regmap(data->np->parent); 317 if (IS_ERR(data->sys_regs)) { 318 pr_err("Failed to find syscon regs for '%s'\n", 319 of_node_full_name(data->np)); 320 return PTR_ERR(data->sys_regs); 321 } 322 323 return 0; 324 } 325 326 static struct clk_hw *ccu_div_of_clk_hw_get(struct of_phandle_args *clkspec, 327 void *priv) 328 { 329 struct ccu_div_data *data = priv; 330 struct ccu_div *div; 331 unsigned int clk_id; 332 333 clk_id = clkspec->args[0]; 334 div = ccu_div_find_desc(data, clk_id); 335 if (IS_ERR(div)) { 336 if (div != ERR_PTR(-EPROBE_DEFER)) 337 pr_info("Invalid clock ID %d specified\n", clk_id); 338 339 return ERR_CAST(div); 340 } 341 342 return ccu_div_get_clk_hw(div); 343 } 344 345 static int ccu_div_clk_register(struct ccu_div_data *data, bool defer) 346 { 347 int idx, ret; 348 349 for (idx = 0; idx < data->divs_num; ++idx) { 350 const struct ccu_div_info *info = &data->divs_info[idx]; 351 struct ccu_div_init_data init = {0}; 352 353 if (!!(info->features & CCU_DIV_BASIC) ^ defer) { 354 if (!data->divs[idx]) 355 data->divs[idx] = ERR_PTR(-EPROBE_DEFER); 356 357 continue; 358 } 359 360 init.id = info->id; 361 init.name = info->name; 362 init.parent_name = info->parent_name; 363 init.np = data->np; 364 init.type = info->type; 365 init.flags = info->flags; 366 init.features = info->features; 367 368 if (init.type == CCU_DIV_VAR) { 369 init.base = info->base; 370 init.sys_regs = data->sys_regs; 371 init.width = info->width; 372 } else if (init.type == CCU_DIV_GATE) { 373 init.base = info->base; 374 init.sys_regs = data->sys_regs; 375 init.divider = info->divider; 376 } else if (init.type == CCU_DIV_BUF) { 377 init.base = info->base; 378 init.sys_regs = data->sys_regs; 379 } else { 380 init.divider = info->divider; 381 } 382 383 data->divs[idx] = ccu_div_hw_register(&init); 384 if (IS_ERR(data->divs[idx])) { 385 ret = PTR_ERR(data->divs[idx]); 386 pr_err("Couldn't register divider '%s' hw\n", 387 init.name); 388 goto err_hw_unregister; 389 } 390 } 391 392 return 0; 393 394 err_hw_unregister: 395 for (--idx; idx >= 0; --idx) { 396 if (!!(data->divs_info[idx].features & CCU_DIV_BASIC) ^ defer) 397 continue; 398 399 ccu_div_hw_unregister(data->divs[idx]); 400 } 401 402 return ret; 403 } 404 405 static void ccu_div_clk_unregister(struct ccu_div_data *data, bool defer) 406 { 407 int idx; 408 409 /* Uninstall only the clocks registered on the specfied stage */ 410 for (idx = 0; idx < data->divs_num; ++idx) { 411 if (!!(data->divs_info[idx].features & CCU_DIV_BASIC) ^ defer) 412 continue; 413 414 ccu_div_hw_unregister(data->divs[idx]); 415 } 416 } 417 418 static int ccu_div_of_register(struct ccu_div_data *data) 419 { 420 int ret; 421 422 ret = of_clk_add_hw_provider(data->np, ccu_div_of_clk_hw_get, data); 423 if (ret) { 424 pr_err("Couldn't register dividers '%s' clock provider\n", 425 of_node_full_name(data->np)); 426 } 427 428 return ret; 429 } 430 431 static int ccu_div_rst_register(struct ccu_div_data *data) 432 { 433 struct ccu_rst_init_data init = {0}; 434 435 init.sys_regs = data->sys_regs; 436 init.np = data->np; 437 438 data->rsts = ccu_rst_hw_register(&init); 439 if (IS_ERR(data->rsts)) { 440 pr_err("Couldn't register divider '%s' reset controller\n", 441 of_node_full_name(data->np)); 442 return PTR_ERR(data->rsts); 443 } 444 445 return 0; 446 } 447 448 static int ccu_div_probe(struct platform_device *pdev) 449 { 450 struct ccu_div_data *data; 451 int ret; 452 453 data = ccu_div_get_data(dev_of_node(&pdev->dev)); 454 if (!data) 455 return -EINVAL; 456 457 ret = ccu_div_clk_register(data, false); 458 if (ret) 459 return ret; 460 461 ret = ccu_div_rst_register(data); 462 if (ret) 463 goto err_clk_unregister; 464 465 return 0; 466 467 err_clk_unregister: 468 ccu_div_clk_unregister(data, false); 469 470 return ret; 471 } 472 473 static const struct of_device_id ccu_div_of_match[] = { 474 { .compatible = "baikal,bt1-ccu-axi" }, 475 { .compatible = "baikal,bt1-ccu-sys" }, 476 { } 477 }; 478 479 static struct platform_driver ccu_div_driver = { 480 .probe = ccu_div_probe, 481 .driver = { 482 .name = "clk-ccu-div", 483 .of_match_table = ccu_div_of_match, 484 .suppress_bind_attrs = true, 485 }, 486 }; 487 builtin_platform_driver(ccu_div_driver); 488 489 static __init void ccu_div_init(struct device_node *np) 490 { 491 struct ccu_div_data *data; 492 int ret; 493 494 data = ccu_div_create_data(np); 495 if (IS_ERR(data)) 496 return; 497 498 ret = ccu_div_find_sys_regs(data); 499 if (ret) 500 goto err_free_data; 501 502 ret = ccu_div_clk_register(data, true); 503 if (ret) 504 goto err_free_data; 505 506 ret = ccu_div_of_register(data); 507 if (ret) 508 goto err_clk_unregister; 509 510 ccu_div_set_data(data); 511 512 return; 513 514 err_clk_unregister: 515 ccu_div_clk_unregister(data, true); 516 517 err_free_data: 518 ccu_div_free_data(data); 519 } 520 CLK_OF_DECLARE_DRIVER(ccu_axi, "baikal,bt1-ccu-axi", ccu_div_init); 521 CLK_OF_DECLARE_DRIVER(ccu_sys, "baikal,bt1-ccu-sys", ccu_div_init); 522