uniphier: support Socionext UniPhier platform

Initial commit for Socionext UniPhier SoC support.  BL1, Bl2, and
BL31 are supported.  Refer to docs/plat/socionext-uniphier.md for
more detais.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
This commit is contained in:
Masahiro Yamada 2016-09-03 11:37:40 +09:00
parent c396b7368a
commit d8e919c7b8
28 changed files with 2866 additions and 0 deletions

View File

@ -7,6 +7,8 @@ Linaro Limited
NVIDIA Corporation
Socionext Inc.
Xilinx, Inc.
Individuals

View File

@ -0,0 +1,123 @@
ARM Trusted Firmware for Socionext UniPhier SoCs
================================================
Socionext UniPhier ARMv8-A SoCs use ARM Trusted Firmware as the secure world
firmware, supporting BL1, BL2, and BL31.
UniPhier SoC family implements its internal boot ROM, so BL1 is used as pseudo
ROM (i.e. runs in RAM). The internal boot ROM loads 64KB [1] image from a
non-volatile storage to the on-chip SRAM. Unfortunately, BL1 does not fit in
the 64KB limit if [Trusted Board Boot] (TBB) is enabled. To solve this problem,
Socionext provides a first stage loader called [UniPhier BL]. This loader runs
in the on-chip SRAM, initializes the DRAM, expands BL1 there, and hands the
control over to it. Therefore, all images of ARM Trusted Firmware run in DRAM.
The UniPhier platform works with/without TBB. See below for the build process
of each case. The image authentication for the UniPhier platform fully
complies with the Trusted Board Boot Requirements (TBBR) specification.
The UniPhier BL does not implement the authentication functionality, that is,
it can not verify the BL1 image by itself. Instead, the UniPhier BL assures
the BL1 validity in a different way; BL1 is GZIP-compressed and appended to
the UniPhier BL. The concatenation of the UniPhier BL and the compressed BL1
fits in the 64KB limit. The concatenated image is loaded by the boot ROM
(and verified if the chip fuses are blown).
[1]: Some SoCs can load 80KB, but the software implementation must be aligned
to the lowest common denominator.
[Trusted Board Boot]: ../trusted-board-boot.md
[UniPhier BL]: https://github.com/uniphier/uniphier-bl
Boot Flow
---------
1. The Boot ROM
This is hard-wired ROM, so never corrupted. It loads the UniPhier BL (with
compressed-BL1 appended) into the on-chip SRAM. If the SoC fuses are blown,
the image is verified by the SoC's own method.
2. UniPhier BL
This runs in the on-chip SRAM. After the minimum SoC initialization and DRAM
setup, it decompresses the appended BL1 image into the DRAM, then jumps to
the BL1 entry.
3. BL1
This runs in the DRAM. It extracts BL2 from FIP (Firmware Image Package).
If TBB is enabled, the BL2 is authenticated by the standard mechanism of ARM
Trusted Firmware.
4. BL2, BL31, and more
They all run in the DRAM, and are authenticated by the standard mechanism if
TBB is enabled. See [Firmware Design] for details.
[Firmware Design]: ../firmware-design.md
Basic Build
-----------
BL1 must be compressed for the reason above. The UniPhier's platform makefile
provides a build target `bl1_gzip` for this.
For a non-secure boot loader (aka BL33), U-Boot is well supported for UniPhier
SoCs. The U-Boot image (`u-boot.bin`) must be built in advance. For the build
procedure of U-Boot, refer to the document in the [U-Boot] project.
[U-Boot]: https://www.denx.de/wiki/U-Boot
To build minimum functionality for UniPhier (without TBB):
```
make CROSS_COMPILE=<gcc-prefix> PLAT=uniphier BL33=<path-to-BL33> bl1_gzip fip
```
Output images:
- `bl1.bin.gzip`
- `fip.bin`
Optional features
-----------------
- Trusted Board Boot
[mbed TLS] is needed as the cryptographic and image parser modules.
Refer to the [User Guide] for the appropriate version of mbed TLS.
To enable TBB, add the following options to the build command:
```
TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR=<path-to-mbedtls>
```
[mbed TLS]: https://tls.mbed.org/
[User Guide]: ../user-guide.md
- System Control Processor (SCP)
If desired, FIP can include an SCP BL2 image. If BL2 finds an SCP BL2 image
in FIP, BL2 loads it into DRAM and kicks the SCP. Most of UniPhier boards
still work without SCP, but SCP provides better power management support.
To include SCP_BL2, add the following option to the build command:
```
SCP_BL2=<path-to-SCP>
```
- BL32 (Secure Payload)
To enable BL32, add the following option to the build command:
```
SPD=<spd> BL32=<path-to-BL32>
```

View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __PLAT_MACROS_S__
#define __PLAT_MACROS_S__
.macro plat_crash_print_regs
.endm
#endif /* __PLAT_MACROS_S__ */

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __PLATFORM_DEF_H__
#define __PLATFORM_DEF_H__
#include <common_def.h>
#include <tbbr/tbbr_img_def.h>
#define PLATFORM_STACK_SIZE 0x1000
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (1 << (CACHE_WRITEBACK_SHIFT))
/* topology */
#define UNIPHIER_MAX_CPUS_PER_CLUSTER 4
#define UNIPHIER_CLUSTER_COUNT 2
#define PLATFORM_CORE_COUNT \
((UNIPHIER_MAX_CPUS_PER_CLUSTER) * (UNIPHIER_CLUSTER_COUNT))
#define PLAT_MAX_PWR_LVL 1
#define PLAT_MAX_OFF_STATE 2
#define PLAT_MAX_RET_STATE 1
#define UNIPHIER_SEC_DRAM_BASE 0x81000000
#define UNIPHIER_SEC_DRAM_LIMIT 0x82000000
#define UNIPHIER_SEC_DRAM_SIZE ((UNIPHIER_SEC_DRAM_LIMIT) - \
(UNIPHIER_SEC_DRAM_BASE))
#define BL1_RO_BASE 0x80000000
#define BL1_RO_LIMIT 0x80018000
#define BL1_RW_LIMIT (UNIPHIER_SEC_DRAM_LIMIT)
#define BL1_RW_BASE ((BL1_RW_LIMIT) - 0x00040000)
#define BL2_LIMIT (BL1_RW_BASE)
#define BL2_BASE ((BL2_LIMIT) - 0x00040000)
#define BL31_BASE (UNIPHIER_SEC_DRAM_BASE)
#define BL31_LIMIT ((BL31_BASE) + 0x00080000)
#define BL32_BASE (BL31_LIMIT)
#define BL32_LIMIT (UNIPHIER_SEC_DRAM_LIMIT)
#define UNIPHIER_BLOCK_BUF_SIZE 0x00400000
#define UNIPHIER_BLOCK_BUF_BASE ((BL2_LIMIT) - \
(UNIPHIER_BLOCK_BUF_SIZE))
#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
#define PLAT_XLAT_TABLES_DYNAMIC 1
#define MAX_XLAT_TABLES 7
#define MAX_MMAP_REGIONS 6
#define MAX_IO_HANDLES 2
#define MAX_IO_DEVICES 2
#define MAX_IO_BLOCK_DEVICES 1
#endif /* __PLATFORM_DEF_H__ */

View File

