Revert "Remove support for xpp drivers."
[dahdi/linux.git] / drivers / dahdi / xpp / init_card_4_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) 2007, 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 #       XBUS_LABEL      - xbus label string
40 #
41 # Output data format:
42 #       - An optional comment start with ';' or '#' until the end of line
43 #       - Optional Blank lines are ignored
44 #       - Fields are whitespace separated (spaces or tabs)
45 #
46 # The fields are (in command line order):
47 #       1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
48 #       2. Command word:
49 #               - RD    Read Direct register.
50 #               - WD    Write Direct register.
51 #       3. Register number in hexadecimal.
52 #       5. Data byte in hexadecimal. (for WD command only).
53 #
54
55 package main;
56 use File::Basename;
57 use Getopt::Std;
58
59 my $program = basename("$0");
60 my $init_dir = dirname("$0");
61 BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
62 use XppConfig $init_dir;
63 my $unit_id;
64 my %opts;
65
66 getopts('o:', \%opts);
67
68 my %settings;
69
70 sub logit {
71         print STDERR "$unit_id: @_\n";
72 }
73
74 sub debug {
75         logit @_ if $settings{debug};
76 }
77
78 # Arrange for error logging
79 if (-t STDERR) {
80         $unit_id = 'Interactive';
81         debug "Interactive startup";
82 } else {
83         $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
84         open (STDERR, "| logger -t $program -p kern.info") || die;
85         debug "Non Interactive startup";
86         foreach my $k (qw(
87                         XBUS_NAME
88                         XBUS_NUMBER
89                         UNIT_NUMBER
90                         UNIT_TYPE
91                         UNIT_SUBUNITS
92                         UNIT_SUBUNITS_DIR
93                         XBUS_REVISION
94                         XBUS_CONNECTOR
95                         XBUS_LABEL)) {
96                 unless(defined $ENV{$k}) {
97                         logit "Missing ENV{$k}\n";
98                         die;
99                 }
100         }
101 }
102
103 sub select_subunit($) {
104         my $subunit = shift;
105         die unless defined $subunit;
106         my $output;
107
108         if($opts{o}) {
109                 $output = $opts{o};
110         } else {
111                 $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs",
112                                 $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
113                 if(! -f $output) {
114                         my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
115                         $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
116                         logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
117                                 if -f $output;
118                 }
119         }
120         open(REG, ">$output") || die "Failed to open '$output': $!\n";
121         my $oldfh = select REG;
122         print "# Selecting subunit $subunit\n" if $opts{o};
123         return $oldfh;
124 }
125
126 package PRI;
127
128 sub gen {
129         my $fmt = shift;
130         $| = 1;
131         printf "$fmt\n", @_;
132 }
133
134 sub init_quad() {
135         main::select_subunit(0);
136
137         PRI::gen "0 WD D6 20";          # GPC6.COMP_DIS=1
138                                         # (Compatibility Mode Disable)
139
140         # Tuning of clocking unit to the 16.384 MHz reference frequence
141         # by setting Global Clock Mode registers (GCM[1:8]), same for E1 and T1/J1
142         PRI::gen "0 WD 92 00";          # GCM1
143         PRI::gen "0 WD 93 18";          # GCM2
144         PRI::gen "0 WD 94 FB";          # GCM3
145         PRI::gen "0 WD 95 0B";          # GCM4
146         PRI::gen "0 WD 96 01";          # GCM5
147         PRI::gen "0 WD 97 0B";          # GCM6
148         PRI::gen "0 WD 98 DB";          # GCM7
149         PRI::gen "0 WD 99 DF";          # GCM8
150 }
151
152 sub finish_quad() {
153         PRI::gen "0 WD BB 2C";          # REGFP
154         PRI::gen "0 WD BC FF";          # REGFD
155         PRI::gen "0 WD BB AC";          # REGFP
156         PRI::gen "0 WD BB 2B";          # REGFP
157         PRI::gen "0 WD BC 00";          # REGFD
158         PRI::gen "0 WD BB AB";          # REGFP
159         PRI::gen "0 WD BB 2A";          # REGFP
160         PRI::gen "0 WD BC FF";          # REGFD
161         PRI::gen "0 WD BB AA";          # REGFP
162         PRI::gen "0 WD BB 29";          # REGFP
163         PRI::gen "0 WD BC FF";          # REGFD
164         PRI::gen "0 WD BB A9";          # REGFP
165         PRI::gen "0 WD BB 28";          # REGFP
166         PRI::gen "0 WD BC 00";          # REGFD
167         PRI::gen "0 WD BB A8";          # REGFP
168         PRI::gen "0 WD BB 27";          # REGFP
169         PRI::gen "0 WD BC FF";          # REGFD
170         PRI::gen "0 WD BB A7";          # REGFP
171         PRI::gen "0 WD BB 00";          # REGFP
172
173 #       PRI::gen "0 WD 80 00";  # PC1 (Port configuration 1): RPB_1.SYPR           , XPB_1.SYPX
174 }
175
176 sub read_defaults() {
177         if(XppConfig::read_config(\%settings)) {
178                 main::logit "Defaults from $settings{xppconf}";
179         } else {
180                 main::logit "No defaults file, use hard-coded defaults.";
181         }
182 }
183
184 package PRI::Port;
185
186 sub new {
187         my $pack = shift;
188         my $port = { @_ };
189         bless $port, $pack;
190         return $port;
191 }
192
193 sub get_pri_protocol {
194         my $port = shift;
195         my $subunit = $port->{PORT_NUM};
196         my $xpd_name = "XPD-$ENV{UNIT_NUMBER}$subunit";
197         my $pri_protocol;
198         my @keys = (
199                         "pri_protocol/connector:$ENV{XBUS_CONNECTOR}/$xpd_name",
200                         "pri_protocol/label:$ENV{XBUS_LABEL}/$xpd_name",
201                         "pri_protocol/$ENV{XBUS_NAME}/$xpd_name",
202                         "pri_protocol"
203                 );
204         foreach my $k (@keys) {
205                 $k = lc($k);            # Lowercase
206                 $pri_protocol = $settings{$k};
207                 if(defined $pri_protocol) {
208                         $port->{pri_protocol} = $pri_protocol;
209                         return $pri_protocol;
210                 }
211         }
212         return undef;
213 }
214
215 sub write_pri_info {
216         my $port = shift;
217         my $subunit = $port->{PORT_NUM};
218         my $pri_protocol = $port->get_pri_protocol;
219         my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
220
221         if(defined $pri_protocol) {
222                 main::logit "$xpd_name: pri_protocol $pri_protocol";
223                 my $file = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/pri_protocol",
224                                 $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
225                 if(! -f $file) {
226                         $file = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/pri_info";
227                         main::logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
228                                 if -f $file;
229                 }
230                 open(INFO, ">$file") || die "Failed to open '$file': $!\n";
231                 print INFO "$pri_protocol\n" || die "Failed writing '$pri_protocol' to '$file': $!\n";
232                 close INFO || die "Failed during close of '$file': $!\n";
233         } else {
234                 main::logit "$xpd_name: pri_protocol not given. Driver will use defaults.";
235         }
236 }
237
238 sub port_setup($) {
239         my $port = shift;
240         my $portno = $port->{PORT_NUM};
241         my $pri_protocol = $port->get_pri_protocol;
242
243         PRI::gen "$portno WD 28 40";    # XPM2.XLT Tristate
244
245         my $cmr5 = sprintf("%x", ($portno << 5));
246
247         PRI::gen "$portno WD 42 $cmr5"; # CMR5.DRSS=portno
248
249         PRI::gen "$portno WD 26 F6";    # XPM0: Pulse Shape Programming for R1=18Ohms 
250         PRI::gen "$portno WD 27 02";    # XPM1: ...3V Pulse Level at the line (Vp-p=6v)
251
252                                         # if (unchannelized)
253         #PRI::gen "$portno WD 1F 22";   # LOOP (Channel Looback): 
254                                         #      ECLB (Enable Channel Loop-Back) 
255                                         #      CLA  (Channel Address)
256         PRI::gen "$portno WD 2B EF";    # IDL (Idle): 
257                                         #      If channel loopback is enabled than transmit this code on the outgoing
258         PRI::gen "$portno WD 1F 00";    # LOOP (Channel Looback): 
259         #if($portno eq 0){ 
260         #       PRI::gen "0 WD 1F 00";  # LOOP (Channel Looback): 
261         #                               #      channels (XL1/XL2)
262         #}else { 
263         #       PRI::gen "0 WD 1F 20";  # LOOP (Channel Looback): 
264         #}
265
266         # only one of the following loopbacks can be activated in the same time 
267         my $LIM1_RL  = 0 << 1;  # RL  (Remote  Loopback)
268         my $lim1 = 0xB0 | $LIM1_RL;
269         PRI::gen "$portno WD 37 %02X", $lim1;
270                                         # LIM1: ~RL (Remote Loop bit 0x02),
271                                         #       ~DRS (Dual Rail Select, latch receive data while trasmit),
272                                         #       RIL1, RIL0 (Receive Input Treshold 0.62 V),
273                                         #       CLOS (Clear data in case of LOS)
274         PRI::gen "$portno WD 3A 20";    # LIM2: SLT1, SLT0 = 01 
275                                         #            (Receiver Slicer Threshold, the receive slicer 
276                                         #             generates a mark (digital one) if the voltage at
277                                         #             RL1/2 exceeds 50% of the peak amplitude,
278                                         #             default, recommended in E1 mode).
279           
280         PRI::gen "$portno WD 38 0A";    # PCD: (Pulse Count Detection, LOS Detection after 176 consecutive 0s)
281         PRI::gen "$portno WD 39 15";    # PCR: (Pulse Count Recovery, LOS Recovery after 22 ones in PCD interval)
282
283         # Configure system interface
284         PRI::gen "$portno WD 3E C2";    # SIC1: SSC1 (System clock    ) is 8.192 Mhz, 
285                                         #       SSD1 (System Data rate) is 8.192 Mbit/s,
286                                         #       ~BIM (Byte interleaved mode),
287                                         #       XBS  (Transmit Buffer Size) is 2 frames
288         PRI::gen "$portno WD 40 04";    # SIC3: Edges for capture, Synchronous Pulse Receive @Rising Edge
289         PRI::gen "$portno WD 41 04";    # CMR4: RCLK is 8.192 MHz
290         PRI::gen "$portno WD 43 04";    # CMR5: TCLK is 8.192 MHz
291         PRI::gen "$portno WD 44 34";    # CMR6: Receive reference clock generated by channel 1,
292                                         #       RCLK is at 8.192 Mhz dejittered, Clock recovered from the line
293                                         #       TCLK is at 8.192 MHz is de-jittered by DCO-R to drive a6.176 MHz 
294                                         #       clock on RCLK.*/
295
296         PRI::gen "$portno WD 22 00";    # XC0: (Transmit Counter Offset = 497/T=2)
297         PRI::gen "$portno WD 23 04";    # XC1: X=4  => T=4-X=0 offset
298
299         PRI::gen "$portno WD 24 00";    # RC0: (Receive  Counter Offset = 497/T=2)
300         PRI::gen "$portno WD 25 05";    # RC1: Remaining part of RC0
301
302         my $sic2 = sprintf("%x", 0x00 | ($portno << 1));
303
304         PRI::gen "$portno WD 3F $sic2"; # SIC2: No FFS, no center receive elastic buffer, data active at phase ($sic >> 1)
305                 
306         # enable the following interrupt sources
307         PRI::gen "$portno WD 14 F7";    # IMR0 (Interrupt Mask Register2): Enable CASC_E1/RSC_T1
308         PRI::gen "$portno WD 16 00";    # IMR2 (Interrupt Mask Register2): Enable ALL
309                 
310         PRI::gen "$portno WD 17 3F";    # IMR3 ~ES, ~SEC (Enable ES and SEC interrupts)
311         PRI::gen "$portno WD 18 00";    # IMR4: Enable ALL
312         PRI::gen "$portno WD 46 80";    # GCR: (Global Configuration Register)
313                                         #      VIS (Masked Interrupts Visible)
314
315         PRI::gen "$portno WD 08 04";    # IPC: SYNC is 8 Khz
316
317         PRI::gen "$portno WD 02 51";    # CMDR (Command Register): RRES, XRES, SRES (Receiver/Transmitter reset)
318         PRI::gen "$portno WD 02 00";    # CMDR
319
320
321         PRI::gen "$portno WD 45 00";    # CMR2: External sources for SYPR, SCLKR, SYPX, SCLKX for TX and RX.
322
323         #  Configure ports
324         PRI::gen "$portno WD 85 80";            # GPC1 (Global Port Configuration 1):
325         #PRI::gen "$portno WD 85 00";           # GPC1 (Global Port Configuration 1):
326                                                                 #      SMM (System Interface Multiplex Mode)
327         PRI::gen "$portno WD 80 00";    # PC1: SYPR/SYPX provided to RPA/XPA inputs
328
329         PRI::gen "$portno WD 84 31";    # PC5: XMFS active low, SCLKR is input, RCLK is output (unused)
330         PRI::gen "$portno WD 3B 00";    # Clear LCR1 - Loop Code Register 1
331
332         #  printk("TE110P: Successfully initialized serial bus for card\n");
333
334         # Initialize PCM and SIG regs
335         PRI::gen "$portno WD A0 00";    # TSEO (Time Slot Even/Odd Select) 
336         PRI::gen "$portno WD A1 FF";    # TSBS (Time Slot Bit Select)- only selected bits are used for HDLC channel 1
337                                         #      in selected time slots
338         PRI::gen "$portno WD 03 89";    # Mode Register:
339                                         #      MDS  (Mode Select) = 100 (No address comparison)
340                                         #      HRAC (Receiver Active - HDLC channel 1) 
341                                         #      RFT2 (HDLC Receive FIFO is 64 byte deep)
342         my $ccr1 = 0x18;                # CCR1 (Common Configuration Register1)
343                                         #      EITS (Enable Internal Time Slot 0 to 31 Signalling)
344                                         #      ITF  (Interframe Time Fill)
345         my $sysfs_pri_protocol;
346         if (defined $pri_protocol) {
347                 $sysfs_pri_protocol = $pri_protocol;
348         } else {
349                 my $file = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/pri_protocol",
350                                 $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $portno;
351                 # The 'open' will fail if the port does not exist.
352                 # (or rather: the XPD for it does not exist). While
353                 # we only read this file to get the default E1/T1 value,
354                 # if it does not exist, it also implies the commands sent would
355                 # get nowhere. So we might as well quit now.
356                 open(F, $file) || return;
357                 $sysfs_pri_protocol = <F>;
358                 close F;
359                 chomp $sysfs_pri_protocol;
360         }
361         if($sysfs_pri_protocol eq 'T1') {
362                 $ccr1 |= 0x80;          #      RSCC (Serial CAS Format Selection)
363         }
364
365         PRI::gen "$portno WD 09 %02X", $ccr1;
366         PRI::gen "$portno WD 0A 04";    # CCR2 (Common Configuration Register2)
367                                         #      RCRC (enable CRC - HDLC channel 1enable CRC - HDLC channel 1)
368         PRI::gen "$portno WD 0C 00";    # RTR1 (Receive  Time Slot register 1)
369         PRI::gen "$portno WD 0D 00";    # RTR2 (Receive  Time Slot register 2)
370         PRI::gen "$portno WD 0E 00";    # RTR3 (Receive  Time Slot register 3), TS16 (Enable time slot 16) 
371         PRI::gen "$portno WD 0F 00";    # RTR4 (Receive  Time Slot register 4)
372
373         PRI::gen "$portno WD 10 00";    # TTR1 (Transmit Time Slot register 1)
374         PRI::gen "$portno WD 11 00";    # TTR2 (Transmit Time Slot register 2)
375         PRI::gen "$portno WD 12 00";    # TTR3 (Transmit Time Slot register 3), TS16 (Enable time slot 16) 
376         PRI::gen "$portno WD 13 00";    # TTR4 (Transmit Time Slot register 4)
377
378         # configure the best performance of the Bipolar Violation detection for all four channels
379         PRI::gen "$portno WD BD 00";    # BFR (Bugfix Register): ~BVP (Bipolar Violations),
380                                         #                         use Improved Bipolar Violation Detection instead
381 }
382
383 package main;
384
385 main::debug "Starting '$0'";
386
387 PRI::read_defaults;
388
389 sub main() {
390         my @ports;
391         my $subunit;
392
393         main::debug "main(): Initializing chip ($ENV{UNIT_SUBUNITS} ports)";
394         PRI::init_quad;
395         # Must initialize all 4 ports, regardless how much there are
396         for($subunit = 0; $subunit < 4; $subunit++) {
397                 #main::debug "main(): Initializing subunit $subunit";
398                 my $p = PRI::Port->new(
399                                 'PORT_NUM'              => $subunit,
400                                 'EXIST'                 => ($subunit < $ENV{UNIT_SUBUNITS})
401                                 );
402                 $p->port_setup;
403                 push(@ports, $p);
404         }
405         PRI::finish_quad;
406         foreach my $p (@ports) {
407                 if($p->{EXIST}) {
408                         $p->write_pri_info;
409                 }
410         }
411 }
412
413 main;
414
415 main::debug "Ending '$0'";
416
417 close REG;
418 close STDERR;
419 exit 0;