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