@ -0,0 +1,100 @@
#
# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
override COLD_BOOT_SINGLE_CPU := 1
override ENABLE_PLAT_COMPAT := 0
override ERROR_DEPRECATED := 1
override LOAD_IMAGE_V2 := 1
override USE_COHERENT_MEM := 1
override USE_TBBR_DEFS := 1
# Cortex-A53 revision r0p4-51rel0
# needed for LD20, unneeded for LD11, PXs3 (no ACE)
ERRATA_A53_855873 := 1
FIP_ALIGN := 512
ifeq ($(NEED_BL32),yes)
$(eval $(call add_define,UNIPHIER_LOAD_BL32))
endif
PLAT_PATH := plat/socionext/uniphier
PLAT_INCLUDES := -I$(PLAT_PATH)/include
# IO sources for BL1, BL2
IO_SOURCES := drivers/io/io_block.c \
drivers/io/io_fip.c \
drivers/io/io_memmap.c \
drivers/io/io_storage.c \
$(PLAT_PATH)/uniphier_boot_device.c \
$(PLAT_PATH)/uniphier_emmc.c \
$(PLAT_PATH)/uniphier_io_storage.c \
$(PLAT_PATH)/uniphier_nand.c \
$(PLAT_PATH)/uniphier_usb.c
# common sources for BL1, BL2, BL31
PLAT_BL_COMMON_SOURCES += drivers/console/aarch64/console.S \
lib/xlat_tables_v2/aarch64/xlat_tables_arch.c \
lib/xlat_tables_v2/xlat_tables_common.c \
lib/xlat_tables_v2/xlat_tables_internal.c \
$(PLAT_PATH)/uniphier_console.S \
$(PLAT_PATH)/uniphier_helpers.S \
$(PLAT_PATH)/uniphier_soc_info.c \
$(PLAT_PATH)/uniphier_xlat_setup.c
BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a72.S \
$(PLAT_PATH)/uniphier_bl1_helpers.S \
$(PLAT_PATH)/uniphier_bl1_setup.c \
$(IO_SOURCES)
BL2_SOURCES += common/desc_image_load.c \
$(PLAT_PATH)/uniphier_bl2_setup.c \
$(PLAT_PATH)/uniphier_image_desc.c \
$(PLAT_PATH)/uniphier_scp.c \
$(IO_SOURCES)
BL31_SOURCES += drivers/arm/cci/cci.c \
drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v3/gicv3_helpers.c \
drivers/arm/gic/v3/gicv3_main.c \
lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a72.S \
plat/common/plat_gicv3.c \
plat/common/plat_psci_common.c \
$(PLAT_PATH)/uniphier_bl31_setup.c \
$(PLAT_PATH)/uniphier_cci.c \
$(PLAT_PATH)/uniphier_gicv3.c \
$(PLAT_PATH)/uniphier_psci.c \
$(PLAT_PATH)/uniphier_scp.c \
$(PLAT_PATH)/uniphier_smp.S \
$(PLAT_PATH)/uniphier_syscnt.c \
$(PLAT_PATH)/uniphier_topology.c
ifeq (${TRUSTED_BOARD_BOOT},1)
include drivers/auth/mbedtls/mbedtls_crypto.mk
include drivers/auth/mbedtls/mbedtls_x509.mk
PLAT_INCLUDES += -Iinclude/common/tbbr
TBB_SOURCES := drivers/auth/auth_mod.c \
drivers/auth/crypto_mod.c \
drivers/auth/img_parser_mod.c \
drivers/auth/tbbr/tbbr_cot.c \
plat/common/tbbr/plat_tbbr.c \
$(PLAT_PATH)/uniphier_tbbr.c
BL1_SOURCES += $(TBB_SOURCES)
BL2_SOURCES += $(TBB_SOURCES)
endif
.PHONY: bl1_gzip
bl1_gzip: $(BUILD_PLAT)/bl1.bin.gzip
%.gzip: %
@echo " GZIP $@"
$(Q)(cat $< | gzip -n -f -9 > $@) || (rm -f $@ || false)

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __UNIPHIER_H__
#define __UNIPHIER_H__
#include <stdint.h>
#include <types.h>
unsigned int uniphier_get_soc_type(void);
unsigned int uniphier_get_soc_model(void);
unsigned int uniphier_get_soc_revision(void);
unsigned int uniphier_get_soc_id(void);
#define UNIPHIER_SOC_LD11 0
#define UNIPHIER_SOC_LD20 1
#define UNIPHIER_SOC_PXS3 2
#define UNIPHIER_SOC_UNKNOWN 0xffffffff
unsigned int uniphier_get_boot_device(unsigned int soc);
#define UNIPHIER_BOOT_DEVICE_EMMC 0
#define UNIPHIER_BOOT_DEVICE_NAND 1
#define UNIPHIER_BOOT_DEVICE_NOR 2
#define UNIPHIER_BOOT_DEVICE_USB 3
#define UNIPHIER_BOOT_DEVICE_RSV 0xffffffff
unsigned int uniphier_get_boot_master(unsigned int soc);
#define UNIPHIER_BOOT_MASTER_THIS 0
#define UNIPHIER_BOOT_MASTER_SCP 1
#define UNIPHIER_BOOT_MASTER_EXT 2
void uniphier_console_setup(void);
int uniphier_emmc_init(uintptr_t *block_dev_spec);
int uniphier_nand_init(uintptr_t *block_dev_spec);
int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec);
int uniphier_io_setup(unsigned int soc);
int uniphier_check_image(unsigned int image_id);
void uniphier_image_descs_fixup(void);
int uniphier_scp_is_running(void);
void uniphier_scp_start(void);
void uniphier_scp_open_com(void);
void uniphier_scp_system_off(void);
void uniphier_scp_system_reset(void);
struct mmap_region;
void uniphier_mmap_setup(uintptr_t total_base, size_t total_size,
const struct mmap_region *mmap);
void uniphier_cci_init(unsigned int soc);
void uniphier_cci_enable(void);
void uniphier_cci_disable(void);
void uniphier_gic_driver_init(unsigned int soc);
void uniphier_gic_init(void);
void uniphier_gic_cpuif_enable(void);
void uniphier_gic_cpuif_disable(void);
void uniphier_gic_pcpu_init(void);
unsigned int uniphier_calc_core_pos(u_register_t mpidr);
#define UNIPHIER_NS_DRAM_BASE 0x84000000
#define UNIPHIER_NS_DRAM_SIZE 0x01000000
#define UNIPHIER_BL33_BASE (UNIPHIER_NS_DRAM_BASE)
#define UNIPHIER_BL33_MAX_SIZE 0x00100000
#define UNIPHIER_SCP_BASE ((UNIPHIER_BL33_BASE) + \
(UNIPHIER_BL33_MAX_SIZE))
#define UNIPHIER_SCP_MAX_SIZE 0x00020000
#endif /* __UNIPHIER_H__ */

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
.globl plat_get_my_entrypoint
func plat_get_my_entrypoint
mov x0, #0
ret
endfunc plat_get_my_entrypoint

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <bl_common.h>
#include <console.h>
#include <debug.h>
#include <errno.h>
#include <platform.h>
#include <platform_def.h>
#include <xlat_mmu_helpers.h>
#include "uniphier.h"
void bl1_early_platform_setup(void)
{
uniphier_console_setup();
}
void bl1_plat_arch_setup(void)
{
uniphier_mmap_setup(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
NULL);
enable_mmu_el3(0);
}
void bl1_platform_setup(void)
{
unsigned int soc;
int ret;
soc = uniphier_get_soc_id();
if (soc == UNIPHIER_SOC_UNKNOWN) {
ERROR("unsupported SoC\n");
plat_error_handler(-ENOTSUP);
}
ret = uniphier_io_setup(soc);
if (ret) {
ERROR("failed to setup io devices\n");
plat_error_handler(ret);
}
}
static meminfo_t uniphier_tzram_layout = {
.total_base = UNIPHIER_SEC_DRAM_BASE,
.total_size = UNIPHIER_SEC_DRAM_SIZE,
};
meminfo_t *bl1_plat_sec_mem_layout(void)
{
return &uniphier_tzram_layout;
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <bl_common.h>
#include <debug.h>
#include <desc_image_load.h>
#include <errno.h>
#include <io/io_storage.h>
#include <platform.h>
#include <platform_def.h>
#include <xlat_tables_v2.h>
#include "uniphier.h"
static meminfo_t uniphier_bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
static int uniphier_bl2_kick_scp;
void bl2_early_platform_setup(meminfo_t *mem_layout)
{
uniphier_bl2_tzram_layout = *mem_layout;
uniphier_console_setup();
}
static const struct mmap_region uniphier_bl2_mmap[] = {
/* for SCP, BL33 */
MAP_REGION_FLAT(UNIPHIER_NS_DRAM_BASE, UNIPHIER_NS_DRAM_SIZE,
MT_MEMORY | MT_RW | MT_NS),
{ .size = 0 },
};
void bl2_plat_arch_setup(void)
{
unsigned int soc;
int skip_scp = 0;
int ret;
uniphier_mmap_setup(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
uniphier_bl2_mmap);
enable_mmu_el1(0);
soc = uniphier_get_soc_id();
if (soc == UNIPHIER_SOC_UNKNOWN) {
ERROR("unsupported SoC\n");
plat_error_handler(-ENOTSUP);
}
ret = uniphier_io_setup(soc);
if (ret) {
ERROR("failed to setup io devices\n");
plat_error_handler(ret);
}
switch (uniphier_get_boot_master(soc)) {
case UNIPHIER_BOOT_MASTER_THIS:
INFO("Booting from this SoC\n");
skip_scp = 1;
break;
case UNIPHIER_BOOT_MASTER_SCP:
INFO("Booting from on-chip SCP\n");
if (uniphier_scp_is_running()) {
INFO("SCP is already running. SCP_BL2 load will be skipped.\n");
skip_scp = 1;
}
/*
* SCP must be kicked every time even if it is already running
* because it polls this event after the reboot of the backend.
*/
uniphier_bl2_kick_scp = 1;
break;
case UNIPHIER_BOOT_MASTER_EXT:
INFO("Booting from external SCP\n");
skip_scp = 1;
break;
default:
plat_error_handler(-ENOTSUP);
}
if (!skip_scp) {
ret = uniphier_check_image(SCP_BL2_IMAGE_ID);
if (ret) {
WARN("SCP_BL2 image not found. SCP_BL2 load will be skipped.\n");
WARN("You must setup SCP by other means.\n");
skip_scp = 1;
uniphier_bl2_kick_scp = 0;
}
}
if (skip_scp)
uniphier_image_descs_fixup();
}
void bl2_platform_setup(void)
{
}
void plat_flush_next_bl_params(void)
{
flush_bl_params_desc();
}
bl_load_info_t *plat_get_bl_image_load_info(void)
{
return get_bl_load_info_from_mem_params_desc();
}
bl_params_t *plat_get_next_bl_params(void)
{
return get_next_bl_params_from_mem_params_desc();
}
int bl2_plat_handle_post_image_load(unsigned int image_id)
{
if (image_id == SCP_BL2_IMAGE_ID && uniphier_bl2_kick_scp)
uniphier_scp_start();
return 0;
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <debug.h>
#include <errno.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <xlat_mmu_helpers.h>
#include "uniphier.h"
#define BL31_END (unsigned long)(&__BL31_END__)
#define BL31_SIZE ((BL31_END) - (BL31_BASE))
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
assert(sec_state_is_valid(type));
return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info;
}
void bl31_early_platform_setup(void *from_bl2, void *plat_params_from_bl2)
{
bl_params_node_t *bl_params = ((bl_params_t *)from_bl2)->head;
uniphier_console_setup();
while (bl_params) {
if (bl_params->image_id == BL32_IMAGE_ID)
bl32_image_ep_info = *bl_params->ep_info;
if (bl_params->image_id == BL33_IMAGE_ID)
bl33_image_ep_info = *bl_params->ep_info;
bl_params = bl_params->next_params_info;
}
if (bl33_image_ep_info.pc == 0)
panic();
}
#define UNIPHIER_SYS_CNTCTL_BASE 0x60E00000
void bl31_platform_setup(void)
{
unsigned int soc;
soc = uniphier_get_soc_id();
if (soc == UNIPHIER_SOC_UNKNOWN) {
ERROR("unsupported SoC\n");
plat_error_handler(-ENOTSUP);
}
uniphier_cci_init(soc);
uniphier_cci_enable();
/* Initialize the GIC driver, cpu and distributor interfaces */
uniphier_gic_driver_init(soc);
uniphier_gic_init();
/* Enable and initialize the System level generic timer */
mmio_write_32(UNIPHIER_SYS_CNTCTL_BASE + CNTCR_OFF,
CNTCR_FCREQ(0) | CNTCR_EN);
}
void bl31_plat_arch_setup(void)
{
uniphier_mmap_setup(BL31_BASE, BL31_SIZE, NULL);
enable_mmu_el3(0);
}
void bl31_plat_runtime_setup(void)
{
/* Suppress any runtime logs unless DEBUG is defined */
#if !DEBUG
console_uninit();
#endif
}

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <mmio.h>
#include <stdbool.h>
#include <stddef.h>
#include <utils_def.h>
#include "uniphier.h"
#define UNIPHIER_PINMON0 0x5f900100
#define UNIPHIER_PINMON2 0x5f900108
static int uniphier_ld11_is_usb_boot(uint32_t pinmon)
{
return !!(~pinmon & 0x00000080);
}
static int uniphier_ld20_is_usb_boot(uint32_t pinmon)
{
return !!(~pinmon & 0x00000780);
}
static int uniphier_pxs3_is_usb_boot(uint32_t pinmon)
{
uint32_t pinmon2 = mmio_read_32(UNIPHIER_PINMON2);
return !!(pinmon2 & BIT(31));
}
static const unsigned int uniphier_ld11_boot_device_table[] = {
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_NOR,
};
static unsigned int uniphier_ld11_get_boot_device(uint32_t pinmon)
{
unsigned int boot_sel = (pinmon >> 1) & 0x1f;
assert(boot_sel < ARRAY_SIZE(uniphier_ld11_boot_device_table));
return uniphier_ld11_boot_device_table[boot_sel];
}
static const unsigned int uniphier_pxs3_boot_device_table[] = {
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_EMMC,
UNIPHIER_BOOT_DEVICE_NAND,
UNIPHIER_BOOT_DEVICE_NAND,
};
static unsigned int uniphier_pxs3_get_boot_device(uint32_t pinmon)
{
unsigned int boot_sel = (pinmon >> 1) & 0xf;
assert(boot_sel < ARRAY_SIZE(uniphier_pxs3_boot_device_table));
return uniphier_pxs3_boot_device_table[boot_sel];
}
struct uniphier_boot_device_info {
int (*is_usb_boot)(uint32_t pinmon);
unsigned int (*get_boot_device)(uint32_t pinmon);
};
static const struct uniphier_boot_device_info uniphier_boot_device_info[] = {
[UNIPHIER_SOC_LD11] = {
.is_usb_boot = uniphier_ld11_is_usb_boot,
.get_boot_device = uniphier_ld11_get_boot_device,
},
[UNIPHIER_SOC_LD20] = {
.is_usb_boot = uniphier_ld20_is_usb_boot,
.get_boot_device = uniphier_ld11_get_boot_device,
},
[UNIPHIER_SOC_PXS3] = {
.is_usb_boot = uniphier_pxs3_is_usb_boot,
.get_boot_device = uniphier_pxs3_get_boot_device,
},
};
unsigned int uniphier_get_boot_device(unsigned int soc)
{
const struct uniphier_boot_device_info *info;
uint32_t pinmon;
assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
info = &uniphier_boot_device_info[soc];
pinmon = mmio_read_32(UNIPHIER_PINMON0);
if (!(pinmon & BIT(29)))
return UNIPHIER_BOOT_DEVICE_NOR;
if (info->is_usb_boot(pinmon))
return UNIPHIER_BOOT_DEVICE_USB;
return info->get_boot_device(pinmon);
}
static const bool uniphier_have_onchip_scp[] = {
[UNIPHIER_SOC_LD11] = true,
[UNIPHIER_SOC_LD20] = true,
[UNIPHIER_SOC_PXS3] = false,
};
unsigned int uniphier_get_boot_master(unsigned int soc)
{
assert(soc < ARRAY_SIZE(uniphier_have_onchip_scp));
if (uniphier_have_onchip_scp[soc]) {
if (mmio_read_32(UNIPHIER_PINMON0) & BIT(27))
return UNIPHIER_BOOT_MASTER_THIS;
else
return UNIPHIER_BOOT_MASTER_SCP;
} else {
return UNIPHIER_BOOT_MASTER_EXT;
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <cci.h>
#include <stddef.h>
#include <utils_def.h>
#include "uniphier.h"
#define UNIPHIER_CCI500_BASE 0x5FD00000
static const int uniphier_cci_map[] = {0, 1};
static void __uniphier_cci_init(void)
{
cci_init(UNIPHIER_CCI500_BASE, uniphier_cci_map,
ARRAY_SIZE(uniphier_cci_map));
}
static void __uniphier_cci_enable(void)
{
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
}
static void __uniphier_cci_disable(void)
{
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
}
struct uniphier_cci_ops {
void (*init)(void);
void (*enable)(void);
void (*disable)(void);
};
static const struct uniphier_cci_ops uniphier_cci_ops_table[] = {
[UNIPHIER_SOC_LD11] = {
.init = NULL,
.enable = NULL,
.disable = NULL,
},
[UNIPHIER_SOC_LD20] = {
.init = __uniphier_cci_init,
.enable = __uniphier_cci_enable,
.disable = __uniphier_cci_disable,
},
[UNIPHIER_SOC_PXS3] = {
.init = NULL,
.enable = NULL,
.disable = NULL,
},
};
static struct uniphier_cci_ops uniphier_cci_ops;
void uniphier_cci_init(unsigned int soc)
{
uniphier_cci_ops = uniphier_cci_ops_table[soc];
flush_dcache_range((uint64_t)&uniphier_cci_ops,
sizeof(uniphier_cci_ops));
if (uniphier_cci_ops.init)
uniphier_cci_ops.init();
}
void uniphier_cci_enable(void)
{
if (uniphier_cci_ops.enable)
uniphier_cci_ops.enable();
}
void uniphier_cci_disable(void)
{
if (uniphier_cci_ops.disable)
uniphier_cci_ops.disable();
}

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#define UNIPHIER_UART_BASE 0x54006800
#define UNIPHIER_UART_END 0x54006c00
#define UNIPHIER_UART_OFFSET 0x100
#define UNIPHIER_UART_RX 0x00 /* In: Receive buffer */
#define UNIPHIER_UART_TX 0x00 /* Out: Transmit buffer */
#define UNIPHIER_UART_FCR 0x0c /* Char/FIFO Control Register */
#define UNIPHIER_UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UNIPHIER_UART_LCR_MCR 0x10 /* Line/Modem Control Register */
#define UNIPHIER_UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
#define UNIPHIER_UART_LSR 0x14 /* Line Status Register */
#define UNIPHIER_UART_LSR_TEMT_BIT 6 /* Transmitter empty */
#define UNIPHIER_UART_LSR_THRE_BIT 5 /* Transmit-hold-register empty */
#define UNIPHIER_UART_LSR_DR_BIT 0 /* Receiver data ready */
#define UNIPHIER_UART_DLR 0x24 /* Divisor Latch Register */
/*
* Uncomment for debug
*/
/* #define UNIPHIER_UART_INIT_DIVISOR */
#define UNIPHIER_UART_DEFAULT_BASE (UNIPHIER_UART_BASE)
#define UNIPHIER_UART_CLK_RATE 58820000
#define UNIPHIER_UART_DEFAULT_BAUDRATE 115200
/*
* In: x0 - console base address
* w1 - uart clock in Hz
* w2 - baud rate
* Out: return 1 on success, or 0 on error
*/
.globl console_core_init
func console_core_init
cbz x0, 1f
#ifdef UNIPHIER_UART_INIT_DIVISOR
cbz w1, 1f
cbz w2, 1f
/* divisor = uart_clock / (16 * baud_rate) */
udiv w2, w1, w2
lsr w2, w2, #4
#endif
/* Make sure the transmitter is empty before the divisor set/change */
0: ldr w1, [x0, #UNIPHIER_UART_LSR]
tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
#ifdef UNIPHIER_UART_INIT_DIVISOR
str w2, [x0, #UNIPHIER_UART_DLR]
#endif
mov w2, #UNIPHIER_UART_FCR_ENABLE_FIFO
str w2, [x0, #UNIPHIER_UART_FCR]
mov w2, #(UNIPHIER_UART_LCR_WLEN8 << 8)
str w2, [x0, #UNIPHIER_UART_LCR_MCR]
mov w0, #1
ret
1: mov w0, #0
ret
endfunc console_core_init
/*
* In: w0 - character to be printed
* x1 - console base address
* Out: return the character written, or -1 on error
* Clobber: x2
*/
.globl console_core_putc
func console_core_putc
/* Error out if the console is not initialized */
cbz x1, 2f
/* Wait until the transmitter FIFO gets empty */
0: ldr w2, [x1, #UNIPHIER_UART_LSR]
tbz w2, #UNIPHIER_UART_LSR_THRE_BIT, 0b
mov w2, w0
1: str w2, [x1, #UNIPHIER_UART_TX]
cmp w2, #'\n'
b.ne 3f
mov w2, #'\r' /* Append '\r' to '\n' */
b 1b
2: mov w0, #-1
3: ret
endfunc console_core_putc
/*
* In: x0 - console base address
* Out: return the character read
* Clobber: x1
*/
.globl console_core_getc
func console_core_getc
/* Error out if the console is not initialized */
cbz x0, 1f
/* Wait while the receiver FIFO is empty */
0: ldr w1, [x0, #UNIPHIER_UART_LSR]
tbz w1, #UNIPHIER_UART_LSR_DR_BIT, 0b
ldr w0, [x0, #UNIPHIER_UART_RX]
ret
1: mov w0, #-1
ret
endfunc console_core_getc
/*
* In: x0 - console base address
* Out: return 0, or -1 on error
* Clobber: x1
*/
.global console_core_flush
func console_core_flush
/* Error out if the console is not initialized */
cbz x0, 1f
/* wait until the transmitter gets empty */
0: ldr w1, [x0, #UNIPHIER_UART_LSR]
tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
mov w0, #0
ret
1: mov w0, #-1
ret
endfunc console_core_flush
/* find initialized UART port */
.macro uniphier_console_get_base base, tmpx, tmpw
ldr \base, =UNIPHIER_UART_BASE
0000: ldr \tmpw, [\base, #UNIPHIER_UART_DLR]
mvn \tmpw, \tmpw
uxth \tmpw, \tmpw
cbnz \tmpw, 0001f
add \base, \base, #UNIPHIER_UART_OFFSET
ldr \tmpx, =UNIPHIER_UART_END
cmp \base, \tmpx
b.lo 0000b
mov \base, #0
0001:
.endm
/*
* int plat_crash_console_init(void)
* Clobber: x0-x2
*/
.globl plat_crash_console_init
func plat_crash_console_init
#ifdef UNIPHIER_UART_INIT_DIVISOR
ldr x0, =UNIPHIER_UART_DEFAULT_BASE
ldr x1, =UNIPHIER_UART_CLK_RATE
ldr x2, =UNIPHIER_UART_DEFAULT_BAUDRATE
b console_core_init
#else
ret
#endif
endfunc plat_crash_console_init
/*
* int plat_crash_console_putc(int c)
* Clobber: x1, x2
*/
.globl plat_crash_console_putc
func plat_crash_console_putc
#ifdef UNIPHIER_UART_INIT_DIVISOR
ldr x1, =UNIPHIER_UART_DEFAULT_BASE
#else
uniphier_console_get_base x1, x2, w2
#endif
b console_core_putc
endfunc plat_crash_console_putc
/*
* int plat_crash_console_flush(void)
* Clobber: x0, x1
*/
.global plat_crash_console_flush
func plat_crash_console_flush
#ifdef UNIPHIER_UART_INIT_DIVISOR
ldr x0, =UNIPHIER_UART_DEFAULT_BASE
#else
uniphier_console_get_base x0, x1, w1
#endif
b console_core_flush
endfunc plat_crash_console_flush
/*
* void uniphier_console_setup(void)
* Clobber: x0-x2
*/
.globl uniphier_console_setup
func uniphier_console_setup
#ifdef UNIPHIER_UART_INIT_DIVISOR
ldr x0, =UNIPHIER_UART_DEFAULT_BASE
ldr w1, =UNIPHIER_UART_CLK_RATE
ldr w2, =UNIPHIER_UART_DEFAULT_BAUDRATE
#else
uniphier_console_get_base x0, x1, w1
mov w1, #0
mov w2, #0
#endif
b console_init
endfunc uniphier_console_setup

View File

@ -0,0 +1,290 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <io/io_block.h>
#include <mmio.h>
#include <platform_def.h>
#include <sys/types.h>
#include <utils_def.h>
#include "uniphier.h"
#define MMC_CMD_SWITCH 6
#define MMC_CMD_SELECT_CARD 7
#define MMC_CMD_SEND_CSD 9
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
#define EXT_CSD_PART_CONF 179 /* R/W */
#define MMC_RSP_PRESENT BIT(0)
#define MMC_RSP_136 BIT(1) /* 136 bit response */
#define MMC_RSP_CRC BIT(2) /* expect valid crc */
#define MMC_RSP_BUSY BIT(3) /* card may send busy */
#define MMC_RSP_OPCODE BIT(4) /* response contains opcode */
#define MMC_RSP_NONE (0)
#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
#define MMC_RSP_R1b (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | \
MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
#define MMC_RSP_R4 (MMC_RSP_PRESENT)
#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
#define SDHCI_DMA_ADDRESS 0x00
#define SDHCI_BLOCK_SIZE 0x04
#define SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
#define SDHCI_BLOCK_COUNT 0x06
#define SDHCI_ARGUMENT 0x08
#define SDHCI_TRANSFER_MODE 0x0C
#define SDHCI_TRNS_DMA BIT(0)
#define SDHCI_TRNS_BLK_CNT_EN BIT(1)
#define SDHCI_TRNS_ACMD12 BIT(2)
#define SDHCI_TRNS_READ BIT(4)
#define SDHCI_TRNS_MULTI BIT(5)
#define SDHCI_COMMAND 0x0E
#define SDHCI_CMD_RESP_MASK 0x03
#define SDHCI_CMD_CRC 0x08
#define SDHCI_CMD_INDEX 0x10
#define SDHCI_CMD_DATA 0x20
#define SDHCI_CMD_ABORTCMD 0xC0
#define SDHCI_CMD_RESP_NONE 0x00
#define SDHCI_CMD_RESP_LONG 0x01
#define SDHCI_CMD_RESP_SHORT 0x02
#define SDHCI_CMD_RESP_SHORT_BUSY 0x03
#define SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff))
#define SDHCI_RESPONSE 0x10
#define SDHCI_HOST_CONTROL 0x28
#define SDHCI_CTRL_DMA_MASK 0x18
#define SDHCI_CTRL_SDMA 0x00
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
#define SDHCI_SOFTWARE_RESET 0x2F
#define SDHCI_RESET_CMD 0x02
#define SDHCI_RESET_DATA 0x04
#define SDHCI_INT_STATUS 0x30
#define SDHCI_INT_RESPONSE BIT(0)
#define SDHCI_INT_DATA_END BIT(1)
#define SDHCI_INT_DMA_END BIT(3)
#define SDHCI_INT_ERROR BIT(15)
#define SDHCI_SIGNAL_ENABLE 0x38
/* RCA assigned by Boot ROM */
#define UNIPHIER_EMMC_RCA 0x1000
struct uniphier_mmc_cmd {
unsigned int cmdidx;
unsigned int resp_type;
unsigned int cmdarg;
unsigned int is_data;
};
static int uniphier_emmc_block_addressing;
static int uniphier_emmc_send_cmd(uintptr_t host_base,
struct uniphier_mmc_cmd *cmd)
{
uint32_t mode = 0;
uint32_t end_bit;
uint32_t stat, flags, dma_addr;
mmio_write_32(host_base + SDHCI_INT_STATUS, -1);
mmio_write_32(host_base + SDHCI_SIGNAL_ENABLE, 0);
mmio_write_32(host_base + SDHCI_ARGUMENT, cmd->cmdarg);
if (cmd->is_data)
mode = SDHCI_TRNS_DMA | SDHCI_TRNS_BLK_CNT_EN |
SDHCI_TRNS_ACMD12 | SDHCI_TRNS_READ |
SDHCI_TRNS_MULTI;
mmio_write_16(host_base + SDHCI_TRANSFER_MODE, mode);
if (!(cmd->resp_type & MMC_RSP_PRESENT))
flags = SDHCI_CMD_RESP_NONE;
else if (cmd->resp_type & MMC_RSP_136)
flags = SDHCI_CMD_RESP_LONG;
else if (cmd->resp_type & MMC_RSP_BUSY)
flags = SDHCI_CMD_RESP_SHORT_BUSY;
else
flags = SDHCI_CMD_RESP_SHORT;
if (cmd->resp_type & MMC_RSP_CRC)
flags |= SDHCI_CMD_CRC;
if (cmd->resp_type & MMC_RSP_OPCODE)
flags |= SDHCI_CMD_INDEX;
if (cmd->is_data)
flags |= SDHCI_CMD_DATA;
if (cmd->resp_type & MMC_RSP_BUSY || cmd->is_data)
end_bit = SDHCI_INT_DATA_END;
else
end_bit = SDHCI_INT_RESPONSE;
mmio_write_16(host_base + SDHCI_COMMAND,
SDHCI_MAKE_CMD(cmd->cmdidx, flags));
do {
stat = mmio_read_32(host_base + SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR)
return -EIO;
if (stat & SDHCI_INT_DMA_END) {
mmio_write_32(host_base + SDHCI_INT_STATUS, stat);
dma_addr = mmio_read_32(host_base + SDHCI_DMA_ADDRESS);
mmio_write_32(host_base + SDHCI_DMA_ADDRESS, dma_addr);
}
} while (!(stat & end_bit));
return 0;
}
static int uniphier_emmc_switch_part(uintptr_t host_base, int part_num)
{
struct uniphier_mmc_cmd cmd = {0};
cmd.cmdidx = MMC_CMD_SWITCH;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = (EXT_CSD_PART_CONF << 16) | (part_num << 8) | (3 << 24);
return uniphier_emmc_send_cmd(host_base, &cmd);
}
static int uniphier_emmc_is_over_2gb(uintptr_t host_base)
{
struct uniphier_mmc_cmd cmd = {0};
uint32_t csd40, csd72; /* CSD[71:40], CSD[103:72] */
int ret;
cmd.cmdidx = MMC_CMD_SEND_CSD;
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = UNIPHIER_EMMC_RCA << 16;
ret = uniphier_emmc_send_cmd(host_base, &cmd);
if (ret)
return ret;
csd40 = mmio_read_32(host_base + SDHCI_RESPONSE + 4);
csd72 = mmio_read_32(host_base + SDHCI_RESPONSE + 8);
return !(~csd40 & 0xffc00380) && !(~csd72 & 0x3);
}
static int uniphier_emmc_load_image(uintptr_t host_base,
uint32_t dev_addr,
unsigned long load_addr,
uint32_t block_cnt)
{
struct uniphier_mmc_cmd cmd = {0};
uint8_t tmp;
assert((load_addr >> 32) == 0);
mmio_write_32(host_base + SDHCI_DMA_ADDRESS, load_addr);
mmio_write_16(host_base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 512));
mmio_write_16(host_base + SDHCI_BLOCK_COUNT, block_cnt);
tmp = mmio_read_8(host_base + SDHCI_HOST_CONTROL);
tmp &= ~SDHCI_CTRL_DMA_MASK;
tmp |= SDHCI_CTRL_SDMA;
mmio_write_8(host_base + SDHCI_HOST_CONTROL, tmp);
tmp = mmio_read_8(host_base + SDHCI_BLOCK_GAP_CONTROL);
tmp &= ~1; /* clear Stop At Block Gap Request */
mmio_write_8(host_base + SDHCI_BLOCK_GAP_CONTROL, tmp);
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = dev_addr;
cmd.is_data = 1;
return uniphier_emmc_send_cmd(host_base, &cmd);
}
static size_t uniphier_emmc_read(int lba, uintptr_t buf, size_t size)
{
uintptr_t host_base = 0x5a000200;
int ret;
inv_dcache_range(buf, size);
if (!uniphier_emmc_block_addressing)
lba *= 512;
ret = uniphier_emmc_load_image(host_base, lba, buf, size / 512);
inv_dcache_range(buf, size);
return ret ? 0 : size;
}
static const struct io_block_dev_spec uniphier_emmc_dev_spec = {
.buffer = {
.offset = UNIPHIER_BLOCK_BUF_BASE,
.length = UNIPHIER_BLOCK_BUF_SIZE,
},
.ops = {
.read = uniphier_emmc_read,
},
.block_size = 512,
};
static int uniphier_emmc_hw_init(void)
{
uintptr_t host_base = 0x5a000200;
struct uniphier_mmc_cmd cmd = {0};
int ret;
/*
* deselect card before SEND_CSD command.
* Do not check the return code. It fails, but it is OK.
*/
cmd.cmdidx = MMC_CMD_SELECT_CARD;
cmd.resp_type = MMC_RSP_R1;
uniphier_emmc_send_cmd(host_base, &cmd); /* CMD7 (arg=0) */
/* reset CMD Line */
mmio_write_8(host_base + SDHCI_SOFTWARE_RESET,
SDHCI_RESET_CMD | SDHCI_RESET_DATA);
while (mmio_read_8(host_base + SDHCI_SOFTWARE_RESET))
;
ret = uniphier_emmc_is_over_2gb(host_base);
if (ret < 0)
return ret;
uniphier_emmc_block_addressing = ret;
cmd.cmdarg = UNIPHIER_EMMC_RCA << 16;
/* select card again */
ret = uniphier_emmc_send_cmd(host_base, &cmd);
if (ret)
return ret;
/* switch to Boot Partition 1 */
ret = uniphier_emmc_switch_part(host_base, 1);
if (ret)
return ret;
return 0;
}
int uniphier_emmc_init(uintptr_t *block_dev_spec)
{
int ret;
ret = uniphier_emmc_hw_init();
if (ret)
return ret;
*block_dev_spec = (uintptr_t)&uniphier_emmc_dev_spec;
return 0;
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <gicv3.h>
#include <platform.h>
#include <platform_def.h>
#include "uniphier.h"
static uintptr_t uniphier_rdistif_base_addrs[PLATFORM_CORE_COUNT];
static const unsigned int g0_interrupt_array[] = {
8, /* SGI0 */
14, /* SGI6 */
};
static const unsigned int g1s_interrupt_array[] = {
29, /* Timer */
9, /* SGI1 */
10, /* SGI2 */
11, /* SGI3 */
12, /* SGI4 */
13, /* SGI5 */
15, /* SGI7 */
};
static unsigned int uniphier_mpidr_to_core_pos(u_register_t mpidr)
{
return plat_core_pos_by_mpidr(mpidr);
}
static const struct gicv3_driver_data uniphier_gic_driver_data[] = {
[UNIPHIER_SOC_LD11] = {
.gicd_base = 0x5fe00000,
.gicr_base = 0x5fe40000,
.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
.g0_interrupt_array = g0_interrupt_array,
.g1s_interrupt_array = g1s_interrupt_array,
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = uniphier_rdistif_base_addrs,
.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
},
[UNIPHIER_SOC_LD20] = {
.gicd_base = 0x5fe00000,
.gicr_base = 0x5fe80000,
.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
.g0_interrupt_array = g0_interrupt_array,
.g1s_interrupt_array = g1s_interrupt_array,
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = uniphier_rdistif_base_addrs,
.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
},
[UNIPHIER_SOC_PXS3] = {
.gicd_base = 0x5fe00000,
.gicr_base = 0x5fe80000,
.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
.g0_interrupt_array = g0_interrupt_array,
.g1s_interrupt_array = g1s_interrupt_array,
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = uniphier_rdistif_base_addrs,
.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
},
};
void uniphier_gic_driver_init(unsigned int soc)
{
assert(soc < ARRAY_SIZE(uniphier_gic_driver_data));
gicv3_driver_init(&uniphier_gic_driver_data[soc]);
}
void uniphier_gic_init(void)
{
gicv3_distif_init();
gicv3_rdistif_init(plat_my_core_pos());
gicv3_cpuif_enable(plat_my_core_pos());
}
void uniphier_gic_cpuif_enable(void)
{
gicv3_cpuif_enable(plat_my_core_pos());
}
void uniphier_gic_cpuif_disable(void)
{
gicv3_cpuif_disable(plat_my_core_pos());
}
void uniphier_gic_pcpu_init(void)
{
gicv3_rdistif_init(plat_my_core_pos());
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <platform_def.h>
.global uniphier_calc_core_pos
.global plat_my_core_pos
.globl platform_mem_init
/*
* unsigned int uniphier_calc_core_pos(u_register_t mpidr)
* core_pos = (cluster_id * max_cpus_per_cluster) + core_id
*/
func uniphier_calc_core_pos
and x1, x0, #MPIDR_CPU_MASK
and x0, x0, #MPIDR_CLUSTER_MASK
lsr x0, x0, #MPIDR_AFFINITY_BITS
mov x2, #UNIPHIER_MAX_CPUS_PER_CLUSTER
madd x0, x0, x2, x1
ret
endfunc uniphier_calc_core_pos
func plat_my_core_pos
mrs x0, mpidr_el1
b uniphier_calc_core_pos
endfunc plat_my_core_pos
func platform_mem_init
ret
endfunc platform_mem_init

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <assert.h>
#include <desc_image_load.h>
#include <platform_def.h>
#include "uniphier.h"
static struct bl_mem_params_node uniphier_image_descs[] = {
{
.image_id = SCP_BL2_IMAGE_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = UNIPHIER_SCP_BASE,
.image_info.image_max_size = UNIPHIER_SCP_MAX_SIZE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
NON_SECURE | NON_EXECUTABLE),
.next_handoff_image_id = INVALID_IMAGE_ID,
},
{
.image_id = BL31_IMAGE_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = BL31_BASE,
.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE | EP_FIRST_EXE),
.ep_info.pc = BL31_BASE,
.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
#ifdef UNIPHIER_LOAD_BL32
.next_handoff_image_id = BL32_IMAGE_ID,
#else
.next_handoff_image_id = BL33_IMAGE_ID,
#endif
},
#ifdef UNIPHIER_LOAD_BL32
{
.image_id = BL32_IMAGE_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = BL32_BASE,
.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE),
.ep_info.pc = BL32_BASE,
.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
.next_handoff_image_id = BL33_IMAGE_ID,
},
#endif
{
.image_id = BL33_IMAGE_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = UNIPHIER_BL33_BASE,
.image_info.image_max_size = UNIPHIER_BL33_MAX_SIZE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
NON_SECURE | EXECUTABLE),
.ep_info.pc = UNIPHIER_BL33_BASE,
.ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
.next_handoff_image_id = INVALID_IMAGE_ID,
},
};
REGISTER_BL_IMAGE_DESCS(uniphier_image_descs)
/* SCP is optional. Allow run-time fixup of the descriptor array. */
void uniphier_image_descs_fixup(void)
{
struct bl_mem_params_node *desc;
desc = get_bl_mem_params_node(SCP_BL2_IMAGE_ID);
assert(desc != NULL);
desc->image_info.h.attr |= IMAGE_ATTRIB_SKIP_LOADING;
}

View File

@ -0,0 +1,340 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <firmware_image_package.h>
#include <io/io_block.h>
#include <io/io_driver.h>
#include <io/io_fip.h>
#include <io/io_memmap.h>
#include <platform_def.h>
#include <types.h>
#include <utils_def.h>
#include <xlat_tables_v2.h>
#include "uniphier.h"
#define UNIPHIER_ROM_REGION_BASE 0x00000000
#define UNIPHIER_ROM_REGION_SIZE 0x10000000
static const io_dev_connector_t *uniphier_fip_dev_con;
static uintptr_t uniphier_fip_dev_handle;
static const io_dev_connector_t *uniphier_backend_dev_con;
static uintptr_t uniphier_backend_dev_handle;
static io_block_spec_t uniphier_fip_spec = {
/* .offset will be set by the io_setup func */
.length = 0x00200000,
};
static const io_uuid_spec_t uniphier_bl2_spec = {
.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
};
static const io_uuid_spec_t uniphier_scp_spec = {
.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
};
static const io_uuid_spec_t uniphier_bl31_spec = {
.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
};
static const io_uuid_spec_t uniphier_bl32_spec = {
.uuid = UUID_SECURE_PAYLOAD_BL32,
};
static const io_uuid_spec_t uniphier_bl33_spec = {
.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
};
#if TRUSTED_BOARD_BOOT
static const io_uuid_spec_t uniphier_tb_fw_cert_spec = {
.uuid = UUID_TRUSTED_BOOT_FW_CERT,
};
static const io_uuid_spec_t uniphier_trusted_key_cert_spec = {
.uuid = UUID_TRUSTED_KEY_CERT,
};
static const io_uuid_spec_t uniphier_scp_fw_key_cert_spec = {
.uuid = UUID_SCP_FW_KEY_CERT,
};
static const io_uuid_spec_t uniphier_soc_fw_key_cert_spec = {
.uuid = UUID_SOC_FW_KEY_CERT,
};
static const io_uuid_spec_t uniphier_tos_fw_key_cert_spec = {
.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
};
static const io_uuid_spec_t uniphier_nt_fw_key_cert_spec = {
.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
};
static const io_uuid_spec_t uniphier_scp_fw_cert_spec = {
.uuid = UUID_SCP_FW_CONTENT_CERT,
};
static const io_uuid_spec_t uniphier_soc_fw_cert_spec = {
.uuid = UUID_SOC_FW_CONTENT_CERT,
};
static const io_uuid_spec_t uniphier_tos_fw_cert_spec = {
.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
};
static const io_uuid_spec_t uniphier_nt_fw_cert_spec = {
.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
};
#endif /* TRUSTED_BOARD_BOOT */
struct uniphier_io_policy {
uintptr_t *dev_handle;
uintptr_t image_spec;
uintptr_t init_params;
};
static const struct uniphier_io_policy uniphier_io_policies[] = {
[FIP_IMAGE_ID] = {
.dev_handle = &uniphier_backend_dev_handle,
.image_spec = (uintptr_t)&uniphier_fip_spec,
},
[BL2_IMAGE_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_bl2_spec,
.init_params = FIP_IMAGE_ID,
},
[SCP_BL2_IMAGE_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_scp_spec,
.init_params = FIP_IMAGE_ID,
},
[BL31_IMAGE_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_bl31_spec,
.init_params = FIP_IMAGE_ID,
},
[BL32_IMAGE_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_bl32_spec,
.init_params = FIP_IMAGE_ID,
},
[BL33_IMAGE_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_bl33_spec,
.init_params = FIP_IMAGE_ID,
},
#if TRUSTED_BOARD_BOOT
[TRUSTED_BOOT_FW_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_tb_fw_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[TRUSTED_KEY_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_trusted_key_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[SCP_FW_KEY_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_scp_fw_key_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[SOC_FW_KEY_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_soc_fw_key_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[TRUSTED_OS_FW_KEY_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_tos_fw_key_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[NON_TRUSTED_FW_KEY_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_nt_fw_key_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[SCP_FW_CONTENT_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_scp_fw_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[SOC_FW_CONTENT_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_soc_fw_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_tos_fw_cert_spec,
.init_params = FIP_IMAGE_ID,
},
[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
.dev_handle = &uniphier_fip_dev_handle,
.image_spec = (uintptr_t)&uniphier_nt_fw_cert_spec,
.init_params = FIP_IMAGE_ID,
},
#endif
};
static int uniphier_io_block_setup(size_t fip_offset, uintptr_t block_dev_spec)
{
int ret;
uniphier_fip_spec.offset = fip_offset;
ret = register_io_dev_block(&uniphier_backend_dev_con);
if (ret)
return ret;
return io_dev_open(uniphier_backend_dev_con, block_dev_spec,
&uniphier_backend_dev_handle);
}
static int uniphier_io_memmap_setup(size_t fip_offset)
{
int ret;
uniphier_fip_spec.offset = fip_offset;
ret = mmap_add_dynamic_region(fip_offset, fip_offset,
uniphier_fip_spec.length,
MT_RO_DATA | MT_SECURE);
if (ret)
return ret;
ret = register_io_dev_memmap(&uniphier_backend_dev_con);
if (ret)
return ret;
return io_dev_open(uniphier_backend_dev_con, 0,
&uniphier_backend_dev_handle);
}
static int uniphier_io_fip_setup(void)
{
int ret;
ret = register_io_dev_fip(&uniphier_fip_dev_con);
if (ret)
return ret;
return io_dev_open(uniphier_fip_dev_con, 0, &uniphier_fip_dev_handle);
}
static int uniphier_io_emmc_setup(unsigned int soc_id)
{
uintptr_t block_dev_spec;
int ret;
ret = uniphier_emmc_init(&block_dev_spec);
if (ret)
return ret;
return uniphier_io_block_setup(0x20000, block_dev_spec);
}
static int uniphier_io_nand_setup(unsigned int soc_id)
{
uintptr_t block_dev_spec;
int ret;
ret = uniphier_nand_init(&block_dev_spec);
if (ret)
return ret;
return uniphier_io_block_setup(0x20000, block_dev_spec);
}
static int uniphier_io_nor_setup(unsigned int soc_id)
{
return uniphier_io_memmap_setup(0x70000);
}
static int uniphier_io_usb_setup(unsigned int soc_id)
{
uintptr_t block_dev_spec;
int ret;
/* use ROM API for loading images from USB storage */
ret = mmap_add_dynamic_region(UNIPHIER_ROM_REGION_BASE,
UNIPHIER_ROM_REGION_BASE,
UNIPHIER_ROM_REGION_SIZE,
MT_CODE | MT_SECURE);
if (ret)
return ret;
ret = uniphier_usb_init(soc_id, &block_dev_spec);
if (ret)
return ret;
return uniphier_io_block_setup(0x20000, block_dev_spec);
}
static int (* const uniphier_io_setup_table[])(unsigned int) = {
[UNIPHIER_BOOT_DEVICE_EMMC] = uniphier_io_emmc_setup,
[UNIPHIER_BOOT_DEVICE_NAND] = uniphier_io_nand_setup,
[UNIPHIER_BOOT_DEVICE_NOR] = uniphier_io_nor_setup,
[UNIPHIER_BOOT_DEVICE_USB] = uniphier_io_usb_setup,
};
int uniphier_io_setup(unsigned int soc_id)
{
int (*io_setup)(unsigned int soc_id);
unsigned int boot_dev;
int ret;
boot_dev = uniphier_get_boot_device(soc_id);
if (boot_dev == UNIPHIER_BOOT_DEVICE_RSV)
return -EINVAL;
io_setup = uniphier_io_setup_table[boot_dev];
ret = io_setup(soc_id);
if (ret)
return ret;
ret = uniphier_io_fip_setup();
if (ret)
return ret;
return 0;
}
int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
uintptr_t *image_spec)
{
uintptr_t init_params;
assert(image_id < ARRAY_SIZE(uniphier_io_policies));
*dev_handle = *(uniphier_io_policies[image_id].dev_handle);
*image_spec = uniphier_io_policies[image_id].image_spec;
init_params = uniphier_io_policies[image_id].init_params;
return io_dev_init(*dev_handle, init_params);
}
int uniphier_check_image(unsigned int image_id)
{
uintptr_t dev_handle, image_spec, image_handle;
int ret;
ret = plat_get_image_source(image_id, &dev_handle, &image_spec);
if (ret)
return ret;
ret = io_open(dev_handle, image_spec, &image_handle);
if (ret)
return ret;
io_close(image_handle);
return 0;
}

View File

@ -0,0 +1,274 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <debug.h>
#include <io/io_block.h>
#include <mmio.h>
#include <platform_def.h>
#include <sys/types.h>
#include <utils_def.h>
#include "uniphier.h"
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define NAND_CMD_READ0 0
#define NAND_CMD_READSTART 0x30
#define DENALI_ECC_ENABLE 0x0e0
#define DENALI_PAGES_PER_BLOCK 0x150
#define DENALI_DEVICE_MAIN_AREA_SIZE 0x170
#define DENALI_DEVICE_SPARE_AREA_SIZE 0x180
#define DENALI_TWO_ROW_ADDR_CYCLES 0x190
#define DENALI_INTR_STATUS0 0x410
#define DENALI_INTR_ECC_UNCOR_ERR BIT(1)
#define DENALI_INTR_DMA_CMD_COMP BIT(2)
#define DENALI_INTR_INT_ACT BIT(12)
#define DENALI_DMA_ENABLE 0x700
#define DENALI_HOST_ADDR 0x00
#define DENALI_HOST_DATA 0x10
#define DENALI_MAP01 (1 << 26)
#define DENALI_MAP10 (2 << 26)
#define DENALI_MAP11 (3 << 26)
#define DENALI_MAP11_CMD ((DENALI_MAP11) | 0)
#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1)
#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2)
#define DENALI_ACCESS_DEFAULT_AREA 0x42
#define UNIPHIER_NAND_BBT_UNKNOWN 0xff
struct uniphier_nand {
uintptr_t host_base;
uintptr_t reg_base;
int pages_per_block;
int page_size;
int two_row_addr_cycles;
uint8_t bbt[16];
};
struct uniphier_nand uniphier_nand;
static void uniphier_nand_host_write(struct uniphier_nand *nand,
uint32_t addr, uint32_t data)
{
mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr);
mmio_write_32(nand->host_base + DENALI_HOST_DATA, data);
}
static uint32_t uniphier_nand_host_read(struct uniphier_nand *nand,
uint32_t addr)
{
mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr);
return mmio_read_32(nand->host_base + DENALI_HOST_DATA);
}
static int uniphier_nand_block_isbad(struct uniphier_nand *nand, int block)
{
int page = nand->pages_per_block * block;
int column = nand->page_size;
uint8_t bbm;
uint32_t status;
int is_bad;
/* use cache if available */
if (block < ARRAY_SIZE(nand->bbt) &&
nand->bbt[block] != UNIPHIER_NAND_BBT_UNKNOWN)
return nand->bbt[block];
mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 0);
mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1);
uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READ0);
uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, column & 0xff);
uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (column >> 8) & 0xff);
uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, page & 0xff);
uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (page >> 8) & 0xff);
if (!nand->two_row_addr_cycles)
uniphier_nand_host_write(nand, DENALI_MAP11_ADDR,
(page >> 16) & 0xff);
uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READSTART);
do {
status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0);
} while (!(status & DENALI_INTR_INT_ACT));
bbm = uniphier_nand_host_read(nand, DENALI_MAP11_DATA);
is_bad = bbm != 0xff;
/* save the result for future re-use */
nand->bbt[block] = is_bad;
if (is_bad)
WARN("found bad block at %d. skip.\n", block);
return is_bad;
}
static int uniphier_nand_read_pages(struct uniphier_nand *nand, uintptr_t buf,
int page_start, int page_count)
{
uint32_t status;
mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 1);
mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 1);
mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1);
/* use Data DMA (64bit) */
mmio_write_32(nand->host_base + DENALI_HOST_ADDR,
DENALI_MAP10 | page_start);
/*
* 1. setup transfer type, interrupt when complete,
* burst len = 64 bytes, the number of pages
*/
mmio_write_32(nand->host_base + DENALI_HOST_DATA,
0x01002000 | (64 << 16) | page_count);
/* 2. set memory low address */
mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf);
/* 3. set memory high address */
mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf >> 32);
do {
status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0);
} while (!(status & DENALI_INTR_DMA_CMD_COMP));
mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 0);
if (status & DENALI_INTR_ECC_UNCOR_ERR) {
ERROR("uncorrectable error in page range %d-%d",
page_start, page_start + page_count - 1);
return -EBADMSG;
}
return 0;
}
static size_t __uniphier_nand_read(struct uniphier_nand *nand, int lba,
uintptr_t buf, size_t size)
{
int pages_per_block = nand->pages_per_block;
int page_size = nand->page_size;
int blocks_to_skip = lba / pages_per_block;
int pages_to_read = DIV_ROUND_UP(size, page_size);
int page = lba % pages_per_block;
int block = 0;
uintptr_t p = buf;
int page_count, ret;
while (blocks_to_skip) {
ret = uniphier_nand_block_isbad(nand, block);
if (ret < 0)
goto out;
if (!ret)
blocks_to_skip--;
block++;
}
while (pages_to_read) {
ret = uniphier_nand_block_isbad(nand, block);
if (ret < 0)
goto out;
if (ret) {
block++;
continue;
}
page_count = MIN(pages_per_block - page, pages_to_read);
ret = uniphier_nand_read_pages(nand, p,
block * pages_per_block + page,
page_count);
if (ret)
goto out;
block++;
page = 0;
p += page_size * page_count;
pages_to_read -= page_count;
}
out:
/* number of read bytes */
return MIN(size, p - buf);
}
static size_t uniphier_nand_read(int lba, uintptr_t buf, size_t size)
{
size_t count;
inv_dcache_range(buf, size);
count = __uniphier_nand_read(&uniphier_nand, lba, buf, size);
inv_dcache_range(buf, size);
return count;
}
static struct io_block_dev_spec uniphier_nand_dev_spec = {
.buffer = {
.offset = UNIPHIER_BLOCK_BUF_BASE,
.length = UNIPHIER_BLOCK_BUF_SIZE,
},
.ops = {
.read = uniphier_nand_read,
},
/* fill .block_size at run-time */
};
static int uniphier_nand_hw_init(struct uniphier_nand *nand)
{
int i;
for (i = 0; i < ARRAY_SIZE(nand->bbt); i++)
nand->bbt[i] = UNIPHIER_NAND_BBT_UNKNOWN;
nand->host_base = 0x68000000;
nand->reg_base = 0x68100000;
nand->pages_per_block =
mmio_read_32(nand->reg_base + DENALI_PAGES_PER_BLOCK);
nand->page_size =
mmio_read_32(nand->reg_base + DENALI_DEVICE_MAIN_AREA_SIZE);
if (mmio_read_32(nand->reg_base + DENALI_TWO_ROW_ADDR_CYCLES) & BIT(0))
nand->two_row_addr_cycles = 1;
uniphier_nand_host_write(nand, DENALI_MAP10,
DENALI_ACCESS_DEFAULT_AREA);
return 0;
}
int uniphier_nand_init(uintptr_t *block_dev_spec)
{
int ret;
ret = uniphier_nand_hw_init(&uniphier_nand);
if (ret)
return ret;
uniphier_nand_dev_spec.block_size = uniphier_nand.page_size;
*block_dev_spec = (uintptr_t)&uniphier_nand_dev_spec;
return 0;
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <debug.h>
#include <mmio.h>
#include <psci.h>
#include "uniphier.h"
#define UNIPHIER_ROM_RSV0 0x59801200
#define UNIPHIER_SLFRSTSEL 0x61843010
#define UNIPHIER_SLFRSTSEL_MASK (0x3 << 0)
#define UNIPHIER_SLFRSTCTL 0x61843014
#define UNIPHIER_SLFRSTCTL_RST (1 << 0)
#define MPIDR_AFFINITY_INVALID ((u_register_t)-1)
uintptr_t uniphier_sec_entrypoint;
void uniphier_warmboot_entrypoint(void);
void __dead2 uniphier_fake_pwr_down(void);
u_register_t uniphier_holding_pen_release;
static int uniphier_psci_scp_mode;
static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
{
uniphier_holding_pen_release = mpidr;
flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
sizeof(uniphier_holding_pen_release));
mmio_write_64(UNIPHIER_ROM_RSV0,
(uint64_t)&uniphier_warmboot_entrypoint);
sev();
return PSCI_E_SUCCESS;
}
static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
{
uniphier_gic_cpuif_disable();
}
static void uniphier_psci_pwr_domain_on_finish(
const psci_power_state_t *target_state)
{
uniphier_gic_pcpu_init();
uniphier_gic_cpuif_enable();
uniphier_cci_enable();
}
static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
const psci_power_state_t *target_state)
{
/*
* The Boot ROM cannot distinguish warn and cold resets.
* Instead of the CPU reset, fake it.
*/
uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
sizeof(uniphier_holding_pen_release));
uniphier_fake_pwr_down();
}
static void uniphier_self_system_reset(void)
{
mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK);
mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST);
}
static void __dead2 uniphier_psci_system_off(void)
{
if (uniphier_psci_scp_mode) {
uniphier_scp_system_off();
} else {
NOTICE("SCP is disabled; can't shutdown the system.\n");
NOTICE("Resetting the system instead.\n");
uniphier_self_system_reset();
}
wfi();
ERROR("UniPhier System Off: operation not handled.\n");
panic();
}
static void __dead2 uniphier_psci_system_reset(void)
{
if (uniphier_psci_scp_mode)
uniphier_scp_system_reset();
else
uniphier_self_system_reset();
wfi();
ERROR("UniPhier System Reset: operation not handled.\n");
panic();
}
static const struct plat_psci_ops uniphier_psci_ops = {
.pwr_domain_on = uniphier_psci_pwr_domain_on,
.pwr_domain_off = uniphier_psci_pwr_domain_off,
.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
.system_off = uniphier_psci_system_off,
.system_reset = uniphier_psci_system_reset,
};
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const struct plat_psci_ops **psci_ops)
{
uniphier_sec_entrypoint = sec_entrypoint;
flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
sizeof(uniphier_sec_entrypoint));
uniphier_psci_scp_mode = uniphier_scp_is_running();
flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
sizeof(uniphier_psci_scp_mode));
if (uniphier_psci_scp_mode)
uniphier_scp_open_com();
*psci_ops = &uniphier_psci_ops;
return 0;
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mmio.h>
#include <utils_def.h>
#include "uniphier.h"
#define UNIPHIER_ROM_RSV3 0x5980120c
#define UNIPHIER_STMBE2COM 0x5f800030
#define UNIPHIER_BETOSTMIRQ0PT 0x5f800070
#define UNIPHIER_SCP_READY_MAGIC 0x0000b6a5
#define UNIPHIER_SCP_PACKET_START 0xA0
#define UNIPHIER_SCP_PACKET_END 0xA5
#define UNIPHIER_SCP_PACKET_ESC 0xA6
#define UNIPHIER_SCP_IS_CTRL_CODE(c) (0xA0 <= (c) && (c) <= 0xA6)
int uniphier_scp_is_running(void)
{
return mmio_read_32(UNIPHIER_STMBE2COM) == UNIPHIER_SCP_READY_MAGIC;
}
void uniphier_scp_start(void)
{
uint32_t tmp;
mmio_write_32(UNIPHIER_STMBE2COM + 4, UNIPHIER_SCP_BASE);
mmio_write_32(UNIPHIER_STMBE2COM, UNIPHIER_SCP_READY_MAGIC);
do {
tmp = mmio_read_32(UNIPHIER_ROM_RSV3);
} while (!(tmp & BIT(8)));
mmio_write_32(UNIPHIER_ROM_RSV3, tmp | BIT(9));
}
static void uniphier_scp_send_packet(const uint8_t *packet, int packet_len)
{
uintptr_t reg = UNIPHIER_STMBE2COM;
uint32_t word;
int len, i;
while (packet_len) {
len = MIN(packet_len, 4);
word = 0;
for (i = 0; i < len; i++)
word |= *packet++ << (8 * i);
mmio_write_32(reg, word);
reg += 4;
packet_len -= len;
}
mmio_write_8(UNIPHIER_BETOSTMIRQ0PT, 0x55);
}
static void uniphier_scp_send_cmd(const uint8_t *cmd, int cmd_len)
{
uint8_t packet[32]; /* long enough */
uint8_t *p = packet;
uint8_t c;
int i;
*p++ = UNIPHIER_SCP_PACKET_START;
*p++ = cmd_len;
for (i = 0; i < cmd_len; i++) {
c = *cmd++;
if (UNIPHIER_SCP_IS_CTRL_CODE(c)) {
*p++ = UNIPHIER_SCP_PACKET_ESC;
*p++ = c ^ BIT(7);
} else {
*p++ = c;
}
}
*p++ = UNIPHIER_SCP_PACKET_END;
uniphier_scp_send_packet(packet, p - packet);
}
#define UNIPHIER_SCP_CMD(name, ...) \
static const uint8_t __uniphier_scp_##name##_cmd[] = { \
__VA_ARGS__ \
}; \
void uniphier_scp_##name(void) \
{ \
uniphier_scp_send_cmd(__uniphier_scp_##name##_cmd, \
ARRAY_SIZE(__uniphier_scp_##name##_cmd)); \
}
UNIPHIER_SCP_CMD(open_com, 0x00, 0x00, 0x05)
UNIPHIER_SCP_CMD(system_off, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01)
UNIPHIER_SCP_CMD(system_reset, 0x00, 0x02, 0x00)

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
.globl uniphier_warmboot_entrypoint
.globl uniphier_fake_pwr_down
func uniphier_warmboot_entrypoint
mrs x0, mpidr_el1
mov_imm x1, MPIDR_AFFINITY_MASK
and x0, x0, x1
b 1f
0: wfe
1: ldr x1, uniphier_holding_pen_release
cmp x1, x0
b.ne 0b
ldr x0, uniphier_sec_entrypoint
br x0
endfunc uniphier_warmboot_entrypoint
func uniphier_fake_pwr_down
bl disable_mmu_icache_el3
b uniphier_warmboot_entrypoint
endfunc uniphier_fake_pwr_down

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mmio.h>
#include "uniphier.h"
#define UNIPHIER_REVISION 0x5f800000
static unsigned int uniphier_get_revision_field(unsigned int mask,
unsigned int shift)
{
uint32_t revision = mmio_read_32(UNIPHIER_REVISION);
return (revision >> shift) & mask;
}
unsigned int uniphier_get_soc_type(void)
{
return uniphier_get_revision_field(0xff, 16);
}
unsigned int uniphier_get_soc_model(void)
{
return uniphier_get_revision_field(0x07, 8);
}
unsigned int uniphier_get_soc_revision(void)
{
return uniphier_get_revision_field(0x1f, 0);
}
unsigned int uniphier_get_soc_id(void)
{
uint32_t type = uniphier_get_soc_type();
switch (type) {
case 0x31:
return UNIPHIER_SOC_LD11;
case 0x32:
return UNIPHIER_SOC_LD20;
case 0x35:
return UNIPHIER_SOC_PXS3;
default:
return UNIPHIER_SOC_UNKNOWN;
}
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform.h>
unsigned int plat_get_syscnt_freq2(void)
{
return 50000000;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform.h>
int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
unsigned int *flags)
{
*flags = ROTPK_NOT_DEPLOYED;
return 0;
}
int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
{
/*
* No support for non-volatile counter. Update the ROT key to protect
* the system against rollback.
*/
*nv_ctr = 0;
return 0;
}
int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
{
return 0;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <platform.h>
#include "uniphier.h"
static unsigned char uniphier_power_domain_tree_desc[UNIPHIER_CLUSTER_COUNT + 1];
const unsigned char *plat_get_power_domain_tree_desc(void)
{
int i;
uniphier_power_domain_tree_desc[0] = UNIPHIER_CLUSTER_COUNT;
for (i = 0; i < UNIPHIER_CLUSTER_COUNT; i++)
uniphier_power_domain_tree_desc[i + 1] =
UNIPHIER_MAX_CPUS_PER_CLUSTER;
return uniphier_power_domain_tree_desc;
}
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
unsigned int cluster_id, cpu_id;
cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
if (cluster_id >= UNIPHIER_CLUSTER_COUNT)
return -1;
cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
if (cpu_id >= UNIPHIER_MAX_CPUS_PER_CLUSTER)
return -1;
return uniphier_calc_core_pos(mpidr);
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <io/io_block.h>
#include <mmio.h>
#include <platform_def.h>
#include <sys/types.h>
#include <utils_def.h>
#include "uniphier.h"
#define UNIPHIER_LD11_USB_DESC_BASE 0x30010000
#define UNIPHIER_LD20_USB_DESC_BASE 0x30014000
#define UNIPHIER_SRB_OCM_CONT 0x61200000
struct uniphier_ld11_trans_op {
uint8_t __pad[48];
};
struct uniphier_ld11_op {
uint8_t __pad[56];
struct uniphier_ld11_trans_op *trans_op;
void *__pad2;
void *dev_desc;
};
struct uniphier_ld20_trans_op {
uint8_t __pad[40];
};
struct uniphier_ld20_op {
uint8_t __pad[192];
struct uniphier_ld20_trans_op *trans_op;
void *__pad2;
void *dev_desc;
};
static int (*__uniphier_usb_read)(int lba, uintptr_t buf, size_t size);
static void uniphier_ld11_usb_init(void)
{
struct uniphier_ld11_op *op = (void *)UNIPHIER_LD11_USB_DESC_BASE;
op->trans_op = (void *)(op + 1);
op->dev_desc = op->trans_op + 1;
}
static int uniphier_ld11_usb_read(int lba, uintptr_t buf, size_t size)
{
static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
unsigned int size, uintptr_t buf);
uintptr_t func_addr;
func_addr = uniphier_get_soc_revision() == 1 ? 0x3880 : 0x3958;
rom_usb_read = (__typeof(rom_usb_read))func_addr;
return rom_usb_read(UNIPHIER_LD11_USB_DESC_BASE, lba, size, buf);
}
static void uniphier_ld20_usb_init(void)
{
struct uniphier_ld20_op *op = (void *)UNIPHIER_LD20_USB_DESC_BASE;
op->trans_op = (void *)(op + 1);
op->dev_desc = op->trans_op + 1;
}
static int uniphier_ld20_usb_read(int lba, uintptr_t buf, size_t size)
{
static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
unsigned int size, uintptr_t buf);
int ret;
rom_usb_read = (__typeof(rom_usb_read))0x37f0;
mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0x1ff);
/* ROM-API - return 1 on success, 0 on error */
ret = rom_usb_read(UNIPHIER_LD20_USB_DESC_BASE, lba, size, buf);
mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0);
return ret ? 0 : -1;
}
static int uniphier_pxs3_usb_read(int lba, uintptr_t buf, size_t size)
{
static int (*rom_usb_read)(unsigned int lba, unsigned int size,
uintptr_t buf);
rom_usb_read = (__typeof(rom_usb_read))0x100c;
return rom_usb_read(lba, size, buf);
}
struct uniphier_usb_rom_param {
void (*init)(void);
int (*read)(int lba, uintptr_t buf, size_t size);
};
static const struct uniphier_usb_rom_param uniphier_usb_rom_params[] = {
[UNIPHIER_SOC_LD11] = {
.init = uniphier_ld11_usb_init,
.read = uniphier_ld11_usb_read,
},
[UNIPHIER_SOC_LD20] = {
.init = uniphier_ld20_usb_init,
.read = uniphier_ld20_usb_read,
},
[UNIPHIER_SOC_PXS3] = {
.read = uniphier_pxs3_usb_read,
},
};
static size_t uniphier_usb_read(int lba, uintptr_t buf, size_t size)
{
int ret;
inv_dcache_range(buf, size);
ret = __uniphier_usb_read(lba, buf, size);
inv_dcache_range(buf, size);
return ret ? 0 : size;
}
static struct io_block_dev_spec uniphier_usb_dev_spec = {
.buffer = {
.offset = UNIPHIER_BLOCK_BUF_BASE,
.length = UNIPHIER_BLOCK_BUF_SIZE,
},
.ops = {
.read = uniphier_usb_read,
},
.block_size = 512,
};
int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec)
{
const struct uniphier_usb_rom_param *param;
assert(soc < ARRAY_SIZE(uniphier_usb_rom_params));
param = &uniphier_usb_rom_params[soc];
if (param->init)
param->init();
__uniphier_usb_read = param->read;
*block_dev_spec = (uintptr_t)&uniphier_usb_dev_spec;
return 0;
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <platform_def.h>
#include <xlat_tables_v2.h>
#define UNIPHIER_OCM_REGION_BASE 0x30000000
#define UNIPHIER_OCM_REGION_SIZE 0x00040000
#define UNIPHIER_REG_REGION_BASE 0x50000000
#define UNIPHIER_REG_REGION_SIZE 0x20000000
void uniphier_mmap_setup(uintptr_t total_base, size_t total_size,
const struct mmap_region *mmap)
{
VERBOSE("Trusted RAM seen by this BL image: %p - %p\n",
(void *)total_base, (void *)(total_base + total_size));
mmap_add_region(total_base, total_base,
total_size,
MT_MEMORY | MT_RW | MT_SECURE);
/* remap the code section */
VERBOSE("Code region: %p - %p\n",
(void *)BL_CODE_BASE, (void *)BL_CODE_END);
mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
round_up(BL_CODE_END, PAGE_SIZE) - BL_CODE_BASE,
MT_CODE | MT_SECURE);
/* remap the coherent memory region */
VERBOSE("Coherent region: %p - %p\n",
(void *)BL_COHERENT_RAM_BASE, (void *)BL_COHERENT_RAM_END);
mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
MT_DEVICE | MT_RW | MT_SECURE);
/*
* on-chip SRAM region: should be DEVICE attribute because the USB
* load functions provided by the ROM use this memory region as a work
* area, but do not cater to cache coherency.
*/
mmap_add_region(UNIPHIER_OCM_REGION_BASE, UNIPHIER_OCM_REGION_BASE,
UNIPHIER_OCM_REGION_SIZE,
MT_DEVICE | MT_RW | MT_SECURE);
/* register region */
mmap_add_region(UNIPHIER_REG_REGION_BASE, UNIPHIER_REG_REGION_BASE,
UNIPHIER_REG_REGION_SIZE,
MT_DEVICE | MT_RW | MT_SECURE);
/* additional regions if needed */
if (mmap)
mmap_add(mmap);
init_xlat_tables();
}