Browse Source

hikey960: support BL31

Support BL31 on HiKey960 platform. Implement PSCI.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
pull/959/head
Haojian Zhuang 8 years ago
parent
commit
28b02e2348
  1. 53
      plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
  2. 204
      plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
  3. 395
      plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
  4. 57
      plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
  5. 166
      plat/hisilicon/hikey960/hi3660_mailbox.c
  6. 129
      plat/hisilicon/hikey960/hikey960_bl31_setup.c
  7. 305
      plat/hisilicon/hikey960/hikey960_pm.c
  8. 4
      plat/hisilicon/hikey960/hikey960_private.h
  9. 64
      plat/hisilicon/hikey960/hikey960_topology.c
  10. 24
      plat/hisilicon/hikey960/include/hisi_ipc.h
  11. 13
      plat/hisilicon/hikey960/platform.mk

53
plat/hisilicon/hikey960/aarch64/hikey960_helpers.S

@ -6,6 +6,8 @@
#include <arch.h>
#include <asm_macros.S>
#include <cortex_a53.h>
#include <cortex_a73.h>
#include "../hikey960_def.h"
.globl plat_my_core_pos
@ -14,6 +16,10 @@
.globl plat_crash_console_putc
.globl plat_report_exception
.globl plat_reset_handler
.globl set_retention_ticks
.globl clr_retention_ticks
.globl clr_ex
.globl nop
func plat_my_core_pos
mrs x0, mpidr_el1
@ -132,6 +138,53 @@ func plat_reset_handler
ret
endfunc plat_reset_handler
/* -----------------------------------------------------
* void set_retention_ticks(unsigned int val);
* Clobber list : x0
* -----------------------------------------------------
*/
func set_retention_ticks
mrs x0, CPUECTLR_EL1
bic x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
orr x0, x0, #RETENTION_ENTRY_TICKS_8
msr CPUECTLR_EL1, x0
isb
dsb sy
ret
endfunc set_retention_ticks
/* -----------------------------------------------------
* void clr_retention_ticks(unsigned int val);
* Clobber list : x0
* -----------------------------------------------------
*/
func clr_retention_ticks
mrs x0, CPUECTLR_EL1
bic x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
msr CPUECTLR_EL1, x0
isb
dsb sy
ret
endfunc clr_retention_ticks
/* -----------------------------------------------------
* void clrex(void);
* -----------------------------------------------------
*/
func clr_ex
clrex
ret
endfunc clr_ex
/* -----------------------------------------------------
* void nop(void);
* -----------------------------------------------------
*/
func nop
nop
ret
endfunc nop
.section .rodata.rev_err_str, "aS"
plat_err_str:
.asciz "\nPlatform exception reporting:"

204
plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c

