1*c33b98d7SYidi Lin /* 2*c33b98d7SYidi Lin * Copyright (c) 2025, Mediatek Inc. All rights reserved. 3*c33b98d7SYidi Lin * 4*c33b98d7SYidi Lin * SPDX-License-Identifier: BSD-3-Clause 5*c33b98d7SYidi Lin */ 6*c33b98d7SYidi Lin 7*c33b98d7SYidi Lin #include <common/debug.h> 8*c33b98d7SYidi Lin #include <drivers/delay_timer.h> 9*c33b98d7SYidi Lin #include <lib/mmio.h> 10*c33b98d7SYidi Lin 11*c33b98d7SYidi Lin #include <drivers/mminfra_public.h> 12*c33b98d7SYidi Lin #include <mminfra.h> 13*c33b98d7SYidi Lin #include <mtk_mmap_pool.h> 14*c33b98d7SYidi Lin 15*c33b98d7SYidi Lin static const mmap_region_t mminfra_plat_mmap[] MTK_MMAP_SECTION = { 16*c33b98d7SYidi Lin MAP_REGION_FLAT(MMINFRA_HW_VOTER_BASE, PAGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), 17*c33b98d7SYidi Lin {0} 18*c33b98d7SYidi Lin }; 19*c33b98d7SYidi Lin DECLARE_MTK_MMAP_REGIONS(mminfra_plat_mmap); 20*c33b98d7SYidi Lin 21*c33b98d7SYidi Lin static struct mtk_mminfra_pwr_ctrl mminfra_pwr_ctrl = { 22*c33b98d7SYidi Lin .hw_voter = { 23*c33b98d7SYidi Lin .base = MMINFRA_HW_VOTER_BASE, 24*c33b98d7SYidi Lin .set_ofs = 0x104, 25*c33b98d7SYidi Lin .clr_ofs = 0x108, 26*c33b98d7SYidi Lin .en_ofs = 0x100, 27*c33b98d7SYidi Lin .en_shift = 0x1, 28*c33b98d7SYidi Lin .done_bits = VLP_AO_RSVD6, 29*c33b98d7SYidi Lin }, 30*c33b98d7SYidi Lin .hw_sema = { 31*c33b98d7SYidi Lin .base = SPM_BASE, 32*c33b98d7SYidi Lin .offset = SPM_SEMAPHORE_M1, 33*c33b98d7SYidi Lin .offset_all = { 34*c33b98d7SYidi Lin SPM_SEMAPHORE_M0, 35*c33b98d7SYidi Lin SPM_SEMAPHORE_M1, 36*c33b98d7SYidi Lin SPM_SEMAPHORE_M2, 37*c33b98d7SYidi Lin SPM_SEMAPHORE_M3, 38*c33b98d7SYidi Lin SPM_SEMAPHORE_M4, 39*c33b98d7SYidi Lin SPM_SEMAPHORE_M5, 40*c33b98d7SYidi Lin SPM_SEMAPHORE_M6, 41*c33b98d7SYidi Lin SPM_SEMAPHORE_M7, 42*c33b98d7SYidi Lin }, 43*c33b98d7SYidi Lin .set_val = SPM_SEMA_MMINFRA, 44*c33b98d7SYidi Lin }, 45*c33b98d7SYidi Lin .active = true, 46*c33b98d7SYidi Lin .ref_cnt = 0, 47*c33b98d7SYidi Lin }; 48*c33b98d7SYidi Lin 49*c33b98d7SYidi Lin static int spm_semaphore_get(uint32_t base, uint32_t set_val) 50*c33b98d7SYidi Lin { 51*c33b98d7SYidi Lin int cnt = SEMA_RETRY_CNT; 52*c33b98d7SYidi Lin uint32_t val; 53*c33b98d7SYidi Lin 54*c33b98d7SYidi Lin val = mmio_read_32(base); 55*c33b98d7SYidi Lin if ((val & set_val) == set_val) { 56*c33b98d7SYidi Lin mminfra_err("hw_sem was already got, base:0x%x=0x%x, set_val:0x%x\n", 57*c33b98d7SYidi Lin base, val, set_val); 58*c33b98d7SYidi Lin return -1; 59*c33b98d7SYidi Lin } 60*c33b98d7SYidi Lin 61*c33b98d7SYidi Lin while (cnt > 0) { 62*c33b98d7SYidi Lin mmio_write_32(base, set_val); 63*c33b98d7SYidi Lin udelay(10); 64*c33b98d7SYidi Lin if ((mmio_read_32(base) & set_val) == set_val) 65*c33b98d7SYidi Lin return 0; 66*c33b98d7SYidi Lin cnt--; 67*c33b98d7SYidi Lin } 68*c33b98d7SYidi Lin 69*c33b98d7SYidi Lin mminfra_err("timeout! base:0x%x, set_val:0x%x\n", base, set_val); 70*c33b98d7SYidi Lin return -1; 71*c33b98d7SYidi Lin } 72*c33b98d7SYidi Lin 73*c33b98d7SYidi Lin static int spm_semaphore_release(uint32_t base, uint32_t set_val) 74*c33b98d7SYidi Lin { 75*c33b98d7SYidi Lin int cnt = SEMA_RETRY_CNT; 76*c33b98d7SYidi Lin uint32_t val; 77*c33b98d7SYidi Lin 78*c33b98d7SYidi Lin val = mmio_read_32(base); 79*c33b98d7SYidi Lin if ((val & set_val) != set_val) { 80*c33b98d7SYidi Lin mminfra_err("hw_sem was already released, base:0x%x=0x%x, set_val:0x%x\n", 81*c33b98d7SYidi Lin base, val, set_val); 82*c33b98d7SYidi Lin return -1; 83*c33b98d7SYidi Lin } 84*c33b98d7SYidi Lin do { 85*c33b98d7SYidi Lin mmio_write_32(base, set_val); 86*c33b98d7SYidi Lin udelay(10); 87*c33b98d7SYidi Lin if (cnt-- < 0) { 88*c33b98d7SYidi Lin if ((mmio_read_32(base) & set_val) != set_val) 89*c33b98d7SYidi Lin return 0; 90*c33b98d7SYidi Lin mminfra_err("timeout! base:0x%x, set_val:0x%x\n", base, set_val); 91*c33b98d7SYidi Lin return -1; 92*c33b98d7SYidi Lin } 93*c33b98d7SYidi Lin } while ((mmio_read_32(base) & set_val) == set_val); 94*c33b98d7SYidi Lin 95*c33b98d7SYidi Lin return 0; 96*c33b98d7SYidi Lin } 97*c33b98d7SYidi Lin 98*c33b98d7SYidi Lin static int mminfra_hw_sema_ctrl(struct mminfra_hw_sema *hw_sema, bool is_get) 99*c33b98d7SYidi Lin { 100*c33b98d7SYidi Lin int i, ret; 101*c33b98d7SYidi Lin 102*c33b98d7SYidi Lin if (!hw_sema) 103*c33b98d7SYidi Lin return 0; 104*c33b98d7SYidi Lin 105*c33b98d7SYidi Lin if (is_get) 106*c33b98d7SYidi Lin ret = spm_semaphore_get(hw_sema->base + hw_sema->offset, hw_sema->set_val); 107*c33b98d7SYidi Lin else 108*c33b98d7SYidi Lin ret = spm_semaphore_release(hw_sema->base + hw_sema->offset, hw_sema->set_val); 109*c33b98d7SYidi Lin 110*c33b98d7SYidi Lin if (ret) 111*c33b98d7SYidi Lin for (i = 0; i < SPM_SEMA_MMINFRA_NR; i++) 112*c33b98d7SYidi Lin mminfra_err("0x%x=0x%x\n", hw_sema->base + hw_sema->offset_all[i], 113*c33b98d7SYidi Lin mmio_read_32(hw_sema->base + hw_sema->offset_all[i])); 114*c33b98d7SYidi Lin 115*c33b98d7SYidi Lin return ret; 116*c33b98d7SYidi Lin } 117*c33b98d7SYidi Lin 118*c33b98d7SYidi Lin static bool is_mminfra_ready(struct mminfra_hw_voter *hw_voter) 119*c33b98d7SYidi Lin { 120*c33b98d7SYidi Lin if (!hw_voter) 121*c33b98d7SYidi Lin return false; 122*c33b98d7SYidi Lin 123*c33b98d7SYidi Lin return !!(mmio_read_32(hw_voter->done_bits) & MMINFRA_DONE); 124*c33b98d7SYidi Lin } 125*c33b98d7SYidi Lin 126*c33b98d7SYidi Lin static int mminfra_hwv_power_ctrl(struct mminfra_hw_voter *hw_voter, bool is_on) 127*c33b98d7SYidi Lin { 128*c33b98d7SYidi Lin uint32_t vote_ofs, vote_mask, vote_ack; 129*c33b98d7SYidi Lin uint32_t val = 0, cnt; 130*c33b98d7SYidi Lin 131*c33b98d7SYidi Lin vote_mask = BIT(hw_voter->en_shift); 132*c33b98d7SYidi Lin vote_ofs = is_on ? hw_voter->set_ofs : hw_voter->clr_ofs; 133*c33b98d7SYidi Lin vote_ack = is_on ? vote_mask : 0x0; 134*c33b98d7SYidi Lin 135*c33b98d7SYidi Lin /* Vote on off */ 136*c33b98d7SYidi Lin cnt = 0; 137*c33b98d7SYidi Lin do { 138*c33b98d7SYidi Lin mmio_write_32(hw_voter->base + vote_ofs, vote_mask); 139*c33b98d7SYidi Lin udelay(MTK_POLL_HWV_VOTE_US); 140*c33b98d7SYidi Lin val = mmio_read_32(hw_voter->base + hw_voter->en_ofs); 141*c33b98d7SYidi Lin if ((val & vote_mask) == vote_ack) 142*c33b98d7SYidi Lin break; 143*c33b98d7SYidi Lin 144*c33b98d7SYidi Lin if (cnt > MTK_POLL_HWV_VOTE_CNT) { 145*c33b98d7SYidi Lin mminfra_err("vote mminfra timeout, is_on:%d, 0x%x=0x%x\n", 146*c33b98d7SYidi Lin is_on, hw_voter->base + hw_voter->en_ofs, val); 147*c33b98d7SYidi Lin return -1; 148*c33b98d7SYidi Lin } 149*c33b98d7SYidi Lin cnt++; 150*c33b98d7SYidi Lin } while (1); 151*c33b98d7SYidi Lin 152*c33b98d7SYidi Lin if (!is_on) 153*c33b98d7SYidi Lin return 0; 154*c33b98d7SYidi Lin 155*c33b98d7SYidi Lin /* Confirm done bits */ 156*c33b98d7SYidi Lin cnt = 0; 157*c33b98d7SYidi Lin while (cnt < MTK_POLL_DONE_RETRY) { 158*c33b98d7SYidi Lin if (is_mminfra_ready(hw_voter)) 159*c33b98d7SYidi Lin return 0; 160*c33b98d7SYidi Lin udelay(MTK_POLL_DONE_DELAY_US); 161*c33b98d7SYidi Lin cnt++; 162*c33b98d7SYidi Lin } 163*c33b98d7SYidi Lin 164*c33b98d7SYidi Lin mminfra_err("polling mminfra done timeout, 0x%x=0x%x\n", 165*c33b98d7SYidi Lin hw_voter->done_bits, val); 166*c33b98d7SYidi Lin return -1; 167*c33b98d7SYidi Lin } 168*c33b98d7SYidi Lin 169*c33b98d7SYidi Lin int mminfra_get_if_in_use(void) 170*c33b98d7SYidi Lin { 171*c33b98d7SYidi Lin int ret, is_on = MMINFRA_RET_POWER_OFF; 172*c33b98d7SYidi Lin 173*c33b98d7SYidi Lin if (!mminfra_pwr_ctrl.active) { 174*c33b98d7SYidi Lin mminfra_err("not ready\n"); 175*c33b98d7SYidi Lin return MMINFRA_RET_POWER_OFF; 176*c33b98d7SYidi Lin } 177*c33b98d7SYidi Lin 178*c33b98d7SYidi Lin spin_lock(&mminfra_pwr_ctrl.lock); 179*c33b98d7SYidi Lin if (mminfra_pwr_ctrl.ref_cnt > 0) { 180*c33b98d7SYidi Lin mminfra_pwr_ctrl.ref_cnt++; 181*c33b98d7SYidi Lin is_on = MMINFRA_RET_POWER_ON; 182*c33b98d7SYidi Lin spin_unlock(&mminfra_pwr_ctrl.lock); 183*c33b98d7SYidi Lin return is_on; 184*c33b98d7SYidi Lin } 185*c33b98d7SYidi Lin 186*c33b98d7SYidi Lin ret = mminfra_hw_sema_ctrl(&mminfra_pwr_ctrl.hw_sema, true); 187*c33b98d7SYidi Lin if (ret) 188*c33b98d7SYidi Lin goto err; 189*c33b98d7SYidi Lin 190*c33b98d7SYidi Lin /* Check if mminfra is in use */ 191*c33b98d7SYidi Lin if (is_mminfra_ready(&mminfra_pwr_ctrl.hw_voter)) { 192*c33b98d7SYidi Lin ret = mminfra_hwv_power_ctrl(&mminfra_pwr_ctrl.hw_voter, true); 193*c33b98d7SYidi Lin if (ret) { 194*c33b98d7SYidi Lin mminfra_err("vote for mminfra fail, ret=%d\n", ret); 195*c33b98d7SYidi Lin goto err; 196*c33b98d7SYidi Lin } 197*c33b98d7SYidi Lin mminfra_pwr_ctrl.ref_cnt++; 198*c33b98d7SYidi Lin is_on = MMINFRA_RET_POWER_ON; 199*c33b98d7SYidi Lin } else { 200*c33b98d7SYidi Lin is_on = MMINFRA_RET_POWER_OFF; 201*c33b98d7SYidi Lin } 202*c33b98d7SYidi Lin 203*c33b98d7SYidi Lin ret = mminfra_hw_sema_ctrl(&mminfra_pwr_ctrl.hw_sema, false); 204*c33b98d7SYidi Lin if (ret) 205*c33b98d7SYidi Lin goto err; 206*c33b98d7SYidi Lin ret = is_on; /* Return power is on or off. */ 207*c33b98d7SYidi Lin err: 208*c33b98d7SYidi Lin spin_unlock(&mminfra_pwr_ctrl.lock); 209*c33b98d7SYidi Lin return ret; 210*c33b98d7SYidi Lin } 211*c33b98d7SYidi Lin 212*c33b98d7SYidi Lin int mminfra_put(void) 213*c33b98d7SYidi Lin { 214*c33b98d7SYidi Lin if (!mminfra_pwr_ctrl.active) { 215*c33b98d7SYidi Lin mminfra_err("not ready\n"); 216*c33b98d7SYidi Lin return 0; 217*c33b98d7SYidi Lin } 218*c33b98d7SYidi Lin 219*c33b98d7SYidi Lin spin_lock(&mminfra_pwr_ctrl.lock); 220*c33b98d7SYidi Lin mminfra_pwr_ctrl.ref_cnt--; 221*c33b98d7SYidi Lin if (mminfra_pwr_ctrl.ref_cnt > 0) 222*c33b98d7SYidi Lin goto out; 223*c33b98d7SYidi Lin 224*c33b98d7SYidi Lin mminfra_hwv_power_ctrl(&mminfra_pwr_ctrl.hw_voter, false); 225*c33b98d7SYidi Lin out: 226*c33b98d7SYidi Lin spin_unlock(&mminfra_pwr_ctrl.lock); 227*c33b98d7SYidi Lin return 0; 228*c33b98d7SYidi Lin } 229