1*a881aebcSirving-ch-lin /* 2*a881aebcSirving-ch-lin * Copyright (c) 2025, MediaTek Inc. All rights reserved. 3*a881aebcSirving-ch-lin * 4*a881aebcSirving-ch-lin * SPDX-License-Identifier: BSD-3-Clause 5*a881aebcSirving-ch-lin */ 6*a881aebcSirving-ch-lin #include <stdint.h> 7*a881aebcSirving-ch-lin 8*a881aebcSirving-ch-lin #include <common/debug.h> 9*a881aebcSirving-ch-lin #include <drivers/delay_timer.h> 10*a881aebcSirving-ch-lin #include <lib/mmio.h> 11*a881aebcSirving-ch-lin #include <lib/spinlock.h> 12*a881aebcSirving-ch-lin #include <platform_def.h> 13*a881aebcSirving-ch-lin 14*a881aebcSirving-ch-lin #include <mtcmos.h> 15*a881aebcSirving-ch-lin 16*a881aebcSirving-ch-lin #define SPM_PROJECT_CODE 0xB16 17*a881aebcSirving-ch-lin 18*a881aebcSirving-ch-lin #define PWR_RST_B BIT(0) 19*a881aebcSirving-ch-lin #define PWR_ISO BIT(1) 20*a881aebcSirving-ch-lin #define PWR_ON BIT(2) 21*a881aebcSirving-ch-lin #define PWR_ON_2ND BIT(3) 22*a881aebcSirving-ch-lin #define PWR_CLK_DIS BIT(4) 23*a881aebcSirving-ch-lin #define RTFF_SAVE BIT(24) 24*a881aebcSirving-ch-lin #define RTFF_NRESTORE BIT(25) 25*a881aebcSirving-ch-lin #define RTFF_CLK_DIS BIT(26) 26*a881aebcSirving-ch-lin #define RTFF_SAVE_FLAG BIT(27) 27*a881aebcSirving-ch-lin #define PWR_ACK BIT(30) 28*a881aebcSirving-ch-lin #define PWR_ACK_2ND BIT(31) 29*a881aebcSirving-ch-lin 30*a881aebcSirving-ch-lin #define UFS0_SRAM_PDN BIT(8) 31*a881aebcSirving-ch-lin #define UFS0_SRAM_PDN_ACK BIT(12) 32*a881aebcSirving-ch-lin 33*a881aebcSirving-ch-lin #define POWERON_CONFIG_EN (SPM_BASE + 0x0) 34*a881aebcSirving-ch-lin #define UFS0_PWR_CON (SPM_BASE + 0xE2C) 35*a881aebcSirving-ch-lin #define UFS0_PHY_PWR_CON (SPM_BASE + 0xE30) 36*a881aebcSirving-ch-lin 37*a881aebcSirving-ch-lin #define SPM_BUS_PROTECT_EN_SET (SPM_BASE + 0x90DC) 38*a881aebcSirving-ch-lin #define SPM_BUS_PROTECT_EN_CLR (SPM_BASE + 0x90E0) 39*a881aebcSirving-ch-lin #define SPM_BUS_PROTECT_CG_EN_SET (SPM_BASE + 0x90F4) 40*a881aebcSirving-ch-lin #define SPM_BUS_PROTECT_CG_EN_CLR (SPM_BASE + 0x90F8) 41*a881aebcSirving-ch-lin #define SPM_BUS_PROTECT_RDY_STA (SPM_BASE + 0x9208) 42*a881aebcSirving-ch-lin 43*a881aebcSirving-ch-lin #define UFS0_PROT_STEP1_MASK BIT(11) 44*a881aebcSirving-ch-lin #define UFS0_PHY_PROT_STEP1_MASK BIT(12) 45*a881aebcSirving-ch-lin 46*a881aebcSirving-ch-lin enum { 47*a881aebcSirving-ch-lin RELEASE_BUS_PROTECT, 48*a881aebcSirving-ch-lin SET_BUS_PROTECT 49*a881aebcSirving-ch-lin }; 50*a881aebcSirving-ch-lin 51*a881aebcSirving-ch-lin #define MTCMOS_TIMEOUT_US 500 52*a881aebcSirving-ch-lin 53*a881aebcSirving-ch-lin #define MTCMOS_ETIMEDOUT 25 54*a881aebcSirving-ch-lin 55*a881aebcSirving-ch-lin static spinlock_t mtcmos_ctrl_lock; 56*a881aebcSirving-ch-lin 57*a881aebcSirving-ch-lin static int mtcmos_wait_for_state(uint32_t reg, uint32_t mask, bool is_set) 58*a881aebcSirving-ch-lin { 59*a881aebcSirving-ch-lin uint32_t retry = MTCMOS_TIMEOUT_US; 60*a881aebcSirving-ch-lin uint32_t expect = is_set ? mask : 0; 61*a881aebcSirving-ch-lin 62*a881aebcSirving-ch-lin do { 63*a881aebcSirving-ch-lin if ((mmio_read_32(reg) & mask) == expect) 64*a881aebcSirving-ch-lin return 0; 65*a881aebcSirving-ch-lin udelay(1); 66*a881aebcSirving-ch-lin retry--; 67*a881aebcSirving-ch-lin } while (retry); 68*a881aebcSirving-ch-lin 69*a881aebcSirving-ch-lin ERROR("%s(0x%x, 0x%x, %d) timeout, reg_val=0x%x\n", 70*a881aebcSirving-ch-lin __func__, reg, mask, is_set, mmio_read_32(reg)); 71*a881aebcSirving-ch-lin 72*a881aebcSirving-ch-lin return -MTCMOS_ETIMEDOUT; 73*a881aebcSirving-ch-lin } 74*a881aebcSirving-ch-lin 75*a881aebcSirving-ch-lin 76*a881aebcSirving-ch-lin static int spm_mtcmos_ctrl_bus_prot(int state, uint32_t mask) 77*a881aebcSirving-ch-lin { 78*a881aebcSirving-ch-lin mmio_write_32(SPM_BUS_PROTECT_CG_EN_SET, mask); 79*a881aebcSirving-ch-lin 80*a881aebcSirving-ch-lin if (state == SET_BUS_PROTECT) { 81*a881aebcSirving-ch-lin mmio_write_32(SPM_BUS_PROTECT_EN_SET, mask); 82*a881aebcSirving-ch-lin if (mtcmos_wait_for_state(SPM_BUS_PROTECT_RDY_STA, mask, 83*a881aebcSirving-ch-lin true)) 84*a881aebcSirving-ch-lin return -MTCMOS_ETIMEDOUT; 85*a881aebcSirving-ch-lin } else if (state == RELEASE_BUS_PROTECT) { 86*a881aebcSirving-ch-lin mmio_write_32(SPM_BUS_PROTECT_EN_CLR, mask); 87*a881aebcSirving-ch-lin } 88*a881aebcSirving-ch-lin 89*a881aebcSirving-ch-lin mmio_write_32(SPM_BUS_PROTECT_CG_EN_CLR, mask); 90*a881aebcSirving-ch-lin 91*a881aebcSirving-ch-lin return 0; 92*a881aebcSirving-ch-lin } 93*a881aebcSirving-ch-lin 94*a881aebcSirving-ch-lin static int spm_mtcmos_ctrl(enum mtcmos_state state, uintptr_t reg, uint32_t mask) 95*a881aebcSirving-ch-lin { 96*a881aebcSirving-ch-lin int ret = 0; 97*a881aebcSirving-ch-lin 98*a881aebcSirving-ch-lin spin_lock(&mtcmos_ctrl_lock); 99*a881aebcSirving-ch-lin 100*a881aebcSirving-ch-lin mmio_write_32(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | BIT(0)); 101*a881aebcSirving-ch-lin 102*a881aebcSirving-ch-lin if (state == STA_POWER_DOWN) { 103*a881aebcSirving-ch-lin ret = spm_mtcmos_ctrl_bus_prot(SET_BUS_PROTECT, mask); 104*a881aebcSirving-ch-lin if (ret) 105*a881aebcSirving-ch-lin goto exit; 106*a881aebcSirving-ch-lin 107*a881aebcSirving-ch-lin if (reg == UFS0_PWR_CON) { 108*a881aebcSirving-ch-lin mmio_setbits_32(reg, UFS0_SRAM_PDN); 109*a881aebcSirving-ch-lin ret = mtcmos_wait_for_state(reg, UFS0_SRAM_PDN_ACK, 110*a881aebcSirving-ch-lin true); 111*a881aebcSirving-ch-lin if (ret) 112*a881aebcSirving-ch-lin goto exit; 113*a881aebcSirving-ch-lin } 114*a881aebcSirving-ch-lin 115*a881aebcSirving-ch-lin mmio_setbits_32(reg, RTFF_CLK_DIS); 116*a881aebcSirving-ch-lin mmio_setbits_32(reg, RTFF_SAVE); 117*a881aebcSirving-ch-lin mmio_clrbits_32(reg, RTFF_SAVE); 118*a881aebcSirving-ch-lin mmio_clrbits_32(reg, RTFF_CLK_DIS); 119*a881aebcSirving-ch-lin mmio_setbits_32(reg, RTFF_SAVE_FLAG); 120*a881aebcSirving-ch-lin 121*a881aebcSirving-ch-lin mmio_setbits_32(reg, PWR_ISO); 122*a881aebcSirving-ch-lin mmio_setbits_32(reg, PWR_CLK_DIS); 123*a881aebcSirving-ch-lin mmio_clrbits_32(reg, PWR_RST_B); 124*a881aebcSirving-ch-lin 125*a881aebcSirving-ch-lin mmio_clrbits_32(reg, PWR_ON); 126*a881aebcSirving-ch-lin ret = mtcmos_wait_for_state(reg, PWR_ACK, false); 127*a881aebcSirving-ch-lin if (ret) 128*a881aebcSirving-ch-lin goto exit; 129*a881aebcSirving-ch-lin 130*a881aebcSirving-ch-lin mmio_clrbits_32(reg, PWR_ON_2ND); 131*a881aebcSirving-ch-lin ret = mtcmos_wait_for_state(reg, PWR_ACK_2ND, false); 132*a881aebcSirving-ch-lin if (ret) 133*a881aebcSirving-ch-lin goto exit; 134*a881aebcSirving-ch-lin } else if (state == STA_POWER_ON) { 135*a881aebcSirving-ch-lin mmio_setbits_32(reg, PWR_ON); 136*a881aebcSirving-ch-lin ret = mtcmos_wait_for_state(reg, PWR_ACK, true); 137*a881aebcSirving-ch-lin if (ret) 138*a881aebcSirving-ch-lin goto exit; 139*a881aebcSirving-ch-lin 140*a881aebcSirving-ch-lin udelay(50); 141*a881aebcSirving-ch-lin 142*a881aebcSirving-ch-lin mmio_setbits_32(reg, PWR_ON_2ND); 143*a881aebcSirving-ch-lin ret = mtcmos_wait_for_state(reg, PWR_ACK_2ND, true); 144*a881aebcSirving-ch-lin if (ret) 145*a881aebcSirving-ch-lin goto exit; 146*a881aebcSirving-ch-lin 147*a881aebcSirving-ch-lin mmio_clrbits_32(reg, PWR_CLK_DIS); 148*a881aebcSirving-ch-lin mmio_clrbits_32(reg, PWR_ISO); 149*a881aebcSirving-ch-lin udelay(10); 150*a881aebcSirving-ch-lin mmio_setbits_32(reg, PWR_RST_B); 151*a881aebcSirving-ch-lin 152*a881aebcSirving-ch-lin if ((mmio_read_32(reg) & RTFF_SAVE_FLAG) == RTFF_SAVE_FLAG) { 153*a881aebcSirving-ch-lin mmio_setbits_32(reg, RTFF_CLK_DIS); 154*a881aebcSirving-ch-lin mmio_clrbits_32(reg, RTFF_NRESTORE); 155*a881aebcSirving-ch-lin mmio_setbits_32(reg, RTFF_NRESTORE); 156*a881aebcSirving-ch-lin mmio_clrbits_32(reg, RTFF_CLK_DIS); 157*a881aebcSirving-ch-lin } 158*a881aebcSirving-ch-lin 159*a881aebcSirving-ch-lin if (reg == UFS0_PWR_CON) { 160*a881aebcSirving-ch-lin mmio_clrbits_32(UFS0_PWR_CON, UFS0_SRAM_PDN); 161*a881aebcSirving-ch-lin ret = mtcmos_wait_for_state(UFS0_PWR_CON, 162*a881aebcSirving-ch-lin UFS0_SRAM_PDN_ACK, 163*a881aebcSirving-ch-lin false); 164*a881aebcSirving-ch-lin if (ret) 165*a881aebcSirving-ch-lin goto exit; 166*a881aebcSirving-ch-lin } 167*a881aebcSirving-ch-lin 168*a881aebcSirving-ch-lin spm_mtcmos_ctrl_bus_prot(RELEASE_BUS_PROTECT, mask); 169*a881aebcSirving-ch-lin } 170*a881aebcSirving-ch-lin 171*a881aebcSirving-ch-lin exit: 172*a881aebcSirving-ch-lin spin_unlock(&mtcmos_ctrl_lock); 173*a881aebcSirving-ch-lin return ret; 174*a881aebcSirving-ch-lin } 175*a881aebcSirving-ch-lin 176*a881aebcSirving-ch-lin int spm_mtcmos_ctrl_ufs0(enum mtcmos_state state) 177*a881aebcSirving-ch-lin { 178*a881aebcSirving-ch-lin return spm_mtcmos_ctrl(state, UFS0_PWR_CON, UFS0_PROT_STEP1_MASK); 179*a881aebcSirving-ch-lin } 180*a881aebcSirving-ch-lin 181*a881aebcSirving-ch-lin int spm_mtcmos_ctrl_ufs0_phy(enum mtcmos_state state) 182*a881aebcSirving-ch-lin { 183*a881aebcSirving-ch-lin return spm_mtcmos_ctrl(state, UFS0_PHY_PWR_CON, 184*a881aebcSirving-ch-lin UFS0_PHY_PROT_STEP1_MASK); 185*a881aebcSirving-ch-lin } 186