Skip to content

Commit

Permalink
Merge pull request #973 from notro/vchiq
Browse files Browse the repository at this point in the history
Enable vchiq on ARCH_BCM2835
  • Loading branch information
pelwell committed May 19, 2015
2 parents 1dd8cb4 + 346c1e2 commit e72ad4b
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 98 deletions.
6 changes: 6 additions & 0 deletions arch/arm/boot/dts/bcm2708_common.dtsi
Expand Up @@ -114,6 +114,12 @@
compatible = "brcm,bcm2708-fb";
status = "disabled";
};

vchiq: vchiq {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0xf>;
interrupts = <0 2>;
};
};

clocks {
Expand Down
6 changes: 6 additions & 0 deletions arch/arm/boot/dts/bcm2835.dtsi
Expand Up @@ -164,6 +164,12 @@
compatible = "brcm,bcm2708-fb";
status = "disabled";
};

vchiq: vchiq {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0xf>;
interrupts = <0 2>;
};
};

clocks {
Expand Down
26 changes: 26 additions & 0 deletions arch/arm/mach-bcm2708/bcm2708.c
Expand Up @@ -437,6 +437,31 @@ static struct platform_device bcm2708_vcio_device = {
},
};

static struct resource bcm2708_vchiq_resources[] = {
{
.start = ARMCTRL_0_BELL_BASE,
.end = ARMCTRL_0_BELL_BASE + 16,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_ARM_DOORBELL_0,
.end = IRQ_ARM_DOORBELL_0,
.flags = IORESOURCE_IRQ,
},
};

static u64 vchiq_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);

static struct platform_device bcm2708_vchiq_device = {
.name = "bcm2835_vchiq",
.id = -1,
.resource = bcm2708_vchiq_resources,
.num_resources = ARRAY_SIZE(bcm2708_vchiq_resources),
.dev = {
.dma_mask = &vchiq_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
},
};

#ifdef CONFIG_BCM2708_GPIO
#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"

Expand Down Expand Up @@ -909,6 +934,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_vchiq_device);
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
#endif
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-bcm2708/include/mach/platform.h
Expand Up @@ -81,6 +81,7 @@
#define ARMCTRL_IC_BASE (ARM_BASE + 0x200) /* ARM interrupt controller */
#define ARMCTRL_TIMER0_1_BASE (ARM_BASE + 0x400) /* Timer 0 and 1 */
#define ARMCTRL_0_SBM_BASE (ARM_BASE + 0x800) /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
#define ARMCTRL_0_BELL_BASE (ARMCTRL_0_SBM_BASE + 0x40) /* User 0 (ARM)'s Doorbell */
#define ARMCTRL_0_MAIL0_BASE (ARMCTRL_0_SBM_BASE + 0x80) /* User 0 (ARM)'s Mailbox 0 */


Expand Down
26 changes: 26 additions & 0 deletions arch/arm/mach-bcm2709/bcm2709.c
Expand Up @@ -456,6 +456,31 @@ static struct platform_device bcm2708_vcio_device = {
},
};

static struct resource bcm2708_vchiq_resources[] = {
{
.start = ARMCTRL_0_BELL_BASE,
.end = ARMCTRL_0_BELL_BASE + 16,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_ARM_DOORBELL_0,
.end = IRQ_ARM_DOORBELL_0,
.flags = IORESOURCE_IRQ,
},
};

static u64 vchiq_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);

static struct platform_device bcm2708_vchiq_device = {
.name = "bcm2835_vchiq",
.id = -1,
.resource = bcm2708_vchiq_resources,
.num_resources = ARRAY_SIZE(bcm2708_vchiq_resources),
.dev = {
.dma_mask = &vchiq_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
},
};

#ifdef CONFIG_BCM2708_GPIO
#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"

Expand Down Expand Up @@ -930,6 +955,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_vchiq_device);
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
#endif
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-bcm2709/include/mach/platform.h
Expand Up @@ -81,6 +81,7 @@
#define ARMCTRL_IC_BASE (ARM_BASE + 0x200) /* ARM interrupt controller */
#define ARMCTRL_TIMER0_1_BASE (ARM_BASE + 0x400) /* Timer 0 and 1 */
#define ARMCTRL_0_SBM_BASE (ARM_BASE + 0x800) /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
#define ARMCTRL_0_BELL_BASE (ARMCTRL_0_SBM_BASE + 0x40) /* User 0 (ARM)'s Doorbell */
#define ARMCTRL_0_MAIL0_BASE (ARMCTRL_0_SBM_BASE + 0x80) /* User 0 (ARM)'s Mailbox 0 */


Expand Down
2 changes: 1 addition & 1 deletion drivers/misc/vc04_services/Kconfig
@@ -1,6 +1,6 @@
config BCM2708_VCHIQ
tristate "Videocore VCHIQ"
depends on MACH_BCM2708 || MACH_BCM2709
depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
default y
help
Kernel to VideoCore communication interface for the
Expand Down
124 changes: 53 additions & 71 deletions drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
Expand Up @@ -35,22 +35,17 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
#include <linux/version.h>
#include <linux/io.h>
#include <linux/platform_data/mailbox-bcm2708.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/pgtable.h>

#include <mach/irqs.h>

#include <mach/platform.h>

#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)

#define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
#define VCHIQ_ARM_ADDRESS(x) ((void *)__virt_to_bus((unsigned)x))

#include "vchiq_arm.h"
Expand All @@ -60,14 +55,15 @@

#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)

