diff options
36 files changed, 794 insertions, 184 deletions
diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S index 9ff6a57b..68f9b7ae 100644 --- a/bl1/aarch64/bl1_exceptions.S +++ b/bl1/aarch64/bl1_exceptions.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,42 +34,37 @@ #include <bl1.h> #include <context.h> +/* ----------------------------------------------------------------------------- + * Very simple stackless exception handlers used by BL1. + * ----------------------------------------------------------------------------- + */ .globl bl1_exceptions - .section .vectors, "ax"; .align 11 +vector_base bl1_exceptions /* ----------------------------------------------------- - * Very simple stackless exception handlers used by BL1. - * ----------------------------------------------------- - */ - .align 7 -bl1_exceptions: - /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ -SynchronousExceptionSP0: +vector_entry SynchronousExceptionSP0 mov x0, #SYNC_EXCEPTION_SP_EL0 bl plat_report_exception b SynchronousExceptionSP0 check_vector_size SynchronousExceptionSP0 - .align 7 -IrqSP0: +vector_entry IrqSP0 mov x0, #IRQ_SP_EL0 bl plat_report_exception b IrqSP0 check_vector_size IrqSP0 - .align 7 -FiqSP0: +vector_entry FiqSP0 mov x0, #FIQ_SP_EL0 bl plat_report_exception b FiqSP0 check_vector_size FiqSP0 - .align 7 -SErrorSP0: +vector_entry SErrorSP0 mov x0, #SERROR_SP_EL0 bl plat_report_exception b SErrorSP0 @@ -79,29 +74,25 @@ SErrorSP0: * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ - .align 7 -SynchronousExceptionSPx: +vector_entry SynchronousExceptionSPx mov x0, #SYNC_EXCEPTION_SP_ELX bl plat_report_exception b SynchronousExceptionSPx check_vector_size SynchronousExceptionSPx - .align 7 -IrqSPx: +vector_entry IrqSPx mov x0, #IRQ_SP_ELX bl plat_report_exception b IrqSPx check_vector_size IrqSPx - .align 7 -FiqSPx: +vector_entry FiqSPx mov x0, #FIQ_SP_ELX bl plat_report_exception b FiqSPx check_vector_size FiqSPx - .align 7 -SErrorSPx: +vector_entry SErrorSPx mov x0, #SERROR_SP_ELX bl plat_report_exception b SErrorSPx @@ -111,8 +102,7 @@ SErrorSPx: * Lower EL using AArch64 : 0x400 - 0x600 * ----------------------------------------------------- */ - .align 7 -SynchronousExceptionA64: +vector_entry SynchronousExceptionA64 /* Enable the SError interrupt */ msr daifclr, #DAIF_ABT_BIT @@ -127,22 +117,19 @@ SynchronousExceptionA64: b smc_handler64 check_vector_size SynchronousExceptionA64 - .align 7 -IrqA64: +vector_entry IrqA64 mov x0, #IRQ_AARCH64 bl plat_report_exception b IrqA64 check_vector_size IrqA64 - .align 7 -FiqA64: +vector_entry FiqA64 mov x0, #FIQ_AARCH64 bl plat_report_exception b FiqA64 check_vector_size FiqA64 - .align 7 -SErrorA64: +vector_entry SErrorA64 mov x0, #SERROR_AARCH64 bl plat_report_exception b SErrorA64 @@ -152,29 +139,25 @@ SErrorA64: * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ - .align 7 -SynchronousExceptionA32: +vector_entry SynchronousExceptionA32 mov x0, #SYNC_EXCEPTION_AARCH32 bl plat_report_exception b SynchronousExceptionA32 check_vector_size SynchronousExceptionA32 - .align 7 -IrqA32: +vector_entry IrqA32 mov x0, #IRQ_AARCH32 bl plat_report_exception b IrqA32 check_vector_size IrqA32 - .align 7 -FiqA32: +vector_entry FiqA32 mov x0, #FIQ_AARCH32 bl plat_report_exception b FiqA32 check_vector_size FiqA32 - .align 7 -SErrorA32: +vector_entry SErrorA32 mov x0, #SERROR_AARCH32 bl plat_report_exception b SErrorA32 diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S index dc11e0a7..799062ef 100644 --- a/bl31/aarch64/runtime_exceptions.S +++ b/bl31/aarch64/runtime_exceptions.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -161,14 +161,14 @@ interrupt_exit_\label: str x18, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0] .endm - .section .vectors, "ax"; .align 11 - .align 7 -runtime_exceptions: + +vector_base runtime_exceptions + /* ----------------------------------------------------- * Current EL with _sp_el0 : 0x0 - 0x200 * ----------------------------------------------------- */ -sync_exception_sp_el0: +vector_entry sync_exception_sp_el0 /* ----------------------------------------------------- * We don't expect any synchronous exceptions from EL3 * ----------------------------------------------------- @@ -176,23 +176,22 @@ sync_exception_sp_el0: bl report_unhandled_exception check_vector_size sync_exception_sp_el0 - .align 7 /* ----------------------------------------------------- * EL3 code is non-reentrant. Any asynchronous exception * is a serious error. Loop infinitely. * ----------------------------------------------------- */ -irq_sp_el0: +vector_entry irq_sp_el0 bl report_unhandled_interrupt check_vector_size irq_sp_el0 - .align 7 -fiq_sp_el0: + +vector_entry fiq_sp_el0 bl report_unhandled_interrupt check_vector_size fiq_sp_el0 - .align 7 -serror_sp_el0: + +vector_entry serror_sp_el0 bl report_unhandled_exception check_vector_size serror_sp_el0 @@ -200,8 +199,8 @@ serror_sp_el0: * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ - .align 7 -sync_exception_sp_elx: + +vector_entry sync_exception_sp_elx /* ----------------------------------------------------- * This exception will trigger if anything went wrong * during a previous exception entry or exit or while @@ -212,18 +211,15 @@ sync_exception_sp_elx: bl report_unhandled_exception check_vector_size sync_exception_sp_elx - .align 7 -irq_sp_elx: +vector_entry irq_sp_elx bl report_unhandled_interrupt check_vector_size irq_sp_elx - .align 7 -fiq_sp_elx: +vector_entry fiq_sp_elx bl report_unhandled_interrupt check_vector_size fiq_sp_elx - .align 7 -serror_sp_elx: +vector_entry serror_sp_elx bl report_unhandled_exception check_vector_size serror_sp_elx @@ -231,8 +227,7 @@ serror_sp_elx: * Lower EL using AArch64 : 0x400 - 0x600 * ----------------------------------------------------- */ - .align 7 -sync_exception_aarch64: +vector_entry sync_exception_aarch64 /* ----------------------------------------------------- * This exception vector will be the entry point for * SMCs and traps that are unhandled at lower ELs most @@ -244,23 +239,20 @@ sync_exception_aarch64: handle_sync_exception check_vector_size sync_exception_aarch64 - .align 7 /* ----------------------------------------------------- * Asynchronous exceptions from lower ELs are not * currently supported. Report their occurrence. * ----------------------------------------------------- */ -irq_aarch64: +vector_entry irq_aarch64 handle_interrupt_exception irq_aarch64 check_vector_size irq_aarch64 - .align 7 -fiq_aarch64: +vector_entry fiq_aarch64 handle_interrupt_exception fiq_aarch64 check_vector_size fiq_aarch64 - .align 7 -serror_aarch64: +vector_entry serror_aarch64 bl report_unhandled_exception check_vector_size serror_aarch64 @@ -268,8 +260,7 @@ serror_aarch64: * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ - .align 7 -sync_exception_aarch32: +vector_entry sync_exception_aarch32 /* ----------------------------------------------------- * This exception vector will be the entry point for * SMCs and traps that are unhandled at lower ELs most @@ -281,27 +272,23 @@ sync_exception_aarch32: handle_sync_exception check_vector_size sync_exception_aarch32 - .align 7 /* ----------------------------------------------------- * Asynchronous exceptions from lower ELs are not * currently supported. Report their occurrence. * ----------------------------------------------------- */ -irq_aarch32: +vector_entry irq_aarch32 handle_interrupt_exception irq_aarch32 check_vector_size irq_aarch32 - .align 7 -fiq_aarch32: +vector_entry fiq_aarch32 handle_interrupt_exception fiq_aarch32 check_vector_size fiq_aarch32 - .align 7 -serror_aarch32: +vector_entry serror_aarch32 bl report_unhandled_exception check_vector_size serror_aarch32 - .align 7 /* ----------------------------------------------------- * The following code handles secure monitor calls. diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S index edcfb718..20e40dfb 100644 --- a/bl32/tsp/aarch64/tsp_exceptions.S +++ b/bl32/tsp/aarch64/tsp_exceptions.S @@ -28,10 +28,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <bl_common.h> #include <arch.h> -#include <tsp.h> #include <asm_macros.S> +#include <bl_common.h> +#include <tsp.h> /* ---------------------------------------------------- @@ -98,110 +98,90 @@ interrupt_exit_\label: * TSP exception handlers. * ----------------------------------------------------- */ - .section .vectors, "ax"; .align 11 - - .align 7 -tsp_exceptions: +vector_base tsp_exceptions /* ----------------------------------------------------- - * Current EL with _sp_el0 : 0x0 - 0x180. No exceptions + * Current EL with _sp_el0 : 0x0 - 0x200. No exceptions * are expected and treated as irrecoverable errors. * ----------------------------------------------------- */ -sync_exception_sp_el0: +vector_entry sync_exception_sp_el0 bl plat_panic_handler check_vector_size sync_exception_sp_el0 - .align 7 - -irq_sp_el0: +vector_entry irq_sp_el0 bl plat_panic_handler check_vector_size irq_sp_el0 - .align 7 -fiq_sp_el0: +vector_entry fiq_sp_el0 bl plat_panic_handler check_vector_size fiq_sp_el0 - .align 7 -serror_sp_el0: +vector_entry serror_sp_el0 bl plat_panic_handler check_vector_size serror_sp_el0 /* ----------------------------------------------------- - * Current EL with SPx: 0x200 - 0x380. Only IRQs/FIQs + * Current EL with SPx: 0x200 - 0x400. Only IRQs/FIQs * are expected and handled * ----------------------------------------------------- */ - .align 7 -sync_exception_sp_elx: +vector_entry sync_exception_sp_elx bl plat_panic_handler check_vector_size sync_exception_sp_elx - .align 7 -irq_sp_elx: +vector_entry irq_sp_elx handle_tsp_interrupt irq_sp_elx check_vector_size irq_sp_elx - .align 7 -fiq_sp_elx: +vector_entry fiq_sp_elx handle_tsp_interrupt fiq_sp_elx check_vector_size fiq_sp_elx - .align 7 -serror_sp_elx: +vector_entry serror_sp_elx bl plat_panic_handler check_vector_size serror_sp_elx /* ----------------------------------------------------- - * Lower EL using AArch64 : 0x400 - 0x580. No exceptions + * Lower EL using AArch64 : 0x400 - 0x600. No exceptions * are handled since TSP does not implement a lower EL * ----------------------------------------------------- */ - .align 7 -sync_exception_aarch64: +vector_entry sync_exception_aarch64 bl plat_panic_handler check_vector_size sync_exception_aarch64 - .align 7 -irq_aarch64: +vector_entry irq_aarch64 bl plat_panic_handler check_vector_size irq_aarch64 - .align 7 -fiq_aarch64: +vector_entry fiq_aarch64 bl plat_panic_handler check_vector_size fiq_aarch64 - .align 7 -serror_aarch64: +vector_entry serror_aarch64 bl plat_panic_handler check_vector_size serror_aarch64 /* ----------------------------------------------------- - * Lower EL using AArch32 : 0x600 - 0x780. No exceptions + * Lower EL using AArch32 : 0x600 - 0x800. No exceptions * handled since the TSP does not implement a lower EL. * ----------------------------------------------------- */ - .align 7 -sync_exception_aarch32: +vector_entry sync_exception_aarch32 bl plat_panic_handler check_vector_size sync_exception_aarch32 - .align 7 -irq_aarch32: +vector_entry irq_aarch32 bl plat_panic_handler check_vector_size irq_aarch32 - .align 7 -fiq_aarch32: +vector_entry fiq_aarch32 bl plat_panic_handler check_vector_size fiq_aarch32 - .align 7 -serror_aarch32: +vector_entry serror_aarch32 bl plat_panic_handler check_vector_size serror_aarch32 - .align 7 diff --git a/common/aarch64/early_exceptions.S b/common/aarch64/early_exceptions.S index 64bfcd0f..0ef59507 100644 --- a/common/aarch64/early_exceptions.S +++ b/common/aarch64/early_exceptions.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,140 +31,122 @@ #include <asm_macros.S> #include <bl_common.h> +/* ----------------------------------------------------------------------------- + * Very simple stackless exception handlers used by BL2 and BL31 stages. + * BL31 uses them before stacks are setup. BL2 uses them throughout. + * ----------------------------------------------------------------------------- + */ .globl early_exceptions - .section .vectors, "ax"; .align 11 +vector_base early_exceptions /* ----------------------------------------------------- - * Very simple stackless exception handlers used by BL2 - * and BL31 bootloader stages. BL31 uses them before - * stacks are setup. BL2 uses them throughout. - * ----------------------------------------------------- - */ - .align 7 -early_exceptions: - /* ----------------------------------------------------- - * Current EL with SP0 : 0x0 - 0x180 + * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ -SynchronousExceptionSP0: +vector_entry SynchronousExceptionSP0 mov x0, #SYNC_EXCEPTION_SP_EL0 bl plat_report_exception b SynchronousExceptionSP0 check_vector_size SynchronousExceptionSP0 - .align 7 -IrqSP0: +vector_entry IrqSP0 mov x0, #IRQ_SP_EL0 bl plat_report_exception b IrqSP0 check_vector_size IrqSP0 - .align 7 -FiqSP0: +vector_entry FiqSP0 mov x0, #FIQ_SP_EL0 bl plat_report_exception b FiqSP0 check_vector_size FiqSP0 - .align 7 -SErrorSP0: +vector_entry SErrorSP0 mov x0, #SERROR_SP_EL0 bl plat_report_exception b SErrorSP0 check_vector_size SErrorSP0 /* ----------------------------------------------------- - * Current EL with SPx: 0x200 - 0x380 + * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ - .align 7 -SynchronousExceptionSPx: +vector_entry SynchronousExceptionSPx mov x0, #SYNC_EXCEPTION_SP_ELX bl plat_report_exception b SynchronousExceptionSPx check_vector_size SynchronousExceptionSPx - .align 7 -IrqSPx: +vector_entry IrqSPx mov x0, #IRQ_SP_ELX bl plat_report_exception b IrqSPx check_vector_size IrqSPx - .align 7 -FiqSPx: +vector_entry FiqSPx mov x0, #FIQ_SP_ELX bl plat_report_exception b FiqSPx check_vector_size FiqSPx - .align 7 -SErrorSPx: +vector_entry SErrorSPx mov x0, #SERROR_SP_ELX bl plat_report_exception b SErrorSPx check_vector_size SErrorSPx /* ----------------------------------------------------- - * Lower EL using AArch64 : 0x400 - 0x580 + * Lower EL using AArch64 : 0x400 - 0x600 * ----------------------------------------------------- */ - .align 7 -SynchronousExceptionA64: +vector_entry SynchronousExceptionA64 mov x0, #SYNC_EXCEPTION_AARCH64 bl plat_report_exception b SynchronousExceptionA64 check_vector_size SynchronousExceptionA64 - .align 7 -IrqA64: +vector_entry IrqA64 mov x0, #IRQ_AARCH64 bl plat_report_exception b IrqA64 check_vector_size IrqA64 - .align 7 -FiqA64: +vector_entry FiqA64 mov x0, #FIQ_AARCH64 bl plat_report_exception b FiqA64 check_vector_size FiqA64 - .align 7 -SErrorA64: +vector_entry SErrorA64 mov x0, #SERROR_AARCH64 bl plat_report_exception b SErrorA64 check_vector_size SErrorA64 /* ----------------------------------------------------- - * Lower EL using AArch32 : 0x0 - 0x180 + * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ - .align 7 -SynchronousExceptionA32: +vector_entry SynchronousExceptionA32 mov x0, #SYNC_EXCEPTION_AARCH32 bl plat_report_exception b SynchronousExceptionA32 check_vector_size SynchronousExceptionA32 - .align 7 -IrqA32: +vector_entry IrqA32 mov x0, #IRQ_AARCH32 bl plat_report_exception b IrqA32 check_vector_size IrqA32 - .align 7 -FiqA32: +vector_entry FiqA32 mov x0, #FIQ_AARCH32 bl plat_report_exception b FiqA32 check_vector_size FiqA32 - .align 7 -SErrorA32: +vector_entry SErrorA32 mov x0, #SERROR_AARCH32 bl plat_report_exception b SErrorA32 diff --git a/docs/porting-guide.md b/docs/porting-guide.md index 0cd36134..8947defb 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -1715,6 +1715,22 @@ latter case, the power domain is expected to save enough state so that it can resume execution by restoring this state when its powered on (see `pwr_domain_suspend_finish()`). +#### plat_psci_ops.pwr_domain_pwr_down_wfi() + +This is an optional function and, if implemented, is expected to perform +platform specific actions including the `wfi` invocation which allows the +CPU to powerdown. Since this function is invoked outside the PSCI locks, +the actions performed in this hook must be local to the CPU or the platform +must ensure that races between multiple CPUs cannot occur. + +The `target_state` has a similar meaning as described in the `pwr_domain_off()` +operation and it encodes the platform coordinated target local power states for +the CPU power domain and its parent power domain levels. This function must +not return back to the caller. + +If this function is not implemented by the platform, PSCI generic +implementation invokes `psci_power_down_wfi()` for power down. + #### plat_psci_ops.pwr_domain_on_finish() This function is called by the PSCI implementation after the calling CPU is diff --git a/docs/user-guide.md b/docs/user-guide.md index 0911eb8b..0bdedf90 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -502,6 +502,14 @@ map is explained in the [Firmware Design]. for functions that wait for an arbitrary time length (udelay and mdelay). The default value is 0. +* `FVP_INTERCONNECT_DRIVER`: Selects the interconnect driver to be built. The + default interconnect driver depends on the value of `FVP_CLUSTER_COUNT` as + explained in the options below: + - `FVP_CCI` : The CCI driver is selected. This is the default + if 0 < `FVP_CLUSTER_COUNT` <= 2. + - `FVP_CCN` : The CCN driver is selected. This is the default + if `FVP_CLUSTER_COUNT` > 2. + ### Debugging options To compile a debug version and make the build more verbose use diff --git a/drivers/arm/ccn/ccn.c b/drivers/arm/ccn/ccn.c index 28d27098..060acdd2 100644 --- a/drivers/arm/ccn/ccn.c +++ b/drivers/arm/ccn/ccn.c @@ -254,6 +254,7 @@ static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map) assert(ccn_plat_desc); FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, master_map) { + assert(iface_id < ccn_plat_desc->num_masters); /* Convert the master ID into the node ID */ node_id = ccn_plat_desc->master_to_rn_id_map[iface_id]; @@ -501,3 +502,15 @@ void ccn_program_sys_addrmap(unsigned int sn0_id, } } + +/******************************************************************************* + * This function returns the part0 id from the peripheralID 0 register + * in CCN. This id can be used to distinguish the CCN variant present in the + * system. + ******************************************************************************/ +int ccn_get_part0_id(uintptr_t periphbase) +{ + assert(periphbase); + return (int)(mmio_read_64(periphbase + + MN_PERIPH_ID_0_1_OFFSET) & 0xFF); +} diff --git a/drivers/arm/ccn/ccn_private.h b/drivers/arm/ccn/ccn_private.h index 8b154725..fffa2ca9 100644 --- a/drivers/arm/ccn/ccn_private.h +++ b/drivers/arm/ccn/ccn_private.h @@ -149,6 +149,7 @@ typedef enum rn_types { #define MN_DDC_STAT_OFFSET DOMAIN_CTRL_STAT_OFFSET #define MN_DDC_SET_OFFSET DOMAIN_CTRL_SET_OFFSET #define MN_DDC_CLR_OFFSET DOMAIN_CTRL_CLR_OFFSET +#define MN_PERIPH_ID_0_1_OFFSET 0xFE0 #define MN_ID_OFFSET REGION_ID_OFFSET /* HNF System Address Map register bit masks and shifts */ diff --git a/drivers/gpio/gpio.c b/drivers/gpio/gpio.c index c06172fc..ef6bb9c8 100644 --- a/drivers/gpio/gpio.c +++ b/drivers/gpio/gpio.c @@ -80,6 +80,26 @@ void gpio_set_value(int gpio, int value) ops->set_value(gpio, value); } +void gpio_set_pull(int gpio, int pull) +{ + assert(ops); + assert(ops->set_pull != 0); + assert((pull == GPIO_PULL_NONE) || (pull == GPIO_PULL_UP) || + (pull == GPIO_PULL_DOWN)); + assert(gpio >= 0); + + ops->set_pull(gpio, pull); +} + +int gpio_get_pull(int gpio) +{ + assert(ops); + assert(ops->get_pull != 0); + assert(gpio >= 0); + + return ops->get_pull(gpio); +} + /* * Initialize the gpio. The fields in the provided gpio * ops pointer must be valid. diff --git a/include/bl31/services/psci.h b/include/bl31/services/psci.h index acf07869..95e77809 100644 --- a/include/bl31/services/psci.h +++ b/include/bl31/services/psci.h @@ -265,6 +265,8 @@ typedef struct plat_psci_ops { void (*pwr_domain_on_finish)(const psci_power_state_t *target_state); void (*pwr_domain_suspend_finish)( const psci_power_state_t *target_state); + void (*pwr_domain_pwr_down_wfi)( + const psci_power_state_t *target_state) __dead2; void (*system_off)(void) __dead2; void (*system_reset)(void) __dead2; int (*validate_power_state)(unsigned int power_state, diff --git a/include/common/asm_macros.S b/include/common/asm_macros.S index a331c051..d4bd11ee 100644 --- a/include/common/asm_macros.S +++ b/include/common/asm_macros.S @@ -66,11 +66,36 @@ b.ne $label .endm + /* + * Declare the exception vector table, enforcing it is aligned on a + * 2KB boundary, as required by the ARMv8 architecture. + * Use zero bytes as the fill value to be stored in the padding bytes + * so that it inserts illegal AArch64 instructions. This increases + * security, robustness and potentially facilitates debugging. + */ + .macro vector_base label + .section .vectors, "ax" + .align 11, 0 + \label: + .endm + + /* + * Create an entry in the exception vector table, enforcing it is + * aligned on a 128-byte boundary, as required by the ARMv8 architecture. + * Use zero bytes as the fill value to be stored in the padding bytes + * so that it inserts illegal AArch64 instructions. This increases + * security, robustness and potentially facilitates debugging. + */ + .macro vector_entry label + .section .vectors, "ax" + .align 7, 0 + \label: + .endm /* - * This macro verifies that the a given vector doesn't exceed the + * This macro verifies that the given vector doesn't exceed the * architectural limit of 32 instructions. This is meant to be placed - * immedately after the last instruction in the vector. It takes the + * immediately after the last instruction in the vector. It takes the * vector entry as the parameter */ .macro check_vector_size since diff --git a/include/drivers/arm/ccn.h b/include/drivers/arm/ccn.h index 23615966..85c45c68 100644 --- a/include/drivers/arm/ccn.h +++ b/include/drivers/arm/ccn.h @@ -51,6 +51,13 @@ #define CCN_L3_RUN_MODE_HAM 0x2 /* HNF_PM_HALF */ #define CCN_L3_RUN_MODE_FAM 0x3 /* HNF_PM_FULL */ +/* part 0 IDs for various CCN variants */ +#define CCN_502_PART0_ID 0x30 +#define CCN_504_PART0_ID 0x26 +#define CCN_505_PART0_ID 0x27 +#define CCN_508_PART0_ID 0x28 +#define CCN_512_PART0_ID 0x29 + /* * The following macro takes the value returned from a read of a HN-F P-state * status register and returns the retention state value. @@ -107,6 +114,7 @@ void ccn_program_sys_addrmap(unsigned int sn0_id, unsigned int top_addr_bit1, unsigned char three_sn_en); unsigned int ccn_get_l3_run_mode(void); +int ccn_get_part0_id(uintptr_t periphbase); #endif /* __ASSEMBLY__ */ #endif /* __CCN_H__ */ diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h index a5cb5c7f..633b3f6b 100644 --- a/include/drivers/gpio.h +++ b/include/drivers/gpio.h @@ -37,17 +37,25 @@ #define GPIO_LEVEL_LOW 0 #define GPIO_LEVEL_HIGH 1 +#define GPIO_PULL_NONE 0 +#define GPIO_PULL_UP 1 +#define GPIO_PULL_DOWN 2 + typedef struct gpio_ops { int (*get_direction)(int gpio); void (*set_direction)(int gpio, int direction); int (*get_value)(int gpio); void (*set_value)(int gpio, int value); + void (*set_pull)(int gpio, int pull); + int (*get_pull)(int gpio); } gpio_ops_t; int gpio_get_direction(int gpio); void gpio_set_direction(int gpio, int direction); int gpio_get_value(int gpio); void gpio_set_value(int gpio, int value); +void gpio_set_pull(int gpio, int pull); +int gpio_get_pull(int gpio); void gpio_init(const gpio_ops_t *ops); #endif /* __GPIO_H__ */ diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c index 78782d43..eb67dab2 100644 --- a/plat/arm/board/fvp/fvp_common.c +++ b/plat/arm/board/fvp/fvp_common.c @@ -30,6 +30,7 @@ #include <arm_config.h> #include <arm_def.h> +#include <ccn.h> #include <debug.h> #include <gicv2.h> #include <mmio.h> @@ -213,8 +214,16 @@ void fvp_config_setup(void) void fvp_interconnect_init(void) { - if (arm_config.flags & ARM_CONFIG_HAS_INTERCONNECT) + if (arm_config.flags & ARM_CONFIG_HAS_INTERCONNECT) { +#if FVP_INTERCONNECT_DRIVER == FVP_CCN + if (ccn_get_part0_id(PLAT_ARM_CCN_BASE) != CCN_502_PART0_ID) { + ERROR("Unrecognized CCN variant detected. Only CCN-502" + " is supported"); + panic(); + } +#endif plat_arm_interconnect_init(); + } } void fvp_interconnect_enable(void) diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h index b0f07ef5..40d20fce 100644 --- a/plat/arm/board/fvp/fvp_def.h +++ b/plat/arm/board/fvp/fvp_def.h @@ -40,6 +40,10 @@ #define FVP_PRIMARY_CPU 0x0 +/* Defines for the Interconnect build selection */ +#define FVP_CCI 1 +#define FVP_CCN 2 + /******************************************************************************* * FVP memory map related constants ******************************************************************************/ @@ -57,16 +61,23 @@ #define DEVICE0_BASE 0x20000000 #define DEVICE0_SIZE 0x0c200000 +/* + * In case of FVP models with CCN, the CCN register space overlaps into + * the NSRAM area. + */ +#if FVP_INTERCONNECT_DRIVER == FVP_CCN +#define DEVICE1_BASE 0x2e000000 +#define DEVICE1_SIZE 0x1A00000 +#else #define DEVICE1_BASE 0x2f000000 #define DEVICE1_SIZE 0x200000 - +#define NSRAM_BASE 0x2e000000 +#define NSRAM_SIZE 0x10000 +#endif /* Devices in the second GB */ #define DEVICE2_BASE 0x7fe00000 #define DEVICE2_SIZE 0x00200000 -#define NSRAM_BASE 0x2e000000 -#define NSRAM_SIZE 0x10000 - #define PCIE_EXP_BASE 0x40000000 #define TZRNG_BASE 0x7fe60000 diff --git a/plat/arm/board/fvp/include/plat_macros.S b/plat/arm/board/fvp/include/plat_macros.S index e43c7acf..657a39b9 100644 --- a/plat/arm/board/fvp/include/plat_macros.S +++ b/plat/arm/board/fvp/include/plat_macros.S @@ -64,7 +64,9 @@ use_ve_mmap: mov_imm x16, VE_GICD_BASE print_gic_regs: arm_print_gic_regs +#if FVP_INTERCONNECT_DRIVER == FVP_CCI print_cci_regs +#endif .endm #endif /* __PLAT_MACROS_S__ */ diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index ca8e35e3..1e906d82 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -90,6 +90,10 @@ #define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 3 #define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 4 +/* CCN related constants. Only CCN 502 is currently supported */ +#define PLAT_ARM_CCN_BASE 0x2e000000 +#define PLAT_ARM_CLUSTER_TO_CCN_ID_MAP 1, 5, 7, 11 + /* System timer related constants */ #define PLAT_ARM_NSTIMER_FRAME_ID 1 diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index c0fe662e..6456cdea 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -39,11 +39,22 @@ $(eval $(call add_define,FVP_USE_SP804_TIMER)) # The FVP platform depends on this macro to build with correct GIC driver. $(eval $(call add_define,FVP_USE_GIC_DRIVER)) -# If FVP_CLUSTER_COUNT has been defined, pass it into the build system. -ifdef FVP_CLUSTER_COUNT +# Define default FVP_CLUSTER_COUNT to 2 and pass it into the build system. +FVP_CLUSTER_COUNT := 2 $(eval $(call add_define,FVP_CLUSTER_COUNT)) + +# Sanity check the cluster count and if FVP_CLUSTER_COUNT <= 2, +# choose the CCI driver , else the CCN driver +ifeq ($(FVP_CLUSTER_COUNT), 0) +$(error "Incorrect cluster count specified for FVP port") +else ifeq ($(FVP_CLUSTER_COUNT),$(filter $(FVP_CLUSTER_COUNT),1 2)) +FVP_INTERCONNECT_DRIVER := FVP_CCI +else +FVP_INTERCONNECT_DRIVER := FVP_CCN endif +$(eval $(call add_define,FVP_INTERCONNECT_DRIVER)) + # Choose the GIC sources depending upon the how the FVP will be invoked ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3) FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ @@ -67,8 +78,15 @@ else $(error "Incorrect GIC driver chosen on FVP port") endif +ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCI) FVP_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c \ plat/arm/common/arm_cci.c +else ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCN) +FVP_INTERCONNECT_SOURCES := drivers/arm/ccn/ccn.c \ + plat/arm/common/arm_ccn.c +else +$(error "Incorrect CCN driver chosen on FVP port") +endif FVP_SECURITY_SOURCES := drivers/arm/tzc/tzc400.c \ plat/arm/board/fvp/fvp_security.c \ diff --git a/plat/arm/common/arm_ccn.c b/plat/arm/common/arm_ccn.c index 5cb443aa..fe10d7b5 100644 --- a/plat/arm/common/arm_ccn.c +++ b/plat/arm/common/arm_ccn.c @@ -43,6 +43,9 @@ static const ccn_desc_t arm_ccn_desc = { .master_to_rn_id_map = master_to_rn_id_map }; +CASSERT(PLAT_ARM_CLUSTER_COUNT == ARRAY_SIZE(master_to_rn_id_map), + assert_invalid_cluster_count_for_ccn_variant); + /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way ARM CCN driver is initialised and used. diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c index 727a2c74..47a245a6 100644 --- a/plat/rockchip/common/bl31_plat_setup.c +++ b/plat/rockchip/common/bl31_plat_setup.c @@ -120,6 +120,9 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, * Copy the code into pmusram. */ plat_rockchip_pmusram_prepare(); + + /* there may have some board sepcific message need to initialize */ + params_early_setup(plat_params_from_bl2); } /******************************************************************************* diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h new file mode 100644 index 00000000..cad45353 --- /dev/null +++ b/plat/rockchip/common/include/plat_params.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PLAT_PARAMS_H__ +#define __PLAT_PARAMS_H__ + +#include <stdint.h> + +/* + * We defined several plat parameter structs for BL2 to pass platform related + * parameters to Rockchip BL31 platform code. All plat parameters start with + * a common header, which has a type field to indicate the parameter type, and + * a next pointer points to next parameter. If the parameter is the last one in + * the list, next pointer will points to NULL. After the header comes the + * variable-sized members that describe the parameter. The picture below shows + * how the parameters are kept in memory. + * + * head of list ---> +----------------+ --+ + * | type | | + * +----------------+ |--> struct bl31_plat_param + * +----| next | | + * | +----------------+ --+ + * | | parameter data | + * | +----------------+ + * | + * +--> +----------------+ --+ + * | type | | + * +----------------+ |--> struct bl31_plat_param + * NULL <---| next | | + * +----------------+ --+ + * | parameter data | + * +----------------+ + * + * Note: The SCTLR_EL3.A bit (Alignment fault check enable) of ARM TF is set, + * so be sure each parameter struct starts on 64-bit aligned address. If not, + * alignment fault will occur during accessing its data member. + */ + +/* param type */ +enum { + PARAM_NONE = 0, + PARAM_RESET, + PARAM_POWEROFF, +}; + +struct gpio_info { + uint8_t polarity; + uint8_t direction; + uint8_t pull_mode; + uint32_t index; +}; + +/* common header for all plat parameter type */ +struct bl31_plat_param { + uint64_t type; + void *next; +}; + +struct bl31_gpio_param { + struct bl31_plat_param h; + struct gpio_info gpio; +}; + +#endif /* __PLAT_PARAMS_H__ */ diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h index e05bda41..031a3413 100644 --- a/plat/rockchip/common/include/plat_private.h +++ b/plat/rockchip/common/include/plat_private.h @@ -97,6 +97,8 @@ void plat_cci_disable(void); void plat_delay_timer_init(void); +void params_early_setup(void *plat_params_from_bl2); + void plat_rockchip_gic_driver_init(void); void plat_rockchip_gic_init(void); void plat_rockchip_gic_cpuif_enable(void); @@ -110,6 +112,10 @@ void plat_setup_rockchip_pm_ops(struct rockchip_pm_ops_cb *ops); void platform_cpu_warmboot(void); +void *plat_get_rockchip_gpio_reset(void); +void *plat_get_rockchip_gpio_poweroff(void); +void plat_rockchip_gpio_init(void); + extern const unsigned char rockchip_power_domain_tree_desc[]; extern void *pmu_cpuson_entrypoint_start; diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c new file mode 100644 index 00000000..2a49556f --- /dev/null +++ b/plat/rockchip/common/params_setup.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arm_gic.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <debug.h> +#include <gpio.h> +#include <mmio.h> +#include <platform.h> +#include <plat_params.h> +#include <plat_private.h> +#include <string.h> + +static struct bl31_plat_param *bl31_params_head; +static struct bl31_gpio_param param_reset; +static struct bl31_gpio_param param_poweroff; +static struct gpio_info *rst_gpio; +static struct gpio_info *poweroff_gpio; + +void *plat_get_rockchip_gpio_reset(void) +{ + return rst_gpio; +} + +void *plat_get_rockchip_gpio_poweroff(void) +{ + return poweroff_gpio; +} + +void params_early_setup(void *plat_param_from_bl2) +{ + struct bl31_plat_param *param; + struct bl31_plat_param *bl2_param; + struct bl31_gpio_param *gpio_param; + + /* keep plat parameters for later processing if need */ + bl2_param = (struct bl31_plat_param *)plat_param_from_bl2; + while (bl2_param) { + switch (bl2_param->type) { + case PARAM_RESET: + param = (struct bl31_plat_param *)¶m_reset; + memcpy((void *)param, (void *)bl2_param, + sizeof(struct bl31_gpio_param)); + gpio_param = (struct bl31_gpio_param *)param; + rst_gpio = &gpio_param->gpio; + break; + case PARAM_POWEROFF: + param = (struct bl31_plat_param *)¶m_poweroff; + memcpy((void *)param, (void *)bl2_param, + sizeof(struct bl31_gpio_param)); + gpio_param = (struct bl31_gpio_param *)param; + poweroff_gpio = &gpio_param->gpio; + break; + default: + NOTICE("not expected type found\n"); + return; /* don't continue if unexpected type found */ + } + param->next = bl31_params_head; + bl31_params_head = param; + bl2_param = bl2_param->next; + } +} diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c index 43558b65..d20a683b 100644 --- a/plat/rockchip/common/plat_pm.c +++ b/plat/rockchip/common/plat_pm.c @@ -253,6 +253,16 @@ static void __dead2 rockchip_system_reset(void) } /******************************************************************************* + * RockChip handlers to power off the system + ******************************************************************************/ +static void __dead2 rockchip_system_poweroff(void) +{ + assert(rockchip_ops && rockchip_ops->system_off); + + rockchip_ops->system_off(); +} + +/******************************************************************************* * Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip * standard * platform layer will take care of registering the handlers with PSCI. @@ -265,6 +275,7 @@ const plat_psci_ops_t plat_rockchip_psci_pm_ops = { .pwr_domain_on_finish = rockchip_pwr_domain_on_finish, .pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish, .system_reset = rockchip_system_reset, + .system_off = rockchip_system_poweroff, .validate_power_state = rockchip_validate_power_state, .get_sys_suspend_power_state = rockchip_get_sys_suspend_power_state }; diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk index 0e64b7e8..50eda322 100644 --- a/plat/rockchip/rk3368/platform.mk +++ b/plat/rockchip/rk3368/platform.mk @@ -63,6 +63,7 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ plat/common/aarch64/platform_mp_stack.S \ ${RK_PLAT_COMMON}/aarch64/plat_helpers.S \ ${RK_PLAT_COMMON}/bl31_plat_setup.c \ + ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S \ ${RK_PLAT_COMMON}/pmusram/pmu_sram.c \ ${RK_PLAT_COMMON}/plat_pm.c \ diff --git a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c new file mode 100644 index 00000000..eca9fbcc --- /dev/null +++ b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <assert.h> +#include <debug.h> +#include <delay_timer.h> +#include <errno.h> +#include <gpio.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <plat_private.h> +#include <soc.h> + +uint32_t gpio_port[] = { + GPIO0_BASE, + GPIO1_BASE, + GPIO2_BASE, + GPIO3_BASE, + GPIO4_BASE, +}; + +#define SWPORTA_DR 0x00 +#define SWPORTA_DDR 0x04 +#define EXT_PORTA 0x50 + +#define PMU_GPIO_PORT0 0 +#define PMU_GPIO_PORT1 1 + +#define PMU_GRF_GPIO0A_P 0x40 +#define GRF_GPIO2A_P 0xe040 +#define GPIO_P_MASK 0x03 + +/* + * gpio clock disabled when not operate + * so need to enable gpio clock before operate gpio + * after setting, need to disable gpio clock + * gate 1: disable clock; 0: enable clock + */ +static void gpio_clk(int gpio, uint32_t gate) +{ + uint32_t port = gpio / 32; + + assert(port < 5); + + switch (port) { + case 0: + mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), + BITS_WITH_WMASK(gate, CLK_GATE_MASK, + PCLK_GPIO0_GATE_SHIFT)); + break; + case 1: + mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), + BITS_WITH_WMASK(gate, CLK_GATE_MASK, + PCLK_GPIO1_GATE_SHIFT)); + break; + case 2: + mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), + BITS_WITH_WMASK(gate, CLK_GATE_MASK, + PCLK_GPIO2_GATE_SHIFT)); + break; + case 3: + mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), + BITS_WITH_WMASK(gate, CLK_GATE_MASK, + PCLK_GPIO3_GATE_SHIFT)); + + break; + case 4: + mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), + BITS_WITH_WMASK(gate, CLK_GATE_MASK, + PCLK_GPIO4_GATE_SHIFT)); + break; + default: + break; + } +} + +static void set_pull(int gpio, int pull) +{ + uint32_t port = gpio / 32; + uint32_t num = gpio % 32; + uint32_t bank = num / 8; + uint32_t id = num % 8; + + assert((port < 5) && (num < 32)); + + gpio_clk(gpio, 0); + + /* + * in gpio0a, gpio0b, gpio2c, gpio2d, + * 00: Z + * 01: pull down + * 10: Z + * 11: pull up + * different with other gpio, so need to correct it + */ + if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 2))) { + if (pull == GPIO_PULL_UP) + pull = 3; + else if (pull == GPIO_PULL_DOWN) + pull = 1; + else + pull = 0; + } + + if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { + mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + + port * 16 + bank * 4, + BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); + } else { + mmio_write_32(GRF_BASE + GRF_GPIO2A_P + + (port - 2) * 16 + bank * 4, + BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); + } + gpio_clk(gpio, 1); +} + +static void set_direction(int gpio, int direction) +{ + uint32_t port = gpio / 32; + uint32_t num = gpio % 32; + + assert((port < 5) && (num < 32)); + + gpio_clk(gpio, 0); + + /* + * in gpio.h + * #define GPIO_DIR_OUT 0 + * #define GPIO_DIR_IN 1 + * but rk3399 gpio direction 1: output, 0: input + * so need to revert direction value + */ + mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); + gpio_clk(gpio, 1); +} + +static int get_direction(int gpio) +{ + uint32_t port = gpio / 32; + uint32_t num = gpio % 32; + int direction; + + assert((port < 5) && (num < 32)); + + gpio_clk(gpio, 0); + + /* + * in gpio.h + * #define GPIO_DIR_OUT 0 + * #define GPIO_DIR_IN 1 + * but rk3399 gpio direction 1: output, 0: input + * so need to revert direction value + */ + direction = !((mmio_read_32(gpio_port[port] + + SWPORTA_DDR) >> num) & 0x1); + gpio_clk(gpio, 1); + + return direction; +} + +static int get_value(int gpio) +{ + uint32_t port = gpio / 32; + uint32_t num = gpio % 32; + int value; + + assert((port < 5) && (num < 32)); + + gpio_clk(gpio, 0); + value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; + gpio_clk(gpio, 1); + + return value; +} + +static void set_value(int gpio, int value) +{ + uint32_t port = gpio / 32; + uint32_t num = gpio % 32; + + assert((port < 5) && (num < 32)); + + gpio_clk(gpio, 0); + mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, + !!value << num); + gpio_clk(gpio, 0); +} + +const gpio_ops_t rk3399_gpio_ops = { + .get_direction = get_direction, + .set_direction = set_direction, + .get_value = get_value, + .set_value = set_value, + .set_pull = set_pull, +}; + +void plat_rockchip_gpio_init(void) +{ + gpio_init(&rk3399_gpio_ops); +} diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c index 859e89f5..9b95621f 100644 --- a/plat/rockchip/rk3399/drivers/pmu/pmu.c +++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c @@ -34,9 +34,11 @@ #include <debug.h> #include <delay_timer.h> #include <errno.h> +#include <gpio.h> #include <mmio.h> #include <platform.h> #include <platform_def.h> +#include <plat_params.h> #include <plat_private.h> #include <rk3399_def.h> #include <pmu_sram.h> @@ -384,6 +386,48 @@ static int sys_pwr_domain_resume(void) return 0; } +void __dead2 soc_soft_reset(void) +{ + struct gpio_info *rst_gpio; + + rst_gpio = (struct gpio_info *)plat_get_rockchip_gpio_reset(); + + if (rst_gpio) { + gpio_set_direction(rst_gpio->index, GPIO_DIR_OUT); + gpio_set_value(rst_gpio->index, rst_gpio->polarity); + } else { + soc_global_soft_reset(); + } + + while (1) + ; +} + +void __dead2 soc_system_off(void) +{ + struct gpio_info *poweroff_gpio; + + poweroff_gpio = (struct gpio_info *)plat_get_rockchip_gpio_poweroff(); + + if (poweroff_gpio) { + /* + * if use tsadc over temp pin(GPIO1A6) as shutdown gpio, + * need to set this pin iomux back to gpio function + */ + if (poweroff_gpio->index == TSADC_INT_PIN) { + mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1A_IOMUX, + GPIO1A6_IOMUX); + } + gpio_set_direction(poweroff_gpio->index, GPIO_DIR_OUT); + gpio_set_value(poweroff_gpio->index, poweroff_gpio->polarity); + } else { + WARN("Do nothing when system off\n"); + } + + while (1) + ; +} + static struct rockchip_pm_ops_cb pm_ops = { .cores_pwr_dm_on = cores_pwr_domain_on, .cores_pwr_dm_off = cores_pwr_domain_off, @@ -392,7 +436,8 @@ static struct rockchip_pm_ops_cb pm_ops = { .cores_pwr_dm_resume = cores_pwr_domain_resume, .sys_pwr_dm_suspend = sys_pwr_domain_suspend, .sys_pwr_dm_resume = sys_pwr_domain_resume, - .sys_gbl_soft_reset = soc_global_soft_reset, + .sys_gbl_soft_reset = soc_soft_reset, + .system_off = soc_system_off, }; void plat_rockchip_pmu_init(void) diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h index d5ff8ce0..8f935e98 100644 --- a/plat/rockchip/rk3399/drivers/pmu/pmu.h +++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h @@ -810,6 +810,8 @@ enum pmu_core_pwr_st { #define PMUGRF_GPIO1A_IOMUX 0x10 #define AP_PWROFF 0x0a +#define GPIO1A6_IOMUX BITS_WITH_WMASK(0, 3, 12) +#define TSADC_INT_PIN 38 #define CORES_PM_DISABLE 0x0 #define PD_CTR_LOOP 500 diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c index 5b7613d7..bf2d4413 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.c +++ b/plat/rockchip/rk3399/drivers/soc/soc.c @@ -57,7 +57,18 @@ const mmap_region_t plat_rk_mmap[] = { MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMUGRF_BASE, PMUGRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), - + MAP_REGION_FLAT(GPIO0_BASE, GPIO0_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(GPIO1_BASE, GPIO1_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(GPIO2_BASE, GPIO2_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(GPIO3_BASE, GPIO3_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(GPIO4_BASE, GPIO4_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(GRF_BASE, GRF_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; @@ -349,4 +360,5 @@ void plat_rockchip_soc_init(void) dma_secure_cfg(0); sgrf_init(); soc_global_soft_reset_init(); + plat_rockchip_gpio_init(); } diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h index e48f2f03..4c6f0001 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.h +++ b/plat/rockchip/rk3399/drivers/soc/soc.h @@ -72,6 +72,8 @@ #define REG_SIZE 0x04 #define REG_SOC_WMSK 0xffff0000 +#define CLK_GATE_MASK 0x01 + enum plls_id { ALPLL_ID = 0, ABPLL_ID, @@ -152,6 +154,11 @@ struct deepsleep_data_s { #define CRU_GLB_SRST_FST 0x0500 #define CRU_GLB_SRST_SND 0x0504 +#define CRU_CLKGATE_CON(n) (0x300 + n * 4) +#define PCLK_GPIO2_GATE_SHIFT 3 +#define PCLK_GPIO3_GATE_SHIFT 4 +#define PCLK_GPIO4_GATE_SHIFT 5 + /************************************************** * pmu cru reg, offset **************************************************/ @@ -167,6 +174,10 @@ struct deepsleep_data_s { #define CRU_PMU_FIRST_SFTRST_MSK (0x3 << 2) #define CRU_PMU_FIRST_SFTRST_EN 0x0 +#define CRU_PMU_CLKGATE_CON(n) (0x100 + n * 4) +#define PCLK_GPIO0_GATE_SHIFT 3 +#define PCLK_GPIO1_GATE_SHIFT 4 + /************************************************** * sgrf reg, offset **************************************************/ diff --git a/plat/rockchip/rk3399/include/platform_def.h b/plat/rockchip/rk3399/include/platform_def.h index f7da0e70..5f04db92 100644 --- a/plat/rockchip/rk3399/include/platform_def.h +++ b/plat/rockchip/rk3399/include/platform_def.h @@ -109,7 +109,7 @@ ******************************************************************************/ #define ADDR_SPACE_SIZE (1ull << 32) #define MAX_XLAT_TABLES 20 -#define MAX_MMAP_REGIONS 16 +#define MAX_MMAP_REGIONS 20 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index 45064e7f..b0ce56f3 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -58,16 +58,19 @@ BL31_SOURCES += ${RK_GIC_SOURCES} drivers/ti/uart/16550_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ + drivers/gpio/gpio.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ plat/common/aarch64/platform_mp_stack.S \ ${RK_PLAT_COMMON}/aarch64/plat_helpers.S \ ${RK_PLAT_COMMON}/bl31_plat_setup.c \ + ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S \ ${RK_PLAT_COMMON}/pmusram/pmu_sram.c \ ${RK_PLAT_COMMON}/plat_pm.c \ ${RK_PLAT_COMMON}/plat_topology.c \ ${RK_PLAT_COMMON}/aarch64/platform_common.c \ + ${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h index b1fc1e6a..ed3a4243 100644 --- a/plat/rockchip/rk3399/rk3399_def.h +++ b/plat/rockchip/rk3399/rk3399_def.h @@ -64,6 +64,24 @@ #define PMUGRF_BASE 0xff320000 #define PMUGRF_SIZE SIZE_K(64) +#define GPIO0_BASE 0xff720000 +#define GPIO0_SIZE SIZE_K(64) + +#define GPIO1_BASE 0xff730000 +#define GPIO1_SIZE SIZE_K(64) + +#define GPIO2_BASE 0xff780000 +#define GPIO2_SIZE SIZE_K(32) + +#define GPIO3_BASE 0xff788000 +#define GPIO3_SIZE SIZE_K(32) + +#define GPIO4_BASE 0xff790000 +#define GPIO4_SIZE SIZE_K(32) + +#define GRF_BASE 0xff770000 +#define GRF_SIZE SIZE_K(64) + /* * include i2c pmu/audio, pwm0-3 rkpwm0-3 uart_dbg,mailbox scr * 0xff650000 -0xff6c0000 diff --git a/services/std_svc/psci/psci_entry.S b/services/std_svc/psci/psci_entry.S index 5f4f91c5..f8c0afa2 100644 --- a/services/std_svc/psci/psci_entry.S +++ b/services/std_svc/psci/psci_entry.S @@ -106,7 +106,6 @@ endfunc psci_entrypoint func psci_power_down_wfi dsb sy // ensure write buffer empty wfi -wfi_spill: - b wfi_spill + bl plat_panic_handler endfunc psci_power_down_wfi diff --git a/services/std_svc/psci/psci_off.c b/services/std_svc/psci/psci_off.c index cef66689..686666d5 100644 --- a/services/std_svc/psci/psci_off.c +++ b/services/std_svc/psci/psci_off.c @@ -138,11 +138,16 @@ exit: dsbish(); inv_cpu_data(psci_svc_cpu_data.aff_info_state); - /* - * Enter a wfi loop which will allow the power controller to - * physically power down this cpu. - */ - psci_power_down_wfi(); + if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi) { + /* This function must not return */ + psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info); + } else { + /* + * Enter a wfi loop which will allow the power + * controller to physically power down this cpu. + */ + psci_power_down_wfi(); + } } return rc; diff --git a/services/std_svc/psci/psci_suspend.c b/services/std_svc/psci/psci_suspend.c index 367bb32a..8c6ab6b4 100644 --- a/services/std_svc/psci/psci_suspend.c +++ b/services/std_svc/psci/psci_suspend.c @@ -189,8 +189,13 @@ exit: if (skip_wfi) return; - if (is_power_down_state) - psci_power_down_wfi(); + if (is_power_down_state) { + /* The function calls below must not return */ + if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi) + psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info); + else + psci_power_down_wfi(); + } /* * We will reach here if only retention/standby states have been |