Skip to content

Commit

Permalink
bus: mhi: core: Add support for ringing channel/event ring doorbells
Browse files Browse the repository at this point in the history
This commit adds support for ringing channel and event ring doorbells
by MHI host. The MHI host can use the channel and event ring doorbells
for notifying the client device about processing transfer and event
rings which it has queued using MMIO registers.

This is based on the patch submitted by Sujeev Dias:
https://lkml.org/lkml/2018/7/9/989

Signed-off-by: Sujeev Dias <sdias@codeaurora.org>
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
[mani: splitted from pm patch and cleaned up for upstream]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Jeffrey Hugo <jhugo@codeaurora.org>
Tested-by: Jeffrey Hugo <jhugo@codeaurora.org>
Link: https://lore.kernel.org/r/20200220095854.4804-6-manivannan.sadhasivam@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Manivannan Sadhasivam authored and Greg Kroah-Hartman committed Mar 19, 2020
1 parent da1c4f8 commit 6cd330a
Show file tree
Hide file tree
Showing 4 changed files with 545 additions and 0 deletions.
141 changes: 141 additions & 0 deletions drivers/bus/mhi/core/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,137 @@
#include <linux/wait.h>
#include "internal.h"

int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
{
u32 val;
int i, ret;
struct mhi_chan *mhi_chan;
struct mhi_event *mhi_event;
void __iomem *base = mhi_cntrl->regs;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
struct {
u32 offset;
u32 mask;
u32 shift;
u32 val;
} reg_info[] = {
{
CCABAP_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->mhi_ctxt->chan_ctxt_addr),
},
{
CCABAP_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->mhi_ctxt->chan_ctxt_addr),
},
{
ECABAP_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->mhi_ctxt->er_ctxt_addr),
},
{
ECABAP_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->mhi_ctxt->er_ctxt_addr),
},
{
CRCBAP_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->mhi_ctxt->cmd_ctxt_addr),
},
{
CRCBAP_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->mhi_ctxt->cmd_ctxt_addr),
},
{
MHICFG, MHICFG_NER_MASK, MHICFG_NER_SHIFT,
mhi_cntrl->total_ev_rings,
},
{
MHICFG, MHICFG_NHWER_MASK, MHICFG_NHWER_SHIFT,
mhi_cntrl->hw_ev_rings,
},
{
MHICTRLBASE_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->iova_start),
},
{
MHICTRLBASE_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->iova_start),
},
{
MHIDATABASE_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->iova_start),
},
{
MHIDATABASE_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->iova_start),
},
{
MHICTRLLIMIT_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->iova_stop),
},
{
MHICTRLLIMIT_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->iova_stop),
},
{
MHIDATALIMIT_HIGHER, U32_MAX, 0,
upper_32_bits(mhi_cntrl->iova_stop),
},
{
MHIDATALIMIT_LOWER, U32_MAX, 0,
lower_32_bits(mhi_cntrl->iova_stop),
},
{ 0, 0, 0 }
};

dev_dbg(dev, "Initializing MHI registers\n");

/* Read channel db offset */
ret = mhi_read_reg_field(mhi_cntrl, base, CHDBOFF, CHDBOFF_CHDBOFF_MASK,
CHDBOFF_CHDBOFF_SHIFT, &val);
if (ret) {
dev_err(dev, "Unable to read CHDBOFF register\n");
return -EIO;
}

/* Setup wake db */
mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB);
mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 4, 0);
mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0);
mhi_cntrl->wake_set = false;

/* Setup channel db address for each channel in tre_ring */
mhi_chan = mhi_cntrl->mhi_chan;
for (i = 0; i < mhi_cntrl->max_chan; i++, val += 8, mhi_chan++)
mhi_chan->tre_ring.db_addr = base + val;

/* Read event ring db offset */
ret = mhi_read_reg_field(mhi_cntrl, base, ERDBOFF, ERDBOFF_ERDBOFF_MASK,
ERDBOFF_ERDBOFF_SHIFT, &val);
if (ret) {
dev_err(dev, "Unable to read ERDBOFF register\n");
return -EIO;
}

/* Setup event db address for each ev_ring */
mhi_event = mhi_cntrl->mhi_event;
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, val += 8, mhi_event++) {
if (mhi_event->offload_ev)
continue;

mhi_event->ring.db_addr = base + val;
}

/* Setup DB register for primary CMD rings */
mhi_cntrl->mhi_cmd[PRIMARY_CMD_RING].ring.db_addr = base + CRDB_LOWER;

/* Write to MMIO registers */
for (i = 0; reg_info[i].offset; i++)
mhi_write_reg_field(mhi_cntrl, base, reg_info[i].offset,
reg_info[i].mask, reg_info[i].shift,
reg_info[i].val);

return 0;
}

static int parse_ev_cfg(struct mhi_controller *mhi_cntrl,
struct mhi_controller_config *config)
{
Expand Down Expand Up @@ -62,6 +193,11 @@ static int parse_ev_cfg(struct mhi_controller *mhi_cntrl,
if (MHI_INVALID_BRSTMODE(mhi_event->db_cfg.brstmode))
goto error_ev_cfg;

if (mhi_event->db_cfg.brstmode == MHI_DB_BRST_ENABLE)
mhi_event->db_cfg.process_db = mhi_db_brstmode;
else
mhi_event->db_cfg.process_db = mhi_db_brstmode_disable;

mhi_event->data_type = event_cfg->data_type;

mhi_event->hw_ring = event_cfg->hardware_event;
Expand Down Expand Up @@ -185,6 +321,11 @@ static int parse_ch_cfg(struct mhi_controller *mhi_cntrl,
}
}

if (mhi_chan->db_cfg.brstmode == MHI_DB_BRST_ENABLE)
mhi_chan->db_cfg.process_db = mhi_db_brstmode;
else
mhi_chan->db_cfg.process_db = mhi_db_brstmode_disable;

mhi_chan->configured = true;

if (mhi_chan->lpm_notify)
Expand Down
Loading

0 comments on commit 6cd330a

Please sign in to comment.