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/types.h> | |
14 | #include "2t3e3.h" | |
15 | #include "ctrl.h" | |
16 | ||
17 | void t3e3_set_frame_type(struct channel *sc, u32 mode) | |
18 | { | |
19 | if (sc->p.frame_type == mode) | |
20 | return; | |
21 | ||
22 | if (sc->r.flags & SBE_2T3E3_FLAG_NETWORK_UP) { | |
23 | dev_err(&sc->pdev->dev, "SBE 2T3E3: changing frame type during active connection\n"); | |
24 | return; | |
25 | } | |
26 | ||
27 | exar7300_set_frame_type(sc, mode); | |
28 | exar7250_set_frame_type(sc, mode); | |
29 | cpld_set_frame_type(sc, mode); | |
30 | ||
31 | sc->p.frame_type = mode; | |
32 | } | |
33 | ||
39e2ce9a | 34 | static void t3e3_set_loopback(struct channel *sc, u32 mode) |
921a86e0 KH |
35 | { |
36 | u32 tx, rx; | |
37 | ||
38 | if (sc->p.loopback == mode) | |
39 | return; | |
40 | ||
41 | tx = sc->p.transmitter_on; | |
42 | rx = sc->p.receiver_on; | |
43 | if (tx == SBE_2T3E3_ON) | |
44 | dc_transmitter_onoff(sc, SBE_2T3E3_OFF); | |
45 | if (rx == SBE_2T3E3_ON) | |
46 | dc_receiver_onoff(sc, SBE_2T3E3_OFF); | |
47 | ||
48 | /* stop current loopback if any exists */ | |
49 | switch (sc->p.loopback) { | |
50 | case SBE_2T3E3_LOOPBACK_NONE: | |
51 | break; | |
52 | case SBE_2T3E3_LOOPBACK_ETHERNET: | |
53 | dc_set_loopback(sc, SBE_2T3E3_21143_VAL_LOOPBACK_OFF); | |
54 | break; | |
55 | case SBE_2T3E3_LOOPBACK_FRAMER: | |
56 | exar7250_set_loopback(sc, SBE_2T3E3_FRAMER_VAL_LOOPBACK_OFF); | |
57 | break; | |
58 | case SBE_2T3E3_LOOPBACK_LIU_DIGITAL: | |
59 | case SBE_2T3E3_LOOPBACK_LIU_ANALOG: | |
60 | case SBE_2T3E3_LOOPBACK_LIU_REMOTE: | |
61 | exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_OFF); | |
62 | break; | |
63 | default: | |
64 | return; | |
65 | } | |
66 | ||
67 | switch (mode) { | |
68 | case SBE_2T3E3_LOOPBACK_NONE: | |
69 | break; | |
70 | case SBE_2T3E3_LOOPBACK_ETHERNET: | |
71 | dc_set_loopback(sc, SBE_2T3E3_21143_VAL_LOOPBACK_INTERNAL); | |
72 | break; | |
73 | case SBE_2T3E3_LOOPBACK_FRAMER: | |
74 | exar7250_set_loopback(sc, SBE_2T3E3_FRAMER_VAL_LOOPBACK_ON); | |
75 | break; | |
76 | case SBE_2T3E3_LOOPBACK_LIU_DIGITAL: | |
77 | exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_DIGITAL); | |
78 | break; | |
79 | case SBE_2T3E3_LOOPBACK_LIU_ANALOG: | |
80 | exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_ANALOG); | |
81 | break; | |
82 | case SBE_2T3E3_LOOPBACK_LIU_REMOTE: | |
83 | exar7300_set_loopback(sc, SBE_2T3E3_LIU_VAL_LOOPBACK_REMOTE); | |
84 | break; | |
85 | default: | |
86 | return; | |
87 | } | |
88 | ||
89 | sc->p.loopback = mode; | |
90 | ||
91 | if (tx == SBE_2T3E3_ON) | |
92 | dc_transmitter_onoff(sc, SBE_2T3E3_ON); | |
93 | if (rx == SBE_2T3E3_ON) | |
94 | dc_receiver_onoff(sc, SBE_2T3E3_ON); | |
95 | } | |
96 | ||
97 | ||
39e2ce9a | 98 | static void t3e3_reg_read(struct channel *sc, u32 *reg, u32 *val) |
921a86e0 KH |
99 | { |
100 | u32 i; | |
101 | ||
102 | *val = 0; | |
103 | ||
104 | switch (reg[0]) { | |
105 | case SBE_2T3E3_CHIP_21143: | |
106 | if (!(reg[1] & 7)) | |
107 | *val = dc_read(sc->addr, reg[1] / 8); | |
108 | break; | |
109 | case SBE_2T3E3_CHIP_CPLD: | |
110 | for (i = 0; i < SBE_2T3E3_CPLD_REG_MAX; i++) | |
111 | if (cpld_reg_map[i][sc->h.slot] == reg[1]) { | |
112 | *val = cpld_read(sc, i); | |
113 | break; | |
114 | } | |
115 | break; | |
116 | case SBE_2T3E3_CHIP_FRAMER: | |
117 | for (i = 0; i < SBE_2T3E3_FRAMER_REG_MAX; i++) | |
118 | if (t3e3_framer_reg_map[i] == reg[1]) { | |
119 | *val = exar7250_read(sc, i); | |
120 | break; | |
121 | } | |
122 | break; | |
123 | case SBE_2T3E3_CHIP_LIU: | |
124 | for (i = 0; i < SBE_2T3E3_LIU_REG_MAX; i++) | |
125 | if (t3e3_liu_reg_map[i] == reg[1]) { | |
126 | *val = exar7300_read(sc, i); | |
127 | break; | |
128 | } | |
129 | break; | |
130 | default: | |
131 | break; | |
132 | } | |
133 | } | |
134 | ||
39e2ce9a | 135 | static void t3e3_reg_write(struct channel *sc, u32 *reg) |
921a86e0 KH |
136 | { |
137 | u32 i; | |
138 | ||
139 | switch (reg[0]) { | |
140 | case SBE_2T3E3_CHIP_21143: | |
141 | dc_write(sc->addr, reg[1], reg[2]); | |
142 | break; | |
143 | case SBE_2T3E3_CHIP_CPLD: | |
144 | for (i = 0; i < SBE_2T3E3_CPLD_REG_MAX; i++) | |
145 | if (cpld_reg_map[i][sc->h.slot] == reg[1]) { | |
146 | cpld_write(sc, i, reg[2]); | |
147 | break; | |
148 | } | |
149 | break; | |
150 | case SBE_2T3E3_CHIP_FRAMER: | |
151 | for (i = 0; i < SBE_2T3E3_FRAMER_REG_MAX; i++) | |
152 | if (t3e3_framer_reg_map[i] == reg[1]) { | |
153 | exar7250_write(sc, i, reg[2]); | |
154 | break; | |
155 | } | |
156 | break; | |
157 | case SBE_2T3E3_CHIP_LIU: | |
158 | for (i = 0; i < SBE_2T3E3_LIU_REG_MAX; i++) | |
159 | if (t3e3_liu_reg_map[i] == reg[1]) { | |
160 | exar7300_write(sc, i, reg[2]); | |
161 | break; | |
162 | } | |
163 | break; | |
164 | } | |
165 | } | |
166 | ||
39e2ce9a | 167 | static void t3e3_port_get(struct channel *sc, t3e3_param_t *param) |
921a86e0 KH |
168 | { |
169 | memcpy(param, &(sc->p), sizeof(t3e3_param_t)); | |
170 | } | |
171 | ||
39e2ce9a | 172 | static void t3e3_port_set(struct channel *sc, t3e3_param_t *param) |
921a86e0 KH |
173 | { |
174 | if (param->frame_mode != 0xff) | |
175 | cpld_set_frame_mode(sc, param->frame_mode); | |
176 | ||
177 | if (param->fractional_mode != 0xff) | |
178 | cpld_set_fractional_mode(sc, param->fractional_mode, | |
179 | param->bandwidth_start, | |
180 | param->bandwidth_stop); | |
181 | ||
182 | if (param->pad_count != 0xff) | |
183 | cpld_set_pad_count(sc, param->pad_count); | |
184 | ||
185 | if (param->crc != 0xff) | |
186 | cpld_set_crc(sc, param->crc); | |
187 | ||
188 | if (param->receiver_on != 0xff) | |
189 | dc_receiver_onoff(sc, param->receiver_on); | |
190 | ||
191 | if (param->transmitter_on != 0xff) | |
192 | dc_transmitter_onoff(sc, param->transmitter_on); | |
193 | ||
194 | if (param->frame_type != 0xff) | |
195 | t3e3_set_frame_type(sc, param->frame_type); | |
196 | ||
197 | if (param->panel != 0xff) | |
198 | cpld_select_panel(sc, param->panel); | |
199 | ||
200 | if (param->line_build_out != 0xff) | |
201 | exar7300_line_build_out_onoff(sc, param->line_build_out); | |
202 | ||
203 | if (param->receive_equalization != 0xff) | |
204 | exar7300_receive_equalization_onoff(sc, param->receive_equalization); | |
205 | ||
206 | if (param->transmit_all_ones != 0xff) | |
207 | exar7300_transmit_all_ones_onoff(sc, param->transmit_all_ones); | |
208 | ||
209 | if (param->loopback != 0xff) | |
210 | t3e3_set_loopback(sc, param->loopback); | |
211 | ||
212 | if (param->clock_source != 0xff) | |
213 | cpld_set_clock(sc, param->clock_source); | |
214 | ||
215 | if (param->scrambler != 0xff) | |
216 | cpld_set_scrambler(sc, param->scrambler); | |
217 | } | |
218 | ||
39e2ce9a | 219 | static void t3e3_port_get_stats(struct channel *sc, |
921a86e0 KH |
220 | t3e3_stats_t *stats) |
221 | { | |
222 | u32 result; | |
223 | ||
224 | sc->s.LOC = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_IO_CONTROL) | |
225 | & SBE_2T3E3_FRAMER_VAL_LOSS_OF_CLOCK_STATUS ? 1 : 0; | |
226 | ||
227 | switch (sc->p.frame_type) { | |
228 | case SBE_2T3E3_FRAME_TYPE_E3_G751: | |
229 | case SBE_2T3E3_FRAME_TYPE_E3_G832: | |
230 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); | |
231 | sc->s.LOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_LOF ? 1 : 0; | |
232 | sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; | |
12f3f21d | 233 | |
921a86e0 | 234 | cpld_LOS_update(sc); |
12f3f21d | 235 | |
921a86e0 KH |
236 | sc->s.AIS = result & SBE_2T3E3_FRAMER_VAL_E3_RX_AIS ? 1 : 0; |
237 | sc->s.FERF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_FERF ? 1 : 0; | |
238 | break; | |
239 | ||
240 | case SBE_2T3E3_FRAME_TYPE_T3_CBIT: | |
241 | case SBE_2T3E3_FRAME_TYPE_T3_M13: | |
242 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); | |
243 | sc->s.AIS = result & SBE_2T3E3_FRAMER_VAL_T3_RX_AIS ? 1 : 0; | |
12f3f21d | 244 | |
921a86e0 | 245 | cpld_LOS_update(sc); |
12f3f21d | 246 | |
921a86e0 KH |
247 | sc->s.IDLE = result & SBE_2T3E3_FRAMER_VAL_T3_RX_IDLE ? 1 : 0; |
248 | sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; | |
249 | ||
250 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_STATUS); | |
251 | sc->s.FERF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_FERF ? 1 : 0; | |
252 | sc->s.AIC = result & SBE_2T3E3_FRAMER_VAL_T3_RX_AIC ? 1 : 0; | |
253 | sc->s.FEBE_code = result & SBE_2T3E3_FRAMER_VAL_T3_RX_FEBE; | |
254 | ||
255 | sc->s.FEAC = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC); | |
256 | break; | |
257 | ||
258 | default: | |
259 | break; | |
260 | } | |
261 | ||
262 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_LCV_EVENT_COUNT_MSB) << 8; | |
263 | result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); | |
264 | sc->s.LCV += result; | |
265 | ||
266 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_FRAMING_BIT_ERROR_EVENT_COUNT_MSB) << 8; | |
267 | result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); | |
268 | sc->s.FRAMING_BIT += result; | |
269 | ||
270 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_PARITY_ERROR_EVENT_COUNT_MSB) << 8; | |
271 | result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); | |
272 | sc->s.PARITY_ERROR += result; | |
273 | ||
274 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_FEBE_EVENT_COUNT_MSB) << 8; | |
275 | result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); | |
276 | sc->s.FEBE_count += result; | |
277 | ||
278 | result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_CP_BIT_ERROR_EVENT_COUNT_MSB) << 8; | |
279 | result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER); | |
280 | sc->s.CP_BIT += result; | |
281 | ||
282 | memcpy(stats, &(sc->s), sizeof(t3e3_stats_t)); | |
283 | } | |
284 | ||
39e2ce9a | 285 | static void t3e3_port_del_stats(struct channel *sc) |
921a86e0 KH |
286 | { |
287 | memset(&(sc->s), 0, sizeof(t3e3_stats_t)); | |
288 | } | |
289 | ||
290 | void t3e3_if_config(struct channel *sc, u32 cmd, char *set, | |
291 | t3e3_resp_t *ret, int *rlen) | |
292 | { | |
293 | t3e3_param_t *param = (t3e3_param_t *)set; | |
294 | u32 *data = (u32 *)set; | |
295 | ||
296 | /* turn off all interrupt */ | |
297 | /* cpld_stop_intr(sc); */ | |
298 | ||
299 | switch (cmd) { | |
300 | case SBE_2T3E3_PORT_GET: | |
301 | t3e3_port_get(sc, &(ret->u.param)); | |
302 | *rlen = sizeof(ret->u.param); | |
303 | break; | |
304 | case SBE_2T3E3_PORT_SET: | |
305 | t3e3_port_set(sc, param); | |
306 | *rlen = 0; | |
307 | break; | |
308 | case SBE_2T3E3_PORT_GET_STATS: | |
309 | t3e3_port_get_stats(sc, &(ret->u.stats)); | |
310 | *rlen = sizeof(ret->u.stats); | |
311 | break; | |
312 | case SBE_2T3E3_PORT_DEL_STATS: | |
313 | t3e3_port_del_stats(sc); | |
314 | *rlen = 0; | |
315 | break; | |
316 | case SBE_2T3E3_PORT_READ_REGS: | |
317 | t3e3_reg_read(sc, data, &(ret->u.data)); | |
318 | *rlen = sizeof(ret->u.data); | |
319 | break; | |
320 | case SBE_2T3E3_PORT_WRITE_REGS: | |
921a86e0 KH |
321 | t3e3_reg_write(sc, data); |
322 | *rlen = 0; | |
323 | break; | |
324 | case SBE_2T3E3_LOG_LEVEL: | |
325 | *rlen = 0; | |
326 | break; | |
327 | default: | |
328 | *rlen = 0; | |
329 | break; | |
330 | } | |
921a86e0 KH |
331 | } |
332 | ||
333 | void t3e3_sc_init(struct channel *sc) | |
334 | { | |
335 | memset(sc, 0, sizeof(*sc)); | |
336 | ||
337 | sc->p.frame_mode = SBE_2T3E3_FRAME_MODE_HDLC; | |
338 | sc->p.fractional_mode = SBE_2T3E3_FRACTIONAL_MODE_NONE; | |
339 | sc->p.crc = SBE_2T3E3_CRC_32; | |
340 | sc->p.receiver_on = SBE_2T3E3_OFF; | |
341 | sc->p.transmitter_on = SBE_2T3E3_OFF; | |
342 | sc->p.frame_type = SBE_2T3E3_FRAME_TYPE_T3_CBIT; | |
343 | sc->p.panel = SBE_2T3E3_PANEL_FRONT; | |
344 | sc->p.line_build_out = SBE_2T3E3_OFF; | |
345 | sc->p.receive_equalization = SBE_2T3E3_OFF; | |
346 | sc->p.transmit_all_ones = SBE_2T3E3_OFF; | |
347 | sc->p.loopback = SBE_2T3E3_LOOPBACK_NONE; | |
348 | sc->p.clock_source = SBE_2T3E3_TIMING_LOCAL; | |
349 | sc->p.scrambler = SBE_2T3E3_SCRAMBLER_OFF; | |
350 | sc->p.pad_count = SBE_2T3E3_PAD_COUNT_1; | |
351 | } |