Merge pull request #711 from leon-chen-mtk/mt6795_2
Remove MT6795 plat_sip_svc.c to fix Coverity analysis error.
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index 68cad2e..90ce4b1 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -716,7 +716,7 @@
|`PSCI_FEATURES` | Yes | |
|`CPU_FREEZE` | No | |
|`CPU_DEFAULT_SUSPEND` | No | |
-|`CPU_HW_STATE` | No | |
+|`NODE_HW_STATE` | Yes* | |
|`SYSTEM_SUSPEND` | Yes* | |
|`PSCI_SET_SUSPEND_MODE`| No | |
|`PSCI_STAT_RESIDENCY` | Yes* | |
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index 8dad4a0..195c937 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -1832,6 +1832,20 @@
power state encoding for `power_state` parameter of PSCI_STAT_COUNT/RESIDENCY
APIs as described in Section 5.18 of [PSCI].
+#### plat_psci_ops.get_node_hw_state()
+
+This is an optional function. If implemented this function is intended to return
+the power state of a node (identified by the first parameter, the `MPIDR`) in
+the power domain topology (identified by the second parameter, `power_level`),
+as retrieved from a power controller or equivalent component on the platform.
+Upon successful completion, the implementation must map and return the final
+status among `HW_ON`, `HW_OFF` or `HW_STANDBY`. Upon encountering failures, it
+must return either `PSCI_E_INVALID_PARAMS` or `PSCI_E_NOT_SUPPORTED` as
+appropriate.
+
+Implementations are not expected to handle `power_levels` greater than
+`PLAT_MAX_PWR_LVL`.
+
3.6 Interrupt Management framework (in BL31)
----------------------------------------------
BL31 implements an Interrupt Management Framework (IMF) to manage interrupts
diff --git a/docs/user-guide.md b/docs/user-guide.md
index a6959b1..d545262 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -64,7 +64,7 @@
Install the required packages to build Trusted Firmware with the following
command:
- sudo apt-get install build-essential gcc make git
+ sudo apt-get install build-essential gcc make git libssl-dev
Download and install the AArch64 little-endian GCC cross compiler as indicated
in the [Linaro instructions][Linaro SW Instructions].
@@ -74,8 +74,6 @@
* `device-tree-compiler` package if you need to rebuild the Flattened Device
Tree (FDT) source files (`.dts` files) provided with this software.
-* `libssl-dev` package if Trusted Board Boot is enabled in the build.
-
* For debugging, ARM [Development Studio 5 (DS-5)][DS-5].
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index d13e2c9..ac43372 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -120,10 +120,12 @@
******************************************************************************/
void gicv3_distif_init(void)
{
+ unsigned int bitmap = 0;
+
assert(driver_data);
assert(driver_data->gicd_base);
- assert(driver_data->g1s_interrupt_array);
- assert(driver_data->g0_interrupt_array);
+ assert(driver_data->g1s_interrupt_array ||
+ driver_data->g0_interrupt_array);
assert(IS_IN_EL3());
@@ -146,21 +148,25 @@
gicv3_spis_configure_defaults(driver_data->gicd_base);
/* Configure the G1S SPIs */
- gicv3_secure_spis_configure(driver_data->gicd_base,
+ if (driver_data->g1s_interrupt_array) {
+ gicv3_secure_spis_configure(driver_data->gicd_base,
driver_data->g1s_interrupt_num,
driver_data->g1s_interrupt_array,
INTR_GROUP1S);
+ bitmap |= CTLR_ENABLE_G1S_BIT;
+ }
/* Configure the G0 SPIs */
- gicv3_secure_spis_configure(driver_data->gicd_base,
+ if (driver_data->g0_interrupt_array) {
+ gicv3_secure_spis_configure(driver_data->gicd_base,
driver_data->g0_interrupt_num,
driver_data->g0_interrupt_array,
INTR_GROUP0);
+ bitmap |= CTLR_ENABLE_G0_BIT;
+ }
/* Enable the secure SPIs now that they have been configured */
- gicd_set_ctlr(driver_data->gicd_base,
- CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G0_BIT,
- RWP_TRUE);
+ gicd_set_ctlr(driver_data->gicd_base, bitmap, RWP_TRUE);
}
/*******************************************************************************
@@ -177,8 +183,8 @@
assert(driver_data->rdistif_base_addrs);
assert(driver_data->gicd_base);
assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT);
- assert(driver_data->g1s_interrupt_array);
- assert(driver_data->g0_interrupt_array);
+ assert(driver_data->g1s_interrupt_array ||
+ driver_data->g0_interrupt_array);
assert(IS_IN_EL3());
@@ -188,16 +194,20 @@
gicv3_ppi_sgi_configure_defaults(gicr_base);
/* Configure the G1S SGIs/PPIs */
- gicv3_secure_ppi_sgi_configure(gicr_base,
- driver_data->g1s_interrupt_num,
- driver_data->g1s_interrupt_array,
- INTR_GROUP1S);
+ if (driver_data->g1s_interrupt_array) {
+ gicv3_secure_ppi_sgi_configure(gicr_base,
+ driver_data->g1s_interrupt_num,
+ driver_data->g1s_interrupt_array,
+ INTR_GROUP1S);
+ }
/* Configure the G0 SGIs/PPIs */
- gicv3_secure_ppi_sgi_configure(gicr_base,
- driver_data->g0_interrupt_num,
- driver_data->g0_interrupt_array,
- INTR_GROUP0);
+ if (driver_data->g0_interrupt_array) {
+ gicv3_secure_ppi_sgi_configure(gicr_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array,
+ INTR_GROUP0);
+ }
}
/*******************************************************************************
diff --git a/include/lib/pmf/pmf_asm_macros.S b/include/lib/pmf/pmf_asm_macros.S
index 42dcd79..be7338b 100644
--- a/include/lib/pmf/pmf_asm_macros.S
+++ b/include/lib/pmf/pmf_asm_macros.S
@@ -34,12 +34,11 @@
#define PMF_TS_SIZE 8
/*
- * This macro calculates the offset into the memory
- * region where the per-cpu timestamp value is stored
- * for the given service name and timestamp id.
+ * This macro calculates the address of the per-cpu timestamp
+ * for the given service name and local timestamp id.
* Clobbers: x0 - x9
*/
- .macro pmf_calc_timestamp_offset _name _tid
+ .macro pmf_calc_timestamp_addr _name _tid
mov x9, x30
bl plat_my_core_pos
mov x30, x9
diff --git a/include/lib/pmf/pmf_helpers.h b/include/lib/pmf/pmf_helpers.h
index 9be6050..bb4242c 100644
--- a/include/lib/pmf/pmf_helpers.h
+++ b/include/lib/pmf/pmf_helpers.h
@@ -71,7 +71,9 @@
*/
#define PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _total_id) \
unsigned long long pmf_ts_mem_ ## _name[_total_id] \
- __section("pmf_timestamp_array") __used;
+ __aligned(CACHE_WRITEBACK_GRANULE) \
+ __section("pmf_timestamp_array") \
+ __used;
/*
* Convenience macro to validate tid index for the given TS array.
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index a583fef..02cbbf3 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -78,6 +78,8 @@
#define PSCI_SYSTEM_OFF 0x84000008
#define PSCI_SYSTEM_RESET 0x84000009
#define PSCI_FEATURES 0x8400000A
+#define PSCI_NODE_HW_STATE_AARCH32 0x8400000d
+#define PSCI_NODE_HW_STATE_AARCH64 0xc400000d
#define PSCI_SYSTEM_SUSPEND_AARCH32 0x8400000E
#define PSCI_SYSTEM_SUSPEND_AARCH64 0xc400000E
#define PSCI_STAT_RESIDENCY_AARCH32 0x84000010
@@ -200,6 +202,17 @@
} aff_info_state_t;
/*
+ * These are the power states reported by PSCI_NODE_HW_STATE API for the
+ * specified CPU. The definitions of these states can be found in Section 5.15.3
+ * of PSCI specification (ARM DEN 0022C).
+ */
+typedef enum {
+ HW_ON = 0,
+ HW_OFF = 1,
+ HW_STANDBY = 2
+} node_hw_state_t;
+
+/*
* Macro to represent invalid affinity level within PSCI.
*/
#define PSCI_INVALID_PWR_LVL (PLAT_MAX_PWR_LVL + 1)
@@ -293,6 +306,7 @@
int (*translate_power_state_by_mpidr)(u_register_t mpidr,
unsigned int power_state,
psci_power_state_t *output_state);
+ int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
} plat_psci_ops_t;
/*******************************************************************************
@@ -330,6 +344,8 @@
int psci_migrate(u_register_t target_cpu);
int psci_migrate_info_type(void);
long psci_migrate_info_up_cpu(void);
+int psci_node_hw_state(u_register_t target_cpu,
+ unsigned int power_level);
int psci_features(unsigned int psci_fid);
void __dead2 psci_power_down_wfi(void);
void psci_arch_setup(void);
diff --git a/include/lib/xlat_tables.h b/include/lib/xlat_tables.h
index d2ac6db..0e9800a 100644
--- a/include/lib/xlat_tables.h
+++ b/include/lib/xlat_tables.h
@@ -32,13 +32,27 @@
#define __XLAT_TABLES_H__
/* Miscellaneous MMU related constants */
+#define NUM_2MB_IN_GB (1 << 9)
+#define NUM_4K_IN_2MB (1 << 9)
+#define NUM_GB_IN_4GB (1 << 2)
+
+#define TWO_MB_SHIFT 21
+#define ONE_GB_SHIFT 30
#define FOUR_KB_SHIFT 12
+#define ONE_GB_INDEX(x) ((x) >> ONE_GB_SHIFT)
+#define TWO_MB_INDEX(x) ((x) >> TWO_MB_SHIFT)
+#define FOUR_KB_INDEX(x) ((x) >> FOUR_KB_SHIFT)
+
#define INVALID_DESC 0x0
#define BLOCK_DESC 0x1 /* Table levels 0-2 */
#define TABLE_DESC 0x3 /* Table levels 0-2 */
#define PAGE_DESC 0x3 /* Table level 3 */
+#define FIRST_LEVEL_DESC_N ONE_GB_SHIFT
+#define SECOND_LEVEL_DESC_N TWO_MB_SHIFT
+#define THIRD_LEVEL_DESC_N FOUR_KB_SHIFT
+
#define XN (1ull << 2)
#define PXN (1ull << 1)
#define CONT_HINT (1ull << 0)
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 25aab24..d2e8729 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -37,6 +37,12 @@
#include <utils.h>
#include <xlat_tables.h>
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+struct bl31_params;
+struct meminfo;
+
#define ARM_CASSERT_MMAP \
CASSERT((ARRAY_SIZE(plat_arm_mmap) + ARM_BL_REGIONS) \
<= MAX_MMAP_REGIONS, \
@@ -145,7 +151,7 @@
void arm_bl1_plat_arch_setup(void);
/* BL2 utility functions */
-void arm_bl2_early_platform_setup(meminfo_t *mem_layout);
+void arm_bl2_early_platform_setup(struct meminfo *mem_layout);
void arm_bl2_platform_setup(void);
void arm_bl2_plat_arch_setup(void);
uint32_t arm_get_spsr_for_bl32_entry(void);
@@ -158,7 +164,7 @@
void arm_bl2u_plat_arch_setup(void);
/* BL31 utility functions */
-void arm_bl31_early_platform_setup(bl31_params_t *from_bl2,
+void arm_bl31_early_platform_setup(struct bl31_params *from_bl2,
void *plat_params_from_bl2);
void arm_bl31_platform_setup(void);
void arm_bl31_plat_runtime_setup(void);
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
index 636daf2..173de1b 100644
--- a/include/plat/arm/css/common/css_def.h
+++ b/include/plat/arm/css/common/css_def.h
@@ -148,5 +148,15 @@
/* Trusted mailbox base address common to all CSS */
#define PLAT_ARM_TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE
+/*
+ * Parsing of CPU and Cluster states, as returned by 'Get CSS Power State' SCP
+ * command
+ */
+#define CSS_CLUSTER_PWR_STATE_ON 0
+#define CSS_CLUSTER_PWR_STATE_OFF 3
+
+#define CSS_CPU_PWR_STATE_ON 1
+#define CSS_CPU_PWR_STATE_OFF 0
+#define CSS_CPU_PWR_STATE(state, n) (((state) >> (n)) & 1)
#endif /* __CSS_DEF_H__ */
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
index ea6a5d2..4a6ca81 100644
--- a/include/plat/arm/css/common/css_pm.h
+++ b/include/plat/arm/css/common/css_pm.h
@@ -45,5 +45,6 @@
void __dead2 css_system_reset(void);
void css_cpu_standby(plat_local_state_t cpu_state);
void css_get_sys_suspend_power_state(psci_power_state_t *req_state);
+int css_node_hw_state(u_register_t mpidr, unsigned int power_level);
#endif /* __CSS_PM_H__ */
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 3ad3dd4..23bd106 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -295,6 +295,31 @@
return resident_cpu_mpidr;
}
+int psci_node_hw_state(u_register_t target_cpu,
+ unsigned int power_level)
+{
+ int rc;
+
+ /* Validate target_cpu */
+ rc = psci_validate_mpidr(target_cpu);
+ if (rc != PSCI_E_SUCCESS)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Validate power_level against PLAT_MAX_PWR_LVL */
+ if (power_level > PLAT_MAX_PWR_LVL)
+ return PSCI_E_INVALID_PARAMS;
+
+ /*
+ * Dispatch this call to platform to query power controller, and pass on
+ * to the caller what it returns
+ */
+ assert(psci_plat_pm_ops->get_node_hw_state);
+ rc = psci_plat_pm_ops->get_node_hw_state(target_cpu, power_level);
+ assert((rc >= HW_ON && rc <= HW_STANDBY) || rc == PSCI_E_NOT_SUPPORTED
+ || rc == PSCI_E_INVALID_PARAMS);
+ return rc;
+}
+
int psci_features(unsigned int psci_fid)
{
unsigned int local_caps = psci_caps;
@@ -378,6 +403,9 @@
case PSCI_MIG_INFO_UP_CPU_AARCH32:
return psci_migrate_info_up_cpu();
+ case PSCI_NODE_HW_STATE_AARCH32:
+ return psci_node_hw_state(x1, x2);
+
case PSCI_SYSTEM_SUSPEND_AARCH32:
return psci_system_suspend(x1, x2);
@@ -422,6 +450,9 @@
case PSCI_MIG_INFO_UP_CPU_AARCH64:
return psci_migrate_info_up_cpu();
+ case PSCI_NODE_HW_STATE_AARCH64:
+ return psci_node_hw_state(x1, x2);
+
case PSCI_SYSTEM_SUSPEND_AARCH64:
return psci_system_suspend(x1, x2);
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index b795c8e..781b3b5 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -68,6 +68,7 @@
define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \
define_psci_cap(PSCI_MIG_AARCH64) | \
define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) | \
+ define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) | \
define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \
define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \
define_psci_cap(PSCI_STAT_COUNT_AARCH64))
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 20d0635..263ab68 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -238,6 +238,13 @@
plat_setup_psci_ops(mailbox_ep, &psci_plat_pm_ops);
assert(psci_plat_pm_ops);
+ /*
+ * Flush `psci_plat_pm_ops` as it will be accessed by secondary CPUs
+ * during warm boot before data cache is enabled.
+ */
+ flush_dcache_range((uintptr_t)&psci_plat_pm_ops,
+ sizeof(psci_plat_pm_ops));
+
/* Initialize the psci capability */
psci_caps = PSCI_GENERIC_CAP;
@@ -256,6 +263,8 @@
psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF);
if (psci_plat_pm_ops->system_reset)
psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
+ if (psci_plat_pm_ops->get_node_hw_state)
+ psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
#if ENABLE_PSCI_STAT
psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 3976ef2..66c0c3d 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -287,6 +287,42 @@
panic();
}
+static int fvp_node_hw_state(u_register_t target_cpu,
+ unsigned int power_level)
+{
+ unsigned int psysr;
+ int ret;
+
+ /*
+ * The format of 'power_level' is implementation-defined, but 0 must
+ * mean a CPU. We also allow 1 to denote the cluster
+ */
+ if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
+ return PSCI_E_INVALID_PARAMS;
+
+ /*
+ * Read the status of the given MPDIR from FVP power controller. The
+ * power controller only gives us on/off status, so map that to expected
+ * return values of the PSCI call
+ */
+ psysr = fvp_pwrc_read_psysr(target_cpu);
+ if (psysr == PSYSR_INVALID)
+ return PSCI_E_INVALID_PARAMS;
+
+ switch (power_level) {
+ case ARM_PWR_LVL0:
+ ret = (psysr & PSYSR_AFF_L0) ? HW_ON : HW_OFF;
+ break;
+ case ARM_PWR_LVL1:
+ ret = (psysr & PSYSR_AFF_L1) ? HW_ON : HW_OFF;
+ break;
+ default:
+ assert(0);
+ }
+
+ return ret;
+}
+
/*******************************************************************************
* Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
* platform layer will take care of registering the handlers with PSCI.
@@ -301,5 +337,6 @@
.system_off = fvp_system_off,
.system_reset = fvp_system_reset,
.validate_power_state = arm_validate_power_state,
- .validate_ns_entrypoint = arm_validate_ns_entrypoint
+ .validate_ns_entrypoint = arm_validate_ns_entrypoint,
+ .get_node_hw_state = fvp_node_hw_state
};
diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c
index cbf994a..c355d94 100644
--- a/plat/arm/board/juno/juno_pm.c
+++ b/plat/arm/board/juno/juno_pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-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:
@@ -88,5 +88,6 @@
.validate_power_state = juno_validate_power_state,
.validate_ns_entrypoint = arm_validate_ns_entrypoint,
.get_sys_suspend_power_state = css_get_sys_suspend_power_state,
- .translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr
+ .translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr,
+ .get_node_hw_state = css_node_hw_state
};
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 801d937..7607f61 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -299,6 +299,43 @@
}
/*******************************************************************************
+ * Handler to query CPU/cluster power states from SCP
+ ******************************************************************************/
+int css_node_hw_state(u_register_t mpidr, unsigned int power_level)
+{
+ int rc, element;
+ unsigned int cpu_state, cluster_state;
+
+ /*
+ * The format of 'power_level' is implementation-defined, but 0 must
+ * mean a CPU. We also allow 1 to denote the cluster
+ */
+ if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Query SCP */
+ rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
+ if (rc != 0)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Map power states of CPU and cluster to expected PSCI return codes */
+ if (power_level == ARM_PWR_LVL0) {
+ /*
+ * The CPU state returned by SCP is an 8-bit bit mask
+ * corresponding to each CPU in the cluster
+ */
+ element = mpidr & MPIDR_AFFLVL_MASK;
+ return CSS_CPU_PWR_STATE(cpu_state, element) ==
+ CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
+ } else {
+ assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
+ cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
+ return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
+ HW_OFF;
+ }
+}
+
+/*******************************************************************************
* Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
* platform will take care of registering the handlers with PSCI.
******************************************************************************/
@@ -312,5 +349,6 @@
.system_off = css_system_off,
.system_reset = css_system_reset,
.validate_power_state = arm_validate_power_state,
- .validate_ns_entrypoint = arm_validate_ns_entrypoint
+ .validate_ns_entrypoint = arm_validate_ns_entrypoint,
+ .get_node_hw_state = css_node_hw_state
};
diff --git a/plat/arm/css/common/css_scpi.c b/plat/arm/css/common/css_scpi.c
index 02d573c..90a8939 100644
--- a/plat/arm/css/common/css_scpi.c
+++ b/plat/arm/css/common/css_scpi.c
@@ -41,11 +41,18 @@
#define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
+ 0x100)
+/* Header and payload addresses for commands from AP to SCP */
#define SCPI_CMD_HEADER_AP_TO_SCP \
((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
#define SCPI_CMD_PAYLOAD_AP_TO_SCP \
((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
+/* Header and payload addresses for responses from SCP to AP */
+#define SCPI_RES_HEADER_SCP_TO_AP \
+ ((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP)
+#define SCPI_RES_PAYLOAD_SCP_TO_AP \
+ ((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t)))
+
/* ID of the MHU slot used for the SCPI protocol */
#define SCPI_MHU_SLOT_ID 0
@@ -160,7 +167,69 @@
* from the sender, which could interfere with its power state request.
*/
+ scpi_secure_message_end();
+}
+
+/*
+ * Query and obtain CSS power state from SCP.
+ *
+ * In response to the query, SCP returns power states of all CPUs in all
+ * clusters of the system. The returned response is then filtered based on the
+ * supplied MPIDR. Power states of requested cluster and CPUs within are updated
+ * via. supplied non-NULL pointer arguments.
+ *
+ * Returns 0 on success, or -1 on errors.
+ */
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+ unsigned int *cluster_state_p)
+{
+ scpi_cmd_t *cmd;
+ scpi_cmd_t response;
+ int power_state, cpu, cluster, rc = -1;
+
+ /*
+ * Extract CPU and cluster membership of the given MPIDR. SCPI caters
+ * for only up to 0xf clusters, and 8 CPUs per cluster
+ */
+ cpu = mpidr & MPIDR_AFFLVL_MASK;
+ cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+ if (cpu >= 8 || cluster >= 0xf)
+ return -1;
+
+ scpi_secure_message_start();
+
+ /* Populate request headers */
+ cmd = memset(SCPI_CMD_HEADER_AP_TO_SCP, 0, sizeof(*cmd));
+ cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
+
+ /*
+ * Send message and wait for SCP's response
+ */
+ scpi_secure_message_send(0);
+ scpi_secure_message_receive(&response);
+
+ if (response.status != SCP_OK)
+ goto exit;
+
+ /* Validate SCP response */
+ if (!CHECK_RESPONSE(response, cluster))
+ goto exit;
+
+ /* Extract power states for required cluster */
+ power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster);
+ if (CLUSTER_ID(power_state) != cluster)
+ goto exit;
+
+ /* Update power state via. pointers */
+ if (cluster_state_p)
+ *cluster_state_p = CLUSTER_POWER_STATE(power_state);
+ if (cpu_state_p)
+ *cpu_state_p = CPU_POWER_STATE(power_state);
+ rc = 0;
+
+exit:
scpi_secure_message_end();
+ return rc;
}
uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
diff --git a/plat/arm/css/common/css_scpi.h b/plat/arm/css/common/css_scpi.h
index 4a601f3..1fb55e4 100644
--- a/plat/arm/css/common/css_scpi.h
+++ b/plat/arm/css/common/css_scpi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-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:
@@ -81,9 +81,34 @@
typedef enum {
SCPI_CMD_SCP_READY = 0x01,
SCPI_CMD_SET_CSS_POWER_STATE = 0x03,
+ SCPI_CMD_GET_CSS_POWER_STATE = 0x04,
SCPI_CMD_SYS_POWER_STATE = 0x05
} scpi_command_t;
+/*
+ * Macros to parse SCP response to GET_CSS_POWER_STATE command
+ *
+ * [3:0] : cluster ID
+ * [7:4] : cluster state: 0 = on; 3 = off; rest are reserved
+ * [15:8]: on/off state for individual CPUs in the cluster
+ *
+ * Payload is in little-endian
+ */
+#define CLUSTER_ID(_resp) ((_resp) & 0xf)
+#define CLUSTER_POWER_STATE(_resp) (((_resp) >> 4) & 0xf)
+
+/* Result is a bit mask of CPU on/off states in the cluster */
+#define CPU_POWER_STATE(_resp) (((_resp) >> 8) & 0xff)
+
+/*
+ * For GET_CSS_POWER_STATE, SCP returns the power states of every cluster. The
+ * size of response depends on the number of clusters in the system. The
+ * SCP-to-AP payload contains 2 bytes per cluster. Make sure the response is
+ * large enough to contain power states of a given cluster
+ */
+#define CHECK_RESPONSE(_resp, _clus) \
+ (_resp.size >= (((_clus) + 1) * 2))
+
typedef enum {
scpi_power_on = 0,
scpi_power_retention = 1,
@@ -101,6 +126,8 @@
scpi_power_state_t cpu_state,
scpi_power_state_t cluster_state,
scpi_power_state_t css_state);
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+ unsigned int *cluster_state_p);
uint32_t scpi_sys_power_state(scpi_system_state_t system_state);
diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h
index cad4535..8c64796 100644
--- a/plat/rockchip/common/include/plat_params.h
+++ b/plat/rockchip/common/include/plat_params.h
@@ -63,11 +63,31 @@
* alignment fault will occur during accessing its data member.
*/
+#define BL31_GPIO_DIR_OUT 0
+#define BL31_GPIO_DIR_IN 1
+
+#define BL31_GPIO_LEVEL_LOW 0
+#define BL31_GPIO_LEVEL_HIGH 1
+
+#define BL31_GPIO_PULL_NONE 0
+#define BL31_GPIO_PULL_UP 1
+#define BL31_GPIO_PULL_DOWN 2
+
/* param type */
enum {
PARAM_NONE = 0,
PARAM_RESET,
PARAM_POWEROFF,
+ PARAM_SUSPEND_GPIO,
+ PARAM_SUSPEND_APIO,
+};
+
+struct apio_info {
+ uint8_t apio1 : 1;
+ uint8_t apio2 : 1;
+ uint8_t apio3 : 1;
+ uint8_t apio4 : 1;
+ uint8_t apio5 : 1;
};
struct gpio_info {
@@ -88,4 +108,9 @@
struct gpio_info gpio;
};
+struct bl31_apio_param {
+ struct bl31_plat_param h;
+ struct apio_info apio;
+};
+
#endif /* __PLAT_PARAMS_H__ */
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index b9b634e..ad01266 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -121,8 +121,10 @@
void platform_cpu_warmboot(void);
-void *plat_get_rockchip_gpio_reset(void);
-void *plat_get_rockchip_gpio_poweroff(void);
+struct gpio_info *plat_get_rockchip_gpio_reset(void);
+struct gpio_info *plat_get_rockchip_gpio_poweroff(void);
+struct gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count);
+struct apio_info *plat_get_rockchip_suspend_apio(void);
void plat_rockchip_gpio_init(void);
extern const unsigned char rockchip_power_domain_tree_desc[];
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
index 2a49556..646c1e1 100644
--- a/plat/rockchip/common/params_setup.c
+++ b/plat/rockchip/common/params_setup.c
@@ -40,25 +40,39 @@
#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 param_reset;
+static struct gpio_info param_poweroff;
+static struct bl31_apio_param param_apio;
static struct gpio_info *rst_gpio;
static struct gpio_info *poweroff_gpio;
+static struct gpio_info suspend_gpio[10];
+uint32_t suspend_gpio_cnt;
+static struct apio_info *suspend_apio;
-void *plat_get_rockchip_gpio_reset(void)
+struct gpio_info *plat_get_rockchip_gpio_reset(void)
{
return rst_gpio;
}
-void *plat_get_rockchip_gpio_poweroff(void)
+struct gpio_info *plat_get_rockchip_gpio_poweroff(void)
{
return poweroff_gpio;
}
+struct gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count)
+{
+ *count = suspend_gpio_cnt;
+
+ return &suspend_gpio[0];
+}
+
+struct apio_info *plat_get_rockchip_suspend_apio(void)
+{
+ return suspend_apio;
+}
+
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;
@@ -67,25 +81,38 @@
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;
+ gpio_param = (struct bl31_gpio_param *)bl2_param;
+ memcpy(¶m_reset, &gpio_param->gpio,
+ sizeof(struct gpio_info));
+ rst_gpio = ¶m_reset;
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;
+ gpio_param = (struct bl31_gpio_param *)bl2_param;
+ memcpy(¶m_poweroff, &gpio_param->gpio,
+ sizeof(struct gpio_info));
+ poweroff_gpio = ¶m_poweroff;
+ break;
+ case PARAM_SUSPEND_GPIO:
+ if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) {
+ ERROR("exceed support suspend gpio number\n");
+ break;
+ }
+ gpio_param = (struct bl31_gpio_param *)bl2_param;
+ memcpy(&suspend_gpio[suspend_gpio_cnt],
+ &gpio_param->gpio,
+ sizeof(struct gpio_info));
+ suspend_gpio_cnt++;
+ break;
+ case PARAM_SUSPEND_APIO:
+ memcpy(¶m_apio, bl2_param,
+ sizeof(struct bl31_apio_param));
+ suspend_apio = ¶m_apio.apio;
break;
default:
- NOTICE("not expected type found\n");
- return; /* don't continue if unexpected type found */
+ ERROR("not expected type found %ld\n",
+ bl2_param->type);
+ break;
}
- 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
old mode 100755
new mode 100644
index 3c2c79a..d28100d
--- a/plat/rockchip/common/plat_pm.c
+++ b/plat/rockchip/common/plat_pm.c
@@ -283,9 +283,10 @@
rockchip_ops->cores_pwr_dm_resume();
/*
* Program the gic per-cpu distributor or re-distributor interface.
- * For sys power domain operation, resuming of the gic needs to operate in
- * rockchip_ops->sys_pwr_dm_resume, according to the sys power mode implements.
- */
+ * For sys power domain operation, resuming of the gic needs to operate
+ * in rockchip_ops->sys_pwr_dm_resume, according to the sys power mode
+ * implements.
+ */
plat_rockchip_gic_cpuif_enable();
comm_finish:
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
index ddae84d..94aa076 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -2147,7 +2147,7 @@
{
int pll_cnt, i;
- pll_cnt = sizeof(dpll_rates_table) / sizeof(struct pll_div);
+ pll_cnt = ARRAY_SIZE(dpll_rates_table);
/* Assumming rate_table is in descending order */
for (i = 0; i < pll_cnt; i++) {
@@ -2155,6 +2155,10 @@
break;
}
+ /* if mhz lower than lowest frequency in table, use lowest frequency */
+ if (i == pll_cnt)
+ i = pll_cnt - 1;
+
return i;
}
@@ -2174,7 +2178,7 @@
return (24 * fbdiv) / refdiv / postdiv1 / postdiv2;
}
-uint64_t ddr_get_rate(void)
+uint32_t ddr_get_rate(void)
{
uint32_t refdiv, postdiv1, fbdiv, postdiv2;
@@ -2464,7 +2468,6 @@
* target freq.
*/
dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing);
-
gen_rk3399_ctl_params(&rk3399_dram_status.timing_config,
&dram_timing, index);
gen_rk3399_pi_params(&rk3399_dram_status.timing_config,
@@ -2494,7 +2497,7 @@
tf_printf("%u\n", p[i]);
}
-uint64_t ddr_set_rate(uint64_t hz)
+uint32_t ddr_set_rate(uint32_t hz)
{
uint32_t low_power, index;
uint32_t mhz = hz / (1000 * 1000);
@@ -2503,13 +2506,13 @@
rk3399_dram_status.index_freq[rk3399_dram_status.current_index])
goto out;
+ index = to_get_clk_index(mhz);
+ mhz = dpll_rates_table[index].mhz;
+
low_power = exit_low_power();
index = prepare_ddr_timing(mhz);
- if (index > 1) {
- /* set timing error, quit */
- mhz = 0;
+ if (index > 1)
goto out;
- }
dcf_start(mhz, index);
wait_dcf_done();
@@ -2526,7 +2529,7 @@
return mhz;
}
-uint64_t ddr_round_rate(uint64_t hz)
+uint32_t ddr_round_rate(uint32_t hz)
{
int index;
uint32_t mhz = hz / (1000 * 1000);
@@ -2536,7 +2539,7 @@
return dpll_rates_table[index].mhz * 1000 * 1000;
}
-uint64_t dts_timing_receive(uint64_t timing, uint64_t index)
+uint32_t dts_timing_receive(uint32_t timing, uint32_t index)
{
uint32_t *p = (uint32_t *) &dts_parameter;
static uint32_t receive_nums;
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
index 62c5170..4f99070 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -321,9 +321,9 @@
#define DDR_RESTORE_SP(save_sp) ddr_save_sp(save_sp)
void ddr_init(void);
-uint64_t ddr_set_rate(uint64_t hz);
-uint64_t ddr_round_rate(uint64_t hz);
-uint64_t ddr_get_rate(void);
+uint32_t ddr_set_rate(uint32_t hz);
+uint32_t ddr_round_rate(uint32_t hz);
+uint32_t ddr_get_rate(void);
void clr_dcf_irq(void);
-uint64_t dts_timing_receive(uint64_t timing, uint64_t index);
+uint32_t dts_timing_receive(uint32_t timing, uint32_t index);
#endif
diff --git a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
index eca9fbc..4995d56 100644
--- a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
+++ b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
@@ -52,48 +52,105 @@
#define PMU_GPIO_PORT0 0
#define PMU_GPIO_PORT1 1
+#define GPIO_PORT2 2
+#define GPIO_PORT3 3
+#define GPIO_PORT4 4
#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)
+#define GET_GPIO_PORT(pin) (pin / 32)
+#define GET_GPIO_NUM(pin) (pin % 32)
+#define GET_GPIO_BANK(pin) ((pin % 32) / 8)
+#define GET_GPIO_ID(pin) ((pin % 32) % 8)
+
+/* returns old clock state, enables clock, in order to do GPIO access */
+static int gpio_get_clock(uint32_t gpio_number)
{
- uint32_t port = gpio / 32;
+ uint32_t port = GET_GPIO_PORT(gpio_number);
+ uint32_t clock_state = 0;
assert(port < 5);
switch (port) {
- case 0:
+ case PMU_GPIO_PORT0:
+ clock_state = (mmio_read_32(PMUCRU_BASE +
+ CRU_PMU_CLKGATE_CON(1)) >>
+ PCLK_GPIO0_GATE_SHIFT) & 0x01;
mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
- BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+ BITS_WITH_WMASK(0, CLK_GATE_MASK,
PCLK_GPIO0_GATE_SHIFT));
break;
- case 1:
+ case PMU_GPIO_PORT1:
+ clock_state = (mmio_read_32(PMUCRU_BASE +
+ CRU_PMU_CLKGATE_CON(1)) >>
+ PCLK_GPIO1_GATE_SHIFT) & 0x01;
mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
- BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+ BITS_WITH_WMASK(0, CLK_GATE_MASK,
PCLK_GPIO1_GATE_SHIFT));
break;
- case 2:
+ case GPIO_PORT2:
+ clock_state = (mmio_read_32(CRU_BASE +
+ CRU_CLKGATE_CON(31)) >>
+ PCLK_GPIO2_GATE_SHIFT) & 0x01;
mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
- BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+ BITS_WITH_WMASK(0, CLK_GATE_MASK,
PCLK_GPIO2_GATE_SHIFT));
break;
- case 3:
+ case GPIO_PORT3:
+ clock_state = (mmio_read_32(CRU_BASE +
+ CRU_CLKGATE_CON(31)) >>
+ PCLK_GPIO3_GATE_SHIFT) & 0x01;
mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
- BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+ BITS_WITH_WMASK(0, CLK_GATE_MASK,
PCLK_GPIO3_GATE_SHIFT));
+ break;
+ case GPIO_PORT4:
+ clock_state = (mmio_read_32(CRU_BASE +
+ CRU_CLKGATE_CON(31)) >>
+ PCLK_GPIO4_GATE_SHIFT) & 0x01;
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+ BITS_WITH_WMASK(0, CLK_GATE_MASK,
+ PCLK_GPIO4_GATE_SHIFT));
+ break;
+ default:
+ break;
+ }
+
+ return clock_state;
+}
+
+/* restores old state of gpio clock */
+void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
+{
+ uint32_t port = GET_GPIO_PORT(gpio_number);
+ switch (port) {
+ case PMU_GPIO_PORT0:
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+ BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+ PCLK_GPIO0_GATE_SHIFT));
+ break;
+ case PMU_GPIO_PORT1:
+ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+ BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+ PCLK_GPIO1_GATE_SHIFT));
break;
- case 4:
+ case GPIO_PORT2:
mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
- BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+ BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+ PCLK_GPIO2_GATE_SHIFT));
+ break;
+ case GPIO_PORT3:
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+ BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+ PCLK_GPIO3_GATE_SHIFT));
+
+ break;
+ case GPIO_PORT4:
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+ BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
PCLK_GPIO4_GATE_SHIFT));
break;
default:
@@ -101,16 +158,58 @@
}
}
+static int get_pull(int gpio)
+{
+ uint32_t port = GET_GPIO_PORT(gpio);
+ uint32_t bank = GET_GPIO_BANK(gpio);
+ uint32_t id = GET_GPIO_ID(gpio);
+ uint32_t val, clock_state;
+
+ assert((port < 5) && (bank < 4));
+
+ clock_state = gpio_get_clock(gpio);
+
+ if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
+ val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
+ port * 16 + bank * 4);
+ val = (val >> (id * 2)) & GPIO_P_MASK;
+ } else {
+ val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
+ (port - 2) * 16 + bank * 4);
+ val = (val >> (id * 2)) & GPIO_P_MASK;
+ }
+ gpio_put_clock(gpio, clock_state);
+
+ /*
+ * 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 > 1))) {
+ if (val == 3)
+ val = GPIO_PULL_UP;
+ else if (val == 1)
+ val = GPIO_PULL_DOWN;
+ else
+ val = 0;
+ }
+
+ return val;
+}
+
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;
+ uint32_t port = GET_GPIO_PORT(gpio);
+ uint32_t bank = GET_GPIO_BANK(gpio);
+ uint32_t id = GET_GPIO_ID(gpio);
+ uint32_t clock_state;
- assert((port < 5) && (num < 32));
+ assert((port < 5) && (bank < 4));
- gpio_clk(gpio, 0);
+ clock_state = gpio_get_clock(gpio);
/*
* in gpio0a, gpio0b, gpio2c, gpio2d,
@@ -120,7 +219,7 @@
* 11: pull up
* different with other gpio, so need to correct it
*/
- if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 2))) {
+ if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
if (pull == GPIO_PULL_UP)
pull = 3;
else if (pull == GPIO_PULL_DOWN)
@@ -138,17 +237,18 @@
(port - 2) * 16 + bank * 4,
BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
}
- gpio_clk(gpio, 1);
+ gpio_put_clock(gpio, clock_state);
}
static void set_direction(int gpio, int direction)
{
- uint32_t port = gpio / 32;
- uint32_t num = gpio % 32;
+ uint32_t port = GET_GPIO_PORT(gpio);
+ uint32_t num = GET_GPIO_NUM(gpio);
+ uint32_t clock_state;
assert((port < 5) && (num < 32));
- gpio_clk(gpio, 0);
+ clock_state = gpio_get_clock(gpio);
/*
* in gpio.h
@@ -158,18 +258,18 @@
* so need to revert direction value
*/
mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
- gpio_clk(gpio, 1);
+ gpio_put_clock(gpio, clock_state);
}
static int get_direction(int gpio)
{
- uint32_t port = gpio / 32;
- uint32_t num = gpio % 32;
- int direction;
+ uint32_t port = GET_GPIO_PORT(gpio);
+ uint32_t num = GET_GPIO_NUM(gpio);
+ int direction, clock_state;
assert((port < 5) && (num < 32));
- gpio_clk(gpio, 0);
+ clock_state = gpio_get_clock(gpio);
/*
* in gpio.h
@@ -180,37 +280,38 @@
*/
direction = !((mmio_read_32(gpio_port[port] +
SWPORTA_DDR) >> num) & 0x1);
- gpio_clk(gpio, 1);
+ gpio_put_clock(gpio, clock_state);
return direction;
}
static int get_value(int gpio)
{
- uint32_t port = gpio / 32;
- uint32_t num = gpio % 32;
- int value;
+ uint32_t port = GET_GPIO_PORT(gpio);
+ uint32_t num = GET_GPIO_NUM(gpio);
+ int value, clock_state;
assert((port < 5) && (num < 32));
- gpio_clk(gpio, 0);
+ clock_state = gpio_get_clock(gpio);
value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
- gpio_clk(gpio, 1);
+ gpio_put_clock(gpio, clock_state);
return value;
}
static void set_value(int gpio, int value)
{
- uint32_t port = gpio / 32;
- uint32_t num = gpio % 32;
+ uint32_t port = GET_GPIO_PORT(gpio);
+ uint32_t num = GET_GPIO_NUM(gpio);
+ uint32_t clock_state;
assert((port < 5) && (num < 32));
- gpio_clk(gpio, 0);
+ clock_state = gpio_get_clock(gpio);
mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
!!value << num);
- gpio_clk(gpio, 0);
+ gpio_put_clock(gpio, clock_state);
}
const gpio_ops_t rk3399_gpio_ops = {
@@ -219,6 +320,7 @@
.get_value = get_value,
.set_value = set_value,
.set_pull = set_pull,
+ .get_pull = get_pull,
};
void plat_rockchip_gpio_init(void)
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
old mode 100755
new mode 100644
index 50953d8..07a5b1e
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -874,6 +874,190 @@
mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle);
}
+static uint32_t iomux_status[12];
+static uint32_t pull_mode_status[12];
+static uint32_t gpio_direction[3];
+static uint32_t gpio_2_4_clk_gate;
+
+static void suspend_apio(void)
+{
+ struct apio_info *suspend_apio;
+ int i;
+
+ suspend_apio = plat_get_rockchip_suspend_apio();
+
+ if (!suspend_apio)
+ return;
+
+ /* save gpio2 ~ gpio4 iomux and pull mode */
+ for (i = 0; i < 12; i++) {
+ iomux_status[i] = mmio_read_32(GRF_BASE +
+ GRF_GPIO2A_IOMUX + i * 4);
+ pull_mode_status[i] = mmio_read_32(GRF_BASE +
+ GRF_GPIO2A_P + i * 4);
+ }
+
+ /* store gpio2 ~ gpio4 clock gate state */
+ gpio_2_4_clk_gate = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >>
+ PCLK_GPIO2_GATE_SHIFT) & 0x07;
+
+ /* enable gpio2 ~ gpio4 clock gate */
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+ BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+ /* save gpio2 ~ gpio4 direction */
+ gpio_direction[0] = mmio_read_32(GPIO2_BASE + 0x04);
+ gpio_direction[1] = mmio_read_32(GPIO3_BASE + 0x04);
+ gpio_direction[2] = mmio_read_32(GPIO4_BASE + 0x04);
+
+ /* apio1 charge gpio3a0 ~ gpio3c7 */
+ if (suspend_apio->apio1) {
+
+ /* set gpio3a0 ~ gpio3c7 iomux to gpio */
+ mmio_write_32(GRF_BASE + GRF_GPIO3A_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+ mmio_write_32(GRF_BASE + GRF_GPIO3B_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+ mmio_write_32(GRF_BASE + GRF_GPIO3C_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+ /* set gpio3a0 ~ gpio3c7 pull mode to pull none */
+ mmio_write_32(GRF_BASE + GRF_GPIO3A_P, REG_SOC_WMSK | 0);
+ mmio_write_32(GRF_BASE + GRF_GPIO3B_P, REG_SOC_WMSK | 0);
+ mmio_write_32(GRF_BASE + GRF_GPIO3C_P, REG_SOC_WMSK | 0);
+
+ /* set gpio3a0 ~ gpio3c7 to input */
+ mmio_clrbits_32(GPIO3_BASE + 0x04, 0x00ffffff);
+ }
+
+ /* apio2 charge gpio2a0 ~ gpio2b4 */
+ if (suspend_apio->apio2) {
+
+ /* set gpio2a0 ~ gpio2b4 iomux to gpio */
+ mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+ mmio_write_32(GRF_BASE + GRF_GPIO2B_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+ /* set gpio2a0 ~ gpio2b4 pull mode to pull none */
+ mmio_write_32(GRF_BASE + GRF_GPIO2A_P, REG_SOC_WMSK | 0);
+ mmio_write_32(GRF_BASE + GRF_GPIO2B_P, REG_SOC_WMSK | 0);
+
+ /* set gpio2a0 ~ gpio2b4 to input */
+ mmio_clrbits_32(GPIO2_BASE + 0x04, 0x00001fff);
+ }
+
+ /* apio3 charge gpio2c0 ~ gpio2d4*/
+ if (suspend_apio->apio3) {
+
+ /* set gpio2a0 ~ gpio2b4 iomux to gpio */
+ mmio_write_32(GRF_BASE + GRF_GPIO2C_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+ mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+ /* set gpio2c0 ~ gpio2d4 pull mode to pull none */
+ mmio_write_32(GRF_BASE + GRF_GPIO2C_P, REG_SOC_WMSK | 0);
+ mmio_write_32(GRF_BASE + GRF_GPIO2D_P, REG_SOC_WMSK | 0);
+
+ /* set gpio2c0 ~ gpio2d4 to input */
+ mmio_clrbits_32(GPIO2_BASE + 0x04, 0x1fff0000);
+ }
+
+ /* apio4 charge gpio4c0 ~ gpio4c7, gpio4d0 ~ gpio4d6 */
+ if (suspend_apio->apio4) {
+
+ /* set gpio4c0 ~ gpio4d6 iomux to gpio */
+ mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+ mmio_write_32(GRF_BASE + GRF_GPIO4D_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+ /* set gpio4c0 ~ gpio4d6 pull mode to pull none */
+ mmio_write_32(GRF_BASE + GRF_GPIO4C_P, REG_SOC_WMSK | 0);
+ mmio_write_32(GRF_BASE + GRF_GPIO4D_P, REG_SOC_WMSK | 0);
+
+ /* set gpio4c0 ~ gpio4d6 to input */
+ mmio_clrbits_32(GPIO4_BASE + 0x04, 0x7fff0000);
+ }
+
+ /* apio5 charge gpio3d0 ~ gpio3d7, gpio4a0 ~ gpio4a7*/
+ if (suspend_apio->apio5) {
+ /* set gpio3d0 ~ gpio4a7 iomux to gpio */
+ mmio_write_32(GRF_BASE + GRF_GPIO3D_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+ mmio_write_32(GRF_BASE + GRF_GPIO4A_IOMUX,
+ REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+ /* set gpio3d0 ~ gpio4a7 pull mode to pull none */
+ mmio_write_32(GRF_BASE + GRF_GPIO3D_P, REG_SOC_WMSK | 0);
+ mmio_write_32(GRF_BASE + GRF_GPIO4A_P, REG_SOC_WMSK | 0);
+
+ /* set gpio4c0 ~ gpio4d6 to input */
+ mmio_clrbits_32(GPIO3_BASE + 0x04, 0xff000000);
+ mmio_clrbits_32(GPIO4_BASE + 0x04, 0x000000ff);
+ }
+}
+
+static void resume_apio(void)
+{
+ struct apio_info *suspend_apio;
+ int i;
+
+ suspend_apio = plat_get_rockchip_suspend_apio();
+
+ if (!suspend_apio)
+ return;
+
+ for (i = 0; i < 12; i++) {
+ mmio_write_32(GRF_BASE + GRF_GPIO2A_P + i * 4,
+ REG_SOC_WMSK | pull_mode_status[i]);
+ mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
+ REG_SOC_WMSK | iomux_status[i]);
+ }
+
+ /* set gpio2 ~ gpio4 direction back to store value */
+ mmio_write_32(GPIO2_BASE + 0x04, gpio_direction[0]);
+ mmio_write_32(GPIO3_BASE + 0x04, gpio_direction[1]);
+ mmio_write_32(GPIO4_BASE + 0x04, gpio_direction[2]);
+
+ /* set gpio2 ~ gpio4 clock gate back to store value */
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+ BITS_WITH_WMASK(gpio_2_4_clk_gate, 0x07,
+ PCLK_GPIO2_GATE_SHIFT));
+}
+
+static void suspend_gpio(void)
+{
+ struct gpio_info *suspend_gpio;
+ uint32_t count;
+ int i;
+
+ suspend_gpio = plat_get_rockchip_suspend_gpio(&count);
+
+ for (i = 0; i < count; i++) {
+ gpio_set_value(suspend_gpio[i].index, suspend_gpio[i].polarity);
+ gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT);
+ udelay(1);
+ }
+}
+
+static void resume_gpio(void)
+{
+ struct gpio_info *suspend_gpio;
+ uint32_t count;
+ int i;
+
+ suspend_gpio = plat_get_rockchip_suspend_gpio(&count);
+
+ for (i = count - 1; i >= 0; i--) {
+ gpio_set_value(suspend_gpio[i].index,
+ !suspend_gpio[i].polarity);
+ gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT);
+ udelay(1);
+ }
+}
+
static int sys_pwr_domain_suspend(void)
{
uint32_t wait_cnt = 0;
@@ -919,7 +1103,6 @@
}
}
mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
-
/*
* Disabling PLLs/PWM/DVFS is approaching WFI which is
* the last steps in suspend.
@@ -928,6 +1111,8 @@
disable_dvfs_plls();
disable_pwms();
disable_nodvfs_plls();
+ suspend_apio();
+ suspend_gpio();
return 0;
}
@@ -937,6 +1122,8 @@
uint32_t wait_cnt = 0;
uint32_t status = 0;
+ resume_apio();
+ resume_gpio();
enable_nodvfs_plls();
enable_pwms();
/* PWM regulators take time to come up; give 300us to be safe. */
@@ -952,7 +1139,6 @@
* somewhere.
*/
mmio_write_32(PMU_BASE + PMU_WAKEUP_STATUS, 0xffffffff);
-
mmio_write_32(PMU_BASE + PMU_WKUP_CFG4, 0x00);
mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
@@ -1003,6 +1189,9 @@
BIT(PMU_CLR_PERILP) |
BIT(PMU_CLR_PMU) |
BIT(PMU_CLR_GIC));
+
+ plat_rockchip_gic_cpuif_enable();
+
return 0;
}
@@ -1010,7 +1199,7 @@
{
struct gpio_info *rst_gpio;
- rst_gpio = (struct gpio_info *)plat_get_rockchip_gpio_reset();
+ rst_gpio = plat_get_rockchip_gpio_reset();
if (rst_gpio) {
gpio_set_direction(rst_gpio->index, GPIO_DIR_OUT);
@@ -1027,7 +1216,7 @@
{
struct gpio_info *poweroff_gpio;
- poweroff_gpio = (struct gpio_info *)plat_get_rockchip_gpio_poweroff();
+ poweroff_gpio = plat_get_rockchip_gpio_poweroff();
if (poweroff_gpio) {
/*
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
index 65fe7db..ab2896b 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -875,7 +875,32 @@
#define MAX_WAIT_COUNT 1000
#define GRF_SOC_CON4 0x0e210
-#define GRF_GPIO4C_IOMUX 0x0e028
+
+#define GRF_GPIO2A_IOMUX 0xe000
+#define GRF_GPIO2B_IOMUX 0xe004
+#define GRF_GPIO2C_IOMUX 0xe008
+#define GRF_GPIO2D_IOMUX 0xe00c
+#define GRF_GPIO3A_IOMUX 0xe010
+#define GRF_GPIO3B_IOMUX 0xe014
+#define GRF_GPIO3C_IOMUX 0xe018
+#define GRF_GPIO3D_IOMUX 0xe01c
+#define GRF_GPIO4A_IOMUX 0xe020
+#define GRF_GPIO4B_IOMUX 0xe024
+#define GRF_GPIO4C_IOMUX 0xe028
+#define GRF_GPIO4D_IOMUX 0xe02c
+
+#define GRF_GPIO2A_P 0xe040
+#define GRF_GPIO2B_P 0xe044
+#define GRF_GPIO2C_P 0xe048
+#define GRF_GPIO2D_P 0xe04C
+#define GRF_GPIO3A_P 0xe050
+#define GRF_GPIO3B_P 0xe054
+#define GRF_GPIO3C_P 0xe058
+#define GRF_GPIO3D_P 0xe05C
+#define GRF_GPIO4A_P 0xe060
+#define GRF_GPIO4B_P 0xe064
+#define GRF_GPIO4C_P 0xe068
+#define GRF_GPIO4D_P 0xe06C
#define PMUGRF_GPIO0A_SMT 0x0120
#define PMUGRF_SOC_CON0 0x0180
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
index 6069be2..a20ee2d 100644
--- a/plat/rockchip/rk3399/plat_sip_calls.c
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -31,33 +31,33 @@
#include <runtime_svc.h>
#include <dram.h>
-#define RK_SIP_DDR_CFG64 0x82000008
-#define CONFIG_DRAM_INIT 0x00
-#define CONFIG_DRAM_SET_RATE 0x01
-#define CONFIG_DRAM_ROUND_RATE 0x02
-#define CONFIG_DRAM_SET_AT_SR 0x03
-#define CONFIG_DRAM_GET_BW 0x04
-#define CONFIG_DRAM_GET_RATE 0x05
-#define CONFIG_DRAM_CLR_IRQ 0x06
-#define CONFIG_DRAM_SET_PARAM 0x07
+#define RK_SIP_DDR_CFG 0x82000008
+#define DRAM_INIT 0x00
+#define DRAM_SET_RATE 0x01
+#define DRAM_ROUND_RATE 0x02
+#define DRAM_SET_AT_SR 0x03
+#define DRAM_GET_BW 0x04
+#define DRAM_GET_RATE 0x05
+#define DRAM_CLR_IRQ 0x06
+#define DRAM_SET_PARAM 0x07
-uint64_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id)
+uint32_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id)
{
switch (id) {
- case CONFIG_DRAM_INIT:
+ case DRAM_INIT:
ddr_init();
break;
- case CONFIG_DRAM_SET_RATE:
- return ddr_set_rate(arg0);
- case CONFIG_DRAM_ROUND_RATE:
- return ddr_round_rate(arg0);
- case CONFIG_DRAM_GET_RATE:
+ case DRAM_SET_RATE:
+ return ddr_set_rate((uint32_t)arg0);
+ case DRAM_ROUND_RATE:
+ return ddr_round_rate((uint32_t)arg0);
+ case DRAM_GET_RATE:
return ddr_get_rate();
- case CONFIG_DRAM_CLR_IRQ:
+ case DRAM_CLR_IRQ:
clr_dcf_irq();
break;
- case CONFIG_DRAM_SET_PARAM:
- dts_timing_receive(arg0, arg1);
+ case DRAM_SET_PARAM:
+ dts_timing_receive((uint32_t)arg0, (uint32_t)arg1);
break;
default:
break;
@@ -76,7 +76,7 @@
uint64_t flags)
{
switch (smc_fid) {
- case RK_SIP_DDR_CFG64:
+ case RK_SIP_DDR_CFG:
SMC_RET1(handle, ddr_smc_handler(x1, x2, x3));
default:
ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
index 1ba301d..60a1605 100644
--- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -29,6 +29,7 @@
*/
#include <debug.h>
+#include <generic_delay_timer.h>
#include <mmio.h>
#include <platform.h>
#include <xlat_tables.h>
@@ -89,6 +90,18 @@
return 100000000;
}
+unsigned int zynqmp_get_silicon_id(void)
+{
+ uint32_t id;
+
+ id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+ id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
+ id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+
+ return id;
+}
+
#if LOG_LEVEL >= LOG_LEVEL_NOTICE
static const struct {
unsigned int id;
@@ -140,18 +153,6 @@
},
};
-static unsigned int zynqmp_get_silicon_id(void)
-{
- uint32_t id;
-
- id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
-
- id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
- id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
-
- return id;
-}
-
static char *zynqmp_get_silicon_idcode_name(void)
{
unsigned int id;
@@ -289,6 +290,8 @@
/* Program freq register in System counter and enable system counter. */
mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq());
mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN);
+
+ generic_delay_timer_init();
}
unsigned int plat_get_syscnt_freq2(void)
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index d878b86..c05b094 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -118,11 +118,31 @@
NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
}
+/* Enable the test setup */
+#ifndef ZYNQMP_TESTING
+static void zynqmp_testing_setup(void) { }
+#else
+static void zynqmp_testing_setup(void)
+{
+ uint32_t actlr_el3, actlr_el2;
+
+ /* Enable CPU ACTLR AND L2ACTLR RW access from non-secure world */
+ actlr_el3 = read_actlr_el3();
+ actlr_el2 = read_actlr_el2();
+
+ actlr_el3 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT;
+ actlr_el2 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT;
+ write_actlr_el3(actlr_el3);
+ write_actlr_el2(actlr_el2);
+}
+#endif
+
void bl31_platform_setup(void)
{
/* Initialize the gic cpu and distributor interfaces */
plat_arm_gic_driver_init();
plat_arm_gic_init();
+ zynqmp_testing_setup();
}
void bl31_plat_runtime_setup(void)
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
index a35bd12..3c1a9e5 100644
--- a/plat/xilinx/zynqmp/include/platform_def.h
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -56,8 +56,7 @@
* little space for growth.
*/
#ifndef ZYNQMP_ATF_MEM_BASE
-# define BL31_BASE 0xfffe5000
-# define BL31_PROGBITS_LIMIT 0xffffa000
+# define BL31_BASE 0xfffea000
# define BL31_LIMIT 0xffffffff
#else
# define BL31_BASE (ZYNQMP_ATF_MEM_BASE)
@@ -101,11 +100,7 @@
******************************************************************************/
#define ADDR_SPACE_SIZE (1ull << 32)
#define MAX_MMAP_REGIONS 7
-#if IMAGE_BL32
-# define MAX_XLAT_TABLES 5
-#else
-# define MAX_XLAT_TABLES 4
-#endif
+#define MAX_XLAT_TABLES 5
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
index 56eb742..55227ea 100644
--- a/plat/xilinx/zynqmp/plat_psci.c
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -147,7 +147,7 @@
* invoking CPU_on function, during which resume address will
* be set.
*/
- pm_self_suspend(proc->node_id, MAX_LATENCY, 0, 0);
+ pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
}
static void zynqmp_nopmu_pwr_domain_suspend(const psci_power_state_t *target_state)
@@ -179,6 +179,7 @@
static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
{
+ unsigned int state;
unsigned int cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);
@@ -186,15 +187,14 @@
VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
__func__, i, target_state->pwr_domain_state[i]);
+ state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
/* Send request to PMU to suspend this core */
- pm_self_suspend(proc->node_id, MAX_LATENCY, 0, zynqmp_sec_entry);
+ pm_self_suspend(proc->node_id, MAX_LATENCY, state, zynqmp_sec_entry);
/* APU is to be turned off */
if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
- /* Power down L2 cache */
- pm_set_requirement(NODE_L2, 0, 0, REQ_ACK_NO);
- /* Send request for OCM retention state */
- set_ocm_retention();
/* disable coherency */
plat_arm_interconnect_exit_coherency();
}
@@ -242,6 +242,13 @@
/* enable coherency */
plat_arm_interconnect_enter_coherency();
+ /* APU was turned off */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_arm_gic_init();
+ } else {
+ gicv2_cpuif_enable();
+ gicv2_pcpu_distif_init();
+ }
}
/*******************************************************************************
@@ -308,7 +315,20 @@
{
VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+ int pstate = psci_get_pstate_type(power_state);
+
+ assert(req_state);
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY)
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+ else
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+
+ /* We expect the 'state id' to be zero */
+ if (psci_get_pstate_id(power_state))
+ return PSCI_E_INVALID_PARAMS;
+
- /* FIXME: populate req_state */
return PSCI_E_SUCCESS;
}
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index 9bde5ff..33c55a0 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -31,6 +31,7 @@
PSCI_EXTENDED_STATE_ID := 1
A53_DISABLE_NON_TEMPORAL_HINT := 0
SEPARATE_CODE_AND_RODATA := 1
+RESET_TO_BL31 := 1
ifdef ZYNQMP_ATF_MEM_BASE
$(eval $(call add_define,ZYNQMP_ATF_MEM_BASE))
@@ -64,6 +65,8 @@
PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
lib/xlat_tables/aarch64/xlat_tables.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_main.c \
drivers/arm/gic/v2/gicv2_helpers.c \
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index eac7801..e859ee3 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -76,7 +76,7 @@
* pm_self_suspend() - PM call for processor to suspend itself
* @nid Node id of the processor or subsystem
* @latency Requested maximum wakeup latency (not supported)
- * @state Requested state (not supported)
+ * @state Requested state
* @address Resume address
*
* This is a blocking call, it will return only once PMU has responded.
@@ -97,7 +97,7 @@
* Do client specific suspend operations
* (e.g. set powerdown request bit)
*/
- pm_client_suspend(proc);
+ pm_client_suspend(proc, state);
/* Send request to the PMU */
PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
state, address, (address >> 32));
@@ -476,7 +476,7 @@
/* Send request to the PMU */
PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
- return pm_ipi_send(primary_proc, payload);
+ return pm_ipi_send_sync(primary_proc, payload, NULL);
}
/**
@@ -497,3 +497,47 @@
PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
return pm_ipi_send_sync(primary_proc, payload, value);
}
+
+/**
+ * pm_fpga_load() - Load the bitstream into the PL.
+ *
+ * This function provides access to the xilfpga library to load
+ * the Bit-stream into PL.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ *
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * size: Number of 32bit words
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_load(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t size,
+ uint32_t flags)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low,
+ size, flags);
+ return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_fpga_get_status() - Read value from fpga status register
+ * @value Value to read
+ *
+ * This function provides access to the xilfpga library to get
+ * the fpga status
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_get_status(unsigned int *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS);
+ return pm_ipi_send_sync(primary_proc, payload, value);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index 22bdb47..26d83e7 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -109,4 +109,10 @@
unsigned int mask,
unsigned int value);
enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value);
+enum pm_ret_status pm_fpga_load(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t size,
+ uint32_t flags);
+enum pm_ret_status pm_fpga_get_status(unsigned int *value);
+
#endif /* _PM_API_SYS_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
index cf0d5f0..b77a1cf 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.c
@@ -33,26 +33,25 @@
* for getting information about and changing state of the APU.
*/
+#include <assert.h>
#include <bakery_lock.h>
#include <gicv2.h>
+#include <gic_common.h>
#include <bl_common.h>
#include <mmio.h>
+#include <string.h>
#include <utils.h>
#include "pm_api_sys.h"
#include "pm_client.h"
#include "pm_ipi.h"
#include "../zynqmp_def.h"
-#define OCM_BANK_0 0xFFFC0000
-#define OCM_BANK_1 (OCM_BANK_0 + 0x10000)
-#define OCM_BANK_2 (OCM_BANK_1 + 0x10000)
-#define OCM_BANK_3 (OCM_BANK_2 + 0x10000)
-
+#define IRQ_MAX 84
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1)
#define UNDEFINED_CPUID (~0)
+
DEFINE_BAKERY_LOCK(pm_client_secure_lock);
-/* Declaration of linker defined symbol */
-extern unsigned long __BL31_END__;
extern const struct pm_ipi apu_ipi;
/* Order in pm_procs_all array must match cpu ids */
@@ -79,36 +78,146 @@
},
};
+/* Interrupt to PM node ID map */
+static enum pm_node_id irq_node_map[IRQ_MAX + 1] = {
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 3 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 7 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 11 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_NAND,
+ NODE_QSPI, /* 15 */
+ NODE_GPIO,
+ NODE_I2C_0,
+ NODE_I2C_1,
+ NODE_SPI_0, /* 19 */
+ NODE_SPI_1,
+ NODE_UART_0,
+ NODE_UART_1,
+ NODE_CAN_0, /* 23 */
+ NODE_CAN_1,
+ NODE_UNKNOWN,
+ NODE_RTC,
+ NODE_RTC, /* 27 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 31 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 35, NODE_IPI_APU */
+ NODE_TTC_0,
+ NODE_TTC_0,
+ NODE_TTC_0,
+ NODE_TTC_1, /* 39 */
+ NODE_TTC_1,
+ NODE_TTC_1,
+ NODE_TTC_2,
+ NODE_TTC_2, /* 43 */
+ NODE_TTC_2,
+ NODE_TTC_3,
+ NODE_TTC_3,
+ NODE_TTC_3, /* 47 */
+ NODE_SD_0,
+ NODE_SD_1,
+ NODE_SD_0,
+ NODE_SD_1, /* 51 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 55 */
+ NODE_UNKNOWN,
+ NODE_ETH_0,
+ NODE_ETH_0,
+ NODE_ETH_1, /* 59 */
+ NODE_ETH_1,
+ NODE_ETH_2,
+ NODE_ETH_2,
+ NODE_ETH_3, /* 63 */
+ NODE_ETH_3,
+ NODE_USB_0,
+ NODE_USB_0,
+ NODE_USB_0, /* 67 */
+ NODE_USB_0,
+ NODE_USB_0,
+ NODE_USB_1,
+ NODE_USB_1, /* 71 */
+ NODE_USB_1,
+ NODE_USB_1,
+ NODE_USB_1,
+ NODE_USB_0, /* 75 */
+ NODE_USB_0,
+ NODE_ADMA,
+ NODE_ADMA,
+ NODE_ADMA, /* 79 */
+ NODE_ADMA,
+ NODE_ADMA,
+ NODE_ADMA,
+ NODE_ADMA, /* 83 */
+ NODE_ADMA,
+};
+
/**
- * set_ocm_retention() - Configure OCM memory banks for retention
+ * irq_to_pm_node - Get PM node ID corresponding to the interrupt number
+ * @irq: Interrupt number
*
- * APU specific requirements for suspend action:
- * OCM has to enter retention state in order to preserve saved
- * context after suspend request. OCM banks are determined by
- * __BL31_END__ linker symbol.
- *
- * Return: Returns status, either success or error+reason
+ * Return: PM node ID corresponding to the specified interrupt
*/
-enum pm_ret_status set_ocm_retention(void)
+static enum pm_node_id irq_to_pm_node(unsigned int irq)
{
- enum pm_ret_status ret;
+ assert(irq <= IRQ_MAX);
+ return irq_node_map[irq];
+}
- /* OCM_BANK_0 will always be occupied */
- ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0,
- REQ_ACK_NO);
+/**
+ * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake
+ * sources in the PMU firmware
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+ uint32_t reg_num;
+ uint8_t pm_wakeup_nodes_set[NODE_MAX];
+ uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4;
- /* Check for other OCM banks */
- if ((unsigned long)&__BL31_END__ >= OCM_BANK_1)
- ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0,
- REQ_ACK_NO);
- if ((unsigned long)&__BL31_END__ >= OCM_BANK_2)
- ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0,
- REQ_ACK_NO);
- if ((unsigned long)&__BL31_END__ >= OCM_BANK_3)
- ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0,
- REQ_ACK_NO);
+ memset(&pm_wakeup_nodes_set, 0, sizeof(pm_wakeup_nodes_set));
- return ret;
+ for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+ uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+ uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
+
+ if (!reg)
+ continue;
+
+ while (reg) {
+ enum pm_node_id node;
+ uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+ idx = __builtin_ctz(lowest_set);
+ irq = base_irq + idx;
+
+ if (irq > IRQ_MAX)
+ break;
+
+ node = irq_to_pm_node(irq);
+ reg &= ~lowest_set;
+
+ if ((node != NODE_UNKNOWN) &&
+ (!pm_wakeup_nodes_set[node])) {
+ ret = pm_set_wakeup_source(NODE_APU, node, 1);
+ pm_wakeup_nodes_set[node] = !ret;
+ }
+ }
+ }
}
/**
@@ -162,11 +271,15 @@
*
* This function should contain any PU-specific actions
* required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
*/
-void pm_client_suspend(const struct pm_proc *proc)
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
{
bakery_lock_get(&pm_client_secure_lock);
+ if (state == PM_STATE_SUSPEND_TO_RAM)
+ pm_client_set_wakeup_sources();
+
/* Set powerdown request */
mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h
index 9483b0d..7f80d5b 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.h
@@ -40,7 +40,7 @@
#include "pm_common.h"
/* Functions to be implemented by each PU */
-void pm_client_suspend(const struct pm_proc *proc);
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
void pm_client_abort_suspend(void);
void pm_client_wakeup(const struct pm_proc *proc);
enum pm_ret_status set_ocm_retention(void);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index adeec64..aec335a 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -53,6 +53,10 @@
#define MAX_LATENCY (~0U)
#define MAX_QOS 100U
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE 0x0U
+#define PM_STATE_SUSPEND_TO_RAM 0xFU
+
/*********************************************************************
* Enum definitions
********************************************************************/
@@ -82,6 +86,10 @@
PM_RESET_GET_STATUS,
PM_MMIO_WRITE,
PM_MMIO_READ,
+ PM_INIT,
+ PM_FPGA_LOAD,
+ PM_FPGA_GET_STATUS,
+ PM_GET_CHIPID,
PM_API_MAX
};
@@ -143,6 +151,12 @@
NODE_IOPLL,
NODE_DDR,
NODE_IPI_APU,
+ NODE_IPI_RPU_0,
+ NODE_GPU,
+ NODE_PCIE,
+ NODE_PCAP,
+ NODE_RTC,
+ NODE_MAX
};
enum pm_request_ack {
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index e3c25c3..9c08ffb 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -228,6 +228,22 @@
ret = pm_mmio_read(pm_arg[0], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
+
+ case PM_FPGA_LOAD:
+ ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_FPGA_GET_STATUS:
+ {
+ uint32_t value;
+
+ ret = pm_fpga_get_status(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_GET_CHIPID:
+ SMC_RET1(handle, zynqmp_get_silicon_id());
+
default:
WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h
index 4bb332e..65bc25f 100644
--- a/plat/xilinx/zynqmp/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/zynqmp_def.h
@@ -201,4 +201,8 @@
#define ZYNQMP_CSU_VERSION_OFFSET 0x44
+/* Access control register defines */
+#define ACTLR_EL3_L2ACTLR_BIT (1 << 6)
+#define ACTLR_EL3_CPUACTLR_BIT (1 << 0)
+
#endif /* __ZYNQMP_DEF_H__ */
diff --git a/plat/xilinx/zynqmp/zynqmp_private.h b/plat/xilinx/zynqmp/zynqmp_private.h
index ddef37b..abcdebc 100644
--- a/plat/xilinx/zynqmp/zynqmp_private.h
+++ b/plat/xilinx/zynqmp/zynqmp_private.h
@@ -39,6 +39,7 @@
unsigned int zynqmp_get_uart_clk(void);
int zynqmp_is_pmu_up(void);
unsigned int zynqmp_get_bootmode(void);
+unsigned int zynqmp_get_silicon_id(void);
/* For FSBL handover */
void fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info,
diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile
index 3bc372a..df76a75 100644
--- a/tools/fiptool/Makefile
+++ b/tools/fiptool/Makefile
@@ -44,6 +44,7 @@
else
CFLAGS += -O2
endif
+LDLIBS := -lcrypto
ifeq (${V},0)
Q := @
@@ -62,7 +63,7 @@
${PROJECT}: ${OBJECTS} Makefile
@echo " LD $@"
- ${Q}${CC} ${OBJECTS} -o $@
+ ${Q}${CC} ${OBJECTS} -o $@ ${LDLIBS}
@${ECHO_BLANK_LINE}
@echo "Built $@ successfully"
@${ECHO_BLANK_LINE}
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 68ddcf5..b3f02f6 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -42,6 +42,8 @@
#include <string.h>
#include <unistd.h>
+#include <openssl/sha.h>
+
#include "fiptool.h"
#include "firmware_image_package.h"
#include "tbbr_config.h"
@@ -354,6 +356,14 @@
opts[idx].val = val;
}
+static void md_print(unsigned char *md, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ printf("%02x", md[i]);
+}
+
static int info_cmd(int argc, char *argv[])
{
image_t *image;
@@ -363,7 +373,7 @@
int i;
if (argc != 2)
- usage();
+ info_usage();
argc--, argv++;
parse_fip(argv[0], &toc_header);
@@ -391,10 +401,16 @@
(unsigned long long)image_offset,
(unsigned long long)image_size);
if (image->toc_entry != NULL)
- printf(", cmdline=\"--%s\"\n",
+ printf(", cmdline=\"--%s\"",
image->toc_entry->cmdline_name);
- else
- putchar('\n');
+ if (verbose) {
+ unsigned char md[SHA256_DIGEST_LENGTH];
+
+ SHA256(image->buffer, image_size, md);
+ printf(", sha256=");
+ md_print(md, sizeof(md));
+ }
+ putchar('\n');
image_offset += image_size;
}
@@ -405,6 +421,7 @@
static void info_usage(void)
{
printf("fiptool info FIP_FILENAME\n");
+ exit(1);
}
static int pack_images(char *filename, uint64_t toc_flags)
@@ -538,7 +555,7 @@
int i;
if (argc < 2)
- usage();
+ create_usage();
i = fill_common_opts(opts, required_argument);
add_opt(opts, i, "plat-toc-flags", required_argument,
@@ -567,14 +584,14 @@
parse_plat_toc_flags(optarg, &toc_flags);
break;
default:
- usage();
+ create_usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
- usage();
+ create_usage();
update_fip();
@@ -595,6 +612,7 @@
for (; toc_entry->cmdline_name != NULL; toc_entry++)
printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
toc_entry->name);
+ exit(1);
}
static int update_cmd(int argc, char *argv[])
@@ -607,7 +625,7 @@
int i;
if (argc < 2)
- usage();
+ update_usage();
i = fill_common_opts(opts, required_argument);
add_opt(opts, i, "out", required_argument, 'o');
@@ -642,14 +660,14 @@
snprintf(outfile, sizeof(outfile), "%s", optarg);
break;
default:
- usage();
+ update_usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
- usage();
+ update_usage();
if (outfile[0] == '\0')
snprintf(outfile, sizeof(outfile), "%s", argv[0]);
@@ -682,6 +700,7 @@
for (; toc_entry->cmdline_name != NULL; toc_entry++)
printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
toc_entry->name);
+ exit(1);
}
static int unpack_cmd(int argc, char *argv[])
@@ -694,7 +713,7 @@
int i;
if (argc < 2)
- usage();
+ unpack_usage();
i = fill_common_opts(opts, required_argument);
add_opt(opts, i, "force", no_argument, 'f');
@@ -724,14 +743,14 @@
snprintf(outdir, sizeof(outdir), "%s", optarg);
break;
default:
- usage();
+ unpack_usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
- usage();
+ unpack_usage();
parse_fip(argv[0], NULL);
@@ -806,6 +825,7 @@
toc_entry->name);
fputc('\n', stderr);
printf("If no options are provided, all images will be unpacked.\n");
+ exit(1);
}
static int remove_cmd(int argc, char *argv[])
@@ -818,7 +838,7 @@
int i;
if (argc < 2)
- usage();
+ remove_usage();
i = fill_common_opts(opts, no_argument);
add_opt(opts, i, "force", no_argument, 'f');
@@ -844,14 +864,14 @@
snprintf(outfile, sizeof(outfile), "%s", optarg);
break;
default:
- usage();
+ remove_usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0)
- usage();
+ remove_usage();
if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
log_errx("File %s already exists, use --force to overwrite it",
@@ -896,6 +916,7 @@
for (; toc_entry->cmdline_name != NULL; toc_entry++)
printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
toc_entry->name);
+ exit(1);
}
static int version_cmd(int argc, char *argv[])
@@ -912,6 +933,7 @@
static void version_usage(void)
{
printf("fiptool version\n");
+ exit(1);
}
static int help_cmd(int argc, char *argv[])
@@ -924,10 +946,8 @@
for (i = 0; i < NELEM(cmds); i++) {
if (strcmp(cmds[i].name, argv[0]) == 0 &&
- cmds[i].usage != NULL) {
+ cmds[i].usage != NULL)
cmds[i].usage();
- break;
- }
}
if (i == NELEM(cmds))
printf("No help for subcommand '%s'\n", argv[0]);