@ -0,0 +1,204 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <hi3660.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <hisi_ipc.h>
#include <debug.h>
#include "../../hikey960_private.h"
#define IPC_MBX_SOURCE_REG(m) (IPC_BASE + ((m) << 6))
#define IPC_MBX_DSET_REG(m) (IPC_BASE + ((m) << 6) + 0x04)
#define IPC_MBX_DCLEAR_REG(m) (IPC_BASE + ((m) << 6) + 0x08)
#define IPC_MBX_DSTATUS_REG(m) (IPC_BASE + ((m) << 6) + 0x0C)
#define IPC_MBX_MODE_REG(m) (IPC_BASE + ((m) << 6) + 0x10)
#define IPC_MBX_IMASK_REG(m) (IPC_BASE + ((m) << 6) + 0x14)
#define IPC_MBX_ICLR_REG(m) (IPC_BASE + ((m) << 6) + 0x18)
#define IPC_MBX_SEND_REG(m) (IPC_BASE + ((m) << 6) + 0x1C)
#define IPC_MBX_DATA_REG(m, d) (IPC_BASE + ((m) << 6) + 0x20 + \
((d) * 4))
#define IPC_CPU_IMST_REG(m) (IPC_BASE + ((m) << 3))
#define IPC_LOCK_REG (IPC_BASE + 0xA00)
#define IPC_ACK_BIT_SHIFT (1 << 7)
#define IPC_UNLOCK_VALUE (0x1ACCE551)
/*********************************************************
*bit[31:24]:0~AP
*bit[23:16]:0x1~A15, 0x2~A7
*bit[15:8]:0~ON, 1~OFF
*bit[7:0]:0x3 cpu power mode
*********************************************************/
#define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
/*********************************************************
*bit[15:8]:0~no idle, 1~idle
*bit[7:0]:cpux
*********************************************************/
#define IPC_CMD_PARA(is_idle, cpu) \
((is_idle << 8) | (cpu))
#define IPC_STATE_IDLE 0x10
enum src_id {
SRC_IDLE = 0,
SRC_A15 = 1 << 0,
SRC_A7 = 1 << 1,
SRC_IOM3 = 1 << 2,
SRC_LPM3 = 1 << 3
};
/*lpm3's mailboxs are 13~17*/
enum lpm3_mbox_id {
LPM3_MBX0 = 13,
LPM3_MBX1,
LPM3_MBX2,
LPM3_MBX3,
LPM3_MBX4,
};
static void cpu_relax(void)
{
volatile int i;
for (i = 0; i < 10; i++)
nop();
}
static inline void
hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
{
unsigned int int_status = 0;
do {
int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
int_status &= 0xF0;
cpu_relax();
} while (int_status != IPC_ACK_BIT_SHIFT);
mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
}
static void
hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
unsigned int cmdtype, unsigned int cmdpara)
{
unsigned int regval;
unsigned int mask;
unsigned int state;
mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
/* wait for idle and occupy */
do {
state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
if (state == IPC_STATE_IDLE) {
mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
if (regval == source)
break;
}
cpu_relax();
} while (1);
/* auto answer */
mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
mask = (~((int)source | SRC_LPM3) & 0x3F);
/* mask the other cpus */
mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
/* set data */
mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
/* send cmd */
mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
/* wait ack and clear */
hisi_ipc_clear_ack(source, mbox);
/* release mailbox */
mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
}
void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
enum pm_mode mode)
{
unsigned int cmdtype = 0;
unsigned int cmdpara = 0;
enum src_id source = SRC_IDLE;
enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
cmdpara = IPC_CMD_PARA(0, core);
source = cluster ? SRC_A7 : SRC_A15;
hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
}
void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
unsigned int affinity_level)
{
unsigned int cmdtype = 0;
unsigned int cmdpara = 0;
enum src_id source = SRC_IDLE;
enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
if (affinity_level == 0x3)
cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
else
cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
cmdpara = IPC_CMD_PARA(1, core);
source = cluster ? SRC_A7 : SRC_A15;
hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
}
void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
{
unsigned int cmdtype = 0;
unsigned int cmdpara = 0;
enum src_id source = SRC_IDLE;
enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
cmdpara = IPC_CMD_PARA(0, 0);
source = cluster ? SRC_A7 : SRC_A15;
hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
}
void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
unsigned int cmd_id)
{
unsigned int cmdtype = 0;
unsigned int cmdpara = 0;
enum src_id source = SRC_IDLE;
enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
cmdpara = cmd_id;
source = cluster ? SRC_A7 : SRC_A15;
hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
}
int hisi_ipc_init(void)
{
int ret = 0;
enum lpm3_mbox_id i = LPM3_MBX0;
mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
mmio_write_32(IPC_MBX_MODE_REG(i), 1);
mmio_write_32(IPC_MBX_IMASK_REG(i),
((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
}
return ret;
}

395
plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c

@ -0,0 +1,395 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <../hikey960_def.h>
#include <hisi_ipc.h>
#include "hisi_pwrc.h"
/* resource lock api */
#define RES0_LOCK_BASE (SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE))
#define RES1_LOCK_BASE (SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE))
#define RES2_LOCK_BASE (SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE))
#define LOCK_BIT (0x1 << 28)
#define LOCK_ID_MASK (0x7 << 29)
#define CPUIDLE_LOCK_ID(core) (0x6 - (core))
#define LOCK_UNLOCK_OFFSET 0x4
#define LOCK_STAT_OFFSET 0x8
#define CLUSTER0_CPUS_ONLINE_MASK (0xF << 16)
#define CLUSTER1_CPUS_ONLINE_MASK (0xF << 20)
/* cpu hotplug flag api */
#define SCTRL_BASE (SOC_ACPU_SCTRL_BASE_ADDR)
#define REG_SCBAKDATA3_OFFSET (SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE))
#define REG_SCBAKDATA8_OFFSET (SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE))
#define REG_SCBAKDATA9_OFFSET (SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE))
#define CPUIDLE_FLAG_REG(cluster) \
((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \
REG_SCBAKDATA9_OFFSET)
#define CLUSTER_IDLE_BIT BIT(8)
#define CLUSTER_IDLE_MASK (CLUSTER_IDLE_BIT | 0x0F)
#define AP_SUSPEND_FLAG (1 << 16)
#define CLUSTER_PWDN_IDLE (0<<28)
#define CLUSTER_PWDN_HOTPLUG (1<<28)
#define CLUSTER_PWDN_SR (2<<28)
#define CLUSTER0_PDC_OFFSET 0x260
#define CLUSTER1_PDC_OFFSET 0x300
#define PDC_EN_OFFSET 0x0
#define PDC_COREPWRINTEN_OFFSET 0x4
#define PDC_COREPWRINTSTAT_OFFSET 0x8
#define PDC_COREGICMASK_OFFSET 0xc
#define PDC_COREPOWERUP_OFFSET 0x10
#define PDC_COREPOWERDN_OFFSET 0x14
#define PDC_COREPOWERSTAT_OFFSET 0x18
#define PDC_COREPWRSTAT_MASK (0XFFFF)
enum pdc_gic_mask {
PDC_MASK_GIC_WAKE_IRQ,
PDC_UNMASK_GIC_WAKE_IRQ
};
enum pdc_finish_int_mask {
PDC_DISABLE_FINISH_INT,
PDC_ENABLE_FINISH_INT
};
static void hisi_resource_lock(unsigned int lockid, unsigned int offset)
{
unsigned int lock_id = (lockid << 29);
unsigned int lock_val = lock_id | LOCK_BIT;
unsigned int lock_state;
do {
mmio_write_32(offset, lock_val);
lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset);
} while ((lock_state & LOCK_ID_MASK) != lock_id);
}
static void hisi_resource_unlock(unsigned int lockid, unsigned int offset)
{
unsigned int lock_val = (lockid << 29) | LOCK_BIT;
mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val);
}
static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core)
{
unsigned int lock_id;
lock_id = (cluster << 2) + core;
hisi_resource_lock(lock_id, RES2_LOCK_BASE);
}
static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core)
{
unsigned int lock_id;
lock_id = (cluster << 2) + core;
hisi_resource_unlock(lock_id, RES2_LOCK_BASE);
}
/* get the resource lock */
void hisi_cpuidle_lock(unsigned int cluster, unsigned int core)
{
unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset);
}
/* release the resource lock */
void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core)
{
unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset);
}
unsigned int hisi_get_cpuidle_flag(unsigned int cluster)
{
unsigned int val;
val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
val &= 0xF;
return val;
}
void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
{
mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
}
void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
{
mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
}
int hisi_test_ap_suspend_flag(unsigned int cluster)
{
unsigned int val;
val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
val &= AP_SUSPEND_FLAG;
return !!val;
}
void hisi_set_cluster_pwdn_flag(unsigned int cluster,
unsigned int core, unsigned int value)
{
unsigned int val;
hisi_cpuhotplug_lock(cluster, core);
val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
val = (value << (cluster << 1)) | (val & 0xFFFFFFF);
mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
hisi_cpuhotplug_unlock(cluster, core);
}
unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
{
unsigned int val;
hisi_cpuhotplug_lock(cluster, core);
val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
val = val >> (16 + (cluster << 2));
val &= 0xF;
hisi_cpuhotplug_unlock(cluster, core);
return val;
}
unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
{
unsigned int val;
hisi_cpuhotplug_lock(cluster, core);
val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
val = val >> (16 + (cluster << 2));
val &= 0xF;
hisi_cpuhotplug_unlock(cluster, core);
if (val)
return 0;
else
return 1;
}
void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
{
unsigned int flag = BIT((cluster<<2) + core + 16);
hisi_cpuhotplug_lock(cluster, core);
mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
hisi_cpuhotplug_unlock(cluster, core);
}
void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
{
unsigned int flag = BIT((cluster<<2) + core + 16);
hisi_cpuhotplug_lock(cluster, core);
mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
hisi_cpuhotplug_unlock(cluster, core);
}
int cluster_is_powered_on(unsigned int cluster)
{
unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
int ret;
if (cluster == 0)
ret = val & CLUSTER0_CPUS_ONLINE_MASK;
else
ret = val & CLUSTER1_CPUS_ONLINE_MASK;
return !!ret;
}
static void *hisi_get_pdc_addr(unsigned int cluster)
{
void *pdc_base_addr;
uintptr_t addr;
if (cluster == 0)
addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
else
addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
pdc_base_addr = (void *)addr;
return pdc_base_addr;
}
static unsigned int hisi_get_pdc_stat(unsigned int cluster)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
unsigned int val;
val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
return val;
}
int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
{
unsigned int mask = 0xf << (core * 4);
unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
mask = (PDC_COREPWRSTAT_MASK & (~mask));
pdc_stat &= mask;
if ((boot_flag ^ cpuidle_flag) || pdc_stat)
return 0;
else
return 1;
}
void hisi_disable_pdc(unsigned int cluster)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
}
void hisi_enable_pdc(unsigned int cluster)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
}
static inline void hisi_pdc_set_intmask(void *pdc_base_addr,
unsigned int core,
enum pdc_finish_int_mask intmask)
{
unsigned int val;
val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
if (intmask == PDC_ENABLE_FINISH_INT)
val |= BIT(core);
else
val &= ~BIT(core);
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
}
static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
unsigned int core,
enum pdc_gic_mask gicmask)
{
unsigned int val;
val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
val |= BIT(core);
else
val &= ~BIT(core);
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
}
void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
{
int i;
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
for (i = 0; i < 4; i++)
hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
}
static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
enum pdc_gic_mask gicmask,
enum pdc_finish_int_mask intmask)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
BIT(core));
}
static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
enum pdc_gic_mask gicmask,
enum pdc_finish_int_mask intmask)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
BIT(core));
}
void hisi_powerup_core(unsigned int cluster, unsigned int core)
{
hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
PDC_DISABLE_FINISH_INT);
}
void hisi_powerdn_core(unsigned int cluster, unsigned int core)
{
hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
PDC_DISABLE_FINISH_INT);
}
void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
{
hisi_ipc_pm_on_off(core, cluster, PM_ON);
}
void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
(0x10001 << core));
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
BIT(core));
}
void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
{
hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
PDC_DISABLE_FINISH_INT);
}
void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
{
void *pdc_base_addr = hisi_get_pdc_addr(cluster);
hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
(0x10001 << core));
mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
BIT(core));
}
void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
{
hisi_ipc_pm_suspend(core, cluster, 0x3);
}

