diff --git a/CODEOWNERS b/CODEOWNERS index b45c040cb1f..9d7965dac14 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -122,6 +122,7 @@ /drivers/i2s/i2s_ll_stm32* @avisconti /drivers/ieee802154/ @jukkar @tbursztyka /drivers/interrupt_controller/ @andrewboie +/drivers/ipm/ipm_mhu* @karl-zh /drivers/*/vexriscv_litex.c @mateusz-holenko @kgugala @pgielda /drivers/led/ @Mani-Sadhasivam /drivers/led_strip/ @mbolivar diff --git a/boards/arm/v2m_musca/v2m_musca-common.dtsi b/boards/arm/v2m_musca/v2m_musca-common.dtsi index 736d4454ef5..8aae94b1751 100644 --- a/boards/arm/v2m_musca/v2m_musca-common.dtsi +++ b/boards/arm/v2m_musca/v2m_musca-common.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Linaro Limited + * Copyright (c) 2018-2019 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,20 @@ dtimer0: dtimer@2000 { label = "DTIMER_0"; }; +mhu0: mhu@3000 { + compatible = "arm,mhu"; + reg = <0x3000 0x1000>; + interrupts = <6 3>; + label = "MHU_0"; +}; + +mhu1: mhu@4000 { + compatible = "arm,mhu"; + reg = <0x4000 0x1000>; + interrupts = <7 3>; + label = "MHU_1"; +}; + wdog0: wdog@81000 { compatible = "arm,cmsdk-watchdog"; reg = <0x81000 0x1000>; diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index 0a902379cce..793a00f8a4b 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -5,5 +5,6 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_IPM_MCUX ipm_mcux.c) zephyr_library_sources_ifdef(CONFIG_IPM_IMX ipm_imx.c) zephyr_library_sources_ifdef(CONFIG_IPM_QUARK_SE ipm_quark_se.c) +zephyr_library_sources_ifdef(CONFIG_IPM_MHU ipm_mhu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE ipm_handlers.c) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index 902d037ef2a..f37c017749e 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -76,3 +76,9 @@ config IPM_IMX_MAX_ID_VAL default 1 if IPM_IMX_MAX_DATA_SIZE_8 default 0 if IPM_IMX_MAX_DATA_SIZE_16 depends on IPM_IMX + +config IPM_MHU + bool "IPM MHU driver" + depends on IPM + help + Driver for SSE 200 MHU (Message Handling Unit) diff --git a/drivers/ipm/ipm_mhu.c b/drivers/ipm/ipm_mhu.c new file mode 100644 index 00000000000..eb0912062c4 --- /dev/null +++ b/drivers/ipm/ipm_mhu.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "ipm_mhu.h" + +#define DEV_CFG(dev) \ + ((const struct ipm_mhu_device_config * const)(dev)->config->config_info) +#define DEV_DATA(dev) \ + ((struct ipm_mhu_data *)(dev)->driver_data) +#define IPM_MHU_REGS(dev) \ + ((volatile struct ipm_mhu_reg_map_t *)(DEV_CFG(dev))->base) + +static enum ipm_mhu_cpu_id_t ipm_mhu_get_cpu_id(const struct device *d) +{ + volatile u32_t *p_mhu_dev_base; + volatile u32_t *p_cpu_id; + + p_mhu_dev_base = (volatile u32_t *)IPM_MHU_REGS(d); + + p_cpu_id = (volatile u32_t *)(((u32_t)p_mhu_dev_base & + SSE_200_DEVICE_BASE_REG_MSK) + + SSE_200_CPU_ID_UNIT_OFFSET); + + return (enum ipm_mhu_cpu_id_t)*p_cpu_id; +} + +static u32_t ipm_mhu_get_status(const struct device *d, + enum ipm_mhu_cpu_id_t cpu_id, + u32_t *status) +{ + struct ipm_mhu_reg_map_t *p_mhu_dev; + + if (status == NULL) { + return IPM_MHU_ERR_INVALID_ARG; + } + + p_mhu_dev = (struct ipm_mhu_reg_map_t *)IPM_MHU_REGS(d); + + switch (cpu_id) { + case IPM_MHU_CPU1: + *status = p_mhu_dev->cpu1intr_stat; + break; + case IPM_MHU_CPU0: + default: + *status = p_mhu_dev->cpu0intr_stat; + break; + } + + return IPM_MHU_ERR_NONE; +} + +static int ipm_mhu_send(struct device *d, int wait, u32_t cpu_id, + const void *data, int size) +{ + ARG_UNUSED(wait); + ARG_UNUSED(data); + const u32_t set_val = 0x01; + + struct ipm_mhu_reg_map_t *p_mhu_dev; + + if (cpu_id >= IPM_MHU_CPU_MAX) { + return -EINVAL; + } + + if (size > IPM_MHU_MAX_DATA_SIZE) { + return -EMSGSIZE; + } + + p_mhu_dev = (struct ipm_mhu_reg_map_t *)IPM_MHU_REGS(d); + + switch (cpu_id) { + case IPM_MHU_CPU1: + p_mhu_dev->cpu1intr_set = set_val; + break; + case IPM_MHU_CPU0: + default: + p_mhu_dev->cpu0intr_set = set_val; + break; + } + + return 0; +} + +static void ipm_mhu_clear_val(const struct device *d, + enum ipm_mhu_cpu_id_t cpu_id, + u32_t clear_val) +{ + struct ipm_mhu_reg_map_t *p_mhu_dev; + + p_mhu_dev = (struct ipm_mhu_reg_map_t *)IPM_MHU_REGS(d); + + switch (cpu_id) { + case IPM_MHU_CPU1: + p_mhu_dev->cpu1intr_clr = clear_val; + break; + case IPM_MHU_CPU0: + default: + p_mhu_dev->cpu0intr_clr = clear_val; + break; + } +} + +static u32_t ipm_mhu_max_id_val_get(struct device *d) +{ + ARG_UNUSED(d); + + return IPM_MHU_MAX_ID_VAL; +} + +static int ipm_mhu_init(struct device *d) +{ + const struct ipm_mhu_device_config *config = DEV_CFG(d); + + config->irq_config_func(d); + + return 0; +} + +static void ipm_mhu_isr(void *arg) +{ + struct device *d = arg; + struct ipm_mhu_data *driver_data = DEV_DATA(d); + enum ipm_mhu_cpu_id_t cpu_id; + u32_t ipm_mhu_status; + + cpu_id = ipm_mhu_get_cpu_id(d); + + ipm_mhu_get_status(d, cpu_id, &ipm_mhu_status); + ipm_mhu_clear_val(d, cpu_id, ipm_mhu_status); + + if (driver_data->callback) { + driver_data->callback(driver_data->callback_ctx, cpu_id, + &ipm_mhu_status); + } +} + +static int ipm_mhu_set_enabled(struct device *d, int enable) +{ + ARG_UNUSED(d); + ARG_UNUSED(enable); + return 0; +} + +static int ipm_mhu_max_data_size_get(struct device *d) +{ + ARG_UNUSED(d); + + return IPM_MHU_MAX_DATA_SIZE; +} + +static void ipm_mhu_register_cb(struct device *d, + ipm_callback_t cb, + void *context) +{ + struct ipm_mhu_data *driver_data = DEV_DATA(d); + + driver_data->callback = cb; + driver_data->callback_ctx = context; +} + +static const struct ipm_driver_api ipm_mhu_driver_api = { + .send = ipm_mhu_send, + .register_callback = ipm_mhu_register_cb, + .max_data_size_get = ipm_mhu_max_data_size_get, + .max_id_val_get = ipm_mhu_max_id_val_get, + .set_enabled = ipm_mhu_set_enabled, +}; + +static void ipm_mhu_irq_config_func_0(struct device *d); + +static const struct ipm_mhu_device_config ipm_mhu_cfg_0 = { + .base = (u8_t *)DT_ARM_MHU_0_BASE_ADDRESS, + .irq_config_func = ipm_mhu_irq_config_func_0, +}; + +static struct ipm_mhu_data ipm_mhu_data_0 = { + .callback = NULL, + .callback_ctx = NULL, +}; + +DEVICE_AND_API_INIT(mhu_0, + DT_ARM_MHU_0_LABEL, + &ipm_mhu_init, + &ipm_mhu_data_0, + &ipm_mhu_cfg_0, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &ipm_mhu_driver_api); + +static void ipm_mhu_irq_config_func_0(struct device *d) +{ + ARG_UNUSED(d); + IRQ_CONNECT(DT_ARM_MHU_0_IRQ_0, + DT_ARM_MHU_0_IRQ_0, + ipm_mhu_isr, + DEVICE_GET(mhu_0), + 0); + irq_enable(DT_ARM_MHU_0_IRQ_0); +} + +static void ipm_mhu_irq_config_func_1(struct device *d); + +static const struct ipm_mhu_device_config ipm_mhu_cfg_1 = { + .base = (u8_t *)DT_ARM_MHU_1_BASE_ADDRESS, + .irq_config_func = ipm_mhu_irq_config_func_1, +}; + +static struct ipm_mhu_data ipm_mhu_data_1 = { + .callback = NULL, + .callback_ctx = NULL, +}; + +DEVICE_AND_API_INIT(mhu_1, + DT_ARM_MHU_1_LABEL, + &ipm_mhu_init, + &ipm_mhu_data_1, + &ipm_mhu_cfg_1, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &ipm_mhu_driver_api); + +static void ipm_mhu_irq_config_func_1(struct device *d) +{ + ARG_UNUSED(d); + IRQ_CONNECT(DT_ARM_MHU_1_IRQ_0, + DT_ARM_MHU_1_IRQ_0_PRIORITY, + ipm_mhu_isr, + DEVICE_GET(mhu_1), + 0); + irq_enable(DT_ARM_MHU_1_IRQ_0); +} diff --git a/drivers/ipm/ipm_mhu.h b/drivers/ipm/ipm_mhu.h new file mode 100644 index 00000000000..d9e84f9c252 --- /dev/null +++ b/drivers/ipm/ipm_mhu.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_IPM_IPM_MHU_H_ +#define ZEPHYR_DRIVERS_IPM_IPM_MHU_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPM_MHU_MAX_DATA_SIZE 1 +#define IPM_MHU_MAX_ID_VAL 0 +#define SSE_200_CPU_ID_UNIT_OFFSET ((0x1F000UL)) +#define SSE_200_DEVICE_BASE_REG_MSK (0xF0000000UL) + +/* SSE 200 MHU register map structure */ +struct ipm_mhu_reg_map_t { + /* (R/ ) CPU 0 Interrupt Status Register */ + volatile u32_t cpu0intr_stat; + volatile u32_t cpu0intr_set; /* ( /W) CPU 0 Interrupt Set Register */ + volatile u32_t cpu0intr_clr; /* ( /W) CPU 0 Interrupt Clear Register */ + volatile u32_t reserved0; + /* (R/ ) CPU 1 Interrupt Status Register */ + volatile u32_t cpu1intr_stat; + volatile u32_t cpu1intr_set; /* ( /W) CPU 1 Interrupt Set Register */ + volatile u32_t cpu1intr_clr; /* ( /W) CPU 1 Interrupt Clear Register */ + volatile u32_t reserved1[1004]; + volatile u32_t pidr4; /* ( /W) Peripheral ID 4 */ + volatile u32_t reserved2[3]; + volatile u32_t pidr0; /* ( /W) Peripheral ID 0 */ + volatile u32_t pidr1; /* ( /W) Peripheral ID 1 */ + volatile u32_t pidr2; /* ( /W) Peripheral ID 2 */ + volatile u32_t pidr3; /* ( /W) Peripheral ID 3 */ + volatile u32_t cidr0; /* ( /W) Component ID 0 */ + volatile u32_t cidr1; /* ( /W) Component ID 1 */ + volatile u32_t cidr2; /* ( /W) Component ID 2 */ + volatile u32_t cidr3; /* ( /W) Component ID 3 */ +}; + +/* MHU enumeration types */ +enum ipm_mhu_error_t { + IPM_MHU_ERR_NONE = 0, /* No error */ + IPM_MHU_ERR_INVALID_ARG, /* Invalid argument */ +}; + +/* MHU enumeration types */ +enum ipm_mhu_cpu_id_t { + IPM_MHU_CPU0 = 0, + IPM_MHU_CPU1, + IPM_MHU_CPU_MAX, +}; + +struct ipm_mhu_device_config { + u8_t *base; + void (*irq_config_func)(struct device *d); +}; + +/* Device data structure */ +struct ipm_mhu_data { + ipm_callback_t callback; + void *callback_ctx; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_IPM_IPM_MHU_H_ */ diff --git a/dts/bindings/mhu/arm,mhu.yaml b/dts/bindings/mhu/arm,mhu.yaml new file mode 100644 index 00000000000..c898b7ee2e2 --- /dev/null +++ b/dts/bindings/mhu/arm,mhu.yaml @@ -0,0 +1,38 @@ +# +# Copyright (c) 2019, Linaro Limited +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: ARM MHU +version: 0.1 + +description: > + This binding gives a base representation of the ARM MHU + +properties: + compatible: + type: string + category: required + description: compatible strings + constraint: "arm,mhu" + generation: define + + reg: + type: array + description: mmio register space + generation: define + category: required + + interrupts: + type: array + category: required + description: required interrupts + generation: define + + label: + type: string + category: required + description: Human readable string describing the device (used by Zephyr for API name) + generation: define +...