struct rockchip_mbox_chan *chans;
};
+#define MBOX_CHAN_NUMS 4
+int idx_map_irq[MBOX_CHAN_NUMS] = {0, 0, 0, 0};
+
static inline int chan_to_idx(struct rockchip_mbox *mb,
struct mbox_chan *chan)
{
static irqreturn_t rockchip_mbox_irq(int irq, void *dev_id)
{
+ int idx;
struct rockchip_mbox *mb = (struct rockchip_mbox *)dev_id;
u32 status = readl_relaxed(mb->mbox_base + MAILBOX_B2A_STATUS);
- int idx;
for (idx = 0; idx < mb->mbox.num_chans; idx++) {
- struct rockchip_mbox_msg *msg = mb->chans[idx].msg;
+ if ((status & (1 << idx)) && (irq == idx_map_irq[idx])) {
+ /* Clear mbox interrupt */
+ writel_relaxed(1 << idx,
+ mb->mbox_base + MAILBOX_B2A_STATUS);
+ return IRQ_WAKE_THREAD;
+ }
+ }
+
+ return IRQ_NONE;
+}
- /* Clear mbox interrupt */
- writel_relaxed(1 << idx, mb->mbox_base + MAILBOX_B2A_STATUS);
+static irqreturn_t rockchip_mbox_isr(int irq, void *dev_id)
+{
+ int idx;
+ struct rockchip_mbox_msg *msg = NULL;
+ struct rockchip_mbox *mb = (struct rockchip_mbox *)dev_id;
- if (!(status & (1 << idx)))
+ for (idx = 0; idx < mb->mbox.num_chans; idx++) {
+ if (irq != idx_map_irq[idx])
continue;
- if (!msg)
- continue; /* spurious */
+
+ msg = mb->chans[idx].msg;
+ if (!msg) {
+ dev_err(mb->mbox.dev,
+ "Chan[%d]: B2A message is NULL\n", idx);
+ break; /* spurious */
+ }
if (msg->rx_buf)
memcpy(msg->rx_buf,
dev_dbg(mb->mbox.dev, "Chan[%d]: B2A message, cmd 0x%08x\n",
idx, msg->cmd);
+
+ break;
}
return IRQ_HANDLED;
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
- rockchip_mbox_irq, IRQF_ONESHOT,
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ rockchip_mbox_irq,
+ rockchip_mbox_isr, IRQF_ONESHOT,
dev_name(&pdev->dev), mb);
if (ret < 0)
return ret;
mb->chans[i].idx = i;
mb->chans[i].mb = mb;
mb->chans[i].msg = NULL;
+ idx_map_irq[i] = irq;
}
/* Enable all B2A interrupts */
#define DVFS_LATENCY(hdr) ((hdr) >> 16)
#define DVFS_OPP_COUNT(hdr) (((hdr) >> 8) & 0xff)
+int max_chan_num = 0;
+static DECLARE_BITMAP(bm_mbox_chans, 4);
+static DEFINE_MUTEX(scpi_mtx);
+
struct scpi_data_buf {
int client_id;
struct rockchip_mbox_msg *data;
return -EIO;
}
-static bool high_priority_chan_supported(int cmd)
+static bool __maybe_unused high_priority_chan_supported(int cmd)
{
int idx;
return false;
}
+static int scpi_alloc_mbox_chan(void)
+{
+ int index;
+
+ mutex_lock(&scpi_mtx);
+
+ index = find_first_zero_bit(bm_mbox_chans, max_chan_num);
+ if (index >= max_chan_num) {
+ pr_err("alloc mailbox channel failed\n");
+ mutex_unlock(&scpi_mtx);
+ return -EBUSY;
+ }
+
+ set_bit(index, bm_mbox_chans);
+
+ mutex_unlock(&scpi_mtx);
+ return index;
+}
+
+static void scpi_free_mbox_chan(int chan)
+{
+ int index = chan;
+
+ mutex_lock(&scpi_mtx);
+
+ if (index < max_chan_num && index >= 0)
+ clear_bit(index, bm_mbox_chans);
+
+ mutex_unlock(&scpi_mtx);
+}
+
static void scpi_rx_callback(struct mbox_client *cl, void *msg)
{
struct rockchip_mbox_msg *data = (struct rockchip_mbox_msg *)msg;
complete(&scpi_buf->complete);
}
-static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority)
+static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, int index)
{
struct mbox_chan *chan;
struct mbox_client cl;
cl.tx_block = false;
cl.knows_txdone = false;
- chan = mbox_request_channel(&cl, high_priority);
- if (IS_ERR(chan))
+ chan = mbox_request_channel(&cl, index);
+ if (IS_ERR(chan)) {
+ scpi_free_mbox_chan(index);
return PTR_ERR(chan);
+ }
init_completion(&scpi_buf->complete);
if (mbox_send_message(chan, (void *)data) < 0) {
free_channel:
mbox_free_channel(chan);
+ scpi_free_mbox_chan(index);
return scpi_to_linux_errno(status);
}
static int scpi_execute_cmd(struct scpi_data_buf *scpi_buf)
{
struct rockchip_mbox_msg *data;
- bool high_priority;
+ int index;
if (!scpi_buf || !scpi_buf->data)
return -EINVAL;
+ index = scpi_alloc_mbox_chan();
+ if (index < 0)
+ return -EBUSY;
+
data = scpi_buf->data;
- high_priority = high_priority_chan_supported(data->cmd);
data->cmd = PACK_SCPI_CMD(data->cmd, scpi_buf->client_id,
data->tx_size);
data->cl_data = scpi_buf;
- return send_scpi_cmd(scpi_buf, high_priority);
+ return send_scpi_cmd(scpi_buf, index);
}
unsigned long scpi_clk_get_val(u16 clk_id)
int scpi_thermal_get_temperature(void)
{
+ int ret;
struct scpi_data_buf sdata;
struct rockchip_mbox_msg mdata;
struct __packed1 {
tx_buf.status = 0;
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL,
SCPI_THERMAL_GET_TSADC_DATA, tx_buf, rx_buf);
- if (scpi_execute_cmd(&sdata))
- return 0;
+
+ ret = scpi_execute_cmd(&sdata);
+ if (ret) {
+ pr_err("get temperature from MCU failed, ret=%d\n", ret);
+ return ret;
+ }
return rx_buf.tsadc_data;
}
int retry = 3;
u32 ver = 0;
int check_version = 0; /*0: not check version, 1: check version*/
+ int val = 0;
the_scpi_device = &pdev->dev;
goto exit;
}
+ /* try to get mboxes chan nums from DT */
+ if (of_property_read_u32((&pdev->dev)->of_node, "chan-nums", &val)) {
+ dev_err(&pdev->dev, "parse mboxes chan-nums failed\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ max_chan_num = val;
+
dev_info(&pdev->dev,
- "Scpi initialize, version: 0x%x\n", ver);
+ "Scpi initialize, version: 0x%x, chan nums: %d\n", ver, val);
return 0;
exit:
the_scpi_device = NULL;