From bc305984565a8f30e8afd02026dc99c16853a362 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 3 Jun 2021 11:03:48 +0200 Subject: [PATCH] drivers: syscon: Add generic syscon API A syscon device is a device managing a memory region containing a set of registers that are not cohesive enough to represent as any specific type of device. We need a driver for that because several other drivers could use the same region at the same time and we need to io-map the region at boot for MMU enabled platforms. Signed-off-by: Carlo Caione --- CODEOWNERS | 1 + drivers/CMakeLists.txt | 1 + drivers/Kconfig | 2 + drivers/syscon/CMakeLists.txt | 3 + drivers/syscon/Kconfig | 43 ++++++++++++ drivers/syscon/syscon.c | 117 ++++++++++++++++++++++++++++++++ dts/bindings/syscon/syscon.yaml | 12 ++++ include/drivers/syscon.h | 70 +++++++++++++++++++ 8 files changed, 249 insertions(+) create mode 100644 drivers/syscon/CMakeLists.txt create mode 100644 drivers/syscon/Kconfig create mode 100644 drivers/syscon/syscon.c create mode 100644 dts/bindings/syscon/syscon.yaml create mode 100644 include/drivers/syscon.h diff --git a/CODEOWNERS b/CODEOWNERS index 90160a1e051..468417514a3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -186,6 +186,7 @@ /drivers/adc/adc_stm32.c @cybertale /drivers/bluetooth/ @joerchan @jhedberg @Vudentz /drivers/cache/ @carlocaione +/drivers/syscon/ @carlocaione /drivers/can/ @alexanderwachter /drivers/can/*mcp2515* @karstenkoenig /drivers/can/*rcar* @julien-massot diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 483895f2266..aa6fd19403e 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -57,3 +57,4 @@ add_subdirectory_ifdef(CONFIG_NEURAL_NET_ACCEL neural_net) add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock) add_subdirectory_ifdef(CONFIG_EDAC edac) add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache) +add_subdirectory_ifdef(CONFIG_SYSCON syscon) diff --git a/drivers/Kconfig b/drivers/Kconfig index 546a3aaaa44..4b913ea4c0f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -115,4 +115,6 @@ source "drivers/disk/Kconfig" source "drivers/cache/Kconfig" +source "drivers/syscon/Kconfig" + endmenu diff --git a/drivers/syscon/CMakeLists.txt b/drivers/syscon/CMakeLists.txt new file mode 100644 index 00000000000..1e8fc34d941 --- /dev/null +++ b/drivers/syscon/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_SYSCON syscon.c) diff --git a/drivers/syscon/Kconfig b/drivers/syscon/Kconfig new file mode 100644 index 00000000000..bbc14e8161f --- /dev/null +++ b/drivers/syscon/Kconfig @@ -0,0 +1,43 @@ +# SYSCON configuration options + +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +# +# SYSCON options +# +menuconfig SYSCON + bool "SYSCON (System Controller) drivers" + help + SYSCON (System Controller) drivers. System controller node represents + a register region containing a set of miscellaneous registers. The + registers are not cohesive enough to represent as any specific type + of device. The typical use-case is for some other node's driver, or + platform-specific code, to acquire a reference to the syscon node and + extract information from there. + +if SYSCON + +module = SYSCON +module-str = syscon +source "subsys/logging/Kconfig.template.log_config" + +DT_COMPAT_SYSCON := syscon + +config SYSCON_GENERIC + bool "Generic SYSCON (System Controller) driver" + default $(dt_compat_enabled,$(DT_COMPAT_SYSCON)) + help + Enable generic SYSCON (System Controller) driver + +config SYSCON_GENERIC_INIT_PRIORITY_DEVICE + int "SYSCON (System Controller) generic init device priority" + default 50 + depends on SYSCON_GENERIC + help + This option controls the priority of the syscon device + initialization. Higher priority ensures that the device is + initialized earlier in the startup cycle. If unsure, leave at default + value + +endif # SYSCON diff --git a/drivers/syscon/syscon.c b/drivers/syscon/syscon.c new file mode 100644 index 00000000000..5489c7f641b --- /dev/null +++ b/drivers/syscon/syscon.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT syscon + +#include +#include +#include + +#include + +static const struct device *syscon_dev; + +struct syscon_generic_config { + DEVICE_MMIO_ROM; +}; + +static struct syscon_generic_config syscon_generic_config_0 = { + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(0)), +}; + +struct syscon_generic_data { + DEVICE_MMIO_RAM; + size_t size; +}; + +static struct syscon_generic_data syscon_generic_data_0; + +uintptr_t syscon_generic_get_base(void) +{ + if (!syscon_dev) { + return -ENODEV; + } + + return DEVICE_MMIO_GET(syscon_dev); +} + +static int sanitize_reg(uint16_t *reg, size_t reg_size) +{ + /* Avoid unaligned readings */ + *reg = ROUND_DOWN(*reg, sizeof(uint32_t)); + + /* Check for out-of-bounds readings */ + if (*reg >= reg_size) { + return -EINVAL; + } + + return 0; +} + +int syscon_generic_read_reg(uint16_t reg, uint32_t *val) +{ + struct syscon_generic_data *data; + uintptr_t base_address; + + if (!syscon_dev) { + return -ENODEV; + } + + data = syscon_dev->data; + + if (!val) { + return -EINVAL; + } + + if (sanitize_reg(®, data->size)) { + return -EINVAL; + } + + base_address = DEVICE_MMIO_GET(syscon_dev); + + *val = sys_read32(base_address + reg); + + return 0; +} + +int syscon_generic_write_reg(uint16_t reg, uint32_t val) +{ + struct syscon_generic_data *data; + uintptr_t base_address; + + if (!syscon_dev) { + return -ENODEV; + } + + data = syscon_dev->data; + + if (sanitize_reg(®, data->size)) { + return -EINVAL; + } + + base_address = DEVICE_MMIO_GET(syscon_dev); + + sys_write32(val, (base_address + reg)); + + return 0; +} + +int syscon_generic_init(const struct device *dev) +{ + struct syscon_generic_data *data = dev->data; + + syscon_dev = dev; + + DEVICE_MMIO_MAP(syscon_dev, K_MEM_CACHE_NONE); + + data->size = DT_REG_SIZE(DT_DRV_INST(0)); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, syscon_generic_init, NULL, &syscon_generic_data_0, + &syscon_generic_config_0, PRE_KERNEL_1, + CONFIG_SYSCON_GENERIC_INIT_PRIORITY_DEVICE, NULL); diff --git a/dts/bindings/syscon/syscon.yaml b/dts/bindings/syscon/syscon.yaml new file mode 100644 index 00000000000..5f9c1fed04a --- /dev/null +++ b/dts/bindings/syscon/syscon.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +description: System Controller Registers R/W + +compatible: "syscon" + +include: base.yaml + +properties: + reg: + required: true diff --git a/include/drivers/syscon.h b/include/drivers/syscon.h new file mode 100644 index 00000000000..cfd98889b68 --- /dev/null +++ b/include/drivers/syscon.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public SYSCON driver APIs + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SYSCON_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SYSCON_H_ + +/** + * @brief SYSCON Interface + * @defgroup syscon_interface SYSCON Interface + * @ingroup io_interfaces + * @{ + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get the syscon base address + * + * This function returns the syscon base address + * + * @return 0 on error, the base address on success + */ +uintptr_t syscon_get_base(void); + +/** + * @brief Read from syscon register + * + * This function reads from a specific register in the syscon area + * + * @param reg The register offset + * @param val The returned value read from the syscon register + * + * @return 0 on success, negative on error + */ +int syscon_read_reg(uint16_t reg, uint32_t *val); + +/** + * @brief Write to syscon register + * + * This function writes to a specific register in the syscon area + * + * @param reg The register offset + * @param val The value to be written in the register + * + * @return 0 on success, negative on error + */ +int syscon_write_reg(uint16_t reg, uint32_t val); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SYSCON_H_ */