57
plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h

@ -0,0 +1,57 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __HISI_PWRC_H__
#define __HISI_PWRC_H__
#include <hi3660.h>
#include <hi3660_crg.h>
#define PCTRL_BASE (PCTRL_REG_BASE)
#define CRG_BASE (CRG_REG_BASE)
#define SOC_CRGPERIPH_A53_PDCEN_ADDR(base) ((base) + (0x260))
#define SOC_CRGPERIPH_MAIA_PDCEN_ADDR(base) ((base) + (0x300))
#define SOC_PCTRL_RESOURCE0_LOCK_ADDR(base) ((base) + (0x400))
#define SOC_PCTRL_RESOURCE0_UNLOCK_ADDR(base) ((base) + (0x404))
#define SOC_PCTRL_RESOURCE0_LOCK_ST_ADDR(base) ((base) + (0x408))
#define SOC_PCTRL_RESOURCE1_LOCK_ADDR(base) ((base) + (0x40C))
#define SOC_PCTRL_RESOURCE1_UNLOCK_ADDR(base) ((base) + (0x410))
#define SOC_PCTRL_RESOURCE1_LOCK_ST_ADDR(base) ((base) + (0x414))
#define SOC_PCTRL_RESOURCE2_LOCK_ADDR(base) ((base) + (0x418))
#define SOC_SCTRL_SCBAKDATA3_ADDR(base) ((base) + (0x418))
#define SOC_SCTRL_SCBAKDATA8_ADDR(base) ((base) + (0x42C))
#define SOC_SCTRL_SCBAKDATA9_ADDR(base) ((base) + (0x430))
#define SOC_ACPU_SCTRL_BASE_ADDR (0xFFF0A000)
void hisi_cpuidle_lock(unsigned int cluster, unsigned int core);
void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core);
void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core);
void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core);
void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core);
void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core);
int cluster_is_powered_on(unsigned int cluster);
void hisi_enter_core_idle(unsigned int cluster, unsigned int core);
void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core);
int hisi_test_ap_suspend_flag(unsigned int cluster);
void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core);
/* pdc api */
void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster);
int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core);
void hisi_disable_pdc(unsigned int cluster);
void hisi_enable_pdc(unsigned int cluster);
void hisi_powerup_core(unsigned int cluster, unsigned int core);
void hisi_powerdn_core(unsigned int cluster, unsigned int core);
void hisi_powerup_cluster(unsigned int cluster, unsigned int core);
void hisi_powerdn_cluster(unsigned int cluster, unsigned int core);
unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core);
#endif /* __HISI_PWRC_H__ */

