Browse Source
Add MCDI driver for power saving. Signed-off-by: kenny liang <kenny.liang@mediatek.com> Change-Id: I93ecff4d7581f678be09dd8fb5dfaaccd5f2c22cpull/1934/head
kenny liang
5 years ago
6 changed files with 757 additions and 83 deletions
@ -0,0 +1,259 @@ |
|||
/*
|
|||
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. |
|||
* |
|||
* SPDX-License-Identifier: BSD-3-Clause |
|||
*/ |
|||
|
|||
#include <common/debug.h> |
|||
#include <drivers/delay_timer.h> |
|||
#include <lib/mmio.h> |
|||
#include <sspm_reg.h> |
|||
#include <mtk_mcdi.h> |
|||
|
|||
static inline uint32_t mcdi_mbox_read(uint32_t id) |
|||
{ |
|||
return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2)); |
|||
} |
|||
|
|||
static inline void mcdi_mbox_write(uint32_t id, uint32_t val) |
|||
{ |
|||
mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val); |
|||
} |
|||
|
|||
void sspm_set_bootaddr(uint32_t bootaddr) |
|||
{ |
|||
mcdi_mbox_write(MCDI_MBOX_BOOTADDR, bootaddr); |
|||
} |
|||
|
|||
void sspm_cluster_pwr_off_notify(uint32_t cluster) |
|||
{ |
|||
mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 1); |
|||
} |
|||
|
|||
void sspm_cluster_pwr_on_notify(uint32_t cluster) |
|||
{ |
|||
mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 0); |
|||
} |
|||
|
|||
void sspm_standbywfi_irq_enable(uint32_t cpu_idx) |
|||
{ |
|||
mmio_write_32(SSPM_CFGREG_ACAO_INT_SET, STANDBYWFI_EN(cpu_idx)); |
|||
} |
|||
|
|||
uint32_t mcdi_avail_cpu_mask_read(void) |
|||
{ |
|||
return mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); |
|||
} |
|||
|
|||
uint32_t mcdi_avail_cpu_mask_write(uint32_t mask) |
|||
{ |
|||
mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, mask); |
|||
|
|||
return mask; |
|||
} |
|||
|
|||
uint32_t mcdi_avail_cpu_mask_set(uint32_t mask) |
|||
{ |
|||
uint32_t m; |
|||
|
|||
m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); |
|||
m |= mask; |
|||
mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m); |
|||
|
|||
return m; |
|||
} |
|||
|
|||
uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask) |
|||
{ |
|||
uint32_t m; |
|||
|
|||
m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); |
|||
m &= ~mask; |
|||
mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m); |
|||
|
|||
return m; |
|||
} |
|||
|
|||
uint32_t mcdi_cpu_cluster_pwr_stat_read(void) |
|||
{ |
|||
return mcdi_mbox_read(MCDI_MBOX_CPU_CLUSTER_PWR_STAT); |
|||
} |
|||
|
|||
#define PAUSE_BIT 1 |
|||
#define CLUSTER_OFF_OFS 20 |
|||
#define CPU_OFF_OFS 24 |
|||
#define CLUSTER_ON_OFS 4 |
|||
#define CPU_ON_OFS 8 |
|||
|
|||
static uint32_t target_mask(int cluster, int cpu_idx, bool on) |
|||
{ |
|||
uint32_t t = 0; |
|||
|
|||
if (on) { |
|||
if (cluster >= 0) |
|||
t |= BIT(cluster + CLUSTER_ON_OFS); |
|||
|
|||
if (cpu_idx >= 0) |
|||
t |= BIT(cpu_idx + CPU_ON_OFS); |
|||
} else { |
|||
if (cluster >= 0) |
|||
t |= BIT(cluster + CLUSTER_OFF_OFS); |
|||
|
|||
if (cpu_idx >= 0) |
|||
t |= BIT(cpu_idx + CPU_OFF_OFS); |
|||
} |
|||
|
|||
return t; |
|||
} |
|||
|
|||
void mcdi_pause_clr(int cluster, int cpu_idx, bool on) |
|||
{ |
|||
uint32_t tgt = target_mask(cluster, cpu_idx, on); |
|||
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION); |
|||
|
|||
m &= ~tgt; |
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
} |
|||
|
|||
void mcdi_pause_set(int cluster, int cpu_idx, bool on) |
|||
{ |
|||
uint32_t tgt = target_mask(cluster, cpu_idx, on); |
|||
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION); |
|||
uint32_t tgtn = target_mask(-1, cpu_idx, !on); |
|||
|
|||
/* request on and off at the same time to ensure it can be paused */ |
|||
m |= tgt | tgtn; |
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
|
|||
/* wait pause_ack */ |
|||
while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK)) |
|||
; |
|||
|
|||
/* clear non-requested operation */ |
|||
m &= ~tgtn; |
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
} |
|||
|
|||
void mcdi_pause(void) |
|||
{ |
|||
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT); |
|||
|
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
|
|||
/* wait pause_ack */ |
|||
while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK)) |
|||
; |
|||
} |
|||
|
|||
void mcdi_unpause(void) |
|||
{ |
|||
uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT); |
|||
|
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
} |
|||
|
|||
void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on) |
|||
{ |
|||
uint32_t tgt = target_mask(cluster, cpu_idx, on); |
|||
uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); |
|||
|
|||
/* wait until ack */ |
|||
while (!(ack & tgt)) |
|||
ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); |
|||
} |
|||
|
|||
void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on) |
|||
{ |
|||
uint32_t tgt = target_mask(cluster, cpu_idx, on); |
|||
uint32_t tgt_cpu = target_mask(-1, cpu_idx, on); |
|||
uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD); |
|||
uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); |
|||
|
|||
if (!(cmd & tgt)) |
|||
return; |
|||
|
|||
/* wait until ack */ |
|||
while (!(ack & tgt_cpu)) |
|||
ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); |
|||
|
|||
cmd &= ~tgt; |
|||
mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd); |
|||
} |
|||
|
|||
void mcdi_hotplug_set(int cluster, int cpu_idx, bool on) |
|||
{ |
|||
uint32_t tgt = target_mask(cluster, cpu_idx, on); |
|||
uint32_t tgt_cpu = target_mask(-1, cpu_idx, on); |
|||
uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD); |
|||
uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); |
|||
|
|||
if ((cmd & tgt) == tgt) |
|||
return; |
|||
|
|||
/* wait until ack clear */ |
|||
while (ack & tgt_cpu) |
|||
ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); |
|||
|
|||
cmd |= tgt; |
|||
mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd); |
|||
} |
|||
|
|||
bool check_mcdi_ctl_stat(void) |
|||
{ |
|||
uint32_t clk_regs[] = {0x100010ac, 0x100010c8}; |
|||
uint32_t clk_mask[] = {0x00028000, 0x00000018}; |
|||
uint32_t tgt = target_mask(0, 0, true); |
|||
uint32_t m; |
|||
int i; |
|||
|
|||
/* check clk status */ |
|||
for (i = 0; i < ARRAY_SIZE(clk_regs); i++) { |
|||
if (mmio_read_32(clk_regs[i]) & clk_mask[i]) { |
|||
WARN("mcdi: clk check fail.\n"); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/* check mcdi cmd handling */ |
|||
m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT); |
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
|
|||
i = 500; |
|||
while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK) && --i > 0) |
|||
udelay(10); |
|||
|
|||
m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT); |
|||
mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); |
|||
|
|||
if (i == 0) { |
|||
WARN("mcdi: pause_action fail.\n"); |
|||
return false; |
|||
} |
|||
|
|||
/* check mcdi cmd handling */ |
|||
if (mcdi_mbox_read(MCDI_MBOX_HP_CMD) || |
|||
mcdi_mbox_read(MCDI_MBOX_HP_ACK)) { |
|||
WARN("mcdi: hp_cmd fail.\n"); |
|||
return false; |
|||
} |
|||
|
|||
mcdi_mbox_write(MCDI_MBOX_HP_CMD, tgt); |
|||
|
|||
i = 500; |
|||
while ((mcdi_mbox_read(MCDI_MBOX_HP_ACK) & tgt) != tgt && --i > 0) |
|||
udelay(10); |
|||
|
|||
mcdi_mbox_write(MCDI_MBOX_HP_CMD, 0); |
|||
|
|||
if (i == 0) { |
|||
WARN("mcdi: hp_ack fail.\n"); |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void mcdi_init(void) |
|||
{ |
|||
mcdi_avail_cpu_mask_write(0x01); /* cpu0 default on */ |
|||
} |
@ -0,0 +1,34 @@ |
|||
/*
|
|||
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. |
|||
* |
|||
* SPDX-License-Identifier: BSD-3-Clause |
|||
*/ |
|||
|
|||
#ifndef __MTK_MCDI_H__ |
|||
#define __MTK_MCDI_H__ |
|||
|
|||
#include <stdbool.h> |
|||
|
|||
void sspm_set_bootaddr(uint32_t bootaddr); |
|||
void sspm_standbywfi_irq_enable(uint32_t cpu_idx); |
|||
void sspm_cluster_pwr_off_notify(uint32_t cluster); |
|||
void sspm_cluster_pwr_on_notify(uint32_t cluster); |
|||
|
|||
uint32_t mcdi_avail_cpu_mask_read(void); |
|||
uint32_t mcdi_avail_cpu_mask_write(uint32_t mask); |
|||
uint32_t mcdi_avail_cpu_mask_set(uint32_t mask); |
|||
uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask); |
|||
uint32_t mcdi_cpu_cluster_pwr_stat_read(void); |
|||
|
|||
void mcdi_pause(void); |
|||
void mcdi_unpause(void); |
|||
void mcdi_pause_set(int cluster, int cpu_idx, bool on); |
|||
void mcdi_pause_clr(int cluster, int cpu_idx, bool on); |
|||
void mcdi_hotplug_set(int cluster, int cpu_idx, bool on); |
|||
void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on); |
|||
void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on); |
|||
|
|||
bool check_mcdi_ctl_stat(void); |
|||
void mcdi_init(void); |
|||
|
|||
#endif /* __MTK_MCDI_H__ */ |
@ -0,0 +1,41 @@ |
|||
/*
|
|||
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. |
|||
* |
|||
* SPDX-License-Identifier: BSD-3-Clause |
|||
*/ |
|||
|
|||
#ifndef __SSPM_REG_H__ |
|||
#define __SSPM_REG_H__ |
|||
|
|||
#include "platform_def.h" |
|||
|
|||
#define SSPM_CFGREG_RSV_RW_REG0 (SSPM_CFGREG_BASE + 0x0100) |
|||
#define SSPM_CFGREG_ACAO_INT_SET (SSPM_CFGREG_BASE + 0x00D8) |
|||
#define SSPM_CFGREG_ACAO_INT_CLR (SSPM_CFGREG_BASE + 0x00DC) |
|||
#define SSPM_CFGREG_ACAO_WAKEUP_EN (SSPM_CFGREG_BASE + 0x0204) |
|||
|
|||
#define STANDBYWFI_EN(n) (1 << (n + 8)) |
|||
#define GIC_IRQOUT_EN(n) (1 << (n + 0)) |
|||
|
|||
#define NF_MCDI_MBOX 19 |
|||
#define MCDI_MBOX_CLUSTER_0_CAN_POWER_OFF 0 |
|||
#define MCDI_MBOX_CLUSTER_1_CAN_POWER_OFF 1 |
|||
#define MCDI_MBOX_BUCK_POWER_OFF_MASK 2 |
|||
#define MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE 3 |
|||
#define MCDI_MBOX_CLUSTER_1_ATF_ACTION_DONE 4 |
|||
#define MCDI_MBOX_BOOTADDR 5 |
|||
#define MCDI_MBOX_PAUSE_ACTION 6 |
|||
#define MCDI_MBOX_AVAIL_CPU_MASK 7 |
|||
#define MCDI_MBOX_CPU_CLUSTER_PWR_STAT 8 |
|||
#define MCDI_MBOX_ACTION_STAT 9 |
|||
#define MCDI_MBOX_CLUSTER_0_CNT 10 |
|||
#define MCDI_MBOX_CLUSTER_1_CNT 11 |
|||
#define MCDI_MBOX_CPU_ISOLATION_MASK 12 |
|||
#define MCDI_MBOX_PAUSE_ACK 13 |
|||
#define MCDI_MBOX_PENDING_ON_EVENT 14 |
|||
#define MCDI_MBOX_PROF_CMD 15 |
|||
#define MCDI_MBOX_DRCC_CALI_DONE 16 |
|||
#define MCDI_MBOX_HP_CMD 17 |
|||
#define MCDI_MBOX_HP_ACK 18 |
|||
|
|||
#endif /* __SSPM_REG_H__ */ |
Loading…
Reference in new issue