sym_nvram.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:18k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
  3.  * of PCI-SCSI IO processors.
  4.  *
  5.  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
  6.  *
  7.  * This driver is derived from the Linux sym53c8xx driver.
  8.  * Copyright (C) 1998-2000  Gerard Roudier
  9.  *
  10.  * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
  11.  * a port of the FreeBSD ncr driver to Linux-1.2.13.
  12.  *
  13.  * The original ncr driver has been written for 386bsd and FreeBSD by
  14.  *         Wolfgang Stanglmeier        <wolf@cologne.de>
  15.  *         Stefan Esser                <se@mi.Uni-Koeln.de>
  16.  * Copyright (C) 1994  Wolfgang Stanglmeier
  17.  *
  18.  * Other major contributions:
  19.  *
  20.  * NVRAM detection and reading.
  21.  * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
  22.  *
  23.  *-----------------------------------------------------------------------------
  24.  *
  25.  * Redistribution and use in source and binary forms, with or without
  26.  * modification, are permitted provided that the following conditions
  27.  * are met:
  28.  * 1. Redistributions of source code must retain the above copyright
  29.  *    notice, this list of conditions and the following disclaimer.
  30.  * 2. The name of the author may not be used to endorse or promote products
  31.  *    derived from this software without specific prior written permission.
  32.  *
  33.  * Where this Software is combined with software released under the terms of 
  34.  * the GNU Public License ("GPL") and the terms of the GPL would require the 
  35.  * combined work to also be released under the terms of the GPL, the terms
  36.  * and conditions of this License will apply in addition to those of the
  37.  * GPL with the exception of any terms or conditions of this License that
  38.  * conflict with, or are expressly prohibited by, the GPL.
  39.  *
  40.  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
  41.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  42.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  43.  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  44.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  45.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  46.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  47.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  48.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  49.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  50.  * SUCH DAMAGE.
  51.  */
  52. #ifdef __FreeBSD__
  53. #include <dev/sym/sym_glue.h>
  54. #else
  55. #include "sym_glue.h"
  56. #endif
  57. /*
  58.  *  Some poor and bogus sync table that refers to Tekram NVRAM layout.
  59.  */
  60. #if SYM_CONF_NVRAM_SUPPORT
  61. static u_char Tekram_sync[16] =
  62. {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
  63. #ifdef SYM_CONF_DEBUG_NVRAM
  64. static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
  65. #endif
  66. #endif
  67. /*
  68.  *  Get host setup from NVRAM.
  69.  */
  70. void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram)
  71. {
  72. #if SYM_CONF_NVRAM_SUPPORT
  73. /*
  74.  *  Get parity checking, host ID, verbose mode 
  75.  *  and miscellaneous host flags from NVRAM.
  76.  */
  77. switch(nvram->type) {
  78. case SYM_SYMBIOS_NVRAM:
  79. if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
  80. np->rv_scntl0  &= ~0x0a;
  81. np->myaddr = nvram->data.Symbios.host_id & 0x0f;
  82. if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
  83. np->verbose += 1;
  84. if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
  85. np->usrflags |= SYM_SCAN_TARGETS_HILO;
  86. if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
  87. np->usrflags |= SYM_AVOID_BUS_RESET;
  88. break;
  89. case SYM_TEKRAM_NVRAM:
  90. np->myaddr = nvram->data.Tekram.host_id & 0x0f;
  91. break;
  92. default:
  93. break;
  94. }
  95. #endif
  96. }
  97. /*
  98.  *  Get target setup from NVRAM.
  99.  */
  100. #if SYM_CONF_NVRAM_SUPPORT
  101. static void sym_Symbios_setup_target(hcb_p np,int target, Symbios_nvram *nvram);
  102. static void sym_Tekram_setup_target(hcb_p np,int target, Tekram_nvram *nvram);
  103. #endif
  104. void sym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp)
  105. {
  106. #if SYM_CONF_NVRAM_SUPPORT
  107. switch(nvp->type) {
  108. case SYM_SYMBIOS_NVRAM:
  109. sym_Symbios_setup_target (np, target, &nvp->data.Symbios);
  110. break;
  111. case SYM_TEKRAM_NVRAM:
  112. sym_Tekram_setup_target (np, target, &nvp->data.Tekram);
  113. break;
  114. default:
  115. break;
  116. }
  117. #endif
  118. }
  119. #if SYM_CONF_NVRAM_SUPPORT
  120. /*
  121.  *  Get target set-up from Symbios format NVRAM.
  122.  */
  123. static void
  124. sym_Symbios_setup_target(hcb_p np, int target, Symbios_nvram *nvram)
  125. {
  126. tcb_p tp = &np->target[target];
  127. Symbios_target *tn = &nvram->target[target];
  128. tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0;
  129. tp->tinfo.user.width  = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT;
  130. tp->usrtags =
  131. (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0;
  132. if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
  133. tp->usrflags &= ~SYM_DISC_ENABLED;
  134. if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
  135. tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
  136. if (!(tn->flags & SYMBIOS_SCAN_LUNS))
  137. tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
  138. }
  139. /*
  140.  *  Get target set-up from Tekram format NVRAM.
  141.  */
  142. static void
  143. sym_Tekram_setup_target(hcb_p np, int target, Tekram_nvram *nvram)
  144. {
  145. tcb_p tp = &np->target[target];
  146. struct Tekram_target *tn = &nvram->target[target];
  147. int i;
  148. if (tn->flags & TEKRAM_SYNC_NEGO) {
  149. i = tn->sync_index & 0xf;
  150. tp->tinfo.user.period = Tekram_sync[i];
  151. }
  152. tp->tinfo.user.width =
  153. (tn->flags & TEKRAM_WIDE_NEGO) ? BUS_16_BIT : BUS_8_BIT;
  154. if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
  155. tp->usrtags = 2 << nvram->max_tags_index;
  156. }
  157. if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
  158. tp->usrflags |= SYM_DISC_ENABLED;
  159.  
  160. /* If any device does not support parity, we will not use this option */
  161. if (!(tn->flags & TEKRAM_PARITY_CHECK))
  162. np->rv_scntl0  &= ~0x0a; /* SCSI parity checking disabled */
  163. }
  164. #ifdef SYM_CONF_DEBUG_NVRAM
  165. /*
  166.  *  Dump Symbios format NVRAM for debugging purpose.
  167.  */
  168. static void sym_display_Symbios_nvram(sdev_p np, Symbios_nvram *nvram)
  169. {
  170. int i;
  171. /* display Symbios nvram host data */
  172. printf("%s: HOST ID=%d%s%s%s%s%s%sn",
  173. sym_name(np), nvram->host_id & 0x0f,
  174. (nvram->flags  & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
  175. (nvram->flags  & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"",
  176. (nvram->flags  & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", 
  177. (nvram->flags  & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", 
  178. (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"",
  179. (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"");
  180. /* display Symbios nvram drive data */
  181. for (i = 0 ; i < 15 ; i++) {
  182. struct Symbios_target *tn = &nvram->target[i];
  183. printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%dn",
  184. sym_name(np), i,
  185. (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "",
  186. (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "",
  187. (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "",
  188. (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "",
  189. tn->bus_width,
  190. tn->sync_period / 4,
  191. tn->timeout);
  192. }
  193. }
  194. /*
  195.  *  Dump TEKRAM format NVRAM for debugging purpose.
  196.  */
  197. static void sym_display_Tekram_nvram(sdev_p np, Tekram_nvram *nvram)
  198. {
  199. int i, tags, boot_delay;
  200. char *rem;
  201. /* display Tekram nvram host data */
  202. tags = 2 << nvram->max_tags_index;
  203. boot_delay = 0;
  204. if (nvram->boot_delay_index < 6)
  205. boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
  206. switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
  207. default:
  208. case 0: rem = ""; break;
  209. case 1: rem = " REMOVABLE=boot device"; break;
  210. case 2: rem = " REMOVABLE=all"; break;
  211. }
  212. printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%dn",
  213. sym_name(np), nvram->host_id & 0x0f,
  214. (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
  215. (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
  216. (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"",
  217. (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"",
  218. (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"",
  219. (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"",
  220. (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"",
  221. (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"",
  222. rem, boot_delay, tags);
  223. /* display Tekram nvram drive data */
  224. for (i = 0; i <= 15; i++) {
  225. int sync, j;
  226. struct Tekram_target *tn = &nvram->target[i];
  227. j = tn->sync_index & 0xf;
  228. sync = Tekram_sync[j];
  229. printf("%s-%d:%s%s%s%s%s%s PERIOD=%dn",
  230. sym_name(np), i,
  231. (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "",
  232. (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "",
  233. (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "",
  234. (tn->flags & TEKRAM_START_CMD) ? " START" : "",
  235. (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "",
  236. (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "",
  237. sync);
  238. }
  239. }
  240. #endif /* SYM_CONF_DEBUG_NVRAM */
  241. #endif /* SYM_CONF_NVRAM_SUPPORT */
  242. /*
  243.  *  Try reading Symbios or Tekram NVRAM
  244.  */
  245. #if SYM_CONF_NVRAM_SUPPORT
  246. static int sym_read_Symbios_nvram (sdev_p np, Symbios_nvram *nvram);
  247. static int sym_read_Tekram_nvram  (sdev_p np, Tekram_nvram *nvram);
  248. #endif
  249. int sym_read_nvram (sdev_p np, struct sym_nvram *nvp)
  250. {
  251. #if SYM_CONF_NVRAM_SUPPORT
  252. /*
  253.  *  Try to read SYMBIOS nvram.
  254.  *  Try to read TEKRAM nvram if Symbios nvram not found.
  255.  */
  256. if (SYM_SETUP_SYMBIOS_NVRAM &&
  257.  !sym_read_Symbios_nvram (np, &nvp->data.Symbios)) {
  258. nvp->type = SYM_SYMBIOS_NVRAM;
  259. #ifdef SYM_CONF_DEBUG_NVRAM
  260. sym_display_Symbios_nvram(np, &nvp->data.Symbios);
  261. #endif
  262. }
  263. else if (SYM_SETUP_TEKRAM_NVRAM &&
  264.  !sym_read_Tekram_nvram (np, &nvp->data.Tekram)) {
  265. nvp->type = SYM_TEKRAM_NVRAM;
  266. #ifdef SYM_CONF_DEBUG_NVRAM
  267. sym_display_Tekram_nvram(np, &nvp->data.Tekram);
  268. #endif
  269. }
  270. else
  271. nvp->type = 0;
  272. #else
  273. nvp->type = 0;
  274. #endif
  275. return nvp->type;
  276. }
  277. #if SYM_CONF_NVRAM_SUPPORT
  278. /*
  279.  *  24C16 EEPROM reading.
  280.  *
  281.  *  GPOI0 - data in/data out
  282.  *  GPIO1 - clock
  283.  *  Symbios NVRAM wiring now also used by Tekram.
  284.  */
  285. #define SET_BIT 0
  286. #define CLR_BIT 1
  287. #define SET_CLK 2
  288. #define CLR_CLK 3
  289. /*
  290.  *  Set/clear data/clock bit in GPIO0
  291.  */
  292. static void S24C16_set_bit(sdev_p np, u_char write_bit, u_char *gpreg, 
  293.   int bit_mode)
  294. {
  295. UDELAY (5);
  296. switch (bit_mode){
  297. case SET_BIT:
  298. *gpreg |= write_bit;
  299. break;
  300. case CLR_BIT:
  301. *gpreg &= 0xfe;
  302. break;
  303. case SET_CLK:
  304. *gpreg |= 0x02;
  305. break;
  306. case CLR_CLK:
  307. *gpreg &= 0xfd;
  308. break;
  309. }
  310. OUTB (nc_gpreg, *gpreg);
  311. UDELAY (5);
  312. }
  313. /*
  314.  *  Send START condition to NVRAM to wake it up.
  315.  */
  316. static void S24C16_start(sdev_p np, u_char *gpreg)
  317. {
  318. S24C16_set_bit(np, 1, gpreg, SET_BIT);
  319. S24C16_set_bit(np, 0, gpreg, SET_CLK);
  320. S24C16_set_bit(np, 0, gpreg, CLR_BIT);
  321. S24C16_set_bit(np, 0, gpreg, CLR_CLK);
  322. }
  323. /*
  324.  *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
  325.  */
  326. static void S24C16_stop(sdev_p np, u_char *gpreg)
  327. {
  328. S24C16_set_bit(np, 0, gpreg, SET_CLK);
  329. S24C16_set_bit(np, 1, gpreg, SET_BIT);
  330. }
  331. /*
  332.  *  Read or write a bit to the NVRAM,
  333.  *  read if GPIO0 input else write if GPIO0 output
  334.  */
  335. static void S24C16_do_bit(sdev_p np, u_char *read_bit, u_char write_bit, 
  336.  u_char *gpreg)
  337. {
  338. S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
  339. S24C16_set_bit(np, 0, gpreg, SET_CLK);
  340. if (read_bit)
  341. *read_bit = INB (nc_gpreg);
  342. S24C16_set_bit(np, 0, gpreg, CLR_CLK);
  343. S24C16_set_bit(np, 0, gpreg, CLR_BIT);
  344. }
  345. /*
  346.  *  Output an ACK to the NVRAM after reading,
  347.  *  change GPIO0 to output and when done back to an input
  348.  */
  349. static void S24C16_write_ack(sdev_p np, u_char write_bit, u_char *gpreg, 
  350.     u_char *gpcntl)
  351. {
  352. OUTB (nc_gpcntl, *gpcntl & 0xfe);
  353. S24C16_do_bit(np, 0, write_bit, gpreg);
  354. OUTB (nc_gpcntl, *gpcntl);
  355. }
  356. /*
  357.  *  Input an ACK from NVRAM after writing,
  358.  *  change GPIO0 to input and when done back to an output
  359.  */
  360. static void S24C16_read_ack(sdev_p np, u_char *read_bit, u_char *gpreg, 
  361.    u_char *gpcntl)
  362. {
  363. OUTB (nc_gpcntl, *gpcntl | 0x01);
  364. S24C16_do_bit(np, read_bit, 1, gpreg);
  365. OUTB (nc_gpcntl, *gpcntl);
  366. }
  367. /*
  368.  *  WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
  369.  *  GPIO0 must already be set as an output
  370.  */
  371. static void S24C16_write_byte(sdev_p np, u_char *ack_data, u_char write_data, 
  372.      u_char *gpreg, u_char *gpcntl)
  373. {
  374. int x;
  375. for (x = 0; x < 8; x++)
  376. S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
  377. S24C16_read_ack(np, ack_data, gpreg, gpcntl);
  378. }
  379. /*
  380.  *  READ a byte from the NVRAM and then send an ACK to say we have got it,
  381.  *  GPIO0 must already be set as an input
  382.  */
  383. static void S24C16_read_byte(sdev_p np, u_char *read_data, u_char ack_data, 
  384.     u_char *gpreg, u_char *gpcntl)
  385. {
  386. int x;
  387. u_char read_bit;
  388. *read_data = 0;
  389. for (x = 0; x < 8; x++) {
  390. S24C16_do_bit(np, &read_bit, 1, gpreg);
  391. *read_data |= ((read_bit & 0x01) << (7 - x));
  392. }
  393. S24C16_write_ack(np, ack_data, gpreg, gpcntl);
  394. }
  395. /*
  396.  *  Read 'len' bytes starting at 'offset'.
  397.  */
  398. static int sym_read_S24C16_nvram (sdev_p np, int offset, u_char *data, int len)
  399. {
  400. u_char gpcntl, gpreg;
  401. u_char old_gpcntl, old_gpreg;
  402. u_char ack_data;
  403. int retv = 1;
  404. int x;
  405. /* save current state of GPCNTL and GPREG */
  406. old_gpreg = INB (nc_gpreg);
  407. old_gpcntl = INB (nc_gpcntl);
  408. gpcntl = old_gpcntl & 0x1c;
  409. /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
  410. OUTB (nc_gpreg,  old_gpreg);
  411. OUTB (nc_gpcntl, gpcntl);
  412. /* this is to set NVRAM into a known state with GPIO0/1 both low */
  413. gpreg = old_gpreg;
  414. S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
  415. S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
  416. /* now set NVRAM inactive with GPIO0/1 both high */
  417. S24C16_stop(np, &gpreg);
  418. /* activate NVRAM */
  419. S24C16_start(np, &gpreg);
  420. /* write device code and random address MSB */
  421. S24C16_write_byte(np, &ack_data,
  422. 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
  423. if (ack_data & 0x01)
  424. goto out;
  425. /* write random address LSB */
  426. S24C16_write_byte(np, &ack_data,
  427. offset & 0xff, &gpreg, &gpcntl);
  428. if (ack_data & 0x01)
  429. goto out;
  430. /* regenerate START state to set up for reading */
  431. S24C16_start(np, &gpreg);
  432. /* rewrite device code and address MSB with read bit set (lsb = 0x01) */
  433. S24C16_write_byte(np, &ack_data,
  434. 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
  435. if (ack_data & 0x01)
  436. goto out;
  437. /* now set up GPIO0 for inputting data */
  438. gpcntl |= 0x01;
  439. OUTB (nc_gpcntl, gpcntl);
  440. /* input all requested data - only part of total NVRAM */
  441. for (x = 0; x < len; x++) 
  442. S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
  443. /* finally put NVRAM back in inactive mode */
  444. gpcntl &= 0xfe;
  445. OUTB (nc_gpcntl, gpcntl);
  446. S24C16_stop(np, &gpreg);
  447. retv = 0;
  448. out:
  449. /* return GPIO0/1 to original states after having accessed NVRAM */
  450. OUTB (nc_gpcntl, old_gpcntl);
  451. OUTB (nc_gpreg,  old_gpreg);
  452. return retv;
  453. }
  454. #undef SET_BIT
  455. #undef CLR_BIT
  456. #undef SET_CLK
  457. #undef CLR_CLK
  458. /*
  459.  *  Try reading Symbios NVRAM.
  460.  *  Return 0 if OK.
  461.  */
  462. static int sym_read_Symbios_nvram (sdev_p np, Symbios_nvram *nvram)
  463. {
  464. static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
  465. u_char *data = (u_char *) nvram;
  466. int len  = sizeof(*nvram);
  467. u_short csum;
  468. int x;
  469. /* probe the 24c16 and read the SYMBIOS 24c16 area */
  470. if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
  471. return 1;
  472. /* check valid NVRAM signature, verify byte count and checksum */
  473. if (nvram->type != 0 ||
  474.     bcmp(nvram->trailer, Symbios_trailer, 6) ||
  475.     nvram->byte_count != len - 12)
  476. return 1;
  477. /* verify checksum */
  478. for (x = 6, csum = 0; x < len - 6; x++)
  479. csum += data[x];
  480. if (csum != nvram->checksum)
  481. return 1;
  482. return 0;
  483. }
  484. /*
  485.  *  93C46 EEPROM reading.
  486.  *
  487.  *  GPOI0 - data in
  488.  *  GPIO1 - data out
  489.  *  GPIO2 - clock
  490.  *  GPIO4 - chip select
  491.  *
  492.  *  Used by Tekram.
  493.  */
  494. /*
  495.  *  Pulse clock bit in GPIO0
  496.  */
  497. static void T93C46_Clk(sdev_p np, u_char *gpreg)
  498. {
  499. OUTB (nc_gpreg, *gpreg | 0x04);
  500. UDELAY (2);
  501. OUTB (nc_gpreg, *gpreg);
  502. }
  503. /* 
  504.  *  Read bit from NVRAM
  505.  */
  506. static void T93C46_Read_Bit(sdev_p np, u_char *read_bit, u_char *gpreg)
  507. {
  508. UDELAY (2);
  509. T93C46_Clk(np, gpreg);
  510. *read_bit = INB (nc_gpreg);
  511. }
  512. /*
  513.  *  Write bit to GPIO0
  514.  */
  515. static void T93C46_Write_Bit(sdev_p np, u_char write_bit, u_char *gpreg)
  516. {
  517. if (write_bit & 0x01)
  518. *gpreg |= 0x02;
  519. else
  520. *gpreg &= 0xfd;
  521. *gpreg |= 0x10;
  522. OUTB (nc_gpreg, *gpreg);
  523. UDELAY (2);
  524. T93C46_Clk(np, gpreg);
  525. }
  526. /*
  527.  *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
  528.  */
  529. static void T93C46_Stop(sdev_p np, u_char *gpreg)
  530. {
  531. *gpreg &= 0xef;
  532. OUTB (nc_gpreg, *gpreg);
  533. UDELAY (2);
  534. T93C46_Clk(np, gpreg);
  535. }
  536. /*
  537.  *  Send read command and address to NVRAM
  538.  */
  539. static void T93C46_Send_Command(sdev_p np, u_short write_data, 
  540. u_char *read_bit, u_char *gpreg)
  541. {
  542. int x;
  543. /* send 9 bits, start bit (1), command (2), address (6)  */
  544. for (x = 0; x < 9; x++)
  545. T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
  546. *read_bit = INB (nc_gpreg);
  547. }
  548. /*
  549.  *  READ 2 bytes from the NVRAM
  550.  */
  551. static void T93C46_Read_Word(sdev_p np, u_short *nvram_data, u_char *gpreg)
  552. {
  553. int x;
  554. u_char read_bit;
  555. *nvram_data = 0;
  556. for (x = 0; x < 16; x++) {
  557. T93C46_Read_Bit(np, &read_bit, gpreg);
  558. if (read_bit & 0x01)
  559. *nvram_data |=  (0x01 << (15 - x));
  560. else
  561. *nvram_data &= ~(0x01 << (15 - x));
  562. }
  563. }
  564. /*
  565.  *  Read Tekram NvRAM data.
  566.  */
  567. static int T93C46_Read_Data(sdev_p np, u_short *data,int len,u_char *gpreg)
  568. {
  569. u_char read_bit;
  570. int x;
  571. for (x = 0; x < len; x++)  {
  572. /* output read command and address */
  573. T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
  574. if (read_bit & 0x01)
  575. return 1; /* Bad */
  576. T93C46_Read_Word(np, &data[x], gpreg);
  577. T93C46_Stop(np, gpreg);
  578. }
  579. return 0;
  580. }
  581. /*
  582.  *  Try reading 93C46 Tekram NVRAM.
  583.  */
  584. static int sym_read_T93C46_nvram (sdev_p np, Tekram_nvram *nvram)
  585. {
  586. u_char gpcntl, gpreg;
  587. u_char old_gpcntl, old_gpreg;
  588. int retv = 1;
  589. /* save current state of GPCNTL and GPREG */
  590. old_gpreg = INB (nc_gpreg);
  591. old_gpcntl = INB (nc_gpcntl);
  592. /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
  593.    1/2/4 out */
  594. gpreg = old_gpreg & 0xe9;
  595. OUTB (nc_gpreg, gpreg);
  596. gpcntl = (old_gpcntl & 0xe9) | 0x09;
  597. OUTB (nc_gpcntl, gpcntl);
  598. /* input all of NVRAM, 64 words */
  599. retv = T93C46_Read_Data(np, (u_short *) nvram,
  600. sizeof(*nvram) / sizeof(short), &gpreg);
  601. /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
  602. OUTB (nc_gpcntl, old_gpcntl);
  603. OUTB (nc_gpreg,  old_gpreg);
  604. return retv;
  605. }
  606. /*
  607.  *  Try reading Tekram NVRAM.
  608.  *  Return 0 if OK.
  609.  */
  610. static int sym_read_Tekram_nvram (sdev_p np, Tekram_nvram *nvram)
  611. {
  612. u_char *data = (u_char *) nvram;
  613. int len = sizeof(*nvram);
  614. u_short csum;
  615. int x;
  616. switch (np->device_id) {
  617. case PCI_ID_SYM53C885:
  618. case PCI_ID_SYM53C895:
  619. case PCI_ID_SYM53C896:
  620. x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
  621.   data, len);
  622. break;
  623. case PCI_ID_SYM53C875:
  624. x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
  625.   data, len);
  626. if (!x)
  627. break;
  628. default:
  629. x = sym_read_T93C46_nvram(np, nvram);
  630. break;
  631. }
  632. if (x)
  633. return 1;
  634. /* verify checksum */
  635. for (x = 0, csum = 0; x < len - 1; x += 2)
  636. csum += data[x] + (data[x+1] << 8);
  637. if (csum != 0x1234)
  638. return 1;
  639. return 0;
  640. }
  641. #endif /* SYM_CONF_NVRAM_SUPPORT */