166
plat/hisilicon/hikey960/hi3660_mailbox.c

@ -0,0 +1,166 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <hi3660_mailbox.h>
#include <mailbox.h>
#include <mmio.h>
#include <string.h>
typedef struct hi3660_chan {
unsigned char src;
unsigned char dst;
unsigned char used;
} hi3660_chan_t;
static hi3660_chan_t chan_map[MBX_MAX_CHANNELS];
static void hi3660_mbox_check_state(int chan, unsigned int state)
{
unsigned int data;
data = mmio_read_32(MBX_MODE(chan));
assert((data & (MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK)) == 0);
data &= MBX_MODE_STATE_STATUS_MASK;
assert(data == state);
(void)state;
}
static int hi3660_mbox_send(int chan, void *message, int len)
{
int i;
unsigned int *buf;
unsigned int data;
assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
(message != NULL) && (len <= MBX_MAX_DATA_LEN));
assert((chan_map[chan].used != 0) &&
(chan_map[chan].src != 0) &&
(chan_map[chan].dst != 0));
buf = (unsigned int *)message;
len = ((len + 3) >> 2); /* convert to word count */
for (i = 0; i < len; i++)
mmio_write_32(MBX_DATA0(chan) + (i << 2), *(buf + i));
/* send out */
mmio_write_32(MBX_SEND(chan), chan_map[chan].src);
do {
data = mmio_read_32(MBX_ICLR(chan));
} while ((data & chan_map[chan].src) == 0);
/* ack */
mmio_write_32(MBX_ICLR(chan), chan_map[chan].src);
return 0;
}
static int hi3660_mbox_recv(int chan, void *message, int *len)
{
unsigned int *buf, data;
int i;
assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
(message != NULL) && (len != NULL));
assert((chan_map[chan].used != 0) &&
(chan_map[chan].src != 0) &&
(chan_map[chan].dst != 0));
/* wait IPC event */
do {
data = mmio_read_32(MBX_MODE(chan));
} while ((data & MBX_MODE_STATE_STATUS_MASK) != MBX_MODE_STATE_DEST);
/* wait to clear interrupt */
do {
data = mmio_read_32(MBX_ICLR(chan));
} while (data == 0);
do {
mmio_write_32(MBX_ICLR(chan), chan_map[chan].dst);
data = mmio_read_32(MBX_ICLR(chan));
} while (data);
/* read data from IPC */
buf = (unsigned int *)message;
for (i = 0; i < MBX_MAX_DATA_LEN; i += 4)
*(buf + (i >> 2)) = mmio_read_32(MBX_DATA0(chan) + i);
*len = MBX_MAX_DATA_LEN;
/* ack */
mmio_write_32(MBX_SEND(chan), chan_map[chan].dst);
return 0;
}
static int hi3660_mbox_request(int chan, int direction)
{
unsigned int data;
unsigned int src, dst;
assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
if (direction == MAILBOX_DIR_TX) {
src = CPU_A53;
dst = CPU_LPM3;
} else if (direction == MAILBOX_DIR_RX) {
src = CPU_LPM3;
dst = CPU_A53;
} else
assert(0);
mmio_write_32(MBX_SOURCE(chan), src);
data = mmio_read_32(MBX_SOURCE(chan));
assert(data == src);
/* mask all interrupts */
mmio_write_32(MBX_IMASK(chan), CPU_MASK);
/* unmask interrupt */
mmio_write_32(MBX_IMASK(chan), ~(src | dst));
/* set destination */
mmio_write_32(MBX_DCLEAR(chan), (~dst) & CPU_MASK);
mmio_write_32(MBX_DSET(chan), dst);
data = mmio_read_32(MBX_DSTATUS(chan));
assert((data & dst) != 0);
/* clear auto link & auto answer */
data = mmio_read_32(MBX_MODE(chan));
data &= ~(MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK);
mmio_write_32(MBX_MODE(chan), data);
hi3660_mbox_check_state(chan, MBX_MODE_STATE_SOURCE);
chan_map[chan].used = 1;
chan_map[chan].src = src;
chan_map[chan].dst = dst;
return 0;
}
static void hi3660_mbox_free(int chan)
{
assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
}
static mbox_ops_t hi3660_mbox_ops = {
.send = hi3660_mbox_send,
.recv = hi3660_mbox_recv,
.request = hi3660_mbox_request,
.free = hi3660_mbox_free,
};
int hi3660_mbox_init(mbox_params_t *params)
{
int result;
unsigned int data;
assert(params != NULL);
result = mbox_init(&hi3660_mbox_ops, params);
assert(result == 0);
memset(&chan_map, 0, sizeof(chan_map));
/* unlock mailbox */
data = mmio_read_32(IPC_LOCK);
while (data == MBX_IPC_LOCKED) {
mmio_write_32(IPC_LOCK, MBX_IPC_UNLOCK_MAGIC);
data = mmio_read_32(IPC_LOCK);
}
(void)result;
return 0;
}