#define BELL0 0x00
#define BELL2 0x08

typedef struct vchiq_2835_state_struct {
int inited;
VCHIQ_ARM_STATE_T arm_state;
} VCHIQ_2835_ARM_STATE_T;

static char *g_slot_mem;
static int g_slot_mem_size;
dma_addr_t g_slot_phys;
static void __iomem *g_regs;
static FRAGMENTS_T *g_fragments_base;
static FRAGMENTS_T *g_free_fragments;
struct semaphore g_free_fragments_sema;
Expand All @@ -86,43 +82,40 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
static void
free_pagelist(PAGELIST_T *pagelist, int actual);

int __init
vchiq_platform_init(VCHIQ_STATE_T *state)
int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
{
struct device *dev = &pdev->dev;
VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
int frag_mem_size;
int err;
int i;
struct resource *res;
void *slot_mem;
dma_addr_t slot_phys;
int slot_mem_size, frag_mem_size;
int err, irq, i;

/* Allocate space for the channels in coherent memory */
g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS);

g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size,
&g_slot_phys, GFP_KERNEL);

if (!g_slot_mem) {
vchiq_log_error(vchiq_arm_log_level,
"Unable to allocate channel memory");
err = -ENOMEM;
goto failed_alloc;
slot_mem = dmam_alloc_coherent(dev, slot_mem_size + frag_mem_size,
&slot_phys, GFP_KERNEL);
if (!slot_mem) {
dev_err(dev, "could not allocate DMA memory\n");
return -ENOMEM;
}

WARN_ON(((int)g_slot_mem & (PAGE_SIZE - 1)) != 0);
WARN_ON(((int)slot_mem & (PAGE_SIZE - 1)) != 0);

vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
if (!vchiq_slot_zero) {
err = -EINVAL;
goto failed_init_slots;
}
vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
if (!vchiq_slot_zero)
return -EINVAL;

vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
(int)g_slot_phys + g_slot_mem_size;
(int)slot_phys + slot_mem_size;
vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
MAX_FRAGMENTS;

g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size);
g_slot_mem_size += frag_mem_size;
g_fragments_base = (FRAGMENTS_T *)(slot_mem + slot_mem_size);
slot_mem_size += frag_mem_size;

g_free_fragments = g_fragments_base;
for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
Expand All @@ -132,54 +125,46 @@ vchiq_platform_init(VCHIQ_STATE_T *state)
*(FRAGMENTS_T **)&g_fragments_base[i] = NULL;
sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);

if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
VCHIQ_SUCCESS) {
err = -EINVAL;
goto failed_vchiq_init;
if (vchiq_init_state(state, vchiq_slot_zero, 0) != VCHIQ_SUCCESS)
return -EINVAL;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
g_regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(g_regs))
return PTR_ERR(g_regs);

irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "failed to get IRQ\n");
return irq;
}

err = request_irq(VCHIQ_DOORBELL_IRQ, vchiq_doorbell_irq,
IRQF_IRQPOLL, "VCHIQ doorbell",
state);
if (err < 0) {
vchiq_log_error(vchiq_arm_log_level, "%s: failed to register "
"irq=%d err=%d", __func__,
VCHIQ_DOORBELL_IRQ, err);
goto failed_request_irq;
err = devm_request_irq(dev, irq, vchiq_doorbell_irq, IRQF_IRQPOLL,
"VCHIQ doorbell", state);
if (err) {
dev_err(dev, "failed to register irq=%d\n", irq);
return err;
}

/* Send the base address of the slots to VideoCore */

dsb(); /* Ensure all writes have completed */

bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys);
err = bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)slot_phys);
if (err) {
dev_err(dev, "mailbox write failed\n");
return err;
}

vchiq_log_info(vchiq_arm_log_level,
"vchiq_init - done (slots %x, phys %x)",
(unsigned int)vchiq_slot_zero, g_slot_phys);
"vchiq_init - done (slots %x, phys %pad)",
(unsigned int)vchiq_slot_zero, &slot_phys);

vchiq_call_connected_callbacks();
vchiq_call_connected_callbacks();

return 0;

failed_request_irq:
failed_vchiq_init:
failed_init_slots:
dma_free_coherent(NULL, g_slot_mem_size, g_slot_mem, g_slot_phys);

failed_alloc:
return err;
}

void __exit
vchiq_platform_exit(VCHIQ_STATE_T *state)
{
free_irq(VCHIQ_DOORBELL_IRQ, state);
dma_free_coherent(NULL, g_slot_mem_size,
g_slot_mem, g_slot_phys);
}


VCHIQ_STATUS_T
vchiq_platform_init_state(VCHIQ_STATE_T *state)
{
Expand Down Expand Up @@ -213,11 +198,8 @@ remote_event_signal(REMOTE_EVENT_T *event)

dsb(); /* data barrier operation */

if (event->armed) {
/* trigger vc interrupt */

writel(0, __io_address(ARM_0_BELL2));
}
if (event->armed)
writel(0, g_regs + BELL2); /* trigger vc interrupt */
}

int
Expand Down Expand Up @@ -341,7 +323,7 @@ vchiq_doorbell_irq(int irq, void *dev_id)
unsigned int status;

/* Read (and clear) the doorbell */
status = readl(__io_address(ARM_0_BELL0));
status = readl(g_regs + BELL0);

if (status & 0x4) { /* Was the doorbell rung? */
remote_event_pollall(state);
Expand Down

0 comments on commit e72ad4b

Please sign in to comment.