From 3349eaf79dd91c2e6f9b7aed0c155668e4f5a856 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 26 Jun 2015 14:37:19 +0200
Subject: [PATCH 117/121] BCM270x: Switch to firmware driver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

defconfig: enable BCM2835_MBOX, RASPBERRYPI_FIRMWARE and BCM_VCIO.
Add firmware node and change mailbox node in Device Tree.
Add/update platform file for firmware and mailbox.
Strip bcm2708-vcio of everything except the legacy API and hook it
up with the firmware driver.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 arch/arm/boot/dts/bcm2708_common.dtsi |   8 +-
 arch/arm/configs/bcm2709_defconfig    |   3 +
 arch/arm/configs/bcmrpi_defconfig     |   3 +
 arch/arm/mach-bcm2708/bcm2708.c       |  13 +-
 arch/arm/mach-bcm2709/bcm2709.c       |  13 +-
 drivers/mailbox/Kconfig               |   2 +-
 drivers/mailbox/bcm2708-vcio.c        | 353 ++--------------------------------
 7 files changed, 51 insertions(+), 344 deletions(-)

--- a/arch/arm/boot/dts/bcm2708_common.dtsi
+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
@@ -74,9 +74,10 @@
 		};
 
 		mailbox: mailbox@7e00b800 {
-			compatible = "brcm,bcm2708-vcio";
+			compatible = "brcm,bcm2835-mbox";
 			reg = <0x7e00b880 0x40>;
 			interrupts = <0 1>;
+			#mbox-cells = <0>;
 		};
 
 		watchdog: watchdog@7e100000 {
@@ -205,6 +206,11 @@
 				     <1 9>;
 		};
 
+		firmware: firmware {
+			compatible = "raspberrypi,bcm2835-firmware";
+			mboxes = <&mailbox>;
+		};
+
 		leds: leds {
 			compatible = "gpio-leds";
 		};
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -574,6 +574,7 @@ CONFIG_HW_RANDOM_BCM2708=m
 CONFIG_RAW_DRIVER=y
 CONFIG_BRCM_CHAR_DRIVERS=y
 CONFIG_BCM_VC_CMA=y
+CONFIG_BCM_VCIO=y
 CONFIG_BCM_VC_SM=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
@@ -1074,6 +1075,7 @@ CONFIG_FB_FLEX=m
 CONFIG_FB_TFT_FBTFT_DEVICE=m
 CONFIG_MAILBOX=y
 CONFIG_BCM2708_MBOX=y
+CONFIG_BCM2835_MBOX=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXTCON=m
 CONFIG_EXTCON_ARIZONA=m
@@ -1082,6 +1084,7 @@ CONFIG_IIO_BUFFER=y
 CONFIG_IIO_BUFFER_CB=y
 CONFIG_IIO_KFIFO_BUF=m
 CONFIG_DHT11=m
+CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -567,6 +567,7 @@ CONFIG_HW_RANDOM_BCM2708=m
 CONFIG_RAW_DRIVER=y
 CONFIG_BRCM_CHAR_DRIVERS=y
 CONFIG_BCM_VC_CMA=y
+CONFIG_BCM_VCIO=y
 CONFIG_BCM_VC_SM=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
@@ -1067,6 +1068,7 @@ CONFIG_FB_FLEX=m
 CONFIG_FB_TFT_FBTFT_DEVICE=m
 CONFIG_MAILBOX=y
 CONFIG_BCM2708_MBOX=y
+CONFIG_BCM2835_MBOX=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXTCON=m
 CONFIG_EXTCON_ARIZONA=m
@@ -1075,6 +1077,7 @@ CONFIG_IIO_BUFFER=y
 CONFIG_IIO_BUFFER_CB=y
 CONFIG_IIO_KFIFO_BUF=m
 CONFIG_DHT11=m
+CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -405,7 +405,7 @@ static struct resource bcm2708_vcio_reso
 static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
 
 static struct platform_device bcm2708_vcio_device = {
-	.name = "bcm2708_vcio",
+	.name = "bcm2835-mbox",
 	.id = -1,		/* only one VideoCore I/O area */
 	.resource = bcm2708_vcio_resources,
 	.num_resources = ARRAY_SIZE(bcm2708_vcio_resources),
@@ -415,6 +415,16 @@ static struct platform_device bcm2708_vc
 		},
 };
 
