diff options
author | Amit Daniel Kachhap <amit.kachhap@arm.com> | 2018-07-20 17:10:25 +0530 |
---|---|---|
committer | ronald-cron-arm <39518861+ronald-cron-arm@users.noreply.github.com> | 2018-10-18 17:22:34 +0000 |
commit | 4102c08df350404298f9e9acb49e3c259b3661ea (patch) | |
tree | dd437f070bdfdaa7cb679211d1ac5509fd18e853 /product/sgi575 | |
parent | c0ab6c61af055205b3801e16e549ed76340c5f57 (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')
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, +}; |