5 local $SIG{__WARN__} = sub { die @_ };
12 # Written by Oron Peled <oron@actcom.co.il>
13 # Copyright (C) 2006, Xorcom
15 # All rights reserved.
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # See the file LICENSE in the top level of this tarball.
25 # This script is run from the xpp kernel module upon detection
28 # Expects the following environment variables to be set:
29 # XBUS_NAME - bus name
30 # UNIT_NUMBER - xpd unit number
31 # UNIT_SUBUNITS - number of subunits in this xpd
32 # UNIT_TYPE - xpd type number (from protocol reply):
37 # XBUS_REVISION - xbus revision number
38 # XBUS_CONNECTOR - xbus connector string
41 # - An optional comment start with ';' or '#' until the end of line
42 # - Optional Blank lines are ignored
43 # - Fields are whitespace separated (spaces or tabs)
45 # The fields are (in command line order):
46 # 1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
48 # - RD Read Direct register.
49 # - RS Read Sub-register.
50 # - WD Write Direct register.
51 # - WS Write Sub-register.
52 # 3. Register number in hexadecimal.
53 # 4. Subregister number in hexadecimal. (for RS and WS commands).
54 # 5. Data byte in hexadecimal. (for WD and WS commands only).
61 my $program = basename("$0");
62 my $init_dir = dirname("$0");
63 BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
64 use XppConfig $init_dir;
68 getopts('o:', \%opts);
73 print STDERR "$unit_id: @_\n";
77 logit @_ if $settings{debug};
80 # Arrange for error logging
82 $unit_id = 'Interactive';
83 debug "Interactive startup";
85 $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
86 open (STDERR, "| logger -t $program -p kern.info") || die;
87 debug "Non Interactive startup";
98 unless(defined $ENV{$k}) {
99 logit "Missing ENV{$k}\n";
105 sub select_subunit($) {
107 die unless defined $subunit;
113 $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs",
114 $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
116 my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
117 $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
118 logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
122 open(REG, ">$output") || die "Failed to open '$output': $!\n";
123 my $oldfh = select REG;
124 print "# Selecting subunit $subunit\n" if $opts{o};
136 # Turning on/off multi-byte packet reception.
138 my $active = (shift) ? 'M' : 'm';
139 for my $subunit (0 .. $ENV{UNIT_SUBUNITS} - 1) {
140 #main::logit "multibyte(): $subunit -> $active";
141 main::select_subunit($subunit);
143 BRI::gen "$subunit W$active";
147 sub read_defaults() {
148 if(XppConfig::read_config(\%settings)) {
149 main::logit "Defaults from $settings{xppconf}";
151 main::logit "No defaults file, use hard-coded defaults.";
166 my $portnum = $port->{PORT_NUM};
167 my $port_mode_up = $port->{PORT_MODE_UP};
168 my $port_mode_exch = $port->{PORT_MODE_EXCH};
169 my $bri_nt = $port->{BRI_NT};
170 #main::logit "init_su(portnum=$portnum, port_mode_up=$port_mode_up, bri_nt=$bri_nt)";
173 # R_PLL_CTRL = 0 (V_PLL_M = 0, Reset PLL, Disable PLL_
174 # R_CLK_CFG = 05 (PLL clock as system clock, output it to CLK_OUT pin)
178 # R_PLL_CTRL = 1 (V_PLL_M)
180 BRI::gen "#--------------------------- init_su($portnum, $bri_nt, $port_mode_up, $port_mode_exch)";
181 BRI::gen "$portnum WD 02 04";
182 BRI::gen "$portnum WD 50 00"; # disable PLL
183 BRI::gen "$portnum WD 51 02";
184 BRI::gen "$portnum WD 52 06";
185 BRI::gen "$portnum WD 53 04";
186 BRI::gen "$portnum WD 50 01"; # Enable PLL
187 BRI::gen "$portnum WD 02 05"; # Enable PLL
189 su_sel($portnum); # select port
190 if ("$port_mode_up" == 1) {
191 $port->{CTRL3} = 0x01; # A_ST_CTRL3: V_ST_SEL = 1
192 $port->{CTRL0} = 0x10; # A_SU_CTRL0: V_ST_SQ_EN = 1
193 BRI::gen "$portnum WD 34 0F"; # A_MS_TX:
194 # (multiframe/superframe transmit register)
196 $port->{CTRL3} = 0x00; # A_ST_CTRL3: V_ST_SEL = 0
197 $port->{CTRL0} = 0x00; # A_SU_CTRL0: V_ST_SQ_EN = 0
199 if ("$bri_nt" == 1) {
200 $port->{CTRL0} |= 0x04; # V_SU_MD
202 # ((V_SU_EXCH)?0x80:00) (change polarity)
203 if($port_mode_exch) {
204 $port->{CTRL2} = 0x80;
206 $port->{CTRL2} = 0x00;
208 BRI::gen "$portnum WD 35 %02X", $port->{CTRL3}; # A_ST_CTRL3
209 BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0
210 BRI::gen "$portnum WD 35 F8"; # A_ST_CTRL3 = set end of pulse control to 0xF8
211 BRI::gen "$portnum WD 32 09"; # A_SU_CTRL1 = Ignore E-channel data, Force automatic transition from G2 to G3
212 BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2
214 # zap_xhfc_su.c:1030 in init_su()
217 if ("$bri_nt" == 1) {
222 #main::logit "clk_dly=$clk_dly";
223 BRI::gen "$portnum WD 37 %02X", "$clk_dly";
228 main::logit "ERROR: su_sel() called with " . scalar(@_) . " parameters";
232 BRI::gen "$portnum WD 16 %02X", $portnum; # R_SU_SEL
238 my $portnum = $port->{PORT_NUM};
241 main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters";
245 #main::logit "xhfc_selfifo($fifonum)";
246 BRI::gen "$portnum WD 0F %02X", $fifonum;
247 # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
251 sub xhfc_resetfifo() {
253 my $portnum = $port->{PORT_NUM};
255 #main::logit "xhfc_resetfifo()";
256 # A_INC_RES_FIFO = M_RES_FIFO | M_RES_FIFO_ERR
257 BRI::gen "$portnum WD 0E 0A";
258 # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
262 # Initialize fifo (called for each portnum, channel, direction)
266 my $direction = shift;
269 my $fifoctrl = shift;
270 my $portnum = $port->{PORT_NUM};
271 my $port_mode_up = $port->{PORT_MODE_UP};
272 my $port_mode_exch = $port->{PORT_MODE_EXCH};
273 my $bri_nt = $port->{BRI_NT};
275 BRI::gen "#--------------------------- setup_fifo($portnum, $chan, $direction)";
276 # my $fifonum = 0x80 | ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first
277 my $fifonum = ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first
278 my $r_slot = ($portnum << 3) | ($chan << 1) | ($direction);
280 # channel order workaround, swap odd and even portnums in $r_slot for PCM (chan 0, 1) only
281 if ("$chan" == 0 || "$chan" == 1) {
282 $r_slot = $r_slot ^ 0x08;
285 my $short_portnum = $portnum & 0x03;
286 my $a_sl_cfg = (0x80 | ($short_portnum << 3) | ($chan << 1) | ($direction)); # receive data from STIO2, transmit to STIO1
288 #main::logit "setup_fifo($fifonum)";
289 $port->xhfc_selfifo($fifonum);
290 # A_CON_HDLC: transparent mode selection
291 BRI::gen "$portnum WD FA %02X", $conhdlc;
292 # A_SUBCH_CFG: subchnl params
293 BRI::gen "$portnum WD FB %02X", $subcfg;
294 # A_FIFO_CTRL: FIFO Control Register
295 BRI::gen "$portnum WD FF %02X", $fifoctrl;
296 $port->xhfc_resetfifo();
297 $port->xhfc_selfifo($fifonum); # wait for busy is builtin in this command
298 BRI::gen "$portnum WD 10 %02X", $r_slot; # R_SLOT
299 BRI::gen "$portnum WD D0 %02X", $a_sl_cfg; # A_SL_CFG
301 #system("/bin/echo \"----=====TE\" \"short_portnum=\"$short_portnum \"portnum=\" $portnum \"chan=\" $chan\"======----\n\" >>/root/xortel/test_init");
308 my $portnum = $port->{PORT_NUM};
309 my $port_mode_exch = $port->{PORT_MODE_EXCH};
310 my $bri_nt = $port->{BRI_NT};
312 BRI::gen "#--------------------------- setup_su($portnum, $bchan)";
313 #main::logit "setup_su(portnum=$portnum, bchan=$bchan, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)";
314 $port->{CTRL0} |= (1 << $bchan) | $bri_nt;
315 $port->{CTRL2} |= ($port_mode_exch << 7) | (1 << $bchan);
316 su_sel($portnum); # Select port
317 BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0: V_B1_TX_EN | V_SU_MD | (NT/TE)
318 BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2: V_B1_RX_EN
321 sub xhfc_ph_command {
324 my $portnum = $port->{PORT_NUM};
325 #main::logit "xhfc_ph_command(portnum=$portnum)";
326 if ("$cmd" eq "HFC_L1_ACTIVATE_TE") {
327 su_sel($portnum); # Select port
328 BRI::gen "$portnum WD 30 60"; # A_SU_WR_STA = (M_SU_ACT & 0x03)
330 } elsif ("$cmd" eq "HFC_L1_FORCE_DEACTIVATE_TE") {
331 su_sel($portnum); # Select port
332 BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02)
334 } elsif ("$cmd" eq "HFC_L1_ACTIVATE_NT") {
335 su_sel($portnum); # Select port
336 BRI::gen "$portnum WD 30 E0"; # A_SU_WR_STA = (M_SU_ACT & 0x03) | 0x80
337 # (set activation + NT)
338 } elsif ("$cmd" eq "HFC_L1_DEACTIVATE_NT") {
339 su_sel($portnum); # Select port
340 BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02)
348 my $portnum = $port->{PORT_NUM};
349 my $port_mode_exch = $port->{PORT_MODE_EXCH};
350 my $bri_nt = $port->{BRI_NT};
351 #main::logit "zthfc_startup(portnum=$portnum, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)";
353 # PCM <-> ST/Up Configuration
354 foreach my $chan ( 0, 1 ) {
355 $port->setup_fifo($chan, 0, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM
356 $port->setup_fifo($chan, 1, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM
357 $port->setup_su($chan); # zap_xhfc_su.c:194
360 # Dahdi chan 2 used as HDLC D-Channel
361 $port->setup_fifo(2, 0, 0x05, 2, 0); # D-TX: zap_xhfc_su.c:205
362 $port->setup_fifo(2, 1, 0x05, 2, 0); # D-RX: zap_xhfc_su.c:206
363 # E-chan, Echo channel is ignored
366 # enable this port's state machine
367 su_sel($portnum); # Select port
368 # A_SU_WR_STA: reset port state machine
369 BRI::gen "$portnum WD 30 00";
370 if ("$bri_nt" == 0) {
371 $port->xhfc_ph_command("HFC_L1_ACTIVATE_TE");
373 $port->xhfc_ph_command("HFC_L1_ACTIVATE_NT");
379 debug "Starting '$0'";
383 #------------------------------------------- Instance detection
388 main::debug "init_xhfc($portnum)";
389 BRI::gen "#--------------------------- init_xhfc";
390 BRI::gen "$portnum WD 0D 00"; # r_FIFO_MD: 16 fifos,
391 # 64 bytes for TX and RX each (FIFO mode config)
393 # software reset to enable R_FIFO_MD setting
394 BRI::gen "$portnum WD 00 08"; # R_CIRM = M_SRES (soft reset)
396 BRI::gen "$portnum WD 00 00"; # R_CIRM = 0 (zero it to deactivate reset)
399 BRI::gen "$portnum WD 46 80"; # R_PWM_MD: (PWM output mode register)
400 # PWM push to zero only
401 BRI::gen "$portnum WD 39 18"; # R_PWM1: (modulator register for PWM1)
404 BRI::gen "$portnum WD 0C 11"; # R_FIFO_THRES: (FIFO fill lvl control register)
405 # RX/TX threshold = 16 bytes
407 # set PCM bus mode to slave by default
408 BRI::gen "$portnum WD 14 08"; # R_PCM_MD0 = PCM slave mode, F0IO duration is 2 HFC_PCLK's
409 # (C4IO, F0IO are inputs)
411 BRI::gen "$portnum WD 14 98"; # R_PCM_MD0: Index value to select
412 # the register at address 15
413 BRI::gen "$portnum WD 15 20"; # R_PCM_MD1: V_PLL_ADJ (DPLL adjust speed),
414 # in the last slot of PCM frame
415 # V_PCM_DR, C4IO is 16.384MHz(128 time slots)
417 BRI::gen "$portnum WD 4C 07"; # GPIOGPIO function (not PWM) on GPIO0, GPIO1 and GPIO2 pins
418 BRI::gen "$portnum WD 4A 07"; # Output enable for GPIO0, GPIO1 and GPIO2 pins
419 BRI::gen "$portnum WD 48 01"; # GPIO output data bits
431 my $subunits_mask = pack("C", $ENV{UNIT_SUBUNITS_DIR});
432 my @direction = split(//, unpack("b*", $subunits_mask));
434 #logit "main(): UNIT_TYPE=$ENV{UNIT_TYPE} UNIT_SUBUNITS_DIR=[@direction]";
436 foreach my $var (qw(XBUS_NAME UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR)) {
437 die "Missing mandatory '$var' environment variable" unless defined $var;
440 # Turn off multi-byte packet reception before initialization started
441 # Otherwise we mess with registers while the FPGA firmware tries to
445 # Port initialization
446 for($subunit = 0; $subunit < $ENV{UNIT_SUBUNITS}; $subunit++) {
447 my $is_nt = $direction[$subunit];
449 main::select_subunit($subunit);
450 if(($subunit % 4) == 0) { # A new xhfc chip
451 #logit "main(): Initializing chip";
452 init_xhfc($subunit); # zap_xhfc_su.c:1173 in setup_instance()
454 #logit "main(): Initializing subunit $subunit is_nt=$is_nt";
455 my $p = BRI::Port->new(
456 'PORT_NUM' => $subunit,
459 'PORT_MODE_EXCH' => 0
461 # zap_XHfc_su.c:1186 in setup_instance()
465 # Turn on multi-byte packet reception when ports initialization finished