mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
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:
committed by
popcornmix
parent
73c2075dd4
commit
2dcd32b4d1
@@ -74,9 +74,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
mailbox: mailbox@7e00b800 {
|
mailbox: mailbox@7e00b800 {
|
||||||
compatible = "brcm,bcm2708-vcio";
|
compatible = "brcm,bcm2835-mbox";
|
||||||
reg = <0x7e00b880 0x40>;
|
reg = <0x7e00b880 0x40>;
|
||||||
interrupts = <0 1>;
|
interrupts = <0 1>;
|
||||||
|
#mbox-cells = <0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
watchdog: watchdog@7e100000 {
|
watchdog: watchdog@7e100000 {
|
||||||
@@ -205,6 +206,11 @@
|
|||||||
<1 9>;
|
<1 9>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
firmware: firmware {
|
||||||
|
compatible = "raspberrypi,bcm2835-firmware";
|
||||||
|
mboxes = <&mailbox>;
|
||||||
|
};
|
||||||
|
|
||||||
leds: leds {
|
leds: leds {
|
||||||
compatible = "gpio-leds";
|
compatible = "gpio-leds";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -560,6 +560,7 @@ CONFIG_GAMEPORT_NS558=m
|
|||||||
CONFIG_GAMEPORT_L4=m
|
CONFIG_GAMEPORT_L4=m
|
||||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||||
CONFIG_BCM_VC_CMA=y
|
CONFIG_BCM_VC_CMA=y
|
||||||
|
CONFIG_BCM_VCIO=y
|
||||||
CONFIG_BCM_VC_SM=y
|
CONFIG_BCM_VC_SM=y
|
||||||
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
|
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
|
||||||
# CONFIG_LEGACY_PTYS is not set
|
# CONFIG_LEGACY_PTYS is not set
|
||||||
@@ -1078,6 +1079,7 @@ CONFIG_FB_FLEX=m
|
|||||||
CONFIG_FB_TFT_FBTFT_DEVICE=m
|
CONFIG_FB_TFT_FBTFT_DEVICE=m
|
||||||
CONFIG_MAILBOX=y
|
CONFIG_MAILBOX=y
|
||||||
CONFIG_BCM2708_MBOX=y
|
CONFIG_BCM2708_MBOX=y
|
||||||
|
CONFIG_BCM2835_MBOX=y
|
||||||
# CONFIG_IOMMU_SUPPORT is not set
|
# CONFIG_IOMMU_SUPPORT is not set
|
||||||
CONFIG_EXTCON=m
|
CONFIG_EXTCON=m
|
||||||
CONFIG_EXTCON_ARIZONA=m
|
CONFIG_EXTCON_ARIZONA=m
|
||||||
@@ -1086,6 +1088,7 @@ CONFIG_IIO_BUFFER=y
|
|||||||
CONFIG_IIO_BUFFER_CB=y
|
CONFIG_IIO_BUFFER_CB=y
|
||||||
CONFIG_IIO_KFIFO_BUF=m
|
CONFIG_IIO_KFIFO_BUF=m
|
||||||
CONFIG_DHT11=m
|
CONFIG_DHT11=m
|
||||||
|
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||||
CONFIG_EXT4_FS=y
|
CONFIG_EXT4_FS=y
|
||||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||||
CONFIG_EXT4_FS_SECURITY=y
|
CONFIG_EXT4_FS_SECURITY=y
|
||||||
|
|||||||
@@ -553,6 +553,7 @@ CONFIG_GAMEPORT_NS558=m
|
|||||||
CONFIG_GAMEPORT_L4=m
|
CONFIG_GAMEPORT_L4=m
|
||||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||||
CONFIG_BCM_VC_CMA=y
|
CONFIG_BCM_VC_CMA=y
|
||||||
|
CONFIG_BCM_VCIO=y
|
||||||
CONFIG_BCM_VC_SM=y
|
CONFIG_BCM_VC_SM=y
|
||||||
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
|
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
|
||||||
# CONFIG_LEGACY_PTYS is not set
|
# CONFIG_LEGACY_PTYS is not set
|
||||||
@@ -1071,6 +1072,7 @@ CONFIG_FB_FLEX=m
|
|||||||
CONFIG_FB_TFT_FBTFT_DEVICE=m
|
CONFIG_FB_TFT_FBTFT_DEVICE=m
|
||||||
CONFIG_MAILBOX=y
|
CONFIG_MAILBOX=y
|
||||||
CONFIG_BCM2708_MBOX=y
|
CONFIG_BCM2708_MBOX=y
|
||||||
|
CONFIG_BCM2835_MBOX=y
|
||||||
# CONFIG_IOMMU_SUPPORT is not set
|
# CONFIG_IOMMU_SUPPORT is not set
|
||||||
CONFIG_EXTCON=m
|
CONFIG_EXTCON=m
|
||||||
CONFIG_EXTCON_ARIZONA=m
|
CONFIG_EXTCON_ARIZONA=m
|
||||||
@@ -1079,6 +1081,7 @@ CONFIG_IIO_BUFFER=y
|
|||||||
CONFIG_IIO_BUFFER_CB=y
|
CONFIG_IIO_BUFFER_CB=y
|
||||||
CONFIG_IIO_KFIFO_BUF=m
|
CONFIG_IIO_KFIFO_BUF=m
|
||||||
CONFIG_DHT11=m
|
CONFIG_DHT11=m
|
||||||
|
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||||
CONFIG_EXT4_FS=y
|
CONFIG_EXT4_FS=y
|
||||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||||
CONFIG_EXT4_FS_SECURITY=y
|
CONFIG_EXT4_FS_SECURITY=y
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ static struct resource bcm2708_vcio_resources[] = {
|
|||||||
static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
|
static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
|
||||||
|
|
||||||
static struct platform_device bcm2708_vcio_device = {
|
static struct platform_device bcm2708_vcio_device = {
|
||||||
.name = "bcm2708_vcio",
|
.name = "bcm2835-mbox",
|
||||||
.id = -1, /* only one VideoCore I/O area */
|
.id = -1, /* only one VideoCore I/O area */
|
||||||
.resource = bcm2708_vcio_resources,
|
.resource = bcm2708_vcio_resources,
|
||||||
.num_resources = ARRAY_SIZE(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[] = {
|
static struct resource bcm2708_vchiq_resources[] = {
|
||||||
{
|
{
|
||||||
.start = ARMCTRL_0_BELL_BASE,
|
.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_dmaengine_device);
|
||||||
bcm_register_device_dt(&bcm2708_vcio_device);
|
bcm_register_device_dt(&bcm2708_vcio_device);
|
||||||
|
bcm_register_device_dt(&bcm2708_rpifw_device);
|
||||||
bcm_register_device_dt(&bcm2708_vchiq_device);
|
bcm_register_device_dt(&bcm2708_vchiq_device);
|
||||||
#ifdef CONFIG_BCM2708_GPIO
|
#ifdef CONFIG_BCM2708_GPIO
|
||||||
bcm_register_device_dt(&bcm2708_gpio_device);
|
bcm_register_device_dt(&bcm2708_gpio_device);
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ static struct resource bcm2708_vcio_resources[] = {
|
|||||||
static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
|
static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
|
||||||
|
|
||||||
static struct platform_device bcm2708_vcio_device = {
|
static struct platform_device bcm2708_vcio_device = {
|
||||||
.name = "bcm2708_vcio",
|
.name = "bcm2835-mbox",
|
||||||
.id = -1, /* only one VideoCore I/O area */
|
.id = -1, /* only one VideoCore I/O area */
|
||||||
.resource = bcm2708_vcio_resources,
|
.resource = bcm2708_vcio_resources,
|
||||||
.num_resources = ARRAY_SIZE(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[] = {
|
static struct resource bcm2708_vchiq_resources[] = {
|
||||||
{
|
{
|
||||||
.start = ARMCTRL_0_BELL_BASE,
|
.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_dmaengine_device);
|
||||||
bcm_register_device_dt(&bcm2708_vcio_device);
|
bcm_register_device_dt(&bcm2708_vcio_device);
|
||||||
|
bcm_register_device_dt(&bcm2708_rpifw_device);
|
||||||
bcm_register_device_dt(&bcm2708_vchiq_device);
|
bcm_register_device_dt(&bcm2708_vchiq_device);
|
||||||
#ifdef CONFIG_BCM2708_GPIO
|
#ifdef CONFIG_BCM2708_GPIO
|
||||||
bcm_register_device_dt(&bcm2708_gpio_device);
|
bcm_register_device_dt(&bcm2708_gpio_device);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ if MAILBOX
|
|||||||
|
|
||||||
config BCM2708_MBOX
|
config BCM2708_MBOX
|
||||||
bool "Broadcom BCM2708 Mailbox (vcio)"
|
bool "Broadcom BCM2708 Mailbox (vcio)"
|
||||||
depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
|
depends on BCM2835_MBOX
|
||||||
help
|
help
|
||||||
Broadcom BCM2708 Mailbox (vcio)
|
Broadcom BCM2708 Mailbox (vcio)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* linux/arch/arm/mach-bcm2708/vcio.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 Broadcom
|
* Copyright (C) 2010 Broadcom
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -12,196 +10,39 @@
|
|||||||
* VideoCore processor
|
* VideoCore processor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/module.h>
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/ioctl.h>
|
|
||||||
#include <linux/platform_data/mailbox-bcm2708.h>
|
#include <linux/platform_data/mailbox-bcm2708.h>
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||||
|
|
||||||
#define DRIVER_NAME "bcm2708_vcio"
|
#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)
|
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 -ENODEV;
|
||||||
|
|
||||||
return dev_mbox_write(mbox_dev, chan, data28);
|
return rpi_firmware_transaction(fw, chan, data28);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bcm_mailbox_write);
|
EXPORT_SYMBOL_GPL(bcm_mailbox_write);
|
||||||
|
|
||||||
extern int bcm_mailbox_read(unsigned chan, uint32_t *data28)
|
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 -ENODEV;
|
||||||
|
|
||||||
return dev_mbox_read(mbox_dev, chan, data28);
|
*data28 = rpi_firmware_transaction_received(fw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bcm_mailbox_read);
|
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);
|
static DEFINE_MUTEX(mailbox_lock);
|
||||||
extern int bcm_mailbox_property(void *data, int size)
|
extern int bcm_mailbox_property(void *data, int size)
|
||||||
{
|
{
|
||||||
@@ -216,7 +57,7 @@ extern int bcm_mailbox_property(void *data, int size)
|
|||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (mem_kern) {
|
if (mem_kern) {
|
||||||
/* create the message */
|
/* create the message */
|
||||||
mbox_copy_from_user(mem_kern, data, size);
|
memcpy(mem_kern, data, size);
|
||||||
|
|
||||||
/* send the message */
|
/* send the message */
|
||||||
wmb();
|
wmb();
|
||||||
@@ -226,7 +67,7 @@ extern int bcm_mailbox_property(void *data, int size)
|
|||||||
if (s == 0) {
|
if (s == 0) {
|
||||||
/* copy the response */
|
/* copy the response */
|
||||||
rmb();
|
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);
|
dma_free_coherent(NULL, PAGE_ALIGN(size), mem_kern, mem_bus);
|
||||||
} else {
|
} else {
|
||||||
@@ -240,174 +81,6 @@ extern int bcm_mailbox_property(void *data, int size)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bcm_mailbox_property);
|
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_AUTHOR("Gray Girling");
|
||||||
MODULE_DESCRIPTION("ARM I/O to VideoCore processor");
|
MODULE_DESCRIPTION("ARM I/O to VideoCore processor");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
Reference in New Issue
Block a user