BCM270x: Switch to firmware driver

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>
This commit is contained in:
Noralf Trønnes
2015-06-26 14:37:19 +02:00
committed by popcornmix
parent 73c2075dd4
commit 2dcd32b4d1
7 changed files with 52 additions and 345 deletions

View File

@@ -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";
};

View File

@@ -560,6 +560,7 @@ CONFIG_GAMEPORT_NS558=m
CONFIG_GAMEPORT_L4=m
CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_BCM_VC_CMA=y
CONFIG_BCM_VCIO=y
CONFIG_BCM_VC_SM=y
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
# CONFIG_LEGACY_PTYS is not set
@@ -1078,6 +1079,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
@@ -1086,6 +1088,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

View File

@@ -553,6 +553,7 @@ CONFIG_GAMEPORT_NS558=m
CONFIG_GAMEPORT_L4=m
CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_BCM_VC_CMA=y
CONFIG_BCM_VCIO=y
CONFIG_BCM_VC_SM=y
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
# CONFIG_LEGACY_PTYS is not set
@@ -1071,6 +1072,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
@@ -1079,6 +1081,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

View File

@@ -405,7 +405,7 @@ static struct resource bcm2708_vcio_resources[] = {
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_vcio_device = {
},
};
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,
@@ -870,6 +880,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);

View File

@@ -426,7 +426,7 @@ static struct resource bcm2708_vcio_resources[] = {
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_vcio_device = {
},
};
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);

View File

@@ -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)

View File

@@ -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,196 +10,39 @@
* 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)
struct rpi_firmware *fw = rpi_firmware_get(NULL);
if (!fw)
return -ENODEV;
return dev_mbox_read(mbox_dev, chan, data28);
*data28 = rpi_firmware_transaction_received(fw);
return 0;
}
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);
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);
memcpy(dst, src, size);
return 0;
}
static DEFINE_MUTEX(mailbox_lock);
extern int bcm_mailbox_property(void *data, int size)
{
@@ -216,7 +57,7 @@ extern int bcm_mailbox_property(void *data, int size)
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 *data, int size)
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 *data, int size)
}
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");