Commit 5747ecab authored by danh-arm's avatar danh-arm Committed by GitHub
Browse files

Merge pull request #959 from hzhuang1/hikey960_v1

Hikey960 v1
parents f9a050e4 7fe08b2b
Description
====================
HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960.
More information are listed in [link](http://www.96boards.org/documentation/ConsumerEdition/HiKey960/README.md).
How to build
====================
1. Code Locations
-----------------
* ARM Trusted Firmware:
[link](https://github.com/ARM-software/arm-trusted-firmware)
* edk2:
[link](https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5)
* OpenPlatformPkg:
[link](https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4)
* l-loader:
[link](https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2)
* uefi-tools:
[link](https://github.com/96boards-hikey/uefi-tools/tree/hikey960_v1)
2. Build Procedure
------------------
* Fetch all the above 5 repositories into local host.
Make all the repositories in the same ${BUILD_PATH}.
* Create the symbol link to OpenPlatformPkg in edk2.
<br>`$cd ${BUILD_PATH}/edk2`</br>
<br>`$ln -sf ../OpenPlatformPkg`</br>
* Prepare AARCH64 toolchain.
* If your hikey960 hardware is v1, update _uefi-tools/platform.config_ first. _(optional)_
<br>__Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
console on hikey960 v1.__</br>
<br>`BUILDFLAGS=-DSERIAL_BASE=0xFDF05000`</br>
<br>If your hikey960 hardware is v2 or newer, nothing to do.</br>
* Build it as debug mode. Create script file for build.
<br>`BUILD_OPTION=DEBUG`</br>
<br>`export AARCH64_TOOLCHAIN=GCC48`</br>
<br>`export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools`<br>
<br>`export EDK2_DIR=${BUILD_PATH}/edk2`</br>
<br>`EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey960/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}`</br>
<br>`cd ${EDK2_DIR}`</br>
<br>`# Build UEFI & ARM Trust Firmware`</br>
<br>`${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware hikey960`</br>
<br>`# Generate l-loader.bin`</br>
<br>`cd ${BUILD_PATH}/l-loader`</br>
<br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin`</br>
<br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin`</br>
<br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd`</br>
<br>`python gen_loader.py -o l-loader.bin --img_bl1=bl1.bin --img_ns_bl1u=BL33_AP_UEFI.fd`</br>
* Generate partition table.
<br>_Make sure that you're using the sgdisk in the l-loader directory._</br>
<br>`$PTABLE=aosp-32g SECTOR_SIZE=4096 SGDISK=./sgdisk bash -x generate_ptable.sh`</br>
3. Setup Console
----------------
* Install ser2net. Use telnet as the console since UEFI will output window
that fails to display in minicom.
<br>`$sudo apt-get install ser2net`</br>
* Configure ser2net.
<br>`$sudo vi /etc/ser2net.conf`</br>
<br>Append one line for serial-over-USB in below.</br>
<br>_#ser2net.conf_</br>
<br>`2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner`</br>
* Open the console.
<br>`$telnet localhost 2004`</br>
<br>And you could open the console remotely, too.</br>
4. Boot UEFI in recovery mode
-----------------------------
* Fetch that are used in recovery mode. The code location is in below.
[link](https://github.com/96boards-hikey/tools-images-hikey960)
* Generate l-loader.bin.
<br>`$cd tools-images-hikey960`</br>
<br>`$ln -sf ${BUILD_PATH}/l-loader/l-loader.bin`</br>
* Prepare config file.
<br>_$vi config_</br>
<br>_# The content of config file_</br>
<br>`./sec_user_xloader.img 0x00020000`</br>
<br>`./sec_uce_boot.img 0x6A908000`</br>
<br>`./l-loader.bin 0x1AC00000`</br>
* Remove the modemmanager package. This package may causes hikey_idt tool failure.
<br>`$sudo apt-get purge modemmanager`</br>
* Run the command to download l-loader.bin into HiKey960.
<br>`$sudo ./hikey_idt -c config -p /dev/ttyUSB1`</br>
* UEFI running in recovery mode.
<br>When prompt '.' is displayed on console, press hotkey 'f' in keyboard. Then Android fastboot app is running.</br>
<br>The timeout of prompt '.' is 10 seconds.</br>
* Update images.
<br>`$sudo fastboot flash ptable prm_ptable.img`</br>
<br>`$sudo fastboot flash xloader sec_xloader.img`</br>
<br>`$sudo fastboot flash fastboot l-loader.bin`</br>
<br>`$sudo fastboot flash fip fip.bin`</br>
<br>`$sudo fastboot flash boot boot.img`</br>
<br>`$sudo fastboot flash cache cache.img`</br>
<br>`$sudo fastboot flash system system.img`</br>
<br>`$sudo fastboot flash userdata userdata.img`</br>
* Notice: UEFI could also boot kernel in recovery mode, but BL31 isn't loaded in
recovery mode.
5. Boot UEFI in normal mode
-----------------------------
* Make sure "Boot Mode" switch is OFF for normal boot mode. Then power on HiKey960.
* Reference [link](https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md)
/*-
* Copyright (c) 2001 David E. O'Brien
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)endian.h 8.1 (Berkeley) 6/10/93
* $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $
* $FreeBSD$
*/
/*
* Portions copyright (c) 2017, ARM Limited and Contributors.
* All rights reserved.
*/
#ifndef _MACHINE_ENDIAN_H_
#define _MACHINE_ENDIAN_H_
#include <sys/_types.h>
/*
* Definitions for byte order, according to byte significance from low
* address to high.
*/
#define _LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
#define _BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
#define _PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */
#define _BYTE_ORDER _LITTLE_ENDIAN
#if __BSD_VISIBLE
#define LITTLE_ENDIAN _LITTLE_ENDIAN
#define BIG_ENDIAN _BIG_ENDIAN
#define PDP_ENDIAN _PDP_ENDIAN
#define BYTE_ORDER _BYTE_ORDER
#endif
#define _QUAD_HIGHWORD 1
#define _QUAD_LOWWORD 0
#define __ntohl(x) (__bswap32(x))
#define __ntohs(x) (__bswap16(x))
#define __htonl(x) (__bswap32(x))
#define __htons(x) (__bswap16(x))
#ifdef AARCH32
static __inline __uint64_t
__bswap64(__uint64_t _x)
{
return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) |
((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) |
((_x << 24) & ((__uint64_t)0xff << 40)) |
((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56)));
}
static __inline __uint32_t
__bswap32_var(__uint32_t v)
{
__uint32_t t1;
__asm __volatile("eor %1, %0, %0, ror #16\n"
"bic %1, %1, #0x00ff0000\n"
"mov %0, %0, ror #8\n"
"eor %0, %0, %1, lsr #8\n"
: "+r" (v), "=r" (t1));
return (v);
}
static __inline __uint16_t
__bswap16_var(__uint16_t v)
{
__uint32_t ret = v & 0xffff;
__asm __volatile(
"mov %0, %0, ror #8\n"
"orr %0, %0, %0, lsr #16\n"
"bic %0, %0, %0, lsl #16"
: "+r" (ret));
return ((__uint16_t)ret);
}
#elif defined AARCH64
static __inline __uint64_t
__bswap64(__uint64_t x)
{
__uint64_t ret;
__asm __volatile("rev %0, %1\n"
: "=&r" (ret), "+r" (x));
return (ret);
}
static __inline __uint32_t
__bswap32_var(__uint32_t v)
{
__uint32_t ret;
__asm __volatile("rev32 %x0, %x1\n"
: "=&r" (ret), "+r" (v));
return (ret);
}
static __inline __uint16_t
__bswap16_var(__uint16_t v)
{
__uint32_t ret;
__asm __volatile("rev16 %w0, %w1\n"
: "=&r" (ret), "+r" (v));
return ((__uint16_t)ret);
}
#else
#error "Only AArch32 or AArch64 supported"
#endif /* AARCH32 */
#ifdef __OPTIMIZE__
#define __bswap32_constant(x) \
((((x) & 0xff000000U) >> 24) | \
(((x) & 0x00ff0000U) >> 8) | \
(((x) & 0x0000ff00U) << 8) | \
(((x) & 0x000000ffU) << 24))
#define __bswap16_constant(x) \
((((x) & 0xff00) >> 8) | \
(((x) & 0x00ff) << 8))
#define __bswap16(x) \
((__uint16_t)(__builtin_constant_p(x) ? \
__bswap16_constant(x) : \
__bswap16_var(x)))
#define __bswap32(x) \
((__uint32_t)(__builtin_constant_p(x) ? \
__bswap32_constant(x) : \
__bswap32_var(x)))
#else
#define __bswap16(x) __bswap16_var(x)
#define __bswap32(x) __bswap32_var(x)
#endif /* __OPTIMIZE__ */
#endif /* !_MACHINE_ENDIAN_H_ */
/*-
* Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _SYS_ENDIAN_H_
#define _SYS_ENDIAN_H_
#include <sys/cdefs.h>
#include <sys/_types.h>
#include <machine/endian.h>
#ifndef _UINT8_T_DECLARED
typedef __uint8_t uint8_t;
#define _UINT8_T_DECLARED
#endif
#ifndef _UINT16_T_DECLARED
typedef __uint16_t uint16_t;
#define _UINT16_T_DECLARED
#endif
#ifndef _UINT32_T_DECLARED
typedef __uint32_t uint32_t;
#define _UINT32_T_DECLARED
#endif
#ifndef _UINT64_T_DECLARED
typedef __uint64_t uint64_t;
#define _UINT64_T_DECLARED
#endif
/*
* General byte order swapping functions.
*/
#define bswap16(x) __bswap16(x)
#define bswap32(x) __bswap32(x)
#define bswap64(x) __bswap64(x)
/*
* Host to big endian, host to little endian, big endian to host, and little
* endian to host byte order functions as detailed in byteorder(9).
*/
#if _BYTE_ORDER == _LITTLE_ENDIAN
#define htobe16(x) bswap16((x))
#define htobe32(x) bswap32((x))
#define htobe64(x) bswap64((x))
#define htole16(x) ((uint16_t)(x))
#define htole32(x) ((uint32_t)(x))
#define htole64(x) ((uint64_t)(x))
#define be16toh(x) bswap16((x))
#define be32toh(x) bswap32((x))
#define be64toh(x) bswap64((x))
#define le16toh(x) ((uint16_t)(x))
#define le32toh(x) ((uint32_t)(x))
#define le64toh(x) ((uint64_t)(x))
#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
#define htobe16(x) ((uint16_t)(x))
#define htobe32(x) ((uint32_t)(x))
#define htobe64(x) ((uint64_t)(x))
#define htole16(x) bswap16((x))
#define htole32(x) bswap32((x))
#define htole64(x) bswap64((x))
#define be16toh(x) ((uint16_t)(x))
#define be32toh(x) ((uint32_t)(x))
#define be64toh(x) ((uint64_t)(x))
#define le16toh(x) bswap16((x))
#define le32toh(x) bswap32((x))
#define le64toh(x) bswap64((x))
#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
static __inline uint16_t
be16dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return ((p[0] << 8) | p[1]);
}
static __inline uint32_t
be32dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
}
static __inline uint64_t
be64dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
}
static __inline uint16_t
le16dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return ((p[1] << 8) | p[0]);
}
static __inline uint32_t
le32dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
}
static __inline uint64_t
le64dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
}
static __inline void
be16enc(void *pp, uint16_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = (u >> 8) & 0xff;
p[1] = u & 0xff;
}
static __inline void
be32enc(void *pp, uint32_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = (u >> 24) & 0xff;
p[1] = (u >> 16) & 0xff;
p[2] = (u >> 8) & 0xff;
p[3] = u & 0xff;
}
static __inline void
be64enc(void *pp, uint64_t u)
{
uint8_t *p = (uint8_t *)pp;
be32enc(p, (uint32_t)(u >> 32));
be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
}
static __inline void
le16enc(void *pp, uint16_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = u & 0xff;
p[1] = (u >> 8) & 0xff;
}
static __inline void
le32enc(void *pp, uint32_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = u & 0xff;
p[1] = (u >> 8) & 0xff;
p[2] = (u >> 16) & 0xff;
p[3] = (u >> 24) & 0xff;
}
static __inline void
le64enc(void *pp, uint64_t u)
{
uint8_t *p = (uint8_t *)pp;
le32enc(p, (uint32_t)(u & 0xffffffffU));
le32enc(p + 4, (uint32_t)(u >> 32));
}
#endif /* _SYS_ENDIAN_H_ */
/*
* 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 <debug.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <xlat_tables.h>
#include "../hikey960_def.h"
#include "../hikey960_private.h"
#define MAP_DDR MAP_REGION_FLAT(DDR_BASE, \
DDR_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
#define MAP_DEVICE MAP_REGION_FLAT(DEVICE_BASE, \
DEVICE_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
#define MAP_BL1_RW MAP_REGION_FLAT(BL1_RW_BASE, \
BL1_RW_LIMIT - BL1_RW_BASE, \
MT_MEMORY | MT_RW | MT_NS)
#define MAP_UFS_DATA MAP_REGION_FLAT(HIKEY960_UFS_DATA_BASE, \
HIKEY960_UFS_DATA_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
#define MAP_UFS_DESC MAP_REGION_FLAT(HIKEY960_UFS_DESC_BASE, \
HIKEY960_UFS_DESC_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
/*
* Table of regions for different BL stages to map using the MMU.
* This doesn't include Trusted RAM as the 'mem_layout' argument passed to
* hikey960_init_mmu_elx() will give the available subset of that,
*/
#if IMAGE_BL1
static const mmap_region_t hikey960_mmap[] = {
MAP_UFS_DATA,
MAP_BL1_RW,
MAP_UFS_DESC,
MAP_DEVICE,
{0}
};
#endif
#if IMAGE_BL2
static const mmap_region_t hikey960_mmap[] = {
MAP_DDR,
MAP_DEVICE,
{0}
};
#endif
#if IMAGE_BL31
static const mmap_region_t hikey960_mmap[] = {
MAP_DEVICE,
{0}
};
#endif
/*
* Macro generating the code for the function setting up the pagetables as per
* the platform memory map & initialize the mmu, for the given exception level
*/
#define HIKEY960_CONFIGURE_MMU_EL(_el) \
void hikey960_init_mmu_el##_el(unsigned long total_base, \
unsigned long total_size, \
unsigned long ro_start, \
unsigned long ro_limit, \
unsigned long coh_start, \
unsigned long coh_limit) \
{ \
mmap_add_region(total_base, total_base, \
total_size, \
MT_MEMORY | MT_RW | MT_SECURE); \
mmap_add_region(ro_start, ro_start, \
ro_limit - ro_start, \
MT_MEMORY | MT_RO | MT_SECURE); \
mmap_add_region(coh_start, coh_start, \
coh_limit - coh_start, \
MT_DEVICE | MT_RW | MT_SECURE); \
mmap_add(hikey960_mmap); \
init_xlat_tables(); \
\
enable_mmu_el##_el(0); \
}
/* Define EL1 and EL3 variants of the function initialising the MMU */
HIKEY960_CONFIGURE_MMU_EL(1)
HIKEY960_CONFIGURE_MMU_EL(3)
unsigned long plat_get_ns_image_entrypoint(void)
{
return NS_BL1U_BASE;
}
unsigned int plat_get_syscnt_freq2(void)
{
return 1920000;
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <cortex_a53.h>
#include <cortex_a73.h>
#include "../hikey960_def.h"
.globl plat_my_core_pos
.globl platform_mem_init
.globl plat_crash_console_init
.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
and x1, x0, #MPIDR_CPU_MASK
and x0, x0, #MPIDR_CLUSTER_MASK
add x0, x1, x0, LSR #6
ret
endfunc plat_my_core_pos
/* -----------------------------------------------------
* void platform_mem_init(void);
*
* We don't need to carry out any memory initialization
* on HIKEY. The Secure RAM is accessible straight away.
* -----------------------------------------------------
*/
func platform_mem_init
ret
endfunc platform_mem_init
/* ---------------------------------------------
* int plat_crash_console_init(void)
* Function to initialize the crash console
* without a C Runtime to print crash report.
* Clobber list : x0, x1, x2
* ---------------------------------------------
*/
func plat_crash_console_init
mov_imm x0, CRASH_CONSOLE_BASE
mov_imm x1, PL011_UART_CLK_IN_HZ
mov_imm x2, PL011_BAUDRATE
b console_core_init
endfunc plat_crash_console_init
/* ---------------------------------------------
* int plat_crash_console_putc(int c)
* Function to print a character on the crash
* console without a C Runtime.
* Clobber list : x1, x2
* ---------------------------------------------
*/
func plat_crash_console_putc
mov_imm x1, CRASH_CONSOLE_BASE
b console_core_putc
endfunc plat_crash_console_putc
/* ---------------------------------------------
* void plat_report_exception(unsigned int type)
* Function to report an unhandled exception
* with platform-specific means.
* On HIKEY platform, it updates the LEDs
* to indicate where we are
* ---------------------------------------------
*/
func plat_report_exception
mov x8, x30
/* Turn on LED according to x0 (0 -- f) */
ldr x2, =0xf7020000
and x1, x0, #1
str w1, [x2, #4]
and x1, x0, #2
str w1, [x2, #8]
and x1, x0, #4
str w1, [x2, #16]
and x1, x0, #8
str w1, [x2, #32]
mrs x2, currentel
and x2, x2, #0x0c
/* Check EL1 */
cmp x2, #0x04
beq plat_report_el1
adr x4, plat_err_str
bl asm_print_str
adr x4, esr_el3_str
bl asm_print_str
mrs x4, esr_el3
bl asm_print_hex
adr x4, elr_el3_str
bl asm_print_str
mrs x4, elr_el3
bl asm_print_hex
b plat_report_end
plat_report_el1:
adr x4, plat_err_str
bl asm_print_str
adr x4, esr_el1_str
bl asm_print_str
mrs x4, esr_el1
bl asm_print_hex
adr x4, elr_el1_str
bl asm_print_str
mrs x4, elr_el1
bl asm_print_hex
plat_report_end:
mov x30, x8
ret
endfunc plat_report_exception
/* -----------------------------------------------------
* void plat_reset_handler(void);
* -----------------------------------------------------
*/
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:"
esr_el3_str:
.asciz "\nESR_EL3: "
elr_el3_str:
.asciz "\nELR_EL3: "
esr_el1_str:
.asciz "\nESR_EL1: "
elr_el1_str:
.asciz "\nELR_EL1: "
/*
* 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;
}
/*
* 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);
}
/*
* 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__ */
/*
* 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;
}
/*
* 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 <console.h>
#include <debug.h>
#include <delay_timer.h>
#include <dw_ufs.h>
#include <errno.h>
#include <gicv2.h>
#include <hi3660.h>
#include <mmio.h>
#include <generic_delay_timer.h>
#include <platform.h>
#include <platform_def.h>
#include <string.h>
#include <tbbr/tbbr_img_desc.h>
#include <ufs.h>
#include "../../bl1/bl1_private.h"
#include "hikey960_def.h"
#include "hikey960_private.h"
enum {
BOOT_MODE_RECOVERY = 0,
BOOT_MODE_NORMAL,
BOOT_MODE_MASK = 1,
};
/*
* Declarations of linker defined symbols which will help us find the layout
* of trusted RAM
*/
extern unsigned long __COHERENT_RAM_START__;
extern unsigned long __COHERENT_RAM_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 BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
/* Data structure which holds the extents of the trusted RAM for BL1 */
static meminfo_t bl1_tzram_layout;
/******************************************************************************
* 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,
};
meminfo_t *bl1_plat_sec_mem_layout(void)
{
return &bl1_tzram_layout;
}
/*
* Perform any BL1 specific platform actions.
*/
void bl1_early_platform_setup(void)
{
const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
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);
/* Allow BL1 to see the whole Trusted RAM */
bl1_tzram_layout.total_base = BL1_RW_BASE;
bl1_tzram_layout.total_size = BL1_RW_SIZE;
/* Calculate how much RAM BL1 is using and how much remains free */
bl1_tzram_layout.free_base = BL1_RW_BASE;
bl1_tzram_layout.free_size = BL1_RW_SIZE;
reserve_mem(&bl1_tzram_layout.free_base,
&bl1_tzram_layout.free_size,
BL1_RAM_BASE,
bl1_size);
INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
bl1_size);
}
/*
* Perform the very early platform specific architecture setup here. At the
* moment this only does basic initialization. Later architectural setup
* (bl1_arch_setup()) does not do anything platform specific.
*/
void bl1_plat_arch_setup(void)
{
hikey960_init_mmu_el3(bl1_tzram_layout.total_base,
bl1_tzram_layout.total_size,
BL1_RO_BASE,
BL1_RO_LIMIT,
BL1_COHERENT_RAM_BASE,
BL1_COHERENT_RAM_LIMIT);
}
static void hikey960_clk_init(void)
{
/* change ldi0 sel to ppll2 */
mmio_write_32(0xfff350b4, 0xf0002000);
/* ldi0 20' */
mmio_write_32(0xfff350bc, 0xfc004c00);
}
static void hikey960_pmu_init(void)
{
/* clear np_xo_abb_dig_START bit in PMIC_CLK_TOP_CTRL7 register */
mmio_clrbits_32(PMU_SSI0_CLK_TOP_CTRL7_REG, NP_XO_ABB_DIG);
}
static void hikey960_enable_ppll3(void)
{
/* enable ppll3 */
mmio_write_32(PMC_PPLL3_CTRL0_REG, 0x4904305);
mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x2300000);
mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x6300000);
}
static void bus_idle_clear(unsigned int value)
{
unsigned int pmc_value, value1, value2;
int timeout = 100;
pmc_value = value << 16;
pmc_value &= ~value;
mmio_write_32(PMC_NOC_POWER_IDLEREQ_REG, pmc_value);
for (;;) {
value1 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLEACK_REG);
value2 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLE_REG);
if (((value1 & value) == 0) && ((value2 & value) == 0))
break;
udelay(1);
timeout--;
if (timeout <= 0) {
WARN("%s timeout\n", __func__);
break;
}
}
}
static void set_vivobus_power_up(void)
{
/* clk enable */
mmio_write_32(CRG_CLKDIV20_REG, 0x00020002);
mmio_write_32(CRG_PEREN0_REG, 0x00001000);
}
static void set_dss_power_up(void)
{
/* set edc0 133MHz = 1600MHz / 12 */
mmio_write_32(CRG_CLKDIV5_REG, 0x003f000b);
/* set ldi0 ppl0 */
mmio_write_32(CRG_CLKDIV3_REG, 0xf0001000);
/* set ldi0 133MHz, 1600MHz / 12 */
mmio_write_32(CRG_CLKDIV5_REG, 0xfc002c00);
/* mtcmos on */
mmio_write_32(CRG_PERPWREN_REG, 0x00000020);
udelay(100);
/* DISP CRG */
mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000010);
/* clk enable */
mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
mmio_write_32(CRG_PEREN0_REG, 0x00002000);
mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
udelay(1);
/* clk disable */
mmio_write_32(CRG_PERDIS3_REG, 0x0003b000);
mmio_write_32(CRG_PERDIS0_REG, 0x00002000);
mmio_write_32(CRG_CLKDIV18_REG, 0x01400000);
udelay(1);
/* iso disable */
mmio_write_32(CRG_ISODIS_REG, 0x00000040);
/* unreset */
mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000006);
mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000c00);
/* clk enable */
mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
mmio_write_32(CRG_PEREN0_REG, 0x00002000);
mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
/* bus idle clear */
bus_idle_clear(PMC_NOC_POWER_IDLEREQ_DSS);
/* set edc0 400MHz for 2K 1600MHz / 4 */
mmio_write_32(CRG_CLKDIV5_REG, 0x003f0003);
/* set ldi 266MHz, 1600MHz / 6 */
mmio_write_32(CRG_CLKDIV5_REG, 0xfc001400);
}
static void set_vcodec_power_up(void)
{
/* clk enable */
mmio_write_32(CRG_CLKDIV20_REG, 0x00040004);
mmio_write_32(CRG_PEREN0_REG, 0x00000060);
mmio_write_32(CRG_PEREN2_REG, 0x10000000);
/* unreset */
mmio_write_32(CRG_PERRSTDIS0_REG, 0x00000018);
/* bus idle clear */
bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VCODEC);
}
static void set_vdec_power_up(void)
{
/* mtcmos on */
mmio_write_32(CRG_PERPWREN_REG, 0x00000004);
udelay(100);
/* clk enable */
mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
mmio_write_32(CRG_PEREN2_REG, 0x20080000);
mmio_write_32(CRG_PEREN3_REG, 0x00000800);
udelay(1);
/* clk disable */
mmio_write_32(CRG_PERDIS3_REG, 0x00000800);
mmio_write_32(CRG_PERDIS2_REG, 0x20080000);
mmio_write_32(CRG_CLKDIV18_REG, 0x80000000);
udelay(1);
/* iso disable */
mmio_write_32(CRG_ISODIS_REG, 0x00000004);
/* unreset */
mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000200);
/* clk enable */
mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
mmio_write_32(CRG_PEREN2_REG, 0x20080000);
mmio_write_32(CRG_PEREN3_REG, 0x00000800);
/* bus idle clear */
bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VDEC);
}
static void set_venc_power_up(void)
{
/* set venc ppll3 */
mmio_write_32(CRG_CLKDIV8_REG, 0x18001000);
/* set venc 258MHz, 1290MHz / 5 */
mmio_write_32(CRG_CLKDIV8_REG, 0x07c00100);
/* mtcmos on */
mmio_write_32(CRG_PERPWREN_REG, 0x00000002);
udelay(100);
/* clk enable */
mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
mmio_write_32(CRG_PEREN2_REG, 0x40000100);
mmio_write_32(CRG_PEREN3_REG, 0x00000400);
udelay(1);
/* clk disable */
mmio_write_32(CRG_PERDIS3_REG, 0x00000400);
mmio_write_32(CRG_PERDIS2_REG, 0x40000100);
mmio_write_32(CRG_CLKDIV19_REG, 0x00010000);
udelay(1);
/* iso disable */
mmio_write_32(CRG_ISODIS_REG, 0x00000002);
/* unreset */
mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000100);
/* clk enable */
mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
mmio_write_32(CRG_PEREN2_REG, 0x40000100);
mmio_write_32(CRG_PEREN3_REG, 0x00000400);
/* bus idle clear */
bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VENC);
/* set venc 645MHz, 1290MHz / 2 */
mmio_write_32(CRG_CLKDIV8_REG, 0x07c00040);
}
static void set_isp_power_up(void)
{
/* mtcmos on */
mmio_write_32(CRG_PERPWREN_REG, 0x00000001);
udelay(100);
/* clk enable */
mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
mmio_write_32(CRG_PEREN5_REG, 0x01000010);
mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
udelay(1);
/* clk disable */
mmio_write_32(CRG_PERDIS5_REG, 0x01000010);
mmio_write_32(CRG_PERDIS3_REG, 0x0bf00000);
mmio_write_32(CRG_CLKDIV18_REG, 0x70000000);
mmio_write_32(CRG_CLKDIV20_REG, 0x00100000);
udelay(1);
/* iso disable */
mmio_write_32(CRG_ISODIS_REG, 0x00000001);
/* unreset */
mmio_write_32(CRG_ISP_SEC_RSTDIS_REG, 0x0000002f);
/* clk enable */
mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
mmio_write_32(CRG_PEREN5_REG, 0x01000010);
mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
/* bus idle clear */
bus_idle_clear(PMC_NOC_POWER_IDLEREQ_ISP);
/* csi clk enable */
mmio_write_32(CRG_PEREN3_REG, 0x00700000);
}
static void set_ivp_power_up(void)
{
/* set ivp ppll0 */
mmio_write_32(CRG_CLKDIV0_REG, 0xc0000000);
/* set ivp 267MHz, 1600MHz / 6 */
mmio_write_32(CRG_CLKDIV0_REG, 0x3c001400);
/* mtcmos on */
mmio_write_32(CRG_PERPWREN_REG, 0x00200000);
udelay(100);
/* IVP CRG unreset */
mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000001);
/* clk enable */
mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
udelay(1);
/* clk disable */
mmio_write_32(CRG_PERDIS4_REG, 0x000000a8);
mmio_write_32(CRG_CLKDIV20_REG, 0x02000000);
udelay(1);
/* iso disable */
mmio_write_32(CRG_ISODIS_REG, 0x01000000);
/* unreset */
mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000002);
/* clk enable */
mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
/* bus idle clear */
bus_idle_clear(PMC_NOC_POWER_IDLEREQ_IVP);
/* set ivp 533MHz, 1600MHz / 3 */
mmio_write_32(CRG_CLKDIV0_REG, 0x3c000800);
}
static void set_audio_power_up(void)
{
unsigned int ret;
int timeout = 100;
/* mtcmos on */
mmio_write_32(SCTRL_SCPWREN_REG, 0x00000001);
udelay(100);
/* clk enable */
mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
mmio_write_32(CRG_PEREN0_REG, 0x04000000);
mmio_write_32(CRG_PEREN5_REG, 0x00000080);
mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
udelay(1);
/* clk disable */
mmio_write_32(SCTRL_SCPERDIS1_REG, 0x0000000f);
mmio_write_32(SCTRL_SCPERDIS0_REG, 0x0c000000);
mmio_write_32(CRG_PERDIS5_REG, 0x00000080);
mmio_write_32(CRG_PERDIS0_REG, 0x04000000);
mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010000);
mmio_write_32(CRG_CLKDIV19_REG, 0x80100000);
udelay(1);
/* iso disable */
mmio_write_32(SCTRL_SCISODIS_REG, 0x00000001);
udelay(1);
/* unreset */
mmio_write_32(SCTRL_PERRSTDIS1_SEC_REG, 0x00000001);
mmio_write_32(SCTRL_SCPERRSTDIS0_REG, 0x00000780);
/* clk enable */
mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
mmio_write_32(CRG_PEREN0_REG, 0x04000000);
mmio_write_32(CRG_PEREN5_REG, 0x00000080);
mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
/* bus idle clear */
mmio_write_32(SCTRL_SCPERCTRL7_REG, 0x00040000);
for (;;) {
ret = mmio_read_32(SCTRL_SCPERSTAT6_REG);
if (((ret & (1 << 5)) == 0) && ((ret & (1 << 8)) == 0))
break;
udelay(1);
timeout--;
if (timeout <= 0) {
WARN("%s timeout\n", __func__);
break;
}
}
mmio_write_32(ASP_CFG_MMBUF_CTRL_REG, 0x00ff0000);
}
static void set_pcie_power_up(void)
{
/* mtcmos on */
mmio_write_32(SCTRL_SCPWREN_REG, 0x00000010);
udelay(100);
/* clk enable */
mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
udelay(1);
/* clk disable */
mmio_write_32(SCTRL_SCPERDIS2_REG, 0x00104000);
mmio_write_32(CRG_PERDIS7_REG, 0x000003a0);
mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000000);
udelay(1);
/* iso disable */
mmio_write_32(SCTRL_SCISODIS_REG, 0x00000030);
/* unreset */
mmio_write_32(CRG_PERRSTDIS3_REG, 0x8c000000);
/* clk enable */
mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
}
static void ispfunc_enable(void)
{
/* enable ispfunc. Otherwise powerup isp_srt causes exception. */
mmio_write_32(0xfff35000, 0x00000008);
mmio_write_32(0xfff35460, 0xc004ffff);
mmio_write_32(0xfff35030, 0x02000000);
mdelay(10);
}
static void isps_control_clock(int flag)
{
unsigned int ret;
/* flag: 0 -- disable clock, 1 -- enable clock */
if (flag) {
ret = mmio_read_32(0xe8420364);
ret |= 1;
mmio_write_32(0xe8420364, ret);
} else {
ret = mmio_read_32(0xe8420364);
ret &= ~1;
mmio_write_32(0xe8420364, ret);
}
}
static void set_isp_srt_power_up(void)
{
unsigned int ret;
ispfunc_enable();
/* reset */
mmio_write_32(0xe8420374, 0x00000001);
mmio_write_32(0xe8420350, 0x00000000);
mmio_write_32(0xe8420358, 0x00000000);
/* mtcmos on */
mmio_write_32(0xfff35150, 0x00400000);
udelay(100);
/* clk enable */
isps_control_clock(1);
udelay(1);
isps_control_clock(0);
udelay(1);
/* iso disable */
mmio_write_32(0xfff35148, 0x08000000);
/* unreset */
ret = mmio_read_32(0xe8420374);
ret &= ~0x1;
mmio_write_32(0xe8420374, ret);
/* clk enable */
isps_control_clock(1);
/* enable clock gating for accessing csi registers */
mmio_write_32(0xe8420010, ~0);
}
static void hikey960_regulator_enable(void)
{
set_vivobus_power_up();
hikey960_enable_ppll3();
set_dss_power_up();
set_vcodec_power_up();
set_vdec_power_up();
set_venc_power_up();
set_isp_power_up();
set_ivp_power_up();
set_audio_power_up();
set_pcie_power_up();
set_isp_srt_power_up();
}
static void hikey960_ufs_reset(void)
{
unsigned int data, mask;
mmio_write_32(CRG_PERDIS7_REG, 1 << 14);
mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
do {
data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
} while (data & BIT_SYSCTRL_REF_CLOCK_EN);
/* use abb clk */
mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1);
mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN);
mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16));
mdelay(1);
mmio_write_32(CRG_PEREN7_REG, 1 << 14);
mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT);
do {
data = mmio_read_32(CRG_PERRSTSTAT3_REG);
} while ((data & PERI_UFS_BIT) == 0);
mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN);
mdelay(1);
mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY);
mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
MASK_UFS_DEVICE_RESET);
/* clear SC_DIV_UFS_PERIBUS */
mask = SC_DIV_UFS_PERIBUS << 16;
mmio_write_32(CRG_CLKDIV17_REG, mask);
/* set SC_DIV_UFSPHY_CFG(3) */
mask = SC_DIV_UFSPHY_CFG_MASK << 16;
data = SC_DIV_UFSPHY_CFG(3);
mmio_write_32(CRG_CLKDIV16_REG, mask | data);
data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ;
data |= 0x39;
mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data);
mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL);
mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG,
MASK_UFS_CLK_GATE_BYPASS);
mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS);
mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN);
mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL);
mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL);
mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN);
mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT);
mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N);
mdelay(1);
mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET);
mdelay(20);
mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
0x03300330);
mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT);
do {
data = mmio_read_32(CRG_PERRSTSTAT3_REG);
} while (data & PERI_UFS_BIT);
}
static void hikey960_ufs_init(void)
{
dw_ufs_params_t ufs_params;
memset(&ufs_params, 0, sizeof(ufs_params));
ufs_params.reg_base = UFS_REG_BASE;
ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0)
hikey960_ufs_reset();
dw_ufs_init(&ufs_params);
}
static void hikey960_tzc_init(void)
{
mmio_write_32(TZC_EN0_REG, 0x7fbff066);
mmio_write_32(TZC_EN1_REG, 0xfffff5fc);
mmio_write_32(TZC_EN2_REG, 0x0007005c);
mmio_write_32(TZC_EN3_REG, 0x37030700);
mmio_write_32(TZC_EN4_REG, 0xf63fefae);
mmio_write_32(TZC_EN5_REG, 0x000410fd);
mmio_write_32(TZC_EN6_REG, 0x0063ff68);
mmio_write_32(TZC_EN7_REG, 0x030000f3);
mmio_write_32(TZC_EN8_REG, 0x00000007);
}
static void hikey960_peri_init(void)
{
/* unreset */
mmio_setbits_32(CRG_PERRSTDIS4_REG, 1);
}
static void hikey960_pinmux_init(void)
{
unsigned int id;
hikey960_read_boardid(&id);
if (id == 5301) {
/* hikey960 hardware v2 */
/* GPIO150: LED */
mmio_write_32(IOMG_FIX_006_REG, 0);
/* GPIO151: LED */
mmio_write_32(IOMG_FIX_007_REG, 0);
/* GPIO189: LED */
mmio_write_32(IOMG_AO_011_REG, 0);
/* GPIO190: LED */
mmio_write_32(IOMG_AO_012_REG, 0);
/* GPIO46 */
mmio_write_32(IOMG_044_REG, 0);
/* GPIO202 */
mmio_write_32(IOMG_AO_023_REG, 0);
/* GPIO206 */
mmio_write_32(IOMG_AO_026_REG, 0);
/* GPIO219 - PD pullup */
mmio_write_32(IOMG_AO_039_REG, 0);
mmio_write_32(IOCG_AO_043_REG, 1 << 0);
}
/* GPIO005 - PMU SSI, 10mA */
mmio_write_32(IOCG_006_REG, 2 << 4);
}
/*
* Function which will perform any remaining platform-specific setup that can
* occur after the MMU and data cache have been enabled.
*/
void bl1_platform_setup(void)
{
hikey960_clk_init();
hikey960_pmu_init();
hikey960_regulator_enable();
hikey960_tzc_init();
hikey960_peri_init();
hikey960_ufs_init();
hikey960_pinmux_init();
hikey960_io_setup();
}
/*
* The following function checks if Firmware update is needed,
* by checking if TOC in FIP image is valid or not.
*/
unsigned int bl1_plat_get_next_image_id(void)
{
unsigned int mode, ret;
mode = mmio_read_32(SCTRL_BAK_DATA0_REG);
switch (mode & BOOT_MODE_MASK) {
case BOOT_MODE_RECOVERY:
ret = NS_BL1U_IMAGE_ID;
break;
case BOOT_MODE_NORMAL:
ret = BL2_IMAGE_ID;
break;
default:
WARN("Invalid boot mode is found:%d\n", mode);
panic();
}
return ret;
}
image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
{
unsigned int index = 0;
while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
if (bl1_tbbr_image_descs[index].image_id == image_id)
return &bl1_tbbr_image_descs[index];
index++;
}
return NULL;
}
void bl1_plat_set_ep_info(unsigned int image_id,
entry_point_info_t *ep_info)
{
unsigned int data = 0;
uintptr_t tmp = HIKEY960_NS_TMP_OFFSET;
if (image_id == BL2_IMAGE_ID)
return;
/* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */
memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET,
NS_BL1U_SIZE);
memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE);
inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE);
/* Initialize the GIC driver, cpu and distributor interfaces */
gicv2_driver_init(&hikey960_gic_data);
gicv2_distif_init();
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
/* CNTFRQ is read-only in EL1 */
write_cntfrq_el0(plat_get_syscnt_freq2());
data = read_cpacr_el1();
do {
data |= 3 << 20;
write_cpacr_el1(data);
data = read_cpacr_el1();
} while ((data & (3 << 20)) != (3 << 20));
INFO("cpacr_el1:0x%x\n", data);
ep_info->args.arg0 = 0xffff & read_mpidr();
ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS);
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <debug.h>
#include <errno.h>
#include <generic_delay_timer.h>
#include <hi3660.h>
#include <mmio.h>
#include <platform_def.h>
#include <string.h>
#include <ufs.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 BL2_RO_BASE (unsigned long)(&__RO_START__)
#define BL2_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 BL2_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
#define BL2_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
typedef struct bl2_to_bl31_params_mem {
bl31_params_t bl31_params;
image_info_t bl31_image_info;
image_info_t bl32_image_info;
image_info_t bl33_image_info;
entry_point_info_t bl33_ep_info;
entry_point_info_t bl32_ep_info;
entry_point_info_t bl31_ep_info;
} bl2_to_bl31_params_mem_t;
static bl2_to_bl31_params_mem_t bl31_params_mem;
meminfo_t *bl2_plat_sec_mem_layout(void)
{
return &bl2_tzram_layout;
}
bl31_params_t *bl2_plat_get_bl31_params(void)
{
bl31_params_t *bl2_to_bl31_params = NULL;
/*
* Initialise the memory for all the arguments that needs to
* be passed to BL3-1
*/
memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
/* Assign memory for TF related information */
bl2_to_bl31_params = &bl31_params_mem.bl31_params;
SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
/* Fill BL3-1 related information */
bl2_to_bl31_params->bl31_image_info = &bl31_params_mem.bl31_image_info;
SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
VERSION_1, 0);
/* Fill BL3-2 related information if it exists */
#if BL32_BASE
bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
VERSION_1, 0);
bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
VERSION_1, 0);
#endif
/* Fill BL3-3 related information */
bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info,
PARAM_EP, VERSION_1, 0);
/* BL3-3 expects to receive the primary CPU MPID (through x0) */
bl2_to_bl31_params->bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
VERSION_1, 0);
return bl2_to_bl31_params;
}
/*******************************************************************************
* Populate the extents of memory available for loading SCP_BL2 (if used),
* i.e. anywhere in trusted RAM as long as it doesn't overwrite BL2.
******************************************************************************/
void bl2_plat_get_scp_bl2_meminfo(meminfo_t *scp_bl2_meminfo)
{
ufs_params_t ufs_params;
memset(&ufs_params, 0, sizeof(ufs_params_t));
ufs_params.reg_base = UFS_REG_BASE;
ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
ufs_params.flags = UFS_FLAGS_SKIPINIT;
ufs_init(NULL, &ufs_params);
hikey960_io_setup();
*scp_bl2_meminfo = bl2_tzram_layout;
}
extern int load_lpm3(void);
int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
{
int i;
int *buf;
assert(scp_bl2_image_info->image_size < SCP_MEM_SIZE);
INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
INFO("BL2: SCP_BL2: 0x%lx@0x%x\n",
scp_bl2_image_info->image_base,
scp_bl2_image_info->image_size);
buf = (int *)scp_bl2_image_info->image_base;
INFO("BL2: SCP_BL2 HEAD:\n");
for (i = 0; i < 64; i += 4)
INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
buf[i], buf[i+1], buf[i+2], buf[i+3]);
buf = (int *)(scp_bl2_image_info->image_base +
scp_bl2_image_info->image_size - 256);
INFO("BL2: SCP_BL2 TAIL:\n");
for (i = 0; i < 64; i += 4)
INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
buf[i], buf[i+1], buf[i+2], buf[i+3]);
memcpy((void *)SCP_MEM_BASE,
(void *)scp_bl2_image_info->image_base,
scp_bl2_image_info->image_size);
INFO("BL2: SCP_BL2 transferred to SCP\n");
load_lpm3();
(void)buf;
return 0;
}
struct entry_point_info *bl2_plat_get_bl31_ep_info(void)
{
return &bl31_params_mem.bl31_ep_info;
}
void bl2_plat_set_bl31_ep_info(image_info_t *image,
entry_point_info_t *bl31_ep_info)
{
SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE);
bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS);
}
void bl2_plat_set_bl33_ep_info(image_info_t *image,
entry_point_info_t *bl33_ep_info)
{
unsigned long el_status;
unsigned int mode;
/* Figure out what mode we enter the non-secure world in */
el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
el_status &= ID_AA64PFR0_ELX_MASK;
if (el_status)
mode = MODE_EL2;
else
mode = MODE_EL1;
/*
* TODO: Consider the possibility of specifying the SPSR in
* the FIP ToC and allowing the platform to have a say as
* well.
*/
bl33_ep_info->spsr = SPSR_64(mode, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS);
SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE);
}
void bl2_plat_flush_bl31_params(void)
{
flush_dcache_range((unsigned long)&bl31_params_mem,
sizeof(bl2_to_bl31_params_mem_t));
}
void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo)
{
bl33_meminfo->total_base = DDR_BASE;
bl33_meminfo->total_size = DDR_SIZE;
bl33_meminfo->free_base = DDR_BASE;
bl33_meminfo->free_size = DDR_SIZE;
}
void bl2_early_platform_setup(meminfo_t *mem_layout)
{
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);
/* Setup the BL2 memory layout */
bl2_tzram_layout = *mem_layout;
}
void bl2_plat_arch_setup(void)
{
hikey960_init_mmu_el1(bl2_tzram_layout.total_base,
bl2_tzram_layout.total_size,
BL2_RO_BASE,
BL2_RO_LIMIT,
BL2_COHERENT_RAM_BASE,
BL2_COHERENT_RAM_LIMIT);
}
void bl2_platform_setup(void)
{
/* disable WDT0 */
if (mmio_read_32(WDT0_REG_BASE + WDT_LOCK_OFFSET) == WDT_LOCKED) {
mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, WDT_UNLOCK);
mmio_write_32(WDT0_REG_BASE + WDT_CONTROL_OFFSET, 0);
mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, 0);
}
}
/*
* 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)
{
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <debug.h>
#include <delay_timer.h>
#include <errno.h>
#include <hi3660.h>
#include <mmio.h>
#include "hikey960_private.h"
#define ADC_ADCIN0 0
#define ADC_ADCIN1 1
#define ADC_ADCIN2 2
#define HKADC_DATA_GRADE0 0
#define HKADC_DATA_GRADE1 100
#define HKADC_DATA_GRADE2 300
#define HKADC_DATA_GRADE3 500
#define HKADC_DATA_GRADE4 700
#define HKADC_DATA_GRADE5 900
#define HKADC_DATA_GRADE6 1100
#define HKADC_DATA_GRADE7 1300
#define HKADC_DATA_GRADE8 1500
#define HKADC_DATA_GRADE9 1700
#define HKADC_DATA_GRADE10 1800
#define BOARDID_VALUE0 0
#define BOARDID_VALUE1 1
#define BOARDID_VALUE2 2
#define BOARDID_VALUE3 3
#define BOARDID_VALUE4 4
#define BOARDID_VALUE5 5
#define BOARDID_VALUE6 6
#define BOARDID_VALUE7 7
#define BOARDID_VALUE8 8
#define BOARDID_VALUE9 9
#define BOARDID_UNKNOWN 0xF
#define BOARDID3_BASE 5
static void init_adc(void)
{
/* reset hkadc */
mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
/* wait a few clock cycles */
udelay(2);
mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
udelay(2);
/* enable hkadc clock */
mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
udelay(2);
mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
udelay(2);
}
static int get_adc(unsigned int channel, unsigned int *value)
{
unsigned int data, value1, value0;
if (channel > HKADC_CHANNEL_MAX) {
WARN("invalid channel:%d\n", channel);
return -EFAULT;
}
/* configure the read/write operation for external HKADC */
mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
/* configure the number of accessing registers */
mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
/* configure delay of accessing registers */
mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
/* start HKADC */
mmio_write_32(HKADC_DSP_START_REG, 1);
do {
data = mmio_read_32(HKADC_DSP_START_REG);
} while (data & 1);
/* convert AD result */
value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
data = ((value1 << 4) & HKADC_VALUE_HIGH) |
((value0 >> 4) & HKADC_VALUE_LOW);
*value = data;
return 0;
}
static int get_value(unsigned int channel, unsigned int *value)
{
int ret;
ret = get_adc(channel, value);
if (ret)
return ret;
/* convert ADC value to micro-volt */
ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
*value = ret;
return 0;
}
static int adcin_data_remap(unsigned int adcin_value)
{
int ret;
if (adcin_value < HKADC_DATA_GRADE0)
ret = BOARDID_UNKNOWN;
else if (adcin_value < HKADC_DATA_GRADE1)
ret = BOARDID_VALUE0;
else if (adcin_value < HKADC_DATA_GRADE2)
ret = BOARDID_VALUE1;
else if (adcin_value < HKADC_DATA_GRADE3)
ret = BOARDID_VALUE2;
else if (adcin_value < HKADC_DATA_GRADE4)
ret = BOARDID_VALUE3;
else if (adcin_value < HKADC_DATA_GRADE5)
ret = BOARDID_VALUE4;
else if (adcin_value < HKADC_DATA_GRADE6)
ret = BOARDID_VALUE5;
else if (adcin_value < HKADC_DATA_GRADE7)
ret = BOARDID_VALUE6;
else if (adcin_value < HKADC_DATA_GRADE8)
ret = BOARDID_VALUE7;
else if (adcin_value < HKADC_DATA_GRADE9)
ret = BOARDID_VALUE8;
else if (adcin_value < HKADC_DATA_GRADE10)
ret = BOARDID_VALUE9;
else
ret = BOARDID_UNKNOWN;
return ret;
}
int hikey960_read_boardid(unsigned int *id)
{
unsigned int adcin0, adcin1, adcin2;
unsigned int adcin0_remap, adcin1_remap, adcin2_remap;
assert(id != NULL);
init_adc();
/* read ADC channel0 data */
get_value(ADC_ADCIN0, &adcin0);
adcin0_remap = adcin_data_remap(adcin0);
INFO("[BDID]adcin0:%d adcin0_remap:%d\n", adcin0, adcin0_remap);
if (adcin0_remap == BOARDID_UNKNOWN)
return -EINVAL;
/* read ADC channel1 data */
get_value(ADC_ADCIN1, &adcin1);
adcin1_remap = adcin_data_remap(adcin1);
INFO("[BDID]adcin1:%d adcin1_remap:%d\n", adcin1, adcin1_remap);
if (adcin1_remap == BOARDID_UNKNOWN)
return -EINVAL;
/* read ADC channel2 data */
get_value(ADC_ADCIN2, &adcin2);
adcin2_remap = adcin_data_remap(adcin2);
INFO("[BDID]adcin2:%d adcin2_remap:%d\n", adcin2, adcin2_remap);
if (adcin2_remap == BOARDID_UNKNOWN)
return -EINVAL;
*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
(adcin1_remap * 10) + adcin0_remap;
INFO("[BDID]boardid: %d\n", *id);
return 0;
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __HIKEY960_DEF_H__
#define __HIKEY960_DEF_H__
#include <common_def.h>
#include <tbbr_img_def.h>
#define DDR_BASE 0x0
#define DDR_SIZE 0xC0000000
#define DEVICE_BASE 0xE0000000
#define DEVICE_SIZE 0x20000000
/*
* PL011 related constants
*/
#define PL011_UART5_BASE 0xFDF05000
#define PL011_UART6_BASE 0xFFF32000
#define PL011_BAUDRATE 115200
#define PL011_UART_CLK_IN_HZ 19200000
#define UFS_BASE 0
/* FIP partition */
#define HIKEY960_FIP_BASE (UFS_BASE + 0x1400000)
#define HIKEY960_FIP_MAX_SIZE (12 << 20)
#define HIKEY960_UFS_DESC_BASE 0x20000000
#define HIKEY960_UFS_DESC_SIZE 0x00200000 /* 2MB */
#define HIKEY960_UFS_DATA_BASE 0x10000000
#define HIKEY960_UFS_DATA_SIZE 0x0A000000 /* 160MB */
#endif /* __HIKEY960_DEF_H__ */
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <firmware_image_package.h>
#include <io_block.h>
#include <io_driver.h>
#include <io_fip.h>
#include <io_memmap.h>
#include <io_storage.h>
#include <mmio.h>
#include <platform_def.h>
#include <semihosting.h> /* For FOPEN_MODE_... */
#include <string.h>
#include <ufs.h>
struct plat_io_policy {
uintptr_t *dev_handle;
uintptr_t image_spec;
int (*check)(const uintptr_t spec);
};
static const io_dev_connector_t *ufs_dev_con, *fip_dev_con;
static uintptr_t ufs_dev_handle, fip_dev_handle;
static int check_ufs(const uintptr_t spec);
static int check_fip(const uintptr_t spec);
size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size);
size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size);
static const io_block_spec_t ufs_fip_spec = {
.offset = HIKEY960_FIP_BASE,
.length = HIKEY960_FIP_MAX_SIZE,
};
static const io_block_spec_t ufs_data_spec = {
.offset = 0,
.length = 256 << 20,
};
static const io_block_dev_spec_t ufs_dev_spec = {
/* It's used as temp buffer in block driver. */
.buffer = {
.offset = HIKEY960_UFS_DATA_BASE,
.length = HIKEY960_UFS_DATA_SIZE,
},
.ops = {
.read = ufs_read_lun3_blks,
.write = ufs_write_lun3_blks,
},
.block_size = UFS_BLOCK_SIZE,
};
static const io_uuid_spec_t bl2_uuid_spec = {
.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
};
static const io_uuid_spec_t scp_bl2_uuid_spec = {
.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
};
static const io_uuid_spec_t bl31_uuid_spec = {
.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
};
static const io_uuid_spec_t bl33_uuid_spec = {
.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
};
static const struct plat_io_policy policies[] = {
[FIP_IMAGE_ID] = {
&ufs_dev_handle,
(uintptr_t)&ufs_fip_spec,
check_ufs
},
[BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl2_uuid_spec,
check_fip
},
[SCP_BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&scp_bl2_uuid_spec,
check_fip
},
[BL31_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl31_uuid_spec,
check_fip
},
[BL33_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl33_uuid_spec,
check_fip
},
[BL2U_IMAGE_ID] = {
&ufs_dev_handle,
(uintptr_t)&ufs_data_spec,
check_ufs
}
};
static int check_ufs(const uintptr_t spec)
{
int result;
uintptr_t local_handle;
result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL);
if (result == 0) {
result = io_open(ufs_dev_handle, spec, &local_handle);
if (result == 0)
io_close(local_handle);
}
return result;
}
static int check_fip(const uintptr_t spec)
{
int result;
uintptr_t local_image_handle;
/* See if a Firmware Image Package is available */
result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
if (result == 0) {
result = io_open(fip_dev_handle, spec, &local_image_handle);
if (result == 0) {
VERBOSE("Using FIP\n");
io_close(local_image_handle);
}
}
return result;
}
void hikey960_io_setup(void)
{
int result;
result = register_io_dev_block(&ufs_dev_con);
assert(result == 0);
result = register_io_dev_fip(&fip_dev_con);
assert(result == 0);
result = io_dev_open(ufs_dev_con, (uintptr_t)&ufs_dev_spec,
&ufs_dev_handle);
assert(result == 0);
result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
assert(result == 0);
/* Ignore improbable errors in release builds */
(void)result;
}
/* Return an IO device handle and specification which can be used to access
* an image. Use this to enforce platform load policy
*/
int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
uintptr_t *image_spec)
{
int result;
const struct plat_io_policy *policy;
assert(image_id < ARRAY_SIZE(policies));
policy = &policies[image_id];
result = policy->check(policy->image_spec);
assert(result == 0);
*image_spec = policy->image_spec;
*dev_handle = *(policy->dev_handle);
return result;
}
size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size)
{
return ufs_read_blocks(3, lba, buf, size);
}
size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size)
{
return ufs_write_blocks(3, lba, buf, size);
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <debug.h>
#include <delay_timer.h>
#include <errno.h>
#include <hi3660.h>
#include <mmio.h>
#include <string.h>
#define ADDR_CONVERT(addr) ((addr) < 0x40000 ? \
(addr) + 0xFFF30000 : \
(addr) + 0x40000000)
static void fw_data_init(void)
{
unsigned long data_head_addr;
unsigned int *data_addr;
data_head_addr = mmio_read_32((uintptr_t) HISI_DATA_HEAD_BASE) + 0x14;
data_addr = (unsigned int *) ADDR_CONVERT(data_head_addr);
memcpy((void *)HISI_DATA0_BASE,
(const void *)(unsigned long)ADDR_CONVERT(data_addr[0]),
HISI_DATA0_SIZE);
memcpy((void *)HISI_DATA1_BASE,
(const void *)(unsigned long)ADDR_CONVERT(data_addr[1]),
HISI_DATA1_SIZE);
}
int load_lpm3(void)
{
INFO("start fw loading\n");
fw_data_init();
flush_dcache_range((uintptr_t)HISI_RESERVED_MEM_BASE,
HISI_RESERVED_MEM_SIZE);
sev();
sev();
INFO("fw load success\n");
return 0;
}
/*
* 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;
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __HIKEY960_PRIVATE_H__
#define __HIKEY960_PRIVATE_H__
#include <bl_common.h>
/*
* Function and variable prototypes
*/
void hikey960_init_mmu_el1(unsigned long total_base,
unsigned long total_size,
unsigned long ro_start,
unsigned long ro_limit,
unsigned long coh_start,
unsigned long coh_limit);
void hikey960_init_mmu_el3(unsigned long total_base,
unsigned long total_size,
unsigned long ro_start,
unsigned long ro_limit,
unsigned long coh_start,
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__ */
/*
* 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));
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __HI3660_H__
#define __HI3660_H__
#include <hi3660_crg.h>
#include <hi3660_hkadc.h>
#include <hi3660_mem_map.h>
#define ASP_CFG_REG_BASE 0xE804E000
#define ASP_CFG_MMBUF_CTRL_REG (ASP_CFG_REG_BASE + 0x148)
#define LP_RAM_BASE 0xFFF50000
#define SCTRL_REG_BASE 0xFFF0A000
#define SCTRL_CONTROL_REG (SCTRL_REG_BASE + 0x000)
#define SCTRL_CONTROL_SYS_MODE(x) (((x) & 0xf) << 3)
#define SCTRL_CONTROL_SYS_MODE_NORMAL ((1 << 2) << 3)
#define SCTRL_CONTROL_SYS_MODE_SLOW ((1 << 1) << 3)
#define SCTRL_CONTROL_SYS_MODE_MASK (0xf << 3)
#define SCTRL_CONTROL_MODE_CTRL_NORMAL (1 << 2)
#define SCTRL_CONTROL_MODE_CTRL_SLOW (1 << 1)
#define SCTRL_CONTROL_MODE_CTRL_MASK 0x7
#define SCTRL_SCSYSSTAT_REG (SCTRL_REG_BASE + 0x004)
#define SCTRL_DEEPSLEEPED_REG (SCTRL_REG_BASE + 0x008)
#define SCTRL_EFUSE_USB_MASK (1 << 30)
#define SCTRL_EFUSE_USB_PLL (1 << 30)
#define SCTRL_EFUSE_USB_ABB (0 << 30)
#define SCTRL_EFUSE_UFS_MASK (3 << 6)
#define SCTRL_EFUSE_UFS_PLL (1 << 6)
#define SCTRL_EFUSE_UFS_ABB (0 << 6)
#define SCTRL_SCISOEN_REG (SCTRL_REG_BASE + 0x040)
#define SCTRL_SCISODIS_REG (SCTRL_REG_BASE + 0x044)
#define SCISO_MMBUFISO (1 << 3)
#define SCTRL_SCPWREN_REG (SCTRL_REG_BASE + 0x060)
#define SCPWREN_MMBUFPWREN (1 << 3)
#define SCTRL_PLL_CTRL0_REG (SCTRL_REG_BASE + 0x100)
#define SCTRL_PLL0_POSTDIV2(x) (((x) & 0x7) << 23)
#define SCTRL_PLL0_POSTDIV1(x) (((x) & 0x7) << 20)
#define SCTRL_PLL0_FBDIV(x) (((x) & 0xfff) << 8)
#define SCTRL_PLL0_REFDIV(x) (((x) & 0x3f) << 2)
#define SCTRL_PLL0_EN (1 << 0)
#define SCTRL_PLL_CTRL1_REG (SCTRL_REG_BASE + 0x104)
#define SCTRL_PLL0_CLK_NO_GATE (1 << 26)
#define SCTRL_PLL0_CFG_VLD (1 << 25)
#define SCTRL_PLL0_FRACDIV(x) ((x) & 0xFFFFFF)
#define SCTRL_PLL_STAT_REG (SCTRL_REG_BASE + 0x10C)
#define SCTRL_PLL0_STAT (1 << 0)
#define SCTRL_SCPEREN0_REG (SCTRL_REG_BASE + 0x160)
#define SCTRL_SCPERDIS0_REG (SCTRL_REG_BASE + 0x164)
#define SCTRL_SCPERSTAT0_REG (SCTRL_REG_BASE + 0x168)
#define SCTRL_SCPEREN1_REG (SCTRL_REG_BASE + 0x170)
#define SCTRL_SCPERDIS1_REG (SCTRL_REG_BASE + 0x174)
#define SCTRL_SCPEREN1_REG (SCTRL_REG_BASE + 0x170)
#define SCTRL_SCPERDIS1_REG (SCTRL_REG_BASE + 0x174)
#define SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS (1 << 31)
#define SCPEREN_GT_PCLK_MMBUFCFG (1 << 25)
#define SCPEREN_GT_PCLK_MMBUF (1 << 23)
#define SCPEREN_GT_ACLK_MMBUF (1 << 22)
#define SCPEREN_GT_CLK_NOC_AOBUS2MMBUF (1 << 6)
#define SCTRL_SCPEREN2_REG (SCTRL_REG_BASE + 0x190)
#define SCTRL_SCPERDIS2_REG (SCTRL_REG_BASE + 0x194)
#define SCTRL_SCPERSTAT2_REG (SCTRL_REG_BASE + 0x198)
#define SCTRL_SCPERRSTEN0_REG (SCTRL_REG_BASE + 0x200)
#define SCTRL_SCPERRSTDIS0_REG (SCTRL_REG_BASE + 0x204)
#define SCTRL_SCPERRSTSTAT0_REG (SCTRL_REG_BASE + 0x208)
#define SCTRL_SCPERRSTEN1_REG (SCTRL_REG_BASE + 0x20C)
#define SCTRL_SCPERRSTDIS1_REG (SCTRL_REG_BASE + 0x210)
#define SCTRL_SCPERRSTSTAT1_REG (SCTRL_REG_BASE + 0x214)
#define IP_RST_MMBUFCFG (1 << 12)
#define IP_RST_MMBUF (1 << 11)
#define SCTRL_SCPERRSTEN2_REG (SCTRL_REG_BASE + 0x218)
#define SCTRL_SCPERRSTDIS2_REG (SCTRL_REG_BASE + 0x21C)
#define SCTRL_SCPERRSTSTAT2_REG (SCTRL_REG_BASE + 0x220)
#define SCTRL_SCCLKDIV2_REG (SCTRL_REG_BASE + 0x258)
#define SEL_CLK_MMBUF_MASK (0x3 << 8)
#define SEL_CLK_MMBUF_PLL0 (0x3 << 8)
#define SCCLKDIV2_GT_PCLK_MMBUF (1 << 7)
#define SCTRL_SCCLKDIV4_REG (SCTRL_REG_BASE + 0x260)
#define GT_MMBUF_SYS (1 << 13)
#define GT_MMBUF_FLL (1 << 12)
#define GT_PLL_CLK_MMBUF (1 << 11)
#define SCTRL_SCCLKDIV6_REG (SCTRL_REG_BASE + 0x268)
#define SCTRL_SCPERCTRL7_REG (SCTRL_REG_BASE + 0x31C)
#define SCTRL_SCPERSTAT6_REG (SCTRL_REG_BASE + 0x378)
#define SCTRL_SCINNERSTAT_REG (SCTRL_REG_BASE + 0x3A0)
#define EMMC_UFS_SEL (1 << 15)
#define SCTRL_BAK_DATA0_REG (SCTRL_REG_BASE + 0x40C)
#define SCTRL_BAK_DATA4_REG (SCTRL_REG_BASE + 0x41C)
#define SCTRL_LPMCU_CLKEN_REG (SCTRL_REG_BASE + 0x480)
#define SCTRL_LPMCU_CLKDIS_REG (SCTRL_REG_BASE + 0x484)
#define SCTRL_LPMCU_RSTEN_REG (SCTRL_REG_BASE + 0x500)
#define SCTRL_LPMCU_RSTDIS_REG (SCTRL_REG_BASE + 0x504)
#define DDRC_SOFT_BIT (1 << 6)
#define DDRC_CLK_BIT (1 << 5)
#define SCTRL_SCPEREN0_SEC_REG (SCTRL_REG_BASE + 0x900)
#define SCTRL_SCPERDIS0_SEC_REG (SCTRL_REG_BASE + 0x904)
#define MMBUF_SEC_CTRL_MASK (0xfff << 20)
#define MMBUF_SEC_CTRL(x) (((x) & 0xfff) << 20)
#define SCTRL_PERRSTEN1_SEC_REG (SCTRL_REG_BASE + 0xA50)
#define SCTRL_PERRSTDIS1_SEC_REG (SCTRL_REG_BASE + 0xA54)
#define SCTRL_PERRSTSTAT1_SEC_REG (SCTRL_REG_BASE + 0xA58)
#define RST_ASP_SUBSYS_BIT (1 << 0)
#define SCTRL_PERRSTEN2_SEC_REG (SCTRL_REG_BASE + 0xB50)
#define SCTRL_PERRSTDIS2_SEC_REG (SCTRL_REG_BASE + 0xB54)
#define SCTRL_PERRSTSTAT2_SEC_REG (SCTRL_REG_BASE + 0xB58)
#define SCTRL_HISEECLKDIV_REG (SCTRL_REG_BASE + 0xC28)
#define SC_SEL_HISEE_PLL_MASK (1 << 4)
#define SC_SEL_HISEE_PLL0 (1 << 4)
#define SC_SEL_HISEE_PLL2 (0 << 4)
#define SC_DIV_HISEE_PLL_MASK (7 << 16)
#define SC_DIV_HISEE_PLL(x) ((x) & 0x7)
#define SCTRL_SCSOCID0_REG (SCTRL_REG_BASE + 0xE00)
#define PMC_REG_BASE 0xFFF31000
#define PMC_PPLL1_CTRL0_REG (PMC_REG_BASE + 0x038)
#define PMC_PPLL1_CTRL1_REG (PMC_REG_BASE + 0x03C)
#define PMC_PPLL2_CTRL0_REG (PMC_REG_BASE + 0x040)
#define PMC_PPLL2_CTRL1_REG (PMC_REG_BASE + 0x044)
#define PMC_PPLL3_CTRL0_REG (PMC_REG_BASE + 0x048)
#define PMC_PPLL3_CTRL1_REG (PMC_REG_BASE + 0x04C)
#define PPLLx_LOCK (1 << 26)
#define PPLLx_WITHOUT_CLK_GATE (1 << 26)
#define PPLLx_CFG_VLD (1 << 25)
#define PPLLx_INT_MOD (1 << 24)
#define PPLLx_POSTDIV2_MASK (0x7 << 23)
#define PPLLx_POSTDIV2(x) (((x) & 0x7) << 23)
#define PPLLx_POSTDIV1_MASK (0x7 << 20)
#define PPLLx_POSTDIV1(x) (((x) & 0x7) << 20)
#define PPLLx_FRACDIV_MASK (0x00FFFFFF)
#define PPLLx_FRACDIV(x) ((x) & 0x00FFFFFF)
#define PPLLx_FBDIV_MASK (0xfff << 8)
#define PPLLx_FBDIV(x) (((x) & 0xfff) << 8)
#define PPLLx_REFDIV_MASK (0x3f << 2)
#define PPLLx_REFDIV(x) (((x) & 0x3f) << 2)
#define PPLLx_BP (1 << 1)
#define PPLLx_EN (1 << 0)
#define PMC_DDRLP_CTRL_REG (PMC_REG_BASE + 0x30C)
#define DDRC_CSYSREQ_CFG(x) ((x) & 0xF)
#define PMC_NOC_POWER_IDLEREQ_REG (PMC_REG_BASE + 0x380)
#define PMC_NOC_POWER_IDLEREQ_IVP (1 << 14)
#define PMC_NOC_POWER_IDLEREQ_DSS (1 << 13)
#define PMC_NOC_POWER_IDLEREQ_VENC (1 << 11)
#define PMC_NOC_POWER_IDLEREQ_VDEC (1 << 10)
#define PMC_NOC_POWER_IDLEREQ_ISP (1 << 5)
#define PMC_NOC_POWER_IDLEREQ_VCODEC (1 << 4)
#define DDRPHY_BYPASS_MODE (1 << 0)
#define PMC_NOC_POWER_IDLEACK_REG (PMC_REG_BASE + 0x384)
#define PMC_NOC_POWER_IDLE_REG (PMC_REG_BASE + 0x388)
#define PMU_SSI0_REG_BASE 0xFFF34000
#define PMU_SSI0_LDO8_CTRL0_REG (PMU_SSI0_REG_BASE + (0x68 << 2))
#define LDO8_CTRL0_EN_1_8V 0x02
#define PMU_SSI0_CLK_TOP_CTRL7_REG (PMU_SSI0_REG_BASE + (0x10C << 2))
#define NP_XO_ABB_DIG (1 << 1)
#define LP_CONFIG_REG_BASE 0xFFF3F000
#define DMAC_BASE 0xFDF30000
#define CCI400_REG_BASE 0xE8100000
#define CCI400_SL_IFACE3_CLUSTER_IX 0
#define CCI400_SL_IFACE4_CLUSTER_IX 1
#define GICD_REG_BASE 0xE82B1000
#define GICC_REG_BASE 0xE82B2000
/*
* GIC400 interrupt handling related constants
*/
#define IRQ_SEC_PHY_TIMER 29
#define IRQ_SEC_SGI_0 8
#define IRQ_SEC_SGI_1 9
#define IRQ_SEC_SGI_2 10
#define IRQ_SEC_SGI_3 11
#define IRQ_SEC_SGI_4 12
#define IRQ_SEC_SGI_5 13
#define IRQ_SEC_SGI_6 14
#define IRQ_SEC_SGI_7 15
#define IRQ_SEC_SGI_8 16
#define IPC_REG_BASE 0xE896A000
#define IPC_BASE (IPC_REG_BASE)
#define IOMG_REG_BASE 0xE896C000
/* GPIO46: HUB 3.3V enable. active low */
#define IOMG_044_REG (IOMG_REG_BASE + 0x0B0)
#define IOMG_UART5_RX_REG (IOMG_REG_BASE + 0x0BC)
#define IOMG_UART5_TX_REG (IOMG_REG_BASE + 0x0C0)
#define IOCG_REG_BASE 0xE896C800
/* GPIO005: PMIC SSI. (2 << 4) */
#define IOCG_006_REG (IOCG_REG_BASE + 0x018)
#define TIMER9_REG_BASE 0xE8A00000
#define WDT0_REG_BASE 0xE8A06000
#define WDT1_REG_BASE 0xE8A07000
#define WDT_CONTROL_OFFSET 0x008
#define WDT_LOCK_OFFSET 0xC00
#define WDT_UNLOCK 0x1ACCE551
#define WDT_LOCKED 1
#define PCTRL_REG_BASE 0xE8A09000
#define PCTRL_PERI_CTRL3_REG (PCTRL_REG_BASE + 0x010)
#define PCTRL_PERI_CTRL24_REG (PCTRL_REG_BASE + 0x064)
#define TZC_REG_BASE 0xE8A21000
#define TZC_STAT0_REG (TZC_REG_BASE + 0x800)
#define TZC_EN0_REG (TZC_REG_BASE + 0x804)
#define TZC_DIS0_REG (TZC_REG_BASE + 0x808)
#define TZC_STAT1_REG (TZC_REG_BASE + 0x80C)
#define TZC_EN1_REG (TZC_REG_BASE + 0x810)
#define TZC_DIS1_REG (TZC_REG_BASE + 0x814)
#define TZC_STAT2_REG (TZC_REG_BASE + 0x818)
#define TZC_EN2_REG (TZC_REG_BASE + 0x81C)
#define TZC_DIS2_REG (TZC_REG_BASE + 0x820)
#define TZC_STAT3_REG (TZC_REG_BASE + 0x824)
#define TZC_EN3_REG (TZC_REG_BASE + 0x828)
#define TZC_DIS3_REG (TZC_REG_BASE + 0x82C)
#define TZC_STAT4_REG (TZC_REG_BASE + 0x830)
#define TZC_EN4_REG (TZC_REG_BASE + 0x834)
#define TZC_DIS4_REG (TZC_REG_BASE + 0x838)
#define TZC_STAT5_REG (TZC_REG_BASE + 0x83C)
#define TZC_EN5_REG (TZC_REG_BASE + 0x840)
#define TZC_DIS5_REG (TZC_REG_BASE + 0x844)
#define TZC_STAT6_REG (TZC_REG_BASE + 0x848)
#define TZC_EN6_REG (TZC_REG_BASE + 0x84C)
#define TZC_DIS6_REG (TZC_REG_BASE + 0x850)
#define TZC_STAT7_REG (TZC_REG_BASE + 0x854)
#define TZC_EN7_REG (TZC_REG_BASE + 0x858)
#define TZC_DIS7_REG (TZC_REG_BASE + 0x85C)
#define TZC_STAT8_REG (TZC_REG_BASE + 0x860)
#define TZC_EN8_REG (TZC_REG_BASE + 0x864)
#define TZC_DIS8_REG (TZC_REG_BASE + 0x868)
#define MMBUF_BASE 0xEA800000
#define ACPU_DMCPACK0_BASE 0xEA900000
#define ACPU_DMCPACK1_BASE 0xEA920000
#define ACPU_DMCPACK2_BASE 0xEA940000
#define ACPU_DMCPACK3_BASE 0xEA960000
#define UART5_REG_BASE 0xFDF05000
#define USB3OTG_REG_BASE 0xFF100000
#define UFS_REG_BASE 0xFF3B0000
#define UFS_SYS_REG_BASE 0xFF3B1000
#define UFS_SYS_PSW_POWER_CTRL_REG (UFS_SYS_REG_BASE + 0x004)
#define UFS_SYS_PHY_ISO_EN_REG (UFS_SYS_REG_BASE + 0x008)
#define UFS_SYS_HC_LP_CTRL_REG (UFS_SYS_REG_BASE + 0x00C)
#define UFS_SYS_PHY_CLK_CTRL_REG (UFS_SYS_REG_BASE + 0x010)
#define UFS_SYS_PSW_CLK_CTRL_REG (UFS_SYS_REG_BASE + 0x014)
#define UFS_SYS_CLOCK_GATE_BYPASS_REG (UFS_SYS_REG_BASE + 0x018)
#define UFS_SYS_RESET_CTRL_EN_REG (UFS_SYS_REG_BASE + 0x01C)
#define UFS_SYS_MONITOR_HH_REG (UFS_SYS_REG_BASE + 0x03C)
#define UFS_SYS_UFS_SYSCTRL_REG (UFS_SYS_REG_BASE + 0x05C)
#define UFS_SYS_UFS_DEVICE_RESET_CTRL_REG (UFS_SYS_REG_BASE + 0x060)
#define UFS_SYS_UFS_APB_ADDR_MASK_REG (UFS_SYS_REG_BASE + 0x064)
#define BIT_UFS_PSW_ISO_CTRL (1 << 16)
#define BIT_UFS_PSW_MTCMOS_EN (1 << 0)
#define BIT_UFS_REFCLK_ISO_EN (1 << 16)
#define BIT_UFS_PHY_ISO_CTRL (1 << 0)
#define BIT_SYSCTRL_LP_ISOL_EN (1 << 16)
#define BIT_SYSCTRL_PWR_READY (1 << 8)
#define BIT_SYSCTRL_REF_CLOCK_EN (1 << 24)
#define MASK_SYSCTRL_REF_CLOCK_SEL (3 << 8)
#define MASK_SYSCTRL_CFG_CLOCK_FREQ (0xFF)
#define BIT_SYSCTRL_PSW_CLK_EN (1 << 4)
#define MASK_UFS_CLK_GATE_BYPASS (0x3F)
#define BIT_SYSCTRL_LP_RESET_N (1 << 0)
#define BIT_UFS_REFCLK_SRC_SE1 (1 << 0)
#define MASK_UFS_SYSCTRL_BYPASS (0x3F << 16)
#define MASK_UFS_DEVICE_RESET (1 << 16)
#define BIT_UFS_DEVICE_RESET (1 << 0)
#define IOMG_FIX_REG_BASE 0xFF3B6000
/* GPIO150: LED */
#define IOMG_FIX_006_REG (IOMG_FIX_REG_BASE + 0x018)
/* GPIO151: LED */
#define IOMG_FIX_007_REG (IOMG_FIX_REG_BASE + 0x01C)
#define IOMG_AO_REG_BASE 0xFFF11000
/* GPIO189: LED */
#define IOMG_AO_011_REG (IOMG_AO_REG_BASE + 0x02C)
/* GPIO190: LED */
#define IOMG_AO_012_REG (IOMG_AO_REG_BASE + 0x030)
/* GPIO202: type C enable. active low */
#define IOMG_AO_023_REG (IOMG_AO_REG_BASE + 0x05C)
/* GPIO206: USB switch. active low */
#define IOMG_AO_026_REG (IOMG_AO_REG_BASE + 0x068)
/* GPIO219: PD interrupt. pull up */
#define IOMG_AO_039_REG (IOMG_AO_REG_BASE + 0x09C)
#define IOCG_AO_REG_BASE 0xFFF1187C
/* GPIO219: PD interrupt. pull up */
#define IOCG_AO_043_REG (IOCG_AO_REG_BASE + 0x030)
#endif /* __HI3660_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment