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