.. | .. |
---|
15 | 15 | #include <asm/fiq_glue.h> |
---|
16 | 16 | #include <asm/tlbflush.h> |
---|
17 | 17 | #include <asm/suspend.h> |
---|
| 18 | +#include <linux/irqchip/arm-gic.h> |
---|
18 | 19 | |
---|
19 | 20 | #include "rkpm_gicv2.h" |
---|
20 | 21 | #include "rkpm_helpers.h" |
---|
.. | .. |
---|
91 | 92 | static void __iomem *pmu_base; |
---|
92 | 93 | static void __iomem *nstimer_base; |
---|
93 | 94 | static void __iomem *stimer_base; |
---|
| 95 | +static void __iomem *mbox_base; |
---|
94 | 96 | static void __iomem *ddrc_base; |
---|
95 | 97 | static void __iomem *ioc_base[5]; |
---|
96 | 98 | static void __iomem *gpio_base[5]; |
---|
.. | .. |
---|
309 | 311 | |
---|
310 | 312 | static void gic400_restore(void) |
---|
311 | 313 | { |
---|
312 | | - rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save); |
---|
| 314 | + if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP)) |
---|
| 315 | + writel_relaxed(0x3, gicd_base + GIC_DIST_CTRL); |
---|
| 316 | + else |
---|
| 317 | + rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save); |
---|
313 | 318 | rkpm_gicv2_cpu_restore(gicd_base, gicc_base, &gicc_ctx_save); |
---|
314 | 319 | } |
---|
315 | 320 | |
---|
.. | .. |
---|
408 | 413 | |
---|
409 | 414 | rkpm_bootdata_l2ctlr_f = 1; |
---|
410 | 415 | rkpm_bootdata_l2ctlr = rv1106_l2_config(); |
---|
| 416 | +} |
---|
| 417 | + |
---|
| 418 | +static void writel_clrset_bits(u32 clr, u32 set, void __iomem *addr) |
---|
| 419 | +{ |
---|
| 420 | + u32 val = readl_relaxed(addr); |
---|
| 421 | + |
---|
| 422 | + val &= ~clr; |
---|
| 423 | + val |= set; |
---|
| 424 | + writel_relaxed(val, addr); |
---|
| 425 | +} |
---|
| 426 | + |
---|
| 427 | +static void gic_irq_en(int irq) |
---|
| 428 | +{ |
---|
| 429 | + writel_clrset_bits(0xff << irq % 4 * 8, 0x1 << irq % 4 * 8, |
---|
| 430 | + gicd_base + GIC_DIST_TARGET + (irq >> 2 << 2)); |
---|
| 431 | + writel_clrset_bits(0xff << irq % 4 * 8, 0xa0 << irq % 4 * 8, |
---|
| 432 | + gicd_base + GIC_DIST_PRI + (irq >> 2 << 2)); |
---|
| 433 | + writel_clrset_bits(0x3 << irq % 16 * 2, 0x1 << irq % 16 * 2, |
---|
| 434 | + gicd_base + GIC_DIST_CONFIG + (irq >> 4 << 2)); |
---|
| 435 | + writel_clrset_bits(BIT(irq % 32), BIT(irq % 32), |
---|
| 436 | + gicd_base + GIC_DIST_IGROUP + (irq >> 5 << 2)); |
---|
| 437 | + |
---|
| 438 | + dsb(sy); |
---|
| 439 | + writel_relaxed(0x1 << irq % 32, gicd_base + GIC_DIST_ENABLE_SET + (irq >> 5 << 2)); |
---|
| 440 | + dsb(sy); |
---|
| 441 | +} |
---|
| 442 | + |
---|
| 443 | +static int is_hpmcu_mbox_int(void) |
---|
| 444 | +{ |
---|
| 445 | + return !!(readl(mbox_base + RV1106_MBOX_B2A_STATUS) & BIT(0)); |
---|
| 446 | +} |
---|
| 447 | + |
---|
| 448 | +static void hpmcu_start(void) |
---|
| 449 | +{ |
---|
| 450 | + /* enable hpmcu mailbox AP irq */ |
---|
| 451 | + gic_irq_en(RV1106_HPMCU_MBOX_IRQ_AP); |
---|
| 452 | + |
---|
| 453 | + /* tell hpmcu that we are currently in system wake up. */ |
---|
| 454 | + writel(RV1106_SYS_IS_WKUP, pmu_base + RV1106_PMU_SYS_REG(0)); |
---|
| 455 | + |
---|
| 456 | + /* set the mcu uncache area, usually set the devices address */ |
---|
| 457 | + writel(0xff000, coregrf_base + RV1106_COREGRF_CACHE_PERI_ADDR_START); |
---|
| 458 | + writel(0xffc00, coregrf_base + RV1106_COREGRF_CACHE_PERI_ADDR_END); |
---|
| 459 | + /* Reset the hp mcu */ |
---|
| 460 | + writel(0x1e001e, corecru_base + RV1106_COERCRU_SFTRST_CON(1)); |
---|
| 461 | + /* set the mcu addr */ |
---|
| 462 | + writel(RV1106_HPMCU_BOOT_ADDR, |
---|
| 463 | + coresgrf_base + RV1106_CORESGRF_HPMCU_BOOTADDR); |
---|
| 464 | + dsb(sy); |
---|
| 465 | + |
---|
| 466 | + /* release the mcu */ |
---|
| 467 | + writel(0x1e0000, corecru_base + RV1106_COERCRU_SFTRST_CON(1)); |
---|
| 468 | + dsb(sy); |
---|
| 469 | +} |
---|
| 470 | + |
---|
| 471 | +static int hpmcu_fast_wkup(void) |
---|
| 472 | +{ |
---|
| 473 | + u32 cmd; |
---|
| 474 | + |
---|
| 475 | + hpmcu_start(); |
---|
| 476 | + |
---|
| 477 | + while (1) { |
---|
| 478 | + rkpm_printstr("-s-\n"); |
---|
| 479 | + dsb(sy); |
---|
| 480 | + wfi(); |
---|
| 481 | + rkpm_printstr("-w-\n"); |
---|
| 482 | + |
---|
| 483 | + if (is_hpmcu_mbox_int()) { |
---|
| 484 | + rkpm_printstr("-h-mbox-\n"); |
---|
| 485 | + /* clear system wake up state */ |
---|
| 486 | + writel(0, pmu_base + RV1106_PMU_SYS_REG(0)); |
---|
| 487 | + writel(BIT(0), mbox_base + RV1106_MBOX_B2A_STATUS); |
---|
| 488 | + break; |
---|
| 489 | + } |
---|
| 490 | + } |
---|
| 491 | + |
---|
| 492 | + cmd = readl(mbox_base + RV1106_MBOX_B2A_CMD_0); |
---|
| 493 | + if (cmd == RV1106_MBOX_CMD_AP_SUSPEND) |
---|
| 494 | + return 1; |
---|
| 495 | + else |
---|
| 496 | + return 0; |
---|
411 | 497 | } |
---|
412 | 498 | |
---|
413 | 499 | static void clock_suspend(void) |
---|
.. | .. |
---|
616 | 702 | ddr_data.ioc1_1a_iomux_l = readl_relaxed(ioc_base[1] + 0); |
---|
617 | 703 | |
---|
618 | 704 | pmu_wkup_con = |
---|
619 | | - /* BIT(RV1106_PMU_WAKEUP_TIMEROUT_EN) | */ |
---|
620 | 705 | /* BIT(RV1106_PMU_WAKEUP_CPU_INT_EN) | */ |
---|
621 | 706 | BIT(RV1106_PMU_WAKEUP_GPIO_INT_EN) | |
---|
622 | 707 | 0; |
---|
| 708 | + if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP)) |
---|
| 709 | + pmu_wkup_con |= BIT(RV1106_PMU_WAKEUP_TIMEROUT_EN); |
---|
623 | 710 | |
---|
624 | 711 | pmu_pwr_con = |
---|
625 | 712 | BIT(RV1106_PMU_PWRMODE_EN) | |
---|
.. | .. |
---|
949 | 1036 | |
---|
950 | 1037 | cpu_do_idle(); |
---|
951 | 1038 | |
---|
952 | | - pr_err("%s: Failed to suspend\n", __func__); |
---|
| 1039 | +#if RV1106_WAKEUP_TO_SYSTEM_RESET |
---|
| 1040 | + /* If reaches here, it means wakeup source cames before cpu enter wfi. |
---|
| 1041 | + * So we should do system reset if RV1106_WAKEUP_TO_SYSTEM_RESET. |
---|
| 1042 | + */ |
---|
| 1043 | + writel_relaxed(0x000c000c, cru_base + RV1106_CRU_GLB_RST_CON); |
---|
| 1044 | + writel_relaxed(0xffff0000, pmugrf_base + RV1106_PMUGRF_SOC_CON(4)); |
---|
| 1045 | + writel_relaxed(0xffff0000, pmugrf_base + RV1106_PMUGRF_SOC_CON(5)); |
---|
| 1046 | + dsb(sy); |
---|
| 1047 | + writel_relaxed(0xfdb9, cru_base + RV1106_CRU_GLB_SRST_FST); |
---|
| 1048 | +#endif |
---|
| 1049 | + |
---|
| 1050 | + rkpm_printstr("Failed to suspend\n"); |
---|
953 | 1051 | |
---|
954 | 1052 | return 1; |
---|
955 | 1053 | } |
---|
.. | .. |
---|
964 | 1062 | |
---|
965 | 1063 | rkpm_printch('-'); |
---|
966 | 1064 | |
---|
| 1065 | +RE_ENTER_SLEEP: |
---|
967 | 1066 | clock_suspend(); |
---|
968 | 1067 | rkpm_printch('0'); |
---|
969 | 1068 | |
---|
.. | .. |
---|
1000 | 1099 | |
---|
1001 | 1100 | clock_resume(); |
---|
1002 | 1101 | rkpm_printch('-'); |
---|
| 1102 | + |
---|
| 1103 | + /* Check whether it's time_out wakeup */ |
---|
| 1104 | + if (IS_ENABLED(CONFIG_RV1106_HPMCU_FAST_WAKEUP) && ddr_data.pmu_wkup_int_st == 0) { |
---|
| 1105 | + if (hpmcu_fast_wkup()) { |
---|
| 1106 | + rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save); |
---|
| 1107 | + goto RE_ENTER_SLEEP; |
---|
| 1108 | + } else { |
---|
| 1109 | + rkpm_gicv2_dist_restore(gicd_base, &gicd_ctx_save); |
---|
| 1110 | + rkpm_gicv2_cpu_restore(gicd_base, gicc_base, &gicc_ctx_save); |
---|
| 1111 | + } |
---|
| 1112 | + } |
---|
1003 | 1113 | |
---|
1004 | 1114 | fiq_glue_resume(); |
---|
1005 | 1115 | |
---|
.. | .. |
---|
1062 | 1172 | corecru_base = dev_reg_base + RV1106_CORECRU_OFFSET; |
---|
1063 | 1173 | venccru_base = dev_reg_base + RV1106_VENCCRU_OFFSET; |
---|
1064 | 1174 | vocru_base = dev_reg_base + RV1106_VOCRU_OFFSET; |
---|
| 1175 | + mbox_base = dev_reg_base + RV1106_MBOX_OFFSET; |
---|
1065 | 1176 | |
---|
1066 | 1177 | ioc_base[0] = dev_reg_base + RV1106_GPIO0IOC_OFFSET; |
---|
1067 | 1178 | ioc_base[1] = dev_reg_base + RV1106_GPIO1IOC_OFFSET; |
---|