Squashed backup commit (no shallow-clone history issues) of xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream commit 9eece662e) plus all fixes applied to get everpal_defconfig building clean against a modern (GCC 15.2.0) toolchain -- see the previous commit message on the lineage-23.2 branch (also in this repo history is not available here since this is a squashed snapshot; full incremental history lives in the local DL380 checkout and the upstream GitHub remote). Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
202 lines
4.6 KiB
C
202 lines
4.6 KiB
C
/*
|
|
* 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;
|
|
}
|