LCOV - code coverage report
Current view: top level - drivers/clocksource - timer-sp804.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 124 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 11 0.0 %
Branches: 0 62 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  *  linux/drivers/clocksource/timer-sp.c
       4                 :            :  *
       5                 :            :  *  Copyright (C) 1999 - 2003 ARM Limited
       6                 :            :  *  Copyright (C) 2000 Deep Blue Solutions Ltd
       7                 :            :  */
       8                 :            : #include <linux/clk.h>
       9                 :            : #include <linux/clocksource.h>
      10                 :            : #include <linux/clockchips.h>
      11                 :            : #include <linux/err.h>
      12                 :            : #include <linux/interrupt.h>
      13                 :            : #include <linux/irq.h>
      14                 :            : #include <linux/io.h>
      15                 :            : #include <linux/of.h>
      16                 :            : #include <linux/of_address.h>
      17                 :            : #include <linux/of_clk.h>
      18                 :            : #include <linux/of_irq.h>
      19                 :            : #include <linux/sched_clock.h>
      20                 :            : 
      21                 :            : #include <clocksource/timer-sp804.h>
      22                 :            : 
      23                 :            : #include "timer-sp.h"
      24                 :            : 
      25                 :          0 : static long __init sp804_get_clock_rate(struct clk *clk)
      26                 :            : {
      27                 :            :         long rate;
      28                 :            :         int err;
      29                 :            : 
      30                 :          0 :         err = clk_prepare(clk);
      31         [ #  # ]:          0 :         if (err) {
      32                 :          0 :                 pr_err("sp804: clock failed to prepare: %d\n", err);
      33                 :          0 :                 clk_put(clk);
      34                 :          0 :                 return err;
      35                 :            :         }
      36                 :            : 
      37                 :          0 :         err = clk_enable(clk);
      38         [ #  # ]:          0 :         if (err) {
      39                 :          0 :                 pr_err("sp804: clock failed to enable: %d\n", err);
      40                 :          0 :                 clk_unprepare(clk);
      41                 :          0 :                 clk_put(clk);
      42                 :          0 :                 return err;
      43                 :            :         }
      44                 :            : 
      45                 :          0 :         rate = clk_get_rate(clk);
      46         [ #  # ]:          0 :         if (rate < 0) {
      47                 :          0 :                 pr_err("sp804: clock failed to get rate: %ld\n", rate);
      48                 :          0 :                 clk_disable(clk);
      49                 :          0 :                 clk_unprepare(clk);
      50                 :          0 :                 clk_put(clk);
      51                 :            :         }
      52                 :            : 
      53                 :          0 :         return rate;
      54                 :            : }
      55                 :            : 
      56                 :            : static void __iomem *sched_clock_base;
      57                 :            : 
      58                 :          0 : static u64 notrace sp804_read(void)
      59                 :            : {
      60                 :          0 :         return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
      61                 :            : }
      62                 :            : 
      63                 :          0 : void __init sp804_timer_disable(void __iomem *base)
      64                 :            : {
      65                 :          0 :         writel(0, base + TIMER_CTRL);
      66                 :          0 : }
      67                 :            : 
      68                 :          0 : int  __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
      69                 :            :                                                      const char *name,
      70                 :            :                                                      struct clk *clk,
      71                 :            :                                                      int use_sched_clock)
      72                 :            : {
      73                 :            :         long rate;
      74                 :            : 
      75         [ #  # ]:          0 :         if (!clk) {
      76                 :          0 :                 clk = clk_get_sys("sp804", name);
      77         [ #  # ]:          0 :                 if (IS_ERR(clk)) {
      78                 :          0 :                         pr_err("sp804: clock not found: %d\n",
      79                 :            :                                (int)PTR_ERR(clk));
      80                 :          0 :                         return PTR_ERR(clk);
      81                 :            :                 }
      82                 :            :         }
      83                 :            : 
      84                 :          0 :         rate = sp804_get_clock_rate(clk);
      85         [ #  # ]:          0 :         if (rate < 0)
      86                 :            :                 return -EINVAL;
      87                 :            : 
      88                 :            :         /* setup timer 0 as free-running clocksource */
      89                 :          0 :         writel(0, base + TIMER_CTRL);
      90                 :          0 :         writel(0xffffffff, base + TIMER_LOAD);
      91                 :          0 :         writel(0xffffffff, base + TIMER_VALUE);
      92                 :          0 :         writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
      93                 :            :                 base + TIMER_CTRL);
      94                 :            : 
      95                 :          0 :         clocksource_mmio_init(base + TIMER_VALUE, name,
      96                 :            :                 rate, 200, 32, clocksource_mmio_readl_down);
      97                 :            : 
      98         [ #  # ]:          0 :         if (use_sched_clock) {
      99                 :          0 :                 sched_clock_base = base;
     100                 :          0 :                 sched_clock_register(sp804_read, 32, rate);
     101                 :            :         }
     102                 :            : 
     103                 :            :         return 0;
     104                 :            : }
     105                 :            : 
     106                 :            : 
     107                 :            : static void __iomem *clkevt_base;
     108                 :            : static unsigned long clkevt_reload;
     109                 :            : 
     110                 :            : /*
     111                 :            :  * IRQ handler for the timer
     112                 :            :  */
     113                 :          0 : static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
     114                 :            : {
     115                 :            :         struct clock_event_device *evt = dev_id;
     116                 :            : 
     117                 :            :         /* clear the interrupt */
     118                 :          0 :         writel(1, clkevt_base + TIMER_INTCLR);
     119                 :            : 
     120                 :          0 :         evt->event_handler(evt);
     121                 :            : 
     122                 :          0 :         return IRQ_HANDLED;
     123                 :            : }
     124                 :            : 
     125                 :            : static inline void timer_shutdown(struct clock_event_device *evt)
     126                 :            : {
     127                 :          0 :         writel(0, clkevt_base + TIMER_CTRL);
     128                 :            : }
     129                 :            : 
     130                 :          0 : static int sp804_shutdown(struct clock_event_device *evt)
     131                 :            : {
     132                 :            :         timer_shutdown(evt);
     133                 :          0 :         return 0;
     134                 :            : }
     135                 :            : 
     136                 :          0 : static int sp804_set_periodic(struct clock_event_device *evt)
     137                 :            : {
     138                 :            :         unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
     139                 :            :                              TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
     140                 :            : 
     141                 :            :         timer_shutdown(evt);
     142                 :          0 :         writel(clkevt_reload, clkevt_base + TIMER_LOAD);
     143                 :          0 :         writel(ctrl, clkevt_base + TIMER_CTRL);
     144                 :          0 :         return 0;
     145                 :            : }
     146                 :            : 
     147                 :          0 : static int sp804_set_next_event(unsigned long next,
     148                 :            :         struct clock_event_device *evt)
     149                 :            : {
     150                 :            :         unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
     151                 :            :                              TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
     152                 :            : 
     153                 :          0 :         writel(next, clkevt_base + TIMER_LOAD);
     154                 :          0 :         writel(ctrl, clkevt_base + TIMER_CTRL);
     155                 :            : 
     156                 :          0 :         return 0;
     157                 :            : }
     158                 :            : 
     159                 :            : static struct clock_event_device sp804_clockevent = {
     160                 :            :         .features               = CLOCK_EVT_FEAT_PERIODIC |
     161                 :            :                                   CLOCK_EVT_FEAT_ONESHOT |
     162                 :            :                                   CLOCK_EVT_FEAT_DYNIRQ,
     163                 :            :         .set_state_shutdown     = sp804_shutdown,
     164                 :            :         .set_state_periodic     = sp804_set_periodic,
     165                 :            :         .set_state_oneshot      = sp804_shutdown,
     166                 :            :         .tick_resume            = sp804_shutdown,
     167                 :            :         .set_next_event         = sp804_set_next_event,
     168                 :            :         .rating                 = 300,
     169                 :            : };
     170                 :            : 
     171                 :            : static struct irqaction sp804_timer_irq = {
     172                 :            :         .name           = "timer",
     173                 :            :         .flags          = IRQF_TIMER | IRQF_IRQPOLL,
     174                 :            :         .handler        = sp804_timer_interrupt,
     175                 :            :         .dev_id         = &sp804_clockevent,
     176                 :            : };
     177                 :            : 
     178                 :          0 : int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
     179                 :            : {
     180                 :            :         struct clock_event_device *evt = &sp804_clockevent;
     181                 :            :         long rate;
     182                 :            : 
     183         [ #  # ]:          0 :         if (!clk)
     184                 :          0 :                 clk = clk_get_sys("sp804", name);
     185         [ #  # ]:          0 :         if (IS_ERR(clk)) {
     186                 :          0 :                 pr_err("sp804: %s clock not found: %d\n", name,
     187                 :            :                         (int)PTR_ERR(clk));
     188                 :          0 :                 return PTR_ERR(clk);
     189                 :            :         }
     190                 :            : 
     191                 :          0 :         rate = sp804_get_clock_rate(clk);
     192         [ #  # ]:          0 :         if (rate < 0)
     193                 :            :                 return -EINVAL;
     194                 :            : 
     195                 :          0 :         clkevt_base = base;
     196         [ #  # ]:          0 :         clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
     197                 :          0 :         evt->name = name;
     198                 :          0 :         evt->irq = irq;
     199                 :          0 :         evt->cpumask = cpu_possible_mask;
     200                 :            : 
     201                 :          0 :         writel(0, base + TIMER_CTRL);
     202                 :            : 
     203                 :          0 :         setup_irq(irq, &sp804_timer_irq);
     204                 :          0 :         clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
     205                 :            : 
     206                 :          0 :         return 0;
     207                 :            : }
     208                 :            : 
     209                 :          0 : static int __init sp804_of_init(struct device_node *np)
     210                 :            : {
     211                 :            :         static bool initialized = false;
     212                 :            :         void __iomem *base;
     213                 :            :         int irq, ret = -EINVAL;
     214                 :          0 :         u32 irq_num = 0;
     215                 :            :         struct clk *clk1, *clk2;
     216                 :          0 :         const char *name = of_get_property(np, "compatible", NULL);
     217                 :            : 
     218                 :          0 :         base = of_iomap(np, 0);
     219         [ #  # ]:          0 :         if (!base)
     220                 :            :                 return -ENXIO;
     221                 :            : 
     222                 :            :         /* Ensure timers are disabled */
     223                 :          0 :         writel(0, base + TIMER_CTRL);
     224                 :          0 :         writel(0, base + TIMER_2_BASE + TIMER_CTRL);
     225                 :            : 
     226   [ #  #  #  # ]:          0 :         if (initialized || !of_device_is_available(np)) {
     227                 :            :                 ret = -EINVAL;
     228                 :            :                 goto err;
     229                 :            :         }
     230                 :            : 
     231                 :          0 :         clk1 = of_clk_get(np, 0);
     232         [ #  # ]:          0 :         if (IS_ERR(clk1))
     233                 :            :                 clk1 = NULL;
     234                 :            : 
     235                 :            :         /* Get the 2nd clock if the timer has 3 timer clocks */
     236         [ #  # ]:          0 :         if (of_clk_get_parent_count(np) == 3) {
     237                 :          0 :                 clk2 = of_clk_get(np, 1);
     238         [ #  # ]:          0 :                 if (IS_ERR(clk2)) {
     239                 :          0 :                         pr_err("sp804: %pOFn clock not found: %d\n", np,
     240                 :            :                                 (int)PTR_ERR(clk2));
     241                 :            :                         clk2 = NULL;
     242                 :            :                 }
     243                 :            :         } else
     244                 :            :                 clk2 = clk1;
     245                 :            : 
     246                 :          0 :         irq = irq_of_parse_and_map(np, 0);
     247         [ #  # ]:          0 :         if (irq <= 0)
     248                 :            :                 goto err;
     249                 :            : 
     250                 :            :         of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
     251         [ #  # ]:          0 :         if (irq_num == 2) {
     252                 :            : 
     253                 :          0 :                 ret = __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
     254         [ #  # ]:          0 :                 if (ret)
     255                 :            :                         goto err;
     256                 :            : 
     257                 :          0 :                 ret = __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1);
     258         [ #  # ]:          0 :                 if (ret)
     259                 :            :                         goto err;
     260                 :            :         } else {
     261                 :            : 
     262                 :          0 :                 ret = __sp804_clockevents_init(base, irq, clk1 , name);
     263         [ #  # ]:          0 :                 if (ret)
     264                 :            :                         goto err;
     265                 :            : 
     266                 :          0 :                 ret =__sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
     267                 :            :                                                               name, clk2, 1);
     268         [ #  # ]:          0 :                 if (ret)
     269                 :            :                         goto err;
     270                 :            :         }
     271                 :          0 :         initialized = true;
     272                 :            : 
     273                 :          0 :         return 0;
     274                 :            : err:
     275                 :          0 :         iounmap(base);
     276                 :          0 :         return ret;
     277                 :            : }
     278                 :            : TIMER_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
     279                 :            : 
     280                 :          0 : static int __init integrator_cp_of_init(struct device_node *np)
     281                 :            : {
     282                 :            :         static int init_count = 0;
     283                 :            :         void __iomem *base;
     284                 :            :         int irq, ret = -EINVAL;
     285                 :          0 :         const char *name = of_get_property(np, "compatible", NULL);
     286                 :            :         struct clk *clk;
     287                 :            : 
     288                 :          0 :         base = of_iomap(np, 0);
     289         [ #  # ]:          0 :         if (!base) {
     290                 :          0 :                 pr_err("Failed to iomap\n");
     291                 :          0 :                 return -ENXIO;
     292                 :            :         }
     293                 :            : 
     294                 :          0 :         clk = of_clk_get(np, 0);
     295         [ #  # ]:          0 :         if (IS_ERR(clk)) {
     296                 :          0 :                 pr_err("Failed to get clock\n");
     297                 :          0 :                 return PTR_ERR(clk);
     298                 :            :         }
     299                 :            : 
     300                 :            :         /* Ensure timer is disabled */
     301                 :          0 :         writel(0, base + TIMER_CTRL);
     302                 :            : 
     303   [ #  #  #  # ]:          0 :         if (init_count == 2 || !of_device_is_available(np))
     304                 :            :                 goto err;
     305                 :            : 
     306         [ #  # ]:          0 :         if (!init_count) {
     307                 :          0 :                 ret = __sp804_clocksource_and_sched_clock_init(base, name, clk, 0);
     308         [ #  # ]:          0 :                 if (ret)
     309                 :            :                         goto err;
     310                 :            :         } else {
     311                 :          0 :                 irq = irq_of_parse_and_map(np, 0);
     312         [ #  # ]:          0 :                 if (irq <= 0)
     313                 :            :                         goto err;
     314                 :            : 
     315                 :          0 :                 ret = __sp804_clockevents_init(base, irq, clk, name);
     316         [ #  # ]:          0 :                 if (ret)
     317                 :            :                         goto err;
     318                 :            :         }
     319                 :            : 
     320                 :          0 :         init_count++;
     321                 :          0 :         return 0;
     322                 :            : err:
     323                 :          0 :         iounmap(base);
     324                 :          0 :         return ret;
     325                 :            : }
     326                 :            : TIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);

Generated by: LCOV version 1.14