Commit 6e83ecaa authored by Tero Kristo's avatar Tero Kristo

ARM: OMAP2+: hwmod: fix clkctrl address translation logic

There are cases where clkctrl clock offsets do not match the corresponding
clockdomain, and this case the existing mapping functionality will fail.
Fix this by adding the whole address range for a clkctrl provider and
matching the actual clkctrl registers against these ranges.
Signed-off-by: default avatarTero Kristo <t-kristo@ti.com>
parent 1055d92c
...@@ -185,15 +185,15 @@ ...@@ -185,15 +185,15 @@
/** /**
* struct clkctrl_provider - clkctrl provider mapping data * struct clkctrl_provider - clkctrl provider mapping data
* @addr: base address for the provider * @addr: base address for the provider
* @offset: base offset for the provider * @size: size of the provider address space
* @clkdm: base clockdomain for provider * @offset: offset of the provider from PRCM instance base
* @node: device node associated with the provider * @node: device node associated with the provider
* @link: list link * @link: list link
*/ */
struct clkctrl_provider { struct clkctrl_provider {
u32 addr; u32 addr;
u32 size;
u16 offset; u16 offset;
struct clockdomain *clkdm;
struct device_node *node; struct device_node *node;
struct list_head link; struct list_head link;
}; };
...@@ -223,8 +223,7 @@ struct omap_hwmod_soc_ops { ...@@ -223,8 +223,7 @@ struct omap_hwmod_soc_ops {
void (*update_context_lost)(struct omap_hwmod *oh); void (*update_context_lost)(struct omap_hwmod *oh);
int (*get_context_lost)(struct omap_hwmod *oh); int (*get_context_lost)(struct omap_hwmod *oh);
int (*disable_direct_prcm)(struct omap_hwmod *oh); int (*disable_direct_prcm)(struct omap_hwmod *oh);
u32 (*xlate_clkctrl)(struct omap_hwmod *oh, u32 (*xlate_clkctrl)(struct omap_hwmod *oh);
struct clkctrl_provider *provider);
}; };
/* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */ /* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */
...@@ -716,45 +715,28 @@ static const struct of_device_id ti_clkctrl_match_table[] __initconst = { ...@@ -716,45 +715,28 @@ static const struct of_device_id ti_clkctrl_match_table[] __initconst = {
{ } { }
}; };
static int _match_clkdm(struct clockdomain *clkdm, void *user)
{
struct clkctrl_provider *provider = user;
if (clkdm_xlate_address(clkdm) == provider->addr) {
pr_debug("%s: Matched clkdm %s for addr %x (%s)\n", __func__,
clkdm->name, provider->addr,
provider->node->parent->name);
provider->clkdm = clkdm;
return -1;
}
return 0;
}
static int _setup_clkctrl_provider(struct device_node *np) static int _setup_clkctrl_provider(struct device_node *np)
{ {
const __be32 *addrp; const __be32 *addrp;
struct clkctrl_provider *provider; struct clkctrl_provider *provider;
u64 size;
provider = memblock_virt_alloc(sizeof(*provider), 0); provider = memblock_virt_alloc(sizeof(*provider), 0);
if (!provider) if (!provider)
return -ENOMEM; return -ENOMEM;
addrp = of_get_address(np, 0, NULL, NULL); addrp = of_get_address(np, 0, &size, NULL);
provider->addr = (u32)of_translate_address(np, addrp); provider->addr = (u32)of_translate_address(np, addrp);
provider->offset = provider->addr & 0xff; addrp = of_get_address(np->parent, 0, NULL, NULL);
provider->offset = provider->addr -
(u32)of_translate_address(np->parent, addrp);
provider->addr &= ~0xff; provider->addr &= ~0xff;
provider->size = size | 0xff;
provider->node = np; provider->node = np;
clkdm_for_each(_match_clkdm, provider); pr_debug("%s: %s: %x...%x [+%x]\n", __func__, np->parent->name,
provider->addr, provider->addr + provider->size,
if (!provider->clkdm) { provider->offset);
pr_err("%s: nothing matched for node %s (%x)\n",
__func__, np->parent->name, provider->addr);
memblock_free_early(__pa(provider), sizeof(*provider));
return -EINVAL;
}
list_add(&provider->link, &clkctrl_providers); list_add(&provider->link, &clkctrl_providers);
...@@ -775,32 +757,48 @@ static int _init_clkctrl_providers(void) ...@@ -775,32 +757,48 @@ static int _init_clkctrl_providers(void)
return ret; return ret;
} }
static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh, static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh)
struct clkctrl_provider *provider)
{ {
return oh->prcm.omap4.clkctrl_offs - if (!oh->prcm.omap4.modulemode)
provider->offset - provider->clkdm->clkdm_offs; return 0;
return omap_cm_xlate_clkctrl(oh->clkdm->prcm_partition,
oh->clkdm->cm_inst,
oh->prcm.omap4.clkctrl_offs);
} }
static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh) static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh)
{ {
struct clkctrl_provider *provider; struct clkctrl_provider *provider;
struct clk *clk; struct clk *clk;
u32 addr;
if (!soc_ops.xlate_clkctrl) if (!soc_ops.xlate_clkctrl)
return NULL; return NULL;
addr = soc_ops.xlate_clkctrl(oh);
if (!addr)
return NULL;
pr_debug("%s: %s: addr=%x\n", __func__, oh->name, addr);
list_for_each_entry(provider, &clkctrl_providers, link) { list_for_each_entry(provider, &clkctrl_providers, link) {
if (provider->clkdm == oh->clkdm) { if (provider->addr <= addr &&
provider->addr + provider->size >= addr) {
struct of_phandle_args clkspec; struct of_phandle_args clkspec;
clkspec.np = provider->node; clkspec.np = provider->node;
clkspec.args_count = 2; clkspec.args_count = 2;
clkspec.args[0] = soc_ops.xlate_clkctrl(oh, provider); clkspec.args[0] = addr - provider->addr -
provider->offset;
clkspec.args[1] = 0; clkspec.args[1] = 0;
clk = of_clk_get_from_provider(&clkspec); clk = of_clk_get_from_provider(&clkspec);
pr_debug("%s: %s got %p (offset=%x, provider=%s)\n",
__func__, oh->name, clk, clkspec.args[0],
provider->node->parent->name);
return clk; return clk;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment