123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /*
- * Copyright (c) 2019 MediaTek Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/of.h>
- #include <linux/slab.h>
- #include <linux/errno.h>
- #include <linux/mailbox_controller.h>
- #include <linux/mailbox_client.h>
- #include <linux/mailbox/mtk-rpmsg-mailbox.h>
- #include "../misc/mediatek/include/mt-plat/mtk-mbox.h"
- static struct mtk_mbox_chan *to_mtk_mbox_chan(struct mbox_chan *chan)
- {
- if (!chan || !chan->con_priv)
- return NULL;
- return (struct mtk_mbox_chan *)chan->con_priv;
- }
- int mtk_mbox_send_ipi(struct mtk_mbox_chan *mchan, void *data)
- {
- struct mtk_mbox_device *mbdev;
- struct mtk_ipi_msg *msg;
- unsigned int status;
- int ret;
- if (WARN_ON(!data)) {
- pr_notice("mbox fw:%u warning\n", mchan->mbox);
- return -EINVAL;
- }
- mbdev = mchan->mbdev;
- msg = (struct mtk_ipi_msg *)data;
- status = mtk_mbox_check_send_irq(mbdev, mchan->mbox,
- mchan->send_pin_index);
- if (status != 0) {
- mchan->ipimsg = data;
- return -EBUSY;
- }
- ret = mtk_mbox_write_hd(mbdev, mchan->mbox, mchan->send_slot, msg);
- if (ret != MBOX_DONE)
- return -EIO;
- /*
- * Ensure that all writes to SRAM are committed before sending the
- * interrupt to mbox.
- */
- mb();
- ret = mtk_mbox_trigger_irq(mbdev, mchan->mbox,
- 0x1 << mchan->send_pin_index);
- if (ret != MBOX_DONE)
- pr_notice("mbox fw:%u irq fail\n", mchan->mbox);
- return ret;
- }
- bool mtk_mbox_tx_done(struct mtk_mbox_chan *mchan)
- {
- struct mtk_mbox_device *mbdev;
- struct mbox_chan *chan;
- unsigned int status;
- unsigned long flags;
- chan = mchan->chan;
- mbdev = mchan->mbdev;
- spin_lock_irqsave(&chan->lock, flags);
- status = mtk_mbox_check_send_irq(mbdev, mchan->mbox,
- mchan->send_pin_index);
- spin_unlock_irqrestore(&chan->lock, flags);
- return status ? false : true;
- }
- int mtk_mbox_start(struct mtk_mbox_chan *mchan)
- {
- return 0;
- }
- void mtk_mbox_down(struct mtk_mbox_chan *mchan)
- {
- }
- int mtk_mbox_send_data(struct mbox_chan *chan, void *data)
- {
- struct mtk_mbox_chan *mchan = to_mtk_mbox_chan(chan);
- if (mchan)
- return mchan->ops->mtk_send_ipi(mchan, data);
- return false;
- }
- bool mtk_mbox_last_tx_done(struct mbox_chan *chan)
- {
- struct mtk_mbox_chan *mchan = to_mtk_mbox_chan(chan);
- if (mchan)
- return mchan->ops->mtk_tx_done(mchan);
- return false;
- }
- int mtk_mbox_startup(struct mbox_chan *chan)
- {
- struct mtk_mbox_chan *mchan = to_mtk_mbox_chan(chan);
- if (mchan)
- return mchan->ops->mtk_startup(mchan);
- return 0;
- }
- void mtk_mbox_shutdown(struct mbox_chan *chan)
- {
- struct mtk_mbox_chan *mchan = to_mtk_mbox_chan(chan);
- if (mchan)
- mchan->ops->mtk_shutdown(mchan);
- }
- static const struct mbox_chan_ops mtk_ipi_mbox_chan_ops = {
- .send_data = mtk_mbox_send_data,
- .last_tx_done = mtk_mbox_last_tx_done,
- .startup = mtk_mbox_startup,
- .shutdown = mtk_mbox_shutdown,
- };
- static struct mtk_mbox_operations mtk_mbox_ops = {
- .mtk_send_ipi = mtk_mbox_send_ipi,
- .mtk_tx_done = mtk_mbox_tx_done,
- .mtk_startup = mtk_mbox_start,
- .mtk_shutdown = mtk_mbox_down,
- };
- static struct mbox_chan *mtk_rpmsg_mbox_xlate(struct mbox_controller *mbox,
- const struct of_phandle_args *sp)
- {
- int chan_id = sp->args[0];
- if (chan_id >= mbox->num_chans)
- return ERR_PTR(-EINVAL);
- return &mbox->chans[chan_id];
- }
- int mtk_mbox_chan_create(struct mbox_controller *mboxctrl,
- struct mtk_mbox_device *mbdev, int num)
- {
- struct mtk_mbox_chan *mchan;
- struct mtk_mbox_pin_send *msend;
- struct mbox_chan *chan;
- unsigned int i, j, count;
- mchan = kcalloc(num, sizeof(struct mtk_mbox_chan), GFP_KERNEL);
- if (!mchan)
- return -ENOMEM;
- chan = kcalloc(num, sizeof(struct mbox_chan), GFP_KERNEL);
- if (!chan) {
- kfree(mchan);
- return -ENOMEM;
- }
- count = mbdev->send_count;
- for (i = 0; i < num; i++) {
- chan[i].con_priv = &mchan[i];
- mchan[i].chan = &chan[i];
- mchan[i].mbdev = mbdev;
- mchan[i].ops = &mtk_mbox_ops;
- for (j = 0; j < count; j++) {
- msend = &(mbdev->pin_send_table[j]);
- if (i == msend->chan_id) {
- mchan[i].mbox = msend->mbox;
- mchan[i].send_slot = msend->offset;
- mchan[i].send_slot_size = msend->msg_size;
- mchan[i].send_pin_index = msend->pin_index;
- mchan[i].send_pin_offset = j;
- }
- }
- }
- mboxctrl->ops = &mtk_ipi_mbox_chan_ops;
- mboxctrl->chans = chan;
- mboxctrl->of_xlate = mtk_rpmsg_mbox_xlate;
- return 0;
- }
|