mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00
feat(mhu): add MHUv3 doorbell driver
MHUv3 reworks parts of MHUv2 and introduces MHU extensions. There are currently 3 extensions: * Doorbell extension: which works like MHUv2 * FIFO extension: which uses a buffer for faster inband data transfer * Fastchannel extension: for fast data transfer Add MHUv3 driver with support for Doorbell extension for both postbox sender MHUs and mailbox receiver MHUs. Signed-off-by: Aziz IDOMAR <aziz.idomar@arm.com> Signed-off-by: Sayanta Pattanayak <sayanta.pattanayak@arm.com> Signed-off-by: Shriram K <shriram.k@arm.com> Signed-off-by: Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com> Signed-off-by: Joel Goddard <joel.goddard@arm.com> Change-Id: Icf49df56f1159f4c9830e0ffcda5b3a4bea8d2fd
This commit is contained in:
parent
10eb851f92
commit
bc174764f0
3 changed files with 923 additions and 0 deletions
475
drivers/arm/mhu/mhu_v3_x.c
Normal file
475
drivers/arm/mhu/mhu_v3_x.c
Normal file
|
@ -0,0 +1,475 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mhu_v3_x.h"
|
||||
|
||||
#include "mhu_v3_x_private.h"
|
||||
|
||||
/*
|
||||
* Get the device base from the device struct. Return an error if the dev is
|
||||
* invalid.
|
||||
*/
|
||||
static enum mhu_v3_x_error_t get_dev_base(const struct mhu_v3_x_dev_t *dev,
|
||||
union _mhu_v3_x_frame_t **base)
|
||||
{
|
||||
if (dev == NULL) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Ensure driver has been initialized */
|
||||
if (dev->is_initialized == false) {
|
||||
return MHU_V_3_X_ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
*base = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev)
|
||||
{
|
||||
uint32_t aidr = 0;
|
||||
uint8_t mhu_major_rev;
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
|
||||
if (dev == NULL) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Return if already initialized */
|
||||
if (dev->is_initialized == true) {
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
/* Read revision from MHU hardware */
|
||||
if (dev->frame == MHU_V3_X_PBX_FRAME) {
|
||||
aidr = p_mhu->pbx_frame.pbx_ctrl_page.pbx_aidr;
|
||||
} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
|
||||
aidr = p_mhu->mbx_frame.mbx_ctrl_page.mbx_aidr;
|
||||
} else {
|
||||
/* Only PBX and MBX frames are supported. */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Read the MHU Architecture Major Revision */
|
||||
mhu_major_rev =
|
||||
((aidr & MHU_ARCH_MAJOR_REV_MASK) >> MHU_ARCH_MAJOR_REV_OFF);
|
||||
|
||||
/* Return error if the MHU major revision is not 3 */
|
||||
if (mhu_major_rev != MHU_MAJOR_REV_V3) {
|
||||
/* Unsupported MHU version */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
/* Read the MHU Architecture Minor Revision */
|
||||
dev->subversion =
|
||||
((aidr & MHU_ARCH_MINOR_REV_MASK) >> MHU_ARCH_MINOR_REV_MASK);
|
||||
|
||||
/* Return error if the MHU minor revision is not 0 */
|
||||
if (dev->subversion != MHU_MINOR_REV_3_0) {
|
||||
/* Unsupported subversion */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
/* Initialize the Postbox/Mailbox to remain in operational state */
|
||||
if (dev->frame == MHU_V3_X_PBX_FRAME) {
|
||||
p_mhu->pbx_frame.pbx_ctrl_page.pbx_ctrl |= MHU_V3_OP_REQ;
|
||||
} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
|
||||
p_mhu->mbx_frame.mbx_ctrl_page.mbx_ctrl |= MHU_V3_OP_REQ;
|
||||
} else {
|
||||
/* Only PBX and MBX frames are supported. */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
dev->is_initialized = true;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
|
||||
const struct mhu_v3_x_dev_t *dev,
|
||||
enum mhu_v3_x_channel_type_t ch_type, uint8_t *num_ch)
|
||||
{
|
||||
enum mhu_v3_x_error_t status;
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
|
||||
if (num_ch == NULL) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only doorbell channel is supported */
|
||||
if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Read the number of channels implemented in the MHU */
|
||||
if (dev->frame == MHU_V3_X_PBX_FRAME) {
|
||||
*num_ch = (p_mhu->pbx_frame.pbx_ctrl_page.pbx_dbch_cfg0 + 1);
|
||||
} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
|
||||
*num_ch = (p_mhu->mbx_frame.mbx_ctrl_page.mbx_dbch_cfg0 + 1);
|
||||
} else {
|
||||
/* Only PBX and MBX frames are supported. */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(const struct mhu_v3_x_dev_t *dev,
|
||||
const uint32_t channel, uint32_t flags)
|
||||
{
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only MBX can clear the Doorbell channel */
|
||||
if (dev->frame != MHU_V3_X_MBX_FRAME) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/* Clear the bits in the doorbell channel */
|
||||
mdbcw_reg[channel].mdbcw_clr |= flags;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(const struct mhu_v3_x_dev_t *dev,
|
||||
const uint32_t channel, uint32_t flags)
|
||||
{
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only PBX can set the Doorbell channel value */
|
||||
if (dev->frame != MHU_V3_X_PBX_FRAME) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
|
||||
&(p_mhu->pbx_frame.pdbcw_page);
|
||||
|
||||
/* Write the value to the doorbell channel */
|
||||
pdbcw_reg[channel].pdbcw_set |= flags;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(const struct mhu_v3_x_dev_t *dev,
|
||||
const uint32_t channel, uint32_t *flags)
|
||||
{
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
enum mhu_v3_x_error_t status;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
|
||||
|
||||
if (flags == NULL) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
if (dev->frame == MHU_V3_X_PBX_FRAME) {
|
||||
pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
|
||||
&(p_mhu->pbx_frame.pdbcw_page);
|
||||
|
||||
/* Read the value from Postbox Doorbell status register */
|
||||
*flags = pdbcw_reg[channel].pdbcw_st;
|
||||
} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/* Read the value from Mailbox Doorbell status register */
|
||||
*flags = mdbcw_reg[channel].mdbcw_st;
|
||||
} else {
|
||||
/* Only PBX and MBX frames are supported. */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
uint32_t flags)
|
||||
{
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Doorbell channel mask is not applicable for PBX */
|
||||
if (dev->frame != MHU_V3_X_MBX_FRAME) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/* Set the Doorbell channel mask */
|
||||
mdbcw_reg[channel].mdbcw_msk_set |= flags;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
uint32_t flags)
|
||||
{
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Doorbell channel mask is not applicable for PBX */
|
||||
if (dev->frame != MHU_V3_X_MBX_FRAME) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/* Clear the Doorbell channel mask */
|
||||
mdbcw_reg[channel].mdbcw_msk_clr = flags;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
uint32_t *flags)
|
||||
{
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
if (flags == NULL) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Doorbell channel mask is not applicable for PBX */
|
||||
if (dev->frame != MHU_V3_X_MBX_FRAME) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/* Save the Doorbell channel mask status */
|
||||
*flags = mdbcw_reg[channel].mdbcw_msk_st;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
enum mhu_v3_x_channel_type_t ch_type)
|
||||
{
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only doorbell channel is supported */
|
||||
if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
if (dev->frame == MHU_V3_X_PBX_FRAME) {
|
||||
pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
|
||||
&(p_mhu->pbx_frame.pdbcw_page);
|
||||
|
||||
/*
|
||||
* Enable this doorbell channel to generate interrupts for
|
||||
* transfer acknowledge events.
|
||||
*/
|
||||
pdbcw_reg[channel].pdbcw_int_en = MHU_V3_X_PDBCW_INT_X_TFR_ACK;
|
||||
|
||||
/*
|
||||
* Enable this doorbell channel to contribute to the PBX
|
||||
* combined interrupt.
|
||||
*/
|
||||
pdbcw_reg[channel].pdbcw_ctrl = MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN;
|
||||
} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/*
|
||||
* Enable this doorbell channel to contribute to the MBX
|
||||
* combined interrupt.
|
||||
*/
|
||||
mdbcw_reg[channel].mdbcw_ctrl = MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN;
|
||||
} else {
|
||||
/* Only PBX and MBX frames are supported. */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
enum mhu_v3_x_channel_type_t ch_type)
|
||||
{
|
||||
enum mhu_v3_x_error_t status;
|
||||
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
|
||||
struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only doorbell channel is supported */
|
||||
if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
|
||||
if (dev->frame == MHU_V3_X_PBX_FRAME) {
|
||||
pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
|
||||
&(p_mhu->pbx_frame.pdbcw_page);
|
||||
|
||||
/* Clear channel transfer acknowledge event interrupt */
|
||||
pdbcw_reg[channel].pdbcw_int_clr = MHU_V3_X_PDBCW_INT_X_TFR_ACK;
|
||||
|
||||
/* Disable channel transfer acknowledge event interrupt */
|
||||
pdbcw_reg[channel].pdbcw_int_en &=
|
||||
~(MHU_V3_X_PDBCW_INT_X_TFR_ACK);
|
||||
|
||||
/*
|
||||
* Disable this doorbell channel from contributing to the PBX
|
||||
* combined interrupt.
|
||||
*/
|
||||
pdbcw_reg[channel].pdbcw_ctrl &=
|
||||
~(MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN);
|
||||
} else if (dev->frame == MHU_V3_X_MBX_FRAME) {
|
||||
mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
|
||||
&(p_mhu->mbx_frame.mdbcw_page);
|
||||
|
||||
/*
|
||||
* Disable this doorbell channel from contributing to the MBX
|
||||
* combined interrupt.
|
||||
*/
|
||||
mdbcw_reg[channel].mdbcw_ctrl &=
|
||||
~(MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN);
|
||||
} else {
|
||||
/* Only PBX and MBX frames are supported. */
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
||||
|
||||
enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
enum mhu_v3_x_channel_type_t ch_type)
|
||||
{
|
||||
enum mhu_v3_x_error_t status;
|
||||
union _mhu_v3_x_frame_t *p_mhu;
|
||||
struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
|
||||
|
||||
/* Get dev->base if it is valid or return an error if dev is not */
|
||||
status = get_dev_base(dev, &p_mhu);
|
||||
if (status != MHU_V_3_X_ERR_NONE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only doorbell channel is supported */
|
||||
if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
|
||||
return MHU_V_3_X_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only postbox doorbell channel transfer acknowledge interrupt can be
|
||||
* cleared manually.
|
||||
*
|
||||
* To clear MBX interrupt the unmasked status must be cleared using
|
||||
* mhu_v3_x_doorbell_clear.
|
||||
*/
|
||||
if (dev->frame != MHU_V3_X_PBX_FRAME) {
|
||||
return MHU_V_3_X_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
|
||||
pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)&(
|
||||
p_mhu->pbx_frame.pdbcw_page);
|
||||
|
||||
/* Clear channel transfer acknowledge event interrupt */
|
||||
pdbcw_reg[channel].pdbcw_int_clr |= 0x1;
|
||||
|
||||
return MHU_V_3_X_ERR_NONE;
|
||||
}
|
226
drivers/arm/mhu/mhu_v3_x.h
Normal file
226
drivers/arm/mhu/mhu_v3_x.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MHU_V3_X_H
|
||||
#define MHU_V3_X_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* MHU Architecture Major Revision 3 */
|
||||
#define MHU_MAJOR_REV_V3 U(0x2)
|
||||
/* MHU Architecture Minor Revision 0 */
|
||||
#define MHU_MINOR_REV_3_0 U(0x0)
|
||||
|
||||
/* MHU Architecture Major Revision offset */
|
||||
#define MHU_ARCH_MAJOR_REV_OFF U(0x4)
|
||||
/* MHU Architecture Major Revision mask */
|
||||
#define MHU_ARCH_MAJOR_REV_MASK (U(0xf) << MHU_ARCH_MAJOR_REV_OFF)
|
||||
|
||||
/* MHU Architecture Minor Revision offset */
|
||||
#define MHU_ARCH_MINOR_REV_OFF U(0x0)
|
||||
/* MHU Architecture Minor Revision mask */
|
||||
#define MHU_ARCH_MINOR_REV_MASK (U(0xf) << MHU_ARCH_MINOR_REV_OFF)
|
||||
|
||||
/* MHUv3 PBX/MBX Operational Request offset */
|
||||
#define MHU_V3_OP_REQ_OFF U(0)
|
||||
/* MHUv3 PBX/MBX Operational Request */
|
||||
#define MHU_V3_OP_REQ (U(1) << MHU_V3_OP_REQ_OFF)
|
||||
|
||||
/**
|
||||
* MHUv3 error enumeration types
|
||||
*/
|
||||
enum mhu_v3_x_error_t {
|
||||
/* No error */
|
||||
MHU_V_3_X_ERR_NONE,
|
||||
/* MHU driver not initialized */
|
||||
MHU_V_3_X_ERR_NOT_INIT,
|
||||
/* MHU driver alreary initialized */
|
||||
MHU_V_3_X_ERR_ALREADY_INIT,
|
||||
/* MHU Revision not supported error */
|
||||
MHU_V_3_X_ERR_UNSUPPORTED_VERSION,
|
||||
/* Operation not supported */
|
||||
MHU_V_3_X_ERR_UNSUPPORTED,
|
||||
/* Invalid parameter */
|
||||
MHU_V_3_X_ERR_INVALID_PARAM,
|
||||
/* General MHU driver error */
|
||||
MHU_V_3_X_ERR_GENERAL,
|
||||
};
|
||||
|
||||
/**
|
||||
* MHUv3 channel types
|
||||
*/
|
||||
enum mhu_v3_x_channel_type_t {
|
||||
/* Doorbell channel */
|
||||
MHU_V3_X_CHANNEL_TYPE_DBCH,
|
||||
/* Channel type count */
|
||||
MHU_V3_X_CHANNEL_TYPE_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* MHUv3 frame types
|
||||
*/
|
||||
enum mhu_v3_x_frame_t {
|
||||
/* MHUv3 postbox frame */
|
||||
MHU_V3_X_PBX_FRAME,
|
||||
/* MHUv3 mailbox frame */
|
||||
MHU_V3_X_MBX_FRAME,
|
||||
};
|
||||
|
||||
/**
|
||||
* MHUv3 device structure
|
||||
*/
|
||||
struct mhu_v3_x_dev_t {
|
||||
/* Base address of the MHUv3 frame */
|
||||
uintptr_t base;
|
||||
/* Type of the MHUv3 frame */
|
||||
enum mhu_v3_x_frame_t frame;
|
||||
/* Minor revision of the MHUv3 */
|
||||
uint32_t subversion;
|
||||
/* Flag to indicate if the MHUv3 is initialized */
|
||||
bool is_initialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the MHUv3
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev);
|
||||
|
||||
/**
|
||||
* Returns the number of channels implemented
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* ch_type MHU channel type mhu_v3_x_channel_type_t
|
||||
* num_ch Pointer to the variable that will store the value
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
|
||||
const struct mhu_v3_x_dev_t *dev, enum mhu_v3_x_channel_type_t ch_type,
|
||||
uint8_t *num_ch);
|
||||
|
||||
/**
|
||||
* Clear flags from a doorbell channel
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* flags Flags to be cleared from the channel
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(const struct mhu_v3_x_dev_t *dev,
|
||||
const uint32_t channel, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Write flags to a doorbell channel
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* flags Flags to be written to the channel
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(const struct mhu_v3_x_dev_t *dev,
|
||||
const uint32_t channel, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Read value from a doorbell channel
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* flags Pointer to the variable that will store the flags read from the
|
||||
* channel
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(const struct mhu_v3_x_dev_t *dev,
|
||||
const uint32_t channel, uint32_t *flags);
|
||||
|
||||
/**
|
||||
* Set bits in a doorbell channel mask which is used to disable interrupts for
|
||||
* received flags corresponding to the mask
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* flags Flags to set mask bits in this doorbell channel
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Clear bits in a doorbell channel mask which is used to disable interrupts
|
||||
* for received flags corresponding to the mask
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* flags Flags to clear mask bits in this doorbell channel
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Get the mask of a doorbell channel which is used to disable interrupts for
|
||||
* received flags corresponding to the mask
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* flags Pointer to the variable that will store the flags read from the
|
||||
* mask value
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel, uint32_t *flags);
|
||||
|
||||
/**
|
||||
* Enable the channel interrupt
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* ch_type MHU channel type mhu_v3_x_channel_type_t
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
enum mhu_v3_x_channel_type_t ch_type);
|
||||
|
||||
/**
|
||||
* Disable the channel interrupt
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* ch_type MHU channel type mhu_v3_x_channel_type_t
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
enum mhu_v3_x_channel_type_t ch_type);
|
||||
|
||||
/**
|
||||
* Clear the channel interrupt
|
||||
*
|
||||
* dev MHU device struct mhu_v3_x_dev_t
|
||||
* channel Doorbell channel number
|
||||
* ch_type MHU channel type mhu_v3_x_channel_type_t
|
||||
*
|
||||
* Returns mhu_v3_x_error_t error code
|
||||
*/
|
||||
enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
|
||||
const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
|
||||
enum mhu_v3_x_channel_type_t ch_type);
|
||||
|
||||
#endif /* MHU_V3_X_H */
|
222
drivers/arm/mhu/mhu_v3_x_private.h
Normal file
222
drivers/arm/mhu/mhu_v3_x_private.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef MHU_V3_X_PRIVATE_H
|
||||
#define MHU_V3_X_PRIVATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Flag for PDBCW Interrupt Transfer Acknowledgment */
|
||||
#define MHU_V3_X_PDBCW_INT_X_TFR_ACK 0x1
|
||||
|
||||
/* Flag for PDBCW CTRL Postbox combined interrupts enable */
|
||||
#define MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN 0x1
|
||||
|
||||
/* Flag for MDBCW CTRL Mailbox combined interrupts enable */
|
||||
#define MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN 0x1
|
||||
|
||||
/**
|
||||
* Postbox control page structure
|
||||
*/
|
||||
struct _mhu_v3_x_pbx_ctrl_reg_t {
|
||||
/* Offset: 0x000 (R/ ) Postbox Block Identifier */
|
||||
const volatile uint32_t pbx_blk_id;
|
||||
/* Offset: 0x004 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_0[0x10 - 0x04];
|
||||
/* Offset: 0x010 (R/ ) Postbox Feature Support 0 */
|
||||
const volatile uint32_t pbx_feat_spt0;
|
||||
/* Offset: 0x014 (R/ ) Postbox Feature Support 1 */
|
||||
const volatile uint32_t pbx_feat_spt1;
|
||||
/* Offset: 0x018 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_1[0x20 - 0x18];
|
||||
/* Offset: 0x020 (R/ ) Postbox Doorbell Channel Configuration 0 */
|
||||
const volatile uint32_t pbx_dbch_cfg0;
|
||||
/* Offset: 0x024 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_2[0x30 - 0x24];
|
||||
/* Offset: 0x030 (R/ ) Postbox FIFO Channel Configuration 0 */
|
||||
const volatile uint32_t pbx_ffch_cfg0;
|
||||
/* Offset: 0x034 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_3[0x40 - 0x34];
|
||||
/* Offset: 0x040 (R/ ) Postbox Fast Channel Configuration 0 */
|
||||
const volatile uint32_t pbx_fch_cfg0;
|
||||
/* Offset: 0x044 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_4[0x100 - 0x44];
|
||||
/* Offset: 0x100 (R/W) Postbox control */
|
||||
volatile uint32_t pbx_ctrl;
|
||||
/* Offset: 0x164 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_5[0x400 - 0x104];
|
||||
/*
|
||||
* Offset: 0x400 (R/ ) Postbox Doorbell Channel Interrupt Status n,
|
||||
* where n is 0 - 3.
|
||||
*/
|
||||
const volatile uint32_t pbx_dbch_int_st[4];
|
||||
/*
|
||||
* Offset: 0x410 (R/ ) Postbox FIFO Channel <n> Interrupt Status n,
|
||||
* where n is 0 - 1.
|
||||
*/
|
||||
const volatile uint32_t pbx_ffch_int_st[2];
|
||||
/* Offset: 0x418 (R/ ) Reserved */
|
||||
const uint8_t reserved_6[0xFC8 - 0x418];
|
||||
/* Offset: 0xFC8 (R/ ) Postbox Implementer Identification Register */
|
||||
const volatile uint32_t pbx_iidr;
|
||||
/* Offset: 0xFCC (R/ ) Postbox Architecture Identification Register */
|
||||
const volatile uint32_t pbx_aidr;
|
||||
/*
|
||||
* Offset: 0xFD0 (R/ ) Postbox Implementation Defined Identification
|
||||
* Register n, where n is 0 - 11.
|
||||
*/
|
||||
const volatile uint32_t impl_def_id[12];
|
||||
};
|
||||
|
||||
/**
|
||||
* Postbox doorbell channel window page structure
|
||||
*/
|
||||
struct _mhu_v3_x_pdbcw_reg_t {
|
||||
/* Offset: 0x000 (R/ ) Postbox Doorbell Channel Window Status */
|
||||
const volatile uint32_t pdbcw_st;
|
||||
/* Offset: 0x004 (R/ ) Reserved */
|
||||
const uint8_t reserved_0[0xC - 0x4];
|
||||
/* Offset: 0x00C ( /W) Postbox Doorbell Channel Window Set */
|
||||
volatile uint32_t pdbcw_set;
|
||||
/*
|
||||
* Offset: 0x010 (R/ ) Postbox Doorbell Channel Window Interrupt Status
|
||||
*/
|
||||
const volatile uint32_t pdbcw_int_st;
|
||||
/*
|
||||
* Offset: 0x014 ( /W) Postbox Doorbell Channel Window Interrupt Clear
|
||||
*/
|
||||
volatile uint32_t pdbcw_int_clr;
|
||||
/*
|
||||
* Offset: 0x018 (R/W) Postbox Doorbell Channel Window Interrupt Enable
|
||||
*/
|
||||
volatile uint32_t pdbcw_int_en;
|
||||
/* Offset: 0x01C (R/W) Postbox Doorbell Channel Window Control */
|
||||
volatile uint32_t pdbcw_ctrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Postbox structure
|
||||
*/
|
||||
struct _mhu_v3_x_pbx {
|
||||
/* Postbox Control */
|
||||
struct _mhu_v3_x_pbx_ctrl_reg_t pbx_ctrl_page;
|
||||
/* Postbox Doorbell Channel Window */
|
||||
struct _mhu_v3_x_pdbcw_reg_t pdbcw_page;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mailbox control page structure
|
||||
*/
|
||||
struct _mhu_v3_x_mbx_ctrl_reg_t {
|
||||
/* Offset: 0x000 (R/ ) Mailbox Block Identifier */
|
||||
const volatile uint32_t mbx_blk_id;
|
||||
/* Offset: 0x004 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_0[0x10 - 0x04];
|
||||
/* Offset: 0x010 (R/ ) Mailbox Feature Support 0 */
|
||||
const volatile uint32_t mbx_feat_spt0;
|
||||
/* Offset: 0x014 (R/ ) Mailbox Feature Support 1 */
|
||||
const volatile uint32_t mbx_feat_spt1;
|
||||
/* Offset: 0x018 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_1[0x20 - 0x18];
|
||||
/* Offset: 0x020 (R/ ) Mailbox Doorbell Channel Configuration 0 */
|
||||
const volatile uint32_t mbx_dbch_cfg0;
|
||||
/* Offset: 0x024 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_2[0x30 - 0x24];
|
||||
/* Offset: 0x030 (R/ ) Mailbox FIFO Channel Configuration 0 */
|
||||
const volatile uint32_t mbx_ffch_cfg0;
|
||||
/* Offset: 0x034 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_4[0x40 - 0x34];
|
||||
/* Offset: 0x040 (R/ ) Mailbox Fast Channel Configuration 0 */
|
||||
const volatile uint32_t mbx_fch_cfg0;
|
||||
/* Offset: 0x044 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_5[0x100 - 0x44];
|
||||
/* Offset: 0x100 (R/W) Mailbox control */
|
||||
volatile uint32_t mbx_ctrl;
|
||||
/* Offset: 0x104 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_6[0x140 - 0x104];
|
||||
/* Offset: 0x140 (R/W) Mailbox Fast Channel control */
|
||||
volatile uint32_t mbx_fch_ctrl;
|
||||
/* Offset: 0x144 (R/W) Mailbox Fast Channel Group Interrupt Enable */
|
||||
volatile uint32_t mbx_fcg_int_en;
|
||||
/* Offset: 0x148 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_7[0x400 - 0x148];
|
||||
/*
|
||||
* Offset: 0x400 (R/ ) Mailbox Doorbell Channel Interrupt Status n,
|
||||
* where n = 0 - 3.
|
||||
*/
|
||||
const volatile uint32_t mbx_dbch_int_st[4];
|
||||
/*
|
||||
* Offset: 0x410 (R/ ) Mailbox FIFO Channel Interrupt Status n, where
|
||||
* n = 0 - 1.
|
||||
*/
|
||||
const volatile uint32_t mbx_ffch_int_st[2];
|
||||
/* Offset: 0x418 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_8[0x470 - 0x418];
|
||||
/* Offset: 0x470 (R/ ) Mailbox Fast Channel Group Interrupt Status */
|
||||
const volatile uint32_t mbx_fcg_int_st;
|
||||
/* Offset: 0x474 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_9[0x480 - 0x474];
|
||||
/*
|
||||
* Offset: 0x480 (R/ ) Mailbox Fast Channel Group <n> Interrupt Status,
|
||||
* where n = 0 - 31.
|
||||
*/
|
||||
const volatile uint32_t mbx_fch_grp_int_st[32];
|
||||
/* Offset: 0x500 (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_10[0xFC8 - 0x500];
|
||||
/* Offset: 0xFC8 (R/ ) Mailbox Implementer Identification Register */
|
||||
const volatile uint32_t mbx_iidr;
|
||||
/* Offset: 0xFCC (R/ ) Mailbox Architecture Identification Register */
|
||||
const volatile uint32_t mbx_aidr;
|
||||
/*
|
||||
* Offset: 0xFD0 (R/ ) Mailbox Implementation Defined Identification
|
||||
* Register n, where n is 0 - 11.
|
||||
*/
|
||||
const volatile uint32_t impl_def_id[12];
|
||||
};
|
||||
|
||||
/**
|
||||
* Mailbox doorbell channel window page structure
|
||||
*/
|
||||
struct _mhu_v3_x_mdbcw_reg_t {
|
||||
/* Offset: 0x000 (R/ ) Mailbox Doorbell Channel Window Status */
|
||||
const volatile uint32_t mdbcw_st;
|
||||
/* Offset: 0x004 (R/ ) Mailbox Doorbell Channel Window Status Masked */
|
||||
const volatile uint32_t mdbcw_st_msk;
|
||||
/* Offset: 0x008 ( /W) Mailbox Doorbell Channel Window Clear */
|
||||
volatile uint32_t mdbcw_clr;
|
||||
/* Offset: 0x00C (R/ ) Reserved */
|
||||
const volatile uint8_t reserved_0[0x10 - 0x0C];
|
||||
/* Offset: 0x010 (R/ ) Mailbox Doorbell Channel Window Mask Status */
|
||||
const volatile uint32_t mdbcw_msk_st;
|
||||
/* Offset: 0x014 ( /W) Mailbox Doorbell Channel Window Mask Set */
|
||||
volatile uint32_t mdbcw_msk_set;
|
||||
/* Offset: 0x018 ( /W) Mailbox Doorbell Channel Window Mask Clear */
|
||||
volatile uint32_t mdbcw_msk_clr;
|
||||
/* Offset: 0x01C (R/W) Mailbox Doorbell Channel Window Control */
|
||||
volatile uint32_t mdbcw_ctrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mailbox structure
|
||||
*/
|
||||
struct _mhu_v3_x_mbx {
|
||||
/* Mailbox control */
|
||||
struct _mhu_v3_x_mbx_ctrl_reg_t mbx_ctrl_page;
|
||||
/* Mailbox Doorbell Channel Window */
|
||||
struct _mhu_v3_x_mdbcw_reg_t mdbcw_page;
|
||||
};
|
||||
|
||||
/**
|
||||
* MHUv3 frame type
|
||||
*/
|
||||
union _mhu_v3_x_frame_t {
|
||||
/* Postbox Frame */
|
||||
struct _mhu_v3_x_pbx pbx_frame;
|
||||
/* Mailbox Frame */
|
||||
struct _mhu_v3_x_mbx mbx_frame;
|
||||
};
|
||||
|
||||
#endif /* MHU_V3_X_PRIVATE_H */
|
Loading…
Add table
Reference in a new issue