aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2017-08-04 10:41:50 -0400
committerTero Kristo <t-kristo@ti.com>2017-12-04 04:35:21 -0500
commit6e83ecaa453d0e574723cc94f46eae74e3820a41 (patch)
tree70153e96d47f97e18fd3c30ec3052593dcde7507 /arch/arm/mach-omap2/omap_hwmod.c
parent1055d92ccfee2751605cfe32ed2a4f4d6c64c101 (diff)
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: Tero Kristo <t-kristo@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c72
1 files changed, 35 insertions, 37 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 104256a5f0f7..4b256c83c17b 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -185,15 +185,15 @@
185/** 185/**
186 * struct clkctrl_provider - clkctrl provider mapping data 186 * struct clkctrl_provider - clkctrl provider mapping data
187 * @addr: base address for the provider 187 * @addr: base address for the provider
188 * @offset: base offset for the provider 188 * @size: size of the provider address space
189 * @clkdm: base clockdomain for provider 189 * @offset: offset of the provider from PRCM instance base
190 * @node: device node associated with the provider 190 * @node: device node associated with the provider
191 * @link: list link 191 * @link: list link
192 */ 192 */
193struct clkctrl_provider { 193struct clkctrl_provider {
194 u32 addr; 194 u32 addr;
195 u32 size;
195 u16 offset; 196 u16 offset;
196 struct clockdomain *clkdm;
197 struct device_node *node; 197 struct device_node *node;
198 struct list_head link; 198 struct list_head link;
199}; 199};
@@ -223,8 +223,7 @@ struct omap_hwmod_soc_ops {
223 void (*update_context_lost)(struct omap_hwmod *oh); 223 void (*update_context_lost)(struct omap_hwmod *oh);
224 int (*get_context_lost)(struct omap_hwmod *oh); 224 int (*get_context_lost)(struct omap_hwmod *oh);
225 int (*disable_direct_prcm)(struct omap_hwmod *oh); 225 int (*disable_direct_prcm)(struct omap_hwmod *oh);
226 u32 (*xlate_clkctrl)(struct omap_hwmod *oh, 226 u32 (*xlate_clkctrl)(struct omap_hwmod *oh);
227 struct clkctrl_provider *provider);
228}; 227};
229 228
230/* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */ 229/* 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 { } 715 { }
717}; 716};
718 717
719static int _match_clkdm(struct clockdomain *clkdm, void *user)
720{
721 struct clkctrl_provider *provider = user;
722
723 if (clkdm_xlate_address(clkdm) == provider->addr) {
724 pr_debug("%s: Matched clkdm %s for addr %x (%s)\n", __func__,
725 clkdm->name, provider->addr,
726 provider->node->parent->name);
727 provider->clkdm = clkdm;
728
729 return -1;
730 }
731
732 return 0;
733}
734
735static int _setup_clkctrl_provider(struct device_node *np) 718static int _setup_clkctrl_provider(struct device_node *np)
736{ 719{
737 const __be32 *addrp; 720 const __be32 *addrp;
738 struct clkctrl_provider *provider; 721 struct clkctrl_provider *provider;
722 u64 size;
739 723
740 provider = memblock_virt_alloc(sizeof(*provider), 0); 724 provider = memblock_virt_alloc(sizeof(*provider), 0);
741 if (!provider) 725 if (!provider)
742 return -ENOMEM; 726 return -ENOMEM;
743 727
744 addrp = of_get_address(np, 0, NULL, NULL); 728 addrp = of_get_address(np, 0, &size, NULL);
745 provider->addr = (u32)of_translate_address(np, addrp); 729 provider->addr = (u32)of_translate_address(np, addrp);
746 provider->offset = provider->addr & 0xff; 730 addrp = of_get_address(np->parent, 0, NULL, NULL);
731 provider->offset = provider->addr -
732 (u32)of_translate_address(np->parent, addrp);
747 provider->addr &= ~0xff; 733 provider->addr &= ~0xff;
734 provider->size = size | 0xff;
748 provider->node = np; 735 provider->node = np;
749 736
750 clkdm_for_each(_match_clkdm, provider); 737 pr_debug("%s: %s: %x...%x [+%x]\n", __func__, np->parent->name,
751 738 provider->addr, provider->addr + provider->size,
752 if (!provider->clkdm) { 739 provider->offset);
753 pr_err("%s: nothing matched for node %s (%x)\n",
754 __func__, np->parent->name, provider->addr);
755 memblock_free_early(__pa(provider), sizeof(*provider));
756 return -EINVAL;
757 }
758 740
759 list_add(&provider->link, &clkctrl_providers); 741 list_add(&provider->link, &clkctrl_providers);
760 742
@@ -775,32 +757,48 @@ static int _init_clkctrl_providers(void)
775 return ret; 757 return ret;
776} 758}
777 759
778static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh, 760static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh)
779 struct clkctrl_provider *provider)
780{ 761{
781 return oh->prcm.omap4.clkctrl_offs - 762 if (!oh->prcm.omap4.modulemode)
782 provider->offset - provider->clkdm->clkdm_offs; 763 return 0;
764
765 return omap_cm_xlate_clkctrl(oh->clkdm->prcm_partition,
766 oh->clkdm->cm_inst,
767 oh->prcm.omap4.clkctrl_offs);
783} 768}
784 769
785static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh) 770static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh)
786{ 771{
787 struct clkctrl_provider *provider; 772 struct clkctrl_provider *provider;
788 struct clk *clk; 773 struct clk *clk;
774 u32 addr;
789 775
790 if (!soc_ops.xlate_clkctrl) 776 if (!soc_ops.xlate_clkctrl)
791 return NULL; 777 return NULL;
792 778
779 addr = soc_ops.xlate_clkctrl(oh);
780 if (!addr)
781 return NULL;
782
783 pr_debug("%s: %s: addr=%x\n", __func__, oh->name, addr);
784
793 list_for_each_entry(provider, &clkctrl_providers, link) { 785 list_for_each_entry(provider, &clkctrl_providers, link) {
794 if (provider->clkdm == oh->clkdm) { 786 if (provider->addr <= addr &&
787 provider->addr + provider->size >= addr) {
795 struct of_phandle_args clkspec; 788 struct of_phandle_args clkspec;
796 789
797 clkspec.np = provider->node; 790 clkspec.np = provider->node;
798 clkspec.args_count = 2; 791 clkspec.args_count = 2;
799 clkspec.args[0] = soc_ops.xlate_clkctrl(oh, provider); 792 clkspec.args[0] = addr - provider->addr -
793 provider->offset;
800 clkspec.args[1] = 0; 794 clkspec.args[1] = 0;
801 795
802 clk = of_clk_get_from_provider(&clkspec); 796 clk = of_clk_get_from_provider(&clkspec);
803 797
798 pr_debug("%s: %s got %p (offset=%x, provider=%s)\n",
799 __func__, oh->name, clk, clkspec.args[0],
800 provider->node->parent->name);
801
804 return clk; 802 return clk;
805 } 803 }
806 } 804 }