aboutsummaryrefslogtreecommitdiff
path: root/product/sgi575
diff options
context:
space:
mode:
authorAmit Daniel Kachhap <amit.kachhap@arm.com>2018-07-20 17:10:25 +0530
committerronald-cron-arm <39518861+ronald-cron-arm@users.noreply.github.com>2018-10-18 17:22:34 +0000
commit4102c08df350404298f9e9acb49e3c259b3661ea (patch)
treedd437f070bdfdaa7cb679211d1ac5509fd18e853 /product/sgi575
parentc0ab6c61af055205b3801e16e549ed76340c5f57 (diff)
sgi575: Add system module
The functionality supported by this module are, * PPU interrupt handlers * Power up of the primary application core Change-Id: I7f6666da8653362090375f5fda7dc37d2354c07e Signed-off-by: Amit Daniel Kachhap <amit.kachhap@arm.com>
Diffstat (limited to 'product/sgi575')
-rw-r--r--product/sgi575/module/sgi575_system/include/mod_sgi575_system.h64
-rw-r--r--product/sgi575/module/sgi575_system/src/Makefile11
-rw-r--r--product/sgi575/module/sgi575_system/src/mod_sgi575_system.c269
3 files changed, 344 insertions, 0 deletions
diff --git a/product/sgi575/module/sgi575_system/include/mod_sgi575_system.h b/product/sgi575/module/sgi575_system/include/mod_sgi575_system.h
new file mode 100644
index 00000000..a5cb374f
--- /dev/null
+++ b/product/sgi575/module/sgi575_system/include/mod_sgi575_system.h
@@ -0,0 +1,64 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * SGI575 System Support
+ */
+
+#ifndef MOD_SGI575_SYSTEM_H
+#define MOD_SGI575_SYSTEM_H
+
+#include <mod_power_domain.h>
+
+/*!
+ * \addtogroup GroupSGI575Module SGI575 Product Modules
+ * @{
+ */
+
+/*!
+ * \defgroup GroupSGI575System SGI575 System Support
+ * @{
+ */
+
+/*!
+ * \brief Additional SGI575 system power states.
+ */
+enum mod_sgi575_system_power_states {
+ MOD_SGI575_SYSTEM_POWER_STATE_SLEEP0 = MOD_PD_STATE_COUNT,
+ MOD_SGI575_SYSTEM_POWER_STATE_SLEEP1,
+ MOD_SGI575_SYSTEM_POWER_STATE_COUNT
+};
+
+/*!
+ * \brief System power state masks.
+ */
+enum mod_sgi575_system_power_state_masks {
+ MOD_SGI575_SYSTEM_POWER_STATE_SLEEP0_MASK =
+ (1 << MOD_SGI575_SYSTEM_POWER_STATE_SLEEP0),
+ MOD_SGI575_SYSTEM_POWER_STATE_SLEEP1_MASK =
+ (1 << MOD_SGI575_SYSTEM_POWER_STATE_SLEEP1),
+};
+
+/*!
+ * \brief Indices of the interfaces exposed by the module.
+ */
+enum mod_sgi575_system_api_idx {
+ /*! API index for the driver interface of the SYSTEM POWER module */
+ MOD_SGI575_SYSTEM_API_IDX_SYSTEM_POWER_DRIVER,
+
+ /*! Number of exposed interfaces */
+ MOD_SGI575_SYSTEM_API_COUNT
+};
+
+/*!
+ * @}
+ */
+
+/*!
+ * @}
+ */
+
+#endif /* MOD_SGI575_SYSTEM_H */
diff --git a/product/sgi575/module/sgi575_system/src/Makefile b/product/sgi575/module/sgi575_system/src/Makefile
new file mode 100644
index 00000000..f2769a6c
--- /dev/null
+++ b/product/sgi575/module/sgi575_system/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Arm SCP/MCP Software
+# Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := SGI575 SYSTEM
+BS_LIB_SOURCES = mod_sgi575_system.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/sgi575/module/sgi575_system/src/mod_sgi575_system.c b/product/sgi575/module/sgi575_system/src/mod_sgi575_system.c
new file mode 100644
index 00000000..ddb77e36
--- /dev/null
+++ b/product/sgi575/module/sgi575_system/src/mod_sgi575_system.c
@@ -0,0 +1,269 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * SGI575 System Support.
+ */
+
+#include <stdint.h>
+#include <fwk_assert.h>
+#include <fmw_cmsis.h>
+#include <fwk_id.h>
+#include <fwk_interrupt.h>
+#include <fwk_macros.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <fwk_notification.h>
+#include <mod_clock.h>
+#include <mod_log.h>
+#include <mod_power_domain.h>
+#include <mod_ppu_v1.h>
+#include <mod_sgi575_system.h>
+#include <mod_system_power.h>
+#include <scp_sgi575_irq.h>
+#include <scp_sgi575_mmap.h>
+#include <sgi575_core.h>
+#include <sgi575_pik_scp.h>
+#include <config_clock.h>
+
+/* Module context */
+struct sgi575_system_ctx {
+ /* Pointer to the SCP PIK registers */
+ struct pik_scp_reg *pik_scp_reg;
+
+ /* Log API pointer */
+ const struct mod_log_api *log_api;
+
+ /* Pointer to the Interrupt Service Routine API of the PPU_V1 module */
+ const struct ppu_v1_isr_api *ppu_v1_isr_api;
+
+ /* Power domain module restricted API pointer */
+ struct mod_pd_restricted_api *mod_pd_restricted_api;
+};
+
+struct sgi575_system_isr {
+ unsigned int interrupt;
+ void (*handler)(void);
+};
+
+static struct sgi575_system_ctx sgi575_system_ctx;
+const struct fwk_module_config config_sgi575_system = { 0 };
+
+/*
+ * PPU Interrupt Service Routines for cluster and core power domains
+ */
+
+static void ppu_cores_isr(unsigned int first, uint32_t status)
+{
+ unsigned int core_idx;
+
+ while (status != 0) {
+ core_idx = __builtin_ctz(status);
+ status &= ~(1 << core_idx);
+
+ if ((first + core_idx) >= sgi575_core_get_core_count())
+ continue;
+
+ sgi575_system_ctx.ppu_v1_isr_api->ppu_interrupt_handler(
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_PPU_V1, first + core_idx));
+ }
+}
+
+static void ppu_cores_isr_0(void)
+{
+ ppu_cores_isr(0, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[0]);
+ ppu_cores_isr(128, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[4]);
+}
+
+static void ppu_cores_isr_1(void)
+{
+ ppu_cores_isr(32, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[1]);
+ ppu_cores_isr(160, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[5]);
+}
+
+static void ppu_cores_isr_2(void)
+{
+ ppu_cores_isr(64, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[2]);
+ ppu_cores_isr(192, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[6]);
+}
+
+static void ppu_cores_isr_3(void)
+{
+ ppu_cores_isr(96, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[3]);
+ ppu_cores_isr(224, sgi575_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[7]);
+}
+
+static void ppu_clusters_isr(void)
+{
+ uint32_t status = sgi575_system_ctx.pik_scp_reg->CLUS_PPU_INT_STATUS;
+ unsigned int cluster_idx;
+
+ while (status != 0) {
+ cluster_idx = __builtin_ctz(status);
+
+ sgi575_system_ctx.ppu_v1_isr_api->ppu_interrupt_handler(
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_PPU_V1,
+ sgi575_core_get_core_count() + cluster_idx));
+
+ status &= ~(1 << cluster_idx);
+ }
+}
+
+/*
+ * PPU Interrupt Service Routine table
+ */
+
+static struct sgi575_system_isr isrs[] = {
+ [0] = { .interrupt = PPU_CORES0_IRQ,
+ .handler = ppu_cores_isr_0 },
+ [1] = { .interrupt = PPU_CORES1_IRQ,
+ .handler = ppu_cores_isr_1 },
+ [2] = { .interrupt = PPU_CORES2_IRQ,
+ .handler = ppu_cores_isr_2 },
+ [3] = { .interrupt = PPU_CORES3_IRQ,
+ .handler = ppu_cores_isr_3 },
+ [4] = { .interrupt = PPU_CLUSTERS_IRQ,
+ .handler = ppu_clusters_isr },
+};
+
+/*
+ * SYSTEM POWER driver API
+ */
+
+static int sgi575_system_shutdown(
+ enum mod_pd_system_shutdown system_shutdown)
+{
+ NVIC_SystemReset();
+
+ return FWK_E_DEVICE;
+}
+
+static const struct mod_system_power_driver_api
+ sgi575_system_system_power_driver_api = {
+ .system_shutdown = sgi575_system_shutdown,
+};
+
+/*
+ * Functions fulfilling the framework's module interface
+ */
+
+static int sgi575_system_mod_init(fwk_id_t module_id, unsigned int unused,
+ const void *unused2)
+{
+ int status;
+ unsigned int idx;
+ struct sgi575_system_isr *isr;
+
+ for (idx = 0; idx < FWK_ARRAY_SIZE(isrs); idx++) {
+ isr = &isrs[idx];
+ status = fwk_interrupt_set_isr(isr->interrupt, isr->handler);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+
+ sgi575_system_ctx.pik_scp_reg = (struct pik_scp_reg *)SCP_PIK_SCP_BASE;
+
+ return FWK_SUCCESS;
+}
+
+static int sgi575_system_bind(fwk_id_t id, unsigned int round)
+{
+ int status;
+
+ if (round == 0) {
+ status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG),
+ FWK_ID_API(FWK_MODULE_IDX_LOG, 0), &sgi575_system_ctx.log_api);
+ if (status != FWK_SUCCESS)
+ return status;
+ }
+
+ status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_POWER_DOMAIN),
+ FWK_ID_API(FWK_MODULE_IDX_POWER_DOMAIN, MOD_PD_API_IDX_RESTRICTED),
+ &sgi575_system_ctx.mod_pd_restricted_api);
+ if (status != FWK_SUCCESS)
+ return status;
+
+ return fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_PPU_V1),
+ FWK_ID_API(FWK_MODULE_IDX_PPU_V1, MOD_PPU_V1_API_IDX_ISR),
+ &sgi575_system_ctx.ppu_v1_isr_api);
+}
+
+static int sgi575_system_process_bind_request(fwk_id_t requester_id,
+ fwk_id_t pd_id, fwk_id_t api_id, const void **api)
+{
+ *api = &sgi575_system_system_power_driver_api;
+ return FWK_SUCCESS;
+}
+
+static int sgi575_system_start(fwk_id_t id)
+{
+ int status;
+
+ status = fwk_notification_subscribe(
+ mod_clock_notification_id_state_changed,
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_CLOCK, CLOCK_IDX_INTERCONNECT),
+ id);
+ if (status != FWK_SUCCESS)
+ return status;
+
+ sgi575_system_ctx.log_api->log(MOD_LOG_GROUP_DEBUG,
+ "[SGI575 SYSTEM] Requesting SYSTOP initialization...\n");
+
+ return
+ sgi575_system_ctx.mod_pd_restricted_api->set_composite_state_async(
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, 0), false,
+ MOD_PD_COMPOSITE_STATE(MOD_PD_LEVEL_2, 0, MOD_PD_STATE_ON,
+ MOD_PD_STATE_OFF, MOD_PD_STATE_OFF));
+}
+
+int sgi575_system_process_notification(const struct fwk_event *event,
+ struct fwk_event *resp_event)
+{
+ int status;
+ struct clock_notification_params *params;
+ struct mod_pd_restricted_api *mod_pd_restricted_api;
+
+ assert(fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed));
+ assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE));
+
+ params = (struct clock_notification_params *)event->params;
+
+ /*
+ * Initialize primary core when the system is initialized for the first time
+ * only
+ */
+ if (params->new_state == MOD_CLOCK_STATE_RUNNING) {
+ sgi575_system_ctx.log_api->log(MOD_LOG_GROUP_DEBUG,
+ "[SGI575 SYSTEM] Initializing the primary core...\n");
+
+ mod_pd_restricted_api = sgi575_system_ctx.mod_pd_restricted_api;
+
+ status = mod_pd_restricted_api->set_composite_state_async(
+ FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, 0),
+ false,
+ MOD_PD_COMPOSITE_STATE(MOD_PD_LEVEL_2, 0, MOD_PD_STATE_ON,
+ MOD_PD_STATE_ON, MOD_PD_STATE_ON));
+ if (status != FWK_SUCCESS)
+ return status;
+
+ /* Unsubscribe to the notification */
+ return fwk_notification_unsubscribe(event->id, event->source_id,
+ event->target_id);
+ }
+
+ return FWK_SUCCESS;
+}
+
+const struct fwk_module module_sgi575_system = {
+ .name = "SGI575_SYSTEM",
+ .type = FWK_MODULE_TYPE_DRIVER,
+ .api_count = MOD_SGI575_SYSTEM_API_COUNT,
+ .init = sgi575_system_mod_init,
+ .bind = sgi575_system_bind,
+ .process_bind_request = sgi575_system_process_bind_request,
+ .process_notification = sgi575_system_process_notification,
+ .start = sgi575_system_start,
+};