diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index 1112f6e80fb757099976571701a7d87779d9ea31..520137c3a8ec16f66eeb94e96ef6d46b8c3be056 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -74,6 +74,7 @@ list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/mock_voltage_domain") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/traffic_cop") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/mpmm") list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/thermal_mgmt") +list(APPEND SCP_MODULE_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/sp805") foreach(source_dir IN LISTS SCP_MODULE_PATHS) unset(SCP_MODULE) diff --git a/module/sp805/CMakeLists.txt b/module/sp805/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc5fab9ae30e150c4c80547734be4dc978de2296 --- /dev/null +++ b/module/sp805/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +add_library(${SCP_MODULE_TARGET} SCP_MODULE) + +target_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_sources(${SCP_MODULE_TARGET} + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_sp805.c") + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-clock) diff --git a/module/sp805/Module.cmake b/module/sp805/Module.cmake new file mode 100644 index 0000000000000000000000000000000000000000..173d72c4cb93213f93193da46c9fb390609a54a0 --- /dev/null +++ b/module/sp805/Module.cmake @@ -0,0 +1,9 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(SCP_MODULE "sp805") +set(SCP_MODULE_TARGET "module-sp805") diff --git a/module/sp805/include/mod_sp805.h b/module/sp805/include/mod_sp805.h new file mode 100644 index 0000000000000000000000000000000000000000..f40f960a0d33b8941ea2bed717eb95900d5ae786 --- /dev/null +++ b/module/sp805/include/mod_sp805.h @@ -0,0 +1,140 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SP805 Watchdog Driver + */ + +#ifndef MOD_SP805_H +#define MOD_SP805_H + +#include + +/*! + * Macros to enable/disable write access to SP805 registers. Writing the value + * 0x1ACCE551 to WdogLock register enables write access to all other registers. + * Writing any other value disables write access. + */ +#define ENABLE_WR_ACCESS 0x1ACCE551 +#define DISABLE_WR_ACCESS 0xFFFFFFFF + +/*! + * Macros for enabling SP805 module reset output and interrupt event. + */ +#define RESET_EN (1 << 1) +#define INT_EN (1 << 0) + +/*! + * \brief Represent SP805 WDT module register definitions. + */ +struct sp805_reg { + /*! + * Load Register, contains the value from which the counter is to decrement + */ + FWK_RW uint32_t LOAD; + + /*! Value Register, gives the current value of the decrementing counter */ + FWK_R uint32_t VALUE; + + /*! Control register, enables the software to control the Watchdog module */ + FWK_RW uint32_t CONTROL; + + /*! + * Interrupt Clear Register, A write of any value to this location clears + * the Watchdog module interrupt, and reloads the counter from the value in + * the WdogLoad Register + */ + FWK_W uint32_t INTCLR; + + /*! + * Raw Interrupt Status Register, indicates the raw interrupt status from + * the counter + */ + FWK_R uint32_t RIS; + + /*! + * Masked Interrupt Status Register,indicates the masked interrupt status + * from the counter + */ + FWK_R uint32_t MIS; + + /*! Reserved region 1*/ + uint8_t RESERVED1[0xC00 - 0x18]; + + /*! Lock Register, allows write-access to all other registers */ + FWK_RW uint32_t LOCK; + + /*! Reserved region 2*/ + uint8_t RESERVED2[0xF00 - 0xC04]; + + /*! + * Integration Test Control Register, use to enable integration test mode + */ + FWK_RW uint32_t ITCR; + + /*! + * Integration Test Output Set Register, When in integration test mode, the + * enabled interrupt output and reset output are driven directly from the + * values in this register + */ + FWK_W uint32_t ITOP; + + /*! Reserved region 3*/ + uint8_t RESERVED3[0xFE0 - 0xF08]; + + /*! Peripheral identification register 0 */ + FWK_R uint32_t PERIPHID0; + + /*! Peripheral identification register 1 */ + FWK_R uint32_t PERIPHID1; + + /*! Peripheral identification register 2 */ + FWK_R uint32_t PERIPHID2; + + /*! Peripheral identification register 3 */ + FWK_R uint32_t PERIPHID3; + + /*! PrimeCell Identification Register 0 */ + FWK_R uint32_t PCELLID0; + + /*! PrimeCell Identification Register 1 */ + FWK_R uint32_t PCELLID1; + + /*! PrimeCell Identification Register 2 */ + FWK_R uint32_t PCELLID2; + + /*! PrimeCell Identification Register 3 */ + FWK_R uint32_t PCELLID3; +}; + +/*! + * \brief Configuration data for a SP805 WatchDog device. + */ +struct mod_sp805_config { + /*! Base address of the device registers */ + const uintptr_t reg_base; + + /*! Watchdog Timer value to be loaded in the timer register */ + const unsigned int wdt_load_value; + + /*! + * Identifier of the clock that this device depends on. If the device is not + * dependent on any clock, FWK_ID_NONE_INIT should be assigned for this + * configuration value. + */ + fwk_id_t driver_id; + + /*! + * Watch Dog device IRQ number + * + * Please note that sp805 driver is expecting a valid interrupt number in + * sp805_irq. If FWK_INTERRUPT_NONE is assigned, the SP805 controller is not + * enabled. + */ + const unsigned int sp805_irq; +}; + +#endif /* MOD_SP805_H */ diff --git a/module/sp805/src/mod_sp805.c b/module/sp805/src/mod_sp805.c new file mode 100644 index 0000000000000000000000000000000000000000..8ac2c391a936da758fdff3a7f26a9dddff363f95 --- /dev/null +++ b/module/sp805/src/mod_sp805.c @@ -0,0 +1,125 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include + +#define MOD_NAME "[SP805] " + +/* SP805 Watchdog Timer device context */ +struct mod_sp805_dev_ctx { + const struct mod_sp805_config *config; + struct sp805_reg *reg_base; +}; + +static struct mod_sp805_dev_ctx ctx; + +static void sp805_isr(uintptr_t unused) +{ + FWK_LOG_TRACE(MOD_NAME "SP805 watchdog timer interrupt generated."); + + /* Clear the watchdog Interrupt */ + ctx.reg_base->LOCK = ENABLE_WR_ACCESS; + ctx.reg_base->INTCLR = 0; + ctx.reg_base->LOCK = DISABLE_WR_ACCESS; + + fwk_interrupt_clear_pending(ctx.config->sp805_irq); +} + +static void enable_sp805_interrupt(void) +{ + /* + * Ensure that a valid interrupt number has been specified in the + * configuration data. If not specified, the SP805 WDT is not enabled + * because there is no other mechanism to write to the WdogIntClr register + * when the counter value reaches zero. + */ + if (ctx.config->sp805_irq == FWK_INTERRUPT_NONE) { + FWK_LOG_ERR(MOD_NAME + "Interrupt number not specified in config data, failed to " + "enable watchdog!"); + return; + } + + ctx.reg_base->LOCK = ENABLE_WR_ACCESS; + ctx.reg_base->LOAD = ctx.config->wdt_load_value; + + /* Enable interrupt event and reset output */ + ctx.reg_base->CONTROL = RESET_EN | INT_EN; + ctx.reg_base->LOCK = DISABLE_WR_ACCESS; + fwk_interrupt_set_isr_param( + ctx.config->sp805_irq, sp805_isr, (uintptr_t)NULL); + + fwk_interrupt_clear_pending(ctx.config->sp805_irq); + fwk_interrupt_enable(ctx.config->sp805_irq); + + FWK_LOG_INFO( + MOD_NAME "WatchDog Interrupt enabled, WdogLoad value: %x", + (unsigned int)ctx.reg_base->LOAD); +} + +/* + * Framework handlers + */ +static int mod_sp805_init( + fwk_id_t module_id, + unsigned int unused, + const void *data) +{ + ctx.config = (struct mod_sp805_config *)data; + fwk_assert(ctx.config != NULL); + + ctx.reg_base = (struct sp805_reg *)ctx.config->reg_base; + if (ctx.reg_base == NULL) { + FWK_LOG_ERR(MOD_NAME "Register base address missing in config data"); + return FWK_E_DATA; + } + + return FWK_SUCCESS; +} + +static int mod_sp805_start(fwk_id_t id) +{ + if (!fwk_id_is_type(ctx.config->driver_id, FWK_ID_TYPE_NONE)) { + /* Register for clock state notifications */ + return fwk_notification_subscribe( + mod_clock_notification_id_state_changed, ctx.config->driver_id, id); + } else { + enable_sp805_interrupt(); + } + + return FWK_SUCCESS; +} + +static int mod_sp805_process_notification( + const struct fwk_event *event, + struct fwk_event *resp_event) +{ + struct clock_notification_params *params; + + fwk_assert( + fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed)); + + params = (struct clock_notification_params *)event->params; + if (params->new_state == MOD_CLOCK_STATE_RUNNING) { + enable_sp805_interrupt(); + } + + return FWK_SUCCESS; +} + +const struct fwk_module module_sp805 = { + .type = FWK_MODULE_TYPE_DRIVER, + .init = mod_sp805_init, + .start = mod_sp805_start, + .process_notification = mod_sp805_process_notification, +}; diff --git a/product/rdn2/include/scp_css_mmap.h b/product/rdn2/include/scp_css_mmap.h index fc04ce0bfdebc675da951fb6a4e2a4437b00a4bd..6abfb89dc1e2bb92d6f567a47509321587528639 100644 --- a/product/rdn2/include/scp_css_mmap.h +++ b/product/rdn2/include/scp_css_mmap.h @@ -1,6 +1,6 @@ /* * Arm SCP/MCP Software - * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,6 +18,7 @@ #define SCP_REFCLK_CNTCTL_BASE (SCP_PERIPHERAL_BASE + 0x0000) #define SCP_REFCLK_CNTBASE0_BASE (SCP_PERIPHERAL_BASE + 0x1000) #define SCP_UART_BASE (SCP_PERIPHERAL_BASE + 0x2000) +#define SCP_SP805_WDOG_BASE (SCP_PERIPHERAL_BASE + 0x6000) #define SCP_MHU_AP_BASE (SCP_PERIPHERAL_BASE + 0x1000000) #define SCP_PIK_SCP_BASE (SCP_PIK_BASE) diff --git a/product/rdn2/scp_ramfw/CMakeLists.txt b/product/rdn2/scp_ramfw/CMakeLists.txt index ecfea0926387123ca54c964db4c830abe810dcea..9c29718d619f5c9da85be83cbe01b2a64e4cd562 100644 --- a/product/rdn2/scp_ramfw/CMakeLists.txt +++ b/product/rdn2/scp_ramfw/CMakeLists.txt @@ -66,6 +66,7 @@ target_sources( "${CMAKE_CURRENT_SOURCE_DIR}/config_mock_psu.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_dvfs.c" "${CMAKE_CURRENT_SOURCE_DIR}/config_scmi_perf.c" + "${CMAKE_CURRENT_SOURCE_DIR}/config_sp805.c" "${CMAKE_CURRENT_SOURCE_DIR}/../src/config_system_info.c" "${CMAKE_CURRENT_SOURCE_DIR}/../src/config_pl011.c" "${CMAKE_CURRENT_SOURCE_DIR}/../src/config_sid.c") diff --git a/product/rdn2/scp_ramfw/Firmware.cmake b/product/rdn2/scp_ramfw/Firmware.cmake index 419cf1223b38a2f2c2881c715470935c14ec7d70..da0e6c6eed30a5f4dea8d8e7a4086b0d3f921878 100644 --- a/product/rdn2/scp_ramfw/Firmware.cmake +++ b/product/rdn2/scp_ramfw/Firmware.cmake @@ -64,6 +64,7 @@ list(APPEND SCP_MODULES "power-domain") list(APPEND SCP_MODULES "scmi-power-domain") list(APPEND SCP_MODULES "scmi-system-power") list(APPEND SCP_MODULES "platform-system") +list(APPEND SCP_MODULES "sp805") list(APPEND SCP_MODULES "psu") list(APPEND SCP_MODULES "mock-psu") list(APPEND SCP_MODULES "dvfs") diff --git a/product/rdn2/scp_ramfw/config_sp805.c b/product/rdn2/scp_ramfw/config_sp805.c new file mode 100644 index 0000000000000000000000000000000000000000..4704d5867036e8958c628c16c62c63a25064e657 --- /dev/null +++ b/product/rdn2/scp_ramfw/config_sp805.c @@ -0,0 +1,32 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include +#include + +/* SCP uses NMI as Watchdog interrupt line */ +#define SCP_WDOG_IRQ FWK_INTERRUPT_NMI + +/* Reload value for the WdogLoad register */ +#define LOAD_VALUE 0x0fffffff + +/* + * Watch Dog Timer Driver configuration + */ +const struct fwk_module_config config_sp805 = { + .data = + &(struct mod_sp805_config){ + .reg_base = SCP_SP805_WDOG_BASE, + .wdt_load_value = LOAD_VALUE, + .driver_id = FWK_ID_NONE_INIT, + .sp805_irq = SCP_WDOG_IRQ, + } +};