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 if (count > retry_times) { 26 ERROR("%s: timed out, reg = %x, mask = %x, expect = %x\n", 27 __func__, reg, mask, expect); 28 return -EBUSY; 29 } 30 count += 1; 31 32 if (set_reg) 33 mmio_write_32(set_reg, set_val); 34 udelay(1); 35 } 36 37 return 0; 38 } 39 40 int apu_hw_sema_ctl_per_mbox(uint32_t sem_ctrl_addr, uint32_t sem_sta_addr, 41 uint8_t usr_bit, enum apu_hw_sem_op ctl, uint32_t timeout, 42 uint8_t bypass) 43 { 44 int ret; 45 uint8_t ctl_bit = 0; 46 47 if (ctl == HW_SEM_GET) 48 ctl_bit = 0x1; 49 else if (ctl == HW_SEM_PUT) 50 ctl_bit = 0x2; 51 else 52 return -EINVAL; 53 54 /* return fail if semaphore is currently not held by this user */ 55 if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_sta_addr) & BIT(usr_bit)) == 0) 56 && !bypass) { 57 ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n", 58 __func__, usr_bit, ctl, sem_sta_addr, mmio_read_32(sem_sta_addr)); 59 return -EINVAL; 60 } 61 62 mmio_write_32(sem_ctrl_addr, ctl_bit); 63 64 if (ctl == HW_SEM_PUT) 65 return 0; 66 67 ret = wait_for_state_ready(sem_sta_addr, BIT(usr_bit), BIT(usr_bit), timeout, 68 sem_ctrl_addr, ctl_bit); 69 if (ret) 70 return ret; 71 72 return 0; 73 } 74 75 int apusys_rv_pwr_ctrl(enum APU_PWR_OP op) 76 { 77 int ret; 78 uint32_t global_ref_cnt; 79 80 ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL, 81 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA, 82 APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_TIMEOUT, 0); 83 84 if (ret) { 85 ERROR("%s(%d): sem acquire timeout\n", __func__, op); 86 return ret; 87 } 88 89 global_ref_cnt = mmio_read_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY); 90 91 if (global_ref_cnt > 2) { 92 ERROR("%s: global_ref_cnt(%d) > 2\n", __func__, global_ref_cnt); 93 } else if (op == APU_PWR_OFF) { 94 global_ref_cnt--; 95 mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt); 96 if (global_ref_cnt == 0) 97 mmio_write_32(APU_MBOX_WKUP_CFG(11), 0); 98 } else if (op == APU_PWR_ON) { 99 global_ref_cnt++; 100 mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt); 101 if (global_ref_cnt == 1) 102 mmio_write_32(APU_MBOX_WKUP_CFG(11), 1); 103 } 104 105 ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL, 106 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA, 107 APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_TIMEOUT, 0); 108 109 if (ret) 110 ERROR("%s(%d): sem release timeout\n", __func__, op); 111 112 return ret; 113 } 114 115 int rv_iommu_hw_sem_trylock(void) 116 { 117 return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL, 118 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA, 119 APU_HW_SEM_SYS_APMCU, HW_SEM_GET, 0, 0); 120 } 121 122 int rv_iommu_hw_sem_unlock(void) 123 { 124 return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL, 125 APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA, 126 APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, 0, 0); 127 } 128 129 int apu_hw_sema_ctl(uint32_t sem_addr, uint8_t usr_bit, uint8_t ctl, uint32_t timeout, 130 uint8_t bypass) 131 { 132 int ret; 133 uint8_t ctl_bit = 0; 134 135 if (ctl == HW_SEM_GET) 136 ctl_bit = usr_bit; 137 else if (ctl == HW_SEM_PUT) 138 ctl_bit = usr_bit + HW_SEM_PUT_BIT_SHIFT; 139 else 140 return -EINVAL; 141 142 if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_addr) & BIT(ctl_bit)) == 0) && !bypass) { 143 ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n", 144 __func__, usr_bit, ctl, sem_addr, mmio_read_32(sem_addr)); 145 return -EINVAL; 146 } 147 148 mmio_write_32(sem_addr, BIT(ctl_bit)); 149 150 if (ctl == HW_SEM_PUT) 151 goto end; 152 153 ret = wait_for_state_ready(sem_addr, BIT(ctl_bit), BIT(ctl_bit), timeout, 154 sem_addr, BIT(ctl_bit)); 155 if (ret) 156 return ret; 157 158 end: 159 VERBOSE("%s: sem_addr = 0x%x, usr_bit: %d, ctl: %d, sem_addr = 0x%08x\n", 160 __func__, sem_addr, usr_bit, ctl, mmio_read_32(sem_addr)); 161 162 return 0; 163 } 164 165 int apusys_infra_dcm_setup(void) 166 { 167 mmio_write_32(APU_REG_AO_GLUE_CONFG, 168 mmio_read_32(APU_REG_AO_GLUE_CONFG) | BIT(24) | BIT(26)); 169 170 return 0; 171 } 172