1 /* 2 * Copyright (c) 2019, ARM Limited and Contributors. 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 #include <sspm_reg.h> 11 #include <mtk_mcdi.h> 12 13 static inline uint32_t mcdi_mbox_read(uint32_t id) 14 { 15 return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2)); 16 } 17 18 static inline void mcdi_mbox_write(uint32_t id, uint32_t val) 19 { 20 mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val); 21 } 22 23 void sspm_set_bootaddr(uint32_t bootaddr) 24 { 25 mcdi_mbox_write(MCDI_MBOX_BOOTADDR, bootaddr); 26 } 27 28 void sspm_cluster_pwr_off_notify(uint32_t cluster) 29 { 30 mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 1); 31 } 32 33 void sspm_cluster_pwr_on_notify(uint32_t cluster) 34 { 35 mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 0); 36 } 37 38 void sspm_standbywfi_irq_enable(uint32_t cpu_idx) 39 { 40 mmio_write_32(SSPM_CFGREG_ACAO_INT_SET, STANDBYWFI_EN(cpu_idx)); 41 } 42 43 uint32_t mcdi_avail_cpu_mask_read(void) 44 { 45 return mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); 46 } 47 48 uint32_t mcdi_avail_cpu_mask_write(uint32_t mask) 49 { 50 mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, mask); 51 52 return mask; 53 } 54 55 uint32_t mcdi_avail_cpu_mask_set(uint32_t mask) 56 { 57 uint32_t m; 58 59 m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); 60 m |= mask; 61 mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m); 62 63 return m; 64 } 65 66 uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask) 67 { 68 uint32_t m; 69 70 m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); 71 m &= ~mask; 72 mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m); 73 74 return m; 75 } 76 77 uint32_t mcdi_cpu_cluster_pwr_stat_read(void) 78 { 79 return mcdi_mbox_read(MCDI_MBOX_CPU_CLUSTER_PWR_STAT); 80 } 81 82 #define PAUSE_BIT 1 83 #define CLUSTER_OFF_OFS 20 84 #define CPU_OFF_OFS 24 85 #define CLUSTER_ON_OFS 4 86 #define CPU_ON_OFS 8 87 88 static uint32_t target_mask(int cluster, int cpu_idx, bool on) 89 { 90 uint32_t t = 0; 91 92 if (on) { 93 if (cluster >= 0) 94 t |= BIT(cluster + CLUSTER_ON_OFS); 95 96 if (cpu_idx >= 0) 97 t |= BIT(cpu_idx + CPU_ON_OFS); 98 } else { 99 if (cluster >= 0) 100 t |= BIT(cluster + CLUSTER_OFF_OFS); 101 102 if (cpu_idx >= 0) 103 t |= BIT(cpu_idx + CPU_OFF_OFS); 104 } 105 106 return t; 107 } 108 109 void mcdi_pause_clr(int cluster, int cpu_idx, bool on) 110 { 111 uint32_t tgt = target_mask(cluster, cpu_idx, on); 112 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION); 113 114 m &= ~tgt; 115 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 116 } 117 118 void mcdi_pause_set(int cluster, int cpu_idx, bool on) 119 { 120 uint32_t tgt = target_mask(cluster, cpu_idx, on); 121 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION); 122 uint32_t tgtn = target_mask(-1, cpu_idx, !on); 123 124 /* request on and off at the same time to ensure it can be paused */ 125 m |= tgt | tgtn; 126 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 127 128 /* wait pause_ack */ 129 while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK)) 130 ; 131 132 /* clear non-requested operation */ 133 m &= ~tgtn; 134 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 135 } 136 137 void mcdi_pause(void) 138 { 139 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT); 140 141 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 142 143 /* wait pause_ack */ 144 while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK)) 145 ; 146 } 147 148 void mcdi_unpause(void) 149 { 150 uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT); 151 152 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 153 } 154 155 void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on) 156 { 157 uint32_t tgt = target_mask(cluster, cpu_idx, on); 158 uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); 159 160 /* wait until ack */ 161 while (!(ack & tgt)) 162 ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); 163 } 164 165 void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on) 166 { 167 uint32_t tgt = target_mask(cluster, cpu_idx, on); 168 uint32_t tgt_cpu = target_mask(-1, cpu_idx, on); 169 uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD); 170 uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); 171 172 if (!(cmd & tgt)) 173 return; 174 175 /* wait until ack */ 176 while (!(ack & tgt_cpu)) 177 ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); 178 179 cmd &= ~tgt; 180 mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd); 181 } 182 183 void mcdi_hotplug_set(int cluster, int cpu_idx, bool on) 184 { 185 uint32_t tgt = target_mask(cluster, cpu_idx, on); 186 uint32_t tgt_cpu = target_mask(-1, cpu_idx, on); 187 uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD); 188 uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); 189 190 if ((cmd & tgt) == tgt) 191 return; 192 193 /* wait until ack clear */ 194 while (ack & tgt_cpu) 195 ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); 196 197 cmd |= tgt; 198 mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd); 199 } 200 201 bool check_mcdi_ctl_stat(void) 202 { 203 uint32_t clk_regs[] = {0x100010ac, 0x100010c8}; 204 uint32_t clk_mask[] = {0x00028000, 0x00000018}; 205 uint32_t tgt = target_mask(0, 0, true); 206 uint32_t m; 207 int i; 208 209 /* check clk status */ 210 for (i = 0; i < ARRAY_SIZE(clk_regs); i++) { 211 if (mmio_read_32(clk_regs[i]) & clk_mask[i]) { 212 WARN("mcdi: clk check fail.\n"); 213 return false; 214 } 215 } 216 217 /* check mcdi cmd handling */ 218 m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT); 219 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 220 221 i = 500; 222 while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK) && --i > 0) 223 udelay(10); 224 225 m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT); 226 mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); 227 228 if (i == 0) { 229 WARN("mcdi: pause_action fail.\n"); 230 return false; 231 } 232 233 /* check mcdi cmd handling */ 234 if (mcdi_mbox_read(MCDI_MBOX_HP_CMD) || 235 mcdi_mbox_read(MCDI_MBOX_HP_ACK)) { 236 WARN("mcdi: hp_cmd fail.\n"); 237 return false; 238 } 239 240 mcdi_mbox_write(MCDI_MBOX_HP_CMD, tgt); 241 242 i = 500; 243 while ((mcdi_mbox_read(MCDI_MBOX_HP_ACK) & tgt) != tgt && --i > 0) 244 udelay(10); 245 246 mcdi_mbox_write(MCDI_MBOX_HP_CMD, 0); 247 248 if (i == 0) { 249 WARN("mcdi: hp_ack fail.\n"); 250 return false; 251 } 252 253 return true; 254 } 255 256 void mcdi_init(void) 257 { 258 mcdi_avail_cpu_mask_write(0x01); /* cpu0 default on */ 259 } 260