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