aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c168
1 files changed, 140 insertions, 28 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 8bcea0d83fa0..3b47ded5fa0c 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -141,6 +141,7 @@
141#include <linux/cpu.h> 141#include <linux/cpu.h>
142#include <linux/of.h> 142#include <linux/of.h>
143#include <linux/of_address.h> 143#include <linux/of_address.h>
144#include <linux/bootmem.h>
144 145
145#include <asm/system_misc.h> 146#include <asm/system_misc.h>
146 147
@@ -182,6 +183,24 @@
182#define MOD_CLK_MAX_NAME_LEN 32 183#define MOD_CLK_MAX_NAME_LEN 32
183 184
184/** 185/**
186 * struct clkctrl_provider - clkctrl provider mapping data
187 * @addr: base address for the provider
188 * @offset: base offset for the provider
189 * @clkdm: base clockdomain for provider
190 * @node: device node associated with the provider
191 * @link: list link
192 */
193struct clkctrl_provider {
194 u32 addr;
195 u16 offset;
196 struct clockdomain *clkdm;
197 struct device_node *node;
198 struct list_head link;
199};
200
201static LIST_HEAD(clkctrl_providers);
202
203/**
185 * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations 204 * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
186 * @enable_module: function to enable a module (via MODULEMODE) 205 * @enable_module: function to enable a module (via MODULEMODE)
187 * @disable_module: function to disable a module (via MODULEMODE) 206 * @disable_module: function to disable a module (via MODULEMODE)
@@ -204,6 +223,8 @@ struct omap_hwmod_soc_ops {
204 void (*update_context_lost)(struct omap_hwmod *oh); 223 void (*update_context_lost)(struct omap_hwmod *oh);
205 int (*get_context_lost)(struct omap_hwmod *oh); 224 int (*get_context_lost)(struct omap_hwmod *oh);
206 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,
227 struct clkctrl_provider *provider);
207}; 228};
208 229
209/* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */ 230/* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */
@@ -690,6 +711,103 @@ static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
690 return clkdm_del_sleepdep(clkdm, init_clkdm); 711 return clkdm_del_sleepdep(clkdm, init_clkdm);
691} 712}
692 713
714static const struct of_device_id ti_clkctrl_match_table[] __initconst = {
715 { .compatible = "ti,clkctrl" },
716 { }
717};
718
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)
736{
737 const __be32 *addrp;
738 struct clkctrl_provider *provider;
739
740 provider = memblock_virt_alloc(sizeof(*provider), 0);
741 if (!provider)
742 return -ENOMEM;
743
744 addrp = of_get_address(np, 0, NULL, NULL);
745 provider->addr = (u32)of_translate_address(np, addrp);
746 provider->offset = provider->addr & 0xff;
747 provider->addr &= ~0xff;
748 provider->node = np;
749
750 clkdm_for_each(_match_clkdm, provider);
751
752 if (!provider->clkdm) {
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
759 list_add(&provider->link, &clkctrl_providers);
760
761 return 0;
762}
763
764static int _init_clkctrl_providers(void)
765{
766 struct device_node *np;
767 int ret = 0;
768
769 for_each_matching_node(np, ti_clkctrl_match_table) {
770 ret = _setup_clkctrl_provider(np);
771 if (ret)
772 break;
773 }
774
775 return ret;
776}
777
778static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh,
779 struct clkctrl_provider *provider)
780{
781 return oh->prcm.omap4.clkctrl_offs -
782 provider->offset - provider->clkdm->clkdm_offs;
783}
784
785static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh)
786{
787 struct clkctrl_provider *provider;
788 struct clk *clk;
789
790 if (!soc_ops.xlate_clkctrl)
791 return NULL;
792
793 list_for_each_entry(provider, &clkctrl_providers, link) {
794 if (provider->clkdm == oh->clkdm) {
795 struct of_phandle_args clkspec;
796
797 clkspec.np = provider->node;
798 clkspec.args_count = 2;
799 clkspec.args[0] = soc_ops.xlate_clkctrl(oh, provider);
800 clkspec.args[1] = 0;
801
802 clk = of_clk_get_from_provider(&clkspec);
803
804 return clk;
805 }
806 }
807
808 return NULL;
809}
810
693/** 811/**
694 * _init_main_clk - get a struct clk * for the the hwmod's main functional clk 812 * _init_main_clk - get a struct clk * for the the hwmod's main functional clk
695 * @oh: struct omap_hwmod * 813 * @oh: struct omap_hwmod *
@@ -701,22 +819,16 @@ static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
701static int _init_main_clk(struct omap_hwmod *oh) 819static int _init_main_clk(struct omap_hwmod *oh)
702{ 820{
703 int ret = 0; 821 int ret = 0;
704 char name[MOD_CLK_MAX_NAME_LEN]; 822 struct clk *clk = NULL;
705 struct clk *clk;
706 static const char modck[] = "_mod_ck";
707 823
708 if (strlen(oh->name) >= MOD_CLK_MAX_NAME_LEN - strlen(modck)) 824 clk = _lookup_clkctrl_clk(oh);
709 pr_warn("%s: warning: cropping name for %s\n", __func__,
710 oh->name);
711
712 strlcpy(name, oh->name, MOD_CLK_MAX_NAME_LEN - strlen(modck));
713 strlcat(name, modck, MOD_CLK_MAX_NAME_LEN);
714 825
715 clk = clk_get(NULL, name); 826 if (!IS_ERR_OR_NULL(clk)) {
716 if (!IS_ERR(clk)) { 827 pr_debug("%s: mapped main_clk %s for %s\n", __func__,
828 __clk_get_name(clk), oh->name);
829 oh->main_clk = __clk_get_name(clk);
717 oh->_clk = clk; 830 oh->_clk = clk;
718 soc_ops.disable_direct_prcm(oh); 831 soc_ops.disable_direct_prcm(oh);
719 oh->main_clk = kstrdup(name, GFP_KERNEL);
720 } else { 832 } else {
721 if (!oh->main_clk) 833 if (!oh->main_clk)
722 return 0; 834 return 0;
@@ -1482,13 +1594,13 @@ static int _init_clkdm(struct omap_hwmod *oh)
1482 * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as 1594 * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as
1483 * well the clockdomain. 1595 * well the clockdomain.
1484 * @oh: struct omap_hwmod * 1596 * @oh: struct omap_hwmod *
1485 * @data: not used; pass NULL 1597 * @np: device_node mapped to this hwmod
1486 * 1598 *
1487 * Called by omap_hwmod_setup_*() (after omap2_clk_init()). 1599 * Called by omap_hwmod_setup_*() (after omap2_clk_init()).
1488 * Resolves all clock names embedded in the hwmod. Returns 0 on 1600 * Resolves all clock names embedded in the hwmod. Returns 0 on
1489 * success, or a negative error code on failure. 1601 * success, or a negative error code on failure.
1490 */ 1602 */
1491static int _init_clocks(struct omap_hwmod *oh, void *data) 1603static int _init_clocks(struct omap_hwmod *oh, struct device_node *np)
1492{ 1604{
1493 int ret = 0; 1605 int ret = 0;
1494 1606
@@ -2334,24 +2446,21 @@ static int __init _init(struct omap_hwmod *oh, void *data)
2334{ 2446{
2335 int r, index; 2447 int r, index;
2336 struct device_node *np = NULL; 2448 struct device_node *np = NULL;
2449 struct device_node *bus;
2337 2450
2338 if (oh->_state != _HWMOD_STATE_REGISTERED) 2451 if (oh->_state != _HWMOD_STATE_REGISTERED)
2339 return 0; 2452 return 0;
2340 2453
2341 if (of_have_populated_dt()) { 2454 bus = of_find_node_by_name(NULL, "ocp");
2342 struct device_node *bus; 2455 if (!bus)
2456 return -ENODEV;
2343 2457
2344 bus = of_find_node_by_name(NULL, "ocp"); 2458 r = of_dev_hwmod_lookup(bus, oh, &index, &np);
2345 if (!bus) 2459 if (r)
2346 return -ENODEV; 2460 pr_debug("omap_hwmod: %s missing dt data\n", oh->name);
2347 2461 else if (np && index)
2348 r = of_dev_hwmod_lookup(bus, oh, &index, &np); 2462 pr_warn("omap_hwmod: %s using broken dt data from %s\n",
2349 if (r) 2463 oh->name, np->name);
2350 pr_debug("omap_hwmod: %s missing dt data\n", oh->name);
2351 else if (np && index)
2352 pr_warn("omap_hwmod: %s using broken dt data from %s\n",
2353 oh->name, np->name);
2354 }
2355 2464
2356 r = _init_mpu_rt_base(oh, NULL, index, np); 2465 r = _init_mpu_rt_base(oh, NULL, index, np);
2357 if (r < 0) { 2466 if (r < 0) {
@@ -2360,7 +2469,7 @@ static int __init _init(struct omap_hwmod *oh, void *data)
2360 return 0; 2469 return 0;
2361 } 2470 }
2362 2471
2363 r = _init_clocks(oh, NULL); 2472 r = _init_clocks(oh, np);
2364 if (r < 0) { 2473 if (r < 0) {
2365 WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name); 2474 WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name);
2366 return -EINVAL; 2475 return -EINVAL;
@@ -3722,6 +3831,7 @@ void __init omap_hwmod_init(void)
3722 soc_ops.update_context_lost = _omap4_update_context_lost; 3831 soc_ops.update_context_lost = _omap4_update_context_lost;
3723 soc_ops.get_context_lost = _omap4_get_context_lost; 3832 soc_ops.get_context_lost = _omap4_get_context_lost;
3724 soc_ops.disable_direct_prcm = _omap4_disable_direct_prcm; 3833 soc_ops.disable_direct_prcm = _omap4_disable_direct_prcm;
3834 soc_ops.xlate_clkctrl = _omap4_xlate_clkctrl;
3725 } else if (cpu_is_ti814x() || cpu_is_ti816x() || soc_is_am33xx() || 3835 } else if (cpu_is_ti814x() || cpu_is_ti816x() || soc_is_am33xx() ||
3726 soc_is_am43xx()) { 3836 soc_is_am43xx()) {
3727 soc_ops.enable_module = _omap4_enable_module; 3837 soc_ops.enable_module = _omap4_enable_module;
@@ -3736,6 +3846,8 @@ void __init omap_hwmod_init(void)
3736 WARN(1, "omap_hwmod: unknown SoC type\n"); 3846 WARN(1, "omap_hwmod: unknown SoC type\n");
3737 } 3847 }
3738 3848
3849 _init_clkctrl_providers();
3850
3739 inited = true; 3851 inited = true;
3740} 3852}
3741 3853