staging: vchiq_arm: Set up dma ranges on child devices

The VCHIQ driver now loads the audio, camera, codec, and vc-sm
drivers as platform drivers. However they were not being given
the correct DMA configuration.

Call of_dma_configure with the parent (VCHIQ) parameters to be
inherited by the child.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>

staging: vchiq: Use the old dma controller for OF config on platform devices

vchiq on Pi4 is no longer under the soc node, therefore it
doesn't get the dma-ranges for the VPU.

Switch to using the configuration of the old dma controller as
that will set the dma-ranges correctly.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>

staging: vchiq_arm: Give vchiq children DT nodes

vchiq kernel clients are now instantiated as platform drivers rather
than using DT, but the children of the vchiq interface may still
benefit from access to DT properties. Give them the option of a
a sub-node of the vchiq parent for configuration and to allow
them to be disabled.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>

staging: vchiq_arm: Add 36-bit address support

Conditional on a new compatible string, change the pagelist encoding
such that the top 24 bits are the pfn, leaving 8 bits for run length
(-1), giving a 36-bit address range.

Manage the split between addresses for the VPU and addresses for the
40-bit DMA controller with a dedicated DMA device pointer that on non-
BCM2711 platforms is the same as the main VCHIQ device. This allows
the VCHIQ node to stay in the usual place in the DT.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>

staging: vchiq_arm: children inherit DMA config

Although it is no longer necessary for vchiq's children to have a
different DMA configuration to the parent, they do still need to
explicitly to have their DMA configuration set - to be that of the
parent.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
This commit is contained in:
Dave Stevenson
2019-01-29 16:13:25 +00:00
committed by Dom Cobley
parent de10be0ae1
commit 3a4204cf96
4 changed files with 90 additions and 18 deletions

View File

