| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <linux/completion.h> |
| #include <linux/delay.h> |
| #include <linux/err.h> |
| #include <linux/export.h> |
| #include <linux/io.h> |
| #include <linux/interrupt.h> |
| #include <linux/mailbox_controller.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/notifier.h> |
| #include <linux/platform_device.h> |
| #include <linux/slab.h> |
| #include <linux/spinlock.h> |
| #include <linux/types.h> |
| #include <linux/mailbox_client.h> |
| #include <linux/uaccess.h> |
| #include <linux/fs.h> |
| #include <linux/cdev.h> |
| #include <linux/list.h> |
| #include <linux/of_device.h> |
| #include <linux/amlogic/aml_mbox.h> |
| #include <dt-bindings/mailbox/t3-mbox.h> |
| #include <dt-bindings/mailbox/t7-mbox.h> |
| #include <dt-bindings/mailbox/sc2-mbox.h> |
| #include <dt-bindings/mailbox/s4-mbox.h> |
| #include <dt-bindings/mailbox/t5m-mbox.h> |
| #include <dt-bindings/mailbox/t3x-mbox.h> |
| #include <dt-bindings/mailbox/s5-mbox.h> |
| #include <dt-bindings/mailbox/s1a-mbox.h> |
| #include "meson_mbox_fifo.h" |
| #include "meson_mbox_comm.h" |
| |
| #define ASYNC 1 |
| #define SYNC 2 |
| #define MBOX_HEAD_SIZE 0x1C |
| #define DRIVER_NAME "meson_mbox_fifo" |
| |
| struct mbox_header { |
| u32 status; |
| u64 task; |
| u64 complete; |
| u64 ullclt; |
| } __packed; |
| |
| struct mbox_data { |
| struct mbox_header mbox_header; |
| char data[MBOX_DATA_SIZE]; |
| } __packed; |
| |
| struct mbox_domain { |
| u32 drvid; |
| u32 mboxid; |
| u32 flags; |
| }; |
| |
| struct mbox_domain_data { |
| struct mbox_domain *mbox_domains; |
| u32 domain_counts; |
| }; |
| |
| struct aml_chan_priv { |
| struct aml_mbox_chan *aml_chan; |
| u32 mbox_nums; |
| }; |
| |
| #define MBOX_DOMAIN(drv_id, mbox_id, flag) \ |
| { \ |
| .flags = flag, \ |
| .drvid = drv_id, \ |
| .mboxid = mbox_id, \ |
| } |
| |
| static void mbox_fifo_write(void __iomem *to, void *from, long count) |
| { |
| int i = 0; |
| long len = count / 4; |
| long rlen = count % 4; |
| u32 rdata = 0; |
| u32 *p = (u32 *)from; |
| |
| while (len > 0) { |
| writel(*(const u32 *)p, (to + 4 * i)); |
| len--; |
| i++; |
| p++; |
| } |
| |
| if (rlen != 0) { |
| memcpy(&rdata, p, rlen); |
| writel(rdata, (to + 4 * i)); |
| } |
| } |
| |
| static void mbox_fifo_read(void *to, void __iomem *from, long count) |
| { |
| int i = 0; |
| long len = count / 4; |
| long rlen = count % 4; |
| u32 rdata = 0; |
| u32 *p = to; |
| |
| while (len > 0) { |
| *p = readl(from + (4 * i)); |
| len--; |
| i++; |
| p++; |
| } |
| |
| if (rlen != 0) { |
| rdata = readl(from + (4 * i)); |
| memcpy(p, &rdata, rlen); |
| } |
| } |
| |
| static void mbox_fifo_clr(void __iomem *to, long count) |
| { |
| int i = 0; |
| int len = (count + 3) / 4; |
| |
| while (len > 0) { |
| writel(0, (to + 4 * i)); |
| len--; |
| i++; |
| } |
| } |
| |
| void mbox_irq_clean(struct aml_mbox_chan *aml_chan, bool ack) |
| { |
| u64 h_sts, l_sts; |
| u64 mask; |
| |
| if (ack) |
| mask = IRQ_SENDACK_BIT(aml_chan->mboxid); |
| else |
| mask = IRQ_REV_BIT(aml_chan->mboxid); |
| if (aml_chan->irq_nums / MHUIRQ_MAXNUM_DEF == 2) { |
| h_sts = (mask >> MBOX_IRQSHIFT) & MBOX_IRQMASK; |
| l_sts = mask & MBOX_IRQMASK; |
| writel(l_sts, aml_chan->mbox_irqclr_addr); |
| writel(h_sts, aml_chan->mbox_irqclr_addr + 4); |
| } else { |
| writel((mask & MBOX_IRQMASK), aml_chan->mbox_irqclr_addr); |
| } |
| } |
| |
| static void mbox_wakeup_wait_task(void *mssg) |
| { |
| struct aml_mbox_data *aml_rdata = mssg; |
| struct completion *p_comp = (struct completion *)(unsigned long)aml_rdata->rev_complete; |
| struct aml_mbox_data *aml_sdata = container_of(p_comp, struct aml_mbox_data, complete); |
| |
| if (IS_ERR_OR_NULL(p_comp)) |
| return; |
| |
| if (aml_rdata->rxsize && aml_rdata->rxbuf) { |
| aml_sdata->rxsize = aml_rdata->rxsize; |
| memcpy(aml_sdata->rxbuf, aml_rdata->rxbuf, aml_rdata->rxsize); |
| } |
| complete(p_comp); |
| } |
| |
| static void mbox_isr_handler(struct aml_mbox_chan *aml_chan) |
| { |
| union mbox_stat mbox_stat; |
| struct mbox_cmd_t *mbox_cmd = &mbox_stat.mbox_cmd_t; |
| struct aml_mbox_data aml_data; |
| struct mbox_header *mbox_header; |
| struct mbox_data mbox_data; |
| struct mbox_chan *mbox_chan; |
| struct mbox_controller *mbox_contr = aml_chan->mbox; |
| |
| mbox_stat.set_cmd = readl(aml_chan->mbox_fsts_addr); |
| if (mbox_stat.set_cmd) { |
| if (mbox_cmd->size >= MBOX_HEAD_SIZE) { |
| aml_data.cmd = mbox_cmd->cmd; |
| if (mbox_cmd->size > (MBOX_DATA_SIZE + MBOX_HEAD_SIZE)) { |
| pr_err("%s: rxsize %x > %x\n", |
| __func__, mbox_cmd->size, |
| MBOX_DATA_SIZE + MBOX_HEAD_SIZE); |
| mbox_cmd->size = MBOX_DATA_SIZE + MBOX_HEAD_SIZE; |
| } |
| mbox_fifo_read(&mbox_data, aml_chan->mbox_rd_addr, mbox_cmd->size); |
| mbox_header = &mbox_data.mbox_header; |
| if (mbox_header->complete == MBOX_NO_FEEDBACK) |
| goto mbox_isr_handler_done; |
| |
| aml_data.rxsize = mbox_cmd->size - MBOX_HEAD_SIZE; |
| aml_data.rxbuf = mbox_data.data; |
| if (mbox_header->complete != 0) { |
| aml_data.rev_complete = mbox_header->complete; |
| mbox_wakeup_wait_task(&aml_data); |
| goto mbox_isr_handler_done; |
| } |
| |
| /*transfer data to client data |
| * status contains the mbox client id |
| */ |
| if (mbox_header->status < mbox_contr->num_chans) { |
| mbox_chan = &mbox_contr->chans[mbox_header->status]; |
| mbox_chan_received_data(mbox_chan, &aml_data); |
| } |
| } |
| } |
| mbox_isr_handler_done: |
| mbox_irq_clean(aml_chan, 0); |
| writel(~0, aml_chan->mbox_fclr_addr); |
| } |
| |
| void mbox_ack_isr_handler(struct mbox_chan *mbox_chan) |
| { |
| struct aml_mbox_chan *aml_chan = mbox_chan->con_priv; |
| struct aml_mbox_data *aml_data = mbox_chan->active_req; |
| |
| if (aml_data && aml_data->sync == MBOX_SYNC) { |
| if (aml_data->rxbuf && aml_data->rxsize) { |
| if (aml_data->rxsize > MBOX_DATA_SIZE) { |
| dev_err(mbox_chan->cl->dev, "%s: rxsize %x > %x\n", |
| __func__, aml_data->txsize, MBOX_DATA_SIZE); |
| aml_data->rxsize = MBOX_DATA_SIZE; |
| } |
| mbox_fifo_read(aml_data->rxbuf, |
| aml_chan->mbox_rd_addr + MBOX_HEAD_SIZE, |
| aml_data->rxsize); |
| } |
| } |
| aml_chan->tx_complete = NULL; |
| mbox_fifo_clr(aml_chan->mbox_wr_addr, MBOX_FIFO_SIZE); |
| mbox_irq_clean(aml_chan, 1); |
| mbox_chan_txdone(mbox_chan, 0); |
| } |
| |
| static u64 mbox_irqstatus(struct aml_mbox_chan *aml_chan) |
| { |
| u64 sts, h_sts, l_sts; |
| |
| if (aml_chan->irq_nums / MHUIRQ_MAXNUM_DEF == 2) { |
| l_sts = readl(aml_chan->mbox_irqsts_addr); |
| h_sts = readl(aml_chan->mbox_irqsts_addr + 4); |
| sts = (h_sts << MBOX_IRQSHIFT) | (l_sts & MBOX_IRQMASK); |
| } else { |
| sts = readl(aml_chan->mbox_irqsts_addr); |
| } |
| pr_debug("%s irq %llx\n", __func__, sts); |
| return sts; |
| } |
| |
| static irqreturn_t mbox_handler(int irq, void *p) |
| { |
| struct mbox_controller *mbox_cons = p; |
| struct mbox_chan *mbox_chan = &mbox_cons->chans[0]; |
| struct aml_mbox_chan *aml_chan = mbox_chan->con_priv; |
| u64 irq_sts = mbox_irqstatus(aml_chan); |
| int out_cnt = mbox_cons->num_chans; |
| u64 irq_prests; |
| int idx; |
| |
| while (irq_sts && (out_cnt != 0)) { |
| irq_prests = irq_sts; |
| for (idx = 0; idx < mbox_cons->num_chans; idx++) { |
| mbox_chan = &mbox_cons->chans[idx]; |
| aml_chan = mbox_chan->con_priv; |
| if (irq_sts & (BIT_ULL(aml_chan->mboxid * 2 + 1))) { |
| irq_sts ^= BIT_ULL(aml_chan->mboxid * 2 + 1); |
| mbox_chan = container_of(aml_chan->tx_complete, |
| struct mbox_chan, tx_complete); |
| if (IS_ERR(mbox_chan)) { |
| mbox_irq_clean(aml_chan, 1); |
| continue; |
| } |
| mbox_ack_isr_handler(mbox_chan); |
| } else if (irq_sts & (BIT_ULL(aml_chan->mboxid * 2))) { |
| irq_sts ^= BIT_ULL(aml_chan->mboxid * 2); |
| mbox_isr_handler(aml_chan); |
| } |
| } |
| irq_sts = mbox_irqstatus(aml_chan); |
| irq_sts = (irq_sts | irq_prests) ^ irq_prests; |
| out_cnt--; |
| } |
| |
| pr_debug("%s irq\n", __func__); |
| return IRQ_HANDLED; |
| } |
| |
| static int mbox_transfer_data(struct mbox_chan *mbox_chan, void *data) |
| { |
| struct aml_mbox_chan *aml_chan = mbox_chan->con_priv; |
| struct aml_mbox_data *aml_data = data; |
| union mbox_stat mbox_stat; |
| struct mbox_cmd_t *mbox_cmd = &mbox_stat.mbox_cmd_t; |
| struct mbox_header mbox_header; |
| |
| mbox_cmd->cmd = aml_data->cmd; |
| if (aml_data->txsize > MBOX_DATA_SIZE) { |
| dev_err(mbox_chan->cl->dev, "%s: size %x > %x\n", |
| __func__, aml_data->txsize, MBOX_DATA_SIZE); |
| return -EINVAL; |
| } |
| mbox_cmd->size = aml_data->txsize + MBOX_HEAD_SIZE; |
| if (aml_data->sync == MBOX_SYNC) |
| mbox_cmd->sync = SYNC; |
| else |
| mbox_cmd->sync = ASYNC; |
| aml_chan->tx_complete = &mbox_chan->tx_complete; |
| memset(&mbox_header, 0, sizeof(mbox_header)); |
| if (aml_data->sync == MBOX_TSYNC) |
| mbox_header.complete = (unsigned long)(&aml_data->complete); |
| else |
| mbox_header.complete = MBOX_NO_FEEDBACK; |
| mbox_fifo_write(aml_chan->mbox_wr_addr, &mbox_header, MBOX_HEAD_SIZE); |
| |
| if (aml_data->txbuf) { |
| mbox_fifo_write(aml_chan->mbox_wr_addr + MBOX_HEAD_SIZE, |
| aml_data->txbuf, aml_data->txsize); |
| } |
| writel(mbox_stat.set_cmd, aml_chan->mbox_fset_addr); |
| return 0; |
| } |
| |
| static int mbox_startup(struct mbox_chan *mbox_chan) |
| { |
| return 0; |
| } |
| |
| static void mbox_shutdown(struct mbox_chan *mbox_chan) |
| { |
| } |
| |
| static bool mbox_last_tx_done(struct mbox_chan *mbox_chan) |
| { |
| struct aml_mbox_chan *aml_chan = mbox_chan->con_priv; |
| |
| return !readl(aml_chan->mbox_fsts_addr); |
| } |
| |
| static struct mbox_chan_ops mbox_ops = { |
| .send_data = mbox_transfer_data, |
| .startup = mbox_startup, |
| .shutdown = mbox_shutdown, |
| .last_tx_done = mbox_last_tx_done, |
| }; |
| |
| static int mbox_fifo_parse_dt(struct platform_device *pdev, struct aml_chan_priv *priv) |
| { |
| void __iomem *mbox_wr_base; |
| void __iomem *mbox_rd_base; |
| void __iomem *mbox_fset_base; |
| void __iomem *mbox_fclr_base; |
| void __iomem *mbox_fsts_base; |
| void __iomem *mbox_irq_base; |
| struct aml_mbox_chan *aml_chan; |
| struct device *dev = &pdev->dev; |
| unsigned int memidx = 0; |
| u32 irqctlr = 0; |
| u32 irqclr = 0; |
| u32 irq_nums = 0; |
| u32 mbox_nums = 0; |
| u32 mboxid = 0; |
| int idx = 0; |
| int err = 0; |
| |
| mbox_wr_base = devm_platform_ioremap_resource(pdev, memidx++); |
| if (IS_ERR_OR_NULL(mbox_wr_base)) |
| return PTR_ERR(mbox_wr_base); |
| |
| if (of_property_read_bool(dev->of_node, "mbox-wr-same")) { |
| mbox_rd_base = mbox_wr_base; |
| } else { |
| mbox_rd_base = devm_platform_ioremap_resource(pdev, memidx++); |
| if (IS_ERR_OR_NULL(mbox_rd_base)) |
| return PTR_ERR(mbox_rd_base); |
| } |
| mbox_fset_base = devm_platform_ioremap_resource(pdev, memidx++); |
| if (IS_ERR(mbox_fset_base)) |
| return PTR_ERR(mbox_fset_base); |
| |
| mbox_fclr_base = devm_platform_ioremap_resource(pdev, memidx++); |
| if (IS_ERR(mbox_fclr_base)) |
| return PTR_ERR(mbox_fclr_base); |
| |
| mbox_fsts_base = devm_platform_ioremap_resource(pdev, memidx++); |
| if (IS_ERR(mbox_fsts_base)) |
| return PTR_ERR(mbox_fsts_base); |
| |
| mbox_irq_base = devm_platform_ioremap_resource(pdev, memidx++); |
| if (IS_ERR(mbox_irq_base)) |
| return PTR_ERR(mbox_irq_base); |
| |
| err = of_property_read_u32(dev->of_node, |
| "mbox-irqctlr", &irqctlr); |
| if (err) { |
| dev_err(dev, "failed to get mbox irq ctlr %d\n", err); |
| return -ENXIO; |
| } |
| err = of_property_read_u32(dev->of_node, |
| "mbox-irqclr", &irqclr); |
| if (err) |
| irqclr = irqctlr; |
| |
| err = of_property_read_u32(dev->of_node, |
| "mbox-irqnums", &irq_nums); |
| if (err) { |
| dev_err(dev, "set mbox irq_nums to default value\n"); |
| irq_nums = MHUIRQ_MAXNUM_DEF; |
| } |
| |
| err = of_property_read_u32(dev->of_node, |
| "mbox-nums", &mbox_nums); |
| if (err) { |
| dev_err(dev, "failed to get mbox num %d\n", err); |
| return -ENXIO; |
| } |
| priv->mbox_nums = mbox_nums; |
| |
| aml_chan = devm_kzalloc(dev, sizeof(*aml_chan) * mbox_nums, GFP_KERNEL); |
| if (IS_ERR(aml_chan)) |
| return PTR_ERR(aml_chan); |
| for (idx = 0; idx < mbox_nums; idx++) { |
| err = of_property_read_u32_index(dev->of_node, "mboxids", |
| idx, &mboxid); |
| if (err) |
| return err; |
| aml_chan[idx].mboxid = mboxid; |
| aml_chan[idx].irq_nums = irq_nums; |
| aml_chan[idx].mbox_wr_addr = mbox_wr_base + PAYLOAD_OFFSET(mboxid); |
| aml_chan[idx].mbox_rd_addr = mbox_rd_base + PAYLOAD_OFFSET(mboxid); |
| aml_chan[idx].mbox_fset_addr = mbox_fset_base + CTL_OFFSET(mboxid); |
| aml_chan[idx].mbox_fclr_addr = mbox_fclr_base + CTL_OFFSET(mboxid); |
| aml_chan[idx].mbox_fsts_addr = mbox_fsts_base + CTL_OFFSET(mboxid); |
| aml_chan[idx].mbox_irqsts_addr = mbox_irq_base + IRQ_STS_OFFSET(irqctlr); |
| aml_chan[idx].mbox_irqclr_addr = mbox_irq_base + IRQ_CLR_OFFSET(irqclr); |
| mutex_init(&aml_chan[idx].mutex); |
| aml_chan[idx].tx_complete = NULL; |
| } |
| priv->aml_chan = aml_chan; |
| return 0; |
| } |
| |
| static int mbox_fifo_probe(struct platform_device *pdev) |
| { |
| struct mbox_chan *mbox_chans; |
| struct device *dev = &pdev->dev; |
| struct aml_mbox_chan *aml_chan; |
| struct mbox_controller *mbox_cons; |
| const struct mbox_domain_data *match; |
| struct mbox_domain *mbox_domains; |
| struct aml_chan_priv aml_priv; |
| u32 mboxid = 0; |
| u32 mbox_nums; |
| int mbox_irq; |
| int err = 0; |
| int idx0 = 0; |
| int idx1 = 0; |
| |
| dev_dbg(dev, "mbox fifo probe\n"); |
| |
| err = mbox_fifo_parse_dt(pdev, &aml_priv); |
| if (err) { |
| dev_err(dev, "mbox parse dt fail\n"); |
| return err; |
| } |
| aml_chan = aml_priv.aml_chan; |
| mbox_nums = aml_priv.mbox_nums; |
| |
| match = of_device_get_match_data(&pdev->dev); |
| if (!match) { |
| dev_err(&pdev->dev, "failed to get match data\n"); |
| return -ENODEV; |
| } |
| mbox_domains = match->mbox_domains; |
| mbox_chans = devm_kzalloc(dev, sizeof(*mbox_chans) * match->domain_counts, GFP_KERNEL); |
| if (IS_ERR(mbox_chans)) |
| return PTR_ERR(mbox_chans); |
| |
| for (idx0 = 0; idx0 < match->domain_counts; idx0++) { |
| mboxid = mbox_domains[idx0].mboxid; |
| for (idx1 = 0; idx1 < mbox_nums; idx1++) { |
| if (mboxid == aml_chan[idx1].mboxid) { |
| mbox_chans[idx0].con_priv = &aml_chan[idx1]; |
| break; |
| } |
| } |
| } |
| mbox_cons = devm_kzalloc(dev, sizeof(*mbox_cons), GFP_KERNEL); |
| if (IS_ERR(mbox_cons)) |
| return PTR_ERR(mbox_cons); |
| |
| mbox_cons->chans = mbox_chans; |
| mbox_cons->num_chans = match->domain_counts; |
| mbox_cons->txdone_irq = true; |
| mbox_cons->ops = &mbox_ops; |
| mbox_cons->dev = dev; |
| platform_set_drvdata(pdev, mbox_cons); |
| if (mbox_controller_register(mbox_cons)) { |
| dev_err(dev, "failed to register mailbox controller\n"); |
| return -ENOMEM; |
| } |
| |
| for (idx0 = 0; idx0 < mbox_nums; idx0++) |
| aml_chan[idx0].mbox = mbox_cons; |
| |
| mbox_irq = platform_get_irq(pdev, 0); |
| if (mbox_irq < 0) { |
| dev_err(dev, "failed to get interrupt %d\n", mbox_irq); |
| return -ENXIO; |
| } |
| |
| err = request_threaded_irq(mbox_irq, mbox_handler, |
| NULL, IRQF_ONESHOT | IRQF_NO_SUSPEND, |
| DRIVER_NAME, mbox_cons); |
| if (err) { |
| dev_err(dev, "request irq error\n"); |
| return err; |
| } |
| |
| dev_dbg(dev, "mbox fifo probe done\n"); |
| return 0; |
| } |
| |
| static int mbox_fifo_remove(struct platform_device *pdev) |
| { |
| struct mbox_controller *mbox_cons = platform_get_drvdata(pdev); |
| |
| mbox_controller_unregister(mbox_cons); |
| |
| platform_set_drvdata(pdev, NULL); |
| |
| return 0; |
| } |
| |
| struct mbox_domain sc2_mbox_domains[] = { |
| [SC2_DSPA2REE0] = MBOX_DOMAIN(SC2_DSPA2REE0, SC2_MBOX_DSPA2REE, 0), |
| [SC2_REE2DSPA0] = MBOX_DOMAIN(SC2_REE2DSPA0, SC2_MBOX_REE2DSPA, 0), |
| [SC2_REE2DSPA1] = MBOX_DOMAIN(SC2_REE2DSPA1, SC2_MBOX_REE2DSPA, 0), |
| [SC2_REE2DSPA2] = MBOX_DOMAIN(SC2_REE2DSPA2, SC2_MBOX_REE2DSPA, 0), |
| [SC2_AO2REE] = MBOX_DOMAIN(SC2_AO2REE, SC2_MBOX_AO2REE, 0), |
| [SC2_REE2AO0] = MBOX_DOMAIN(SC2_REE2AO0, SC2_MBOX_REE2AO, 0), |
| [SC2_REE2AO1] = MBOX_DOMAIN(SC2_REE2AO1, SC2_MBOX_REE2AO, 0), |
| [SC2_REE2AO2] = MBOX_DOMAIN(SC2_REE2AO2, SC2_MBOX_REE2AO, 0), |
| [SC2_REE2AO3] = MBOX_DOMAIN(SC2_REE2AO3, SC2_MBOX_REE2AO, 0), |
| [SC2_REE2AO4] = MBOX_DOMAIN(SC2_REE2AO4, SC2_MBOX_REE2AO, 0), |
| [SC2_REE2AO5] = MBOX_DOMAIN(SC2_REE2AO5, SC2_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data sc2_mbox_domains_data __initdata = { |
| .mbox_domains = sc2_mbox_domains, |
| .domain_counts = ARRAY_SIZE(sc2_mbox_domains), |
| }; |
| |
| struct mbox_domain t3_mbox_domains[] = { |
| [T3_DSPA2REE0] = MBOX_DOMAIN(T3_DSPA2REE0, T3_MBOX_DSPA2REE, 0), |
| [T3_REE2DSPA0] = MBOX_DOMAIN(T3_REE2DSPA0, T3_MBOX_REE2DSPA, 0), |
| [T3_REE2DSPA1] = MBOX_DOMAIN(T3_REE2DSPA1, T3_MBOX_REE2DSPA, 0), |
| [T3_REE2DSPA2] = MBOX_DOMAIN(T3_REE2DSPA2, T3_MBOX_REE2DSPA, 0), |
| [T3_AO2REE] = MBOX_DOMAIN(T3_AO2REE, T3_MBOX_AO2REE, 0), |
| [T3_REE2AO0] = MBOX_DOMAIN(T3_REE2AO0, T3_MBOX_REE2AO, 0), |
| [T3_REE2AO1] = MBOX_DOMAIN(T3_REE2AO1, T3_MBOX_REE2AO, 0), |
| [T3_REE2AO2] = MBOX_DOMAIN(T3_REE2AO2, T3_MBOX_REE2AO, 0), |
| [T3_REE2AO3] = MBOX_DOMAIN(T3_REE2AO3, T3_MBOX_REE2AO, 0), |
| [T3_REE2AO4] = MBOX_DOMAIN(T3_REE2AO4, T3_MBOX_REE2AO, 0), |
| [T3_REE2AO5] = MBOX_DOMAIN(T3_REE2AO5, T3_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data t3_mbox_domains_data __initdata = { |
| .mbox_domains = t3_mbox_domains, |
| .domain_counts = ARRAY_SIZE(t3_mbox_domains), |
| }; |
| |
| struct mbox_domain t7_mbox_domains[] = { |
| [T7_DSPA2REE0] = MBOX_DOMAIN(T7_DSPA2REE0, T7_MBOX_DSPA2REE, 0), |
| [T7_REE2DSPA0] = MBOX_DOMAIN(T7_REE2DSPA0, T7_MBOX_REE2DSPA, 0), |
| [T7_REE2DSPA1] = MBOX_DOMAIN(T7_REE2DSPA1, T7_MBOX_REE2DSPA, 0), |
| [T7_REE2DSPA2] = MBOX_DOMAIN(T7_REE2DSPA2, T7_MBOX_REE2DSPA, 0), |
| [T7_AO2REE] = MBOX_DOMAIN(T7_AO2REE, T7_MBOX_AO2REE, 0), |
| [T7_REE2AO0] = MBOX_DOMAIN(T7_REE2AO0, T7_MBOX_REE2AO, 0), |
| [T7_REE2AO1] = MBOX_DOMAIN(T7_REE2AO1, T7_MBOX_REE2AO, 0), |
| [T7_REE2AO2] = MBOX_DOMAIN(T7_REE2AO2, T7_MBOX_REE2AO, 0), |
| [T7_REE2AO3] = MBOX_DOMAIN(T7_REE2AO3, T7_MBOX_REE2AO, 0), |
| [T7_REE2AO4] = MBOX_DOMAIN(T7_REE2AO4, T7_MBOX_REE2AO, 0), |
| [T7_REE2AO5] = MBOX_DOMAIN(T7_REE2AO5, T7_MBOX_REE2AO, 0), |
| [T7_DSPB2REE0] = MBOX_DOMAIN(T7_DSPB2REE0, T7_MBOX_DSPB2REE, 0), |
| [T7_REE2DSPB0] = MBOX_DOMAIN(T7_REE2DSPB0, T7_MBOX_REE2DSPB, 0), |
| [T7_REE2DSPB1] = MBOX_DOMAIN(T7_REE2DSPB1, T7_MBOX_REE2DSPB, 0), |
| [T7_REE2DSPB2] = MBOX_DOMAIN(T7_REE2DSPB2, T7_MBOX_REE2DSPB, 0), |
| }; |
| |
| static struct mbox_domain_data t7_mbox_domains_data __initdata = { |
| .mbox_domains = t7_mbox_domains, |
| .domain_counts = ARRAY_SIZE(t7_mbox_domains), |
| }; |
| |
| struct mbox_domain s4_mbox_domains[] = { |
| [S4_AO2REE] = MBOX_DOMAIN(S4_AO2REE, S4_MBOX_AO2REE, 0), |
| [S4_REE2AO0] = MBOX_DOMAIN(S4_REE2AO0, S4_MBOX_REE2AO, 0), |
| [S4_REE2AO1] = MBOX_DOMAIN(S4_REE2AO1, S4_MBOX_REE2AO, 0), |
| [S4_REE2AO2] = MBOX_DOMAIN(S4_REE2AO2, S4_MBOX_REE2AO, 0), |
| [S4_REE2AO3] = MBOX_DOMAIN(S4_REE2AO3, S4_MBOX_REE2AO, 0), |
| [S4_REE2AO4] = MBOX_DOMAIN(S4_REE2AO4, S4_MBOX_REE2AO, 0), |
| [S4_REE2AO5] = MBOX_DOMAIN(S4_REE2AO5, S4_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data s4_mbox_domains_data __initdata = { |
| .mbox_domains = s4_mbox_domains, |
| .domain_counts = ARRAY_SIZE(s4_mbox_domains), |
| }; |
| |
| struct mbox_domain t5m_mbox_domains[] = { |
| [T5M_AO2REE] = MBOX_DOMAIN(T5M_AO2REE, T5M_MBOX_AO2REE, 0), |
| [T5M_REE2AO0] = MBOX_DOMAIN(T5M_REE2AO0, T5M_MBOX_REE2AO, 0), |
| [T5M_REE2AO1] = MBOX_DOMAIN(T5M_REE2AO1, T5M_MBOX_REE2AO, 0), |
| [T5M_REE2AO2] = MBOX_DOMAIN(T5M_REE2AO2, T5M_MBOX_REE2AO, 0), |
| [T5M_REE2AO3] = MBOX_DOMAIN(T5M_REE2AO3, T5M_MBOX_REE2AO, 0), |
| [T5M_REE2AO4] = MBOX_DOMAIN(T5M_REE2AO4, T5M_MBOX_REE2AO, 0), |
| [T5M_REE2AO5] = MBOX_DOMAIN(T5M_REE2AO5, T5M_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data t5m_mbox_domains_data __initdata = { |
| .mbox_domains = t5m_mbox_domains, |
| .domain_counts = ARRAY_SIZE(t5m_mbox_domains), |
| }; |
| |
| struct mbox_domain t3x_mbox_domains[] = { |
| [T3X_DSPA2REE0] = MBOX_DOMAIN(T3X_DSPA2REE0, T3X_MBOX_DSPA2REE, 0), |
| [T3X_REE2DSPA0] = MBOX_DOMAIN(T3X_REE2DSPA0, T3X_MBOX_REE2DSPA, 0), |
| [T3X_REE2DSPA1] = MBOX_DOMAIN(T3X_REE2DSPA1, T3X_MBOX_REE2DSPA, 0), |
| [T3X_REE2DSPA2] = MBOX_DOMAIN(T3X_REE2DSPA2, T3X_MBOX_REE2DSPA, 0), |
| [T3X_AO2REE] = MBOX_DOMAIN(T3X_AO2REE, T3X_MBOX_AO2REE, 0), |
| [T3X_REE2AO0] = MBOX_DOMAIN(T3X_REE2AO0, T3X_MBOX_REE2AO, 0), |
| [T3X_REE2AO1] = MBOX_DOMAIN(T3X_REE2AO1, T3X_MBOX_REE2AO, 0), |
| [T3X_REE2AO2] = MBOX_DOMAIN(T3X_REE2AO2, T3X_MBOX_REE2AO, 0), |
| [T3X_REE2AO3] = MBOX_DOMAIN(T3X_REE2AO3, T3X_MBOX_REE2AO, 0), |
| [T3X_REE2AO4] = MBOX_DOMAIN(T3X_REE2AO4, T3X_MBOX_REE2AO, 0), |
| [T3X_REE2AO5] = MBOX_DOMAIN(T3X_REE2AO5, T3X_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data t3x_mbox_domains_data __initdata = { |
| .mbox_domains = t3x_mbox_domains, |
| .domain_counts = ARRAY_SIZE(t3x_mbox_domains), |
| }; |
| |
| struct mbox_domain s5_mbox_domains[] = { |
| [S5_AO2REE] = MBOX_DOMAIN(S5_AO2REE, S5_MBOX_AO2REE, 0), |
| [S5_REE2AO0] = MBOX_DOMAIN(S5_REE2AO0, S5_MBOX_REE2AO, 0), |
| [S5_REE2AO1] = MBOX_DOMAIN(S5_REE2AO1, S5_MBOX_REE2AO, 0), |
| [S5_REE2AO2] = MBOX_DOMAIN(S5_REE2AO2, S5_MBOX_REE2AO, 0), |
| [S5_REE2AO3] = MBOX_DOMAIN(S5_REE2AO3, S5_MBOX_REE2AO, 0), |
| [S5_REE2AO4] = MBOX_DOMAIN(S5_REE2AO4, S5_MBOX_REE2AO, 0), |
| [S5_REE2AO5] = MBOX_DOMAIN(S5_REE2AO5, S5_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data s5_mbox_domains_data __initdata = { |
| .mbox_domains = s5_mbox_domains, |
| .domain_counts = ARRAY_SIZE(s5_mbox_domains), |
| }; |
| |
| struct mbox_domain s1a_mbox_domains[] = { |
| [S1A_AO2REE] = MBOX_DOMAIN(S1A_AO2REE, S1A_MBOX_AO2REE, 0), |
| [S1A_REE2AO0] = MBOX_DOMAIN(S1A_REE2AO0, S1A_MBOX_REE2AO, 0), |
| [S1A_REE2AO1] = MBOX_DOMAIN(S1A_REE2AO1, S1A_MBOX_REE2AO, 0), |
| [S1A_REE2AO2] = MBOX_DOMAIN(S1A_REE2AO2, S1A_MBOX_REE2AO, 0), |
| [S1A_REE2AO3] = MBOX_DOMAIN(S1A_REE2AO3, S1A_MBOX_REE2AO, 0), |
| [S1A_REE2AO4] = MBOX_DOMAIN(S1A_REE2AO4, S1A_MBOX_REE2AO, 0), |
| [S1A_REE2AO5] = MBOX_DOMAIN(S1A_REE2AO5, S1A_MBOX_REE2AO, 0), |
| }; |
| |
| static struct mbox_domain_data s1a_mbox_domains_data __initdata = { |
| .mbox_domains = s1a_mbox_domains, |
| .domain_counts = ARRAY_SIZE(s1a_mbox_domains), |
| }; |
| |
| static const struct of_device_id mbox_of_match[] = { |
| { |
| .compatible = "amlogic, t3-mbox-fifo", |
| .data = &t3_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, t7-mbox-fifo", |
| .data = &t7_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, sc2-mbox-fifo", |
| .data = &sc2_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, s4-mbox-fifo", |
| .data = &s4_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, t5m-mbox-fifo", |
| .data = &t5m_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, t3x-mbox-fifo", |
| .data = &t3x_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, s5-mbox-fifo", |
| .data = &s5_mbox_domains_data, |
| }, |
| { |
| .compatible = "amlogic, s1a-mbox-fifo", |
| .data = &s1a_mbox_domains_data, |
| }, |
| {}, |
| }; |
| |
| static struct platform_driver mbox_fifo_driver = { |
| .probe = mbox_fifo_probe, |
| .remove = mbox_fifo_remove, |
| .driver = { |
| .owner = THIS_MODULE, |
| .name = DRIVER_NAME, |
| .of_match_table = mbox_of_match, |
| }, |
| }; |
| |
| int __init mbox_fifo_init(void) |
| { |
| return platform_driver_register(&mbox_fifo_driver); |
| } |
| |
| void __exit mbox_fifo_exit(void) |
| { |
| platform_driver_unregister(&mbox_fifo_driver); |
| } |