diff options
author | Olof Johansson <olof@lixom.net> | 2017-06-18 23:46:30 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2017-06-18 23:46:30 -0400 |
commit | 2b1ee3061f09bd90a5c659b9cb45fcbf49c5fd4c (patch) | |
tree | 37fc6c42bc227468e0c60869fd60e59685726135 /arch/arm/mach-omap2/timer.c | |
parent | 6198c74939c085fbd31fab3ba6f1eb2ce2820b39 (diff) | |
parent | 1df5eaa6bced2d8a9de305d4a5f587adf57ddf35 (diff) |
Merge tag 'omap-for-v4.13/soc-v4-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc
SoC changes for omap variants for v4.13 merge window:
- PM clean-up in preparation of adding am335x/am437x PM support
- Fixes for issues found by Coccinelle
- Legacy code removal now that everything boots in device
tree only mode
- Interconnect changes in preparation of moving clkctrl clocks
to be managed by clkctrl clock driver
- Interconnect changes to add omap4 crypto acceclerator
support
* tag 'omap-for-v4.13/soc-v4-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (27 commits)
ARM: OMAP4: hwmod_data: add SHAM crypto accelerator
ARM: OMAP4: hwmod data: add des
ARM: OMAP4: hwmod data: add aes2
ARM: OMAP4: hwmod data: add aes1
ARM: OMAP2+: Remove unused legacy code for n8x0
ARM: OMAP2+: Remove unused legacy code for watchdog
ARM: OMAP2+: Remove unused legacy code for interconnects
ARM: OMAP2+: Remove unused legacy code for PRM
ARM: OMAP2+: Remove unused legacy code for io.c
ARM: OMAP2+: Remove unused legacy code for McBSP
ARM: OMAP2+: SmartReflex: Delete an error message for a failed memory allocation in two functions
ARM: OMAP2+: Use kcalloc() in sr_set_nvalues()
ARM: OMAP2+: Improve a size determination in sr_dev_init()
ARM: OMAP2+: Delete an error message for a failed memory allocation in two functions
ARM: OMAP2+: Remove unused legacy code for device init
ARM: OMAP2+: Remove unused legacy code for PMU
ARM: OMAP2+: Remove unused legacy code for opp
ARM: OMAP2+: hwmod: populate clkctrl clocks for hwmods if available
ARM: OMAP4: cminst: add support for clkdm_xlate_address
ARM: omap2+: clockdomain: add clkdm_xlate_address
...
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 200 |
1 files changed, 50 insertions, 150 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 07dd692c4737..6a861c0ac343 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -68,6 +68,9 @@ | |||
68 | static struct omap_dm_timer clkev; | 68 | static struct omap_dm_timer clkev; |
69 | static struct clock_event_device clockevent_gpt; | 69 | static struct clock_event_device clockevent_gpt; |
70 | 70 | ||
71 | /* Clockevent hwmod for am335x and am437x suspend */ | ||
72 | static struct omap_hwmod *clockevent_gpt_hwmod; | ||
73 | |||
71 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER | 74 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER |
72 | static unsigned long arch_timer_freq; | 75 | static unsigned long arch_timer_freq; |
73 | 76 | ||
@@ -125,6 +128,23 @@ static int omap2_gp_timer_set_periodic(struct clock_event_device *evt) | |||
125 | return 0; | 128 | return 0; |
126 | } | 129 | } |
127 | 130 | ||
131 | static void omap_clkevt_idle(struct clock_event_device *unused) | ||
132 | { | ||
133 | if (!clockevent_gpt_hwmod) | ||
134 | return; | ||
135 | |||
136 | omap_hwmod_idle(clockevent_gpt_hwmod); | ||
137 | } | ||
138 | |||
139 | static void omap_clkevt_unidle(struct clock_event_device *unused) | ||
140 | { | ||
141 | if (!clockevent_gpt_hwmod) | ||
142 | return; | ||
143 | |||
144 | omap_hwmod_enable(clockevent_gpt_hwmod); | ||
145 | __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); | ||
146 | } | ||
147 | |||
128 | static struct clock_event_device clockevent_gpt = { | 148 | static struct clock_event_device clockevent_gpt = { |
129 | .features = CLOCK_EVT_FEAT_PERIODIC | | 149 | .features = CLOCK_EVT_FEAT_PERIODIC | |
130 | CLOCK_EVT_FEAT_ONESHOT, | 150 | CLOCK_EVT_FEAT_ONESHOT, |
@@ -232,37 +252,29 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
232 | const char **timer_name, | 252 | const char **timer_name, |
233 | int posted) | 253 | int posted) |
234 | { | 254 | { |
235 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ | ||
236 | const char *oh_name = NULL; | 255 | const char *oh_name = NULL; |
237 | struct device_node *np; | 256 | struct device_node *np; |
238 | struct omap_hwmod *oh; | 257 | struct omap_hwmod *oh; |
239 | struct resource irq, mem; | ||
240 | struct clk *src; | 258 | struct clk *src; |
241 | int r = 0; | 259 | int r = 0; |
242 | 260 | ||
243 | if (of_have_populated_dt()) { | 261 | np = omap_get_timer_dt(omap_timer_match, property); |
244 | np = omap_get_timer_dt(omap_timer_match, property); | 262 | if (!np) |
245 | if (!np) | 263 | return -ENODEV; |
246 | return -ENODEV; | ||
247 | 264 | ||
248 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | 265 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); |
249 | if (!oh_name) | 266 | if (!oh_name) |
250 | return -ENODEV; | 267 | return -ENODEV; |
251 | 268 | ||
252 | timer->irq = irq_of_parse_and_map(np, 0); | 269 | timer->irq = irq_of_parse_and_map(np, 0); |
253 | if (!timer->irq) | 270 | if (!timer->irq) |
254 | return -ENXIO; | 271 | return -ENXIO; |
255 | 272 | ||
256 | timer->io_base = of_iomap(np, 0); | 273 | timer->io_base = of_iomap(np, 0); |
257 | 274 | ||
258 | of_node_put(np); | 275 | timer->fclk = of_clk_get_by_name(np, "fck"); |
259 | } else { | ||
260 | if (omap_dm_timer_reserve_systimer(timer->id)) | ||
261 | return -ENODEV; | ||
262 | 276 | ||
263 | sprintf(name, "timer%d", timer->id); | 277 | of_node_put(np); |
264 | oh_name = name; | ||
265 | } | ||
266 | 278 | ||
267 | oh = omap_hwmod_lookup(oh_name); | 279 | oh = omap_hwmod_lookup(oh_name); |
268 | if (!oh) | 280 | if (!oh) |
@@ -270,29 +282,14 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
270 | 282 | ||
271 | *timer_name = oh->name; | 283 | *timer_name = oh->name; |
272 | 284 | ||
273 | if (!of_have_populated_dt()) { | ||
274 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, | ||
275 | &irq); | ||
276 | if (r) | ||
277 | return -ENXIO; | ||
278 | timer->irq = irq.start; | ||
279 | |||
280 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, | ||
281 | &mem); | ||
282 | if (r) | ||
283 | return -ENXIO; | ||
284 | |||
285 | /* Static mapping, never released */ | ||
286 | timer->io_base = ioremap(mem.start, mem.end - mem.start); | ||
287 | } | ||
288 | |||
289 | if (!timer->io_base) | 285 | if (!timer->io_base) |
290 | return -ENXIO; | 286 | return -ENXIO; |
291 | 287 | ||
292 | omap_hwmod_setup_one(oh_name); | 288 | omap_hwmod_setup_one(oh_name); |
293 | 289 | ||
294 | /* After the dmtimer is using hwmod these clocks won't be needed */ | 290 | /* After the dmtimer is using hwmod these clocks won't be needed */ |
295 | timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); | 291 | if (IS_ERR_OR_NULL(timer->fclk)) |
292 | timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); | ||
296 | if (IS_ERR(timer->fclk)) | 293 | if (IS_ERR(timer->fclk)) |
297 | return PTR_ERR(timer->fclk); | 294 | return PTR_ERR(timer->fclk); |
298 | 295 | ||
@@ -358,6 +355,14 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, | |||
358 | 3, /* Timer internal resynch latency */ | 355 | 3, /* Timer internal resynch latency */ |
359 | 0xffffffff); | 356 | 0xffffffff); |
360 | 357 | ||
358 | if (soc_is_am33xx() || soc_is_am43xx()) { | ||
359 | clockevent_gpt.suspend = omap_clkevt_idle; | ||
360 | clockevent_gpt.resume = omap_clkevt_unidle; | ||
361 | |||
362 | clockevent_gpt_hwmod = | ||
363 | omap_hwmod_lookup(clockevent_gpt.name); | ||
364 | } | ||
365 | |||
361 | pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, | 366 | pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, |
362 | clkev.rate); | 367 | clkev.rate); |
363 | } | 368 | } |
@@ -405,18 +410,15 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) | |||
405 | const char *oh_name = "counter_32k"; | 410 | const char *oh_name = "counter_32k"; |
406 | 411 | ||
407 | /* | 412 | /* |
408 | * If device-tree is present, then search the DT blob | 413 | * See if the 32kHz counter is supported. |
409 | * to see if the 32kHz counter is supported. | ||
410 | */ | 414 | */ |
411 | if (of_have_populated_dt()) { | 415 | np = omap_get_timer_dt(omap_counter_match, NULL); |
412 | np = omap_get_timer_dt(omap_counter_match, NULL); | 416 | if (!np) |
413 | if (!np) | 417 | return -ENODEV; |
414 | return -ENODEV; | 418 | |
415 | 419 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | |
416 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | 420 | if (!oh_name) |
417 | if (!oh_name) | 421 | return -ENODEV; |
418 | return -ENODEV; | ||
419 | } | ||
420 | 422 | ||
421 | /* | 423 | /* |
422 | * First check hwmod data is available for sync32k counter | 424 | * First check hwmod data is available for sync32k counter |
@@ -434,18 +436,6 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) | |||
434 | return ret; | 436 | return ret; |
435 | } | 437 | } |
436 | 438 | ||
437 | if (!of_have_populated_dt()) { | ||
438 | void __iomem *vbase; | ||
439 | |||
440 | vbase = omap_hwmod_get_mpu_rt_va(oh); | ||
441 | |||
442 | ret = omap_init_clocksource_32k(vbase); | ||
443 | if (ret) { | ||
444 | pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n", | ||
445 | __func__, ret); | ||
446 | omap_hwmod_idle(oh); | ||
447 | } | ||
448 | } | ||
449 | return ret; | 439 | return ret; |
450 | } | 440 | } |
451 | 441 | ||
@@ -661,96 +651,6 @@ void __init omap5_realtime_timer_init(void) | |||
661 | #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ | 651 | #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ |
662 | 652 | ||
663 | /** | 653 | /** |
664 | * omap_timer_init - build and register timer device with an | ||
665 | * associated timer hwmod | ||
666 | * @oh: timer hwmod pointer to be used to build timer device | ||
667 | * @user: parameter that can be passed from calling hwmod API | ||
668 | * | ||
669 | * Called by omap_hwmod_for_each_by_class to register each of the timer | ||
670 | * devices present in the system. The number of timer devices is known | ||
671 | * by parsing through the hwmod database for a given class name. At the | ||
672 | * end of function call memory is allocated for timer device and it is | ||
673 | * registered to the framework ready to be proved by the driver. | ||
674 | */ | ||
675 | static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) | ||
676 | { | ||
677 | int id; | ||
678 | int ret = 0; | ||
679 | char *name = "omap_timer"; | ||
680 | struct dmtimer_platform_data *pdata; | ||
681 | struct platform_device *pdev; | ||
682 | struct omap_timer_capability_dev_attr *timer_dev_attr; | ||
683 | |||
684 | pr_debug("%s: %s\n", __func__, oh->name); | ||
685 | |||
686 | /* on secure device, do not register secure timer */ | ||
687 | timer_dev_attr = oh->dev_attr; | ||
688 | if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr) | ||
689 | if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE) | ||
690 | return ret; | ||
691 | |||
692 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
693 | if (!pdata) { | ||
694 | pr_err("%s: No memory for [%s]\n", __func__, oh->name); | ||
695 | return -ENOMEM; | ||
696 | } | ||
697 | |||
698 | /* | ||
699 | * Extract the IDs from name field in hwmod database | ||
700 | * and use the same for constructing ids' for the | ||
701 | * timer devices. In a way, we are avoiding usage of | ||
702 | * static variable witin the function to do the same. | ||
703 | * CAUTION: We have to be careful and make sure the | ||
704 | * name in hwmod database does not change in which case | ||
705 | * we might either make corresponding change here or | ||
706 | * switch back static variable mechanism. | ||
707 | */ | ||
708 | sscanf(oh->name, "timer%2d", &id); | ||
709 | |||
710 | if (timer_dev_attr) | ||
711 | pdata->timer_capability = timer_dev_attr->timer_capability; | ||
712 | |||
713 | pdata->timer_errata = omap_dm_timer_get_errata(); | ||
714 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; | ||
715 | |||
716 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); | ||
717 | |||
718 | if (IS_ERR(pdev)) { | ||
719 | pr_err("%s: Can't build omap_device for %s: %s.\n", | ||
720 | __func__, name, oh->name); | ||
721 | ret = -EINVAL; | ||
722 | } | ||
723 | |||
724 | kfree(pdata); | ||
725 | |||
726 | return ret; | ||
727 | } | ||
728 | |||
729 | /** | ||
730 | * omap2_dm_timer_init - top level regular device initialization | ||
731 | * | ||
732 | * Uses dedicated hwmod api to parse through hwmod database for | ||
733 | * given class name and then build and register the timer device. | ||
734 | */ | ||
735 | static int __init omap2_dm_timer_init(void) | ||
736 | { | ||
737 | int ret; | ||
738 | |||
739 | /* If dtb is there, the devices will be created dynamically */ | ||
740 | if (of_have_populated_dt()) | ||
741 | return -ENODEV; | ||
742 | |||
743 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); | ||
744 | if (unlikely(ret)) { | ||
745 | pr_err("%s: device registration failed.\n", __func__); | ||
746 | return -EINVAL; | ||
747 | } | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | omap_arch_initcall(omap2_dm_timer_init); | ||
752 | |||
753 | /** | ||
754 | * omap2_override_clocksource - clocksource override with user configuration | 654 | * omap2_override_clocksource - clocksource override with user configuration |
755 | * | 655 | * |
756 | * Allows user to override default clocksource, using kernel parameter | 656 | * Allows user to override default clocksource, using kernel parameter |