diff --git a/acknowledgements.md b/acknowledgements.md index 2f6309e..028f321 100644 --- a/acknowledgements.md +++ b/acknowledgements.md @@ -7,6 +7,8 @@ NVIDIA Corporation +Socionext Inc. + Xilinx, Inc. Individuals diff --git a/docs/plat/socionext-uniphier.md b/docs/plat/socionext-uniphier.md new file mode 100644 index 0000000..75e6545 --- /dev/null +++ b/docs/plat/socionext-uniphier.md @@ -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= PLAT=uniphier 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= +``` + +[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= +``` + +- BL32 (Secure Payload) + +To enable BL32, add the following option to the build command: + +``` + SPD= BL32= +``` diff --git a/plat/socionext/uniphier/include/plat_macros.S b/plat/socionext/uniphier/include/plat_macros.S new file mode 100644 index 0000000..6de4dde --- /dev/null +++ b/plat/socionext/uniphier/include/plat_macros.S @@ -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__ */ diff --git a/plat/socionext/uniphier/include/platform_def.h b/plat/socionext/uniphier/include/platform_def.h new file mode 100644 index 0000000..7e603a3 --- /dev/null +++ b/plat/socionext/uniphier/include/platform_def.h @@ -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 +#include + +#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__ */ diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk new file mode 100644 index 0000000..af8e3ac --- /dev/null +++ b/plat/socionext/uniphier/platform.mk @@ -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) diff --git a/plat/socionext/uniphier/uniphier.h b/plat/socionext/uniphier/uniphier.h new file mode 100644 index 0000000..95b29b8 --- /dev/null +++ b/plat/socionext/uniphier/uniphier.h @@ -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 +#include + +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__ */ diff --git a/plat/socionext/uniphier/uniphier_bl1_helpers.S b/plat/socionext/uniphier/uniphier_bl1_helpers.S new file mode 100644 index 0000000..5818565 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_bl1_helpers.S @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + + .globl plat_get_my_entrypoint + +func plat_get_my_entrypoint + mov x0, #0 + ret +endfunc plat_get_my_entrypoint diff --git a/plat/socionext/uniphier/uniphier_bl1_setup.c b/plat/socionext/uniphier/uniphier_bl1_setup.c new file mode 100644 index 0000000..da7740a --- /dev/null +++ b/plat/socionext/uniphier/uniphier_bl1_setup.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_bl2_setup.c b/plat/socionext/uniphier/uniphier_bl2_setup.c new file mode 100644 index 0000000..b83e700 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_bl2_setup.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_bl31_setup.c b/plat/socionext/uniphier/uniphier_bl31_setup.c new file mode 100644 index 0000000..d9c87bd --- /dev/null +++ b/plat/socionext/uniphier/uniphier_bl31_setup.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +} diff --git a/plat/socionext/uniphier/uniphier_boot_device.c b/plat/socionext/uniphier/uniphier_boot_device.c new file mode 100644 index 0000000..78ca8ef --- /dev/null +++ b/plat/socionext/uniphier/uniphier_boot_device.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#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; + } +} diff --git a/plat/socionext/uniphier/uniphier_cci.c b/plat/socionext/uniphier/uniphier_cci.c new file mode 100644 index 0000000..30f4b47 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_cci.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#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(); +} diff --git a/plat/socionext/uniphier/uniphier_console.S b/plat/socionext/uniphier/uniphier_console.S new file mode 100644 index 0000000..03aff48 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_console.S @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#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 diff --git a/plat/socionext/uniphier/uniphier_emmc.c b/plat/socionext/uniphier/uniphier_emmc.c new file mode 100644 index 0000000..fcd4cb4 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_emmc.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_gicv3.c b/plat/socionext/uniphier/uniphier_gicv3.c new file mode 100644 index 0000000..05a4e35 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_gicv3.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#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()); +} diff --git a/plat/socionext/uniphier/uniphier_helpers.S b/plat/socionext/uniphier/uniphier_helpers.S new file mode 100644 index 0000000..105cf9e --- /dev/null +++ b/plat/socionext/uniphier/uniphier_helpers.S @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + + .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 diff --git a/plat/socionext/uniphier/uniphier_image_desc.c b/plat/socionext/uniphier/uniphier_image_desc.c new file mode 100644 index 0000000..1e474c5 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_image_desc.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_io_storage.c b/plat/socionext/uniphier/uniphier_io_storage.c new file mode 100644 index 0000000..bc31350 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_io_storage.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_nand.c b/plat/socionext/uniphier/uniphier_nand.c new file mode 100644 index 0000000..acf6a74 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_nand.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c new file mode 100644 index 0000000..82081a0 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_psci.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_scp.c b/plat/socionext/uniphier/uniphier_scp.c new file mode 100644 index 0000000..9a921c4 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_scp.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#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) diff --git a/plat/socionext/uniphier/uniphier_smp.S b/plat/socionext/uniphier/uniphier_smp.S new file mode 100644 index 0000000..d6cb9ff --- /dev/null +++ b/plat/socionext/uniphier/uniphier_smp.S @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + + .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 diff --git a/plat/socionext/uniphier/uniphier_soc_info.c b/plat/socionext/uniphier/uniphier_soc_info.c new file mode 100644 index 0000000..55688f3 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_soc_info.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#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; + } +} diff --git a/plat/socionext/uniphier/uniphier_syscnt.c b/plat/socionext/uniphier/uniphier_syscnt.c new file mode 100644 index 0000000..d7bcaf8 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_syscnt.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +unsigned int plat_get_syscnt_freq2(void) +{ + return 50000000; +} diff --git a/plat/socionext/uniphier/uniphier_tbbr.c b/plat/socionext/uniphier/uniphier_tbbr.c new file mode 100644 index 0000000..cafe1a3 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_tbbr.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +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; +} diff --git a/plat/socionext/uniphier/uniphier_topology.c b/plat/socionext/uniphier/uniphier_topology.c new file mode 100644 index 0000000..1f96f58 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_topology.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#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); +} diff --git a/plat/socionext/uniphier/uniphier_usb.c b/plat/socionext/uniphier/uniphier_usb.c new file mode 100644 index 0000000..49ca8e5 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_usb.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/socionext/uniphier/uniphier_xlat_setup.c b/plat/socionext/uniphier/uniphier_xlat_setup.c new file mode 100644 index 0000000..6532c49 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_xlat_setup.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#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(); +}