xref: /freebsd/sys/contrib/ncsw/Peripherals/FM/Rtc/fman_rtc.c (revision 031beb4e239bfce798af17f5fe8dba8bcaf13d99)
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 
35 void 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 
48 uint32_t fman_rtc_get_events(struct rtc_regs *regs)
49 {
50 	return ioread32be(&regs->tmr_tevent);
51 }
52 
53 uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask)
54 {
55 	return ioread32be(&regs->tmr_tevent) & ev_mask;
56 }
57 
58 uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs)
59 {
60 	return ioread32be(&regs->tmr_temask);
61 }
62 
63 void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask)
64 {
65 	iowrite32be(mask, &regs->tmr_temask);
66 }
67 
68 void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events)
69 {
70 	iowrite32be(events, &regs->tmr_tevent);
71 }
72 
73 uint32_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 
85 uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs)
86 {
87 	return ioread32be(&regs->tmr_add);
88 }
89 
90 void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val)
91 {
92 	iowrite32be(val, &regs->tmr_add);
93 }
94 
95 void 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 
100 void 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 
105 void 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 
110 void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val)
111 {
112 	iowrite32be(val, &regs->tmr_fiper[index]);
113 }
114 
115 void 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 
121 void 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 
127 uint64_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 
138 uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs)
139 {
140 	return ioread32be(&regs->tmr_ctrl);
141 }
142 
143 void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val)
144 {
145 	iowrite32be(val, &regs->tmr_ctrl);
146 }
147 
148 void 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 
155 void 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 
227 bool 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 
232 void 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 
248 void 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 
254 void 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 
270 void 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 
289 void 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 
302 void 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 
316 void 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