diff options
Diffstat (limited to 'drivers/clocksource/timer-imx-tpm.c')
| -rw-r--r-- | drivers/clocksource/timer-imx-tpm.c | 45 | 
1 files changed, 34 insertions, 11 deletions
| diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c index 21bffdcb2f20..6c8318470b48 100644 --- a/drivers/clocksource/timer-imx-tpm.c +++ b/drivers/clocksource/timer-imx-tpm.c @@ -17,9 +17,14 @@  #include <linux/of_irq.h>  #include <linux/sched_clock.h> +#define TPM_PARAM			0x4 +#define TPM_PARAM_WIDTH_SHIFT		16 +#define TPM_PARAM_WIDTH_MASK		(0xff << 16)  #define TPM_SC				0x10  #define TPM_SC_CMOD_INC_PER_CNT		(0x1 << 3)  #define TPM_SC_CMOD_DIV_DEFAULT		0x3 +#define TPM_SC_CMOD_DIV_MAX		0x7 +#define TPM_SC_TOF_MASK			(0x1 << 7)  #define TPM_CNT				0x14  #define TPM_MOD				0x18  #define TPM_STATUS			0x1c @@ -29,8 +34,11 @@  #define TPM_C0SC_MODE_SHIFT		2  #define TPM_C0SC_MODE_MASK		0x3c  #define TPM_C0SC_MODE_SW_COMPARE	0x4 +#define TPM_C0SC_CHF_MASK		(0x1 << 7)  #define TPM_C0V				0x24 +static int counter_width; +static int rating;  static void __iomem *timer_base;  static struct clock_event_device clockevent_tpm; @@ -83,10 +91,11 @@ static int __init tpm_clocksource_init(unsigned long rate)  	tpm_delay_timer.freq = rate;  	register_current_timer_delay(&tpm_delay_timer); -	sched_clock_register(tpm_read_sched_clock, 32, rate); +	sched_clock_register(tpm_read_sched_clock, counter_width, rate);  	return clocksource_mmio_init(timer_base + TPM_CNT, "imx-tpm", -				     rate, 200, 32, clocksource_mmio_readl_up); +				     rate, rating, counter_width, +				     clocksource_mmio_readl_up);  }  static int tpm_set_next_event(unsigned long delta, @@ -105,7 +114,7 @@ static int tpm_set_next_event(unsigned long delta,  	 * 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; +	return (int)(next - now) <= 0 ? -ETIME : 0;  }  static int tpm_set_state_oneshot(struct clock_event_device *evt) @@ -139,7 +148,6 @@ static struct clock_event_device clockevent_tpm = {  	.set_state_oneshot	= tpm_set_state_oneshot,  	.set_next_event		= tpm_set_next_event,  	.set_state_shutdown	= tpm_set_state_shutdown, -	.rating			= 200,  };  static int __init tpm_clockevent_init(unsigned long rate, int irq) @@ -149,10 +157,11 @@ static int __init tpm_clockevent_init(unsigned long rate, int irq)  	ret = request_irq(irq, tpm_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,  			  "i.MX7ULP TPM Timer", &clockevent_tpm); +	clockevent_tpm.rating = rating;  	clockevent_tpm.cpumask = cpumask_of(0);  	clockevent_tpm.irq = irq; -	clockevents_config_and_register(&clockevent_tpm, -					rate, 300, 0xfffffffe); +	clockevents_config_and_register(&clockevent_tpm, rate, 300, +					GENMASK(counter_width - 1, 1));  	return ret;  } @@ -179,7 +188,7 @@ static int __init tpm_timer_init(struct device_node *np)  	ipg = of_clk_get_by_name(np, "ipg");  	per = of_clk_get_by_name(np, "per");  	if (IS_ERR(ipg) || IS_ERR(per)) { -		pr_err("tpm: failed to get igp or per clk\n"); +		pr_err("tpm: failed to get ipg or per clk\n");  		ret = -ENODEV;  		goto err_clk_get;  	} @@ -197,6 +206,11 @@ static int __init tpm_timer_init(struct device_node *np)  		goto err_per_clk_enable;  	} +	counter_width = (readl(timer_base + TPM_PARAM) & TPM_PARAM_WIDTH_MASK) +		>> TPM_PARAM_WIDTH_SHIFT; +	/* use rating 200 for 32-bit counter and 150 for 16-bit counter */ +	rating = counter_width == 0x20 ? 200 : 150; +  	/*  	 * Initialize tpm module to a known state  	 * 1) Counter disabled @@ -205,16 +219,25 @@ static int __init tpm_timer_init(struct device_node *np)  	 * 4) Channel0 disabled  	 * 5) DMA transfers disabled  	 */ +	/* make sure counter is disabled */  	writel(0, timer_base + TPM_SC); +	/* TOF is W1C */ +	writel(TPM_SC_TOF_MASK, timer_base + TPM_SC);  	writel(0, timer_base + TPM_CNT); -	writel(0, timer_base + TPM_C0SC); +	/* CHF is W1C */ +	writel(TPM_C0SC_CHF_MASK, timer_base + TPM_C0SC); -	/* increase per cnt, div 8 by default */ -	writel(TPM_SC_CMOD_INC_PER_CNT | TPM_SC_CMOD_DIV_DEFAULT, +	/* +	 * increase per cnt, +	 * div 8 for 32-bit counter and div 128 for 16-bit counter +	 */ +	writel(TPM_SC_CMOD_INC_PER_CNT | +		(counter_width == 0x20 ? +		TPM_SC_CMOD_DIV_DEFAULT : TPM_SC_CMOD_DIV_MAX),  		     timer_base + TPM_SC);  	/* set MOD register to maximum for free running mode */ -	writel(0xffffffff, timer_base + TPM_MOD); +	writel(GENMASK(counter_width - 1, 0), timer_base + TPM_MOD);  	rate = clk_get_rate(per) >> 3;  	ret = tpm_clocksource_init(rate); | 
