Revert "Remove support for xpp drivers."
[dahdi/linux.git] / drivers / dahdi / xpp / init_card_3_30
1 #! /usr/bin/perl -w
2 use strict;
3
4 # Make warnings fatal
5 local $SIG{__WARN__} = sub { die @_ };
6
7 #
8 # $Id$
9 #
10
11 #
12 # Written by Oron Peled <oron@actcom.co.il>
13 # Copyright (C) 2006, Xorcom
14 #
15 # All rights reserved.
16 #
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.
21 #
22 # See the file LICENSE in the top level of this tarball.
23 #
24
25 # This script is run from the xpp kernel module upon detection
26 # of a new XPD.
27 #
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):
33 #                       1 - FXS
34 #                       2 - FXO
35 #                       3 - BRI
36 #                       4 - PRI
37 #       XBUS_REVISION   - xbus revision number
38 #       XBUS_CONNECTOR  - xbus connector string
39 #
40 # Output data format:
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)
44 #
45 # The fields are (in command line order):
46 #       1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
47 #       2. Command word:
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).
55 #
56
57 package main;
58 use File::Basename;
59 use Getopt::Std;
60
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;
65 my $unit_id;
66 my %opts;
67
68 getopts('o:', \%opts);
69
70 my %settings;
71
72 sub logit {
73         print STDERR "$unit_id: @_\n";
74 }
75
76 sub debug {
77         logit @_ if $settings{debug};
78 }
79
80 # Arrange for error logging
81 if (-t STDERR) {
82         $unit_id = 'Interactive';
83         debug "Interactive startup";
84 } else {
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";
88         foreach my $k (qw(
89                         XBUS_NAME
90                         XBUS_NUMBER
91                         UNIT_NUMBER
92                         UNIT_TYPE
93                         UNIT_SUBUNITS
94                         UNIT_SUBUNITS_DIR
95                         XBUS_REVISION
96                         XBUS_CONNECTOR
97                         XBUS_LABEL)) {
98                 unless(defined $ENV{$k}) {
99                         logit "Missing ENV{$k}\n";
100                         die;
101                 }
102         }
103 }
104
105 sub select_subunit($) {
106         my $subunit = shift;
107         die unless defined $subunit;
108         my $output;
109
110         if($opts{o}) {
111                 $output = $opts{o};
112         } else {
113                 $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs",
114                                 $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
115                 if(! -f $output) {
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"
119                                 if -f $output;
120                 }
121         }
122         open(REG, ">$output") || die "Failed to open '$output': $!\n";
123         my $oldfh = select REG;
124         print "# Selecting subunit $subunit\n" if $opts{o};
125         return $oldfh;
126 }
127
128 package BRI;
129
130 sub gen {
131         my $fmt = shift;
132         $| = 1;
133         printf "$fmt\n", @_;
134 }
135
136 # Turning on/off multi-byte packet reception.
137 sub multibyte($) {
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);
142
143                 BRI::gen "$subunit W$active";
144         }
145 }
146
147 sub read_defaults() {
148         if(XppConfig::read_config(\%settings)) {
149                 main::logit "Defaults from $settings{xppconf}";
150         } else {
151                 main::logit "No defaults file, use hard-coded defaults.";
152         }
153 }
154
155 package BRI::Port;
156
157 sub new {
158         my $pack = shift;
159         my $port = { @_ };
160         bless $port, $pack;
161 }
162
163 # zap_xhfc_su.c:995
164 sub init_su {
165         my $port = shift;
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)";
171         
172         # Setting PLL
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)
175         # R_PLL_P    = 1     
176         # R_PLL_N    = 6
177         # R_PLL_S    = 1
178         # R_PLL_CTRL = 1 (V_PLL_M)
179         
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
188         
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)
195         } else {
196                 $port->{CTRL3} = 0x00;  # A_ST_CTRL3: V_ST_SEL = 0
197                 $port->{CTRL0} = 0x00;  # A_SU_CTRL0: V_ST_SQ_EN = 0
198         }
199         if ("$bri_nt" == 1) {
200                 $port->{CTRL0} |= 0x04; # V_SU_MD
201         }
202         # ((V_SU_EXCH)?0x80:00) (change polarity)
203         if($port_mode_exch) {
204                 $port->{CTRL2} = 0x80;
205         } else {
206                 $port->{CTRL2} = 0x00;
207         }
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
213
214         # zap_xhfc_su.c:1030 in init_su()
215         # A_SU_CLK_DLY
216         my $clk_dly;
217         if ("$bri_nt" == 1) {
218                 $clk_dly = 0x6C;
219         } else {
220                 $clk_dly = 0x0E;
221         }
222         #main::logit "clk_dly=$clk_dly";
223         BRI::gen "$portnum      WD      37      %02X", "$clk_dly";
224 }
225
226 sub su_sel {
227         if (@_ != 1 ) {
228                 main::logit "ERROR: su_sel() called with " . scalar(@_) . " parameters";
229                 exit 1;
230         }
231         my $portnum = shift;
232         BRI::gen "$portnum      WD      16      %02X", $portnum;        # R_SU_SEL
233 }
234
235 # zap_xhfc_su.c:281
236 sub xhfc_selfifo {
237         my $port = shift;
238         my $portnum = $port->{PORT_NUM};
239
240         if (@_ != 1 ) {
241                 main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters";
242                 exit 1;
243         }
244         my $fifonum = shift;
245         #main::logit "xhfc_selfifo($fifonum)";
246         BRI::gen "$portnum      WD      0F      %02X", $fifonum;
247         #       --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
248 }
249
250 # zap_xhfc_su.c:295
251 sub xhfc_resetfifo() {
252         my $port = shift;
253         my $portnum = $port->{PORT_NUM};
254
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
259 }
260
261 # zap_xhfc_su.c:1040
262 # Initialize fifo (called for each portnum, channel, direction)
263 sub setup_fifo {
264         my $port = shift;
265         my $chan = shift;
266         my $direction = shift;
267         my $conhdlc = shift;
268         my $subcfg = 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};
274
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);
279
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;
283         }
284
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
287         
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              
300
301         #system("/bin/echo \"----=====TE\" \"short_portnum=\"$short_portnum \"portnum=\" $portnum \"chan=\" $chan\"======----\n\" >>/root/xortel/test_init");
302 }
303
304 # zap_xhfc_su.c:1071
305 sub setup_su {
306         my $port = shift;
307         my $bchan = shift;
308         my $portnum = $port->{PORT_NUM};
309         my $port_mode_exch = $port->{PORT_MODE_EXCH};
310         my $bri_nt = $port->{BRI_NT};
311
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
319 }
320
321 sub xhfc_ph_command {
322         my $port = shift;
323         my $cmd = shift;
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)
329                                                                         # (set activation)
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)
333                                                                         # (set deactivation)
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)
341                                                                         # (set deactivation)
342         }
343 }
344
345
346 sub zthfc_startup {
347         my $port = shift;
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)";
352
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
358         }
359
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
364         
365         
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");
372         } else {
373                 $port->xhfc_ph_command("HFC_L1_ACTIVATE_NT");
374         }
375 }
376
377 package main;
378
379 debug "Starting '$0'";
380
381 BRI::read_defaults;
382
383 #------------------------------------------- Instance detection
384
385 # zap_xhfc_su.c:895
386 sub init_xhfc($) {
387         my $portnum = shift;
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)
392
393         # software reset to enable R_FIFO_MD setting
394         BRI::gen "$portnum      WD      00      08";    # R_CIRM = M_SRES (soft reset)
395         #       --> WAIT 5u
396         BRI::gen "$portnum      WD      00      00";    # R_CIRM = 0 (zero it to deactivate reset)
397
398         # amplitude
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)
402                                                         #          set duty cycle
403
404         BRI::gen "$portnum      WD      0C      11";    # R_FIFO_THRES: (FIFO fill lvl control register)
405                                                         #               RX/TX threshold = 16 bytes
406
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)
410
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) 
416
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
420
421 }
422
423 my @port_type = (
424                 { 'BRI_NT' => 1 },
425                 { 'BRI_NT' => 0 }
426         );
427
428 # zap_xhfc_su.c:175
429 sub main() {
430         my $subunit;
431         my $subunits_mask = pack("C", $ENV{UNIT_SUBUNITS_DIR});
432         my @direction = split(//, unpack("b*", $subunits_mask));
433
434         #logit "main(): UNIT_TYPE=$ENV{UNIT_TYPE} UNIT_SUBUNITS_DIR=[@direction]";
435         if(!$opts{o}) {
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;
438                 }
439         }
440         # Turn off multi-byte packet reception before initialization started 
441         # Otherwise we mess with registers while the FPGA firmware tries to
442         # send us packets.
443         BRI::multibyte(0);
444
445         # Port initialization
446         for($subunit = 0; $subunit < $ENV{UNIT_SUBUNITS}; $subunit++) {
447                 my $is_nt = $direction[$subunit];
448
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()
453                 }
454                 #logit "main(): Initializing subunit $subunit is_nt=$is_nt";
455                 my $p = BRI::Port->new(
456                                 'PORT_NUM'              => $subunit,
457                                 'BRI_NT'                => $is_nt,
458                                 'PORT_MODE_UP'          => 0,
459                                 'PORT_MODE_EXCH'        => 0
460                                 );
461                 # zap_XHfc_su.c:1186 in setup_instance()
462                 $p->init_su;
463                 $p->zthfc_startup;
464         }
465         # Turn on multi-byte packet reception when ports initialization finished
466         BRI::multibyte(1);
467 }
468
469 main;
470
471 debug "Ending '$0'";
472
473 close REG;
474 close STDERR;
475 exit 0;