summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2017-10-20 00:43:31 +0200
committerArnd Bergmann <arnd@arndb.de>2017-10-20 00:43:31 +0200
commitab63d1efc5674c09e1c24a8bc9301daa172f5050 (patch)
tree0c2d8fc0239249c341c40d7c6aca7b71dbac081a /arch/arm/mach-omap2/omap_hwmod.c
parente4191c53ae4627fe5bf32fd77abaa527f49b628b (diff)
parent684be5a48f4950cb8823b4c4b935515a75615498 (diff)
Merge tag 'omap-for-v4.15/ti-sysc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc
Pull "more soc changes for omaps for v4.15 merge window" from Tony Lindgren: Drop omap legacy platform data for IRQ, DMA and IO resources. With the dts files fixed up to contain the necessary data for basic resources, we can drop the related platform data. Note that this branch depends on the "omap-for-v4.15/fixes-dt-signed" branch and the patches with dependencies are based on a merge with that branch. These patches first ensure things keep working for the legacy "ti,hwmods" property when we start making it optional, then adds a minimal TI sysc interconnect target device driver to handle the new generic "ti,sysc" compatible property. And then we can finally drop the legacy platform data for IRQ, DMA and IO resources as seen in the diffstats. * tag 'omap-for-v4.15/ti-sysc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (25 commits) bus: ti-sysc: Fix unbalanced pm_runtime_enable by adding remove bus: ti-sysc: mark PM functions as __maybe_unused ARM: OMAP2+: omap_device: fix error return code in omap_device_copy_resources() ARM: OMAP2+: Drop legacy struct omap_hwmod_addr_space ARM: OMAP2+: Drop omap_hwmod_dma_info ARM: OMAP2+: Drop omap_hwmod_irq_info ARM: OMAP4: Remove legacy IRQ for PRM ARM: OMAP3: Remove legacy IRQ for PRM bus: ti-sysc: Add minimal TI sysc interconnect target driver ARM: OMAP2+: Populate legacy resources for dma and smartreflex ARM: OMAP2+: Parse module IO range from dts for legacy "ti,hwmods" support ARM: dts: Configure SmartReflex only to idle the interconnect target module ARM: dts: Add nodes for missing omap4 interconnect target modules dt-bindings: bus: Minimal TI sysc interconnect target module binding ARM: dts: Add missing hwmod related properties for dra7 ARM: dts: Add missing hwmod related nodes for am33xx ARM: dts: Add missing dma hwmod property for omap5 ARM: dts: Add missing wdt3 node for omap4 ARM: dts: Add missing hsi node for omap4 ARM: dts: Add missing onewire node for omap4 ...
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c520
1 files changed, 83 insertions, 437 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index d50101d44795..104256a5f0f7 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1102,215 +1102,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
}
/**
- * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
- * @oh: struct omap_hwmod *oh
- *
- * Count and return the number of MPU IRQs associated with the hwmod
- * @oh. Used to allocate struct resource data. Returns 0 if @oh is
- * NULL.
- */
-static int _count_mpu_irqs(struct omap_hwmod *oh)
-{
- struct omap_hwmod_irq_info *ohii;
- int i = 0;
-
- if (!oh || !oh->mpu_irqs)
- return 0;
-
- do {
- ohii = &oh->mpu_irqs[i++];
- } while (ohii->irq != -1);
-
- return i-1;
-}
-
-/**
- * _count_sdma_reqs - count the number of SDMA request lines associated with @oh
- * @oh: struct omap_hwmod *oh
- *
- * Count and return the number of SDMA request lines associated with
- * the hwmod @oh. Used to allocate struct resource data. Returns 0
- * if @oh is NULL.
- */
-static int _count_sdma_reqs(struct omap_hwmod *oh)
-{
- struct omap_hwmod_dma_info *ohdi;
- int i = 0;
-
- if (!oh || !oh->sdma_reqs)
- return 0;
-
- do {
- ohdi = &oh->sdma_reqs[i++];
- } while (ohdi->dma_req != -1);
-
- return i-1;
-}
-
-/**
- * _count_ocp_if_addr_spaces - count the number of address space entries for @oh
- * @oh: struct omap_hwmod *oh
- *
- * Count and return the number of address space ranges associated with
- * the hwmod @oh. Used to allocate struct resource data. Returns 0
- * if @oh is NULL.
- */
-static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os)
-{
- struct omap_hwmod_addr_space *mem;
- int i = 0;
-
- if (!os || !os->addr)
- return 0;
-
- do {
- mem = &os->addr[i++];
- } while (mem->pa_start != mem->pa_end);
-
- return i-1;
-}
-
-/**
- * _get_mpu_irq_by_name - fetch MPU interrupt line number by name
- * @oh: struct omap_hwmod * to operate on
- * @name: pointer to the name of the MPU interrupt number to fetch (optional)
- * @irq: pointer to an unsigned int to store the MPU IRQ number to
- *
- * Retrieve a MPU hardware IRQ line number named by @name associated
- * with the IP block pointed to by @oh. The IRQ number will be filled
- * into the address pointed to by @dma. When @name is non-null, the
- * IRQ line number associated with the named entry will be returned.
- * If @name is null, the first matching entry will be returned. Data
- * order is not meaningful in hwmod data, so callers are strongly
- * encouraged to use a non-null @name whenever possible to avoid
- * unpredictable effects if hwmod data is later added that causes data
- * ordering to change. Returns 0 upon success or a negative error
- * code upon error.
- */
-static int _get_mpu_irq_by_name(struct omap_hwmod *oh, const char *name,
- unsigned int *irq)
-{
- int i;
- bool found = false;
-
- if (!oh->mpu_irqs)
- return -ENOENT;
-
- i = 0;
- while (oh->mpu_irqs[i].irq != -1) {
- if (name == oh->mpu_irqs[i].name ||
- !strcmp(name, oh->mpu_irqs[i].name)) {
- found = true;
- break;
- }
- i++;
- }
-
- if (!found)
- return -ENOENT;
-
- *irq = oh->mpu_irqs[i].irq;
-
- return 0;
-}
-
-/**
- * _get_sdma_req_by_name - fetch SDMA request line ID by name
- * @oh: struct omap_hwmod * to operate on
- * @name: pointer to the name of the SDMA request line to fetch (optional)
- * @dma: pointer to an unsigned int to store the request line ID to
- *
- * Retrieve an SDMA request line ID named by @name on the IP block
- * pointed to by @oh. The ID will be filled into the address pointed
- * to by @dma. When @name is non-null, the request line ID associated
- * with the named entry will be returned. If @name is null, the first
- * matching entry will be returned. Data order is not meaningful in
- * hwmod data, so callers are strongly encouraged to use a non-null
- * @name whenever possible to avoid unpredictable effects if hwmod
- * data is later added that causes data ordering to change. Returns 0
- * upon success or a negative error code upon error.
- */
-static int _get_sdma_req_by_name(struct omap_hwmod *oh, const char *name,
- unsigned int *dma)
-{
- int i;
- bool found = false;
-
- if (!oh->sdma_reqs)
- return -ENOENT;
-
- i = 0;
- while (oh->sdma_reqs[i].dma_req != -1) {
- if (name == oh->sdma_reqs[i].name ||
- !strcmp(name, oh->sdma_reqs[i].name)) {
- found = true;
- break;
- }
- i++;
- }
-
- if (!found)
- return -ENOENT;
-
- *dma = oh->sdma_reqs[i].dma_req;
-
- return 0;
-}
-
-/**
- * _get_addr_space_by_name - fetch address space start & end by name
- * @oh: struct omap_hwmod * to operate on
- * @name: pointer to the name of the address space to fetch (optional)
- * @pa_start: pointer to a u32 to store the starting address to
- * @pa_end: pointer to a u32 to store the ending address to
- *
- * Retrieve address space start and end addresses for the IP block
- * pointed to by @oh. The data will be filled into the addresses
- * pointed to by @pa_start and @pa_end. When @name is non-null, the
- * address space data associated with the named entry will be
- * returned. If @name is null, the first matching entry will be
- * returned. Data order is not meaningful in hwmod data, so callers
- * are strongly encouraged to use a non-null @name whenever possible
- * to avoid unpredictable effects if hwmod data is later added that
- * causes data ordering to change. Returns 0 upon success or a
- * negative error code upon error.
- */
-static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name,
- u32 *pa_start, u32 *pa_end)
-{
- int j;
- struct omap_hwmod_ocp_if *os;
- bool found = false;
-
- list_for_each_entry(os, &oh->slave_ports, node) {
-
- if (!os->addr)
- return -ENOENT;
-
- j = 0;
- while (os->addr[j].pa_start != os->addr[j].pa_end) {
- if (name == os->addr[j].name ||
- !strcmp(name, os->addr[j].name)) {
- found = true;
- break;
- }
- j++;
- }
-
- if (found)
- break;
- }
-
- if (!found)
- return -ENOENT;
-
- *pa_start = os->addr[j].pa_start;
- *pa_end = os->addr[j].pa_end;
-
- return 0;
-}
-
-/**
* _save_mpu_port_index - find and save the index to @oh's MPU port
* @oh: struct omap_hwmod *
*
@@ -1361,32 +1152,6 @@ static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh)
};
/**
- * _find_mpu_rt_addr_space - return MPU register target address space for @oh
- * @oh: struct omap_hwmod *
- *
- * Returns a pointer to the struct omap_hwmod_addr_space record representing
- * the register target MPU address space; or returns NULL upon error.
- */
-static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap_hwmod *oh)
-{
- struct omap_hwmod_ocp_if *os;
- struct omap_hwmod_addr_space *mem;
- int found = 0, i = 0;
-
- os = _find_mpu_rt_port(oh);
- if (!os || !os->addr)
- return NULL;
-
- do {
- mem = &os->addr[i++];
- if (mem->flags & ADDR_TYPE_RT)
- found = 1;
- } while (!found && mem->pa_start != mem->pa_end);
-
- return (found) ? mem : NULL;
-}
-
-/**
* _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
@@ -2394,6 +2159,75 @@ static int of_dev_hwmod_lookup(struct device_node *np,
}
/**
+ * omap_hwmod_parse_module_range - map module IO range from device tree
+ * @oh: struct omap_hwmod *
+ * @np: struct device_node *
+ *
+ * Parse the device tree range an interconnect target module provides
+ * for it's child device IP blocks. This way we can support the old
+ * "ti,hwmods" property with just dts data without a need for platform
+ * data for IO resources. And we don't need all the child IP device
+ * nodes available in the dts.
+ */
+int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
+ struct device_node *np,
+ struct resource *res)
+{
+ struct property *prop;
+ const __be32 *ranges;
+ const char *name;
+ u32 nr_addr, nr_size;
+ u64 base, size;
+ int len, error;
+
+ if (!res)
+ return -EINVAL;
+
+ ranges = of_get_property(np, "ranges", &len);
+ if (!ranges)
+ return -ENOENT;
+
+ len /= sizeof(*ranges);
+
+ if (len < 3)
+ return -EINVAL;
+
+ of_property_for_each_string(np, "compatible", prop, name)
+ if (!strncmp("ti,sysc-", name, 8))
+ break;
+
+ if (!name)
+ return -ENOENT;
+
+ error = of_property_read_u32(np, "#address-cells", &nr_addr);
+ if (error)
+ return -ENOENT;
+
+ error = of_property_read_u32(np, "#size-cells", &nr_size);
+ if (error)
+ return -ENOENT;
+
+ if (nr_addr != 1 || nr_size != 1) {
+ pr_err("%s: invalid range for %s->%s\n", __func__,
+ oh->name, np->name);
+ return -EINVAL;
+ }
+
+ ranges++;
+ base = of_translate_address(np, ranges++);
+ size = be32_to_cpup(ranges);
+
+ pr_debug("omap_hwmod: %s %s at 0x%llx size 0x%llx\n",
+ oh->name, np->name, base, size);
+
+ res->start = base;
+ res->end = base + size - 1;
+ res->flags = IORESOURCE_MEM;
+
+ return 0;
+}
+
+/**
* _init_mpu_rt_base - populate the virtual address for a hwmod
* @oh: struct omap_hwmod * to locate the virtual address
* @data: (unused, caller should pass NULL)
@@ -2413,8 +2247,9 @@ static int of_dev_hwmod_lookup(struct device_node *np,
static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
int index, struct device_node *np)
{
- struct omap_hwmod_addr_space *mem;
void __iomem *va_start = NULL;
+ struct resource res;
+ int error;
if (!oh)
return -EINVAL;
@@ -2429,28 +2264,22 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
return -ENXIO;
- mem = _find_mpu_rt_addr_space(oh);
- if (!mem) {
- pr_debug("omap_hwmod: %s: no MPU register target found\n",
- oh->name);
+ if (!np) {
+ pr_err("omap_hwmod: %s: no dt node\n", oh->name);
+ return -ENXIO;
+ }
- /* Extract the IO space from device tree blob */
- if (!np) {
- pr_err("omap_hwmod: %s: no dt node\n", oh->name);
- return -ENXIO;
- }
+ /* Do we have a dts range for the interconnect target module? */
+ error = omap_hwmod_parse_module_range(oh, np, &res);
+ if (!error)
+ va_start = ioremap(res.start, resource_size(&res));
+ /* No ranges, rely on device reg entry */
+ if (!va_start)
va_start = of_iomap(np, index + oh->mpu_rt_idx);
- } else {
- va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
- }
-
if (!va_start) {
- if (mem)
- pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
- else
- pr_err("omap_hwmod: %s: Missing dt reg%i for %pOF\n",
- oh->name, index, np);
+ pr_err("omap_hwmod: %s: Missing dt reg%i for %pOF\n",
+ oh->name, index, np);
return -ENXIO;
}
@@ -3355,189 +3184,6 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
*/
/**
- * omap_hwmod_count_resources - count number of struct resources needed by hwmod
- * @oh: struct omap_hwmod *
- * @flags: Type of resources to include when counting (IRQ/DMA/MEM)
- *
- * Count the number of struct resource array elements necessary to
- * contain omap_hwmod @oh resources. Intended to be called by code
- * that registers omap_devices. Intended to be used to determine the
- * size of a dynamically-allocated struct resource array, before
- * calling omap_hwmod_fill_resources(). Returns the number of struct
- * resource array elements needed.
- *
- * XXX This code is not optimized. It could attempt to merge adjacent
- * resource IDs.
- *
- */
-int omap_hwmod_count_resources(struct omap_hwmod *oh, unsigned long flags)
-{
- int ret = 0;
-
- if (flags & IORESOURCE_IRQ)
- ret += _count_mpu_irqs(oh);
-
- if (flags & IORESOURCE_DMA)
- ret += _count_sdma_reqs(oh);
-
- if (flags & IORESOURCE_MEM) {
- struct omap_hwmod_ocp_if *os;
-
- list_for_each_entry(os, &oh->slave_ports, node)
- ret += _count_ocp_if_addr_spaces(os);
- }
-
- return ret;
-}
-
-/**
- * omap_hwmod_fill_resources - fill struct resource array with hwmod data
- * @oh: struct omap_hwmod *
- * @res: pointer to the first element of an array of struct resource to fill
- *
- * Fill the struct resource array @res with resource data from the
- * omap_hwmod @oh. Intended to be called by code that registers
- * omap_devices. See also omap_hwmod_count_resources(). Returns the
- * number of array elements filled.
- */
-int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
-{
- struct omap_hwmod_ocp_if *os;
- int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt;
- int r = 0;
-
- /* For each IRQ, DMA, memory area, fill in array.*/
-
- mpu_irqs_cnt = _count_mpu_irqs(oh);
- for (i = 0; i < mpu_irqs_cnt; i++) {
- unsigned int irq;
-
- if (oh->xlate_irq)
- irq = oh->xlate_irq((oh->mpu_irqs + i)->irq);
- else
- irq = (oh->mpu_irqs + i)->irq;
- (res + r)->name = (oh->mpu_irqs + i)->name;
- (res + r)->start = irq;
- (res + r)->end = irq;
- (res + r)->flags = IORESOURCE_IRQ;
- r++;
- }
-
- sdma_reqs_cnt = _count_sdma_reqs(oh);
- for (i = 0; i < sdma_reqs_cnt; i++) {
- (res + r)->name = (oh->sdma_reqs + i)->name;
- (res + r)->start = (oh->sdma_reqs + i)->dma_req;
- (res + r)->end = (oh->sdma_reqs + i)->dma_req;
- (res + r)->flags = IORESOURCE_DMA;
- r++;
- }
-
- list_for_each_entry(os, &oh->slave_ports, node) {
- addr_cnt = _count_ocp_if_addr_spaces(os);
-
- for (j = 0; j < addr_cnt; j++) {
- (res + r)->name = (os->addr + j)->name;
- (res + r)->start = (os->addr + j)->pa_start;
- (res + r)->end = (os->addr + j)->pa_end;
- (res + r)->flags = IORESOURCE_MEM;
- r++;
- }
- }
-
- return r;
-}
-
-/**
- * omap_hwmod_fill_dma_resources - fill struct resource array with dma data
- * @oh: struct omap_hwmod *
- * @res: pointer to the array of struct resource to fill
- *
- * Fill the struct resource array @res with dma resource data from the
- * omap_hwmod @oh. Intended to be called by code that registers
- * omap_devices. See also omap_hwmod_count_resources(). Returns the
- * number of array elements filled.
- */
-int omap_hwmod_fill_dma_resources(struct omap_hwmod *oh, struct resource *res)
-{
- int i, sdma_reqs_cnt;
- int r = 0;
-
- sdma_reqs_cnt = _count_sdma_reqs(oh);
- for (i = 0; i < sdma_reqs_cnt; i++) {
- (res + r)->name = (oh->sdma_reqs + i)->name;
- (res + r)->start = (oh->sdma_reqs + i)->dma_req;
- (res + r)->end = (oh->sdma_reqs + i)->dma_req;
- (res + r)->flags = IORESOURCE_DMA;
- r++;
- }
-
- return r;
-}
-
-/**
- * omap_hwmod_get_resource_byname - fetch IP block integration data by name
- * @oh: struct omap_hwmod * to operate on
- * @type: one of the IORESOURCE_* constants from include/linux/ioport.h
- * @name: pointer to the name of the data to fetch (optional)
- * @rsrc: pointer to a struct resource, allocated by the caller
- *
- * Retrieve MPU IRQ, SDMA request line, or address space start/end
- * data for the IP block pointed to by @oh. The data will be filled
- * into a struct resource record pointed to by @rsrc. The struct
- * resource must be allocated by the caller. When @name is non-null,
- * the data associated with the matching entry in the IRQ/SDMA/address
- * space hwmod data arrays will be returned. If @name is null, the
- * first array entry will be returned. Data order is not meaningful
- * in hwmod data, so callers are strongly encouraged to use a non-null
- * @name whenever possible to avoid unpredictable effects if hwmod
- * data is later added that causes data ordering to change. This
- * function is only intended for use by OMAP core code. Device
- * drivers should not call this function - the appropriate bus-related
- * data accessor functions should be used instead. Returns 0 upon
- * success or a negative error code upon error.
- */
-int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
- const char *name, struct resource *rsrc)
-{
- int r;
- unsigned int irq, dma;
- u32 pa_start, pa_end;
-
- if (!oh || !rsrc)
- return -EINVAL;
-
- if (type == IORESOURCE_IRQ) {
- r = _get_mpu_irq_by_name(oh, name, &irq);
- if (r)
- return r;
-
- rsrc->start = irq;
- rsrc->end = irq;
- } else if (type == IORESOURCE_DMA) {
- r = _get_sdma_req_by_name(oh, name, &dma);
- if (r)
- return r;
-
- rsrc->start = dma;
- rsrc->end = dma;
- } else if (type == IORESOURCE_MEM) {
- r = _get_addr_space_by_name(oh, name, &pa_start, &pa_end);
- if (r)
- return r;
-
- rsrc->start = pa_start;
- rsrc->end = pa_end;
- } else {
- return -EINVAL;
- }
-
- rsrc->flags = type;
- rsrc->name = name;
-
- return 0;
-}
-
-/**
* omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain
* @oh: struct omap_hwmod *
*