aboutsummaryrefslogtreecommitdiff
path: root/module/mock_clock/src
diff options
context:
space:
mode:
authorLuca Vizzarro <Luca.Vizzarro@arm.com>2020-09-20 23:07:12 +0100
committernicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com>2020-11-11 14:24:21 +0000
commitfd1a72483414ff74bb3f45dcec8efbfeed85139f (patch)
treebd836264c69fa2c342e11db5351dcb0d33987202 /module/mock_clock/src
parent3deb59c5f4c64aa092bb3a4ebc018acf3f746f47 (diff)
module: Add Mock Clock module
The mock clock module allows to smoothly test the firmware while using an emulated system, e.g. FVP. Some clock device drivers require hardware features, such as I2C, in order to function correctly. Under an emulated environment, these features cannot be always reproduced, so the mock clock module allows to replace these clock drivers for a smooth operation. Change-Id: I022c56cdf0cadb062742f83d413fa9bdf4adc5aa Signed-off-by: Luca Vizzarro <Luca.Vizzarro@arm.com>
Diffstat (limited to 'module/mock_clock/src')
-rw-r--r--module/mock_clock/src/Makefile12
-rw-r--r--module/mock_clock/src/mod_mock_clock.c273
2 files changed, 285 insertions, 0 deletions
diff --git a/module/mock_clock/src/Makefile b/module/mock_clock/src/Makefile
new file mode 100644
index 00000000..e220b42b
--- /dev/null
+++ b/module/mock_clock/src/Makefile
@@ -0,0 +1,12 @@
+#
+# Arm SCP/MCP Software
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := mock_clock
+BS_LIB_SOURCES := \
+ mod_mock_clock.c
+
+include $(BS_DIR)/lib.mk
diff --git a/module/mock_clock/src/mod_mock_clock.c b/module/mock_clock/src/mod_mock_clock.c
new file mode 100644
index 00000000..bf9ff1dc
--- /dev/null
+++ b/module/mock_clock/src/mod_mock_clock.c
@@ -0,0 +1,273 @@
+/*
+ * Arm SCP/MCP Software
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mod_clock.h>
+#include <mod_mock_clock.h>
+
+#include <fwk_assert.h>
+#include <fwk_id.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <fwk_status.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+static struct mod_mock_clock_element_ctx {
+ const struct mod_mock_clock_element_cfg *config;
+ unsigned int current_rate_index;
+ enum mod_clock_state state;
+
+ /*
+ * We don't rely on the bootloader leaving the clocks
+ * in any specific state.
+ */
+ bool rate_initialized;
+} * elements_ctx;
+
+static struct mod_mock_clock_element_ctx *mod_mock_clock_get_ctx(
+ fwk_id_t element_id)
+{
+ unsigned int element_idx = fwk_id_get_element_idx(element_id);
+
+ return &elements_ctx[element_idx];
+}
+
+static int get_rate_entry(
+ struct mod_mock_clock_element_ctx *ctx,
+ uint64_t target_rate,
+ const struct mod_mock_clock_rate **entry)
+{
+ unsigned int i;
+
+ fwk_assert(ctx != NULL);
+ fwk_assert(entry != NULL);
+
+ /* Find the entry matching the requested rate */
+ for (i = 0; i < ctx->config->rate_count; i++) {
+ if (ctx->config->rate_table[i].rate == target_rate) {
+ *entry = (struct mod_mock_clock_rate *)&ctx->config->rate_table[i];
+ return FWK_SUCCESS;
+ }
+ }
+
+ return FWK_E_PARAM;
+}
+
+/*
+ * Mock clock driver functions
+ */
+
+static int mod_mock_clock_set_rate(
+ fwk_id_t clock_id,
+ uint64_t rate,
+ enum mod_clock_round_mode round_mode)
+{
+ int status;
+ struct mod_mock_clock_element_ctx *ctx;
+ const struct mod_mock_clock_rate *rate_entry;
+
+ ctx = mod_mock_clock_get_ctx(clock_id);
+
+ if (ctx->state == MOD_CLOCK_STATE_STOPPED)
+ return FWK_E_STATE;
+
+ /*
+ * Look up the divider and source settings. We do not perform any rounding
+ * on the clock rate given as input which has to be precise in order not to
+ * be refused with an FWK_E_PARAM error code.
+ */
+ status = get_rate_entry(ctx, rate, &rate_entry);
+ if (status != FWK_SUCCESS)
+ return FWK_E_PARAM;
+
+ ctx->current_rate_index = rate_entry - ctx->config->rate_table;
+
+ ctx->rate_initialized = true;
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_get_rate(fwk_id_t clock_id, uint64_t *rate)
+{
+ struct mod_mock_clock_element_ctx *ctx;
+
+ ctx = mod_mock_clock_get_ctx(clock_id);
+
+ if (!ctx->rate_initialized)
+ return FWK_E_STATE;
+
+ *rate = ctx->config->rate_table[ctx->current_rate_index].rate;
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_get_rate_from_index(
+ fwk_id_t clock_id,
+ unsigned int rate_index,
+ uint64_t *rate)
+{
+ struct mod_mock_clock_element_ctx *ctx;
+
+ ctx = mod_mock_clock_get_ctx(clock_id);
+
+ if (rate_index >= ctx->config->rate_count)
+ return FWK_E_PARAM;
+
+ *rate = ctx->config->rate_table[rate_index].rate;
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_set_state(
+ fwk_id_t clock_id,
+ enum mod_clock_state state)
+{
+ struct mod_mock_clock_element_ctx *ctx;
+
+ ctx = mod_mock_clock_get_ctx(clock_id);
+
+ ctx->state = state;
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_get_state(
+ fwk_id_t clock_id,
+ enum mod_clock_state *state)
+{
+ struct mod_mock_clock_element_ctx *ctx;
+
+ ctx = mod_mock_clock_get_ctx(clock_id);
+
+ *state = ctx->state;
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_get_range(
+ fwk_id_t clock_id,
+ struct mod_clock_range *range)
+{
+ struct mod_mock_clock_element_ctx *ctx;
+
+ ctx = mod_mock_clock_get_ctx(clock_id);
+
+ range->rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE;
+ range->min = ctx->config->rate_table[0].rate;
+ range->max = ctx->config->rate_table[ctx->config->rate_count - 1].rate;
+ range->rate_count = ctx->config->rate_count;
+
+ return FWK_SUCCESS;
+}
+
+/*
+ * Notification handler invoked after the state of a clock's power domain
+ * has changed.
+ */
+static int mod_mock_clock_process_power_transition(
+ fwk_id_t clock_id,
+ unsigned int state)
+{
+ /* Noop, the power state won't affect this module */
+ return FWK_SUCCESS;
+}
+
+static const struct mod_clock_drv_api mod_mock_clock_driver_api = {
+ .set_rate = mod_mock_clock_set_rate,
+ .get_rate = mod_mock_clock_get_rate,
+ .get_rate_from_index = mod_mock_clock_get_rate_from_index,
+ .set_state = mod_mock_clock_set_state,
+ .get_state = mod_mock_clock_get_state,
+ .get_range = mod_mock_clock_get_range,
+ .process_power_transition = mod_mock_clock_process_power_transition,
+};
+
+static const struct mod_clock_driver_response_api
+ mod_mock_clock_response_driver_api = { 0 };
+
+static int mod_mock_clock_init(
+ fwk_id_t module_id,
+ unsigned int element_count,
+ const void *data)
+{
+ fwk_check(data == NULL);
+
+ elements_ctx = fwk_mm_calloc(element_count, sizeof(elements_ctx[0]));
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_element_init(
+ fwk_id_t element_id,
+ unsigned int sub_element_count,
+ const void *data)
+{
+ unsigned int rate_index = 0;
+ uint64_t rate;
+ uint64_t last_rate = 0;
+ struct mod_mock_clock_element_ctx *ctx;
+ const struct mod_mock_clock_element_cfg *cfg = data;
+
+ fwk_check(sub_element_count == 0);
+
+ ctx = mod_mock_clock_get_ctx(element_id);
+
+ /* Verify that the rate entries in the lookup table are ordered */
+ for (rate_index = 0; rate_index < cfg->rate_count; rate_index++) {
+ rate = cfg->rate_table[rate_index].rate;
+
+ /* The rate entries must be in ascending order */
+ if (rate < last_rate)
+ return FWK_E_DATA;
+
+ last_rate = rate;
+ }
+
+ ctx->config = cfg;
+ ctx->state = MOD_CLOCK_STATE_RUNNING;
+
+ return FWK_SUCCESS;
+}
+
+static int mod_mock_clock_process_bind_request(
+ fwk_id_t source_id,
+ fwk_id_t target_id,
+ fwk_id_t api_id,
+ const void **api)
+{
+ enum mod_mock_clock_api_type api_type = fwk_id_get_api_idx(api_id);
+
+ if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT))
+ return FWK_E_ACCESS;
+
+ switch (api_type) {
+ case MOD_MOCK_CLOCK_API_TYPE_DRIVER:
+ *api = &mod_mock_clock_driver_api;
+ return FWK_SUCCESS;
+
+ case MOD_MOCK_CLOCK_API_TYPE_RESPONSE_DRIVER:
+ *api = &mod_mock_clock_response_driver_api;
+ return FWK_SUCCESS;
+
+ default:
+ return FWK_E_ACCESS;
+ }
+}
+
+const struct fwk_module module_mock_clock = {
+ .name = "mock_clock",
+ .type = FWK_MODULE_TYPE_DRIVER,
+
+ .init = mod_mock_clock_init,
+ .element_init = mod_mock_clock_element_init,
+
+ .api_count = MOD_MOCK_CLOCK_API_COUNT,
+ .process_bind_request = mod_mock_clock_process_bind_request,
+};