129
plat/hisilicon/hikey960/hikey960_bl31_setup.c

@ -0,0 +1,129 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <arm_gic.h>
#include <assert.h>
#include <bl_common.h>
#include <cci.h>
#include <console.h>
#include <debug.h>
#include <errno.h>
#include <generic_delay_timer.h>
#include <gicv2.h>
#include <hi3660.h>
#include <hisi_ipc.h>
#include <platform_def.h>
#include "hikey960_def.h"
#include "hikey960_private.h"
/*
* The next 2 constants identify the extents of the code & RO data region.
* These addresses are used by the MMU setup code and therefore they must be
* page-aligned. It is the responsibility of the linker script to ensure that
* __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
*/
#define BL31_RO_BASE (unsigned long)(&__RO_START__)
#define BL31_RO_LIMIT (unsigned long)(&__RO_END__)
/*
* The next 2 constants identify the extents of the coherent memory region.
* These addresses are used by the MMU setup code and therefore they must be
* page-aligned. It is the responsibility of the linker script to ensure that
* __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
* page-aligned addresses.
*/
#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
static entry_point_info_t bl32_ep_info;
static entry_point_info_t bl33_ep_info;
/******************************************************************************
* On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
* interrupts.
*****************************************************************************/
const unsigned int g0_interrupt_array[] = {
IRQ_SEC_PHY_TIMER,
IRQ_SEC_SGI_0
};
const gicv2_driver_data_t hikey960_gic_data = {
.gicd_base = GICD_REG_BASE,
.gicc_base = GICC_REG_BASE,
.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
.g0_interrupt_array = g0_interrupt_array,
};
static const int cci_map[] = {
CCI400_SL_IFACE3_CLUSTER_IX,
CCI400_SL_IFACE4_CLUSTER_IX
};
entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
{
entry_point_info_t *next_image_info;
next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
/* None of the images on this platform can have 0x0 as the entrypoint */
if (next_image_info->pc)
return next_image_info;
return NULL;
}
void bl31_early_platform_setup(bl31_params_t *from_bl2,
void *plat_params_from_bl2)
{
unsigned int id, uart_base;
generic_delay_timer_init();
hikey960_read_boardid(&id);
if (id == 5300)
uart_base = PL011_UART5_BASE;
else
uart_base = PL011_UART6_BASE;
/* Initialize the console to provide early debug support */
console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
/* Initialize CCI driver */
cci_init(CCI400_REG_BASE, cci_map, ARRAY_SIZE(cci_map));
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
/*
* Copy BL3-2 and BL3-3 entry point information.
* They are stored in Secure RAM, in BL2's address space.
*/
bl32_ep_info = *from_bl2->bl32_ep_info;
bl33_ep_info = *from_bl2->bl33_ep_info;
}
void bl31_plat_arch_setup(void)
{
hikey960_init_mmu_el3(BL31_BASE,
BL31_LIMIT - BL31_BASE,
BL31_RO_BASE,
BL31_RO_LIMIT,
BL31_COHERENT_RAM_BASE,
BL31_COHERENT_RAM_LIMIT);
}
void bl31_platform_setup(void)
{
/* Initialize the GIC driver, cpu and distributor interfaces */
gicv2_driver_init(&hikey960_gic_data);
gicv2_distif_init();
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
hisi_ipc_init();
}
void bl31_plat_runtime_setup(void)
{
}

