Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * Copyright (C) 2010,2015 Broadcom 4 : : * Copyright (C) 2013-2014 Lubomir Rintel 5 : : * Copyright (C) 2013 Craig McGeachie 6 : : * 7 : : * Parts of the driver are based on: 8 : : * - arch/arm/mach-bcm2708/vcio.c file written by Gray Girling that was 9 : : * obtained from branch "rpi-3.6.y" of git://github.com/raspberrypi/ 10 : : * linux.git 11 : : * - drivers/mailbox/bcm2835-ipc.c by Lubomir Rintel at 12 : : * https://github.com/hackerspace/rpi-linux/blob/lr-raspberry-pi/drivers/ 13 : : * mailbox/bcm2835-ipc.c 14 : : * - documentation available on the following web site: 15 : : * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface 16 : : */ 17 : : 18 : : #include <linux/device.h> 19 : : #include <linux/dma-mapping.h> 20 : : #include <linux/err.h> 21 : : #include <linux/interrupt.h> 22 : : #include <linux/irq.h> 23 : : #include <linux/kernel.h> 24 : : #include <linux/mailbox_controller.h> 25 : : #include <linux/module.h> 26 : : #include <linux/of_address.h> 27 : : #include <linux/of_irq.h> 28 : : #include <linux/platform_device.h> 29 : : #include <linux/spinlock.h> 30 : : 31 : : /* Mailboxes */ 32 : : #define ARM_0_MAIL0 0x00 33 : : #define ARM_0_MAIL1 0x20 34 : : 35 : : /* 36 : : * Mailbox registers. We basically only support mailbox 0 & 1. We 37 : : * deliver to the VC in mailbox 1, it delivers to us in mailbox 0. See 38 : : * BCM2835-ARM-Peripherals.pdf section 1.3 for an explanation about 39 : : * the placement of memory barriers. 40 : : */ 41 : : #define MAIL0_RD (ARM_0_MAIL0 + 0x00) 42 : : #define MAIL0_POL (ARM_0_MAIL0 + 0x10) 43 : : #define MAIL0_STA (ARM_0_MAIL0 + 0x18) 44 : : #define MAIL0_CNF (ARM_0_MAIL0 + 0x1C) 45 : : #define MAIL1_WRT (ARM_0_MAIL1 + 0x00) 46 : : #define MAIL1_STA (ARM_0_MAIL1 + 0x18) 47 : : 48 : : /* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */ 49 : : #ifndef ARM_MS_FULL 50 : : /* Status register: FIFO state. */ 51 : : #define ARM_MS_FULL BIT(31) 52 : : #define ARM_MS_EMPTY BIT(30) 53 : : 54 : : /* Configuration register: Enable interrupts. */ 55 : : #define ARM_MC_IHAVEDATAIRQEN BIT(0) 56 : : #endif 57 : : 58 : : struct bcm2835_mbox { 59 : : void __iomem *regs; 60 : : spinlock_t lock; 61 : : struct mbox_controller controller; 62 : : }; 63 : : 64 : : static struct bcm2835_mbox *bcm2835_link_mbox(struct mbox_chan *link) 65 : : { 66 : 3 : return container_of(link->mbox, struct bcm2835_mbox, controller); 67 : : } 68 : : 69 : 3 : static irqreturn_t bcm2835_mbox_irq(int irq, void *dev_id) 70 : : { 71 : : struct bcm2835_mbox *mbox = dev_id; 72 : : struct device *dev = mbox->controller.dev; 73 : 3 : struct mbox_chan *link = &mbox->controller.chans[0]; 74 : : 75 : 3 : while (!(readl(mbox->regs + MAIL0_STA) & ARM_MS_EMPTY)) { 76 : 3 : u32 msg = readl(mbox->regs + MAIL0_RD); 77 : : dev_dbg(dev, "Reply 0x%08X\n", msg); 78 : 3 : mbox_chan_received_data(link, &msg); 79 : : } 80 : 3 : return IRQ_HANDLED; 81 : : } 82 : : 83 : 3 : static int bcm2835_send_data(struct mbox_chan *link, void *data) 84 : : { 85 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link); 86 : 3 : u32 msg = *(u32 *)data; 87 : : 88 : : spin_lock(&mbox->lock); 89 : 3 : writel(msg, mbox->regs + MAIL1_WRT); 90 : : dev_dbg(mbox->controller.dev, "Request 0x%08X\n", msg); 91 : : spin_unlock(&mbox->lock); 92 : 3 : return 0; 93 : : } 94 : : 95 : 3 : static int bcm2835_startup(struct mbox_chan *link) 96 : : { 97 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link); 98 : : 99 : : /* Enable the interrupt on data reception */ 100 : 3 : writel(ARM_MC_IHAVEDATAIRQEN, mbox->regs + MAIL0_CNF); 101 : : 102 : 3 : return 0; 103 : : } 104 : : 105 : 0 : static void bcm2835_shutdown(struct mbox_chan *link) 106 : : { 107 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link); 108 : : 109 : 0 : writel(0, mbox->regs + MAIL0_CNF); 110 : 0 : } 111 : : 112 : 3 : static bool bcm2835_last_tx_done(struct mbox_chan *link) 113 : : { 114 : : struct bcm2835_mbox *mbox = bcm2835_link_mbox(link); 115 : : bool ret; 116 : : 117 : : spin_lock(&mbox->lock); 118 : 3 : ret = !(readl(mbox->regs + MAIL1_STA) & ARM_MS_FULL); 119 : : spin_unlock(&mbox->lock); 120 : 3 : return ret; 121 : : } 122 : : 123 : : static const struct mbox_chan_ops bcm2835_mbox_chan_ops = { 124 : : .send_data = bcm2835_send_data, 125 : : .startup = bcm2835_startup, 126 : : .shutdown = bcm2835_shutdown, 127 : : .last_tx_done = bcm2835_last_tx_done 128 : : }; 129 : : 130 : 3 : static struct mbox_chan *bcm2835_mbox_index_xlate(struct mbox_controller *mbox, 131 : : const struct of_phandle_args *sp) 132 : : { 133 : 3 : if (sp->args_count != 0) 134 : : return ERR_PTR(-EINVAL); 135 : : 136 : 3 : return &mbox->chans[0]; 137 : : } 138 : : 139 : 3 : static int bcm2835_mbox_probe(struct platform_device *pdev) 140 : : { 141 : 3 : struct device *dev = &pdev->dev; 142 : : int ret = 0; 143 : : struct resource *iomem; 144 : : struct bcm2835_mbox *mbox; 145 : : 146 : : mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); 147 : 3 : if (mbox == NULL) 148 : : return -ENOMEM; 149 : 3 : spin_lock_init(&mbox->lock); 150 : : 151 : 3 : ret = devm_request_irq(dev, platform_get_irq(pdev, 0), 152 : : bcm2835_mbox_irq, 0, dev_name(dev), mbox); 153 : 3 : if (ret) { 154 : 0 : dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n", 155 : : ret); 156 : 0 : return -ENODEV; 157 : : } 158 : : 159 : 3 : iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 160 : 3 : mbox->regs = devm_ioremap_resource(&pdev->dev, iomem); 161 : 3 : if (IS_ERR(mbox->regs)) { 162 : : ret = PTR_ERR(mbox->regs); 163 : 0 : dev_err(&pdev->dev, "Failed to remap mailbox regs: %d\n", ret); 164 : 0 : return ret; 165 : : } 166 : : 167 : 3 : mbox->controller.txdone_poll = true; 168 : 3 : mbox->controller.txpoll_period = 5; 169 : 3 : mbox->controller.ops = &bcm2835_mbox_chan_ops; 170 : 3 : mbox->controller.of_xlate = &bcm2835_mbox_index_xlate; 171 : 3 : mbox->controller.dev = dev; 172 : 3 : mbox->controller.num_chans = 1; 173 : 3 : mbox->controller.chans = devm_kzalloc(dev, 174 : : sizeof(*mbox->controller.chans), GFP_KERNEL); 175 : 3 : if (!mbox->controller.chans) 176 : : return -ENOMEM; 177 : : 178 : 3 : ret = devm_mbox_controller_register(dev, &mbox->controller); 179 : 3 : if (ret) 180 : : return ret; 181 : : 182 : : platform_set_drvdata(pdev, mbox); 183 : 3 : dev_info(dev, "mailbox enabled\n"); 184 : : 185 : 3 : return ret; 186 : : } 187 : : 188 : : static const struct of_device_id bcm2835_mbox_of_match[] = { 189 : : { .compatible = "brcm,bcm2835-mbox", }, 190 : : {}, 191 : : }; 192 : : MODULE_DEVICE_TABLE(of, bcm2835_mbox_of_match); 193 : : 194 : : static struct platform_driver bcm2835_mbox_driver = { 195 : : .driver = { 196 : : .name = "bcm2835-mbox", 197 : : .of_match_table = bcm2835_mbox_of_match, 198 : : }, 199 : : .probe = bcm2835_mbox_probe, 200 : : }; 201 : : 202 : 3 : static int __init bcm2835_mbox_init(void) 203 : : { 204 : 3 : return platform_driver_register(&bcm2835_mbox_driver); 205 : : } 206 : : arch_initcall(bcm2835_mbox_init); 207 : : 208 : 0 : static void __init bcm2835_mbox_exit(void) 209 : : { 210 : 0 : platform_driver_unregister(&bcm2835_mbox_driver); 211 : 0 : } 212 : : module_exit(bcm2835_mbox_exit); 213 : : 214 : : MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 215 : : MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); 216 : : MODULE_LICENSE("GPL v2");