From 1d07aca68d32460d8cc953dded6908aadf21fd9a Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Mon, 26 Jul 2021 20:55:37 +0200 Subject: [PATCH 1/3] irqchip/apple-aic: fix irq_disable from within irq handlers Signed-off-by: Sven Peter --- drivers/irqchip/irq-apple-aic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c index b8c06bd8659e91..6fc145aacaf029 100644 --- a/drivers/irqchip/irq-apple-aic.c +++ b/drivers/irqchip/irq-apple-aic.c @@ -226,7 +226,7 @@ static void aic_irq_eoi(struct irq_data *d) * Reading the interrupt reason automatically acknowledges and masks * the IRQ, so we just unmask it here if needed. */ - if (!irqd_irq_disabled(d) && !irqd_irq_masked(d)) + if (!irqd_irq_masked(d)) aic_irq_unmask(d); } From 7ba5cbb1bfa68f9791ec95aea14a331be7d4f0c6 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Mon, 2 Aug 2021 08:45:08 +0200 Subject: [PATCH 2/3] mailbox: add TXDONE_DIRECT Add TXDONE_DIRECT for mailbox controllers that can very quickly acknowledge transmission of messages because they are e.g. backed by a hardware FIFO. The mailbox controller on the Apple M1 SoC has a hardware fifo that is 16 messages deep. In the common case this FIFO will always be empty when a message is sent. With TXDONE_DIRECT those messages can be acknowledge immediately and there's no need to enable the interrupt which would directly fire. In the unlikely case that the FIFO is currently full the controller can still fall back to TXDONE_BY_IRQ. Signed-off-by: Sven Peter --- drivers/mailbox/mailbox.c | 18 +++++++++++++++++- drivers/mailbox/mailbox.h | 1 + include/linux/mailbox_controller.h | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 3e7d4b20ab34fa..685914499bc368 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -23,6 +23,8 @@ static LIST_HEAD(mbox_cons); static DEFINE_MUTEX(con_mutex); +static void tx_tick(struct mbox_chan *chan, int r); + static int add_to_rbuf(struct mbox_chan *chan, void *mssg) { int idx; @@ -82,6 +84,12 @@ static void msg_submit(struct mbox_chan *chan) exit: spin_unlock_irqrestore(&chan->lock, flags); + /* check if the message has already been acked */ + if (!err && (chan->txdone_method & TXDONE_DIRECT)) { + tx_tick(chan, 0); + return; + } + /* kick start the timer immediately to avoid delays */ if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { /* but only if not already active */ @@ -490,7 +498,15 @@ int mbox_controller_register(struct mbox_controller *mbox) else /* It has to be ACK then */ txdone = TXDONE_BY_ACK; - if (txdone == TXDONE_BY_POLL) { + if (mbox->txdone_direct) + txdone |= TXDONE_DIRECT; + + if ((txdone & TXDONE_DIRECT) && (txdone & TXDONE_BY_ACK)) { + dev_err(mbox->dev, "TXDONE_DIRECT and TXDONE_BY_ACK cannot be used together.\n"); + return -EINVAL; + } + + if (txdone & TXDONE_BY_POLL) { if (!mbox->ops->last_tx_done) { dev_err(mbox->dev, "last_tx_done method is absent\n"); diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h index 046d6d258b320c..584e7f443429c4 100644 --- a/drivers/mailbox/mailbox.h +++ b/drivers/mailbox/mailbox.h @@ -6,5 +6,6 @@ #define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ #define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ #define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */ +#define TXDONE_DIRECT BIT(3) /* ACK received when ops->send_data was succesful */ #endif /* __MAILBOX_H */ diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 36d6ce673503c1..9900d968f66f3c 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -64,6 +64,11 @@ struct mbox_chan_ops { * @txdone_poll: If the controller can read but not report the TX * done. Ex, some register shows the TX status but * no interrupt rises. Ignored if 'txdone_irq' is set. + * @txdone_direct: Indicates that the API can assume that messages have + * been transmitted successfully when ops->submit_msg was + * successful. Must be used in conjunction with + * 'txdone_irq' or 'txdone_poll' when the message could + * not be submitted directly. * @txpoll_period: If 'txdone_poll' is in effect, the API polls for * last TX's status after these many millisecs * @of_xlate: Controller driver specific mapping of channel via DT @@ -78,6 +83,7 @@ struct mbox_controller { int num_chans; bool txdone_irq; bool txdone_poll; + bool txdone_direct; unsigned txpoll_period; struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox, const struct of_phandle_args *sp); From 90737b3eb7fb0f287590b40c4663f5d601dec830 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Tue, 27 Jul 2021 17:57:33 +0200 Subject: [PATCH 3/3] mailbox WIP --- drivers/mailbox/Kconfig | 5 + drivers/mailbox/Makefile | 4 + drivers/mailbox/apple-asc-mailbox-trace.h | 81 +++++ drivers/mailbox/apple-asc-mailbox.c | 403 ++++++++++++++++++++++ drivers/mailbox/apple-asc-mailbox.h | 78 +++++ 5 files changed, 571 insertions(+) create mode 100644 drivers/mailbox/apple-asc-mailbox-trace.h create mode 100644 drivers/mailbox/apple-asc-mailbox.c create mode 100644 drivers/mailbox/apple-asc-mailbox.h diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index b4b780ea2ac8cc..4e5f3d67a33191 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -8,6 +8,11 @@ menuconfig MAILBOX if MAILBOX +config APPLE_MBOX + tristate "Apple RTKit Mailbox" + depends on ARM64 + default ARCH_APPLE + config ARM_MHU tristate "ARM MHU Mailbox" depends on ARM_AMBA diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index c2089f04887e99..bf946451264cf9 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -58,3 +58,7 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o + +obj-$(CONFIG_APPLE_MBOX) += apple-asc-mailbox.o + +CFLAGS_apple-asc-mailbox.o := -I$(src) diff --git a/drivers/mailbox/apple-asc-mailbox-trace.h b/drivers/mailbox/apple-asc-mailbox-trace.h new file mode 100644 index 00000000000000..9578ea61840190 --- /dev/null +++ b/drivers/mailbox/apple-asc-mailbox-trace.h @@ -0,0 +1,81 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM apple_asc + +#if !defined(__APPLE_ASC_MAILBOX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __APPLE_ASC_MAILBOX_TRACE_H + +#include +#include + +#include "apple-asc-mailbox.h" + +DECLARE_EVENT_CLASS(apple_rtkit_log_msg, + TP_PROTO(struct apple_mbox *mbox, u64 msg0, u64 msg1), + TP_ARGS(mbox, msg0, msg1), + TP_STRUCT__entry( + __string(name, dev_name(mbox->dev)) + __field(u64, msg0) + __field(u64, msg1) + ), + TP_fast_assign( + __assign_str(name, dev_name(mbox->dev)); + __entry->msg0 = msg0; + __entry->msg1 = msg1; + ), + TP_printk("%s: %016llx %016llx (ep: 0x%02x)", + __get_str(name), + __entry->msg0, + __entry->msg1, + ((u8)__entry->msg1&0xff)) +); + +DEFINE_EVENT(apple_rtkit_log_msg, apple_mbox_hw_send, + TP_PROTO(struct apple_mbox *mbox, u64 msg0, u64 msg1), + TP_ARGS(mbox, msg0, msg1) +); + +DEFINE_EVENT(apple_rtkit_log_msg, apple_mbox_hw_recv, + TP_PROTO(struct apple_mbox *mbox, u64 msg0, u64 msg1), + TP_ARGS(mbox, msg0, msg1) +); + +DEFINE_EVENT(apple_rtkit_log_msg, apple_mbox_send_fifo_put, + TP_PROTO(struct apple_mbox *mbox, u64 msg0, u64 msg1), + TP_ARGS(mbox, msg0, msg1) +); + +DECLARE_EVENT_CLASS(apple_rtkit_irq_endis, + TP_PROTO(struct apple_mbox *mbox, bool enable), + TP_ARGS(mbox, enable), + TP_STRUCT__entry( + __string(name, dev_name(mbox->dev)) + __field(bool, enable) + ), + TP_fast_assign( + __assign_str(name, dev_name(mbox->dev)); + __entry->enable = enable; + ), + TP_printk("%s: %d", + __get_str(name), + __entry->enable) +); + +DEFINE_EVENT(apple_rtkit_irq_endis, apple_mbox_can_recv_irq_enable, + TP_PROTO(struct apple_mbox *mbox, bool enable), + TP_ARGS(mbox, enable) +); + +DEFINE_EVENT(apple_rtkit_irq_endis, apple_mbox_can_send_irq_enable, + TP_PROTO(struct apple_mbox *mbox, bool enable), + TP_ARGS(mbox, enable) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE apple-asc-mailbox-trace + +#include \ No newline at end of file diff --git a/drivers/mailbox/apple-asc-mailbox.c b/drivers/mailbox/apple-asc-mailbox.c new file mode 100644 index 00000000000000..171c46c2471d68 --- /dev/null +++ b/drivers/mailbox/apple-asc-mailbox.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "apple-asc-mailbox.h" + +#define CREATE_TRACE_POINTS +#include "apple-asc-mailbox-trace.h" + +static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox) +{ + u32 mbox_ctrl = readl(apple_mbox->regs + APPLE_IOP_A2I_CONTROL); + return !(mbox_ctrl & APPLE_IOP_A2I_CONTROL_FULL); +} + +static void apple_mbox_hw_send(struct apple_mbox *apple_mbox, + struct apple_mbox_msg *msg) +{ + trace_apple_mbox_hw_send(apple_mbox, msg->msg, msg->info); + WARN_ON(!apple_mbox_hw_can_send(apple_mbox)); + writeq(msg->msg, apple_mbox->regs + APPLE_IOP_A2I_MBOX_DATA); + writeq(msg->info, apple_mbox->regs + APPLE_IOP_A2I_MBOX_INFO); +} + +static bool apple_mbox_hw_can_recv(struct apple_mbox *apple_mbox) +{ + u32 mbox_ctrl = readl(apple_mbox->regs + APPLE_IOP_I2A_CONTROL); + return !(mbox_ctrl & APPLE_IOP_I2A_CONTROL_EMPTY); +} + +static void apple_mbox_hw_recv(struct apple_mbox *apple_mbox, + struct apple_mbox_msg *msg) +{ + WARN_ON(!apple_mbox_hw_can_recv(apple_mbox)); + msg->msg = readq(apple_mbox->regs + APPLE_IOP_I2A_MBOX_DATA); + msg->info = readq(apple_mbox->regs + APPLE_IOP_I2A_MBOX_INFO); + trace_apple_mbox_hw_recv(apple_mbox, msg->msg, msg->info); +} + +static void apple_mbox_can_recv_irq_enable(struct apple_mbox *mbox, bool enable) +{ + trace_apple_mbox_can_recv_irq_enable(mbox, enable); + if (enable) + enable_irq(mbox->irq_can_recv); + else + disable_irq_nosync(mbox->irq_can_recv); +} + +static void apple_mbox_can_send_irq_enable(struct apple_mbox *mbox, bool enable) +{ + trace_apple_mbox_can_send_irq_enable(mbox, enable); + if (enable) + enable_irq(mbox->irq_can_send); + else + disable_irq_nosync(mbox->irq_can_send); +} + +static irqreturn_t apple_mbox_can_send_irq_handler(int irq, void *data) +{ + struct apple_mbox *apple_mbox = data; + struct apple_chan_priv *chan_priv; + bool keep_irq_enabled = false; + unsigned long flags; + int i; + + for (i = 0; i < APPLE_IOP_MAX_ACTIVE_CHANS; ++i) { + chan_priv = apple_mbox->chans[i].con_priv; + if (!chan_priv) + continue; + if (!chan_priv->needs_irq) + continue; + if (!apple_mbox_hw_can_send(apple_mbox)) + break; + + chan_priv->needs_irq = false; + mbox_chan_txdone(&apple_mbox->chans[i], 0); + } + + spin_lock_irqsave(&apple_mbox->lock, flags); + for (i = 0; i < APPLE_IOP_MAX_ACTIVE_CHANS; ++i) { + chan_priv = apple_mbox->chans[i].con_priv; + if (!chan_priv) + continue; + if (chan_priv->needs_irq) { + keep_irq_enabled = true; + break; + } + } + + if (keep_irq_enabled) { + apple_mbox->allow_can_send_irq_enable = false; + apple_mbox_can_send_irq_enable(apple_mbox, true); + } else { + apple_mbox->allow_can_send_irq_enable = true; + apple_mbox_can_send_irq_enable(apple_mbox, false); + } + spin_unlock_irqrestore(&apple_mbox->lock, flags); + + return IRQ_HANDLED; +} + +static irqreturn_t apple_mbox_recv_irq_handler(int irq, void *data) +{ + struct apple_mbox *mbox = data; + struct apple_mbox_msg msg; + bool wake = false; + size_t len; + unsigned long flags; + + while (apple_mbox_hw_can_recv(mbox)) { + spin_lock_irqsave(&mbox->lock, flags); + if (unlikely(kfifo_avail(&mbox->recv_fifo) < 1)) { + apple_mbox_can_recv_irq_enable(mbox, false); + mbox->recv_full = true; + spin_unlock_irqrestore(&mbox->lock, flags); + return IRQ_WAKE_THREAD; + } + spin_unlock_irqrestore(&mbox->lock, flags); + + apple_mbox_hw_recv(mbox, &msg); + len = kfifo_in(&mbox->recv_fifo, &msg, 1); + WARN_ON(len != 1); + wake = true; + } + + if (wake) + return IRQ_WAKE_THREAD; + else + return IRQ_HANDLED; +} + +static irqreturn_t apple_mbox_recv_irq_thread(int irq, void *data) +{ + struct apple_mbox *apple_mbox = data; + struct mbox_controller *mbox = &apple_mbox->controller; + struct apple_mbox_msg msg; + struct apple_chan_priv *chan_priv; + int i; + u8 endpoint; + s8 chan_idx; + size_t len; + unsigned long flags; + + while (kfifo_len(&apple_mbox->recv_fifo) >= 1) { + len = kfifo_out(&apple_mbox->recv_fifo, &msg, 1); + WARN_ON(len != 1); + + endpoint = msg.info & 0xff; + chan_idx = apple_mbox->epmap[endpoint]; + if (chan_idx < 0) { + dev_err(mbox->dev, + "Received message for unknown endpoint #0x%02x.", + endpoint); + continue; + } + + chan_priv = mbox->chans[i].con_priv; + if (!chan_priv->enabled) { + dev_err(mbox->dev, + "Received message for disabled endpoint #0x%02x.", + endpoint); + continue; + } + + mbox_chan_received_data(&mbox->chans[chan_idx], + (void *)msg.msg); + } + + spin_lock_irqsave(&apple_mbox->lock, flags); + if (apple_mbox->recv_full) { + apple_mbox->recv_full = false; + apple_mbox_can_recv_irq_enable(apple_mbox, true); + } + spin_unlock_irqrestore(&apple_mbox->lock, flags); + + return IRQ_HANDLED; +} + +static struct mbox_chan *apple_mbox_of_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *spec) +{ + struct apple_mbox *apple_mbox = dev_get_drvdata(mbox->dev); + struct mbox_chan *chan; + struct apple_chan_priv *chan_priv; + int i, endpoint, free_chan_idx; + + if (spec->args_count != 1) + return ERR_PTR(-EINVAL); + + endpoint = spec->args[0]; + if (endpoint > APPLE_IOP_MAX_ENDPOINTS || endpoint < 0) + return ERR_PTR(-EINVAL); + + if (apple_mbox->epmap[endpoint] >= 0) + return ERR_PTR(-EBUSY); + + free_chan_idx = -1; + for (i = 0; i < mbox->num_chans; i++) { + chan_priv = mbox->chans[i].con_priv; + + if (!chan_priv) { + free_chan_idx = i; + break; + } + } + + if (free_chan_idx < 0) { + dev_err(mbox->dev, "No free channels left\n"); + return ERR_PTR(-EBUSY); + } + + chan = &mbox->chans[free_chan_idx]; + chan_priv = devm_kzalloc(mbox->dev, sizeof(*chan_priv), GFP_KERNEL); + if (!chan_priv) + return ERR_PTR(-ENOMEM); + + apple_mbox->epmap[endpoint] = free_chan_idx; + chan_priv->endpoint = endpoint; + chan_priv->apple_mbox = apple_mbox; + chan->con_priv = chan_priv; + return chan; +} + +static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data) +{ + struct apple_chan_priv *chan_priv = chan->con_priv; + struct apple_mbox *apple_mbox = chan_priv->apple_mbox; + struct apple_mbox_msg msg; + unsigned long flags; + int ret = 0; + + msg.info = chan_priv->endpoint; + msg.msg = (u64)data; + + spin_lock_irqsave(&apple_mbox->lock, flags); + + if (apple_mbox_hw_can_send(apple_mbox)) { + apple_mbox_hw_send(apple_mbox, &msg); + } else { + ret = -EBUSY; + if (apple_mbox->allow_can_send_irq_enable) { + apple_mbox->allow_can_send_irq_enable = false; + apple_mbox_can_send_irq_enable(apple_mbox, true); + } + chan_priv->needs_irq = true; + } + + spin_unlock_irqrestore(&apple_mbox->lock, flags); + return ret; +} + +static int apple_mbox_chan_startup(struct mbox_chan *chan) +{ + struct apple_chan_priv *chan_priv = chan->con_priv; + + chan_priv->enabled = true; + return 0; +} + +static void apple_mbox_chan_shutdown(struct mbox_chan *chan) +{ + struct apple_chan_priv *chan_priv = chan->con_priv; + + chan_priv->enabled = false; +} + +static const struct mbox_chan_ops apple_mbox_ops = { + .send_data = &apple_mbox_chan_send_data, + .startup = &apple_mbox_chan_startup, + .shutdown = &apple_mbox_chan_shutdown, +}; + +static int apple_mbox_probe(struct platform_device *pdev) +{ + int ret, i; + struct apple_mbox *mbox; + struct resource *regs; + struct device *dev = &pdev->dev; + + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) + return -ENOMEM; + platform_set_drvdata(pdev, mbox); + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + mbox->dev = dev; + spin_lock_init(&mbox->lock); + INIT_KFIFO(mbox->recv_fifo); + + for (i = 0; i < APPLE_IOP_MAX_ENDPOINTS; ++i) + mbox->epmap[i] = -1; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -EINVAL; + + mbox->regs = devm_ioremap_resource(dev, regs); + if (IS_ERR(mbox->regs)) + return PTR_ERR(mbox->regs); + + mbox->irq_can_send = platform_get_irq_byname(pdev, "can-send"); + if (mbox->irq_can_send < 0) + return -ENODEV; + mbox->irq_can_recv = platform_get_irq_byname(pdev, "can-recv"); + if (mbox->irq_can_recv < 0) + return -ENODEV; + + ret = devm_clk_bulk_get_all(dev, &mbox->clks); + if (ret) + return ret; + mbox->num_clks = ret; + + ret = clk_bulk_prepare_enable(mbox->num_clks, mbox->clks); + if (ret) + return ret; + + mbox->controller.dev = mbox->dev; + mbox->controller.num_chans = APPLE_IOP_MAX_ACTIVE_CHANS; + mbox->controller.chans = mbox->chans; + mbox->controller.ops = &apple_mbox_ops; + mbox->controller.of_xlate = &apple_mbox_of_xlate; + mbox->controller.txdone_irq = true; + mbox->controller.txdone_direct = true; + mbox->allow_can_send_irq_enable = true; + + ret = request_irq(mbox->irq_can_send, &apple_mbox_can_send_irq_handler, + IRQF_NO_AUTOEN, dev_name(dev), mbox); + if (ret) + goto err_clk_disable; + + ret = request_threaded_irq(mbox->irq_can_recv, + &apple_mbox_recv_irq_handler, + &apple_mbox_recv_irq_thread, 0, + dev_name(dev), mbox); + if (ret) + goto free_can_send_irq; + + ret = devm_mbox_controller_register(dev, &mbox->controller); + if (ret) + goto free_can_recv_irq; + + return ret; + +free_can_recv_irq: + free_irq(mbox->irq_can_recv, mbox); +free_can_send_irq: + free_irq(mbox->irq_can_send, mbox); +err_clk_disable: + clk_bulk_disable_unprepare(mbox->num_clks, mbox->clks); + return ret; +} + +/* + * these are probably all the same but use different compatible just in case + * we discover quirks later on + */ +static const struct of_device_id apple_mbox_of_match[] = { + { + .compatible = "apple,t8103-ans-mailbox", + }, + { + .compatible = "apple,t8103-smc-mailbox", + }, + { + .compatible = "apple,t8103-rtkit-mailbox", + }, + { + .compatible = "apple,t8103-sepos-mailbox", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, apple_mbox_of_match); + +static int apple_mbox_remove(struct platform_device *pdev) +{ + struct apple_mbox *apple_mbox = platform_get_drvdata(pdev); + + free_irq(apple_mbox->irq_can_recv, apple_mbox); + free_irq(apple_mbox->irq_can_send, apple_mbox); + + return 0; +} + +static void apple_mbox_shutdown(struct platform_device *pdev) +{ + apple_mbox_remove(pdev); +} + +static struct platform_driver apple_mbox_driver = { + .driver = { + .name = "apple-mailbox", + .of_match_table = apple_mbox_of_match, + }, + .probe = apple_mbox_probe, + .remove = apple_mbox_remove, + .shutdown = apple_mbox_shutdown, +}; +module_platform_driver(apple_mbox_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Sven Peter "); +MODULE_DESCRIPTION("Apple mailbox driver"); diff --git a/drivers/mailbox/apple-asc-mailbox.h b/drivers/mailbox/apple-asc-mailbox.h new file mode 100644 index 00000000000000..ae5cb86668da73 --- /dev/null +++ b/drivers/mailbox/apple-asc-mailbox.h @@ -0,0 +1,78 @@ +#ifndef APPLE_ASC_MAILBOX +#define APPLE_ASC_MAILBOX 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* A2I = Application Processor (us) to I/O Processor (usually RTKit) */ +#define APPLE_IOP_A2I_CONTROL 0x110 +#define APPLE_IOP_A2I_CONTROL_FULL BIT(16) +#define APPLE_IOP_A2I_CONTROL_EMPTY BIT(17) + +#define APPLE_IOP_I2A_CONTROL 0x114 +#define APPLE_IOP_I2A_CONTROL_FULL BIT(16) +#define APPLE_IOP_I2A_CONTROL_EMPTY BIT(17) + +#define APPLE_IOP_A2I_MBOX_DATA 0x800 +#define APPLE_IOP_A2I_MBOX_INFO 0x808 +#define APPLE_IOP_I2A_MBOX_DATA 0x830 +#define APPLE_IOP_I2A_MBOX_INFO 0x838 + +/* max channels to save memory; IPC protocol supports up to 0x100 chans */ +#define APPLE_IOP_MAX_ACTIVE_CHANS 20 +#define APPLE_IOP_MAX_ENDPOINTS 0x100 + +struct apple_mbox; + +struct apple_chan_priv { + u8 endpoint; + bool needs_irq; + bool enabled; + struct apple_mbox *apple_mbox; +}; + +struct apple_mbox_msg { + u64 msg; + u64 info; +}; + +struct apple_mbox { + void __iomem *regs, *sart_regs; + struct resource *mmio_shmem; + int irq_can_send, irq_can_recv; + + bool allow_can_send_irq_enable; + + struct clk_bulk_data *clks; + int num_clks; + + spinlock_t lock; + + s8 epmap[APPLE_IOP_MAX_ENDPOINTS]; + struct mbox_chan chans[APPLE_IOP_MAX_ACTIVE_CHANS]; + + DECLARE_BITMAP(rtkit_endpoints, APPLE_IOP_MAX_ENDPOINTS); + + DECLARE_KFIFO(recv_fifo, struct apple_mbox_msg, 16); + bool recv_full; + + struct device *dev; + struct mbox_controller controller; +}; + +#endif \ No newline at end of file