158fdd608SJacky Bai /*
244dea544SJacky Bai * Copyright 2019-2022 NXP
358fdd608SJacky Bai *
458fdd608SJacky Bai * SPDX-License-Identifier: BSD-3-Clause
558fdd608SJacky Bai */
658fdd608SJacky Bai
758fdd608SJacky Bai #include <stdbool.h>
858fdd608SJacky Bai #include <stdint.h>
958fdd608SJacky Bai #include <stdlib.h>
1058fdd608SJacky Bai
1158fdd608SJacky Bai #include <common/debug.h>
1258fdd608SJacky Bai #include <drivers/delay_timer.h>
1358fdd608SJacky Bai #include <lib/mmio.h>
1458fdd608SJacky Bai #include <lib/psci/psci.h>
1558fdd608SJacky Bai #include <lib/smccc.h>
1658fdd608SJacky Bai #include <services/std_svc.h>
1758fdd608SJacky Bai
1858fdd608SJacky Bai #include <gpc.h>
1958fdd608SJacky Bai #include <imx_sip_svc.h>
2058fdd608SJacky Bai #include <platform_def.h>
2158fdd608SJacky Bai
2258fdd608SJacky Bai #define CCGR(x) (0x4000 + (x) * 0x10)
2358fdd608SJacky Bai
2444dea544SJacky Bai #define MIPI_PWR_REQ BIT(0)
2544dea544SJacky Bai #define OTG1_PWR_REQ BIT(2)
2644dea544SJacky Bai #define HSIOMIX_PWR_REQ BIT(4)
2744dea544SJacky Bai #define GPUMIX_PWR_REQ BIT(7)
2844dea544SJacky Bai #define DISPMIX_PWR_REQ BIT(10)
2944dea544SJacky Bai
3044dea544SJacky Bai #define HSIOMIX_ADB400_SYNC BIT(5)
3144dea544SJacky Bai #define DISPMIX_ADB400_SYNC BIT(7)
3244dea544SJacky Bai #define GPUMIX_ADB400_SYNC (0x5 << 9)
3344dea544SJacky Bai #define HSIOMIX_ADB400_ACK BIT(23)
3444dea544SJacky Bai #define DISPMIX_ADB400_ACK BIT(25)
3544dea544SJacky Bai #define GPUMIX_ADB400_ACK (0x5 << 27)
3644dea544SJacky Bai
3744dea544SJacky Bai #define MIPI_PGC 0xc00
3844dea544SJacky Bai #define OTG1_PGC 0xc80
3944dea544SJacky Bai #define HSIOMIX_PGC 0xd00
4044dea544SJacky Bai #define GPUMIX_PGC 0xdc0
4144dea544SJacky Bai #define DISPMIX_PGC 0xe80
4244dea544SJacky Bai
4344dea544SJacky Bai enum pu_domain_id {
4444dea544SJacky Bai HSIOMIX,
4544dea544SJacky Bai OTG1 = 2,
4644dea544SJacky Bai GPUMIX = 4,
4744dea544SJacky Bai DISPMIX = 9,
4844dea544SJacky Bai MIPI,
4944dea544SJacky Bai };
5044dea544SJacky Bai
5144dea544SJacky Bai /* PU domain, add some hole to minimize the uboot change */
5244dea544SJacky Bai static struct imx_pwr_domain pu_domains[11] = {
5344dea544SJacky Bai [HSIOMIX] = IMX_MIX_DOMAIN(HSIOMIX, false),
5444dea544SJacky Bai [OTG1] = IMX_PD_DOMAIN(OTG1, true),
5544dea544SJacky Bai [GPUMIX] = IMX_MIX_DOMAIN(GPUMIX, false),
5644dea544SJacky Bai [DISPMIX] = IMX_MIX_DOMAIN(DISPMIX, false),
5744dea544SJacky Bai [MIPI] = IMX_PD_DOMAIN(MIPI, true),
5844dea544SJacky Bai };
5944dea544SJacky Bai
6044dea544SJacky Bai static unsigned int pu_domain_status;
6144dea544SJacky Bai
imx_gpc_pm_domain_enable(uint32_t domain_id,bool on)6244dea544SJacky Bai void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
6344dea544SJacky Bai {
6444dea544SJacky Bai if (domain_id > MIPI) {
6544dea544SJacky Bai return;
6644dea544SJacky Bai }
6744dea544SJacky Bai
6844dea544SJacky Bai struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
6944dea544SJacky Bai
7044dea544SJacky Bai if (on) {
7144dea544SJacky Bai if (pwr_domain->need_sync) {
7244dea544SJacky Bai pu_domain_status |= (1 << domain_id);
7344dea544SJacky Bai }
7444dea544SJacky Bai
7544dea544SJacky Bai /* HSIOMIX has no PU bit, so skip for it */
7644dea544SJacky Bai if (domain_id != HSIOMIX) {
7744dea544SJacky Bai /* clear the PGC bit */
7844dea544SJacky Bai mmio_clrbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
7944dea544SJacky Bai
8044dea544SJacky Bai /* power up the domain */
8144dea544SJacky Bai mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, pwr_domain->pwr_req);
8244dea544SJacky Bai
8344dea544SJacky Bai /* wait for power request done */
8444dea544SJacky Bai while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req) {
8544dea544SJacky Bai ;
8644dea544SJacky Bai }
8744dea544SJacky Bai }
8844dea544SJacky Bai
8944dea544SJacky Bai if (domain_id == DISPMIX) {
9044dea544SJacky Bai /* de-reset bus_blk clk and
9144dea544SJacky Bai * enable bus_blk clk
9244dea544SJacky Bai */
9344dea544SJacky Bai mmio_write_32(0x32e28000, 0x100);
9444dea544SJacky Bai mmio_write_32(0x32e28004, 0x100);
9544dea544SJacky Bai }
9644dea544SJacky Bai
9744dea544SJacky Bai /* handle the ADB400 sync */
9844dea544SJacky Bai if (pwr_domain->need_sync) {
9944dea544SJacky Bai /* clear adb power down request */
10044dea544SJacky Bai mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
10144dea544SJacky Bai
10244dea544SJacky Bai /* wait for adb power request ack */
10344dea544SJacky Bai while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
10444dea544SJacky Bai ;
10544dea544SJacky Bai }
10644dea544SJacky Bai }
10744dea544SJacky Bai } else {
10844dea544SJacky Bai pu_domain_status &= ~(1 << domain_id);
10944dea544SJacky Bai
11044dea544SJacky Bai if (domain_id == OTG1) {
11144dea544SJacky Bai return;
11244dea544SJacky Bai }
11344dea544SJacky Bai
11444dea544SJacky Bai /* handle the ADB400 sync */
11544dea544SJacky Bai if (pwr_domain->need_sync) {
11644dea544SJacky Bai
11744dea544SJacky Bai /* set adb power down request */
11844dea544SJacky Bai mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
11944dea544SJacky Bai
12044dea544SJacky Bai /* wait for adb power request ack */
12144dea544SJacky Bai while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
12244dea544SJacky Bai ;
12344dea544SJacky Bai }
12444dea544SJacky Bai }
12544dea544SJacky Bai
12644dea544SJacky Bai /* HSIOMIX has no PU bit, so skip for it */
12744dea544SJacky Bai if (domain_id != HSIOMIX) {
12844dea544SJacky Bai /* set the PGC bit */
12944dea544SJacky Bai mmio_setbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
13044dea544SJacky Bai
13144dea544SJacky Bai /* power down the domain */
13244dea544SJacky Bai mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, pwr_domain->pwr_req);
13344dea544SJacky Bai
13444dea544SJacky Bai /* wait for power request done */
13544dea544SJacky Bai while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req) {
13644dea544SJacky Bai ;
13744dea544SJacky Bai }
13844dea544SJacky Bai }
13944dea544SJacky Bai }
14044dea544SJacky Bai }
14144dea544SJacky Bai
imx_gpc_init(void)14258fdd608SJacky Bai void imx_gpc_init(void)
14358fdd608SJacky Bai {
14458fdd608SJacky Bai unsigned int val;
14558fdd608SJacky Bai int i;
14658fdd608SJacky Bai
14758fdd608SJacky Bai /* mask all the wakeup irq by default */
14858fdd608SJacky Bai for (i = 0; i < 4; i++) {
14958fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, ~0x0);
15058fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, ~0x0);
15158fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, ~0x0);
15258fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, ~0x0);
15358fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0);
15458fdd608SJacky Bai }
15558fdd608SJacky Bai
15658fdd608SJacky Bai val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
15758fdd608SJacky Bai /* use GIC wake_request to wakeup C0~C3 from LPM */
15858fdd608SJacky Bai val |= CORE_WKUP_FROM_GIC;
15958fdd608SJacky Bai /* clear the MASTER0 LPM handshake */
16058fdd608SJacky Bai val &= ~MASTER0_LPM_HSK;
16158fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
16258fdd608SJacky Bai
16358fdd608SJacky Bai /* clear MASTER1 & MASTER2 mapping in CPU0(A53) */
16458fdd608SJacky Bai mmio_clrbits_32(IMX_GPC_BASE + MST_CPU_MAPPING, (MASTER1_MAPPING |
16558fdd608SJacky Bai MASTER2_MAPPING));
16658fdd608SJacky Bai
16758fdd608SJacky Bai /* set all mix/PU in A53 domain */
16858fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xffff);
16958fdd608SJacky Bai
17058fdd608SJacky Bai /*
17158fdd608SJacky Bai * Set the CORE & SCU power up timing:
17258fdd608SJacky Bai * SW = 0x1, SW2ISO = 0x1;
173*1b491eeaSElyes Haouas * the CPU CORE and SCU power up timing counter
17458fdd608SJacky Bai * is drived by 32K OSC, each domain's power up
17558fdd608SJacky Bai * latency is (SW + SW2ISO) / 32768
17658fdd608SJacky Bai */
17758fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(0) + 0x4, 0x401);
17858fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(1) + 0x4, 0x401);
17958fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(2) + 0x4, 0x401);
18058fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(3) + 0x4, 0x401);
18158fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR + 0x4, 0x401);
18258fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
18358fdd608SJacky Bai (0x59 << TMC_TMR_SHIFT) | 0x5B | (0x2 << TRC1_TMC_SHIFT));
18458fdd608SJacky Bai
18558fdd608SJacky Bai /* set DUMMY PDN/PUP ACK by default for A53 domain */
18658fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53,
18758fdd608SJacky Bai A53_DUMMY_PUP_ACK | A53_DUMMY_PDN_ACK);
18858fdd608SJacky Bai
18958fdd608SJacky Bai /* clear DSM by default */
19058fdd608SJacky Bai val = mmio_read_32(IMX_GPC_BASE + SLPCR);
19158fdd608SJacky Bai val &= ~SLPCR_EN_DSM;
19258fdd608SJacky Bai /* enable the fast wakeup wait mode */
19358fdd608SJacky Bai val |= SLPCR_A53_FASTWUP_WAIT_MODE;
19458fdd608SJacky Bai /* clear the RBC */
19558fdd608SJacky Bai val &= ~(0x3f << SLPCR_RBC_COUNT_SHIFT);
19658fdd608SJacky Bai /* set the STBY_COUNT to 0x5, (128 * 30)us */
19758fdd608SJacky Bai val &= ~(0x7 << SLPCR_STBY_COUNT_SHFT);
19858fdd608SJacky Bai val |= (0x5 << SLPCR_STBY_COUNT_SHFT);
19958fdd608SJacky Bai mmio_write_32(IMX_GPC_BASE + SLPCR, val);
20058fdd608SJacky Bai
20158fdd608SJacky Bai /*
20258fdd608SJacky Bai * USB PHY power up needs to make sure RESET bit in SRC is clear,
20358fdd608SJacky Bai * otherwise, the PU power up bit in GPC will NOT self-cleared.
20458fdd608SJacky Bai * only need to do it once.
20558fdd608SJacky Bai */
20658fdd608SJacky Bai mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
20758fdd608SJacky Bai }
208