1/*
2 * Copyright 2008-2013 Freescale Semiconductor Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above copyright
9 *       notice, this list of conditions and the following disclaimer in the
10 *       documentation and/or other materials provided with the distribution.
11 *     * Neither the name of Freescale Semiconductor nor the
12 *       names of its contributors may be used to endorse or promote products
13 *       derived from this software without specific prior written permission.
14 *
15 *
16 * ALTERNATIVELY, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") as published by the Free Software
18 * Foundation, either version 2 of that License or (at your option) any
19 * later version.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include "fsl_fman_rtc.h"
34
35void fman_rtc_defconfig(struct rtc_cfg *cfg)
36{
37	int i;
38	cfg->src_clk = DEFAULT_SRC_CLOCK;
39	cfg->invert_input_clk_phase = DEFAULT_INVERT_INPUT_CLK_PHASE;
40	cfg->invert_output_clk_phase = DEFAULT_INVERT_OUTPUT_CLK_PHASE;
41	cfg->pulse_realign = DEFAULT_PULSE_REALIGN;
42	for (i = 0; i < FMAN_RTC_MAX_NUM_OF_ALARMS; i++)
43		cfg->alarm_polarity[i] = DEFAULT_ALARM_POLARITY;
44	for (i = 0; i < FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS; i++)
45		cfg->trigger_polarity[i] = DEFAULT_TRIGGER_POLARITY;
46}
47
48uint32_t fman_rtc_get_events(struct rtc_regs *regs)
49{
50	return ioread32be(&regs->tmr_tevent);
51}
52
53uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask)
54{
55	return ioread32be(&regs->tmr_tevent) & ev_mask;
56}
57
58uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs)
59{
60	return ioread32be(&regs->tmr_temask);
61}
62
63void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask)
64{
65	iowrite32be(mask, &regs->tmr_temask);
66}
67
68void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events)
69{
70	iowrite32be(events, &regs->tmr_tevent);
71}
72
73uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs)
74{
75	uint32_t event;
76
77	event = ioread32be(&regs->tmr_tevent);
78	event &= ioread32be(&regs->tmr_temask);
79
80	if (event)
81		iowrite32be(event, &regs->tmr_tevent);
82	return event;
83}
84
85uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs)
86{
87	return ioread32be(&regs->tmr_add);
88}
89
90void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val)
91{
92	iowrite32be(val, &regs->tmr_add);
93}
94
95void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t events)
96{
97	fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) | events);
98}
99
100void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t events)
101{
102	fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) & ~events);
103}
104
105void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, uint32_t val)
106{
107	iowrite32be(val, &regs->tmr_alarm[index].tmr_alarm_l);
108}
109
110void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val)
111{
112	iowrite32be(val, &regs->tmr_fiper[index]);
113}
114
115void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val)
116{
117	iowrite32be((uint32_t)val, &regs->tmr_alarm[index].tmr_alarm_l);
118	iowrite32be((uint32_t)(val >> 32), &regs->tmr_alarm[index].tmr_alarm_h);
119}
120
121void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val)
122{
123	iowrite32be((uint32_t)val, &regs->tmr_off_l);
124	iowrite32be((uint32_t)(val >> 32), &regs->tmr_off_h);
125}
126
127uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id)
128{
129	uint64_t time;
130	/* TMR_CNT_L must be read first to get an accurate value */
131	time = (uint64_t)ioread32be(&regs->tmr_etts[id].tmr_etts_l);
132	time |= ((uint64_t)ioread32be(&regs->tmr_etts[id].tmr_etts_h)
133		<< 32);
134
135	return time;
136}
137
138uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs)
139{
140	return ioread32be(&regs->tmr_ctrl);
141}
142
143void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val)
144{
145	iowrite32be(val, &regs->tmr_ctrl);
146}
147
148void fman_rtc_timers_soft_reset(struct rtc_regs *regs)
149{
150	fman_rtc_set_timer_ctrl(regs, FMAN_RTC_TMR_CTRL_TMSR);
151	DELAY(10);
152	fman_rtc_set_timer_ctrl(regs, 0);
153}
154
155void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms,
156		int num_fipers, int num_ext_triggers, bool init_freq_comp,
157		uint32_t freq_compensation, uint32_t output_clock_divisor)
158{
159	uint32_t            tmr_ctrl;
160	int			i;
161
162	fman_rtc_timers_soft_reset(regs);
163
164	/* Set the source clock */
165	switch (cfg->src_clk) {
166	case E_FMAN_RTC_SOURCE_CLOCK_SYSTEM:
167		tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK;
168		break;
169	case E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR:
170		tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK;
171		break;
172	default:
173		/* Use a clock from the External TMR reference clock.*/
174		tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK;
175		break;
176	}
177
178	/* whatever period the user picked, the timestamp will advance in '1'
179	* every time the period passed. */
180	tmr_ctrl |= ((1 << FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT) &
181				FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK);
182
183	if (cfg->invert_input_clk_phase)
184		tmr_ctrl |= FMAN_RTC_TMR_CTRL_CIPH;
185	if (cfg->invert_output_clk_phase)
186		tmr_ctrl |= FMAN_RTC_TMR_CTRL_COPH;
187
188	for (i = 0; i < num_alarms; i++) {
189		if (cfg->alarm_polarity[i] ==
190			E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW)
191			tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ALMP1 >> i);
192	}
193
194	for (i = 0; i < num_ext_triggers; i++)
195		if (cfg->trigger_polarity[i] ==
196			E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE)
197			tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ETEP1 << i);
198
199	if (!cfg->timer_slave_mode && cfg->bypass)
200		tmr_ctrl |= FMAN_RTC_TMR_CTRL_BYP;
201
202	fman_rtc_set_timer_ctrl(regs, tmr_ctrl);
203	if (init_freq_comp)
204		fman_rtc_set_frequency_compensation(regs, freq_compensation);
205
206	/* Clear TMR_ALARM registers */
207	for (i = 0; i < num_alarms; i++)
208		fman_rtc_set_timer_alarm(regs, i, 0xFFFFFFFFFFFFFFFFLL);
209
210	/* Clear TMR_TEVENT */
211	fman_rtc_ack_event(regs, FMAN_RTC_TMR_TEVENT_ALL);
212
213	/* Initialize TMR_TEMASK */
214	fman_rtc_set_interrupt_mask(regs, 0);
215
216	/* Clear TMR_FIPER registers */
217	for (i = 0; i < num_fipers; i++)
218		fman_rtc_set_timer_fiper(regs, i, 0xFFFFFFFF);
219
220	/* Initialize TMR_PRSC */
221	iowrite32be(output_clock_divisor, &regs->tmr_prsc);
222
223	/* Clear TMR_OFF */
224	fman_rtc_set_timer_offset(regs, 0);
225}
226
227bool fman_rtc_is_enabled(struct rtc_regs *regs)
228{
229	return (bool)(fman_rtc_get_timer_ctrl(regs) & FMAN_RTC_TMR_CTRL_TE);
230}
231
232void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock)
233{
234	uint32_t tmr_ctrl = fman_rtc_get_timer_ctrl(regs);
235
236	/* TODO check that no timestamping MACs are working in this stage. */
237	if (reset_clock) {
238		fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TMSR));
239
240		DELAY(10);
241		/* Clear TMR_OFF */
242		fman_rtc_set_timer_offset(regs, 0);
243	}
244
245	fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TE));
246}
247
248void fman_rtc_disable(struct rtc_regs *regs)
249{
250	fman_rtc_set_timer_ctrl(regs, (fman_rtc_get_timer_ctrl(regs)
251					& ~(FMAN_RTC_TMR_CTRL_TE)));
252}
253
254void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id)
255{
256	uint32_t tmp_reg;
257	if (id == 0)
258		tmp_reg = FMAN_RTC_TMR_TEVENT_PP1;
259	else
260		tmp_reg = FMAN_RTC_TMR_TEVENT_PP2;
261	fman_rtc_disable_interupt(regs, tmp_reg);
262
263	tmp_reg = fman_rtc_get_timer_ctrl(regs);
264	if (tmp_reg & FMAN_RTC_TMR_CTRL_FS)
265		fman_rtc_set_timer_ctrl(regs, tmp_reg & ~FMAN_RTC_TMR_CTRL_FS);
266
267	fman_rtc_set_timer_fiper(regs, id, 0xFFFFFFFF);
268}
269
270void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id)
271{
272	uint32_t    tmpReg, tmp_ctrl;
273
274	if (id == 0)
275		tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;
276	else
277		tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;
278	fman_rtc_disable_interupt(regs, tmpReg);
279
280	if (id == 0)
281		tmpReg = FMAN_RTC_TMR_CTRL_PP1L;
282	else
283		tmpReg = FMAN_RTC_TMR_CTRL_PP2L;
284	tmp_ctrl = fman_rtc_get_timer_ctrl(regs);
285	if (tmp_ctrl & tmpReg)
286		fman_rtc_set_timer_ctrl(regs, tmp_ctrl & ~tmpReg);
287}
288
289void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable)
290{
291	uint32_t    tmpReg;
292	fman_rtc_set_timer_alarm(regs, id, val);
293	if (enable) {
294		if (id == 0)
295			tmpReg = FMAN_RTC_TMR_TEVENT_ALM1;
296		else
297			tmpReg = FMAN_RTC_TMR_TEVENT_ALM2;
298		fman_rtc_enable_interupt(regs, tmpReg);
299	}
300}
301
302void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val,
303						bool enable)
304{
305	uint32_t    tmpReg;
306	fman_rtc_set_timer_fiper(regs, id, val);
307	if (enable) {
308		if (id == 0)
309			tmpReg = FMAN_RTC_TMR_TEVENT_PP1;
310		else
311			tmpReg = FMAN_RTC_TMR_TEVENT_PP2;
312		fman_rtc_enable_interupt(regs, tmpReg);
313	}
314}
315
316void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable,
317						bool use_pulse_as_input)
318{
319	uint32_t    tmpReg;
320	if (enable) {
321		if (id == 0)
322			tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;
323		else
324			tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;
325		fman_rtc_enable_interupt(regs, tmpReg);
326	}
327	if (use_pulse_as_input)	{
328		if (id == 0)
329			tmpReg = FMAN_RTC_TMR_CTRL_PP1L;
330		else
331			tmpReg = FMAN_RTC_TMR_CTRL_PP2L;
332		fman_rtc_set_timer_ctrl(regs, fman_rtc_get_timer_ctrl(regs) | tmpReg);
333	}
334}
335