305
plat/hisilicon/hikey960/hikey960_pm.c

@ -0,0 +1,305 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <cci.h>
#include <console.h>
#include <debug.h>
#include <gicv2.h>
#include <hi3660.h>
#include <hi3660_crg.h>
#include <mmio.h>
#include <psci.h>
#include "drivers/pwrc/hisi_pwrc.h"
#include "hikey960_def.h"
#include "hikey960_private.h"
#define CORE_PWR_STATE(state) \
((state)->pwr_domain_state[MPIDR_AFFLVL0])
#define CLUSTER_PWR_STATE(state) \
((state)->pwr_domain_state[MPIDR_AFFLVL1])
#define SYSTEM_PWR_STATE(state) \
((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
#define DMAC_GLB_REG_SEC 0x694
#define AXI_CONF_BASE 0x820
static uintptr_t hikey960_sec_entrypoint;
static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
{
unsigned long scr;
unsigned int val = 0;
assert(cpu_state == PLAT_MAX_RET_STATE);
scr = read_scr_el3();
/* Enable Physical IRQ and FIQ to wake the CPU*/
write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
set_retention_ticks(val);
wfi();
clr_retention_ticks(val);
/*
* Restore SCR to the original value, synchronisazion of
* scr_el3 is done by eret while el3_exit to save some
* execution cycles.
*/
write_scr_el3(scr);
}
static int hikey960_pwr_domain_on(u_register_t mpidr)
{
unsigned int core = mpidr & MPIDR_CPU_MASK;
unsigned int cluster =
(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
int cluster_stat = cluster_is_powered_on(cluster);
hisi_set_cpu_boot_flag(cluster, core);
mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
hikey960_sec_entrypoint >> 2);
if (cluster_stat)
hisi_powerup_core(cluster, core);
else
hisi_powerup_cluster(cluster, core);
return PSCI_E_SUCCESS;
}
static void
hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
}
void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
{
unsigned long mpidr = read_mpidr_el1();
unsigned int core = mpidr & MPIDR_CPU_MASK;
unsigned int cluster =
(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
clr_ex();
isb();
dsbsy();
gicv2_cpuif_disable();
hisi_clear_cpu_boot_flag(cluster, core);
hisi_powerdn_core(cluster, core);
/* check if any core is powered up */
if (hisi_test_pwrdn_allcores(cluster, core)) {
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
isb();
dsbsy();
hisi_powerdn_cluster(cluster, core);
}
}
static void __dead2 hikey960_system_reset(void)
{
mmio_write_32(SCTRL_SCPEREN1_REG,
SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
panic();
}
int hikey960_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int pstate = psci_get_pstate_type(power_state);
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
int i;
assert(req_state);
if (pwr_lvl > PLAT_MAX_PWR_LVL)
return PSCI_E_INVALID_PARAMS;
/* Sanity check the requested state */
if (pstate == PSTATE_TYPE_STANDBY) {
/*
* It's possible to enter standby only on power level 0
* Ignore any other power level.
*/
if (pwr_lvl != MPIDR_AFFLVL0)
return PSCI_E_INVALID_PARAMS;
req_state->pwr_domain_state[MPIDR_AFFLVL0] =
PLAT_MAX_RET_STATE;
} else {
for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
req_state->pwr_domain_state[i] =
PLAT_MAX_OFF_STATE;
}
/*
* We expect the 'state id' to be zero.
*/
if (psci_get_pstate_id(power_state))
return PSCI_E_INVALID_PARAMS;
return PSCI_E_SUCCESS;
}
static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
{
/*
* Check if the non secure entrypoint lies within the non
* secure DRAM.
*/
if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
return PSCI_E_SUCCESS;
return PSCI_E_INVALID_ADDRESS;
}
static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
{
u_register_t mpidr = read_mpidr_el1();
unsigned int core = mpidr & MPIDR_CPU_MASK;
unsigned int cluster =
(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
return;
if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
clr_ex();
isb();
dsbsy();
gicv2_cpuif_disable();
hisi_cpuidle_lock(cluster, core);
hisi_set_cpuidle_flag(cluster, core);
hisi_cpuidle_unlock(cluster, core);
mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
hikey960_sec_entrypoint >> 2);
hisi_enter_core_idle(cluster, core);
}
/* Perform the common cluster specific operations */
if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
hisi_cpuidle_lock(cluster, core);
hisi_disable_pdc(cluster);
/* check if any core is powered up */
if (hisi_test_pwrdn_allcores(cluster, core)) {
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
isb();
dsbsy();
/* mask the pdc wakeup irq, then
* enable pdc to power down the core
*/
hisi_pdc_mask_cluster_wakeirq(cluster);
hisi_enable_pdc(cluster);
hisi_cpuidle_unlock(cluster, core);
/* check the SR flag bit to determine
* CLUSTER_IDLE_IPC or AP_SR_IPC to send
*/
if (hisi_test_ap_suspend_flag(cluster))
hisi_enter_ap_suspend(cluster, core);
else
hisi_enter_cluster_idle(cluster, core);
} else {
/* enable pdc */
hisi_enable_pdc(cluster);
hisi_cpuidle_unlock(cluster, core);
}
}
}
static void hikey960_sr_dma_reinit(void)
{
unsigned int ctr = 0;
mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
/* 1~15 channel is set non_secure */
for (ctr = 1; ctr <= 15; ctr++)
mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
(1 << 6) | (1 << 18));
}
static void
hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
{
unsigned long mpidr = read_mpidr_el1();
unsigned int cluster =
(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
/* Nothing to be done on waking up from retention from CPU level */
if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
return;
if (hisi_test_ap_suspend_flag(cluster)) {
hikey960_sr_dma_reinit();
gicv2_cpuif_enable();
console_init(PL011_UART6_BASE, PL011_UART_CLK_IN_HZ,
PL011_BAUDRATE);
}
hikey960_pwr_domain_on_finish(target_state);
}
static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
int i;
for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
}
static const plat_psci_ops_t hikey960_psci_ops = {
.cpu_standby = hikey960_pwr_domain_standby,
.pwr_domain_on = hikey960_pwr_domain_on,
.pwr_domain_on_finish = hikey960_pwr_domain_on_finish,
.pwr_domain_off = hikey960_pwr_domain_off,
.pwr_domain_suspend = hikey960_pwr_domain_suspend,
.pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish,
.system_off = NULL,
.system_reset = hikey960_system_reset,
.validate_power_state = hikey960_validate_power_state,
.validate_ns_entrypoint = hikey960_validate_ns_entrypoint,
.get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state,
};
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
hikey960_sec_entrypoint = sec_entrypoint;
INFO("%s: sec_entrypoint=0x%lx\n", __func__,
(unsigned long)hikey960_sec_entrypoint);
/*
* Initialize PSCI ops struct
*/
*psci_ops = &hikey960_psci_ops;
return 0;
}

