|
10 | 10 | * http://www.gnu.org/copyleft/gpl.html |
11 | 11 | */ |
12 | 12 |
|
13 | | -#include <linux/clk.h> |
14 | | -#include <linux/delay.h> |
15 | 13 | #include <linux/io.h> |
16 | 14 | #include <linux/irq.h> |
17 | 15 | #include <linux/irqchip.h> |
18 | 16 | #include <linux/of.h> |
19 | 17 | #include <linux/of_address.h> |
20 | 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 | 19 | #include <linux/irqchip/arm-gic.h> |
25 | 20 | #include "common.h" |
26 | 21 | #include "hardware.h" |
27 | 22 |
|
28 | | -#define GPC_CNTR 0x000 |
29 | 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 | 24 | #define GPC_PGC_CPU_PDN 0x2a0 |
34 | 25 | #define GPC_PGC_CPU_PUPSCR 0x2a4 |
35 | 26 | #define GPC_PGC_CPU_PDNSCR 0x2a8 |
|
39 | 30 | #define IMR_NUM 4 |
40 | 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 | 33 | static void __iomem *gpc_base; |
55 | 34 | static u32 gpc_wake_irqs[IMR_NUM]; |
56 | 35 | static u32 gpc_saved_imrs[IMR_NUM]; |
@@ -296,199 +275,3 @@ void __init imx_gpc_check_dt(void) |
296 | 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); |
0 commit comments