+static u64 rpifw_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
+
+static struct platform_device bcm2708_rpifw_device = {
+	.name = "raspberrypi-firmware",
+	.dev = {
+		.dma_mask = &rpifw_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
+	},
+};
+
 static struct resource bcm2708_vchiq_resources[] = {
 	{
 		.start = ARMCTRL_0_BELL_BASE,
@@ -871,6 +881,7 @@ void __init bcm2708_init(void)
 
 	bcm_register_device_dt(&bcm2708_dmaengine_device);
 	bcm_register_device_dt(&bcm2708_vcio_device);
+	bcm_register_device_dt(&bcm2708_rpifw_device);
 	bcm_register_device_dt(&bcm2708_vchiq_device);
 #ifdef CONFIG_BCM2708_GPIO
 	bcm_register_device_dt(&bcm2708_gpio_device);
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -426,7 +426,7 @@ static struct resource bcm2708_vcio_reso
 static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
 
 static struct platform_device bcm2708_vcio_device = {
-	.name = "bcm2708_vcio",
+	.name = "bcm2835-mbox",
 	.id = -1,		/* only one VideoCore I/O area */
 	.resource = bcm2708_vcio_resources,
 	.num_resources = ARRAY_SIZE(bcm2708_vcio_resources),
@@ -436,6 +436,16 @@ static struct platform_device bcm2708_vc
 		},
 };
 
+static u64 rpifw_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
+
+static struct platform_device bcm2708_rpifw_device = {
+	.name = "raspberrypi-firmware",
+	.dev = {
+		.dma_mask = &rpifw_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
+	},
+};
+
 static struct resource bcm2708_vchiq_resources[] = {
 	{
 		.start = ARMCTRL_0_BELL_BASE,
@@ -892,6 +902,7 @@ void __init bcm2709_init(void)
 
 	bcm_register_device_dt(&bcm2708_dmaengine_device);
 	bcm_register_device_dt(&bcm2708_vcio_device);
+	bcm_register_device_dt(&bcm2708_rpifw_device);
 	bcm_register_device_dt(&bcm2708_vchiq_device);
 #ifdef CONFIG_BCM2708_GPIO
 	bcm_register_device_dt(&bcm2708_gpio_device);
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -9,7 +9,7 @@ if MAILBOX
 
 config BCM2708_MBOX
 	bool "Broadcom BCM2708 Mailbox (vcio)"
-	depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
+	depends on BCM2835_MBOX
 	help
 	  Broadcom BCM2708 Mailbox (vcio)
 
--- a/drivers/mailbox/bcm2708-vcio.c
+++ b/drivers/mailbox/bcm2708-vcio.c
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/arm/mach-bcm2708/vcio.c
- *
  *  Copyright (C) 2010 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
@@ -12,195 +10,38 @@
  * VideoCore processor
  */
 
-#include <linux/device.h>
 #include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ioctl.h>
+#include <linux/module.h>
 #include <linux/platform_data/mailbox-bcm2708.h>
-#include <linux/platform_device.h>
 #include <linux/uaccess.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
 
 #define DRIVER_NAME "bcm2708_vcio"
-#define DEVICE_FILE_NAME "vcio"
-
-/* offsets from a mail box base address */
-#define MAIL0_RD	0x00	/* read - and next 4 words */
-#define MAIL0_POL	0x10	/* read without popping the fifo */
-#define MAIL0_SND	0x14	/* sender ID (bottom two bits) */
-#define MAIL0_STA	0x18	/* status */
-#define MAIL0_CNF	0x1C	/* configuration */
-#define MAIL1_WRT	0x20	/* write - and next 4 words */
-#define MAIL1_STA	0x38	/* status */
-
-/* On MACH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
-#ifndef ARM_MS_EMPTY
-#define ARM_MS_EMPTY   BIT(30)
-#define ARM_MS_FULL    BIT(31)
-
-#define ARM_MC_IHAVEDATAIRQEN  BIT(0)
-#endif
-
-#define MBOX_MSG(chan, data28)		(((data28) & ~0xf) | ((chan) & 0xf))
-#define MBOX_MSG_LSB(chan, data28)	(((data28) << 4) | ((chan) & 0xf))
-#define MBOX_CHAN(msg)			((msg) & 0xf)
-#define MBOX_DATA28(msg)		((msg) & ~0xf)
-#define MBOX_DATA28_LSB(msg)		(((uint32_t)msg) >> 4)
-
-#define MBOX_MAGIC 0xd0d0c0de
-
-#define MAJOR_NUM 100
-#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
-
-static struct class *vcio_class;
-
-struct vc_mailbox {
-	void __iomem *regs;
-	uint32_t msg[MBOX_CHAN_COUNT];
-	struct semaphore sema[MBOX_CHAN_COUNT];
-	uint32_t magic;
-};
-
-static void mbox_init(struct vc_mailbox *mbox_out)
-{
-	int i;
-
-	for (i = 0; i < MBOX_CHAN_COUNT; i++) {
-		mbox_out->msg[i] = 0;
-		sema_init(&mbox_out->sema[i], 0);
-	}
-
-	/* Enable the interrupt on data reception */
-	writel(ARM_MC_IHAVEDATAIRQEN, mbox_out->regs + MAIL0_CNF);
-
-	mbox_out->magic = MBOX_MAGIC;
-}
-
-static int mbox_write(struct vc_mailbox *mbox, unsigned chan, uint32_t data28)
-{
-	if (mbox->magic != MBOX_MAGIC)
-		return -EINVAL;
-
-	/* wait for the mailbox FIFO to have some space in it */
-	while (0 != (readl(mbox->regs + MAIL1_STA) & ARM_MS_FULL))
-		cpu_relax();
-
-	writel(MBOX_MSG(chan, data28), mbox->regs + MAIL1_WRT);
-
-	return 0;
-}
-
-static int mbox_read(struct vc_mailbox *mbox, unsigned chan, uint32_t *data28)
-{
-	if (mbox->magic != MBOX_MAGIC)
-		return -EINVAL;
-
-	down(&mbox->sema[chan]);
-	*data28 = MBOX_DATA28(mbox->msg[chan]);
-	mbox->msg[chan] = 0;
-
-	return 0;
-}
-
-static irqreturn_t mbox_irq_handler(int irq, void *dev_id)
-{
-	/* wait for the mailbox FIFO to have some data in it */
-	struct vc_mailbox *mbox = (struct vc_mailbox *)dev_id;
-	int status = readl(mbox->regs + MAIL0_STA);
-	int ret = IRQ_NONE;
-
-	while (!(status & ARM_MS_EMPTY)) {
-		uint32_t msg = readl(mbox->regs + MAIL0_RD);
-		int chan = MBOX_CHAN(msg);
-
-		if (chan < MBOX_CHAN_COUNT) {
-			if (mbox->msg[chan]) {
-				pr_err(DRIVER_NAME
-				       ": mbox chan %d overflow - drop %08x\n",
-				       chan, msg);
-			} else {
-				mbox->msg[chan] = (msg | 0xf);
-				up(&mbox->sema[chan]);
-			}
-		} else {
-			pr_err(DRIVER_NAME
-			       ": invalid channel selector (msg %08x)\n", msg);
-		}
-		ret = IRQ_HANDLED;
-		status = readl(mbox->regs + MAIL0_STA);
-	}
-	return ret;
-}
-
-/* Mailbox Methods */
-
-static struct device *mbox_dev;	/* we assume there's only one! */
-
-static int dev_mbox_write(struct device *dev, unsigned chan, uint32_t data28)
-{
-	struct vc_mailbox *mailbox = dev_get_drvdata(dev);
-	int rc;
-
-	device_lock(dev);
-	rc = mbox_write(mailbox, chan, data28);
-	device_unlock(dev);
-
-	return rc;
-}
-
-static int dev_mbox_read(struct device *dev, unsigned chan, uint32_t *data28)
-{
-	struct vc_mailbox *mailbox = dev_get_drvdata(dev);
-	int rc;
-
-	device_lock(dev);
-	rc = mbox_read(mailbox, chan, data28);
-	device_unlock(dev);
-
-	return rc;
-}
 
 extern int bcm_mailbox_write(unsigned chan, uint32_t data28)
 {
-	if (!mbox_dev)
+	struct rpi_firmware *fw = rpi_firmware_get(NULL);
+
+	if (!fw)
 		return -ENODEV;
 
-	return dev_mbox_write(mbox_dev, chan, data28);
+	return rpi_firmware_transaction(fw, chan, data28);
 }
 EXPORT_SYMBOL_GPL(bcm_mailbox_write);
 
 extern int bcm_mailbox_read(unsigned chan, uint32_t *data28)
 {
-	if (!mbox_dev)
-		return -ENODEV;
-
-	return dev_mbox_read(mbox_dev, chan, data28);
-}
-EXPORT_SYMBOL_GPL(bcm_mailbox_read);
-
-static int mbox_copy_from_user(void *dst, const void *src, int size)
-{
-	if ((uint32_t)src < TASK_SIZE)
-		return copy_from_user(dst, src, size);
-
-	memcpy(dst, src, size);
+	struct rpi_firmware *fw = rpi_firmware_get(NULL);
 
-	return 0;
-}
-
-static int mbox_copy_to_user(void *dst, const void *src, int size)
-{
-	if ((uint32_t)dst < TASK_SIZE)
-		return copy_to_user(dst, src, size);
+	if (!fw)
+		return -ENODEV;
 
-	memcpy(dst, src, size);
+	*data28 = rpi_firmware_transaction_received(fw);
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(bcm_mailbox_read);
 
 static DEFINE_MUTEX(mailbox_lock);
 extern int bcm_mailbox_property(void *data, int size)
@@ -216,7 +57,7 @@ extern int bcm_mailbox_property(void *da
 				      GFP_KERNEL);
 	if (mem_kern) {
 		/* create the message */
-		mbox_copy_from_user(mem_kern, data, size);
+		memcpy(mem_kern, data, size);
 
 		/* send the message */
 		wmb();
@@ -226,7 +67,7 @@ extern int bcm_mailbox_property(void *da
 		if (s == 0) {
 			/* copy the response */
 			rmb();
-			mbox_copy_to_user(data, mem_kern, size);
+			memcpy(data, mem_kern, size);
 		}
 		dma_free_coherent(NULL, PAGE_ALIGN(size), mem_kern, mem_bus);
 	} else {
@@ -240,174 +81,6 @@ extern int bcm_mailbox_property(void *da
 }
 EXPORT_SYMBOL_GPL(bcm_mailbox_property);
 
-/* Platform Device for Mailbox */
-
-/* This is called whenever a process attempts to open the device file */
-static int device_open(struct inode *inode, struct file *file)
-{
-	try_module_get(THIS_MODULE);
-
-	return 0;
-}
-
-static int device_release(struct inode *inode, struct file *file)
-{
-	module_put(THIS_MODULE);
-
-	return 0;
-}
-
-/*
- * This function is called whenever a process tries to do an ioctl on our
- * device file. We get two extra parameters (additional to the inode and file
- * structures, which all device functions get): the number of the ioctl called
- * and the parameter given to the ioctl function.
- *
- * If the ioctl is write or read/write (meaning output is returned to the
- * calling process), the ioctl call returns the output of this function.
- *
- */
-static long device_ioctl(struct file *file, unsigned int ioctl_num,
-			 unsigned long ioctl_param)
-{
-	unsigned size;
-
-	switch (ioctl_num) {
-	case IOCTL_MBOX_PROPERTY:
-		/*
-		 * Receive a pointer to a message (in user space) and set that
-		 * to be the device's message.  Get the parameter given to
-		 * ioctl by the process.
-		 */
-		mbox_copy_from_user(&size, (void *)ioctl_param, sizeof(size));
-		return bcm_mailbox_property((void *)ioctl_param, size);
-	default:
-		pr_err(DRIVER_NAME "unknown ioctl: %d\n", ioctl_num);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* Module Declarations */
-
-/*
- * This structure will hold the functions to be called
- * when a process does something to the device we
- * created. Since a pointer to this structure is kept in
- * the devices table, it can't be local to
- * init_module. NULL is for unimplemented functios.
- */
-const struct file_operations fops = {
-	.unlocked_ioctl = device_ioctl,
-	.open = device_open,
-	.release = device_release,	/* a.k.a. close */
-};
-
-static int bcm_vcio_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct device *vdev;
-	struct vc_mailbox *mailbox;
-	struct resource *res;
-	int irq, ret;
-
-	mailbox = devm_kzalloc(dev, sizeof(*mailbox), GFP_KERNEL);
-	if (!mailbox)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mailbox->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(mailbox->regs))
-		return PTR_ERR(mailbox->regs);
-
-	irq = platform_get_irq(pdev, 0);
-	ret = devm_request_irq(dev, irq, mbox_irq_handler,
-			       IRQF_IRQPOLL,
-			       dev_name(dev), mailbox);
-	if (ret) {
-		dev_err(dev, "Interrupt request failed %d\n", ret);
-		return ret;
-	}
-
-	ret = register_chrdev(MAJOR_NUM, DEVICE_FILE_NAME, &fops);
-	if (ret < 0) {
-		pr_err("Character device registration failed %d\n", ret);
-		return ret;
-	}
-
-	vcio_class = class_create(THIS_MODULE, DRIVER_NAME);
-	if (IS_ERR(vcio_class)) {
-		ret = PTR_ERR(vcio_class);
-		pr_err("Class creation failed %d\n", ret);
-		goto err_class;
-	}
-
-	vdev = device_create(vcio_class, NULL, MKDEV(MAJOR_NUM, 0), NULL,
-			     "vcio");
-	if (IS_ERR(vdev)) {
-		ret = PTR_ERR(vdev);
-		pr_err("Device creation failed %d\n", ret);
-		goto err_dev;
-	}
-
-	mbox_init(mailbox);
-	platform_set_drvdata(pdev, mailbox);
-	mbox_dev = dev;
-
-	dev_info(dev, "mailbox at %p\n", mailbox->regs);
-
-	return 0;
-
-err_dev:
-	class_destroy(vcio_class);
-err_class:
-	unregister_chrdev(MAJOR_NUM, DEVICE_FILE_NAME);
-
-	return ret;
-}
-
-static int bcm_vcio_remove(struct platform_device *pdev)
-{
-	mbox_dev = NULL;
-	platform_set_drvdata(pdev, NULL);
-	device_destroy(vcio_class, MKDEV(MAJOR_NUM, 0));
-	class_destroy(vcio_class);
-	unregister_chrdev(MAJOR_NUM, DEVICE_FILE_NAME);
-
-	return 0;
-}
-
-static const struct of_device_id bcm_vcio_of_match_table[] = {
-	{ .compatible = "brcm,bcm2708-vcio", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, bcm_vcio_of_match_table);
-
-static struct platform_driver bcm_mbox_driver = {
-	.probe = bcm_vcio_probe,
-	.remove = bcm_vcio_remove,
-
-	.driver = {
-		   .name = DRIVER_NAME,
-		   .owner = THIS_MODULE,
-		   .of_match_table = bcm_vcio_of_match_table,
-		   },
-};
-
-static int __init bcm_mbox_init(void)
-{
-	return platform_driver_register(&bcm_mbox_driver);
-}
-
-static void __exit bcm_mbox_exit(void)
-{
-	platform_driver_unregister(&bcm_mbox_driver);
-}
-
-arch_initcall(bcm_mbox_init);	/* Initialize early */
-module_exit(bcm_mbox_exit);
-
 MODULE_AUTHOR("Gray Girling");
 MODULE_DESCRIPTION("ARM I/O to VideoCore processor");
 MODULE_LICENSE("GPL");