-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MHU (Message Handling Unit) enable software to raise interrupts to the processor cores. It enabled in SSE 200 subsystems. This patch aims to implement inter processor communication. It performs similar mechanism with existing ipm except data registers. Signed-off-by: Karl Zhang <karl.zhang@linaro.org>
- Loading branch information
Karl Zhang
committed
Jan 26, 2019
1 parent
7117b73
commit cece68c
Showing
6 changed files
with
378 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
/* | ||
* Copyright (c) 2019 Linaro Limited | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <errno.h> | ||
#include <device.h> | ||
#include <soc.h> | ||
#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) | ||
|
||
#if defined(CONFIG_IPM_MHU0) || defined(CONFIG_IPM_MHU1) | ||
|
||
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 & 0xF0000000) + | ||
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); | ||
u32_t set_val = *(u32_t *)data; | ||
|
||
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, | ||
}; | ||
|
||
#endif | ||
|
||
#ifdef CONFIG_IPM_MHU0 | ||
|
||
static void ipm_mhu_irq_config_func_0(struct device *d); | ||
|
||
static 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, | ||
"MHU_0", | ||
&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); | ||
} | ||
|
||
#endif /* CONFIG_IPM_MHU0 */ | ||
|
||
#ifdef CONFIG_IPM_MHU1 | ||
|
||
static void ipm_mhu_irq_config_func_1(struct device *d); | ||
|
||
static 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, | ||
"MHU_1", | ||
&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); | ||
} | ||
|
||
#endif /* CONFIG_IPM_MHU1 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* 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 <kernel.h> | ||
#include <ipm.h> | ||
#include <device.h> | ||
|
||
#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)) | ||
|
||
/* 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_ */ |
Oops, something went wrong.