init_card_3_30 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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) 2006, 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. #
  36. # Output data format:
  37. # - An optional comment start with ';' or '#' until the end of line
  38. # - Optional Blank lines are ignored
  39. # - Fields are whitespace separated (spaces or tabs)
  40. #
  41. # The fields are (in command line order):
  42. # 1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
  43. # 2. Command word:
  44. # - RD Read Direct register.
  45. # - RS Read Sub-register.
  46. # - WD Write Direct register.
  47. # - WS Write Sub-register.
  48. # 3. Register number in hexadecimal.
  49. # 4. Subregister number in hexadecimal. (for RS and WS commands).
  50. # 5. Data byte in hexadecimal. (for WD and WS commands only).
  51. #
  52. package main;
  53. use File::Basename;
  54. use Getopt::Std;
  55. my $program = basename("$0");
  56. my $init_dir = dirname("$0");
  57. BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
  58. use XppConfig $init_dir;
  59. my $unit_id;
  60. my %opts;
  61. getopts('o:', \%opts);
  62. my %settings;
  63. sub logit {
  64. print STDERR "$unit_id: @_\n";
  65. }
  66. sub debug {
  67. logit @_ if $settings{debug};
  68. }
  69. # Arrange for error logging
  70. if (-t STDERR) {
  71. $unit_id = 'Interactive';
  72. debug "Interactive startup";
  73. } else {
  74. $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
  75. open (STDERR, "| logger -t $program -p kern.info") || die;
  76. debug "Non Interactive startup";
  77. foreach my $k (qw(
  78. XBUS_NAME
  79. XBUS_NUMBER
  80. UNIT_NUMBER
  81. UNIT_TYPE
  82. UNIT_SUBUNITS
  83. UNIT_SUBUNITS_DIR
  84. XBUS_REVISION
  85. XBUS_CONNECTOR
  86. XBUS_LABEL)) {
  87. unless(defined $ENV{$k}) {
  88. logit "Missing ENV{$k}\n";
  89. die;
  90. }
  91. }
  92. }
  93. sub select_subunit($) {
  94. my $subunit = shift;
  95. die unless defined $subunit;
  96. my $output;
  97. if($opts{o}) {
  98. $output = $opts{o};
  99. } else {
  100. $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs",
  101. $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
  102. if(! -f $output) {
  103. my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
  104. $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
  105. logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
  106. if -f $output;
  107. }
  108. }
  109. open(REG, ">$output") || die "Failed to open '$output': $!\n";
  110. my $oldfh = select REG;
  111. print "# Selecting subunit $subunit\n" if $opts{o};
  112. return $oldfh;
  113. }
  114. package BRI;
  115. sub gen {
  116. my $fmt = shift;
  117. $| = 1;
  118. printf "$fmt\n", @_;
  119. }
  120. # Turning on/off multi-byte packet reception.
  121. sub multibyte($) {
  122. my $active = (shift) ? 'M' : 'm';
  123. for my $subunit (0 .. $ENV{UNIT_SUBUNITS} - 1) {
  124. #main::logit "multibyte(): $subunit -> $active";
  125. main::select_subunit($subunit);
  126. BRI::gen "$subunit W$active";
  127. }
  128. }
  129. sub read_defaults() {
  130. if(XppConfig::read_config(\%settings)) {
  131. main::logit "Defaults from $settings{xppconf}";
  132. } else {
  133. main::logit "No defaults file, use hard-coded defaults.";
  134. }
  135. }
  136. package BRI::Port;
  137. sub new {
  138. my $pack = shift;
  139. my $port = { @_ };
  140. bless $port, $pack;
  141. }
  142. # zap_xhfc_su.c:995
  143. sub init_su {
  144. my $port = shift;
  145. my $portnum = $port->{PORT_NUM};
  146. my $port_mode_up = $port->{PORT_MODE_UP};
  147. my $port_mode_exch = $port->{PORT_MODE_EXCH};
  148. my $bri_nt = $port->{BRI_NT};
  149. #main::logit "init_su(portnum=$portnum, port_mode_up=$port_mode_up, bri_nt=$bri_nt)";
  150. # Setting PLL
  151. # R_PLL_CTRL = 0 (V_PLL_M = 0, Reset PLL, Disable PLL_
  152. # R_CLK_CFG = 05 (PLL clock as system clock, output it to CLK_OUT pin)
  153. # R_PLL_P = 1
  154. # R_PLL_N = 6
  155. # R_PLL_S = 1
  156. # R_PLL_CTRL = 1 (V_PLL_M)
  157. BRI::gen "#--------------------------- init_su($portnum, $bri_nt, $port_mode_up, $port_mode_exch)";
  158. BRI::gen "$portnum WD 02 04";
  159. BRI::gen "$portnum WD 50 00"; # disable PLL
  160. BRI::gen "$portnum WD 51 02";
  161. BRI::gen "$portnum WD 52 06";
  162. BRI::gen "$portnum WD 53 04";
  163. BRI::gen "$portnum WD 50 01"; # Enable PLL
  164. BRI::gen "$portnum WD 02 05"; # Enable PLL
  165. su_sel($portnum); # select port
  166. if ("$port_mode_up" == 1) {
  167. $port->{CTRL3} = 0x01; # A_ST_CTRL3: V_ST_SEL = 1
  168. $port->{CTRL0} = 0x10; # A_SU_CTRL0: V_ST_SQ_EN = 1
  169. BRI::gen "$portnum WD 34 0F"; # A_MS_TX:
  170. # (multiframe/superframe transmit register)
  171. } else {
  172. $port->{CTRL3} = 0x00; # A_ST_CTRL3: V_ST_SEL = 0
  173. $port->{CTRL0} = 0x00; # A_SU_CTRL0: V_ST_SQ_EN = 0
  174. }
  175. if ("$bri_nt" == 1) {
  176. $port->{CTRL0} |= 0x04; # V_SU_MD
  177. }
  178. # ((V_SU_EXCH)?0x80:00) (change polarity)
  179. if($port_mode_exch) {
  180. $port->{CTRL2} = 0x80;
  181. } else {
  182. $port->{CTRL2} = 0x00;
  183. }
  184. BRI::gen "$portnum WD 35 %02X", $port->{CTRL3}; # A_ST_CTRL3
  185. BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0
  186. BRI::gen "$portnum WD 35 F8"; # A_ST_CTRL3 = set end of pulse control to 0xF8
  187. BRI::gen "$portnum WD 32 09"; # A_SU_CTRL1 = Ignore E-channel data, Force automatic transition from G2 to G3
  188. BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2
  189. # zap_xhfc_su.c:1030 in init_su()
  190. # A_SU_CLK_DLY
  191. my $clk_dly;
  192. if ("$bri_nt" == 1) {
  193. $clk_dly = 0x6C;
  194. } else {
  195. $clk_dly = 0x0E;
  196. }
  197. #main::logit "clk_dly=$clk_dly";
  198. BRI::gen "$portnum WD 37 %02X", "$clk_dly";
  199. }
  200. sub su_sel {
  201. if (@_ != 1 ) {
  202. main::logit "ERROR: su_sel() called with " . scalar(@_) . " parameters";
  203. exit 1;
  204. }
  205. my $portnum = shift;
  206. BRI::gen "$portnum WD 16 %02X", $portnum; # R_SU_SEL
  207. }
  208. # zap_xhfc_su.c:281
  209. sub xhfc_selfifo {
  210. my $port = shift;
  211. my $portnum = $port->{PORT_NUM};
  212. if (@_ != 1 ) {
  213. main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters";
  214. exit 1;
  215. }
  216. my $fifonum = shift;
  217. #main::logit "xhfc_selfifo($fifonum)";
  218. BRI::gen "$portnum WD 0F %02X", $fifonum;
  219. # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
  220. }
  221. # zap_xhfc_su.c:295
  222. sub xhfc_resetfifo() {
  223. my $port = shift;
  224. my $portnum = $port->{PORT_NUM};
  225. #main::logit "xhfc_resetfifo()";
  226. # A_INC_RES_FIFO = M_RES_FIFO | M_RES_FIFO_ERR
  227. BRI::gen "$portnum WD 0E 0A";
  228. # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
  229. }
  230. # zap_xhfc_su.c:1040
  231. # Initialize fifo (called for each portnum, channel, direction)
  232. sub setup_fifo {
  233. my $port = shift;
  234. my $chan = shift;
  235. my $direction = shift;
  236. my $conhdlc = shift;
  237. my $subcfg = shift;
  238. my $fifoctrl = shift;
  239. my $portnum = $port->{PORT_NUM};
  240. my $port_mode_up = $port->{PORT_MODE_UP};
  241. my $port_mode_exch = $port->{PORT_MODE_EXCH};
  242. my $bri_nt = $port->{BRI_NT};
  243. BRI::gen "#--------------------------- setup_fifo($portnum, $chan, $direction)";
  244. # my $fifonum = 0x80 | ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first
  245. my $fifonum = ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first
  246. my $r_slot = ($portnum << 3) | ($chan << 1) | ($direction);
  247. # channel order workaround, swap odd and even portnums in $r_slot for PCM (chan 0, 1) only
  248. if ("$chan" == 0 || "$chan" == 1) {
  249. $r_slot = $r_slot ^ 0x08;
  250. }
  251. my $short_portnum = $portnum & 0x03;
  252. my $a_sl_cfg = (0x80 | ($short_portnum << 3) | ($chan << 1) | ($direction)); # receive data from STIO2, transmit to STIO1
  253. #main::logit "setup_fifo($fifonum)";
  254. $port->xhfc_selfifo($fifonum);
  255. # A_CON_HDLC: transparent mode selection
  256. BRI::gen "$portnum WD FA %02X", $conhdlc;
  257. # A_SUBCH_CFG: subchnl params
  258. BRI::gen "$portnum WD FB %02X", $subcfg;
  259. # A_FIFO_CTRL: FIFO Control Register
  260. BRI::gen "$portnum WD FF %02X", $fifoctrl;
  261. $port->xhfc_resetfifo();
  262. $port->xhfc_selfifo($fifonum); # wait for busy is builtin in this command
  263. BRI::gen "$portnum WD 10 %02X", $r_slot; # R_SLOT
  264. BRI::gen "$portnum WD D0 %02X", $a_sl_cfg; # A_SL_CFG
  265. #system("/bin/echo \"----=====TE\" \"short_portnum=\"$short_portnum \"portnum=\" $portnum \"chan=\" $chan\"======----\n\" >>/root/xortel/test_init");
  266. }
  267. # zap_xhfc_su.c:1071
  268. sub setup_su {
  269. my $port = shift;
  270. my $bchan = shift;
  271. my $portnum = $port->{PORT_NUM};
  272. my $port_mode_exch = $port->{PORT_MODE_EXCH};
  273. my $bri_nt = $port->{BRI_NT};
  274. BRI::gen "#--------------------------- setup_su($portnum, $bchan)";
  275. #main::logit "setup_su(portnum=$portnum, bchan=$bchan, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)";
  276. $port->{CTRL0} |= (1 << $bchan) | $bri_nt;
  277. $port->{CTRL2} |= ($port_mode_exch << 7) | (1 << $bchan);
  278. su_sel($portnum); # Select port
  279. BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0: V_B1_TX_EN | V_SU_MD | (NT/TE)
  280. BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2: V_B1_RX_EN
  281. }
  282. sub xhfc_ph_command {
  283. my $port = shift;
  284. my $cmd = shift;
  285. my $portnum = $port->{PORT_NUM};
  286. #main::logit "xhfc_ph_command(portnum=$portnum)";
  287. if ("$cmd" eq "HFC_L1_ACTIVATE_TE") {
  288. su_sel($portnum); # Select port
  289. BRI::gen "$portnum WD 30 60"; # A_SU_WR_STA = (M_SU_ACT & 0x03)
  290. # (set activation)
  291. } elsif ("$cmd" eq "HFC_L1_FORCE_DEACTIVATE_TE") {
  292. su_sel($portnum); # Select port
  293. BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02)
  294. # (set deactivation)
  295. } elsif ("$cmd" eq "HFC_L1_ACTIVATE_NT") {
  296. su_sel($portnum); # Select port
  297. BRI::gen "$portnum WD 30 E0"; # A_SU_WR_STA = (M_SU_ACT & 0x03) | 0x80
  298. # (set activation + NT)
  299. } elsif ("$cmd" eq "HFC_L1_DEACTIVATE_NT") {
  300. su_sel($portnum); # Select port
  301. BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02)
  302. # (set deactivation)
  303. }
  304. }
  305. sub zthfc_startup {
  306. my $port = shift;
  307. my $portnum = $port->{PORT_NUM};
  308. my $port_mode_exch = $port->{PORT_MODE_EXCH};
  309. my $bri_nt = $port->{BRI_NT};
  310. #main::logit "zthfc_startup(portnum=$portnum, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)";
  311. # PCM <-> ST/Up Configuration
  312. foreach my $chan ( 0, 1 ) {
  313. $port->setup_fifo($chan, 0, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM
  314. $port->setup_fifo($chan, 1, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM
  315. $port->setup_su($chan); # zap_xhfc_su.c:194
  316. }
  317. # Dahdi chan 2 used as HDLC D-Channel
  318. $port->setup_fifo(2, 0, 0x05, 2, 0); # D-TX: zap_xhfc_su.c:205
  319. $port->setup_fifo(2, 1, 0x05, 2, 0); # D-RX: zap_xhfc_su.c:206
  320. # E-chan, Echo channel is ignored
  321. # enable this port's state machine
  322. su_sel($portnum); # Select port
  323. # A_SU_WR_STA: reset port state machine
  324. BRI::gen "$portnum WD 30 00";
  325. if ("$bri_nt" == 0) {
  326. $port->xhfc_ph_command("HFC_L1_ACTIVATE_TE");
  327. } else {
  328. $port->xhfc_ph_command("HFC_L1_ACTIVATE_NT");
  329. }
  330. }
  331. package main;
  332. debug "Starting '$0'";
  333. BRI::read_defaults;
  334. #------------------------------------------- Instance detection
  335. # zap_xhfc_su.c:895
  336. sub init_xhfc($) {
  337. my $portnum = shift;
  338. main::debug "init_xhfc($portnum)";
  339. BRI::gen "#--------------------------- init_xhfc";
  340. BRI::gen "$portnum WD 0D 00"; # r_FIFO_MD: 16 fifos,
  341. # 64 bytes for TX and RX each (FIFO mode config)
  342. # software reset to enable R_FIFO_MD setting
  343. BRI::gen "$portnum WD 00 08"; # R_CIRM = M_SRES (soft reset)
  344. # --> WAIT 5u
  345. BRI::gen "$portnum WD 00 00"; # R_CIRM = 0 (zero it to deactivate reset)
  346. # amplitude
  347. BRI::gen "$portnum WD 46 80"; # R_PWM_MD: (PWM output mode register)
  348. # PWM push to zero only
  349. BRI::gen "$portnum WD 39 18"; # R_PWM1: (modulator register for PWM1)
  350. # set duty cycle
  351. BRI::gen "$portnum WD 0C 11"; # R_FIFO_THRES: (FIFO fill lvl control register)
  352. # RX/TX threshold = 16 bytes
  353. # set PCM bus mode to slave by default
  354. BRI::gen "$portnum WD 14 08"; # R_PCM_MD0 = PCM slave mode, F0IO duration is 2 HFC_PCLK's
  355. # (C4IO, F0IO are inputs)
  356. BRI::gen "$portnum WD 14 98"; # R_PCM_MD0: Index value to select
  357. # the register at address 15
  358. BRI::gen "$portnum WD 15 20"; # R_PCM_MD1: V_PLL_ADJ (DPLL adjust speed),
  359. # in the last slot of PCM frame
  360. # V_PCM_DR, C4IO is 16.384MHz(128 time slots)
  361. BRI::gen "$portnum WD 4C 07"; # GPIOGPIO function (not PWM) on GPIO0, GPIO1 and GPIO2 pins
  362. BRI::gen "$portnum WD 4A 07"; # Output enable for GPIO0, GPIO1 and GPIO2 pins
  363. BRI::gen "$portnum WD 48 01"; # GPIO output data bits
  364. }
  365. my @port_type = (
  366. { 'BRI_NT' => 1 },
  367. { 'BRI_NT' => 0 }
  368. );
  369. # zap_xhfc_su.c:175
  370. sub main() {
  371. my $subunit;
  372. my $subunits_mask = pack("C", $ENV{UNIT_SUBUNITS_DIR});
  373. my @direction = split(//, unpack("b*", $subunits_mask));
  374. #logit "main(): UNIT_TYPE=$ENV{UNIT_TYPE} UNIT_SUBUNITS_DIR=[@direction]";
  375. if(!$opts{o}) {
  376. foreach my $var (qw(XBUS_NAME UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR)) {
  377. die "Missing mandatory '$var' environment variable" unless defined $var;
  378. }
  379. }
  380. # Turn off multi-byte packet reception before initialization started
  381. # Otherwise we mess with registers while the FPGA firmware tries to
  382. # send us packets.
  383. BRI::multibyte(0);
  384. # Port initialization
  385. for($subunit = 0; $subunit < $ENV{UNIT_SUBUNITS}; $subunit++) {
  386. my $is_nt = $direction[$subunit];
  387. main::select_subunit($subunit);
  388. if(($subunit % 4) == 0) { # A new xhfc chip
  389. #logit "main(): Initializing chip";
  390. init_xhfc($subunit); # zap_xhfc_su.c:1173 in setup_instance()
  391. }
  392. #logit "main(): Initializing subunit $subunit is_nt=$is_nt";
  393. my $p = BRI::Port->new(
  394. 'PORT_NUM' => $subunit,
  395. 'BRI_NT' => $is_nt,
  396. 'PORT_MODE_UP' => 0,
  397. 'PORT_MODE_EXCH' => 0
  398. );
  399. # zap_XHfc_su.c:1186 in setup_instance()
  400. $p->init_su;
  401. $p->zthfc_startup;
  402. }
  403. # Turn on multi-byte packet reception when ports initialization finished
  404. BRI::multibyte(1);
  405. }
  406. main;
  407. debug "Ending '$0'";
  408. close REG;
  409. close STDERR;
  410. exit 0;