Browse Source
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: Icf49df56f1159f4c9830e0ffcda5b3a4bea8d2fdpull/2000/merge
Aziz IDOMAR
11 months ago
committed by
Joel Goddard
3 changed files with 923 additions and 0 deletions
@ -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; |
|||
} |
@ -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 */ |
@ -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…
Reference in new issue