4
plat/hisilicon/hikey960/hikey960_private.h

@ -26,5 +26,9 @@ void hikey960_init_mmu_el3(unsigned long total_base,
unsigned long coh_limit);
void hikey960_io_setup(void);
int hikey960_read_boardid(unsigned int *id);
void set_retention_ticks(unsigned int val);
void clr_retention_ticks(unsigned int val);
void clr_ex(void);
void nop(void);
#endif /* __HIKEY960_PRIVATE_H__ */

64
plat/hisilicon/hikey960/hikey960_topology.c

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <platform_def.h>
#include <psci.h>
/*
* The HiKey power domain tree descriptor. The cluster power domains
* are arranged so that when the PSCI generic code creates the power
* domain tree, the indices of the CPU power domain nodes it allocates
* match the linear indices returned by plat_core_pos_by_mpidr().
*/
const unsigned char hikey960_power_domain_tree_desc[] = {
/* Number of root nodes */
1,
/* Number of clusters */
PLATFORM_CLUSTER_COUNT,
/* Number of children for the first cluster node */
PLATFORM_CORE_COUNT_PER_CLUSTER,
/* Number of children for the second cluster node */
PLATFORM_CORE_COUNT_PER_CLUSTER,
};
/*******************************************************************************
* This function returns the HiKey topology tree information.
******************************************************************************/
const unsigned char *plat_get_power_domain_tree_desc(void)
{
return hikey960_power_domain_tree_desc;
}
/*******************************************************************************
* This function implements a part of the critical interface between the psci
* generic layer and the platform that allows the former to query the platform
* to convert an MPIDR to a unique linear index. An error code (-1) is returned
* in case the MPIDR is invalid.
******************************************************************************/
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
unsigned int cluster_id, cpu_id;
mpidr &= MPIDR_AFFINITY_MASK;
if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
return -1;
cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
if (cluster_id >= PLATFORM_CLUSTER_COUNT)
return -1;
/*
* Validate cpu_id by checking whether it represents a CPU in
* one of the two clusters present on the platform.
*/
if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER)
return -1;
return (cpu_id + (cluster_id * 4));
}

