Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'tenstorrent-clk-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux into clk-tenstorrent

Pull Tenstorrent clk driver updates from Drew Fustini:

- Clock and reset controllers (e.g. PRCM) in the Tenstorrent Atlantis SoC

* tag 'tenstorrent-clk-for-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux:
clk: tenstorrent: Add Atlantis clock controller driver
reset: tenstorrent: Add reset controller for Atlantis
dt-bindings: clk: tenstorrent: Add tenstorrent,atlantis-prcm-rcpu

+1235
+54
Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/clock/tenstorrent,atlantis-prcm-rcpu.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Tenstorrent Atlantis PRCM (Power, Reset, Clock Management) Module 8 + 9 + maintainers: 10 + - Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com> 11 + 12 + description: 13 + Multifunctional register block found in Tenstorrent Atlantis SoC whose main 14 + function is to control clocks and resets. This block is instantiated multiple 15 + times in the SoC, each block controls clock and resets for a different 16 + subsystem. RCPU prcm serves low speed IO interfaces. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - tenstorrent,atlantis-prcm-rcpu 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + clocks: 27 + maxItems: 1 28 + 29 + "#clock-cells": 30 + const: 1 31 + description: 32 + See <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h> for valid indices. 33 + 34 + "#reset-cells": 35 + const: 1 36 + 37 + required: 38 + - compatible 39 + - reg 40 + - clocks 41 + - "#clock-cells" 42 + - "#reset-cells" 43 + 44 + additionalProperties: false 45 + 46 + examples: 47 + - | 48 + clock-controller@a8000000 { 49 + compatible = "tenstorrent,atlantis-prcm-rcpu"; 50 + reg = <0xa8000000 0x10000>; 51 + clocks = <&osc_24m>; 52 + #clock-cells = <1>; 53 + #reset-cells = <1>; 54 + };
+4
MAINTAINERS
··· 22802 22802 L: linux-riscv@lists.infradead.org 22803 22803 S: Maintained 22804 22804 T: git https://github.com/tenstorrent/linux.git 22805 + F: Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml 22805 22806 F: Documentation/devicetree/bindings/riscv/tenstorrent.yaml 22806 22807 F: arch/riscv/boot/dts/tenstorrent/ 22808 + F: drivers/clk/tenstorrent/ 22809 + F: drivers/reset/reset-tenstorrent-atlantis.c 22810 + F: include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h 22807 22811 22808 22812 RISC-V THEAD SoC SUPPORT 22809 22813 M: Drew Fustini <fustini@kernel.org>
+1
drivers/clk/Kconfig
··· 531 531 source "drivers/clk/sunxi/Kconfig" 532 532 source "drivers/clk/sunxi-ng/Kconfig" 533 533 source "drivers/clk/tegra/Kconfig" 534 + source "drivers/clk/tenstorrent/Kconfig" 534 535 source "drivers/clk/thead/Kconfig" 535 536 source "drivers/clk/stm32/Kconfig" 536 537 source "drivers/clk/ti/Kconfig"
+1
drivers/clk/Makefile
··· 155 155 obj-$(CONFIG_ARCH_SUNXI) += sunxi/ 156 156 obj-y += sunxi-ng/ 157 157 obj-$(CONFIG_ARCH_TEGRA) += tegra/ 158 + obj-y += tenstorrent/ 158 159 obj-$(CONFIG_ARCH_THEAD) += thead/ 159 160 obj-y += ti/ 160 161 obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
+14
drivers/clk/tenstorrent/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + config TENSTORRENT_ATLANTIS_PRCM 4 + tristate "Support for Tenstorrent Atlantis PRCM Clock Controller" 5 + depends on ARCH_TENSTORRENT || COMPILE_TEST 6 + default ARCH_TENSTORRENT 7 + select REGMAP_MMIO 8 + select AUXILIARY_BUS 9 + select MFD_SYSCON 10 + help 11 + Say yes here to support the different clock 12 + controllers found in the Tenstorrent Atlantis SoC. 13 + This includes the clocks from the RCPU, HSIO, MMIO 14 + and PCIE domain.
+3
drivers/clk/tenstorrent/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + obj-$(CONFIG_TENSTORRENT_ATLANTIS_PRCM) += atlantis-prcm.o
+870
drivers/clk/tenstorrent/atlantis-prcm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Tenstorrent Atlantis PRCM Clock Driver 4 + * 5 + * Copyright (c) 2026 Tenstorrent 6 + */ 7 + 8 + #include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h> 9 + #include <linux/auxiliary_bus.h> 10 + #include <linux/bitfield.h> 11 + #include <linux/clk-provider.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/regmap.h> 14 + #include <linux/slab.h> 15 + 16 + /* RCPU Clock Register Offsets */ 17 + #define PLL_RCPU_CFG_REG 0x0000 18 + #define PLL_NOCC_CFG_REG 0x0004 19 + #define NOCC_CLK_CFG_REG 0x0008 20 + #define RCPU_DIV_CFG_REG 0x000C 21 + #define RCPU_BLK_CG_REG 0x0014 22 + #define LSIO_BLK_CG_REG 0x0018 23 + #define PLL_RCPU_EN_REG 0x011C 24 + #define PLL_NOCC_EN_REG 0x0120 25 + #define BUS_CG_REG 0x01FC 26 + 27 + /* PLL Bit Definitions */ 28 + #define PLL_CFG_EN_BIT BIT(0) 29 + #define PLL_CFG_BYPASS_BIT BIT(1) 30 + #define PLL_CFG_REFDIV_MASK GENMASK(7, 2) 31 + #define PLL_CFG_REFDIV_SHIFT 2 32 + #define PLL_CFG_POSTDIV1_MASK GENMASK(10, 8) 33 + #define PLL_CFG_POSTDIV1_SHIFT 8 34 + #define PLL_CFG_POSTDIV2_MASK GENMASK(13, 11) 35 + #define PLL_CFG_POSTDIV2_SHIFT 11 36 + #define PLL_CFG_FBDIV_MASK GENMASK(25, 14) 37 + #define PLL_CFG_FBDIV_SHIFT 14 38 + #define PLL_CFG_LKDT_BIT BIT(30) 39 + #define PLL_CFG_LOCK_BIT BIT(31) 40 + #define PLL_LOCK_TIMEOUT_US 1000 41 + #define PLL_BYPASS_WAIT_US 500 42 + 43 + struct atlantis_clk_common { 44 + int clkid; 45 + struct regmap *regmap; 46 + struct clk_hw hw; 47 + }; 48 + 49 + static inline struct atlantis_clk_common * 50 + hw_to_atlantis_clk_common(struct clk_hw *hw) 51 + { 52 + return container_of(hw, struct atlantis_clk_common, hw); 53 + } 54 + 55 + struct atlantis_clk_mux_config { 56 + u8 shift; 57 + u8 width; 58 + u32 reg_offset; 59 + }; 60 + 61 + struct atlantis_clk_mux { 62 + struct atlantis_clk_common common; 63 + struct atlantis_clk_mux_config config; 64 + }; 65 + 66 + struct atlantis_clk_gate_config { 67 + u32 reg_offset; 68 + u32 enable; 69 + }; 70 + 71 + struct atlantis_clk_gate { 72 + struct atlantis_clk_common common; 73 + struct atlantis_clk_gate_config config; 74 + }; 75 + 76 + struct atlantis_clk_divider_config { 77 + u8 shift; 78 + u8 width; 79 + u32 flags; 80 + u32 reg_offset; 81 + }; 82 + 83 + struct atlantis_clk_divider { 84 + struct atlantis_clk_common common; 85 + struct atlantis_clk_divider_config config; 86 + }; 87 + 88 + struct atlantis_clk_pll_config { 89 + u32 tbl_num; 90 + u32 reg_offset; 91 + u32 en_reg_offset; 92 + u32 cg_reg_offset; 93 + u32 cg_reg_enable; 94 + }; 95 + 96 + /* Models a PLL with Bypass Functionality and Enable Bit + an optional Gate Clock at it's output */ 97 + struct atlantis_clk_pll { 98 + struct atlantis_clk_common common; 99 + struct atlantis_clk_pll_config config; 100 + }; 101 + 102 + struct atlantis_clk_gate_shared_config { 103 + u32 reg_offset; 104 + u32 enable; 105 + unsigned int *share_count; 106 + spinlock_t *refcount_lock; 107 + }; 108 + 109 + struct atlantis_clk_gate_shared { 110 + struct atlantis_clk_common common; 111 + struct atlantis_clk_gate_shared_config config; 112 + }; 113 + 114 + struct atlantis_clk_fixed_factor_config { 115 + unsigned int mult; 116 + unsigned int div; 117 + }; 118 + 119 + struct atlantis_clk_fixed_factor { 120 + struct atlantis_clk_fixed_factor_config config; 121 + struct atlantis_clk_common common; 122 + }; 123 + 124 + static inline struct atlantis_clk_mux *hw_to_atlantis_clk_mux(struct clk_hw *hw) 125 + { 126 + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 127 + 128 + return container_of(common, struct atlantis_clk_mux, common); 129 + } 130 + 131 + static inline struct atlantis_clk_gate * 132 + hw_to_atlantis_clk_gate(struct clk_hw *hw) 133 + { 134 + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 135 + 136 + return container_of(common, struct atlantis_clk_gate, common); 137 + } 138 + 139 + static inline struct atlantis_clk_divider * 140 + hw_to_atlantis_clk_divider(struct clk_hw *hw) 141 + { 142 + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 143 + 144 + return container_of(common, struct atlantis_clk_divider, common); 145 + } 146 + 147 + static inline struct atlantis_clk_pll *hw_to_atlantis_pll(struct clk_hw *hw) 148 + { 149 + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 150 + 151 + return container_of(common, struct atlantis_clk_pll, common); 152 + } 153 + 154 + static inline struct atlantis_clk_gate_shared * 155 + hw_to_atlantis_clk_gate_shared(struct clk_hw *hw) 156 + { 157 + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 158 + 159 + return container_of(common, struct atlantis_clk_gate_shared, common); 160 + } 161 + 162 + static inline struct atlantis_clk_fixed_factor * 163 + hw_to_atlantis_clk_fixed_factor(struct clk_hw *hw) 164 + { 165 + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 166 + 167 + return container_of(common, struct atlantis_clk_fixed_factor, common); 168 + } 169 + 170 + static u8 atlantis_clk_mux_get_parent(struct clk_hw *hw) 171 + { 172 + struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); 173 + u32 val; 174 + 175 + regmap_read(mux->common.regmap, mux->config.reg_offset, &val); 176 + val >>= mux->config.shift; 177 + val &= (BIT(mux->config.width) - 1); 178 + 179 + return val; 180 + } 181 + 182 + static int atlantis_clk_mux_set_parent(struct clk_hw *hw, u8 index) 183 + { 184 + struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); 185 + u32 val = index; 186 + 187 + return regmap_update_bits(mux->common.regmap, mux->config.reg_offset, 188 + (BIT(mux->config.width) - 1) << mux->config.shift, 189 + val << mux->config.shift); 190 + } 191 + 192 + static int atlantis_clk_mux_determine_rate(struct clk_hw *hw, 193 + struct clk_rate_request *req) 194 + { 195 + return clk_mux_determine_rate_flags(hw, req, hw->init->flags); 196 + } 197 + 198 + static const struct clk_ops atlantis_clk_mux_ops = { 199 + .get_parent = atlantis_clk_mux_get_parent, 200 + .set_parent = atlantis_clk_mux_set_parent, 201 + .determine_rate = atlantis_clk_mux_determine_rate, 202 + }; 203 + 204 + static int atlantis_clk_gate_endisable(struct clk_hw *hw, int enable) 205 + { 206 + struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); 207 + 208 + if (enable) 209 + return regmap_set_bits(gate->common.regmap, 210 + gate->config.reg_offset, 211 + gate->config.enable); 212 + else 213 + return regmap_clear_bits(gate->common.regmap, 214 + gate->config.reg_offset, 215 + gate->config.enable); 216 + } 217 + 218 + static int atlantis_clk_gate_enable(struct clk_hw *hw) 219 + { 220 + return atlantis_clk_gate_endisable(hw, 1); 221 + } 222 + 223 + static void atlantis_clk_gate_disable(struct clk_hw *hw) 224 + { 225 + atlantis_clk_gate_endisable(hw, 0); 226 + } 227 + 228 + static int atlantis_clk_gate_is_enabled(struct clk_hw *hw) 229 + { 230 + struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); 231 + 232 + return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); 233 + } 234 + 235 + static const struct clk_ops atlantis_clk_gate_ops = { 236 + .enable = atlantis_clk_gate_enable, 237 + .disable = atlantis_clk_gate_disable, 238 + .is_enabled = atlantis_clk_gate_is_enabled, 239 + }; 240 + 241 + static unsigned long atlantis_clk_divider_recalc_rate(struct clk_hw *hw, 242 + unsigned long parent_rate) 243 + { 244 + struct atlantis_clk_divider *divider = hw_to_atlantis_clk_divider(hw); 245 + u32 val; 246 + 247 + regmap_read(divider->common.regmap, divider->config.reg_offset, &val); 248 + 249 + val >>= divider->config.shift; 250 + val &= ((1 << (divider->config.width)) - 1); 251 + 252 + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); 253 + } 254 + 255 + static const struct clk_ops atlantis_clk_divider_ops = { 256 + .recalc_rate = atlantis_clk_divider_recalc_rate, 257 + }; 258 + 259 + static unsigned long 260 + atlantis_clk_fixed_factor_recalc_rate(struct clk_hw *hw, 261 + unsigned long parent_rate) 262 + { 263 + struct atlantis_clk_fixed_factor *factor = 264 + hw_to_atlantis_clk_fixed_factor(hw); 265 + unsigned long long rate; 266 + 267 + rate = (unsigned long long)parent_rate * factor->config.mult; 268 + do_div(rate, factor->config.div); 269 + 270 + return (unsigned long)rate; 271 + } 272 + 273 + static const struct clk_ops atlantis_clk_fixed_factor_ops = { 274 + .recalc_rate = atlantis_clk_fixed_factor_recalc_rate, 275 + }; 276 + 277 + static int atlantis_clk_pll_is_enabled(struct clk_hw *hw) 278 + { 279 + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 280 + u32 val, en_val, cg_val; 281 + 282 + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); 283 + regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); 284 + regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); 285 + 286 + /* Check if PLL is powered on, locked, not bypassed and Gate clk is enabled */ 287 + return !!(en_val & PLL_CFG_EN_BIT) && !!(val & PLL_CFG_LOCK_BIT) && 288 + (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) && 289 + !(val & PLL_CFG_BYPASS_BIT); 290 + } 291 + 292 + static int atlantis_clk_pll_enable(struct clk_hw *hw) 293 + { 294 + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 295 + u32 val, en_val, cg_val; 296 + int ret; 297 + 298 + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); 299 + regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); 300 + regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); 301 + 302 + /* Check if PLL is already enabled, locked, not bypassed and Gate clk is enabled */ 303 + if ((en_val & PLL_CFG_EN_BIT) && (val & PLL_CFG_LOCK_BIT) && 304 + (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) && 305 + !(val & PLL_CFG_BYPASS_BIT)) { 306 + return 0; 307 + } 308 + 309 + /* Step 1: Set bypass mode first */ 310 + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, 311 + PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); 312 + 313 + /* Step 2: Enable PLL (clear then set power bit) */ 314 + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, 315 + PLL_CFG_EN_BIT, 0); 316 + 317 + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, 318 + PLL_CFG_EN_BIT, PLL_CFG_EN_BIT); 319 + 320 + /* Step 3: Wait for PLL lock */ 321 + ret = regmap_read_poll_timeout(pll->common.regmap, 322 + pll->config.reg_offset, val, 323 + val & PLL_CFG_LOCK_BIT, 324 + PLL_BYPASS_WAIT_US, PLL_LOCK_TIMEOUT_US); 325 + if (ret) { 326 + pr_err("PLL failed to lock within timeout\n"); 327 + return ret; 328 + } 329 + 330 + /* Step 4: Switch from bypass to PLL output */ 331 + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, 332 + PLL_CFG_BYPASS_BIT, 0); 333 + 334 + /* Enable Gate clk at PLL Output */ 335 + return regmap_update_bits(pll->common.regmap, pll->config.cg_reg_offset, 336 + pll->config.cg_reg_enable, 337 + pll->config.cg_reg_enable); 338 + } 339 + 340 + static void atlantis_clk_pll_disable(struct clk_hw *hw) 341 + { 342 + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 343 + 344 + /* Step 1: Switch to bypass mode before disabling */ 345 + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, 346 + PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); 347 + /* Step 2: Power down PLL */ 348 + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, 349 + PLL_CFG_EN_BIT, 0); 350 + } 351 + 352 + static unsigned long atlantis_clk_pll_recalc_rate(struct clk_hw *hw, 353 + unsigned long parent_rate) 354 + { 355 + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 356 + 357 + u32 val, refdiv, fbdiv, postdiv1, postdiv2; 358 + u64 fout; 359 + 360 + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); 361 + 362 + if (val & PLL_CFG_BYPASS_BIT) 363 + return parent_rate; 364 + 365 + refdiv = FIELD_GET(PLL_CFG_REFDIV_MASK, val); 366 + fbdiv = FIELD_GET(PLL_CFG_FBDIV_MASK, val); 367 + postdiv1 = FIELD_GET(PLL_CFG_POSTDIV1_MASK, val); 368 + postdiv2 = FIELD_GET(PLL_CFG_POSTDIV2_MASK, val); 369 + 370 + if (!refdiv) 371 + refdiv = 1; 372 + if (!postdiv1) 373 + postdiv1 = 1; 374 + if (!postdiv2) 375 + postdiv2 = 1; 376 + if (!fbdiv) 377 + return 0; 378 + 379 + fout = div64_u64((u64)parent_rate * fbdiv, 380 + refdiv * postdiv1 * postdiv2); 381 + 382 + return fout; 383 + } 384 + 385 + static const struct clk_ops atlantis_clk_pll_ops = { 386 + .enable = atlantis_clk_pll_enable, 387 + .disable = atlantis_clk_pll_disable, 388 + .recalc_rate = atlantis_clk_pll_recalc_rate, 389 + .is_enabled = atlantis_clk_pll_is_enabled, 390 + }; 391 + 392 + static int atlantis_clk_gate_shared_enable(struct clk_hw *hw) 393 + { 394 + struct atlantis_clk_gate_shared *gate = 395 + hw_to_atlantis_clk_gate_shared(hw); 396 + bool need_enable; 397 + 398 + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) 399 + { 400 + need_enable = (*gate->config.share_count)++ == 0; 401 + if (need_enable) { 402 + regmap_set_bits(gate->common.regmap, 403 + gate->config.reg_offset, 404 + gate->config.enable); 405 + } 406 + } 407 + 408 + if (need_enable) { 409 + if (!regmap_test_bits(gate->common.regmap, 410 + gate->config.reg_offset, 411 + gate->config.enable)) { 412 + pr_warn("%s: gate enable %d failed to enable\n", 413 + clk_hw_get_name(hw), gate->config.enable); 414 + return -EIO; 415 + } 416 + } 417 + 418 + return 0; 419 + } 420 + 421 + static void atlantis_clk_gate_shared_disable(struct clk_hw *hw) 422 + { 423 + struct atlantis_clk_gate_shared *gate = 424 + hw_to_atlantis_clk_gate_shared(hw); 425 + 426 + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) 427 + { 428 + if (WARN_ON(*gate->config.share_count == 0)) 429 + return; 430 + if (--(*gate->config.share_count) > 0) 431 + return; 432 + 433 + regmap_clear_bits(gate->common.regmap, 434 + gate->config.reg_offset, 435 + gate->config.enable); 436 + } 437 + } 438 + 439 + static int atlantis_clk_gate_shared_is_enabled(struct clk_hw *hw) 440 + { 441 + struct atlantis_clk_gate_shared *gate = 442 + hw_to_atlantis_clk_gate_shared(hw); 443 + 444 + return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); 445 + } 446 + 447 + static void atlantis_clk_gate_shared_disable_unused(struct clk_hw *hw) 448 + { 449 + struct atlantis_clk_gate_shared *gate = 450 + hw_to_atlantis_clk_gate_shared(hw); 451 + 452 + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) 453 + { 454 + if (*gate->config.share_count == 0) 455 + regmap_clear_bits(gate->common.regmap, 456 + gate->config.reg_offset, 457 + gate->config.enable); 458 + } 459 + } 460 + 461 + static const struct clk_ops atlantis_clk_gate_shared_ops = { 462 + .enable = atlantis_clk_gate_shared_enable, 463 + .disable = atlantis_clk_gate_shared_disable, 464 + .disable_unused = atlantis_clk_gate_shared_disable_unused, 465 + .is_enabled = atlantis_clk_gate_shared_is_enabled, 466 + }; 467 + 468 + #define ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, _cg_reg_offset, \ 469 + _cg_reg_enable) \ 470 + { \ 471 + .reg_offset = (_reg_offset), \ 472 + .en_reg_offset = (_en_reg_offset), \ 473 + .cg_reg_offset = (_cg_reg_offset), \ 474 + .cg_reg_enable = (_cg_reg_enable), \ 475 + } 476 + 477 + #define ATLANTIS_PLL_DEFINE(_clkid, _name, _parent, _reg_offset, \ 478 + _en_reg_offset, _cg_reg_offset, _cg_reg_enable, \ 479 + _flags) \ 480 + static struct atlantis_clk_pll _name = { \ 481 + .config = ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, \ 482 + _cg_reg_offset, _cg_reg_enable), \ 483 + .common = { .clkid = _clkid, \ 484 + .hw.init = CLK_HW_INIT_PARENTS_DATA( \ 485 + #_name, _parent, &atlantis_clk_pll_ops, \ 486 + _flags) }, \ 487 + } 488 + #define ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset) \ 489 + { \ 490 + .shift = _shift, .width = _width, .reg_offset = _reg_offset \ 491 + } 492 + 493 + #define ATLANTIS_MUX_DEFINE(_clkid, _name, _parents, _reg_offset, _shift, \ 494 + _width, _flags) \ 495 + static struct atlantis_clk_mux _name = { \ 496 + .config = ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset), \ 497 + .common = { .clkid = _clkid, \ 498 + .hw.init = CLK_HW_INIT_PARENTS_DATA( \ 499 + #_name, _parents, &atlantis_clk_mux_ops, \ 500 + _flags) } \ 501 + } 502 + 503 + #define ATLANTIS_DIVIDER_CONFIG(_shift, _width, _flags, _reg_offset) \ 504 + { \ 505 + .shift = _shift, .width = _width, .flags = _flags, \ 506 + .reg_offset = _reg_offset \ 507 + } 508 + 509 + #define ATLANTIS_DIVIDER_DEFINE(_clkid, _name, _parent, _reg_offset, _shift, \ 510 + _width, _divflags, _flags) \ 511 + static struct atlantis_clk_divider _name = { \ 512 + .config = ATLANTIS_DIVIDER_CONFIG(_shift, _width, _divflags, \ 513 + _reg_offset), \ 514 + .common = { .clkid = _clkid, \ 515 + .hw.init = CLK_HW_INIT_HW( \ 516 + #_name, &_parent.common.hw, \ 517 + &atlantis_clk_divider_ops, _flags) } \ 518 + } 519 + #define ATLANTIS_GATE_CONFIG(_enable, _reg_offset) \ 520 + { \ 521 + .enable = _enable, .reg_offset = _reg_offset \ 522 + } 523 + 524 + #define ATLANTIS_GATE_DEFINE(_clkid, _name, _parent, _reg_offset, _enable, \ 525 + _flags) \ 526 + static struct atlantis_clk_gate _name = { \ 527 + .config = ATLANTIS_GATE_CONFIG(_enable, _reg_offset), \ 528 + .common = { .clkid = _clkid, \ 529 + .hw.init = CLK_HW_INIT_HW( \ 530 + #_name, &_parent.common.hw, \ 531 + &atlantis_clk_gate_ops, _flags) } \ 532 + } 533 + #define ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, _share_count) \ 534 + { \ 535 + .reg_offset = _reg_offset, .enable = _enable, \ 536 + .share_count = _share_count, .refcount_lock = &refcount_lock \ 537 + } 538 + #define ATLANTIS_GATE_SHARED_DEFINE(_clkid, _name, _parent, _reg_offset, \ 539 + _enable, _share_count, _flags) \ 540 + static struct atlantis_clk_gate_shared _name = { \ 541 + .config = ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, \ 542 + _share_count), \ 543 + .common = { .clkid = _clkid, \ 544 + .hw.init = CLK_HW_INIT_HW( \ 545 + #_name, &_parent.common.hw, \ 546 + &atlantis_clk_gate_shared_ops, _flags) } \ 547 + } 548 + #define ATLANTIS_FIXED_FACTOR_DEFINE(_clkid, _name, _parent, _mult, _div, \ 549 + _flags) \ 550 + static struct atlantis_clk_fixed_factor _name = { \ 551 + .config = { .mult = _mult, .div = _div }, \ 552 + .common = { .clkid = _clkid, \ 553 + .hw.init = CLK_HW_INIT_HW( \ 554 + #_name, &_parent.common.hw, \ 555 + &atlantis_clk_fixed_factor_ops, _flags) } \ 556 + } 557 + 558 + static DEFINE_SPINLOCK(refcount_lock); /* Lock for refcount value accesses */ 559 + 560 + static const struct regmap_config atlantis_prcm_regmap_config = { 561 + .reg_bits = 32, 562 + .reg_stride = 4, 563 + .val_bits = 32, 564 + .max_register = 0xFFFC, 565 + .cache_type = REGCACHE_NONE, 566 + }; 567 + 568 + struct atlantis_prcm_data { 569 + struct clk_hw **hws; 570 + size_t num; 571 + const char *reset_name; 572 + }; 573 + 574 + static const struct clk_parent_data osc_24m_clk[] = { 575 + { .index = 0 }, 576 + }; 577 + 578 + ATLANTIS_PLL_DEFINE(CLK_RCPU_PLL, rcpu_pll_clk, osc_24m_clk, PLL_RCPU_CFG_REG, 579 + PLL_RCPU_EN_REG, BUS_CG_REG, 0, /* No Gate Clk at Output */ 580 + CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL); 581 + 582 + static const struct clk_parent_data rcpu_root_parents[] = { 583 + { .index = 0 }, 584 + { .hw = &rcpu_pll_clk.common.hw }, 585 + }; 586 + 587 + ATLANTIS_MUX_DEFINE(CLK_RCPU_ROOT, rcpu_root_clk, rcpu_root_parents, 588 + RCPU_DIV_CFG_REG, 0, 1, CLK_SET_RATE_NO_REPARENT); 589 + 590 + ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV2, rcpu_div2_clk, rcpu_root_clk, 591 + RCPU_DIV_CFG_REG, 2, 4, 0, 0); 592 + ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV4, rcpu_div4_clk, rcpu_root_clk, 593 + RCPU_DIV_CFG_REG, 7, 4, 0, 0); 594 + ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_RTC, rcpu_rtc_clk, rcpu_div4_clk, 595 + RCPU_DIV_CFG_REG, 12, 6, 0, 0); 596 + 597 + ATLANTIS_GATE_DEFINE(CLK_SMNDMA0_ACLK, rcpu_dma0_clk, rcpu_div2_clk, 598 + RCPU_BLK_CG_REG, BIT(0), 0); 599 + ATLANTIS_GATE_DEFINE(CLK_SMNDMA1_ACLK, rcpu_dma1_clk, rcpu_div2_clk, 600 + RCPU_BLK_CG_REG, BIT(1), 0); 601 + ATLANTIS_GATE_DEFINE(CLK_WDT0_PCLK, sl_wdt0_pclk, rcpu_div4_clk, 602 + RCPU_BLK_CG_REG, BIT(2), 0); 603 + ATLANTIS_GATE_DEFINE(CLK_WDT1_PCLK, sl_wdt1_pclk, rcpu_div4_clk, 604 + RCPU_BLK_CG_REG, BIT(3), 0); 605 + ATLANTIS_GATE_DEFINE(CLK_TIMER_PCLK, sl_timer_pclk, rcpu_div4_clk, 606 + RCPU_BLK_CG_REG, BIT(4), 0); 607 + ATLANTIS_GATE_DEFINE(CLK_PVTC_PCLK, sl_pvtc_pclk, rcpu_div4_clk, 608 + RCPU_BLK_CG_REG, BIT(12), 0); 609 + ATLANTIS_GATE_DEFINE(CLK_PMU_PCLK, sl_pmu_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, 610 + BIT(13), 0); 611 + ATLANTIS_GATE_DEFINE(CLK_MAILBOX_HCLK, rcpu_ipc_clk, rcpu_div2_clk, 612 + RCPU_BLK_CG_REG, BIT(14), 0); 613 + ATLANTIS_GATE_DEFINE(CLK_SEC_SPACC_HCLK, sec_spacc_hclk, rcpu_div2_clk, 614 + RCPU_BLK_CG_REG, BIT(26), 0); 615 + ATLANTIS_GATE_DEFINE(CLK_SEC_OTP_HCLK, sec_otp_hclk, rcpu_div2_clk, 616 + RCPU_BLK_CG_REG, BIT(28), 0); 617 + ATLANTIS_GATE_DEFINE(CLK_TRNG_PCLK, sec_trng_pclk, rcpu_div4_clk, 618 + RCPU_BLK_CG_REG, BIT(29), 0); 619 + ATLANTIS_GATE_DEFINE(CLK_SEC_CRC_HCLK, sec_crc_hclk, rcpu_div2_clk, 620 + RCPU_BLK_CG_REG, BIT(30), 0); 621 + 622 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_HCLK, rcpu_smn_hclk, rcpu_div2_clk, 1, 1, 623 + 0); 624 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_AHB0_HCLK, rcpu_ahb0_hclk, rcpu_div2_clk, 1, 1, 625 + 0); 626 + 627 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_PCLK, rcpu_smn_pclk, rcpu_div4_clk, 1, 1, 628 + 0); 629 + 630 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_CLK, rcpu_smn_clk, rcpu_root_clk, 1, 1, 0); 631 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SCRATCHPAD_CLK, rcpu_scratchpad_aclk, 632 + rcpu_root_clk, 1, 1, 0); 633 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_CORE_CLK, rcpu_core_clk, rcpu_root_clk, 1, 634 + 1, 0); 635 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_ROM_CLK, rcpu_rom_aclk, rcpu_root_clk, 1, 636 + 1, 0); 637 + 638 + static struct atlantis_clk_fixed_factor 639 + otp_load_clk = { .config = { .mult = 1, .div = 1 }, 640 + .common = { 641 + .clkid = CLK_OTP_LOAD_CLK, 642 + .hw.init = CLK_HW_INIT_PARENTS_DATA( 643 + "otp_load_clk", osc_24m_clk, 644 + &atlantis_clk_fixed_factor_ops, 645 + CLK_SET_RATE_NO_REPARENT), 646 + } }; 647 + 648 + ATLANTIS_PLL_DEFINE(CLK_NOC_PLL, nocc_pll_clk, osc_24m_clk, PLL_NOCC_CFG_REG, 649 + PLL_NOCC_EN_REG, BUS_CG_REG, BIT(0), 650 + CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL); 651 + 652 + static const struct clk_parent_data nocc_mux_parents[] = { 653 + { .index = 0 }, 654 + { .hw = &nocc_pll_clk.common.hw }, 655 + }; 656 + 657 + ATLANTIS_MUX_DEFINE(CLK_NOCC_CLK, nocc_clk, nocc_mux_parents, NOCC_CLK_CFG_REG, 658 + 0, 1, CLK_SET_RATE_NO_REPARENT); 659 + 660 + ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV2, nocc_div2_clk, nocc_clk, 661 + NOCC_CLK_CFG_REG, 1, 4, 0, 0); 662 + ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV4, nocc_div4_clk, nocc_clk, 663 + NOCC_CLK_CFG_REG, 5, 4, 0, 0); 664 + ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_RTC, nocc_rtc_clk, nocc_div4_clk, 665 + NOCC_CLK_CFG_REG, 9, 6, 0, 0); 666 + ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_CAN, nocc_can_clk, nocc_clk, NOCC_CLK_CFG_REG, 667 + 15, 4, 0, 0); 668 + 669 + static unsigned int refcnt_qspi; 670 + ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_SCLK, lsio_qspi_sclk, nocc_clk, 671 + LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); 672 + ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_HCLK, lsio_qspi_hclk, nocc_div2_clk, 673 + LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); 674 + ATLANTIS_GATE_DEFINE(CLK_I2C0_PCLK, lsio_i2c0_pclk, nocc_div4_clk, 675 + LSIO_BLK_CG_REG, BIT(1), 0); 676 + ATLANTIS_GATE_DEFINE(CLK_I2C1_PCLK, lsio_i2c1_pclk, nocc_div4_clk, 677 + LSIO_BLK_CG_REG, BIT(2), 0); 678 + ATLANTIS_GATE_DEFINE(CLK_I2C2_PCLK, lsio_i2c2_pclk, nocc_div4_clk, 679 + LSIO_BLK_CG_REG, BIT(3), 0); 680 + ATLANTIS_GATE_DEFINE(CLK_I2C3_PCLK, lsio_i2c3_pclk, nocc_div4_clk, 681 + LSIO_BLK_CG_REG, BIT(4), 0); 682 + ATLANTIS_GATE_DEFINE(CLK_I2C4_PCLK, lsio_i2c4_pclk, nocc_div4_clk, 683 + LSIO_BLK_CG_REG, BIT(5), 0); 684 + 685 + ATLANTIS_GATE_DEFINE(CLK_UART0_PCLK, lsio_uart0_pclk, nocc_div4_clk, 686 + LSIO_BLK_CG_REG, BIT(6), 0); 687 + ATLANTIS_GATE_DEFINE(CLK_UART1_PCLK, lsio_uart1_pclk, nocc_div4_clk, 688 + LSIO_BLK_CG_REG, BIT(7), 0); 689 + ATLANTIS_GATE_DEFINE(CLK_UART2_PCLK, lsio_uart2_pclk, nocc_div4_clk, 690 + LSIO_BLK_CG_REG, BIT(8), 0); 691 + ATLANTIS_GATE_DEFINE(CLK_UART3_PCLK, lsio_uart3_pclk, nocc_div4_clk, 692 + LSIO_BLK_CG_REG, BIT(9), 0); 693 + ATLANTIS_GATE_DEFINE(CLK_UART4_PCLK, lsio_uart4_pclk, nocc_div4_clk, 694 + LSIO_BLK_CG_REG, BIT(10), 0); 695 + ATLANTIS_GATE_DEFINE(CLK_SPI0_PCLK, lsio_spi0_pclk, nocc_div4_clk, 696 + LSIO_BLK_CG_REG, BIT(11), 0); 697 + ATLANTIS_GATE_DEFINE(CLK_SPI1_PCLK, lsio_spi1_pclk, nocc_div4_clk, 698 + LSIO_BLK_CG_REG, BIT(12), 0); 699 + ATLANTIS_GATE_DEFINE(CLK_SPI2_PCLK, lsio_spi2_pclk, nocc_div4_clk, 700 + LSIO_BLK_CG_REG, BIT(13), 0); 701 + ATLANTIS_GATE_DEFINE(CLK_SPI3_PCLK, lsio_spi3_pclk, nocc_div4_clk, 702 + LSIO_BLK_CG_REG, BIT(14), 0); 703 + ATLANTIS_GATE_DEFINE(CLK_GPIO_PCLK, lsio_gpio_pclk, nocc_div4_clk, 704 + LSIO_BLK_CG_REG, BIT(15), 0); 705 + 706 + static unsigned int refcnt_can0; 707 + ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_HCLK, lsio_can0_hclk, nocc_div2_clk, 708 + LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); 709 + ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_CLK, lsio_can0_clk, nocc_can_clk, 710 + LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); 711 + 712 + static unsigned int refcnt_can1; 713 + ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_HCLK, lsio_can1_hclk, nocc_div2_clk, 714 + LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); 715 + ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_CLK, lsio_can1_clk, nocc_can_clk, 716 + LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); 717 + 718 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN0_TIMER_CLK, lsio_can0_timer_clk, 719 + nocc_rtc_clk, 1, 1, 0); 720 + ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN1_TIMER_CLK, lsio_can1_timer_clk, 721 + nocc_rtc_clk, 1, 1, 0); 722 + 723 + static struct clk_hw *atlantis_rcpu_clks[] = { 724 + [CLK_RCPU_PLL] = &rcpu_pll_clk.common.hw, 725 + [CLK_RCPU_ROOT] = &rcpu_root_clk.common.hw, 726 + [CLK_RCPU_DIV2] = &rcpu_div2_clk.common.hw, 727 + [CLK_RCPU_DIV4] = &rcpu_div4_clk.common.hw, 728 + [CLK_RCPU_RTC] = &rcpu_rtc_clk.common.hw, 729 + [CLK_SMNDMA0_ACLK] = &rcpu_dma0_clk.common.hw, 730 + [CLK_SMNDMA1_ACLK] = &rcpu_dma1_clk.common.hw, 731 + [CLK_WDT0_PCLK] = &sl_wdt0_pclk.common.hw, 732 + [CLK_WDT1_PCLK] = &sl_wdt1_pclk.common.hw, 733 + [CLK_TIMER_PCLK] = &sl_timer_pclk.common.hw, 734 + [CLK_PVTC_PCLK] = &sl_pvtc_pclk.common.hw, 735 + [CLK_PMU_PCLK] = &sl_pmu_pclk.common.hw, 736 + [CLK_MAILBOX_HCLK] = &rcpu_ipc_clk.common.hw, 737 + [CLK_SEC_SPACC_HCLK] = &sec_spacc_hclk.common.hw, 738 + [CLK_SEC_OTP_HCLK] = &sec_otp_hclk.common.hw, 739 + [CLK_TRNG_PCLK] = &sec_trng_pclk.common.hw, 740 + [CLK_SEC_CRC_HCLK] = &sec_crc_hclk.common.hw, 741 + [CLK_SMN_HCLK] = &rcpu_smn_hclk.common.hw, 742 + [CLK_AHB0_HCLK] = &rcpu_ahb0_hclk.common.hw, 743 + [CLK_SMN_PCLK] = &rcpu_smn_pclk.common.hw, 744 + [CLK_SMN_CLK] = &rcpu_smn_clk.common.hw, 745 + [CLK_SCRATCHPAD_CLK] = &rcpu_scratchpad_aclk.common.hw, 746 + [CLK_RCPU_CORE_CLK] = &rcpu_core_clk.common.hw, 747 + [CLK_RCPU_ROM_CLK] = &rcpu_rom_aclk.common.hw, 748 + [CLK_OTP_LOAD_CLK] = &otp_load_clk.common.hw, 749 + [CLK_NOC_PLL] = &nocc_pll_clk.common.hw, 750 + [CLK_NOCC_CLK] = &nocc_clk.common.hw, 751 + [CLK_NOCC_DIV2] = &nocc_div2_clk.common.hw, 752 + [CLK_NOCC_DIV4] = &nocc_div4_clk.common.hw, 753 + [CLK_NOCC_RTC] = &nocc_rtc_clk.common.hw, 754 + [CLK_NOCC_CAN] = &nocc_can_clk.common.hw, 755 + [CLK_QSPI_SCLK] = &lsio_qspi_sclk.common.hw, 756 + [CLK_QSPI_HCLK] = &lsio_qspi_hclk.common.hw, 757 + [CLK_I2C0_PCLK] = &lsio_i2c0_pclk.common.hw, 758 + [CLK_I2C1_PCLK] = &lsio_i2c1_pclk.common.hw, 759 + [CLK_I2C2_PCLK] = &lsio_i2c2_pclk.common.hw, 760 + [CLK_I2C3_PCLK] = &lsio_i2c3_pclk.common.hw, 761 + [CLK_I2C4_PCLK] = &lsio_i2c4_pclk.common.hw, 762 + [CLK_UART0_PCLK] = &lsio_uart0_pclk.common.hw, 763 + [CLK_UART1_PCLK] = &lsio_uart1_pclk.common.hw, 764 + [CLK_UART2_PCLK] = &lsio_uart2_pclk.common.hw, 765 + [CLK_UART3_PCLK] = &lsio_uart3_pclk.common.hw, 766 + [CLK_UART4_PCLK] = &lsio_uart4_pclk.common.hw, 767 + [CLK_SPI0_PCLK] = &lsio_spi0_pclk.common.hw, 768 + [CLK_SPI1_PCLK] = &lsio_spi1_pclk.common.hw, 769 + [CLK_SPI2_PCLK] = &lsio_spi2_pclk.common.hw, 770 + [CLK_SPI3_PCLK] = &lsio_spi3_pclk.common.hw, 771 + [CLK_GPIO_PCLK] = &lsio_gpio_pclk.common.hw, 772 + [CLK_CAN0_HCLK] = &lsio_can0_hclk.common.hw, 773 + [CLK_CAN0_CLK] = &lsio_can0_clk.common.hw, 774 + [CLK_CAN1_HCLK] = &lsio_can1_hclk.common.hw, 775 + [CLK_CAN1_CLK] = &lsio_can1_clk.common.hw, 776 + [CLK_CAN0_TIMER_CLK] = &lsio_can0_timer_clk.common.hw, 777 + [CLK_CAN1_TIMER_CLK] = &lsio_can1_timer_clk.common.hw, 778 + }; 779 + 780 + static const struct atlantis_prcm_data atlantis_prcm_rcpu_data = { 781 + .hws = atlantis_rcpu_clks, 782 + .num = ARRAY_SIZE(atlantis_rcpu_clks), 783 + .reset_name = "rcpu-reset" 784 + }; 785 + 786 + static int atlantis_prcm_clocks_register(struct device *dev, 787 + struct regmap *regmap, 788 + const struct atlantis_prcm_data *data) 789 + { 790 + struct clk_hw_onecell_data *clk_data; 791 + int i, ret; 792 + size_t num_clks = data->num; 793 + 794 + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num), 795 + GFP_KERNEL); 796 + if (!clk_data) 797 + return -ENOMEM; 798 + 799 + for (i = 0; i < data->num; i++) { 800 + struct clk_hw *hw = data->hws[i]; 801 + struct atlantis_clk_common *common = 802 + hw_to_atlantis_clk_common(hw); 803 + common->regmap = regmap; 804 + 805 + ret = devm_clk_hw_register(dev, hw); 806 + if (ret) 807 + return ret; 808 + 809 + clk_data->hws[common->clkid] = hw; 810 + } 811 + 812 + clk_data->num = num_clks; 813 + 814 + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); 815 + } 816 + 817 + static int atlantis_prcm_probe(struct platform_device *pdev) 818 + { 819 + const struct atlantis_prcm_data *data; 820 + struct auxiliary_device *reset_adev; 821 + struct regmap *regmap; 822 + void __iomem *base; 823 + struct device *dev = &pdev->dev; 824 + int ret; 825 + 826 + base = devm_platform_ioremap_resource(pdev, 0); 827 + if (IS_ERR(base)) 828 + return dev_err_probe(dev, PTR_ERR(base), 829 + "Failed to map registers\n"); 830 + 831 + regmap = devm_regmap_init_mmio(dev, base, &atlantis_prcm_regmap_config); 832 + if (IS_ERR(regmap)) 833 + return dev_err_probe(dev, PTR_ERR(regmap), 834 + "Failed to init regmap\n"); 835 + 836 + data = of_device_get_match_data(dev); 837 + 838 + ret = atlantis_prcm_clocks_register(dev, regmap, data); 839 + if (ret) 840 + return dev_err_probe(dev, ret, "failed to register clocks\n"); 841 + 842 + reset_adev = devm_auxiliary_device_create(dev, data->reset_name, NULL); 843 + if (!reset_adev) 844 + return dev_err_probe(dev, -ENODEV, "failed to register resets\n"); 845 + 846 + return 0; 847 + } 848 + 849 + static const struct of_device_id atlantis_prcm_of_match[] = { 850 + { 851 + .compatible = "tenstorrent,atlantis-prcm-rcpu", 852 + .data = &atlantis_prcm_rcpu_data, 853 + }, 854 + {} 855 + 856 + }; 857 + MODULE_DEVICE_TABLE(of, atlantis_prcm_of_match); 858 + 859 + static struct platform_driver atlantis_prcm_driver = { 860 + .probe = atlantis_prcm_probe, 861 + .driver = { 862 + .name = "atlantis-prcm", 863 + .of_match_table = atlantis_prcm_of_match, 864 + }, 865 + }; 866 + module_platform_driver(atlantis_prcm_driver); 867 + 868 + MODULE_DESCRIPTION("Tenstorrent Atlantis PRCM Clock Controller Driver"); 869 + MODULE_AUTHOR("Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>"); 870 + MODULE_LICENSE("GPL");
+11
drivers/reset/Kconfig
··· 315 315 help 316 316 This enables the reset driver for Allwinner SoCs. 317 317 318 + config RESET_TENSTORRENT_ATLANTIS 319 + tristate "Tenstorrent atlantis reset driver" 320 + depends on ARCH_TENSTORRENT || COMPILE_TEST 321 + select AUXILIARY_BUS 322 + default ARCH_TENSTORRENT 323 + help 324 + This enables the driver for the reset controller 325 + present in the Tenstorrent Atlantis SoC. 326 + Enable this option to be able to use hardware 327 + resets on Atalantis based systems. 328 + 318 329 config RESET_TH1520 319 330 tristate "T-HEAD TH1520 reset controller" 320 331 depends on ARCH_THEAD || COMPILE_TEST
+1
drivers/reset/Makefile
··· 41 41 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o 42 42 obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o 43 43 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o 44 + obj-$(CONFIG_RESET_TENSTORRENT_ATLANTIS) += reset-tenstorrent-atlantis.o 44 45 obj-$(CONFIG_RESET_TH1520) += reset-th1520.o 45 46 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o 46 47 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
+173
drivers/reset/reset-tenstorrent-atlantis.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Tenstorrent Atlantis PRCM Reset Driver 4 + * 5 + * Copyright (c) 2026 Tenstorrent 6 + */ 7 + 8 + #include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h> 9 + #include <linux/auxiliary_bus.h> 10 + #include <linux/reset-controller.h> 11 + #include <linux/regmap.h> 12 + 13 + /* RCPU Reset Register Offsets */ 14 + #define RCPU_BLK_RST_REG 0x001c 15 + #define LSIO_BLK_RST_REG 0x0020 16 + #define HSIO_BLK_RST_REG 0x000c 17 + #define PCIE_SUBS_RST_REG 0x0000 18 + #define MM_RSTN_REG 0x0014 19 + 20 + struct atlantis_reset_data { 21 + u8 bit; 22 + u16 reg; 23 + bool active_low; 24 + }; 25 + 26 + struct atlantis_reset_controller_data { 27 + const struct atlantis_reset_data *reset_data; 28 + size_t count; 29 + }; 30 + 31 + struct atlantis_reset_controller { 32 + struct reset_controller_dev rcdev; 33 + const struct atlantis_reset_controller_data *data; 34 + struct regmap *regmap; 35 + }; 36 + 37 + static inline struct atlantis_reset_controller * 38 + to_atlantis_reset_controller(struct reset_controller_dev *rcdev) 39 + { 40 + return container_of(rcdev, struct atlantis_reset_controller, rcdev); 41 + } 42 + 43 + #define RESET_DATA(_reg, _bit, _active_low) \ 44 + { \ 45 + .bit = _bit, .reg = _reg, .active_low = _active_low, \ 46 + } 47 + 48 + static const struct atlantis_reset_data atlantis_rcpu_resets[] = { 49 + [RST_SMNDMA0] = RESET_DATA(RCPU_BLK_RST_REG, 0, true), 50 + [RST_SMNDMA1] = RESET_DATA(RCPU_BLK_RST_REG, 1, true), 51 + [RST_WDT0] = RESET_DATA(RCPU_BLK_RST_REG, 2, true), 52 + [RST_WDT1] = RESET_DATA(RCPU_BLK_RST_REG, 3, true), 53 + [RST_TMR] = RESET_DATA(RCPU_BLK_RST_REG, 4, true), 54 + [RST_PVTC] = RESET_DATA(RCPU_BLK_RST_REG, 12, true), 55 + [RST_PMU] = RESET_DATA(RCPU_BLK_RST_REG, 13, true), 56 + [RST_MAILBOX] = RESET_DATA(RCPU_BLK_RST_REG, 14, true), 57 + [RST_SPACC] = RESET_DATA(RCPU_BLK_RST_REG, 26, true), 58 + [RST_OTP] = RESET_DATA(RCPU_BLK_RST_REG, 28, true), 59 + [RST_TRNG] = RESET_DATA(RCPU_BLK_RST_REG, 29, true), 60 + [RST_CRC] = RESET_DATA(RCPU_BLK_RST_REG, 30, true), 61 + [RST_QSPI] = RESET_DATA(LSIO_BLK_RST_REG, 0, true), 62 + [RST_I2C0] = RESET_DATA(LSIO_BLK_RST_REG, 1, true), 63 + [RST_I2C1] = RESET_DATA(LSIO_BLK_RST_REG, 2, true), 64 + [RST_I2C2] = RESET_DATA(LSIO_BLK_RST_REG, 3, true), 65 + [RST_I2C3] = RESET_DATA(LSIO_BLK_RST_REG, 4, true), 66 + [RST_I2C4] = RESET_DATA(LSIO_BLK_RST_REG, 5, true), 67 + [RST_UART0] = RESET_DATA(LSIO_BLK_RST_REG, 6, true), 68 + [RST_UART1] = RESET_DATA(LSIO_BLK_RST_REG, 7, true), 69 + [RST_UART2] = RESET_DATA(LSIO_BLK_RST_REG, 8, true), 70 + [RST_UART3] = RESET_DATA(LSIO_BLK_RST_REG, 9, true), 71 + [RST_UART4] = RESET_DATA(LSIO_BLK_RST_REG, 10, true), 72 + [RST_SPI0] = RESET_DATA(LSIO_BLK_RST_REG, 11, true), 73 + [RST_SPI1] = RESET_DATA(LSIO_BLK_RST_REG, 12, true), 74 + [RST_SPI2] = RESET_DATA(LSIO_BLK_RST_REG, 13, true), 75 + [RST_SPI3] = RESET_DATA(LSIO_BLK_RST_REG, 14, true), 76 + [RST_GPIO] = RESET_DATA(LSIO_BLK_RST_REG, 15, true), 77 + [RST_CAN0] = RESET_DATA(LSIO_BLK_RST_REG, 17, true), 78 + [RST_CAN1] = RESET_DATA(LSIO_BLK_RST_REG, 18, true), 79 + [RST_I2S0] = RESET_DATA(LSIO_BLK_RST_REG, 19, true), 80 + [RST_I2S1] = RESET_DATA(LSIO_BLK_RST_REG, 20, true), 81 + 82 + }; 83 + 84 + static const struct atlantis_reset_controller_data atlantis_rcpu_reset_data = { 85 + .reset_data = atlantis_rcpu_resets, 86 + .count = ARRAY_SIZE(atlantis_rcpu_resets), 87 + }; 88 + 89 + static int atlantis_reset_update(struct reset_controller_dev *rcdev, 90 + unsigned long id, bool assert) 91 + { 92 + unsigned int val; 93 + struct atlantis_reset_controller *rst = 94 + to_atlantis_reset_controller(rcdev); 95 + const struct atlantis_reset_data *data = &rst->data->reset_data[id]; 96 + unsigned int mask = BIT(data->bit); 97 + struct regmap *regmap = rst->regmap; 98 + 99 + if (data->active_low ^ assert) 100 + val = mask; 101 + else 102 + val = 0; 103 + 104 + return regmap_update_bits(regmap, data->reg, mask, val); 105 + } 106 + 107 + static int atlantis_reset_assert(struct reset_controller_dev *rcdev, 108 + unsigned long id) 109 + { 110 + return atlantis_reset_update(rcdev, id, true); 111 + } 112 + 113 + static int atlantis_reset_deassert(struct reset_controller_dev *rcdev, 114 + unsigned long id) 115 + { 116 + return atlantis_reset_update(rcdev, id, false); 117 + } 118 + 119 + static const struct reset_control_ops atlantis_reset_control_ops = { 120 + .assert = atlantis_reset_assert, 121 + .deassert = atlantis_reset_deassert, 122 + }; 123 + 124 + static int 125 + atlantis_reset_controller_register(struct device *dev, 126 + struct atlantis_reset_controller *controller) 127 + { 128 + struct reset_controller_dev *rcdev = &controller->rcdev; 129 + 130 + rcdev->ops = &atlantis_reset_control_ops; 131 + rcdev->owner = THIS_MODULE; 132 + rcdev->of_node = dev->of_node; 133 + rcdev->nr_resets = controller->data->count; 134 + 135 + return devm_reset_controller_register(dev, &controller->rcdev); 136 + } 137 + static int atlantis_reset_probe(struct auxiliary_device *adev, 138 + const struct auxiliary_device_id *id) 139 + { 140 + struct atlantis_reset_controller *controller; 141 + struct device *dev = &adev->dev; 142 + struct regmap *regmap; 143 + 144 + regmap = dev_get_regmap(dev->parent, NULL); 145 + if (!regmap) 146 + return -ENODEV; 147 + 148 + controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL); 149 + if (!controller) 150 + return -ENOMEM; 151 + controller->data = 152 + (const struct atlantis_reset_controller_data *)id->driver_data; 153 + controller->regmap = regmap; 154 + 155 + return atlantis_reset_controller_register(dev, controller); 156 + } 157 + 158 + static const struct auxiliary_device_id atlantis_reset_ids[] = { 159 + { .name = "atlantis_prcm.rcpu-reset", 160 + .driver_data = (kernel_ulong_t)&atlantis_rcpu_reset_data }, 161 + {}, 162 + }; 163 + MODULE_DEVICE_TABLE(auxiliary, atlantis_reset_ids); 164 + 165 + static struct auxiliary_driver atlantis_reset_driver = { 166 + .probe = atlantis_reset_probe, 167 + .id_table = atlantis_reset_ids, 168 + }; 169 + module_auxiliary_driver(atlantis_reset_driver); 170 + 171 + MODULE_AUTHOR("Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>"); 172 + MODULE_DESCRIPTION("Atlantis PRCM reset controller driver"); 173 + MODULE_LICENSE("GPL");
+103
include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 + /* 3 + * Tenstorrent Atlantis PRCM Clock and Reset Indices 4 + * 5 + * Copyright (c) 2026 Tenstorrent 6 + */ 7 + 8 + #ifndef _DT_BINDINGS_ATLANTIS_PRCM_RCPU_H 9 + #define _DT_BINDINGS_ATLANTIS_PRCM_RCPU_H 10 + 11 + /* 12 + * RCPU Domain Clock IDs 13 + */ 14 + #define CLK_RCPU_PLL 0 15 + #define CLK_RCPU_ROOT 1 16 + #define CLK_RCPU_DIV2 2 17 + #define CLK_RCPU_DIV4 3 18 + #define CLK_RCPU_RTC 4 19 + #define CLK_SMNDMA0_ACLK 5 20 + #define CLK_SMNDMA1_ACLK 6 21 + #define CLK_WDT0_PCLK 7 22 + #define CLK_WDT1_PCLK 8 23 + #define CLK_TIMER_PCLK 9 24 + #define CLK_PVTC_PCLK 10 25 + #define CLK_PMU_PCLK 11 26 + #define CLK_MAILBOX_HCLK 12 27 + #define CLK_SEC_SPACC_HCLK 13 28 + #define CLK_SEC_OTP_HCLK 14 29 + #define CLK_TRNG_PCLK 15 30 + #define CLK_SEC_CRC_HCLK 16 31 + #define CLK_SMN_HCLK 17 32 + #define CLK_AHB0_HCLK 18 33 + #define CLK_SMN_PCLK 19 34 + #define CLK_SMN_CLK 20 35 + #define CLK_SCRATCHPAD_CLK 21 36 + #define CLK_RCPU_CORE_CLK 22 37 + #define CLK_RCPU_ROM_CLK 23 38 + #define CLK_OTP_LOAD_CLK 24 39 + #define CLK_NOC_PLL 25 40 + #define CLK_NOCC_CLK 26 41 + #define CLK_NOCC_DIV2 27 42 + #define CLK_NOCC_DIV4 28 43 + #define CLK_NOCC_RTC 29 44 + #define CLK_NOCC_CAN 30 45 + #define CLK_QSPI_SCLK 31 46 + #define CLK_QSPI_HCLK 32 47 + #define CLK_I2C0_PCLK 33 48 + #define CLK_I2C1_PCLK 34 49 + #define CLK_I2C2_PCLK 35 50 + #define CLK_I2C3_PCLK 36 51 + #define CLK_I2C4_PCLK 37 52 + #define CLK_UART0_PCLK 38 53 + #define CLK_UART1_PCLK 39 54 + #define CLK_UART2_PCLK 40 55 + #define CLK_UART3_PCLK 41 56 + #define CLK_UART4_PCLK 42 57 + #define CLK_SPI0_PCLK 43 58 + #define CLK_SPI1_PCLK 44 59 + #define CLK_SPI2_PCLK 45 60 + #define CLK_SPI3_PCLK 46 61 + #define CLK_GPIO_PCLK 47 62 + #define CLK_CAN0_HCLK 48 63 + #define CLK_CAN0_CLK 49 64 + #define CLK_CAN1_HCLK 50 65 + #define CLK_CAN1_CLK 51 66 + #define CLK_CAN0_TIMER_CLK 52 67 + #define CLK_CAN1_TIMER_CLK 53 68 + 69 + /* RCPU domain reset */ 70 + #define RST_SMNDMA0 0 71 + #define RST_SMNDMA1 1 72 + #define RST_WDT0 2 73 + #define RST_WDT1 3 74 + #define RST_TMR 4 75 + #define RST_PVTC 5 76 + #define RST_PMU 6 77 + #define RST_MAILBOX 7 78 + #define RST_SPACC 8 79 + #define RST_OTP 9 80 + #define RST_TRNG 10 81 + #define RST_CRC 11 82 + #define RST_QSPI 12 83 + #define RST_I2C0 13 84 + #define RST_I2C1 14 85 + #define RST_I2C2 15 86 + #define RST_I2C3 16 87 + #define RST_I2C4 17 88 + #define RST_UART0 18 89 + #define RST_UART1 19 90 + #define RST_UART2 20 91 + #define RST_UART3 21 92 + #define RST_UART4 22 93 + #define RST_SPI0 23 94 + #define RST_SPI1 24 95 + #define RST_SPI2 25 96 + #define RST_SPI3 26 97 + #define RST_GPIO 27 98 + #define RST_CAN0 28 99 + #define RST_CAN1 29 100 + #define RST_I2S0 30 101 + #define RST_I2S1 31 102 + 103 + #endif /* _DT_BINDINGS_ATLANTIS_PRCM_RCPU_H */