diff options
Diffstat (limited to 'arch/arm/mach-imx/gpc.c')
-rw-r--r-- | arch/arm/mach-imx/gpc.c | 217 |
1 files changed, 0 insertions, 217 deletions
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 1dc2a34b9dbd..93f584ba0130 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c | |||
@@ -10,26 +10,17 @@ | |||
10 | * http://www.gnu.org/copyleft/gpl.html | 10 | * http://www.gnu.org/copyleft/gpl.html |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | 13 | #include <linux/io.h> |
16 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
17 | #include <linux/irqchip.h> | 15 | #include <linux/irqchip.h> |
18 | #include <linux/of.h> | 16 | #include <linux/of.h> |
19 | #include <linux/of_address.h> | 17 | #include <linux/of_address.h> |
20 | #include <linux/of_irq.h> | 18 | #include <linux/of_irq.h> |
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pm_domain.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/irqchip/arm-gic.h> | 19 | #include <linux/irqchip/arm-gic.h> |
25 | #include "common.h" | 20 | #include "common.h" |
26 | #include "hardware.h" | 21 | #include "hardware.h" |
27 | 22 | ||
28 | #define GPC_CNTR 0x000 | ||
29 | #define GPC_IMR1 0x008 | 23 | #define GPC_IMR1 0x008 |
30 | #define GPC_PGC_GPU_PDN 0x260 | ||
31 | #define GPC_PGC_GPU_PUPSCR 0x264 | ||
32 | #define GPC_PGC_GPU_PDNSCR 0x268 | ||
33 | #define GPC_PGC_CPU_PDN 0x2a0 | 24 | #define GPC_PGC_CPU_PDN 0x2a0 |
34 | #define GPC_PGC_CPU_PUPSCR 0x2a4 | 25 | #define GPC_PGC_CPU_PUPSCR 0x2a4 |
35 | #define GPC_PGC_CPU_PDNSCR 0x2a8 | 26 | #define GPC_PGC_CPU_PDNSCR 0x2a8 |
@@ -39,18 +30,6 @@ | |||
39 | #define IMR_NUM 4 | 30 | #define IMR_NUM 4 |
40 | #define GPC_MAX_IRQS (IMR_NUM * 32) | 31 | #define GPC_MAX_IRQS (IMR_NUM * 32) |
41 | 32 | ||
42 | #define GPU_VPU_PUP_REQ BIT(1) | ||
43 | #define GPU_VPU_PDN_REQ BIT(0) | ||
44 | |||
45 | #define GPC_CLK_MAX 6 | ||
46 | |||
47 | struct pu_domain { | ||
48 | struct generic_pm_domain base; | ||
49 | struct regulator *reg; | ||
50 | struct clk *clk[GPC_CLK_MAX]; | ||
51 | int num_clks; | ||
52 | }; | ||
53 | |||
54 | static void __iomem *gpc_base; | 33 | static void __iomem *gpc_base; |
55 | static u32 gpc_wake_irqs[IMR_NUM]; | 34 | static u32 gpc_wake_irqs[IMR_NUM]; |
56 | static u32 gpc_saved_imrs[IMR_NUM]; | 35 | static u32 gpc_saved_imrs[IMR_NUM]; |
@@ -296,199 +275,3 @@ void __init imx_gpc_check_dt(void) | |||
296 | gpc_base = of_iomap(np, 0); | 275 | gpc_base = of_iomap(np, 0); |
297 | } | 276 | } |
298 | } | 277 | } |
299 | |||
300 | static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) | ||
301 | { | ||
302 | int iso, iso2sw; | ||
303 | u32 val; | ||
304 | |||
305 | /* Read ISO and ISO2SW power down delays */ | ||
306 | val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR); | ||
307 | iso = val & 0x3f; | ||
308 | iso2sw = (val >> 8) & 0x3f; | ||
309 | |||
310 | /* Gate off PU domain when GPU/VPU when powered down */ | ||
311 | writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); | ||
312 | |||
313 | /* Request GPC to power down GPU/VPU */ | ||
314 | val = readl_relaxed(gpc_base + GPC_CNTR); | ||
315 | val |= GPU_VPU_PDN_REQ; | ||
316 | writel_relaxed(val, gpc_base + GPC_CNTR); | ||
317 | |||
318 | /* Wait ISO + ISO2SW IPG clock cycles */ | ||
319 | ndelay((iso + iso2sw) * 1000 / 66); | ||
320 | } | ||
321 | |||
322 | static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) | ||
323 | { | ||
324 | struct pu_domain *pu = container_of(genpd, struct pu_domain, base); | ||
325 | |||
326 | _imx6q_pm_pu_power_off(genpd); | ||
327 | |||
328 | if (pu->reg) | ||
329 | regulator_disable(pu->reg); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd) | ||
335 | { | ||
336 | struct pu_domain *pu = container_of(genpd, struct pu_domain, base); | ||
337 | int i, ret, sw, sw2iso; | ||
338 | u32 val; | ||
339 | |||
340 | if (pu->reg) | ||
341 | ret = regulator_enable(pu->reg); | ||
342 | if (pu->reg && ret) { | ||
343 | pr_err("%s: failed to enable regulator: %d\n", __func__, ret); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | /* Enable reset clocks for all devices in the PU domain */ | ||
348 | for (i = 0; i < pu->num_clks; i++) | ||
349 | clk_prepare_enable(pu->clk[i]); | ||
350 | |||
351 | /* Gate off PU domain when GPU/VPU when powered down */ | ||
352 | writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN); | ||
353 | |||
354 | /* Read ISO and ISO2SW power down delays */ | ||
355 | val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR); | ||
356 | sw = val & 0x3f; | ||
357 | sw2iso = (val >> 8) & 0x3f; | ||
358 | |||
359 | /* Request GPC to power up GPU/VPU */ | ||
360 | val = readl_relaxed(gpc_base + GPC_CNTR); | ||
361 | val |= GPU_VPU_PUP_REQ; | ||
362 | writel_relaxed(val, gpc_base + GPC_CNTR); | ||
363 | |||
364 | /* Wait ISO + ISO2SW IPG clock cycles */ | ||
365 | ndelay((sw + sw2iso) * 1000 / 66); | ||
366 | |||
367 | /* Disable reset clocks for all devices in the PU domain */ | ||
368 | for (i = 0; i < pu->num_clks; i++) | ||
369 | clk_disable_unprepare(pu->clk[i]); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static struct generic_pm_domain imx6q_arm_domain = { | ||
375 | .name = "ARM", | ||
376 | }; | ||
377 | |||
378 | static struct pu_domain imx6q_pu_domain = { | ||
379 | .base = { | ||
380 | .name = "PU", | ||
381 | .power_off = imx6q_pm_pu_power_off, | ||
382 | .power_on = imx6q_pm_pu_power_on, | ||
383 | }, | ||
384 | }; | ||
385 | |||
386 | static struct generic_pm_domain imx6sl_display_domain = { | ||
387 | .name = "DISPLAY", | ||
388 | }; | ||
389 | |||
390 | static struct generic_pm_domain *imx_gpc_domains[] = { | ||
391 | &imx6q_arm_domain, | ||
392 | &imx6q_pu_domain.base, | ||
393 | &imx6sl_display_domain, | ||
394 | }; | ||
395 | |||
396 | static struct genpd_onecell_data imx_gpc_onecell_data = { | ||
397 | .domains = imx_gpc_domains, | ||
398 | .num_domains = ARRAY_SIZE(imx_gpc_domains), | ||
399 | }; | ||
400 | |||
401 | static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg) | ||
402 | { | ||
403 | struct clk *clk; | ||
404 | int i, ret; | ||
405 | |||
406 | imx6q_pu_domain.reg = pu_reg; | ||
407 | |||
408 | for (i = 0; ; i++) { | ||
409 | clk = of_clk_get(dev->of_node, i); | ||
410 | if (IS_ERR(clk)) | ||
411 | break; | ||
412 | if (i >= GPC_CLK_MAX) { | ||
413 | dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX); | ||
414 | goto clk_err; | ||
415 | } | ||
416 | imx6q_pu_domain.clk[i] = clk; | ||
417 | } | ||
418 | imx6q_pu_domain.num_clks = i; | ||
419 | |||
420 | /* Enable power always in case bootloader disabled it. */ | ||
421 | imx6q_pm_pu_power_on(&imx6q_pu_domain.base); | ||
422 | |||
423 | if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) | ||
424 | return 0; | ||
425 | |||
426 | imx6q_pu_domain.base.states = devm_kzalloc(dev, | ||
427 | sizeof(*imx6q_pu_domain.base.states), | ||
428 | GFP_KERNEL); | ||
429 | if (!imx6q_pu_domain.base.states) | ||
430 | return -ENOMEM; | ||
431 | |||
432 | imx6q_pu_domain.base.states[0].power_off_latency_ns = 25000; | ||
433 | imx6q_pu_domain.base.states[0].power_on_latency_ns = 2000000; | ||
434 | imx6q_pu_domain.base.state_count = 1; | ||
435 | |||
436 | for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++) | ||
437 | pm_genpd_init(imx_gpc_domains[i], NULL, false); | ||
438 | |||
439 | ret = of_genpd_add_provider_onecell(dev->of_node, | ||
440 | &imx_gpc_onecell_data); | ||
441 | if (ret) | ||
442 | goto power_off; | ||
443 | |||
444 | return 0; | ||
445 | |||
446 | power_off: | ||
447 | imx6q_pm_pu_power_off(&imx6q_pu_domain.base); | ||
448 | clk_err: | ||
449 | while (i--) | ||
450 | clk_put(imx6q_pu_domain.clk[i]); | ||
451 | imx6q_pu_domain.reg = NULL; | ||
452 | return -EINVAL; | ||
453 | } | ||
454 | |||
455 | static int imx_gpc_probe(struct platform_device *pdev) | ||
456 | { | ||
457 | struct regulator *pu_reg; | ||
458 | int ret; | ||
459 | |||
460 | /* bail out if DT too old and doesn't provide the necessary info */ | ||
461 | if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells")) | ||
462 | return 0; | ||
463 | |||
464 | pu_reg = devm_regulator_get_optional(&pdev->dev, "pu"); | ||
465 | if (PTR_ERR(pu_reg) == -ENODEV) | ||
466 | pu_reg = NULL; | ||
467 | if (IS_ERR(pu_reg)) { | ||
468 | ret = PTR_ERR(pu_reg); | ||
469 | dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret); | ||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | return imx_gpc_genpd_init(&pdev->dev, pu_reg); | ||
474 | } | ||
475 | |||
476 | static const struct of_device_id imx_gpc_dt_ids[] = { | ||
477 | { .compatible = "fsl,imx6q-gpc" }, | ||
478 | { .compatible = "fsl,imx6sl-gpc" }, | ||
479 | { } | ||
480 | }; | ||
481 | |||
482 | static struct platform_driver imx_gpc_driver = { | ||
483 | .driver = { | ||
484 | .name = "imx-gpc", | ||
485 | .of_match_table = imx_gpc_dt_ids, | ||
486 | }, | ||
487 | .probe = imx_gpc_probe, | ||
488 | }; | ||
489 | |||
490 | static int __init imx_pgc_init(void) | ||
491 | { | ||
492 | return platform_driver_register(&imx_gpc_driver); | ||
493 | } | ||
494 | subsys_initcall(imx_pgc_init); | ||