mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
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:
committed by
Dom Cobley
parent
de10be0ae1
commit
3a4204cf96
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user