From 980f899d2355235e51de011c8cabdc3c0cd7cb4a Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Sun, 25 Jun 2023 20:56:39 +0300 Subject: [PATCH] drivers: clock_control: Introduce revision 3 of CCM driver This commit introduces a new version of the CCM driver. The purpose of this is to make the CCM driver usable by all NXP SoCs despite the changes in the HAL API. With this driver, each SoC will have to define its own clock tree and a few common operations such as clock enable/disable, set_rate and get_rate. Signed-off-by: Laurentiu Mihalcea --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.mcux_ccm_rev3 | 8 + .../clock_control_mcux_ccm_rev3.c | 102 ++++++++++++ dts/bindings/clock/nxp,imx-ccm-rev3.yaml | 19 +++ .../clock_control_mcux_ccm_rev3.h | 149 ++++++++++++++++++ 6 files changed, 281 insertions(+) create mode 100644 drivers/clock_control/Kconfig.mcux_ccm_rev3 create mode 100644 drivers/clock_control/clock_control_mcux_ccm_rev3.c create mode 100644 dts/bindings/clock/nxp,imx-ccm-rev3.yaml create mode 100644 include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 5e73ba3da20b175..bf3b89adba8a469 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LPC11U6X clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_XEC clock_control_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM clock_control_mcux_ccm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM_REV2 clock_control_mcux_ccm_rev2.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM_REV3 clock_control_mcux_ccm_rev3.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_MCG clock_control_mcux_mcg.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_PCC clock_control_mcux_pcc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SCG clock_control_mcux_scg.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index c74808e692ebba7..9f75ebe7234990e 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -74,4 +74,6 @@ source "drivers/clock_control/Kconfig.smartbond" source "drivers/clock_control/Kconfig.numaker" +source "drivers/clock_control/Kconfig.mcux_ccm_rev3" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.mcux_ccm_rev3 b/drivers/clock_control/Kconfig.mcux_ccm_rev3 new file mode 100644 index 000000000000000..6bccf4706da79d8 --- /dev/null +++ b/drivers/clock_control/Kconfig.mcux_ccm_rev3 @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_MCUX_CCM_REV3 + bool "MCUX CCM Rev3 driver" + default y + depends on DT_HAS_NXP_IMX_CCM_REV3_ENABLED + help + Enable support for mcux ccm rev3 driver. diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev3.c b/drivers/clock_control/clock_control_mcux_ccm_rev3.c new file mode 100644 index 000000000000000..7db9f157e82d9af --- /dev/null +++ b/drivers/clock_control/clock_control_mcux_ccm_rev3.c @@ -0,0 +1,102 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/* Used for driver binding */ +#define DT_DRV_COMPAT nxp_imx_ccm_rev3 + +extern struct imx_ccm_data imx_ccm_data; +extern struct imx_ccm_config imx_ccm_config; + +static int mcux_ccm_on_off(const struct device *dev, + clock_control_subsys_t sys, bool on) +{ + uint32_t clock_name; + const struct imx_ccm_config *cfg; + + clock_name = (uintptr_t)sys; + cfg = dev->config; + + /* validate clock_name */ + if (clock_name >= cfg->clock_config->clock_num) + return -EINVAL; + + return imx_ccm_clock_on_off(dev, &cfg->clock_config->clocks[clock_name], on); +} + +static int mcux_ccm_on(const struct device *dev, clock_control_subsys_t sys) +{ + return mcux_ccm_on_off(dev, sys, true); +} + +static int mcux_ccm_off(const struct device *dev, clock_control_subsys_t sys) +{ + return mcux_ccm_on_off(dev, sys, false); +} + +static int mcux_ccm_get_rate(const struct device *dev, + clock_control_subsys_t sys, uint32_t *rate) +{ + uint32_t clock_name, returned_rate; + const struct imx_ccm_config *cfg; + + clock_name = (uintptr_t)sys; + cfg = dev->config; + + /* validate clock_name */ + if (clock_name >= cfg->clock_config->clock_num) + return -EINVAL; + + returned_rate = imx_ccm_clock_get_rate(dev, &cfg->clock_config->clocks[clock_name]); + + if (returned_rate > 0) { + *rate = returned_rate; + return 0; + } else { + return returned_rate; + } +} + +static int mcux_ccm_set_rate(const struct device *dev, + clock_control_subsys_t sys, clock_control_subsys_rate_t rate) +{ + uint32_t clock_name, requested_rate; + const struct imx_ccm_config *cfg; + + clock_name = (uintptr_t)sys; + requested_rate = (uintptr_t)rate; + cfg = dev->config; + + /* validate clock_name */ + if (clock_name >= cfg->clock_config->clock_num) + return -EINVAL; + + return imx_ccm_clock_set_rate(dev, &cfg->clock_config->clocks[clock_name], requested_rate); +} + +static int mcux_ccm_init(const struct device *dev) +{ + return imx_ccm_init(dev); +} + +static const struct clock_control_driver_api mcux_ccm_driver_api = { + .on = mcux_ccm_on, + .off = mcux_ccm_off, + .get_rate = mcux_ccm_get_rate, + .set_rate = mcux_ccm_set_rate, +}; + +/* there's only one CCM per SoC */ +DEVICE_DT_INST_DEFINE(0, + &mcux_ccm_init, + NULL, + &imx_ccm_data, &imx_ccm_config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &mcux_ccm_driver_api); diff --git a/dts/bindings/clock/nxp,imx-ccm-rev3.yaml b/dts/bindings/clock/nxp,imx-ccm-rev3.yaml new file mode 100644 index 000000000000000..61781632981ef38 --- /dev/null +++ b/dts/bindings/clock/nxp,imx-ccm-rev3.yaml @@ -0,0 +1,19 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: i.MX CCM (Clock Controller Module) Rev 3 IP node + +compatible: "nxp,imx-ccm-rev3" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 2 + +clock-cells: + - name + - freq diff --git a/include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h b/include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h new file mode 100644 index 000000000000000..7ea4e153326c536 --- /dev/null +++ b/include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h @@ -0,0 +1,149 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCUX_CCM_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCUX_CCM_H_ + +#include +#include + +#define IMX_CCM_MAX_SOURCES 4 + +#define IMX_CCM_FIXED_FREQ(src) ((src).source.fixed.freq) +#define IMX_CCM_PLL_MAX_FREQ(src) ((src).source.pll.max_freq) +#define IMX_CCM_RATE_LIMIT(src) \ + ((src).type == IMX_CCM_TYPE_FIXED ? \ + IMX_CCM_FIXED_FREQ(src) : IMX_CCM_PLL_MAX_FREQ(src)) + +enum imx_ccm_clock_state { + IMX_CCM_CLOCK_STATE_INIT = 0, /* initial state - clock may be gated or not */ + IMX_CCM_CLOCK_STATE_GATED, /* clock is gated */ + IMX_CCM_CLOCK_STATE_UNGATED, /* clock is not gated */ +}; + +enum imx_ccm_type { + IMX_CCM_TYPE_FIXED = 1, + IMX_CCM_TYPE_PLL, + IMX_CCM_TYPE_MAX, +}; + +struct imx_ccm_fixed { + char *name; + uint32_t id; + uint32_t freq; +}; + +struct imx_ccm_pll { + char *name; + uint32_t id; + uint32_t max_freq; /* maximum allowed frequency */ + uint32_t offset; /* offset from PLL regmap */ +}; + +struct imx_ccm_source { + enum imx_ccm_type type; /* source type - fixed or PLL */ + union { + struct imx_ccm_fixed fixed; + struct imx_ccm_pll pll; + } source; +}; + +struct imx_ccm_clock_root { + char *name; + uint32_t id; + struct imx_ccm_source sources[IMX_CCM_MAX_SOURCES]; + uint32_t source_num; +}; + +struct imx_ccm_clock { + char *name; + uint32_t id; + struct imx_ccm_clock_root root; + + uint32_t lpcg_regmap_phys; + uint32_t lpcg_regmap_size; + mm_reg_t lpcg_regmap; + + uint32_t state; +}; + +/* there are a few possible restrictions regarding the clock array: + * + * 1) The index of the clock sources needs to match the + * MUX value. + * e.g: + * The clock root called lpuartx_clock_root has + * the following possible MUX values: + * 00 => PLL0 + * 01 => PLL1 + * 10 => PLL2 + * 11 => PLL3 + * This means that the clock root structure needs + * to be defined as follows: + * struct imx_ccm_clock_root root = { + * .name = "some_name", + * .id = ID_FROM_NXP_HAL, + * .sources = {PLL0, PLL1, PLL2, PLL3}, + * .source_num = 4, + * } + * * note: this restriction is optional as some developers may choose not to + * follow it for their SoC. + * + * + * 2) The macros defined in zephyr/clock/soc_name_ccm.h need to match the indexes + * from the clock array. + * e.g: lpuart1_clock is found at index 5 in the clock array. This means + * that SOC_NAME_LPUART1_CLOCK needs to have value 5. + * + * * note: this restriction is mandatory as it's used in the CCM driver. + * + * 3) The ID value from a clock IP/root/source needs to be a value from the NXP HAL. + * * note: this restriction is optional as some developers may choose not + * to follow it for their SoC. + */ +struct imx_ccm_clock_config { + uint32_t clock_num; + struct imx_ccm_clock *clocks; +}; + +struct imx_ccm_config { + struct imx_ccm_clock_config *clock_config; + + uint32_t regmap_phys; + uint32_t regmap_size; + + uint32_t pll_regmap_phys; + uint32_t pll_regmap_size; +}; + + +struct imx_ccm_data { + mm_reg_t regmap; + mm_reg_t pll_regmap; + + uint32_t ipc_handle; +}; + +/* disable/enable a given clock + * + * it's up to the user of the clock control API to + * make sure that the sequence of operations is valid. + */ +int imx_ccm_clock_on_off(const struct device *dev, struct imx_ccm_clock *clk, bool on); + +/* get the frequency of a given clock */ +int imx_ccm_clock_get_rate(const struct device *dev, struct imx_ccm_clock *clk); + +/* set the rate of a clock. + * + * if successful, the function will return the new rate which + * may differ from the requested rate. + */ +int imx_ccm_clock_set_rate(const struct device *dev, struct imx_ccm_clock *clk, uint32_t rate); + +int imx_ccm_init(const struct device *dev); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCUX_CCM_H_ */