diff --git a/arch/arm/src/am67/am67_rptun.c b/arch/arm/src/am67/am67_rptun.c index ce79df863e4..39ef0173191 100644 --- a/arch/arm/src/am67/am67_rptun.c +++ b/arch/arm/src/am67/am67_rptun.c @@ -93,6 +93,17 @@ #define AM67_MBOX_USER (3U) +/* Control messages the Linux side exchanges in the mailbox payload. Any + * value outside [READY, END_MSG) is a virtqueue index instead. Values are + * from the TI kernel's drivers/remoteproc/omap_remoteproc.h; SHUTDOWN and + * SHUTDOWN_ACK are TI additions used by ti_k3_r5_remoteproc.c. + */ + +#define RP_MBOX_READY (0xffffff00ul) +#define RP_MBOX_SHUTDOWN (0xffffff14ul) +#define RP_MBOX_SHUTDOWN_ACK (0xffffff15ul) +#define RP_MBOX_END_MSG (0xffffff16ul) + /* VIM IRQ number on MAIN_R5FSS0_0 for mailbox0_cluster3/user3 */ #ifndef CONFIG_AM67_RPTUN_IRQ @@ -141,7 +152,6 @@ static const struct rptun_addrenv_s * am67_rptun_get_addrenv(struct rptun_dev_s *dev); static struct resource_table * am67_rptun_get_resource(struct rptun_dev_s *dev); -static size_t am67_rptun_get_rsc_size(struct rptun_dev_s *dev); static bool am67_rptun_is_autostart(struct rptun_dev_s *dev); static bool am67_rptun_is_master(struct rptun_dev_s *dev); static int am67_rptun_start(struct rptun_dev_s *dev); @@ -161,7 +171,6 @@ static const struct rptun_ops_s g_am67_rptun_ops = .get_firmware = am67_rptun_get_firmware, .get_addrenv = am67_rptun_get_addrenv, .get_resource = am67_rptun_get_resource, - .get_rsc_size = am67_rptun_get_rsc_size, .is_autostart = am67_rptun_is_autostart, .is_master = am67_rptun_is_master, .start = am67_rptun_start, @@ -204,16 +213,6 @@ am67_rptun_get_resource(struct rptun_dev_s *dev) return (struct resource_table *)&g_am67_rsc_table; } -static size_t am67_rptun_get_rsc_size(struct rptun_dev_s *dev) -{ - /* Return the real size of the extended resource table so that OpenAMP's - * remoteproc_set_rsc_table() can find both vdev entries (rptun.c would - * otherwise cap the visible region to sizeof(struct rptun_rsc_s)). - */ - - return sizeof(struct am67_rsc_s); -} - static bool am67_rptun_is_autostart(struct rptun_dev_s *dev) { return true; /* start rptun thread automatically */ @@ -309,14 +308,27 @@ static void am67_rptun_notify_work(void *arg) static int am67_rptun_interrupt(int irq, void *context, void *arg) { struct am67_rptun_dev_s *priv = (struct am67_rptun_dev_s *)arg; + bool shutdown = false; + bool kick = false; /* Drain all messages Linux wrote into FIFO 1. Each read pops one - * entry; stop when MSG_STATUS reports 0 pending messages. + * entry; stop when MSG_STATUS reports 0 pending messages. A single + * interrupt can carry both control messages and virtqueue kicks, so + * classify every entry rather than the batch. */ while (getreg32(AM67_MBOX_MSG_STATUS(AM67_MBOX_RX_FIFO)) != 0) { - (void)getreg32(AM67_MBOX_MESSAGE(AM67_MBOX_RX_FIFO)); + uint32_t msg = getreg32(AM67_MBOX_MESSAGE(AM67_MBOX_RX_FIFO)); + + if (msg == RP_MBOX_SHUTDOWN) + { + shutdown = true; + } + else if (msg < RP_MBOX_READY || msg >= RP_MBOX_END_MSG) + { + kick = true; + } } /* Clear the new-message interrupt status for user-3 / FIFO-1. @@ -333,8 +345,26 @@ static int am67_rptun_interrupt(int irq, void *context, void *arg) putreg32(0, AM67_MBOX_EOI); UP_DSB(); + /* Honour a shutdown request: acknowledge it, then park the core. Linux + * polls the TI-SCI WFI status for 2 ms after the ACK and only halts the + * R5F once it sees us in WFI, so this must never return. + */ + + if (shutdown) + { + putreg32(RP_MBOX_SHUTDOWN_ACK, AM67_MBOX_MESSAGE(AM67_MBOX_TX_FIFO)); + UP_DSB(); + + up_irq_save(); + + for (; ; ) + { + __asm__ __volatile__ ("wfi"); + } + } + if (priv != NULL && priv->callback != NULL && - work_available(&priv->work)) + work_available(&priv->work) && kick) { work_queue(HPWORK, &priv->work, am67_rptun_notify_work, priv, 0); }