19e288cefSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0 2b3a33077SSimon Horman /* 3b3a33077SSimon Horman * R-Car MSTP clocks 4b3a33077SSimon Horman * 5b3a33077SSimon Horman * Copyright (C) 2013 Ideas On Board SPRL 6b3a33077SSimon Horman * Copyright (C) 2015 Glider bvba 7b3a33077SSimon Horman * 8b3a33077SSimon Horman * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 9b3a33077SSimon Horman */ 10b3a33077SSimon Horman 11b3a33077SSimon Horman #include <linux/clk.h> 12b3a33077SSimon Horman #include <linux/clk-provider.h> 13b3a33077SSimon Horman #include <linux/clkdev.h> 1409c32427SSimon Horman #include <linux/clk/renesas.h> 15b3a33077SSimon Horman #include <linux/device.h> 16b3a33077SSimon Horman #include <linux/io.h> 17b3a33077SSimon Horman #include <linux/of.h> 18b3a33077SSimon Horman #include <linux/of_address.h> 19b3a33077SSimon Horman #include <linux/pm_clock.h> 20b3a33077SSimon Horman #include <linux/pm_domain.h> 21b3a33077SSimon Horman #include <linux/spinlock.h> 22b3a33077SSimon Horman 23b3a33077SSimon Horman /* 24b3a33077SSimon Horman * MSTP clocks. We can't use standard gate clocks as we need to poll on the 25b3a33077SSimon Horman * status register when enabling the clock. 26b3a33077SSimon Horman */ 27b3a33077SSimon Horman 28b3a33077SSimon Horman #define MSTP_MAX_CLOCKS 32 29b3a33077SSimon Horman 30b3a33077SSimon Horman /** 31b3a33077SSimon Horman * struct mstp_clock_group - MSTP gating clocks group 32b3a33077SSimon Horman * 33*a79f5836SGeert Uytterhoeven * @data: clock specifier translation for clocks in this group 34b3a33077SSimon Horman * @smstpcr: module stop control register 35b3a33077SSimon Horman * @mstpsr: module stop status register (optional) 36b3a33077SSimon Horman * @lock: protects writes to SMSTPCR 37e2a33c34SChris Brandt * @width_8bit: registers are 8-bit, not 32-bit 38*a79f5836SGeert Uytterhoeven * @clks: clocks in this group 39b3a33077SSimon Horman */ 40b3a33077SSimon Horman struct mstp_clock_group { 41b3a33077SSimon Horman struct clk_onecell_data data; 42b3a33077SSimon Horman void __iomem *smstpcr; 43b3a33077SSimon Horman void __iomem *mstpsr; 44b3a33077SSimon Horman spinlock_t lock; 45e2a33c34SChris Brandt bool width_8bit; 46*a79f5836SGeert Uytterhoeven struct clk *clks[]; 47b3a33077SSimon Horman }; 48b3a33077SSimon Horman 49b3a33077SSimon Horman /** 50b3a33077SSimon Horman * struct mstp_clock - MSTP gating clock 51b3a33077SSimon Horman * @hw: handle between common and hardware-specific interfaces 52b3a33077SSimon Horman * @bit_index: control bit index 53b3a33077SSimon Horman * @group: MSTP clocks group 54b3a33077SSimon Horman */ 55b3a33077SSimon Horman struct mstp_clock { 56b3a33077SSimon Horman struct clk_hw hw; 57b3a33077SSimon Horman u32 bit_index; 58b3a33077SSimon Horman struct mstp_clock_group *group; 59b3a33077SSimon Horman }; 60b3a33077SSimon Horman 61b3a33077SSimon Horman #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) 62b3a33077SSimon Horman 63e2a33c34SChris Brandt static inline u32 cpg_mstp_read(struct mstp_clock_group *group, 64e2a33c34SChris Brandt u32 __iomem *reg) 65e2a33c34SChris Brandt { 6680275198SGeert Uytterhoeven return group->width_8bit ? readb(reg) : readl(reg); 67e2a33c34SChris Brandt } 68e2a33c34SChris Brandt 69e2a33c34SChris Brandt static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val, 70e2a33c34SChris Brandt u32 __iomem *reg) 71e2a33c34SChris Brandt { 7280275198SGeert Uytterhoeven group->width_8bit ? writeb(val, reg) : writel(val, reg); 73e2a33c34SChris Brandt } 74e2a33c34SChris Brandt 75b3a33077SSimon Horman static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) 76b3a33077SSimon Horman { 77b3a33077SSimon Horman struct mstp_clock *clock = to_mstp_clock(hw); 78b3a33077SSimon Horman struct mstp_clock_group *group = clock->group; 79b3a33077SSimon Horman u32 bitmask = BIT(clock->bit_index); 80b3a33077SSimon Horman unsigned long flags; 81b3a33077SSimon Horman unsigned int i; 82b3a33077SSimon Horman u32 value; 83b3a33077SSimon Horman 84b3a33077SSimon Horman spin_lock_irqsave(&group->lock, flags); 85b3a33077SSimon Horman 86e2a33c34SChris Brandt value = cpg_mstp_read(group, group->smstpcr); 87b3a33077SSimon Horman if (enable) 88b3a33077SSimon Horman value &= ~bitmask; 89b3a33077SSimon Horman else 90b3a33077SSimon Horman value |= bitmask; 91e2a33c34SChris Brandt cpg_mstp_write(group, value, group->smstpcr); 92b3a33077SSimon Horman 93f59de563SChris Brandt if (!group->mstpsr) { 94f59de563SChris Brandt /* dummy read to ensure write has completed */ 95f59de563SChris Brandt cpg_mstp_read(group, group->smstpcr); 96f59de563SChris Brandt barrier_data(group->smstpcr); 97f59de563SChris Brandt } 98f59de563SChris Brandt 99b3a33077SSimon Horman spin_unlock_irqrestore(&group->lock, flags); 100b3a33077SSimon Horman 101b3a33077SSimon Horman if (!enable || !group->mstpsr) 102b3a33077SSimon Horman return 0; 103b3a33077SSimon Horman 104b3a33077SSimon Horman for (i = 1000; i > 0; --i) { 105e2a33c34SChris Brandt if (!(cpg_mstp_read(group, group->mstpsr) & bitmask)) 106b3a33077SSimon Horman break; 107b3a33077SSimon Horman cpu_relax(); 108b3a33077SSimon Horman } 109b3a33077SSimon Horman 110b3a33077SSimon Horman if (!i) { 111b3a33077SSimon Horman pr_err("%s: failed to enable %p[%d]\n", __func__, 112b3a33077SSimon Horman group->smstpcr, clock->bit_index); 113b3a33077SSimon Horman return -ETIMEDOUT; 114b3a33077SSimon Horman } 115b3a33077SSimon Horman 116b3a33077SSimon Horman return 0; 117b3a33077SSimon Horman } 118b3a33077SSimon Horman 119b3a33077SSimon Horman static int cpg_mstp_clock_enable(struct clk_hw *hw) 120b3a33077SSimon Horman { 121b3a33077SSimon Horman return cpg_mstp_clock_endisable(hw, true); 122b3a33077SSimon Horman } 123b3a33077SSimon Horman 124b3a33077SSimon Horman static void cpg_mstp_clock_disable(struct clk_hw *hw) 125b3a33077SSimon Horman { 126b3a33077SSimon Horman cpg_mstp_clock_endisable(hw, false); 127b3a33077SSimon Horman } 128b3a33077SSimon Horman 129b3a33077SSimon Horman static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) 130b3a33077SSimon Horman { 131b3a33077SSimon Horman struct mstp_clock *clock = to_mstp_clock(hw); 132b3a33077SSimon Horman struct mstp_clock_group *group = clock->group; 133b3a33077SSimon Horman u32 value; 134b3a33077SSimon Horman 135b3a33077SSimon Horman if (group->mstpsr) 136e2a33c34SChris Brandt value = cpg_mstp_read(group, group->mstpsr); 137b3a33077SSimon Horman else 138e2a33c34SChris Brandt value = cpg_mstp_read(group, group->smstpcr); 139b3a33077SSimon Horman 140b3a33077SSimon Horman return !(value & BIT(clock->bit_index)); 141b3a33077SSimon Horman } 142b3a33077SSimon Horman 143b3a33077SSimon Horman static const struct clk_ops cpg_mstp_clock_ops = { 144b3a33077SSimon Horman .enable = cpg_mstp_clock_enable, 145b3a33077SSimon Horman .disable = cpg_mstp_clock_disable, 146b3a33077SSimon Horman .is_enabled = cpg_mstp_clock_is_enabled, 147b3a33077SSimon Horman }; 148b3a33077SSimon Horman 1491ce87dd2SGeert Uytterhoeven static struct clk * __init cpg_mstp_clock_register(const char *name, 1501ce87dd2SGeert Uytterhoeven const char *parent_name, unsigned int index, 1511ce87dd2SGeert Uytterhoeven struct mstp_clock_group *group) 152b3a33077SSimon Horman { 153b3a33077SSimon Horman struct clk_init_data init; 154b3a33077SSimon Horman struct mstp_clock *clock; 155b3a33077SSimon Horman struct clk *clk; 156b3a33077SSimon Horman 157b3a33077SSimon Horman clock = kzalloc(sizeof(*clock), GFP_KERNEL); 158168bcbcbSMarkus Elfring if (!clock) 159b3a33077SSimon Horman return ERR_PTR(-ENOMEM); 160b3a33077SSimon Horman 161b3a33077SSimon Horman init.name = name; 162b3a33077SSimon Horman init.ops = &cpg_mstp_clock_ops; 163ddbae665SStephen Boyd init.flags = CLK_SET_RATE_PARENT; 164e34084fbSGeert Uytterhoeven /* INTC-SYS is the module clock of the GIC, and must not be disabled */ 165e34084fbSGeert Uytterhoeven if (!strcmp(name, "intc-sys")) { 166e34084fbSGeert Uytterhoeven pr_debug("MSTP %s setting CLK_IS_CRITICAL\n", name); 167e34084fbSGeert Uytterhoeven init.flags |= CLK_IS_CRITICAL; 168e34084fbSGeert Uytterhoeven } 169b3a33077SSimon Horman init.parent_names = &parent_name; 170b3a33077SSimon Horman init.num_parents = 1; 171b3a33077SSimon Horman 172b3a33077SSimon Horman clock->bit_index = index; 173b3a33077SSimon Horman clock->group = group; 174b3a33077SSimon Horman clock->hw.init = &init; 175b3a33077SSimon Horman 176b3a33077SSimon Horman clk = clk_register(NULL, &clock->hw); 177b3a33077SSimon Horman 178b3a33077SSimon Horman if (IS_ERR(clk)) 179b3a33077SSimon Horman kfree(clock); 180b3a33077SSimon Horman 181b3a33077SSimon Horman return clk; 182b3a33077SSimon Horman } 183b3a33077SSimon Horman 184b3a33077SSimon Horman static void __init cpg_mstp_clocks_init(struct device_node *np) 185b3a33077SSimon Horman { 186b3a33077SSimon Horman struct mstp_clock_group *group; 187b3a33077SSimon Horman const char *idxname; 188b3a33077SSimon Horman struct clk **clks; 189b3a33077SSimon Horman unsigned int i; 190b3a33077SSimon Horman 191*a79f5836SGeert Uytterhoeven group = kzalloc(struct_size(group, clks, MSTP_MAX_CLOCKS), GFP_KERNEL); 192*a79f5836SGeert Uytterhoeven if (group == NULL) { 193b3a33077SSimon Horman kfree(group); 194b3a33077SSimon Horman return; 195b3a33077SSimon Horman } 196b3a33077SSimon Horman 197*a79f5836SGeert Uytterhoeven clks = group->clks; 198b3a33077SSimon Horman spin_lock_init(&group->lock); 199b3a33077SSimon Horman group->data.clks = clks; 200b3a33077SSimon Horman 201b3a33077SSimon Horman group->smstpcr = of_iomap(np, 0); 202b3a33077SSimon Horman group->mstpsr = of_iomap(np, 1); 203b3a33077SSimon Horman 204b3a33077SSimon Horman if (group->smstpcr == NULL) { 205b3a33077SSimon Horman pr_err("%s: failed to remap SMSTPCR\n", __func__); 206b3a33077SSimon Horman kfree(group); 207b3a33077SSimon Horman return; 208b3a33077SSimon Horman } 209b3a33077SSimon Horman 210e2a33c34SChris Brandt if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks")) 211e2a33c34SChris Brandt group->width_8bit = true; 212e2a33c34SChris Brandt 213b3a33077SSimon Horman for (i = 0; i < MSTP_MAX_CLOCKS; ++i) 214b3a33077SSimon Horman clks[i] = ERR_PTR(-ENOENT); 215b3a33077SSimon Horman 216b3a33077SSimon Horman if (of_find_property(np, "clock-indices", &i)) 217b3a33077SSimon Horman idxname = "clock-indices"; 218b3a33077SSimon Horman else 219b3a33077SSimon Horman idxname = "renesas,clock-indices"; 220b3a33077SSimon Horman 221b3a33077SSimon Horman for (i = 0; i < MSTP_MAX_CLOCKS; ++i) { 222b3a33077SSimon Horman const char *parent_name; 223b3a33077SSimon Horman const char *name; 224b3a33077SSimon Horman u32 clkidx; 225b3a33077SSimon Horman int ret; 226b3a33077SSimon Horman 227b3a33077SSimon Horman /* Skip clocks with no name. */ 228b3a33077SSimon Horman ret = of_property_read_string_index(np, "clock-output-names", 229b3a33077SSimon Horman i, &name); 230b3a33077SSimon Horman if (ret < 0 || strlen(name) == 0) 231b3a33077SSimon Horman continue; 232b3a33077SSimon Horman 233b3a33077SSimon Horman parent_name = of_clk_get_parent_name(np, i); 234b3a33077SSimon Horman ret = of_property_read_u32_index(np, idxname, i, &clkidx); 235b3a33077SSimon Horman if (parent_name == NULL || ret < 0) 236b3a33077SSimon Horman break; 237b3a33077SSimon Horman 238b3a33077SSimon Horman if (clkidx >= MSTP_MAX_CLOCKS) { 239e665f029SRob Herring pr_err("%s: invalid clock %pOFn %s index %u\n", 240e665f029SRob Herring __func__, np, name, clkidx); 241b3a33077SSimon Horman continue; 242b3a33077SSimon Horman } 243b3a33077SSimon Horman 244b3a33077SSimon Horman clks[clkidx] = cpg_mstp_clock_register(name, parent_name, 245b3a33077SSimon Horman clkidx, group); 246b3a33077SSimon Horman if (!IS_ERR(clks[clkidx])) { 247b3a33077SSimon Horman group->data.clk_num = max(group->data.clk_num, 248b3a33077SSimon Horman clkidx + 1); 249b3a33077SSimon Horman /* 250b3a33077SSimon Horman * Register a clkdev to let board code retrieve the 251b3a33077SSimon Horman * clock by name and register aliases for non-DT 252b3a33077SSimon Horman * devices. 253b3a33077SSimon Horman * 254b3a33077SSimon Horman * FIXME: Remove this when all devices that require a 255b3a33077SSimon Horman * clock will be instantiated from DT. 256b3a33077SSimon Horman */ 257b3a33077SSimon Horman clk_register_clkdev(clks[clkidx], name, NULL); 258b3a33077SSimon Horman } else { 259e665f029SRob Herring pr_err("%s: failed to register %pOFn %s clock (%ld)\n", 260e665f029SRob Herring __func__, np, name, PTR_ERR(clks[clkidx])); 261b3a33077SSimon Horman } 262b3a33077SSimon Horman } 263b3a33077SSimon Horman 264b3a33077SSimon Horman of_clk_add_provider(np, of_clk_src_onecell_get, &group->data); 265b3a33077SSimon Horman } 266b3a33077SSimon Horman CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); 267b3a33077SSimon Horman 26812a56817SGeert Uytterhoeven int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev) 269b3a33077SSimon Horman { 270b3a33077SSimon Horman struct device_node *np = dev->of_node; 271b3a33077SSimon Horman struct of_phandle_args clkspec; 272b3a33077SSimon Horman struct clk *clk; 273b3a33077SSimon Horman int i = 0; 274b3a33077SSimon Horman int error; 275b3a33077SSimon Horman 276b3a33077SSimon Horman while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, 277b3a33077SSimon Horman &clkspec)) { 278b3a33077SSimon Horman if (of_device_is_compatible(clkspec.np, 279b3a33077SSimon Horman "renesas,cpg-mstp-clocks")) 280b3a33077SSimon Horman goto found; 281b3a33077SSimon Horman 282b3a33077SSimon Horman /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */ 28387ab1151SRob Herring if (of_node_name_eq(clkspec.np, "zb_clk")) 284b3a33077SSimon Horman goto found; 285b3a33077SSimon Horman 286b3a33077SSimon Horman of_node_put(clkspec.np); 287b3a33077SSimon Horman i++; 288b3a33077SSimon Horman } 289b3a33077SSimon Horman 290b3a33077SSimon Horman return 0; 291b3a33077SSimon Horman 292b3a33077SSimon Horman found: 293b3a33077SSimon Horman clk = of_clk_get_from_provider(&clkspec); 294b3a33077SSimon Horman of_node_put(clkspec.np); 295b3a33077SSimon Horman 296b3a33077SSimon Horman if (IS_ERR(clk)) 297b3a33077SSimon Horman return PTR_ERR(clk); 298b3a33077SSimon Horman 299b3a33077SSimon Horman error = pm_clk_create(dev); 3000f7ece0dSGeert Uytterhoeven if (error) 301b3a33077SSimon Horman goto fail_put; 302b3a33077SSimon Horman 303b3a33077SSimon Horman error = pm_clk_add_clk(dev, clk); 3040f7ece0dSGeert Uytterhoeven if (error) 305b3a33077SSimon Horman goto fail_destroy; 306b3a33077SSimon Horman 307b3a33077SSimon Horman return 0; 308b3a33077SSimon Horman 309b3a33077SSimon Horman fail_destroy: 310b3a33077SSimon Horman pm_clk_destroy(dev); 311b3a33077SSimon Horman fail_put: 312b3a33077SSimon Horman clk_put(clk); 313b3a33077SSimon Horman return error; 314b3a33077SSimon Horman } 315b3a33077SSimon Horman 31612a56817SGeert Uytterhoeven void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev) 317b3a33077SSimon Horman { 318e05e853eSGeert Uytterhoeven if (!pm_clk_no_clocks(dev)) 319b3a33077SSimon Horman pm_clk_destroy(dev); 320b3a33077SSimon Horman } 321b3a33077SSimon Horman 322b3a33077SSimon Horman void __init cpg_mstp_add_clk_domain(struct device_node *np) 323b3a33077SSimon Horman { 324b3a33077SSimon Horman struct generic_pm_domain *pd; 325b3a33077SSimon Horman u32 ncells; 326b3a33077SSimon Horman 327b3a33077SSimon Horman if (of_property_read_u32(np, "#power-domain-cells", &ncells)) { 32816673931SRob Herring pr_warn("%pOF lacks #power-domain-cells\n", np); 329b3a33077SSimon Horman return; 330b3a33077SSimon Horman } 331b3a33077SSimon Horman 332b3a33077SSimon Horman pd = kzalloc(sizeof(*pd), GFP_KERNEL); 333b3a33077SSimon Horman if (!pd) 334b3a33077SSimon Horman return; 335b3a33077SSimon Horman 336b3a33077SSimon Horman pd->name = np->name; 337744dddcaSGeert Uytterhoeven pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; 338b3a33077SSimon Horman pd->attach_dev = cpg_mstp_attach_dev; 339b3a33077SSimon Horman pd->detach_dev = cpg_mstp_detach_dev; 34020729300SGeert Uytterhoeven pm_genpd_init(pd, &pm_domain_always_on_gov, false); 341b3a33077SSimon Horman 342b3a33077SSimon Horman of_genpd_add_provider_simple(np, pd); 343b3a33077SSimon Horman } 344