gpc.c (eb5bc2a213f96bd43b5f00a625acb0c669613645) | gpc.c (00eb60a8b4f7a4aa00fd8abd68c2dc7aec55df19) |
---|---|
1/* 2 * Copyright 2011-2013 Freescale Semiconductor, Inc. 3 * Copyright 2011 Linaro Ltd. 4 * 5 * The code contained herein is licensed under the GNU General Public 6 * License. You may obtain a copy of the GNU General Public License 7 * Version 2 or later at the following locations: 8 * 9 * http://www.opensource.org/licenses/gpl-license.html 10 * http://www.gnu.org/copyleft/gpl.html 11 */ 12 | 1/* 2 * Copyright 2011-2013 Freescale Semiconductor, Inc. 3 * Copyright 2011 Linaro Ltd. 4 * 5 * The code contained herein is licensed under the GNU General Public 6 * License. You may obtain a copy of the GNU General Public License 7 * Version 2 or later at the following locations: 8 * 9 * http://www.opensource.org/licenses/gpl-license.html 10 * http://www.gnu.org/copyleft/gpl.html 11 */ 12 |
13#include <linux/clk.h> 14#include <linux/delay.h> |
|
13#include <linux/io.h> 14#include <linux/irq.h> 15#include <linux/of.h> 16#include <linux/of_address.h> 17#include <linux/of_irq.h> | 15#include <linux/io.h> 16#include <linux/irq.h> 17#include <linux/of.h> 18#include <linux/of_address.h> 19#include <linux/of_irq.h> |
20#include <linux/platform_device.h> 21#include <linux/pm_domain.h> 22#include <linux/regulator/consumer.h> |
|
18#include <linux/irqchip/arm-gic.h> 19#include "common.h" | 23#include <linux/irqchip/arm-gic.h> 24#include "common.h" |
25#include "hardware.h" |
|
20 | 26 |
27#define GPC_CNTR 0x000 |
|
21#define GPC_IMR1 0x008 | 28#define GPC_IMR1 0x008 |
29#define GPC_PGC_GPU_PDN 0x260 30#define GPC_PGC_GPU_PUPSCR 0x264 31#define GPC_PGC_GPU_PDNSCR 0x268 |
|
22#define GPC_PGC_CPU_PDN 0x2a0 23#define GPC_PGC_CPU_PUPSCR 0x2a4 24#define GPC_PGC_CPU_PDNSCR 0x2a8 25#define GPC_PGC_SW2ISO_SHIFT 0x8 26#define GPC_PGC_SW_SHIFT 0x0 27 28#define IMR_NUM 4 29 | 32#define GPC_PGC_CPU_PDN 0x2a0 33#define GPC_PGC_CPU_PUPSCR 0x2a4 34#define GPC_PGC_CPU_PDNSCR 0x2a8 35#define GPC_PGC_SW2ISO_SHIFT 0x8 36#define GPC_PGC_SW_SHIFT 0x0 37 38#define IMR_NUM 4 39 |
40#define GPU_VPU_PUP_REQ BIT(1) 41#define GPU_VPU_PDN_REQ BIT(0) 42 43#define GPC_CLK_MAX 6 44 45struct pu_domain { 46 struct generic_pm_domain base; 47 struct regulator *reg; 48 struct clk *clk[GPC_CLK_MAX]; 49 int num_clks; 50}; 51 |
|
30static void __iomem *gpc_base; 31static u32 gpc_wake_irqs[IMR_NUM]; 32static u32 gpc_saved_imrs[IMR_NUM]; 33 34void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw) 35{ 36 writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) | 37 (sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PUPSCR); --- 127 unchanged lines hidden (view full) --- 165 for (i = 0; i < IMR_NUM; i++) 166 writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); 167 168 /* Register GPC as the secondary interrupt controller behind GIC */ 169 gic_arch_extn.irq_mask = imx_gpc_irq_mask; 170 gic_arch_extn.irq_unmask = imx_gpc_irq_unmask; 171 gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake; 172} | 52static void __iomem *gpc_base; 53static u32 gpc_wake_irqs[IMR_NUM]; 54static u32 gpc_saved_imrs[IMR_NUM]; 55 56void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw) 57{ 58 writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) | 59 (sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PUPSCR); --- 127 unchanged lines hidden (view full) --- 187 for (i = 0; i < IMR_NUM; i++) 188 writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); 189 190 /* Register GPC as the secondary interrupt controller behind GIC */ 191 gic_arch_extn.irq_mask = imx_gpc_irq_mask; 192 gic_arch_extn.irq_unmask = imx_gpc_irq_unmask; 193 gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake; 194} |
195 196#ifdef CONFIG_PM_GENERIC_DOMAINS 197 198static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) 199{ 200 int iso, iso2sw; 201 u32 val; 202 203 /* Read ISO and ISO2SW power down delays */ 204 val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR); 205 iso = val & 0x3f; 206 iso2sw = (val >> 8) & 0x3f; 207 208 /* Gate off PU domain when GPU/VPU when powered down */ 209 writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); 210 211 /* Request GPC to power down GPU/VPU */ 212 val = readl_relaxed(gpc_base + GPC_CNTR); 213 val |= GPU_VPU_PDN_REQ; 214 writel_relaxed(val, gpc_base + GPC_CNTR); 215 216 /* Wait ISO + ISO2SW IPG clock cycles */ 217 ndelay((iso + iso2sw) * 1000 / 66); 218} 219 220static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) 221{ 222 struct pu_domain *pu = container_of(genpd, struct pu_domain, base); 223 224 _imx6q_pm_pu_power_off(genpd); 225 226 if (pu->reg) 227 regulator_disable(pu->reg); 228 229 return 0; 230} 231 232static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd) 233{ 234 struct pu_domain *pu = container_of(genpd, struct pu_domain, base); 235 int i, ret, sw, sw2iso; 236 u32 val; 237 238 if (pu->reg) 239 ret = regulator_enable(pu->reg); 240 if (pu->reg && ret) { 241 pr_err("%s: failed to enable regulator: %d\n", __func__, ret); 242 return ret; 243 } 244 245 /* Enable reset clocks for all devices in the PU domain */ 246 for (i = 0; i < pu->num_clks; i++) 247 clk_prepare_enable(pu->clk[i]); 248 249 /* Gate off PU domain when GPU/VPU when powered down */ 250 writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); 251 252 /* Read ISO and ISO2SW power down delays */ 253 val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR); 254 sw = val & 0x3f; 255 sw2iso = (val >> 8) & 0x3f; 256 257 /* Request GPC to power up GPU/VPU */ 258 val = readl_relaxed(gpc_base + GPC_CNTR); 259 val |= GPU_VPU_PUP_REQ; 260 writel_relaxed(val, gpc_base + GPC_CNTR); 261 262 /* Wait ISO + ISO2SW IPG clock cycles */ 263 ndelay((sw + sw2iso) * 1000 / 66); 264 265 /* Disable reset clocks for all devices in the PU domain */ 266 for (i = 0; i < pu->num_clks; i++) 267 clk_disable_unprepare(pu->clk[i]); 268 269 return 0; 270} 271 272static struct generic_pm_domain imx6q_arm_domain = { 273 .name = "ARM", 274}; 275 276static struct pu_domain imx6q_pu_domain = { 277 .base = { 278 .name = "PU", 279 .power_off = imx6q_pm_pu_power_off, 280 .power_on = imx6q_pm_pu_power_on, 281 .power_off_latency_ns = 25000, 282 .power_on_latency_ns = 2000000, 283 }, 284}; 285 286static struct generic_pm_domain imx6sl_display_domain = { 287 .name = "DISPLAY", 288}; 289 290static struct generic_pm_domain *imx_gpc_domains[] = { 291 &imx6q_arm_domain, 292 &imx6q_pu_domain.base, 293 &imx6sl_display_domain, 294}; 295 296static struct genpd_onecell_data imx_gpc_onecell_data = { 297 .domains = imx_gpc_domains, 298 .num_domains = ARRAY_SIZE(imx_gpc_domains), 299}; 300 301static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) 302{ 303 struct clk *clk; 304 bool is_off; 305 int i; 306 307 imx6q_pu_domain.reg = pu_reg; 308 309 for (i = 0; ; i++) { 310 clk = of_clk_get(dev->of_node, i); 311 if (IS_ERR(clk)) 312 break; 313 if (i >= GPC_CLK_MAX) { 314 dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX); 315 goto clk_err; 316 } 317 imx6q_pu_domain.clk[i] = clk; 318 } 319 imx6q_pu_domain.num_clks = i; 320 321 is_off = IS_ENABLED(CONFIG_PM); 322 if (is_off) { 323 _imx6q_pm_pu_power_off(&imx6q_pu_domain.base); 324 } else { 325 /* 326 * Enable power if compiled without CONFIG_PM in case the 327 * bootloader disabled it. 328 */ 329 imx6q_pm_pu_power_on(&imx6q_pu_domain.base); 330 } 331 332 pm_genpd_init(&imx6q_pu_domain.base, NULL, is_off); 333 return of_genpd_add_provider_onecell(dev->of_node, 334 &imx_gpc_onecell_data); 335 336clk_err: 337 while (i--) 338 clk_put(imx6q_pu_domain.clk[i]); 339 return -EINVAL; 340} 341 342#else 343static inline int imx_gpc_genpd_init(struct device *dev, struct regulator *reg) 344{ 345 return 0; 346} 347#endif /* CONFIG_PM_GENERIC_DOMAINS */ 348 349static int imx_gpc_probe(struct platform_device *pdev) 350{ 351 struct regulator *pu_reg; 352 int ret; 353 354 pu_reg = devm_regulator_get_optional(&pdev->dev, "pu"); 355 if (PTR_ERR(pu_reg) == -ENODEV) 356 pu_reg = NULL; 357 if (IS_ERR(pu_reg)) { 358 ret = PTR_ERR(pu_reg); 359 dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret); 360 return ret; 361 } 362 363 return imx_gpc_genpd_init(&pdev->dev, pu_reg); 364} 365 366static const struct of_device_id imx_gpc_dt_ids[] = { 367 { .compatible = "fsl,imx6q-gpc" }, 368 { .compatible = "fsl,imx6sl-gpc" }, 369 { } 370}; 371 372static struct platform_driver imx_gpc_driver = { 373 .driver = { 374 .name = "imx-gpc", 375 .owner = THIS_MODULE, 376 .of_match_table = imx_gpc_dt_ids, 377 }, 378 .probe = imx_gpc_probe, 379}; 380 381static int __init imx_pgc_init(void) 382{ 383 return platform_driver_register(&imx_gpc_driver); 384} 385subsys_initcall(imx_pgc_init); |
|