Commit | Line | Data |
---|---|---|
921a86e0 KH |
1 | /* |
2 | * SBE 2T3E3 synchronous serial card driver for Linux | |
3 | * | |
4 | * Copyright (C) 2009-2010 Krzysztof Halasa <khc@pm.waw.pl> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of version 2 of the GNU General Public License | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This code is based on a driver written by SBE Inc. | |
11 | */ | |
12 | ||
13 | #include <linux/delay.h> | |
14 | #include "2t3e3.h" | |
15 | #include "ctrl.h" | |
16 | ||
17 | #define bootrom_set_bit(sc, reg, bit) \ | |
18 | bootrom_write((sc), (reg), \ | |
19 | bootrom_read((sc), (reg)) | (bit)) | |
20 | ||
21 | #define bootrom_clear_bit(sc, reg, bit) \ | |
22 | bootrom_write((sc), (reg), \ | |
23 | bootrom_read((sc), (reg)) & ~(bit)) | |
24 | ||
25 | static inline void cpld_set_bit(struct channel *channel, unsigned reg, u32 bit) | |
26 | { | |
27 | unsigned long flags; | |
28 | spin_lock_irqsave(&channel->card->bootrom_lock, flags); | |
29 | bootrom_set_bit(channel, CPLD_MAP_REG(reg, channel), bit); | |
30 | spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); | |
31 | } | |
32 | ||
33 | static inline void cpld_clear_bit(struct channel *channel, unsigned reg, u32 bit) | |
34 | { | |
35 | unsigned long flags; | |
36 | spin_lock_irqsave(&channel->card->bootrom_lock, flags); | |
37 | bootrom_clear_bit(channel, CPLD_MAP_REG(reg, channel), bit); | |
38 | spin_unlock_irqrestore(&channel->card->bootrom_lock, flags); | |
39 | } | |
40 | ||
41 | void cpld_init(struct channel *sc) | |
42 | { | |
43 | u32 val; | |
921a86e0 KH |
44 | |
45 | /* PCRA */ | |
46 | val = SBE_2T3E3_CPLD_VAL_CRC32 | | |
47 | cpld_val_map[SBE_2T3E3_CPLD_VAL_LOOP_TIMING_SOURCE][sc->h.slot]; | |
48 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRA, val); | |
49 | ||
50 | /* PCRB */ | |
51 | val = 0; | |
52 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRB, val); | |
53 | ||
54 | /* PCRC */ | |
55 | val = 0; | |
56 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, val); | |
57 | ||
58 | /* PBWF */ | |
59 | val = 0; | |
60 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, val); | |
61 | ||
62 | /* PBWL */ | |
63 | val = 0; | |
64 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, val); | |
65 | ||
66 | /* PLTR */ | |
67 | val = SBE_2T3E3_CPLD_VAL_LCV_COUNTER; | |
68 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PLTR, val); | |
69 | udelay(1000); | |
70 | ||
71 | /* PLCR */ | |
72 | val = 0; | |
73 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PLCR, val); | |
74 | udelay(1000); | |
75 | ||
76 | /* PPFR */ | |
77 | val = 0x55; | |
78 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PPFR, val); | |
79 | /* TODO: this doesn't work!!! */ | |
80 | ||
81 | /* SERIAL_CHIP_SELECT */ | |
82 | val = 0; | |
83 | cpld_write(sc, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, val); | |
84 | ||
85 | /* PICSR */ | |
86 | val = SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED | | |
87 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED | | |
88 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED; | |
89 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, val); | |
90 | ||
91 | cpld_start_intr(sc); | |
92 | ||
93 | udelay(1000); | |
94 | } | |
95 | ||
96 | void cpld_start_intr(struct channel *sc) | |
97 | { | |
98 | u32 val; | |
99 | ||
100 | /* PIER */ | |
101 | val = SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ENABLE | | |
102 | SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ENABLE; | |
103 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val); | |
921a86e0 KH |
104 | } |
105 | ||
106 | void cpld_stop_intr(struct channel *sc) | |
107 | { | |
108 | u32 val; | |
109 | ||
110 | /* PIER */ | |
111 | val = 0; | |
112 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val); | |
113 | } | |
114 | ||
115 | void cpld_set_frame_mode(struct channel *sc, u32 mode) | |
116 | { | |
117 | if (sc->p.frame_mode == mode) | |
118 | return; | |
119 | ||
120 | switch (mode) { | |
121 | case SBE_2T3E3_FRAME_MODE_HDLC: | |
122 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
123 | SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE | | |
124 | SBE_2T3E3_CPLD_VAL_RAW_MODE); | |
125 | exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
126 | exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
127 | break; | |
128 | case SBE_2T3E3_FRAME_MODE_TRANSPARENT: | |
129 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
130 | SBE_2T3E3_CPLD_VAL_RAW_MODE); | |
131 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
132 | SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE); | |
133 | exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
134 | exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
135 | break; | |
136 | case SBE_2T3E3_FRAME_MODE_RAW: | |
137 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
138 | SBE_2T3E3_CPLD_VAL_RAW_MODE); | |
139 | exar7250_unipolar_onoff(sc, SBE_2T3E3_ON); | |
140 | exar7300_unipolar_onoff(sc, SBE_2T3E3_ON); | |
141 | break; | |
142 | default: | |
143 | return; | |
144 | } | |
145 | ||
146 | sc->p.frame_mode = mode; | |
147 | } | |
148 | ||
149 | /* set rate of the local clock */ | |
150 | void cpld_set_frame_type(struct channel *sc, u32 type) | |
151 | { | |
152 | switch (type) { | |
153 | case SBE_2T3E3_FRAME_TYPE_E3_G751: | |
154 | case SBE_2T3E3_FRAME_TYPE_E3_G832: | |
155 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
156 | SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3); | |
157 | break; | |
158 | case SBE_2T3E3_FRAME_TYPE_T3_CBIT: | |
159 | case SBE_2T3E3_FRAME_TYPE_T3_M13: | |
160 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
161 | SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3); | |
162 | break; | |
163 | default: | |
164 | return; | |
165 | } | |
166 | } | |
167 | ||
168 | void cpld_set_scrambler(struct channel *sc, u32 mode) | |
169 | { | |
170 | if (sc->p.scrambler == mode) | |
171 | return; | |
172 | ||
173 | switch (mode) { | |
174 | case SBE_2T3E3_SCRAMBLER_OFF: | |
175 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
176 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); | |
177 | break; | |
178 | case SBE_2T3E3_SCRAMBLER_LARSCOM: | |
179 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
180 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE); | |
181 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
182 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); | |
183 | break; | |
184 | case SBE_2T3E3_SCRAMBLER_ADC_KENTROX_DIGITAL: | |
185 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
186 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE); | |
187 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
188 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); | |
189 | break; | |
190 | default: | |
191 | return; | |
192 | } | |
193 | ||
194 | sc->p.scrambler = mode; | |
195 | } | |
196 | ||
197 | ||
198 | void cpld_set_crc(struct channel *sc, u32 crc) | |
199 | { | |
200 | if (sc->p.crc == crc) | |
201 | return; | |
202 | ||
203 | switch (crc) { | |
204 | case SBE_2T3E3_CRC_16: | |
205 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
206 | SBE_2T3E3_CPLD_VAL_CRC32); | |
207 | break; | |
208 | case SBE_2T3E3_CRC_32: | |
209 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
210 | SBE_2T3E3_CPLD_VAL_CRC32); | |
211 | break; | |
212 | default: | |
213 | return; | |
214 | } | |
215 | ||
216 | sc->p.crc = crc; | |
217 | } | |
218 | ||
219 | ||
220 | void cpld_select_panel(struct channel *sc, u32 panel) | |
221 | { | |
222 | if (sc->p.panel == panel) | |
223 | return; | |
224 | switch (panel) { | |
225 | case SBE_2T3E3_PANEL_FRONT: | |
226 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
227 | SBE_2T3E3_CPLD_VAL_REAR_PANEL); | |
228 | break; | |
229 | case SBE_2T3E3_PANEL_REAR: | |
230 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
231 | SBE_2T3E3_CPLD_VAL_REAR_PANEL); | |
232 | break; | |
233 | default: | |
234 | return; | |
235 | } | |
236 | ||
237 | udelay(100); | |
238 | ||
239 | sc->p.panel = panel; | |
240 | } | |
241 | ||
242 | ||
243 | extern void cpld_set_clock(struct channel *sc, u32 mode) | |
244 | { | |
245 | if (sc->p.clock_source == mode) | |
246 | return; | |
247 | ||
248 | switch (mode) { | |
249 | case SBE_2T3E3_TIMING_LOCAL: | |
250 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
251 | SBE_2T3E3_CPLD_VAL_ALT); | |
252 | break; | |
253 | case SBE_2T3E3_TIMING_LOOP: | |
254 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
255 | SBE_2T3E3_CPLD_VAL_ALT); | |
256 | break; | |
257 | default: | |
258 | return; | |
259 | } | |
260 | ||
261 | sc->p.clock_source = mode; | |
262 | } | |
263 | ||
264 | void cpld_set_pad_count(struct channel *sc, u32 count) | |
265 | { | |
266 | u32 val; | |
267 | ||
268 | if (sc->p.pad_count == count) | |
269 | return; | |
270 | ||
271 | switch (count) { | |
272 | case SBE_2T3E3_PAD_COUNT_1: | |
273 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_1; | |
274 | break; | |
275 | case SBE_2T3E3_PAD_COUNT_2: | |
276 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_2; | |
277 | break; | |
278 | case SBE_2T3E3_PAD_COUNT_3: | |
279 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_3; | |
280 | break; | |
281 | case SBE_2T3E3_PAD_COUNT_4: | |
282 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_4; | |
283 | break; | |
284 | default: | |
285 | return; | |
286 | } | |
287 | ||
288 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
289 | SBE_2T3E3_CPLD_VAL_PAD_COUNT); | |
290 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, val); | |
291 | sc->p.pad_count = count; | |
292 | } | |
293 | ||
294 | void cpld_LOS_update(struct channel *sc) | |
295 | { | |
296 | u_int8_t los; | |
297 | ||
298 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, | |
299 | SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED | | |
300 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED | | |
301 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED); | |
302 | los = cpld_read(sc, SBE_2T3E3_CPLD_REG_PICSR) & | |
303 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED; | |
304 | ||
305 | if (los != sc->s.LOS) | |
306 | dev_info(&sc->pdev->dev, "SBE 2T3E3: LOS status: %s\n", | |
307 | los ? "Loss of signal" : "Signal OK"); | |
308 | sc->s.LOS = los; | |
309 | } | |
310 | ||
311 | void cpld_set_fractional_mode(struct channel *sc, u32 mode, | |
312 | u32 start, u32 stop) | |
313 | { | |
314 | if (mode == SBE_2T3E3_FRACTIONAL_MODE_NONE) { | |
315 | start = 0; | |
316 | stop = 0; | |
317 | } | |
318 | ||
319 | if (sc->p.fractional_mode == mode && sc->p.bandwidth_start == start && | |
320 | sc->p.bandwidth_stop == stop) | |
321 | return; | |
322 | ||
323 | switch (mode) { | |
324 | case SBE_2T3E3_FRACTIONAL_MODE_NONE: | |
325 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
326 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_NONE); | |
327 | break; | |
328 | case SBE_2T3E3_FRACTIONAL_MODE_0: | |
329 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
330 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_0); | |
331 | break; | |
332 | case SBE_2T3E3_FRACTIONAL_MODE_1: | |
333 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
334 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_1); | |
335 | break; | |
336 | case SBE_2T3E3_FRACTIONAL_MODE_2: | |
337 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
338 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_2); | |
339 | break; | |
340 | default: | |
ce833d36 | 341 | netdev_err(sc->dev, "wrong mode in set_fractional_mode\n"); |
921a86e0 KH |
342 | return; |
343 | } | |
344 | ||
345 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, start); | |
346 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, stop); | |
347 | ||
348 | sc->p.fractional_mode = mode; | |
349 | sc->p.bandwidth_start = start; | |
350 | sc->p.bandwidth_stop = stop; | |
351 | } |