24
plat/hisilicon/hikey960/include/hisi_ipc.h

@ -0,0 +1,24 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __HISI_IPC_H__
#define __HISI_IPC_H__
enum pm_mode {
PM_ON = 0,
PM_OFF,
};
void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
enum pm_mode mode);
void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
unsigned int affinity_level);
void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster);
void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
unsigned int cmd_id);
int hisi_ipc_init(void);
#endif /* __HISI_IPC_H__ */

13
plat/hisilicon/hikey960/platform.mk

@ -50,3 +50,16 @@ BL2_SOURCES += drivers/io/io_block.c \
plat/hisilicon/hikey960/hikey960_bl2_setup.c \
plat/hisilicon/hikey960/hikey960_io_storage.c \
plat/hisilicon/hikey960/hikey960_mcu_load.c
BL31_SOURCES += drivers/arm/cci/cci.c \
lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a72.S \
lib/cpus/aarch64/cortex_a73.S \
plat/common/aarch64/plat_psci_common.c \
plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
plat/hisilicon/hikey960/hikey960_bl31_setup.c \
plat/hisilicon/hikey960/hikey960_pm.c \
plat/hisilicon/hikey960/hikey960_topology.c \
plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c \
plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c \
${HIKEY960_GIC_SOURCES}

Loading…
Cancel
Save