aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2018-03-07 10:16:07 -0500
committerArnd Bergmann <arnd@arndb.de>2018-03-07 10:16:07 -0500
commit6f566c4f304de8a90d520f7ca1925b4ea7dc3581 (patch)
treedee0e7650ce7896509fd3d47f45d1da3ec59094f /include
parent7b80bd29482e692a7286897f4a684ee18dee0f36 (diff)
parent58a54f03e73d67432216931854363e4ba15839b9 (diff)
Merge tag 'omap-for-v4.17/timer-signed' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc
Pull "Move omap timer to drivers for 4.17" from Tony Lindgren: This series from Keerthy and Ladislav Michl move omap dmtimer code to drivers. As we don't want to export custom timer functions to random drivers, we also need to update the related PWM driver to pass the timer specific functions in platform data. Note that this series is based on a merge of omap1 specific timer fix and omap2+ platform data clean-up to keep things working and make the move a bit simpler. * tag 'omap-for-v4.17/timer-signed' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: clocksource: timer-ti-dm: Check prescaler value clocksource: timer-ti-dm: Consolidate set source clocksource: timer-ti-dm: Make unexported functions static ARM: OMAP: pdata-quirks: Remove unused timer pdata pwm: pwm-omap-dmtimer: Adapt driver to utilize dmtimer pdata ops clocksource: timer-ti-dm: Hook device platform data if not already assigned clocksource: timer-ti-dm: Populate the timer ops to the pdata clocksource: timer-ti-dm: Add timer ops to the platform data structure ARM: OMAP: Move dmtimer driver out of plat-omap to drivers under clocksource clocksource: timer-ti-dm: Replace architecture ARM: OMAP: Move dmtimer.h out of plat-omap ARM: OMAP: timer: Wrap the inline functions under OMAP2PLUS define ARM: OMAP: dmtimer: Remove all the exports ARM: OMAP: Fix dmtimer init for omap1
Diffstat (limited to 'include')
-rw-r--r--include/clocksource/timer-ti-dm.h394
-rw-r--r--include/linux/platform_data/dmtimer-omap.h38
2 files changed, 432 insertions, 0 deletions
diff --git a/include/clocksource/timer-ti-dm.h b/include/clocksource/timer-ti-dm.h
new file mode 100644
index 000000000000..7d9598dc578d
--- /dev/null
+++ b/include/clocksource/timer-ti-dm.h
@@ -0,0 +1,394 @@
1/*
2 * OMAP Dual-Mode Timers
3 *
4 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
5 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
6 * Thara Gopinath <thara@ti.com>
7 *
8 * Platform device conversion and hwmod support.
9 *
10 * Copyright (C) 2005 Nokia Corporation
11 * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
12 * PWM and clock framwork support by Timo Teras.
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 *
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * You should have received a copy of the GNU General Public License along
29 * with this program; if not, write to the Free Software Foundation, Inc.,
30 * 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32
33#include <linux/delay.h>
34#include <linux/io.h>
35#include <linux/platform_device.h>
36
37#ifndef __CLOCKSOURCE_DMTIMER_H
38#define __CLOCKSOURCE_DMTIMER_H
39
40/* clock sources */
41#define OMAP_TIMER_SRC_SYS_CLK 0x00
42#define OMAP_TIMER_SRC_32_KHZ 0x01
43#define OMAP_TIMER_SRC_EXT_CLK 0x02
44
45/* timer interrupt enable bits */
46#define OMAP_TIMER_INT_CAPTURE (1 << 2)
47#define OMAP_TIMER_INT_OVERFLOW (1 << 1)
48#define OMAP_TIMER_INT_MATCH (1 << 0)
49
50/* trigger types */
51#define OMAP_TIMER_TRIGGER_NONE 0x00
52#define OMAP_TIMER_TRIGGER_OVERFLOW 0x01
53#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
54
55/* posted mode types */
56#define OMAP_TIMER_NONPOSTED 0x00
57#define OMAP_TIMER_POSTED 0x01
58
59/* timer capabilities used in hwmod database */
60#define OMAP_TIMER_SECURE 0x80000000
61#define OMAP_TIMER_ALWON 0x40000000
62#define OMAP_TIMER_HAS_PWM 0x20000000
63#define OMAP_TIMER_NEEDS_RESET 0x10000000
64#define OMAP_TIMER_HAS_DSP_IRQ 0x08000000
65
66/*
67 * timer errata flags
68 *
69 * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This
70 * errata prevents us from using posted mode on these devices, unless the
71 * timer counter register is never read. For more details please refer to
72 * the OMAP3/4/5 errata documents.
73 */
74#define OMAP_TIMER_ERRATA_I103_I767 0x80000000
75
76struct timer_regs {
77 u32 tidr;
78 u32 tier;
79 u32 twer;
80 u32 tclr;
81 u32 tcrr;
82 u32 tldr;
83 u32 ttrg;
84 u32 twps;
85 u32 tmar;
86 u32 tcar1;
87 u32 tsicr;
88 u32 tcar2;
89 u32 tpir;
90 u32 tnir;
91 u32 tcvr;
92 u32 tocr;
93 u32 towr;
94};
95
96struct omap_dm_timer {
97 int id;
98 int irq;
99 struct clk *fclk;
100
101 void __iomem *io_base;
102 void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */
103 void __iomem *irq_ena; /* irq enable */
104 void __iomem *irq_dis; /* irq disable, only on v2 ip */
105 void __iomem *pend; /* write pending */
106 void __iomem *func_base; /* function register base */
107
108 unsigned long rate;
109 unsigned reserved:1;
110 unsigned posted:1;
111 struct timer_regs context;
112 int (*get_context_loss_count)(struct device *);
113 int ctx_loss_count;
114 int revision;
115 u32 capability;
116 u32 errata;
117 struct platform_device *pdev;
118 struct list_head node;
119};
120
121int omap_dm_timer_reserve_systimer(int id);
122struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);
123
124int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
125
126u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
127
128int omap_dm_timer_trigger(struct omap_dm_timer *timer);
129
130int omap_dm_timers_active(void);
131
132/*
133 * Do not use the defines below, they are not needed. They should be only
134 * used by dmtimer.c and sys_timer related code.
135 */
136
137/*
138 * The interrupt registers are different between v1 and v2 ip.
139 * These registers are offsets from timer->iobase.
140 */
141#define OMAP_TIMER_ID_OFFSET 0x00
142#define OMAP_TIMER_OCP_CFG_OFFSET 0x10
143
144#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14
145#define OMAP_TIMER_V1_STAT_OFFSET 0x18
146#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c
147
148#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24
149#define OMAP_TIMER_V2_IRQSTATUS 0x28
150#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c
151#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30
152
153/*
154 * The functional registers have a different base on v1 and v2 ip.
155 * These registers are offsets from timer->func_base. The func_base
156 * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
157 *
158 */
159#define OMAP_TIMER_V2_FUNC_OFFSET 0x14
160
161#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20
162#define _OMAP_TIMER_CTRL_OFFSET 0x24
163#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
164#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
165#define OMAP_TIMER_CTRL_PT (1 << 12)
166#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
167#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
168#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
169#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
170#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
171#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
172#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */
173#define OMAP_TIMER_CTRL_POSTED (1 << 2)
174#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
175#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
176#define _OMAP_TIMER_COUNTER_OFFSET 0x28
177#define _OMAP_TIMER_LOAD_OFFSET 0x2c
178#define _OMAP_TIMER_TRIGGER_OFFSET 0x30
179#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34
180#define WP_NONE 0 /* no write pending bit */
181#define WP_TCLR (1 << 0)
182#define WP_TCRR (1 << 1)
183#define WP_TLDR (1 << 2)
184#define WP_TTGR (1 << 3)
185#define WP_TMAR (1 << 4)
186#define WP_TPIR (1 << 5)
187#define WP_TNIR (1 << 6)
188#define WP_TCVR (1 << 7)
189#define WP_TOCR (1 << 8)
190#define WP_TOWR (1 << 9)
191#define _OMAP_TIMER_MATCH_OFFSET 0x38
192#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c
193#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40
194#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */
195#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */
196#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */
197#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */
198#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */
199#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */
200
201/* register offsets with the write pending bit encoded */
202#define WPSHIFT 16
203
204#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
205 | (WP_NONE << WPSHIFT))
206
207#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \
208 | (WP_TCLR << WPSHIFT))
209
210#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \
211 | (WP_TCRR << WPSHIFT))
212
213#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \
214 | (WP_TLDR << WPSHIFT))
215
216#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \
217 | (WP_TTGR << WPSHIFT))
218
219#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \
220 | (WP_NONE << WPSHIFT))
221
222#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \
223 | (WP_TMAR << WPSHIFT))
224
225#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \
226 | (WP_NONE << WPSHIFT))
227
228#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \
229 | (WP_NONE << WPSHIFT))
230
231#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \
232 | (WP_NONE << WPSHIFT))
233
234#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \
235 | (WP_TPIR << WPSHIFT))
236
237#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \
238 | (WP_TNIR << WPSHIFT))
239
240#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \
241 | (WP_TCVR << WPSHIFT))
242
243#define OMAP_TIMER_TICK_INT_MASK_SET_REG \
244 (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
245
246#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \
247 (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
248
249/*
250 * The below are inlined to optimize code size for system timers. Other code
251 * should not need these at all, see
252 * include/linux/platform_data/pwm_omap_dmtimer.h
253 */
254#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2PLUS)
255static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
256 int posted)
257{
258 if (posted)
259 while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
260 cpu_relax();
261
262 return readl_relaxed(timer->func_base + (reg & 0xff));
263}
264
265static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
266 u32 reg, u32 val, int posted)
267{
268 if (posted)
269 while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
270 cpu_relax();
271
272 writel_relaxed(val, timer->func_base + (reg & 0xff));
273}
274
275static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
276{
277 u32 tidr;
278
279 /* Assume v1 ip if bits [31:16] are zero */
280 tidr = readl_relaxed(timer->io_base);
281 if (!(tidr >> 16)) {
282 timer->revision = 1;
283 timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
284 timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
285 timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
286 timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
287 timer->func_base = timer->io_base;
288 } else {
289 timer->revision = 2;
290 timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
291 timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
292 timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
293 timer->pend = timer->io_base +
294 _OMAP_TIMER_WRITE_PEND_OFFSET +
295 OMAP_TIMER_V2_FUNC_OFFSET;
296 timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
297 }
298}
299
300/*
301 * __omap_dm_timer_enable_posted - enables write posted mode
302 * @timer: pointer to timer instance handle
303 *
304 * Enables the write posted mode for the timer. When posted mode is enabled
305 * writes to certain timer registers are immediately acknowledged by the
306 * internal bus and hence prevents stalling the CPU waiting for the write to
307 * complete. Enabling this feature can improve performance for writing to the
308 * timer registers.
309 */
310static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
311{
312 if (timer->posted)
313 return;
314
315 if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
316 timer->posted = OMAP_TIMER_NONPOSTED;
317 __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0);
318 return;
319 }
320
321 __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
322 OMAP_TIMER_CTRL_POSTED, 0);
323 timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
324 timer->posted = OMAP_TIMER_POSTED;
325}
326
327/**
328 * __omap_dm_timer_override_errata - override errata flags for a timer
329 * @timer: pointer to timer handle
330 * @errata: errata flags to be ignored
331 *
332 * For a given timer, override a timer errata by clearing the flags
333 * specified by the errata argument. A specific erratum should only be
334 * overridden for a timer if the timer is used in such a way the erratum
335 * has no impact.
336 */
337static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
338 u32 errata)
339{
340 timer->errata &= ~errata;
341}
342
343static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
344 int posted, unsigned long rate)
345{
346 u32 l;
347
348 l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
349 if (l & OMAP_TIMER_CTRL_ST) {
350 l &= ~0x1;
351 __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
352#ifdef CONFIG_ARCH_OMAP2PLUS
353 /* Readback to make sure write has completed */
354 __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
355 /*
356 * Wait for functional clock period x 3.5 to make sure that
357 * timer is stopped
358 */
359 udelay(3500000 / rate + 1);
360#endif
361 }
362
363 /* Ack possibly pending interrupt */
364 writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
365}
366
367static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
368 u32 ctrl, unsigned int load,
369 int posted)
370{
371 __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
372 __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
373}
374
375static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
376 unsigned int value)
377{
378 writel_relaxed(value, timer->irq_ena);
379 __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
380}
381
382static inline unsigned int
383__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
384{
385 return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
386}
387
388static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
389 unsigned int value)
390{
391 writel_relaxed(value, timer->irq_stat);
392}
393#endif /* CONFIG_ARCH_OMAP1 || CONFIG_ARCH_OMAP2PLUS */
394#endif /* __CLOCKSOURCE_DMTIMER_H */
diff --git a/include/linux/platform_data/dmtimer-omap.h b/include/linux/platform_data/dmtimer-omap.h
index a19b78d826e9..757a0f9e26f9 100644
--- a/include/linux/platform_data/dmtimer-omap.h
+++ b/include/linux/platform_data/dmtimer-omap.h
@@ -20,12 +20,50 @@
20#ifndef __PLATFORM_DATA_DMTIMER_OMAP_H__ 20#ifndef __PLATFORM_DATA_DMTIMER_OMAP_H__
21#define __PLATFORM_DATA_DMTIMER_OMAP_H__ 21#define __PLATFORM_DATA_DMTIMER_OMAP_H__
22 22
23struct omap_dm_timer_ops {
24 struct omap_dm_timer *(*request_by_node)(struct device_node *np);
25 struct omap_dm_timer *(*request_specific)(int timer_id);
26 struct omap_dm_timer *(*request)(void);
27
28 int (*free)(struct omap_dm_timer *timer);
29
30 void (*enable)(struct omap_dm_timer *timer);
31 void (*disable)(struct omap_dm_timer *timer);
32
33 int (*get_irq)(struct omap_dm_timer *timer);
34 int (*set_int_enable)(struct omap_dm_timer *timer,
35 unsigned int value);
36 int (*set_int_disable)(struct omap_dm_timer *timer, u32 mask);
37
38 struct clk *(*get_fclk)(struct omap_dm_timer *timer);
39
40 int (*start)(struct omap_dm_timer *timer);
41 int (*stop)(struct omap_dm_timer *timer);
42 int (*set_source)(struct omap_dm_timer *timer, int source);
43
44 int (*set_load)(struct omap_dm_timer *timer, int autoreload,
45 unsigned int value);
46 int (*set_match)(struct omap_dm_timer *timer, int enable,
47 unsigned int match);
48 int (*set_pwm)(struct omap_dm_timer *timer, int def_on,
49 int toggle, int trigger);
50 int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler);
51
52 unsigned int (*read_counter)(struct omap_dm_timer *timer);
53 int (*write_counter)(struct omap_dm_timer *timer,
54 unsigned int value);
55 unsigned int (*read_status)(struct omap_dm_timer *timer);
56 int (*write_status)(struct omap_dm_timer *timer,
57 unsigned int value);
58};
59
23struct dmtimer_platform_data { 60struct dmtimer_platform_data {
24 /* set_timer_src - Only used for OMAP1 devices */ 61 /* set_timer_src - Only used for OMAP1 devices */
25 int (*set_timer_src)(struct platform_device *pdev, int source); 62 int (*set_timer_src)(struct platform_device *pdev, int source);
26 u32 timer_capability; 63 u32 timer_capability;
27 u32 timer_errata; 64 u32 timer_errata;
28 int (*get_context_loss_count)(struct device *); 65 int (*get_context_loss_count)(struct device *);
66 const struct omap_dm_timer_ops *timer_ops;
29}; 67};
30 68
31#endif /* __PLATFORM_DATA_DMTIMER_OMAP_H__ */ 69#endif /* __PLATFORM_DATA_DMTIMER_OMAP_H__ */