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:
parent
c396b7368a
commit
d8e919c7b8
|
@ -7,6 +7,8 @@ Linaro Limited
|
|||
|
||||
NVIDIA Corporation
|
||||
|
||||
Socionext Inc.
|
||||
|
||||
Xilinx, Inc.
|
||||
|
||||
Individuals
|
||||
|
|
|
@ -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>
|
||||
```
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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)
|
|
@ -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__ */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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());
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue