1 /* 2 * Copyright (c) 2024, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <errno.h> 8 9 #include <common/debug.h> 10 #include <drivers/delay_timer.h> 11 #include <lib/mmio.h> 12 13 #include "apusys_power.h" 14 #include "apusys_rv.h" 15 #include "apusys_rv_pwr_ctrl.h" 16 17 #define RPC_POWER_OFF_TIMEOUT_CNT (100000) /* 100ms */ 18 19 static int wait_for_state_ready(uint32_t reg, uint32_t mask, uint32_t expect, 20 uint32_t retry_times, uint32_t set_reg, uint32_t set_val) 21 { 22 uint32_t count = 0; 23 24 while ((mmio_read_32(reg) & mask) != expect) { 25 /* 26 * If retry_times == HW_SEM_NO_WAIT, it is just for checking if the hardware 27 * semaphore can be locked or not. The purpose is for SMMU to check NPU power 28 * status. Hence, just returning -EBUSY is okay. There is no need to show any 29 * ERROR message here. 30 */ 31 if (retry_times == HW_SEM_NO_WAIT) { 32 return -EBUSY; 33 } else if (count > retry_times) { 34 ERROR("%s: timed out, reg = %x, mask = %x, expect = %x\n", 35 __func__, reg, mask, expect); 36 return -EBUSY; 37 } 38 count += 1; 39 40 if (set_reg) 41 mmio_write_32(set_reg, set_val); 42 udelay(1); 43 } 44 45 return 0; 46 } 47 48 int apu_hw_sema_ctl_per_mbox(uint32_t sem_ctrl_addr, uint32_t sem_sta_addr, 49 uint8_t usr_bit, enum apu_hw_sem_op ctl, uint32_t timeout, 50 uint8_t bypass) 51 { 52 int ret; 53 uint8_t ctl_bit = 0; 54 55 if (ctl == HW_SEM_GET) 56 ctl_bit = 0x1; 57 else if (ctl == HW_SEM_PUT) 58 ctl_bit = 0x2; 59 else 60 return -EINVAL; 61 62 /* return fail if semaphore is currently not held by this user */ 63 if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_sta_addr) & BIT(usr_bit)) == 0) 64 && !bypass) { 65 ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n", 66 __func__, usr_bit, ctl, sem_sta_addr, mmio_read_32(sem_sta_addr)); 67 return -EINVAL; 68 } 69 70 mmio_write_32(sem_ctrl_addr, ctl_bit); 71 72 if (ctl == HW_SEM_PUT) 73 return 0; 74 75 ret = wait_for_state_ready(sem_sta_addr, BIT(usr_bit), BIT(usr_bit), timeout, 76 sem_ctrl_addr, ctl_bit); 77 if (ret) 78 return ret; 79 80 return 0; 81 } 82 83 int apusys_rv_pwr_ctrl(enum APU_PWR_OP op) 84 { 85 int ret; 86 uint32_t global_ref_cnt; 87 88 ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL, 89 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA, 90 APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_TIMEOUT, 0); 91 92 if (ret) { 93 ERROR("%s(%d): sem acquire timeout\n", __func__, op); 94 return ret; 95 } 96 97 global_ref_cnt = mmio_read_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY); 98 99 if (global_ref_cnt > 2) { 100 ERROR("%s: global_ref_cnt(%d) > 2\n", __func__, global_ref_cnt); 101 } else if (op == APU_PWR_OFF) { 102 global_ref_cnt--; 103 mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt); 104 if (global_ref_cnt == 0) 105 mmio_write_32(APU_MBOX_WKUP_CFG(11), 0); 106 } else if (op == APU_PWR_ON) { 107 global_ref_cnt++; 108 mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt); 109 if (global_ref_cnt == 1) 110 mmio_write_32(APU_MBOX_WKUP_CFG(11), 1); 111 } 112 113 ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL, 114 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA, 115 APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_TIMEOUT, 0); 116 117 if (ret) 118 ERROR("%s(%d): sem release timeout\n", __func__, op); 119 120 return ret; 121 } 122 123 int rv_iommu_hw_sem_trylock(void) 124 { 125 return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL, 126 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA, 127 APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_NO_WAIT, 0); 128 } 129 130 int rv_iommu_hw_sem_unlock(void) 131 { 132 return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL, 133 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA, 134 APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_NO_WAIT, 0); 135 } 136 137 int apu_hw_sema_ctl(uint32_t sem_addr, uint8_t usr_bit, uint8_t ctl, uint32_t timeout, 138 uint8_t bypass) 139 { 140 int ret; 141 uint8_t ctl_bit = 0; 142 143 if (ctl == HW_SEM_GET) 144 ctl_bit = usr_bit; 145 else if (ctl == HW_SEM_PUT) 146 ctl_bit = usr_bit + HW_SEM_PUT_BIT_SHIFT; 147 else 148 return -EINVAL; 149 150 if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_addr) & BIT(ctl_bit)) == 0) && !bypass) { 151 ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n", 152 __func__, usr_bit, ctl, sem_addr, mmio_read_32(sem_addr)); 153 return -EINVAL; 154 } 155 156 mmio_write_32(sem_addr, BIT(ctl_bit)); 157 158 if (ctl == HW_SEM_PUT) 159 goto end; 160 161 ret = wait_for_state_ready(sem_addr, BIT(ctl_bit), BIT(ctl_bit), timeout, 162 sem_addr, BIT(ctl_bit)); 163 if (ret) 164 return ret; 165 166 end: 167 VERBOSE("%s: sem_addr = 0x%x, usr_bit: %d, ctl: %d, sem_addr = 0x%08x\n", 168 __func__, sem_addr, usr_bit, ctl, mmio_read_32(sem_addr)); 169 170 return 0; 171 } 172 173 int apusys_infra_dcm_setup(void) 174 { 175 mmio_write_32(APU_REG_AO_GLUE_CONFG, 176 mmio_read_32(APU_REG_AO_GLUE_CONFG) | BIT(24) | BIT(26)); 177 178 return 0; 179 } 180