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