]>
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; | |
44 | #if 0 | |
45 | /* reset LIU and Framer */ | |
46 | val = cpld_val_map[SBE_2T3E3_CPLD_VAL_LIU_FRAMER_RESET][sc->h.slot]; | |
47 | cpld_write(sc, SBE_2T3E3_CPLD_REG_STATIC_RESET, val); | |
48 | udelay(10000); /* TODO - how long? */ | |
49 | val = 0; | |
50 | cpld_write(sc, SBE_2T3E3_CPLD_REG_STATIC_RESET, val); | |
51 | #endif | |
52 | ||
53 | /* PCRA */ | |
54 | val = SBE_2T3E3_CPLD_VAL_CRC32 | | |
55 | cpld_val_map[SBE_2T3E3_CPLD_VAL_LOOP_TIMING_SOURCE][sc->h.slot]; | |
56 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRA, val); | |
57 | ||
58 | /* PCRB */ | |
59 | val = 0; | |
60 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRB, val); | |
61 | ||
62 | /* PCRC */ | |
63 | val = 0; | |
64 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, val); | |
65 | ||
66 | /* PBWF */ | |
67 | val = 0; | |
68 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, val); | |
69 | ||
70 | /* PBWL */ | |
71 | val = 0; | |
72 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, val); | |
73 | ||
74 | /* PLTR */ | |
75 | val = SBE_2T3E3_CPLD_VAL_LCV_COUNTER; | |
76 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PLTR, val); | |
77 | udelay(1000); | |
78 | ||
79 | /* PLCR */ | |
80 | val = 0; | |
81 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PLCR, val); | |
82 | udelay(1000); | |
83 | ||
84 | /* PPFR */ | |
85 | val = 0x55; | |
86 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PPFR, val); | |
87 | /* TODO: this doesn't work!!! */ | |
88 | ||
89 | /* SERIAL_CHIP_SELECT */ | |
90 | val = 0; | |
91 | cpld_write(sc, SBE_2T3E3_CPLD_REG_SERIAL_CHIP_SELECT, val); | |
92 | ||
93 | /* PICSR */ | |
94 | val = SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED | | |
95 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED | | |
96 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED; | |
97 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, val); | |
98 | ||
99 | cpld_start_intr(sc); | |
100 | ||
101 | udelay(1000); | |
102 | } | |
103 | ||
104 | void cpld_start_intr(struct channel *sc) | |
105 | { | |
106 | u32 val; | |
107 | ||
108 | /* PIER */ | |
109 | val = SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ENABLE | | |
110 | SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ENABLE; | |
111 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val); | |
112 | #if 0 | |
113 | /* | |
114 | do you want to hang up your computer? | |
115 | ENABLE REST OF INTERRUPTS !!! | |
116 | you have been warned :). | |
117 | */ | |
118 | #endif | |
119 | } | |
120 | ||
121 | void cpld_stop_intr(struct channel *sc) | |
122 | { | |
123 | u32 val; | |
124 | ||
125 | /* PIER */ | |
126 | val = 0; | |
127 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PIER, val); | |
128 | } | |
129 | ||
130 | void cpld_set_frame_mode(struct channel *sc, u32 mode) | |
131 | { | |
132 | if (sc->p.frame_mode == mode) | |
133 | return; | |
134 | ||
135 | switch (mode) { | |
136 | case SBE_2T3E3_FRAME_MODE_HDLC: | |
137 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
138 | SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE | | |
139 | SBE_2T3E3_CPLD_VAL_RAW_MODE); | |
140 | exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
141 | exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
142 | break; | |
143 | case SBE_2T3E3_FRAME_MODE_TRANSPARENT: | |
144 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
145 | SBE_2T3E3_CPLD_VAL_RAW_MODE); | |
146 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
147 | SBE_2T3E3_CPLD_VAL_TRANSPARENT_MODE); | |
148 | exar7250_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
149 | exar7300_unipolar_onoff(sc, SBE_2T3E3_OFF); | |
150 | break; | |
151 | case SBE_2T3E3_FRAME_MODE_RAW: | |
152 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
153 | SBE_2T3E3_CPLD_VAL_RAW_MODE); | |
154 | exar7250_unipolar_onoff(sc, SBE_2T3E3_ON); | |
155 | exar7300_unipolar_onoff(sc, SBE_2T3E3_ON); | |
156 | break; | |
157 | default: | |
158 | return; | |
159 | } | |
160 | ||
161 | sc->p.frame_mode = mode; | |
162 | } | |
163 | ||
164 | /* set rate of the local clock */ | |
165 | void cpld_set_frame_type(struct channel *sc, u32 type) | |
166 | { | |
167 | switch (type) { | |
168 | case SBE_2T3E3_FRAME_TYPE_E3_G751: | |
169 | case SBE_2T3E3_FRAME_TYPE_E3_G832: | |
170 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
171 | SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3); | |
172 | break; | |
173 | case SBE_2T3E3_FRAME_TYPE_T3_CBIT: | |
174 | case SBE_2T3E3_FRAME_TYPE_T3_M13: | |
175 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
176 | SBE_2T3E3_CPLD_VAL_LOCAL_CLOCK_E3); | |
177 | break; | |
178 | default: | |
179 | return; | |
180 | } | |
181 | } | |
182 | ||
183 | void cpld_set_scrambler(struct channel *sc, u32 mode) | |
184 | { | |
185 | if (sc->p.scrambler == mode) | |
186 | return; | |
187 | ||
188 | switch (mode) { | |
189 | case SBE_2T3E3_SCRAMBLER_OFF: | |
190 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
191 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); | |
192 | break; | |
193 | case SBE_2T3E3_SCRAMBLER_LARSCOM: | |
194 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
195 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE); | |
196 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
197 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); | |
198 | break; | |
199 | case SBE_2T3E3_SCRAMBLER_ADC_KENTROX_DIGITAL: | |
200 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
201 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_TYPE); | |
202 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
203 | SBE_2T3E3_CPLD_VAL_SCRAMBLER_ENABLE); | |
204 | break; | |
205 | default: | |
206 | return; | |
207 | } | |
208 | ||
209 | sc->p.scrambler = mode; | |
210 | } | |
211 | ||
212 | ||
213 | void cpld_set_crc(struct channel *sc, u32 crc) | |
214 | { | |
215 | if (sc->p.crc == crc) | |
216 | return; | |
217 | ||
218 | switch (crc) { | |
219 | case SBE_2T3E3_CRC_16: | |
220 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
221 | SBE_2T3E3_CPLD_VAL_CRC32); | |
222 | break; | |
223 | case SBE_2T3E3_CRC_32: | |
224 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
225 | SBE_2T3E3_CPLD_VAL_CRC32); | |
226 | break; | |
227 | default: | |
228 | return; | |
229 | } | |
230 | ||
231 | sc->p.crc = crc; | |
232 | } | |
233 | ||
234 | ||
235 | void cpld_select_panel(struct channel *sc, u32 panel) | |
236 | { | |
237 | if (sc->p.panel == panel) | |
238 | return; | |
239 | switch (panel) { | |
240 | case SBE_2T3E3_PANEL_FRONT: | |
241 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
242 | SBE_2T3E3_CPLD_VAL_REAR_PANEL); | |
243 | break; | |
244 | case SBE_2T3E3_PANEL_REAR: | |
245 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
246 | SBE_2T3E3_CPLD_VAL_REAR_PANEL); | |
247 | break; | |
248 | default: | |
249 | return; | |
250 | } | |
251 | ||
252 | udelay(100); | |
253 | ||
254 | sc->p.panel = panel; | |
255 | } | |
256 | ||
257 | ||
258 | extern void cpld_set_clock(struct channel *sc, u32 mode) | |
259 | { | |
260 | if (sc->p.clock_source == mode) | |
261 | return; | |
262 | ||
263 | switch (mode) { | |
264 | case SBE_2T3E3_TIMING_LOCAL: | |
265 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
266 | SBE_2T3E3_CPLD_VAL_ALT); | |
267 | break; | |
268 | case SBE_2T3E3_TIMING_LOOP: | |
269 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRA, | |
270 | SBE_2T3E3_CPLD_VAL_ALT); | |
271 | break; | |
272 | default: | |
273 | return; | |
274 | } | |
275 | ||
276 | sc->p.clock_source = mode; | |
277 | } | |
278 | ||
279 | void cpld_set_pad_count(struct channel *sc, u32 count) | |
280 | { | |
281 | u32 val; | |
282 | ||
283 | if (sc->p.pad_count == count) | |
284 | return; | |
285 | ||
286 | switch (count) { | |
287 | case SBE_2T3E3_PAD_COUNT_1: | |
288 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_1; | |
289 | break; | |
290 | case SBE_2T3E3_PAD_COUNT_2: | |
291 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_2; | |
292 | break; | |
293 | case SBE_2T3E3_PAD_COUNT_3: | |
294 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_3; | |
295 | break; | |
296 | case SBE_2T3E3_PAD_COUNT_4: | |
297 | val = SBE_2T3E3_CPLD_VAL_PAD_COUNT_4; | |
298 | break; | |
299 | default: | |
300 | return; | |
301 | } | |
302 | ||
303 | cpld_clear_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, | |
304 | SBE_2T3E3_CPLD_VAL_PAD_COUNT); | |
305 | cpld_set_bit(sc, SBE_2T3E3_CPLD_REG_PCRB, val); | |
306 | sc->p.pad_count = count; | |
307 | } | |
308 | ||
309 | void cpld_LOS_update(struct channel *sc) | |
310 | { | |
311 | u_int8_t los; | |
312 | ||
313 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PICSR, | |
314 | SBE_2T3E3_CPLD_VAL_DMO_SIGNAL_DETECTED | | |
315 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_LOCK_DETECTED | | |
316 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED); | |
317 | los = cpld_read(sc, SBE_2T3E3_CPLD_REG_PICSR) & | |
318 | SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_DETECTED; | |
319 | ||
320 | if (los != sc->s.LOS) | |
321 | dev_info(&sc->pdev->dev, "SBE 2T3E3: LOS status: %s\n", | |
322 | los ? "Loss of signal" : "Signal OK"); | |
323 | sc->s.LOS = los; | |
324 | } | |
325 | ||
326 | void cpld_set_fractional_mode(struct channel *sc, u32 mode, | |
327 | u32 start, u32 stop) | |
328 | { | |
329 | if (mode == SBE_2T3E3_FRACTIONAL_MODE_NONE) { | |
330 | start = 0; | |
331 | stop = 0; | |
332 | } | |
333 | ||
334 | if (sc->p.fractional_mode == mode && sc->p.bandwidth_start == start && | |
335 | sc->p.bandwidth_stop == stop) | |
336 | return; | |
337 | ||
338 | switch (mode) { | |
339 | case SBE_2T3E3_FRACTIONAL_MODE_NONE: | |
340 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
341 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_NONE); | |
342 | break; | |
343 | case SBE_2T3E3_FRACTIONAL_MODE_0: | |
344 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
345 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_0); | |
346 | break; | |
347 | case SBE_2T3E3_FRACTIONAL_MODE_1: | |
348 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
349 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_1); | |
350 | break; | |
351 | case SBE_2T3E3_FRACTIONAL_MODE_2: | |
352 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PCRC, | |
353 | SBE_2T3E3_CPLD_VAL_FRACTIONAL_MODE_2); | |
354 | break; | |
355 | default: | |
356 | printk(KERN_ERR "wrong mode in set_fractional_mode\n"); | |
357 | return; | |
358 | } | |
359 | ||
360 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWF, start); | |
361 | cpld_write(sc, SBE_2T3E3_CPLD_REG_PBWL, stop); | |
362 | ||
363 | sc->p.fractional_mode = mode; | |
364 | sc->p.bandwidth_start = start; | |
365 | sc->p.bandwidth_stop = stop; | |
366 | } |