Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/ncsw/Peripherals/FM/Rtc/fman_rtc.c
48417 views
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
336