summaryrefslogtreecommitdiff
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorDong Aisheng <aisheng.dong@nxp.com>2017-09-06 21:28:05 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit7bb9b38d18dd0b3144eafebaa522311ac49aeca0 (patch)
tree0706f21856bec0e84159ce36cbc0d58816ae4a50 /drivers/clocksource
parent493b06d6f4dfdf67665d579236605e8480743328 (diff)
MLK-17491-20 clocksource: imx-tpm: code cleanup and improvement
1) replace magic number with macros 2) add more code comments 3) replace setup_irq with request_irq as no need use setup_irq 4) replace __raw_readl which has endian issue with readl (so far endian issue not exist on IMX, but better write more robust code in advance) 5) remove the last meaningless timer_base read No function level change. Cc: Shenwei Wang <shenwei.wang@nxp.com> Reviewed-by: Bai Ping <ping.bai@nxp.com> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/timer-imx-tpm.c133
1 files changed, 73 insertions, 60 deletions
diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c
index 08d01c83e973..f1c87a27ec46 100644
--- a/drivers/clocksource/timer-imx-tpm.c
+++ b/drivers/clocksource/timer-imx-tpm.c
@@ -8,27 +8,28 @@
* of the License, or (at your option) any later version.
*/
-#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
-#define TPM_GLOBAL 0x8
-
-#define TPM_SC 0x10
-#define TPM_CNT 0x14
-#define TPM_MOD 0x18
-#define TPM_STATUS 0x1c
-#define TPM_C0SC 0x20
-#define TPM_C0V 0x24
-
-#define TPM_STATUS_CH0F 0x1
-
-#define TPM_C0SC_MSA 0x4
+#define TPM_SC 0x10
+#define TPM_SC_CMOD_INC_PER_CNT (0x1 << 3)
+#define TPM_SC_CMOD_DIV_DEFAULT 0x3
+#define TPM_CNT 0x14
+#define TPM_MOD 0x18
+#define TPM_STATUS 0x1c
+#define TPM_STATUS_CH0F BIT(0)
+#define TPM_C0SC 0x20
+#define TPM_C0SC_CHIE BIT(6)
+#define TPM_C0SC_MODE_SHIFT 2
+#define TPM_C0SC_MODE_MASK 0x3c
+#define TPM_C0SC_MODE_SW_COMPARE 0x4
+#define TPM_C0V 0x24
static void __iomem *timer_base;
static struct clock_event_device clockevent_tpm;
@@ -37,35 +38,43 @@ static inline void tpm_timer_disable(void)
{
unsigned int val;
- val = __raw_readl(timer_base + TPM_C0SC);
- val &= ~(0x5 << TPM_C0SC_MSA);
- __raw_writel(val, timer_base + TPM_C0SC);
+ /* channel disable */
+ val = readl(timer_base + TPM_C0SC);
+ val &= ~(TPM_C0SC_MODE_MASK | TPM_C0SC_CHIE);
+ writel(val, timer_base + TPM_C0SC);
}
static inline void tpm_timer_enable(void)
{
unsigned int val;
- val = __raw_readl(timer_base + TPM_C0SC);
- val |= (0x5 << TPM_C0SC_MSA);
- __raw_writel(val, timer_base + TPM_C0SC);
+ /* channel enabled in sw compare mode */
+ val = readl(timer_base + TPM_C0SC);
+ val |= (TPM_C0SC_MODE_SW_COMPARE << TPM_C0SC_MODE_SHIFT) |
+ TPM_C0SC_CHIE;
+ writel(val, timer_base + TPM_C0SC);
}
static inline void tpm_irq_acknowledge(void)
{
- __raw_writel(1, timer_base + TPM_STATUS);
+ writel(TPM_STATUS_CH0F, timer_base + TPM_STATUS);
}
static struct delay_timer tpm_delay_timer;
+static inline unsigned long tpm_read_counter(void)
+{
+ return readl(timer_base + TPM_CNT);
+}
+
static unsigned long tpm_read_current_timer(void)
{
- return __raw_readl(timer_base + TPM_CNT);
+ return tpm_read_counter();
}
static u64 notrace tpm_read_sched_clock(void)
{
- return __raw_readl(timer_base + TPM_CNT);
+ return tpm_read_counter();
}
static int __init tpm_clocksource_init(unsigned long rate)
@@ -75,27 +84,32 @@ static int __init tpm_clocksource_init(unsigned long rate)
register_current_timer_delay(&tpm_delay_timer);
sched_clock_register(tpm_read_sched_clock, 32, rate);
+
return clocksource_mmio_init(timer_base + TPM_CNT, "imx-tpm",
- rate, 200, 32, clocksource_mmio_readl_up);
+ rate, 200, 32, clocksource_mmio_readl_up);
}
static int tpm_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
- unsigned long next, now, ret;
-
- now = __raw_readl(timer_base + TPM_CNT);
- next = now + delta;
- __raw_writel(next, timer_base + TPM_C0V);
- now = __raw_readl(timer_base + TPM_CNT);
-
- ret = next - now;
- return (ret > delta) ? -ETIME : 0;
+ unsigned long next, now;
+
+ next = tpm_read_counter();
+ next += delta;
+ writel(next, timer_base + TPM_C0V);
+ now = tpm_read_counter();
+
+ /*
+ * NOTE: We observed in a very small probability, the bus fabric
+ * contention between GPU and A7 may results a few cycles delay
+ * of writing CNT registers which may cause the min_delta event got
+ * missed, so we need add a ETIME check here in case it happened.
+ */
+ return (int)((next - now) <= 0) ? -ETIME : 0;
}
static int tpm_set_state_oneshot(struct clock_event_device *evt)
{
- /* enable timer */
tpm_timer_enable();
return 0;
@@ -103,7 +117,6 @@ static int tpm_set_state_oneshot(struct clock_event_device *evt)
static int tpm_set_state_shutdown(struct clock_event_device *evt)
{
- /* disable timer */
tpm_timer_disable();
return 0;
@@ -111,7 +124,7 @@ static int tpm_set_state_shutdown(struct clock_event_device *evt)
static irqreturn_t tpm_timer_interrupt(int irq, void *dev_id)
{
- struct clock_event_device *evt = &clockevent_tpm;
+ struct clock_event_device *evt = dev_id;
tpm_irq_acknowledge();
@@ -121,7 +134,7 @@ static irqreturn_t tpm_timer_interrupt(int irq, void *dev_id)
}
static struct clock_event_device clockevent_tpm = {
- .name = "i.MX7ULP tpm timer",
+ .name = "i.MX7ULP TPM Timer",
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_state_oneshot = tpm_set_state_oneshot,
.set_next_event = tpm_set_next_event,
@@ -129,30 +142,24 @@ static struct clock_event_device clockevent_tpm = {
.rating = 200,
};
-static struct irqaction tpm_timer_irq = {
- .name = "i.MX7ULP tpm timer",
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- .handler = tpm_timer_interrupt,
- .dev_id = &clockevent_tpm,
-};
-
static int __init tpm_clockevent_init(unsigned long rate, int irq)
{
- /* init the channel */
- setup_irq(irq, &tpm_timer_irq);
+ int ret;
+
+ ret = request_irq(irq, tpm_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+ "i.MX7ULP TPM Timer", &clockevent_tpm);
clockevent_tpm.cpumask = cpumask_of(0);
clockevent_tpm.irq = irq;
clockevents_config_and_register(&clockevent_tpm,
- rate, 300, 0xfffffffe);
+ rate, 300, 0xfffffffe);
- return 0;
+ return ret;
}
static int __init tpm_timer_init(struct device_node *np)
{
struct clk *ipg, *per;
- uint32_t val;
int irq, ret;
u32 rate;
@@ -190,16 +197,24 @@ static int __init tpm_timer_init(struct device_node *np)
goto err_per_clk_enable;
}
- /* Initialize tpm module to a known state(counter disabled). */
- __raw_writel(0, timer_base + TPM_SC);
- __raw_writel(0, timer_base + TPM_CNT);
- __raw_writel(0, timer_base + TPM_C0SC);
-
- /* set the prescale div, div by 8 = 3MHz */
- __raw_writel(0xb, timer_base + TPM_SC);
-
- /* set the MOD register to 0xffffffff for free running counter */
- __raw_writel(0xffffffff, timer_base + TPM_MOD);
+ /*
+ * Initialize tpm module to a known state
+ * 1) Counter disabled
+ * 2) TPM counter operates in up counting mode
+ * 3) Timer Overflow Interrupt disabled
+ * 4) Channel0 disabled
+ * 5) DMA transfers disabled
+ */
+ writel(0, timer_base + TPM_SC);
+ writel(0, timer_base + TPM_CNT);
+ writel(0, timer_base + TPM_C0SC);
+
+ /* increase per cnt, div 8 by default */
+ writel(TPM_SC_CMOD_INC_PER_CNT | TPM_SC_CMOD_DIV_DEFAULT,
+ timer_base + TPM_SC);
+
+ /* set MOD register to maximum for free running mode */
+ writel(0xffffffff, timer_base + TPM_MOD);
rate = clk_get_rate(per) >> 3;
ret = tpm_clocksource_init(rate);
@@ -210,8 +225,6 @@ static int __init tpm_timer_init(struct device_node *np)
if (ret)
goto err_per_clk_enable;
- val = __raw_readl(timer_base);
-
return 0;
err_per_clk_enable: