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