1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021 Linaro Ltd. 4 * Copyright (C) 2021 Dávid Virág <virag.david003@gmail.com> 5 * Author: Sam Protsenko <semen.protsenko@linaro.org> 6 * Author: Dávid Virág <virag.david003@gmail.com> 7 * 8 * This file contains shared functions used by some arm64 Exynos SoCs, 9 * such as Exynos7885 or Exynos850 to register and init CMUs. 10 */ 11 #include <linux/clk.h> 12 #include <linux/of_address.h> 13 #include <linux/of_device.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/slab.h> 16 17 #include "clk-exynos-arm64.h" 18 19 /* Gate register bits */ 20 #define GATE_MANUAL BIT(20) 21 #define GATE_ENABLE_HWACG BIT(28) 22 23 /* Gate register offsets range */ 24 #define GATE_OFF_START 0x2000 25 #define GATE_OFF_END 0x2fff 26 27 struct exynos_arm64_cmu_data { 28 struct samsung_clk_reg_dump *clk_save; 29 unsigned int nr_clk_save; 30 const struct samsung_clk_reg_dump *clk_suspend; 31 unsigned int nr_clk_suspend; 32 33 struct clk *clk; 34 struct clk **pclks; 35 int nr_pclks; 36 37 struct samsung_clk_provider *ctx; 38 }; 39 40 /** 41 * exynos_arm64_init_clocks - Set clocks initial configuration 42 * @np: CMU device tree node with "reg" property (CMU addr) 43 * @reg_offs: Register offsets array for clocks to init 44 * @reg_offs_len: Number of register offsets in reg_offs array 45 * 46 * Set manual control mode for all gate clocks. 47 */ 48 static void __init exynos_arm64_init_clocks(struct device_node *np, 49 const unsigned long *reg_offs, size_t reg_offs_len) 50 { 51 void __iomem *reg_base; 52 size_t i; 53 54 reg_base = of_iomap(np, 0); 55 if (!reg_base) 56 panic("%s: failed to map registers\n", __func__); 57 58 for (i = 0; i < reg_offs_len; ++i) { 59 void __iomem *reg = reg_base + reg_offs[i]; 60 u32 val; 61 62 /* Modify only gate clock registers */ 63 if (reg_offs[i] < GATE_OFF_START || reg_offs[i] > GATE_OFF_END) 64 continue; 65 66 val = readl(reg); 67 val |= GATE_MANUAL; 68 val &= ~GATE_ENABLE_HWACG; 69 writel(val, reg); 70 } 71 72 iounmap(reg_base); 73 } 74 75 /** 76 * exynos_arm64_enable_bus_clk - Enable parent clock of specified CMU 77 * 78 * @dev: Device object; may be NULL if this function is not being 79 * called from platform driver probe function 80 * @np: CMU device tree node 81 * @cmu: CMU data 82 * 83 * Keep CMU parent clock running (needed for CMU registers access). 84 * 85 * Return: 0 on success or a negative error code on failure. 86 */ 87 static int __init exynos_arm64_enable_bus_clk(struct device *dev, 88 struct device_node *np, const struct samsung_cmu_info *cmu) 89 { 90 struct clk *parent_clk; 91 92 if (!cmu->clk_name) 93 return 0; 94 95 if (dev) { 96 struct exynos_arm64_cmu_data *data; 97 98 parent_clk = clk_get(dev, cmu->clk_name); 99 data = dev_get_drvdata(dev); 100 if (data) 101 data->clk = parent_clk; 102 } else { 103 parent_clk = of_clk_get_by_name(np, cmu->clk_name); 104 } 105 106 if (IS_ERR(parent_clk)) 107 return PTR_ERR(parent_clk); 108 109 return clk_prepare_enable(parent_clk); 110 } 111 112 static int __init exynos_arm64_cmu_prepare_pm(struct device *dev, 113 const struct samsung_cmu_info *cmu) 114 { 115 struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); 116 int i; 117 118 data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs, 119 cmu->nr_clk_regs); 120 if (!data->clk_save) 121 return -ENOMEM; 122 123 data->nr_clk_save = cmu->nr_clk_regs; 124 data->clk_suspend = cmu->suspend_regs; 125 data->nr_clk_suspend = cmu->nr_suspend_regs; 126 data->nr_pclks = of_clk_get_parent_count(dev->of_node); 127 if (!data->nr_pclks) 128 return 0; 129 130 data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks, 131 GFP_KERNEL); 132 if (!data->pclks) { 133 kfree(data->clk_save); 134 return -ENOMEM; 135 } 136 137 for (i = 0; i < data->nr_pclks; i++) { 138 struct clk *clk = of_clk_get(dev->of_node, i); 139 140 if (IS_ERR(clk)) { 141 kfree(data->clk_save); 142 while (--i >= 0) 143 clk_put(data->pclks[i]); 144 return PTR_ERR(clk); 145 } 146 data->pclks[i] = clk; 147 } 148 149 return 0; 150 } 151 152 /** 153 * exynos_arm64_register_cmu - Register specified Exynos CMU domain 154 * @dev: Device object; may be NULL if this function is not being 155 * called from platform driver probe function 156 * @np: CMU device tree node 157 * @cmu: CMU data 158 * 159 * Register specified CMU domain, which includes next steps: 160 * 161 * 1. Enable parent clock of @cmu CMU 162 * 2. Set initial registers configuration for @cmu CMU clocks 163 * 3. Register @cmu CMU clocks using Samsung clock framework API 164 */ 165 void __init exynos_arm64_register_cmu(struct device *dev, 166 struct device_node *np, const struct samsung_cmu_info *cmu) 167 { 168 int err; 169 170 /* 171 * Try to boot even if the parent clock enablement fails, as it might be 172 * already enabled by bootloader. 173 */ 174 err = exynos_arm64_enable_bus_clk(dev, np, cmu); 175 if (err) 176 pr_err("%s: could not enable bus clock %s; err = %d\n", 177 __func__, cmu->clk_name, err); 178 179 exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs); 180 samsung_cmu_register_one(np, cmu); 181 } 182 183 /** 184 * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support 185 * 186 * @pdev: Platform device object 187 * @set_manual: If true, set gate clocks to manual mode 188 * 189 * It's a version of exynos_arm64_register_cmu() with PM support. Should be 190 * called from probe function of platform driver. 191 * 192 * Return: 0 on success, or negative error code on error. 193 */ 194 int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev, 195 bool set_manual) 196 { 197 const struct samsung_cmu_info *cmu; 198 struct device *dev = &pdev->dev; 199 struct device_node *np = dev->of_node; 200 struct exynos_arm64_cmu_data *data; 201 void __iomem *reg_base; 202 int ret; 203 204 cmu = of_device_get_match_data(dev); 205 206 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 207 if (!data) 208 return -ENOMEM; 209 210 platform_set_drvdata(pdev, data); 211 212 ret = exynos_arm64_cmu_prepare_pm(dev, cmu); 213 if (ret) 214 return ret; 215 216 /* 217 * Try to boot even if the parent clock enablement fails, as it might be 218 * already enabled by bootloader. 219 */ 220 ret = exynos_arm64_enable_bus_clk(dev, NULL, cmu); 221 if (ret) 222 dev_err(dev, "%s: could not enable bus clock %s; err = %d\n", 223 __func__, cmu->clk_name, ret); 224 225 if (set_manual) 226 exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs); 227 228 reg_base = devm_platform_ioremap_resource(pdev, 0); 229 if (IS_ERR(reg_base)) 230 return PTR_ERR(reg_base); 231 232 data->ctx = samsung_clk_init(dev, reg_base, cmu->nr_clk_ids); 233 234 /* 235 * Enable runtime PM here to allow the clock core using runtime PM 236 * for the registered clocks. Additionally, we increase the runtime 237 * PM usage count before registering the clocks, to prevent the 238 * clock core from runtime suspending the device. 239 */ 240 pm_runtime_get_noresume(dev); 241 pm_runtime_set_active(dev); 242 pm_runtime_enable(dev); 243 244 samsung_cmu_register_clocks(data->ctx, cmu); 245 samsung_clk_of_add_provider(dev->of_node, data->ctx); 246 pm_runtime_put_sync(dev); 247 248 return 0; 249 } 250 251 int exynos_arm64_cmu_suspend(struct device *dev) 252 { 253 struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); 254 int i; 255 256 samsung_clk_save(data->ctx->reg_base, data->clk_save, 257 data->nr_clk_save); 258 259 for (i = 0; i < data->nr_pclks; i++) 260 clk_prepare_enable(data->pclks[i]); 261 262 /* For suspend some registers have to be set to certain values */ 263 samsung_clk_restore(data->ctx->reg_base, data->clk_suspend, 264 data->nr_clk_suspend); 265 266 for (i = 0; i < data->nr_pclks; i++) 267 clk_disable_unprepare(data->pclks[i]); 268 269 clk_disable_unprepare(data->clk); 270 271 return 0; 272 } 273 274 int exynos_arm64_cmu_resume(struct device *dev) 275 { 276 struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); 277 int i; 278 279 clk_prepare_enable(data->clk); 280 281 for (i = 0; i < data->nr_pclks; i++) 282 clk_prepare_enable(data->pclks[i]); 283 284 samsung_clk_restore(data->ctx->reg_base, data->clk_save, 285 data->nr_clk_save); 286 287 for (i = 0; i < data->nr_pclks; i++) 288 clk_disable_unprepare(data->pclks[i]); 289 290 return 0; 291 } 292