On 03/04/2019 16:11, Alexandre Belloni wrote:
> atmel_tclib is probed too late in the boot process to be able to use the
> TCB as the boot clocksource. This is an issue for SoCs without the PIT
> (sams70, samv70 and samv71 families) as they simply currently can't boot.
> 
> Get rid of the atmel_tclib dependency and probe everything on our own using
> the correct device tree binding.
> 
> This also allows getting rid of ATMEL_TCB_CLKSRC_BLOCK and makes the driver
> a bit more flexible as the TCB is not hardcoded in the kernel anymore.
> 
> Signed-off-by: Alexandre Belloni <[email protected]>
> ---
>  drivers/clocksource/tcb_clksrc.c | 103 +++++++++++++++++++------------
>  drivers/misc/Kconfig             |  14 +----
>  2 files changed, 66 insertions(+), 51 deletions(-)
> 
> diff --git a/drivers/clocksource/tcb_clksrc.c 
> b/drivers/clocksource/tcb_clksrc.c
> index 138a12090149..c7eec9808289 100644
> --- a/drivers/clocksource/tcb_clksrc.c
> +++ b/drivers/clocksource/tcb_clksrc.c
> @@ -9,7 +9,8 @@
>  #include <linux/err.h>
>  #include <linux/ioport.h>
>  #include <linux/io.h>
> -#include <linux/platform_device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
>  #include <linux/syscore_ops.h>
>  #include <soc/at91/atmel_tcb.h>
>  
> @@ -28,13 +29,6 @@
>   *     source, used in either periodic or oneshot mode.  This runs
>   *     at 32 KiHZ, and can handle delays of up to two seconds.
>   *
> - * A boot clocksource and clockevent source are also currently needed,
> - * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
> - * this code can be used when init_timers() is called, well before most
> - * devices are set up.  (Some low end AT91 parts, which can run uClinux,
> - * have only the timers in one TC block... they currently don't support
> - * the tclib code, because of that initialization issue.)
> - *
>   * REVISIT behavior during system suspend states... we should disable
>   * all clocks and save the power.  Easily done for clockevent devices,
>   * but clocksources won't necessarily get the needed notifications.
> @@ -112,7 +106,6 @@ void tc_clksrc_resume(struct clocksource *cs)
>  }
>  
>  static struct clocksource clksrc = {
> -     .name           = "tcb_clksrc",
>       .rating         = 200,
>       .read           = tc_get_cycles,
>       .mask           = CLOCKSOURCE_MASK(32),
> @@ -214,7 +207,6 @@ static int tc_next_event(unsigned long delta, struct 
> clock_event_device *d)
>  
>  static struct tc_clkevt_device clkevt = {
>       .clkevt = {
> -             .name                   = "tc_clkevt",
>               .features               = CLOCK_EVT_FEAT_PERIODIC |
>                                         CLOCK_EVT_FEAT_ONESHOT,
>               /* Should be lower than at91rm9200's system timer */
> @@ -330,33 +322,64 @@ static void __init tcb_setup_single_chan(struct 
> atmel_tc *tc, int mck_divisor_id
>       writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
>  }
>  
> -static int __init tcb_clksrc_init(void)
> +static int __init tcb_clksrc_init(struct device_node *node)
>  {
> -     static char bootinfo[] __initdata
> -             = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
> -
> -     struct platform_device *pdev;
> -     struct atmel_tc *tc;
> +     struct atmel_tc tc;
>       struct clk *t0_clk;
> +     const struct of_device_id *match;
> +     int irq;
>       u32 rate, divided_rate = 0;
>       int best_divisor_idx = -1;
>       int clk32k_divisor_idx = -1;
>       int i;
>       int ret;
>  
> -     tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK);
> -     if (!tc) {
> -             pr_debug("can't alloc TC for clocksource\n");
> -             return -ENODEV;
> -     }
> -     tcaddr = tc->regs;
> -     pdev = tc->pdev;
> +     /* Protect against multiple calls */
> +     if (tcaddr)
> +             return 0;
> +
> +     tc.regs = of_iomap(node->parent, 0);
> +     if (!tc.regs)
> +             return -ENXIO;
> +
> +     t0_clk = of_clk_get_by_name(node->parent, "t0_clk");
> +     if (IS_ERR(t0_clk))
> +             return PTR_ERR(t0_clk);
> +
> +     tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");
> +     if (IS_ERR(tc.slow_clk))
> +             return PTR_ERR(tc.slow_clk);
> +
> +     irq = of_irq_get(node->parent, 0);
> +     if (irq <= 0)
> +             return -EINVAL;
> +
> +     tc.clk[0] = t0_clk;
> +     tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");
> +     if (IS_ERR(tc.clk[1]))
> +             tc.clk[1] = t0_clk;
> +     tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");
> +     if (IS_ERR(tc.clk[2]))
> +             tc.clk[2] = t0_clk;
> +     tc.irq[0] = irq;
> +     tc.irq[1] = of_irq_get(node->parent, 1);
> +     if (tc.irq[1] <= 0)
> +             tc.irq[1] = irq;
> +     tc.irq[2] = of_irq_get(node->parent, 2);
> +     if (tc.irq[2] <= 0)
> +             tc.irq[2] = irq;

Why are clk[1/2] and irq[1/2] defaulting back to t0 in case of error?


[ ... ]



-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

Reply via email to