dm: Introduce xxx_get_dma_range()
Add the following functions to get a specific device's DMA ranges: - dev_get_dma_range() - ofnode_get_dma_range() - of_get_dma_range() - fdt_get_dma_range() They are specially useful in oder to be able validate a physical address space range into a bus's and to convert addresses from and to address spaces. Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Peter Robinson <pbrobinson@gmail.com> Signed-off-by: Matthias Brugger <mbrugger@suse.com>
This commit is contained in:
parent
c709243ee0
commit
51bdb50904
@ -1344,6 +1344,79 @@ u64 fdt_translate_dma_address(const void *blob, int node_offset,
|
||||
return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
|
||||
}
|
||||
|
||||
int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size)
|
||||
{
|
||||
bool found_dma_ranges = false;
|
||||
struct of_bus *bus_node;
|
||||
const fdt32_t *ranges;
|
||||
int na, ns, pna, pns;
|
||||
int parent = node;
|
||||
int ret = 0;
|
||||
int len;
|
||||
|
||||
/* Find the closest dma-ranges property */
|
||||
while (parent >= 0) {
|
||||
ranges = fdt_getprop(blob, parent, "dma-ranges", &len);
|
||||
|
||||
/* Ignore empty ranges, they imply no translation required */
|
||||
if (ranges && len > 0)
|
||||
break;
|
||||
|
||||
/* Once we find 'dma-ranges', then a missing one is an error */
|
||||
if (found_dma_ranges && !ranges) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ranges)
|
||||
found_dma_ranges = true;
|
||||
|
||||
parent = fdt_parent_offset(blob, parent);
|
||||
}
|
||||
|
||||
if (!ranges || parent < 0) {
|
||||
debug("no dma-ranges found for node %s\n",
|
||||
fdt_get_name(blob, node, NULL));
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* switch to that node */
|
||||
node = parent;
|
||||
parent = fdt_parent_offset(blob, node);
|
||||
if (parent < 0) {
|
||||
printf("Found dma-ranges in root node, shoudln't happen\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the address sizes both for the bus and its parent */
|
||||
bus_node = of_match_bus(blob, node);
|
||||
bus_node->count_cells(blob, node, &na, &ns);
|
||||
if (!OF_CHECK_COUNTS(na, ns)) {
|
||||
printf("%s: Bad cell count for %s\n", __FUNCTION__,
|
||||
fdt_get_name(blob, node, NULL));
|
||||
return -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bus_node = of_match_bus(blob, parent);
|
||||
bus_node->count_cells(blob, parent, &pna, &pns);
|
||||
if (!OF_CHECK_COUNTS(pna, pns)) {
|
||||
printf("%s: Bad cell count for %s\n", __FUNCTION__,
|
||||
fdt_get_name(blob, parent, NULL));
|
||||
return -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*bus = fdt_read_number(ranges, na);
|
||||
*cpu = fdt_translate_dma_address(blob, node, ranges + na);
|
||||
*size = fdt_read_number(ranges + na + pna, ns);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
|
||||
* who's reg property matches a physical cpu address
|
||||
|
@ -318,6 +318,84 @@ u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_add
|
||||
return __of_translate_address(dev, in_addr, "dma-ranges");
|
||||
}
|
||||
|
||||
int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size)
|
||||
{
|
||||
bool found_dma_ranges = false;
|
||||
struct device_node *parent;
|
||||
struct of_bus *bus_node;
|
||||
int na, ns, pna, pns;
|
||||
const __be32 *ranges;
|
||||
int ret = 0;
|
||||
int len;
|
||||
|
||||
/* Find the closest dma-ranges property */
|
||||
dev = of_node_get(dev);
|
||||
while (dev) {
|
||||
ranges = of_get_property(dev, "dma-ranges", &len);
|
||||
|
||||
/* Ignore empty ranges, they imply no translation required */
|
||||
if (ranges && len > 0)
|
||||
break;
|
||||
|
||||
/* Once we find 'dma-ranges', then a missing one is an error */
|
||||
if (found_dma_ranges && !ranges) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ranges)
|
||||
found_dma_ranges = true;
|
||||
|
||||
parent = of_get_parent(dev);
|
||||
of_node_put(dev);
|
||||
dev = parent;
|
||||
}
|
||||
|
||||
if (!dev || !ranges) {
|
||||
debug("no dma-ranges found for node %s\n",
|
||||
of_node_full_name(dev));
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* switch to that node */
|
||||
parent = of_get_parent(dev);
|
||||
if (!parent) {
|
||||
printf("Found dma-ranges in root node, shoudln't happen\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the address sizes both for the bus and its parent */
|
||||
bus_node = of_match_bus((struct device_node*)dev);
|
||||
bus_node->count_cells(dev, &na, &ns);
|
||||
if (!OF_CHECK_COUNTS(na, ns)) {
|
||||
printf("Bad cell count for %s\n", of_node_full_name(dev));
|
||||
return -EINVAL;
|
||||
goto out_parent;
|
||||
}
|
||||
|
||||
bus_node = of_match_bus(parent);
|
||||
bus_node->count_cells(parent, &pna, &pns);
|
||||
if (!OF_CHECK_COUNTS(pna, pns)) {
|
||||
printf("Bad cell count for %s\n", of_node_full_name(parent));
|
||||
return -EINVAL;
|
||||
goto out_parent;
|
||||
}
|
||||
|
||||
*bus = of_read_number(ranges, na);
|
||||
*cpu = of_translate_dma_address(dev, ranges + na);
|
||||
*size = of_read_number(ranges + na + pna, ns);
|
||||
|
||||
out_parent:
|
||||
of_node_put(parent);
|
||||
out:
|
||||
of_node_put(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int __of_address_to_resource(const struct device_node *dev,
|
||||
const __be32 *addrp, u64 size, unsigned int flags,
|
||||
const char *name, struct resource *r)
|
||||
|
@ -927,6 +927,15 @@ u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
|
||||
return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
|
||||
}
|
||||
|
||||
int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
|
||||
{
|
||||
if (ofnode_is_np(node))
|
||||
return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
|
||||
else
|
||||
return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
|
||||
cpu, bus, size);
|
||||
}
|
||||
|
||||
int ofnode_device_is_compatible(ofnode node, const char *compat)
|
||||
{
|
||||
if (ofnode_is_np(node))
|
||||
|
@ -341,6 +341,12 @@ u64 dev_translate_dma_address(const struct udevice *dev, const fdt32_t *in_addr)
|
||||
return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
|
||||
}
|
||||
|
||||
int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size)
|
||||
{
|
||||
return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
|
||||
}
|
||||
|
||||
int dev_read_alias_highest_id(const char *stem)
|
||||
{
|
||||
if (of_live_active())
|
||||
|
@ -44,6 +44,23 @@ u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
|
||||
*/
|
||||
u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
|
||||
|
||||
|
||||
/**
|
||||
* of_get_dma_range() - get dma-ranges for a specific DT node
|
||||
*
|
||||
* Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
|
||||
* cpu->bus address translations
|
||||
*
|
||||
* @param blob Pointer to device tree blob
|
||||
* @param node_offset Node DT offset
|
||||
* @param cpu Pointer to variable storing the range's cpu address
|
||||
* @param bus Pointer to variable storing the range's bus address
|
||||
* @param size Pointer to variable storing the range's size
|
||||
* @return translated DMA address or OF_BAD_ADDR on error
|
||||
*/
|
||||
int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size);
|
||||
|
||||
/**
|
||||
* of_get_address() - obtain an address from a node
|
||||
*
|
||||
|
@ -998,6 +998,22 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
|
||||
*/
|
||||
u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
|
||||
|
||||
/**
|
||||
* ofnode_get_dma_range() - get dma-ranges for a specific DT node
|
||||
*
|
||||
* Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
|
||||
* cpu->bus address translations
|
||||
*
|
||||
* @param blob Pointer to device tree blob
|
||||
* @param node_offset Node DT offset
|
||||
* @param cpu Pointer to variable storing the range's cpu address
|
||||
* @param bus Pointer to variable storing the range's bus address
|
||||
* @param size Pointer to variable storing the range's size
|
||||
* @return translated DMA address or OF_BAD_ADDR on error
|
||||
*/
|
||||
int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus,
|
||||
u64 *size);
|
||||
|
||||
/**
|
||||
* ofnode_device_is_compatible() - check if the node is compatible with compat
|
||||
*
|
||||
|
@ -647,6 +647,21 @@ u64 dev_translate_address(const struct udevice *dev, const fdt32_t *in_addr);
|
||||
u64 dev_translate_dma_address(const struct udevice *dev,
|
||||
const fdt32_t *in_addr);
|
||||
|
||||
/**
|
||||
* dev_get_dma_range() - Get a device's DMA constraints
|
||||
*
|
||||
* Provide the address bases and size of the linear mapping between the CPU and
|
||||
* a device's BUS address space.
|
||||
*
|
||||
* @dev: device giving the context in which to translate the DMA address
|
||||
* @cpu: base address for CPU's view of memory
|
||||
* @bus: base address for BUS's view of memory
|
||||
* @size: size of the address space
|
||||
* @return 0 if ok, negative on error
|
||||
*/
|
||||
int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size);
|
||||
|
||||
/**
|
||||
* dev_read_alias_highest_id - Get highest alias id for the given stem
|
||||
* @stem: Alias stem to be examined
|
||||
@ -1005,6 +1020,12 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev,
|
||||
return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
|
||||
}
|
||||
|
||||
static inline int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size)
|
||||
{
|
||||
return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
|
||||
}
|
||||
|
||||
static inline int dev_read_alias_highest_id(const char *stem)
|
||||
{
|
||||
if (!CONFIG_IS_ENABLED(OF_LIBFDT) || !gd->fdt_blob)
|
||||
|
@ -260,6 +260,20 @@ u64 fdt_translate_address(const void *blob, int node_offset,
|
||||
u64 fdt_translate_dma_address(const void *blob, int node_offset,
|
||||
const __be32 *in_addr);
|
||||
|
||||
/**
|
||||
* Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
|
||||
* cpu->bus address translations
|
||||
*
|
||||
* @param blob Pointer to device tree blob
|
||||
* @param node_offset Node DT offset
|
||||
* @param cpu Pointer to variable storing the range's cpu address
|
||||
* @param bus Pointer to variable storing the range's bus address
|
||||
* @param size Pointer to variable storing the range's size
|
||||
* @return translated DMA address or OF_BAD_ADDR on error
|
||||
*/
|
||||
int fdt_get_dma_range(const void *blob, int node_offset, phys_addr_t *cpu,
|
||||
dma_addr_t *bus, u64 *size);
|
||||
|
||||
int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
|
||||
phys_addr_t compat_off);
|
||||
int fdt_alloc_phandle(void *blob);
|
||||
|
Loading…
Reference in New Issue
Block a user