@@ -19,6 +19,7 @@
#include <linux/completion.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/compat.h>
#include <linux/dma-mapping.h>
@@ -74,6 +75,11 @@ static const struct vchiq_platform_info bcm2836_info = {
.cache_line_size = 64,
};
static const struct vchiq_platform_info bcm2711_info = {
.cache_line_size = 64,
.use_36bit_addrs = true,
};
struct vchiq_arm_state {
/* Keepalive-related data */
struct task_struct *ka_thread;
@@ -186,6 +192,7 @@ EXPORT_SYMBOL(vchiq_add_connected_callback);
static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
{
struct device *dev = &pdev->dev;
struct device *dma_dev = NULL;
struct vchiq_drv_mgmt *drv_mgmt = platform_get_drvdata(pdev);
struct rpi_firmware *fw = drv_mgmt->fw;
struct vchiq_slot_zero *vchiq_slot_zero;
@@ -206,6 +213,24 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
drv_mgmt->fragments_size = 2 * drv_mgmt->info->cache_line_size;
if (drv_mgmt->info->use_36bit_addrs) {
struct device_node *dma_node =
of_find_compatible_node(NULL, NULL, "brcm,bcm2711-dma");
if (dma_node) {
struct platform_device *pdev;
pdev = of_find_device_by_node(dma_node);
if (pdev)
dma_dev = &pdev->dev;
of_node_put(dma_node);
g_use_36bit_addrs = true;
} else {
dev_err(dev, "40-bit DMA controller not found\n");
return -EINVAL;
}
}
/* Allocate space for the channels in coherent memory */
slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
frag_mem_size = PAGE_ALIGN(drv_mgmt->fragments_size * MAX_FRAGMENTS);
@@ -273,6 +298,8 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
return -ENXIO;
}
g_dma_dev = dma_dev ?: dev;
dev_dbg(&pdev->dev, "arm: vchiq_init - done (slots %p, phys %pad)\n",
vchiq_slot_zero, &slot_phys);
@@ -1363,6 +1390,7 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state,
static const struct of_device_id vchiq_of_match[] = {
{ .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_info },
{ .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_info },
{ .compatible = "brcm,bcm2711-vchiq", .data = &bcm2711_info },
{},
};
MODULE_DEVICE_TABLE(of, vchiq_of_match);

View File

@@ -32,6 +32,7 @@ enum USE_TYPE_E {
struct vchiq_platform_info {
unsigned int cache_line_size;
bool use_36bit_addrs;
};
struct vchiq_drv_mgmt {

View File

@@ -192,6 +192,9 @@ static const char *const conn_state_names[] = {
"RESUME_TIMEOUT"
};
unsigned int g_use_36bit_addrs = 0;
struct device *g_dma_dev;
static void
release_message_sync(struct vchiq_state *state, struct vchiq_header *header);
@@ -1459,14 +1462,14 @@ static void
cleanup_pagelistinfo(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo)
{
if (pagelistinfo->scatterlist_mapped) {
dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist,
dma_unmap_sg(g_dma_dev, pagelistinfo->scatterlist,
pagelistinfo->num_pages, pagelistinfo->dma_dir);
}
if (pagelistinfo->pages_need_release)
unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages);
dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size,
dma_free_coherent(g_dma_dev, pagelistinfo->pagelist_buffer_size,
pagelistinfo->pagelist, pagelistinfo->dma_addr);
}
@@ -1638,22 +1641,58 @@ create_pagelist(struct vchiq_instance *instance, struct vchiq_bulk *bulk)
/* Combine adjacent blocks for performance */
k = 0;
for_each_sg(scatterlist, sg, dma_buffers, i) {
unsigned int len = sg_dma_len(sg);
dma_addr_t addr = sg_dma_address(sg);
if (g_use_36bit_addrs) {
for_each_sg(scatterlist, sg, dma_buffers, i) {
unsigned int len = sg_dma_len(sg);
dma_addr_t addr = sg_dma_address(sg);
u32 page_id = (u32)((addr >> 4) & ~0xff);
u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
/* Note: addrs is the address + page_count - 1
* The firmware expects blocks after the first to be page-
* aligned and a multiple of the page size
*/
WARN_ON(len == 0);
WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
WARN_ON(i && (addr & ~PAGE_MASK));
if (is_adjacent_block(addrs, addr, k))
addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
else
addrs[k++] = (addr & PAGE_MASK) |
(((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1);
/* Note: addrs is the address + page_count - 1
* The firmware expects blocks after the first to be page-
* aligned and a multiple of the page size
*/
WARN_ON(len == 0);
WARN_ON(i &&
(i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
WARN_ON(i && (addr & ~PAGE_MASK));
WARN_ON(upper_32_bits(addr) > 0xf);
if (k > 0 &&
((addrs[k - 1] & ~0xff) +
(((addrs[k - 1] & 0xff) + 1) << 8)
== page_id)) {
u32 inc_pages = min(sg_pages,
0xff - (addrs[k - 1] & 0xff));
addrs[k - 1] += inc_pages;
page_id += inc_pages << 8;
sg_pages -= inc_pages;
}
while (sg_pages) {
u32 inc_pages = min(sg_pages, 0x100u);
addrs[k++] = page_id | (inc_pages - 1);
page_id += inc_pages << 8;
sg_pages -= inc_pages;
}
}
} else {
for_each_sg(scatterlist, sg, dma_buffers, i) {
unsigned int len = sg_dma_len(sg);
dma_addr_t addr = sg_dma_address(sg);
/* Note: addrs is the address + page_count - 1
* The firmware expects blocks after the first to be page-
* aligned and a multiple of the page size
*/
WARN_ON(len == 0);
WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
WARN_ON(i && (addr & ~PAGE_MASK));
if (is_adjacent_block(addrs, addr, k))
addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
else
addrs[k++] = (addr & PAGE_MASK) |
(((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1);
}
}
/* Partial cache lines (fragments) require special measures */
@@ -1700,7 +1739,7 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel
* NOTE: dma_unmap_sg must be called before the
* cpu can touch any of the data/pages.
*/
dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist,
dma_unmap_sg(g_dma_dev, pagelistinfo->scatterlist,
pagelistinfo->num_pages, pagelistinfo->dma_dir);
pagelistinfo->scatterlist_mapped = 0;

View File

@@ -436,6 +436,10 @@ struct vchiq_pagelist_info {
unsigned int scatterlist_mapped;
};
extern unsigned int g_use_36bit_addrs;
extern struct device *g_dma_dev;
static inline bool vchiq_remote_initialised(const struct vchiq_state *state)
{
return state->remote && state->remote->initialised;