init_card_4_30 13 KB

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