Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // Copyright 2016 Freescale Semiconductor, Inc.
0004 // Copyright 2017 NXP
0005 
0006 #include <linux/clk.h>
0007 #include <linux/clockchips.h>
0008 #include <linux/clocksource.h>
0009 #include <linux/delay.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/sched_clock.h>
0012 
0013 #include "timer-of.h"
0014 
0015 #define TPM_PARAM           0x4
0016 #define TPM_PARAM_WIDTH_SHIFT       16
0017 #define TPM_PARAM_WIDTH_MASK        (0xff << 16)
0018 #define TPM_SC              0x10
0019 #define TPM_SC_CMOD_INC_PER_CNT     (0x1 << 3)
0020 #define TPM_SC_CMOD_DIV_DEFAULT     0x3
0021 #define TPM_SC_CMOD_DIV_MAX     0x7
0022 #define TPM_SC_TOF_MASK         (0x1 << 7)
0023 #define TPM_CNT             0x14
0024 #define TPM_MOD             0x18
0025 #define TPM_STATUS          0x1c
0026 #define TPM_STATUS_CH0F         BIT(0)
0027 #define TPM_C0SC            0x20
0028 #define TPM_C0SC_CHIE           BIT(6)
0029 #define TPM_C0SC_MODE_SHIFT     2
0030 #define TPM_C0SC_MODE_MASK      0x3c
0031 #define TPM_C0SC_MODE_SW_COMPARE    0x4
0032 #define TPM_C0SC_CHF_MASK       (0x1 << 7)
0033 #define TPM_C0V             0x24
0034 
0035 static int counter_width __ro_after_init;
0036 static void __iomem *timer_base __ro_after_init;
0037 
0038 static inline void tpm_timer_disable(void)
0039 {
0040     unsigned int val;
0041 
0042     /* channel disable */
0043     val = readl(timer_base + TPM_C0SC);
0044     val &= ~(TPM_C0SC_MODE_MASK | TPM_C0SC_CHIE);
0045     writel(val, timer_base + TPM_C0SC);
0046 }
0047 
0048 static inline void tpm_timer_enable(void)
0049 {
0050     unsigned int val;
0051 
0052     /* channel enabled in sw compare mode */
0053     val = readl(timer_base + TPM_C0SC);
0054     val |= (TPM_C0SC_MODE_SW_COMPARE << TPM_C0SC_MODE_SHIFT) |
0055            TPM_C0SC_CHIE;
0056     writel(val, timer_base + TPM_C0SC);
0057 }
0058 
0059 static inline void tpm_irq_acknowledge(void)
0060 {
0061     writel(TPM_STATUS_CH0F, timer_base + TPM_STATUS);
0062 }
0063 
0064 static inline unsigned long tpm_read_counter(void)
0065 {
0066     return readl(timer_base + TPM_CNT);
0067 }
0068 
0069 #if defined(CONFIG_ARM)
0070 static struct delay_timer tpm_delay_timer;
0071 
0072 static unsigned long tpm_read_current_timer(void)
0073 {
0074     return tpm_read_counter();
0075 }
0076 
0077 static u64 notrace tpm_read_sched_clock(void)
0078 {
0079     return tpm_read_counter();
0080 }
0081 #endif
0082 
0083 static int tpm_set_next_event(unsigned long delta,
0084                 struct clock_event_device *evt)
0085 {
0086     unsigned long next, now;
0087 
0088     next = tpm_read_counter();
0089     next += delta;
0090     writel(next, timer_base + TPM_C0V);
0091     now = tpm_read_counter();
0092 
0093     /*
0094      * NOTE: We observed in a very small probability, the bus fabric
0095      * contention between GPU and A7 may results a few cycles delay
0096      * of writing CNT registers which may cause the min_delta event got
0097      * missed, so we need add a ETIME check here in case it happened.
0098      */
0099     return (int)(next - now) <= 0 ? -ETIME : 0;
0100 }
0101 
0102 static int tpm_set_state_oneshot(struct clock_event_device *evt)
0103 {
0104     tpm_timer_enable();
0105 
0106     return 0;
0107 }
0108 
0109 static int tpm_set_state_shutdown(struct clock_event_device *evt)
0110 {
0111     tpm_timer_disable();
0112 
0113     return 0;
0114 }
0115 
0116 static irqreturn_t tpm_timer_interrupt(int irq, void *dev_id)
0117 {
0118     struct clock_event_device *evt = dev_id;
0119 
0120     tpm_irq_acknowledge();
0121 
0122     evt->event_handler(evt);
0123 
0124     return IRQ_HANDLED;
0125 }
0126 
0127 static struct timer_of to_tpm = {
0128     .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
0129     .clkevt = {
0130         .name           = "i.MX TPM Timer",
0131         .rating         = 200,
0132         .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ,
0133         .set_state_shutdown = tpm_set_state_shutdown,
0134         .set_state_oneshot  = tpm_set_state_oneshot,
0135         .set_next_event     = tpm_set_next_event,
0136         .cpumask        = cpu_possible_mask,
0137     },
0138     .of_irq = {
0139         .handler        = tpm_timer_interrupt,
0140         .flags          = IRQF_TIMER,
0141     },
0142     .of_clk = {
0143         .name = "per",
0144     },
0145 };
0146 
0147 static int __init tpm_clocksource_init(void)
0148 {
0149 #if defined(CONFIG_ARM)
0150     tpm_delay_timer.read_current_timer = &tpm_read_current_timer;
0151     tpm_delay_timer.freq = timer_of_rate(&to_tpm) >> 3;
0152     register_current_timer_delay(&tpm_delay_timer);
0153 
0154     sched_clock_register(tpm_read_sched_clock, counter_width,
0155                  timer_of_rate(&to_tpm) >> 3);
0156 #endif
0157 
0158     return clocksource_mmio_init(timer_base + TPM_CNT,
0159                      "imx-tpm",
0160                      timer_of_rate(&to_tpm) >> 3,
0161                      to_tpm.clkevt.rating,
0162                      counter_width,
0163                      clocksource_mmio_readl_up);
0164 }
0165 
0166 static void __init tpm_clockevent_init(void)
0167 {
0168     clockevents_config_and_register(&to_tpm.clkevt,
0169                     timer_of_rate(&to_tpm) >> 3,
0170                     300,
0171                     GENMASK(counter_width - 1,
0172                     1));
0173 }
0174 
0175 static int __init tpm_timer_init(struct device_node *np)
0176 {
0177     struct clk *ipg;
0178     int ret;
0179 
0180     ipg = of_clk_get_by_name(np, "ipg");
0181     if (IS_ERR(ipg)) {
0182         pr_err("tpm: failed to get ipg clk\n");
0183         return -ENODEV;
0184     }
0185     /* enable clk before accessing registers */
0186     ret = clk_prepare_enable(ipg);
0187     if (ret) {
0188         pr_err("tpm: ipg clock enable failed (%d)\n", ret);
0189         clk_put(ipg);
0190         return ret;
0191     }
0192 
0193     ret = timer_of_init(np, &to_tpm);
0194     if (ret)
0195         return ret;
0196 
0197     timer_base = timer_of_base(&to_tpm);
0198 
0199     counter_width = (readl(timer_base + TPM_PARAM)
0200         & TPM_PARAM_WIDTH_MASK) >> TPM_PARAM_WIDTH_SHIFT;
0201     /* use rating 200 for 32-bit counter and 150 for 16-bit counter */
0202     to_tpm.clkevt.rating = counter_width == 0x20 ? 200 : 150;
0203 
0204     /*
0205      * Initialize tpm module to a known state
0206      * 1) Counter disabled
0207      * 2) TPM counter operates in up counting mode
0208      * 3) Timer Overflow Interrupt disabled
0209      * 4) Channel0 disabled
0210      * 5) DMA transfers disabled
0211      */
0212     /* make sure counter is disabled */
0213     writel(0, timer_base + TPM_SC);
0214     /* TOF is W1C */
0215     writel(TPM_SC_TOF_MASK, timer_base + TPM_SC);
0216     writel(0, timer_base + TPM_CNT);
0217     /* CHF is W1C */
0218     writel(TPM_C0SC_CHF_MASK, timer_base + TPM_C0SC);
0219 
0220     /*
0221      * increase per cnt,
0222      * div 8 for 32-bit counter and div 128 for 16-bit counter
0223      */
0224     writel(TPM_SC_CMOD_INC_PER_CNT |
0225         (counter_width == 0x20 ?
0226         TPM_SC_CMOD_DIV_DEFAULT : TPM_SC_CMOD_DIV_MAX),
0227         timer_base + TPM_SC);
0228 
0229     /* set MOD register to maximum for free running mode */
0230     writel(GENMASK(counter_width - 1, 0), timer_base + TPM_MOD);
0231 
0232     tpm_clockevent_init();
0233 
0234     return tpm_clocksource_init();
0235 }
0236 TIMER_OF_DECLARE(imx7ulp, "fsl,imx7ulp-tpm", tpm_timer_init);