Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'mailbox-for-next' of git://git.linaro.org/landing-teams/working/fujitsu/integration

Pull mailbox updates from Jussi Brar:
"New driver and DT bindings for MHU controller integrated on Amlogic
Meson platform"

* 'mailbox-for-next' of git://git.linaro.org/landing-teams/working/fujitsu/integration:
dt-bindings: mailbox: Add Amlogic Meson MHU Bindings
mailbox: Add Platform Message-Handling-Unit variant driver

+251
+34
Documentation/devicetree/bindings/mailbox/meson-mhu.txt
··· 1 + Amlogic Meson MHU Mailbox Driver 2 + ================================ 3 + 4 + The Amlogic's Meson SoCs Message-Handling-Unit (MHU) is a mailbox controller 5 + that has 3 independent channels/links to communicate with remote processor(s). 6 + MHU links are hardwired on a platform. A link raises interrupt for any 7 + received data. However, there is no specified way of knowing if the sent 8 + data has been read by the remote. This driver assumes the sender polls 9 + STAT register and the remote clears it after having read the data. 10 + 11 + Mailbox Device Node: 12 + ==================== 13 + 14 + Required properties: 15 + -------------------- 16 + - compatible: Shall be "amlogic,meson-gxbb-mhu" 17 + - reg: Contains the mailbox register address range (base 18 + address and length) 19 + - #mbox-cells Shall be 1 - the index of the channel needed. 20 + - interrupts: Contains the interrupt information corresponding to 21 + each of the 2 links of MHU. 22 + 23 + Example: 24 + -------- 25 + 26 + mailbox: mailbox@c883c404 { 27 + #mbox-cells = <1>; 28 + compatible = "amlogic,meson-gxbb-mhu"; 29 + reg = <0 0xc883c404 0 0x4c>; 30 + interrupts = <0 208 IRQ_TYPE_EDGE_RISING>, 31 + <0 209 IRQ_TYPE_EDGE_RISING>, 32 + <0 210 IRQ_TYPE_EDGE_RISING>; 33 + #mbox-cells = <1>; 34 + };
+10
drivers/mailbox/Kconfig
··· 15 15 The controller has 3 mailbox channels, the last of which can be 16 16 used in Secure mode only. 17 17 18 + config PLATFORM_MHU 19 + tristate "Platform MHU Mailbox" 20 + depends on OF 21 + depends on HAS_IOMEM 22 + help 23 + Say Y here if you want to build a platform specific variant MHU 24 + controller driver. 25 + The controller has a maximum of 3 mailbox channels, the last of 26 + which can be used in Secure mode only. 27 + 18 28 config PL320_MBOX 19 29 bool "ARM PL320 Mailbox" 20 30 depends on ARM_AMBA
+2
drivers/mailbox/Makefile
··· 6 6 7 7 obj-$(CONFIG_ARM_MHU) += arm_mhu.o 8 8 9 + obj-$(CONFIG_PLATFORM_MHU) += platform_mhu.o 10 + 9 11 obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o 10 12 11 13 obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
+205
drivers/mailbox/platform_mhu.c
··· 1 + /* 2 + * Copyright (C) 2016 BayLibre SAS. 3 + * Author: Neil Armstrong <narmstrong@baylibre.com> 4 + * Synchronised with arm_mhu.c from : 5 + * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd. 6 + * Copyright (C) 2015 Linaro Ltd. 7 + * Author: Jassi Brar <jaswinder.singh@linaro.org> 8 + * 9 + * This program is free software: you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation, version 2 of the License. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + 19 + #include <linux/interrupt.h> 20 + #include <linux/spinlock.h> 21 + #include <linux/mutex.h> 22 + #include <linux/delay.h> 23 + #include <linux/slab.h> 24 + #include <linux/err.h> 25 + #include <linux/io.h> 26 + #include <linux/module.h> 27 + #include <linux/platform_device.h> 28 + #include <linux/mailbox_controller.h> 29 + 30 + #define INTR_SET_OFS 0x0 31 + #define INTR_STAT_OFS 0x4 32 + #define INTR_CLR_OFS 0x8 33 + 34 + #define MHU_SEC_OFFSET 0x0 35 + #define MHU_LP_OFFSET 0xc 36 + #define MHU_HP_OFFSET 0x18 37 + #define TX_REG_OFFSET 0x24 38 + 39 + #define MHU_CHANS 3 40 + 41 + struct platform_mhu_link { 42 + int irq; 43 + void __iomem *tx_reg; 44 + void __iomem *rx_reg; 45 + }; 46 + 47 + struct platform_mhu { 48 + void __iomem *base; 49 + struct platform_mhu_link mlink[MHU_CHANS]; 50 + struct mbox_chan chan[MHU_CHANS]; 51 + struct mbox_controller mbox; 52 + }; 53 + 54 + static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p) 55 + { 56 + struct mbox_chan *chan = p; 57 + struct platform_mhu_link *mlink = chan->con_priv; 58 + u32 val; 59 + 60 + val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS); 61 + if (!val) 62 + return IRQ_NONE; 63 + 64 + mbox_chan_received_data(chan, (void *)&val); 65 + 66 + writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS); 67 + 68 + return IRQ_HANDLED; 69 + } 70 + 71 + static bool platform_mhu_last_tx_done(struct mbox_chan *chan) 72 + { 73 + struct platform_mhu_link *mlink = chan->con_priv; 74 + u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); 75 + 76 + return (val == 0); 77 + } 78 + 79 + static int platform_mhu_send_data(struct mbox_chan *chan, void *data) 80 + { 81 + struct platform_mhu_link *mlink = chan->con_priv; 82 + u32 *arg = data; 83 + 84 + writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS); 85 + 86 + return 0; 87 + } 88 + 89 + static int platform_mhu_startup(struct mbox_chan *chan) 90 + { 91 + struct platform_mhu_link *mlink = chan->con_priv; 92 + u32 val; 93 + int ret; 94 + 95 + val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); 96 + writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS); 97 + 98 + ret = request_irq(mlink->irq, platform_mhu_rx_interrupt, 99 + IRQF_SHARED, "platform_mhu_link", chan); 100 + if (ret) { 101 + dev_err(chan->mbox->dev, 102 + "Unable to acquire IRQ %d\n", mlink->irq); 103 + return ret; 104 + } 105 + 106 + return 0; 107 + } 108 + 109 + static void platform_mhu_shutdown(struct mbox_chan *chan) 110 + { 111 + struct platform_mhu_link *mlink = chan->con_priv; 112 + 113 + free_irq(mlink->irq, chan); 114 + } 115 + 116 + static const struct mbox_chan_ops platform_mhu_ops = { 117 + .send_data = platform_mhu_send_data, 118 + .startup = platform_mhu_startup, 119 + .shutdown = platform_mhu_shutdown, 120 + .last_tx_done = platform_mhu_last_tx_done, 121 + }; 122 + 123 + static int platform_mhu_probe(struct platform_device *pdev) 124 + { 125 + int i, err; 126 + struct platform_mhu *mhu; 127 + struct device *dev = &pdev->dev; 128 + struct resource *res; 129 + int platform_mhu_reg[MHU_CHANS] = { 130 + MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET 131 + }; 132 + 133 + /* Allocate memory for device */ 134 + mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL); 135 + if (!mhu) 136 + return -ENOMEM; 137 + 138 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 139 + mhu->base = devm_ioremap_resource(dev, res); 140 + if (IS_ERR(mhu->base)) { 141 + dev_err(dev, "ioremap failed\n"); 142 + return PTR_ERR(mhu->base); 143 + } 144 + 145 + for (i = 0; i < MHU_CHANS; i++) { 146 + mhu->chan[i].con_priv = &mhu->mlink[i]; 147 + mhu->mlink[i].irq = platform_get_irq(pdev, i); 148 + if (mhu->mlink[i].irq < 0) { 149 + dev_err(dev, "failed to get irq%d\n", i); 150 + return mhu->mlink[i].irq; 151 + } 152 + mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i]; 153 + mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; 154 + } 155 + 156 + mhu->mbox.dev = dev; 157 + mhu->mbox.chans = &mhu->chan[0]; 158 + mhu->mbox.num_chans = MHU_CHANS; 159 + mhu->mbox.ops = &platform_mhu_ops; 160 + mhu->mbox.txdone_irq = false; 161 + mhu->mbox.txdone_poll = true; 162 + mhu->mbox.txpoll_period = 1; 163 + 164 + platform_set_drvdata(pdev, mhu); 165 + 166 + err = mbox_controller_register(&mhu->mbox); 167 + if (err) { 168 + dev_err(dev, "Failed to register mailboxes %d\n", err); 169 + return err; 170 + } 171 + 172 + dev_info(dev, "Platform MHU Mailbox registered\n"); 173 + return 0; 174 + } 175 + 176 + static int platform_mhu_remove(struct platform_device *pdev) 177 + { 178 + struct platform_mhu *mhu = platform_get_drvdata(pdev); 179 + 180 + mbox_controller_unregister(&mhu->mbox); 181 + 182 + return 0; 183 + } 184 + 185 + static const struct of_device_id platform_mhu_dt_ids[] = { 186 + { .compatible = "amlogic,meson-gxbb-mhu", }, 187 + { /* sentinel */ }, 188 + }; 189 + MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids); 190 + 191 + static struct platform_driver platform_mhu_driver = { 192 + .probe = platform_mhu_probe, 193 + .remove = platform_mhu_remove, 194 + .driver = { 195 + .name = "platform-mhu", 196 + .of_match_table = platform_mhu_dt_ids, 197 + }, 198 + }; 199 + 200 + module_platform_driver(platform_mhu_driver); 201 + 202 + MODULE_LICENSE("GPL v2"); 203 + MODULE_ALIAS("platform:platform-mhu"); 204 + MODULE_DESCRIPTION("Platform MHU Driver"); 205 + MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");