11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 41da177e4SLinus Torvalds * of PCI-SCSI IO processors. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This driver is derived from the Linux sym53c8xx driver. 91da177e4SLinus Torvalds * Copyright (C) 1998-2000 Gerard Roudier 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 121da177e4SLinus Torvalds * a port of the FreeBSD ncr driver to Linux-1.2.13. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * The original ncr driver has been written for 386bsd and FreeBSD by 151da177e4SLinus Torvalds * Wolfgang Stanglmeier <wolf@cologne.de> 161da177e4SLinus Torvalds * Stefan Esser <se@mi.Uni-Koeln.de> 171da177e4SLinus Torvalds * Copyright (C) 1994 Wolfgang Stanglmeier 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * Other major contributions: 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * NVRAM detection and reading. 221da177e4SLinus Torvalds * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> 231da177e4SLinus Torvalds * 241da177e4SLinus Torvalds *----------------------------------------------------------------------------- 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include "sym_glue.h" 281da177e4SLinus Torvalds #include "sym_nvram.h" 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #ifdef SYM_CONF_DEBUG_NVRAM 311da177e4SLinus Torvalds static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; 321da177e4SLinus Torvalds #endif 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* 351da177e4SLinus Torvalds * Get host setup from NVRAM. 361da177e4SLinus Torvalds */ 371da177e4SLinus Torvalds void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) 381da177e4SLinus Torvalds { 391da177e4SLinus Torvalds /* 401da177e4SLinus Torvalds * Get parity checking, host ID, verbose mode 411da177e4SLinus Torvalds * and miscellaneous host flags from NVRAM. 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds switch (nvram->type) { 441da177e4SLinus Torvalds case SYM_SYMBIOS_NVRAM: 451da177e4SLinus Torvalds if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) 461da177e4SLinus Torvalds np->rv_scntl0 &= ~0x0a; 471da177e4SLinus Torvalds np->myaddr = nvram->data.Symbios.host_id & 0x0f; 481da177e4SLinus Torvalds if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) 491da177e4SLinus Torvalds np->verbose += 1; 501da177e4SLinus Torvalds if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) 511da177e4SLinus Torvalds shost->reverse_ordering = 1; 521da177e4SLinus Torvalds if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) 531da177e4SLinus Torvalds np->usrflags |= SYM_AVOID_BUS_RESET; 541da177e4SLinus Torvalds break; 551da177e4SLinus Torvalds case SYM_TEKRAM_NVRAM: 561da177e4SLinus Torvalds np->myaddr = nvram->data.Tekram.host_id & 0x0f; 571da177e4SLinus Torvalds break; 581da177e4SLinus Torvalds #ifdef CONFIG_PARISC 591da177e4SLinus Torvalds case SYM_PARISC_PDC: 601da177e4SLinus Torvalds if (nvram->data.parisc.host_id != -1) 611da177e4SLinus Torvalds np->myaddr = nvram->data.parisc.host_id; 621da177e4SLinus Torvalds if (nvram->data.parisc.factor != -1) 631da177e4SLinus Torvalds np->minsync = nvram->data.parisc.factor; 641da177e4SLinus Torvalds if (nvram->data.parisc.width != -1) 651da177e4SLinus Torvalds np->maxwide = nvram->data.parisc.width; 661da177e4SLinus Torvalds switch (nvram->data.parisc.mode) { 671da177e4SLinus Torvalds case 0: np->scsi_mode = SMODE_SE; break; 681da177e4SLinus Torvalds case 1: np->scsi_mode = SMODE_HVD; break; 691da177e4SLinus Torvalds case 2: np->scsi_mode = SMODE_LVD; break; 701da177e4SLinus Torvalds default: break; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds #endif 731da177e4SLinus Torvalds default: 741da177e4SLinus Torvalds break; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* 791da177e4SLinus Torvalds * Get target set-up from Symbios format NVRAM. 801da177e4SLinus Torvalds */ 811da177e4SLinus Torvalds static void 82b37df489SMatthew Wilcox sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram) 831da177e4SLinus Torvalds { 841da177e4SLinus Torvalds Symbios_target *tn = &nvram->target[target]; 851da177e4SLinus Torvalds 86b37df489SMatthew Wilcox if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)) 87b37df489SMatthew Wilcox tp->usrtags = 0; 881da177e4SLinus Torvalds if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) 891da177e4SLinus Torvalds tp->usrflags &= ~SYM_DISC_ENABLED; 901da177e4SLinus Torvalds if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) 911da177e4SLinus Torvalds tp->usrflags |= SYM_SCAN_BOOT_DISABLED; 921da177e4SLinus Torvalds if (!(tn->flags & SYMBIOS_SCAN_LUNS)) 931da177e4SLinus Torvalds tp->usrflags |= SYM_SCAN_LUNS_DISABLED; 94b37df489SMatthew Wilcox tp->usr_period = (tn->sync_period + 3) / 4; 95b37df489SMatthew Wilcox tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 98b37df489SMatthew Wilcox static const unsigned char Tekram_sync[16] = { 99b37df489SMatthew Wilcox 25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10 100b37df489SMatthew Wilcox }; 101b37df489SMatthew Wilcox 1021da177e4SLinus Torvalds /* 1031da177e4SLinus Torvalds * Get target set-up from Tekram format NVRAM. 1041da177e4SLinus Torvalds */ 1051da177e4SLinus Torvalds static void 106b37df489SMatthew Wilcox sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds struct Tekram_target *tn = &nvram->target[target]; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds if (tn->flags & TEKRAM_TAGGED_COMMANDS) { 1111da177e4SLinus Torvalds tp->usrtags = 2 << nvram->max_tags_index; 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds if (tn->flags & TEKRAM_DISCONNECT_ENABLE) 1151da177e4SLinus Torvalds tp->usrflags |= SYM_DISC_ENABLED; 1161da177e4SLinus Torvalds 117b37df489SMatthew Wilcox if (tn->flags & TEKRAM_SYNC_NEGO) 118b37df489SMatthew Wilcox tp->usr_period = Tekram_sync[tn->sync_index & 0xf]; 119b37df489SMatthew Wilcox tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* 1231da177e4SLinus Torvalds * Get target setup from NVRAM. 1241da177e4SLinus Torvalds */ 125b37df489SMatthew Wilcox void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds switch (nvp->type) { 1281da177e4SLinus Torvalds case SYM_SYMBIOS_NVRAM: 129b37df489SMatthew Wilcox sym_Symbios_setup_target(tp, target, &nvp->data.Symbios); 1301da177e4SLinus Torvalds break; 1311da177e4SLinus Torvalds case SYM_TEKRAM_NVRAM: 132b37df489SMatthew Wilcox sym_Tekram_setup_target(tp, target, &nvp->data.Tekram); 1331da177e4SLinus Torvalds break; 1341da177e4SLinus Torvalds default: 1351da177e4SLinus Torvalds break; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds #ifdef SYM_CONF_DEBUG_NVRAM 1401da177e4SLinus Torvalds /* 1411da177e4SLinus Torvalds * Dump Symbios format NVRAM for debugging purpose. 1421da177e4SLinus Torvalds */ 1431da177e4SLinus Torvalds static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) 1441da177e4SLinus Torvalds { 1451da177e4SLinus Torvalds int i; 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds /* display Symbios nvram host data */ 1481da177e4SLinus Torvalds printf("%s: HOST ID=%d%s%s%s%s%s%s\n", 1491da177e4SLinus Torvalds sym_name(np), nvram->host_id & 0x0f, 1501da177e4SLinus Torvalds (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 1511da177e4SLinus Torvalds (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", 1521da177e4SLinus Torvalds (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", 1531da177e4SLinus Torvalds (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", 1541da177e4SLinus Torvalds (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"", 1551da177e4SLinus Torvalds (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds /* display Symbios nvram drive data */ 1581da177e4SLinus Torvalds for (i = 0 ; i < 15 ; i++) { 1591da177e4SLinus Torvalds struct Symbios_target *tn = &nvram->target[i]; 1601da177e4SLinus Torvalds printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", 1611da177e4SLinus Torvalds sym_name(np), i, 1621da177e4SLinus Torvalds (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", 1631da177e4SLinus Torvalds (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", 1641da177e4SLinus Torvalds (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", 1651da177e4SLinus Torvalds (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", 1661da177e4SLinus Torvalds tn->bus_width, 1671da177e4SLinus Torvalds tn->sync_period / 4, 1681da177e4SLinus Torvalds tn->timeout); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds /* 1731da177e4SLinus Torvalds * Dump TEKRAM format NVRAM for debugging purpose. 1741da177e4SLinus Torvalds */ 1751da177e4SLinus Torvalds static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) 1761da177e4SLinus Torvalds { 1771da177e4SLinus Torvalds int i, tags, boot_delay; 1781da177e4SLinus Torvalds char *rem; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds /* display Tekram nvram host data */ 1811da177e4SLinus Torvalds tags = 2 << nvram->max_tags_index; 1821da177e4SLinus Torvalds boot_delay = 0; 1831da177e4SLinus Torvalds if (nvram->boot_delay_index < 6) 1841da177e4SLinus Torvalds boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; 1851da177e4SLinus Torvalds switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { 1861da177e4SLinus Torvalds default: 1871da177e4SLinus Torvalds case 0: rem = ""; break; 1881da177e4SLinus Torvalds case 1: rem = " REMOVABLE=boot device"; break; 1891da177e4SLinus Torvalds case 2: rem = " REMOVABLE=all"; break; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", 1931da177e4SLinus Torvalds sym_name(np), nvram->host_id & 0x0f, 1941da177e4SLinus Torvalds (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 1951da177e4SLinus Torvalds (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"", 1961da177e4SLinus Torvalds (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", 1971da177e4SLinus Torvalds (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", 1981da177e4SLinus Torvalds (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", 1991da177e4SLinus Torvalds (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", 2001da177e4SLinus Torvalds (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", 2011da177e4SLinus Torvalds (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", 2021da177e4SLinus Torvalds rem, boot_delay, tags); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* display Tekram nvram drive data */ 2051da177e4SLinus Torvalds for (i = 0; i <= 15; i++) { 2061da177e4SLinus Torvalds int sync, j; 2071da177e4SLinus Torvalds struct Tekram_target *tn = &nvram->target[i]; 2081da177e4SLinus Torvalds j = tn->sync_index & 0xf; 2091da177e4SLinus Torvalds sync = Tekram_sync[j]; 2101da177e4SLinus Torvalds printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", 2111da177e4SLinus Torvalds sym_name(np), i, 2121da177e4SLinus Torvalds (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", 2131da177e4SLinus Torvalds (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", 2141da177e4SLinus Torvalds (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", 2151da177e4SLinus Torvalds (tn->flags & TEKRAM_START_CMD) ? " START" : "", 2161da177e4SLinus Torvalds (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", 2171da177e4SLinus Torvalds (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", 2181da177e4SLinus Torvalds sync); 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds #else 2221da177e4SLinus Torvalds static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; } 2231da177e4SLinus Torvalds static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; } 2241da177e4SLinus Torvalds #endif /* SYM_CONF_DEBUG_NVRAM */ 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds /* 2281da177e4SLinus Torvalds * 24C16 EEPROM reading. 2291da177e4SLinus Torvalds * 23008fcc87bSChen Zhou * GPIO0 - data in/data out 2311da177e4SLinus Torvalds * GPIO1 - clock 2321da177e4SLinus Torvalds * Symbios NVRAM wiring now also used by Tekram. 2331da177e4SLinus Torvalds */ 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds #define SET_BIT 0 2361da177e4SLinus Torvalds #define CLR_BIT 1 2371da177e4SLinus Torvalds #define SET_CLK 2 2381da177e4SLinus Torvalds #define CLR_CLK 3 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* 2411da177e4SLinus Torvalds * Set/clear data/clock bit in GPIO0 2421da177e4SLinus Torvalds */ 2431da177e4SLinus Torvalds static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, 2441da177e4SLinus Torvalds int bit_mode) 2451da177e4SLinus Torvalds { 2461da177e4SLinus Torvalds udelay(5); 2471da177e4SLinus Torvalds switch (bit_mode) { 2481da177e4SLinus Torvalds case SET_BIT: 2491da177e4SLinus Torvalds *gpreg |= write_bit; 2501da177e4SLinus Torvalds break; 2511da177e4SLinus Torvalds case CLR_BIT: 2521da177e4SLinus Torvalds *gpreg &= 0xfe; 2531da177e4SLinus Torvalds break; 2541da177e4SLinus Torvalds case SET_CLK: 2551da177e4SLinus Torvalds *gpreg |= 0x02; 2561da177e4SLinus Torvalds break; 2571da177e4SLinus Torvalds case CLR_CLK: 2581da177e4SLinus Torvalds *gpreg &= 0xfd; 2591da177e4SLinus Torvalds break; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds OUTB(np, nc_gpreg, *gpreg); 26353222b90SMatthew Wilcox INB(np, nc_mbox1); 2641da177e4SLinus Torvalds udelay(5); 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * Send START condition to NVRAM to wake it up. 2691da177e4SLinus Torvalds */ 2701da177e4SLinus Torvalds static void S24C16_start(struct sym_device *np, u_char *gpreg) 2711da177e4SLinus Torvalds { 2721da177e4SLinus Torvalds S24C16_set_bit(np, 1, gpreg, SET_BIT); 2731da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, SET_CLK); 2741da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, CLR_BIT); 2751da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, CLR_CLK); 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /* 2791da177e4SLinus Torvalds * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! 2801da177e4SLinus Torvalds */ 2811da177e4SLinus Torvalds static void S24C16_stop(struct sym_device *np, u_char *gpreg) 2821da177e4SLinus Torvalds { 2831da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, SET_CLK); 2841da177e4SLinus Torvalds S24C16_set_bit(np, 1, gpreg, SET_BIT); 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * Read or write a bit to the NVRAM, 2891da177e4SLinus Torvalds * read if GPIO0 input else write if GPIO0 output 2901da177e4SLinus Torvalds */ 2911da177e4SLinus Torvalds static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit, 2921da177e4SLinus Torvalds u_char *gpreg) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds S24C16_set_bit(np, write_bit, gpreg, SET_BIT); 2951da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, SET_CLK); 2961da177e4SLinus Torvalds if (read_bit) 2971da177e4SLinus Torvalds *read_bit = INB(np, nc_gpreg); 2981da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, CLR_CLK); 2991da177e4SLinus Torvalds S24C16_set_bit(np, 0, gpreg, CLR_BIT); 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds /* 3031da177e4SLinus Torvalds * Output an ACK to the NVRAM after reading, 3041da177e4SLinus Torvalds * change GPIO0 to output and when done back to an input 3051da177e4SLinus Torvalds */ 3061da177e4SLinus Torvalds static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, 3071da177e4SLinus Torvalds u_char *gpcntl) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds OUTB(np, nc_gpcntl, *gpcntl & 0xfe); 3101da177e4SLinus Torvalds S24C16_do_bit(np, NULL, write_bit, gpreg); 3111da177e4SLinus Torvalds OUTB(np, nc_gpcntl, *gpcntl); 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds /* 3151da177e4SLinus Torvalds * Input an ACK from NVRAM after writing, 3161da177e4SLinus Torvalds * change GPIO0 to input and when done back to an output 3171da177e4SLinus Torvalds */ 3181da177e4SLinus Torvalds static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, 3191da177e4SLinus Torvalds u_char *gpcntl) 3201da177e4SLinus Torvalds { 3211da177e4SLinus Torvalds OUTB(np, nc_gpcntl, *gpcntl | 0x01); 3221da177e4SLinus Torvalds S24C16_do_bit(np, read_bit, 1, gpreg); 3231da177e4SLinus Torvalds OUTB(np, nc_gpcntl, *gpcntl); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds /* 3271da177e4SLinus Torvalds * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, 3281da177e4SLinus Torvalds * GPIO0 must already be set as an output 3291da177e4SLinus Torvalds */ 3301da177e4SLinus Torvalds static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data, 3311da177e4SLinus Torvalds u_char *gpreg, u_char *gpcntl) 3321da177e4SLinus Torvalds { 3331da177e4SLinus Torvalds int x; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds for (x = 0; x < 8; x++) 3361da177e4SLinus Torvalds S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg); 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds S24C16_read_ack(np, ack_data, gpreg, gpcntl); 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds /* 3421da177e4SLinus Torvalds * READ a byte from the NVRAM and then send an ACK to say we have got it, 3431da177e4SLinus Torvalds * GPIO0 must already be set as an input 3441da177e4SLinus Torvalds */ 3451da177e4SLinus Torvalds static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data, 3461da177e4SLinus Torvalds u_char *gpreg, u_char *gpcntl) 3471da177e4SLinus Torvalds { 3481da177e4SLinus Torvalds int x; 3491da177e4SLinus Torvalds u_char read_bit; 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds *read_data = 0; 3521da177e4SLinus Torvalds for (x = 0; x < 8; x++) { 3531da177e4SLinus Torvalds S24C16_do_bit(np, &read_bit, 1, gpreg); 3541da177e4SLinus Torvalds *read_data |= ((read_bit & 0x01) << (7 - x)); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds S24C16_write_ack(np, ack_data, gpreg, gpcntl); 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 36044456d37SOlaf Hering #ifdef SYM_CONF_NVRAM_WRITE_SUPPORT 3611da177e4SLinus Torvalds /* 3621da177e4SLinus Torvalds * Write 'len' bytes starting at 'offset'. 3631da177e4SLinus Torvalds */ 3641da177e4SLinus Torvalds static int sym_write_S24C16_nvram(struct sym_device *np, int offset, 3651da177e4SLinus Torvalds u_char *data, int len) 3661da177e4SLinus Torvalds { 3671da177e4SLinus Torvalds u_char gpcntl, gpreg; 3681da177e4SLinus Torvalds u_char old_gpcntl, old_gpreg; 3691da177e4SLinus Torvalds u_char ack_data; 3701da177e4SLinus Torvalds int x; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds /* save current state of GPCNTL and GPREG */ 3731da177e4SLinus Torvalds old_gpreg = INB(np, nc_gpreg); 3741da177e4SLinus Torvalds old_gpcntl = INB(np, nc_gpcntl); 3751da177e4SLinus Torvalds gpcntl = old_gpcntl & 0x1c; 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 3781da177e4SLinus Torvalds OUTB(np, nc_gpreg, old_gpreg); 3791da177e4SLinus Torvalds OUTB(np, nc_gpcntl, gpcntl); 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds /* this is to set NVRAM into a known state with GPIO0/1 both low */ 3821da177e4SLinus Torvalds gpreg = old_gpreg; 3831da177e4SLinus Torvalds S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 3841da177e4SLinus Torvalds S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds /* now set NVRAM inactive with GPIO0/1 both high */ 3871da177e4SLinus Torvalds S24C16_stop(np, &gpreg); 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* NVRAM has to be written in segments of 16 bytes */ 3901da177e4SLinus Torvalds for (x = 0; x < len ; x += 16) { 3911da177e4SLinus Torvalds do { 3921da177e4SLinus Torvalds S24C16_start(np, &gpreg); 3931da177e4SLinus Torvalds S24C16_write_byte(np, &ack_data, 3941da177e4SLinus Torvalds 0xa0 | (((offset+x) >> 7) & 0x0e), 3951da177e4SLinus Torvalds &gpreg, &gpcntl); 3961da177e4SLinus Torvalds } while (ack_data & 0x01); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, 3991da177e4SLinus Torvalds &gpreg, &gpcntl); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds for (y = 0; y < 16; y++) 4021da177e4SLinus Torvalds S24C16_write_byte(np, &ack_data, data[x+y], 4031da177e4SLinus Torvalds &gpreg, &gpcntl); 4041da177e4SLinus Torvalds S24C16_stop(np, &gpreg); 4051da177e4SLinus Torvalds } 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds /* return GPIO0/1 to original states after having accessed NVRAM */ 4081da177e4SLinus Torvalds OUTB(np, nc_gpcntl, old_gpcntl); 4091da177e4SLinus Torvalds OUTB(np, nc_gpreg, old_gpreg); 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds return 0; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds #endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */ 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* 4161da177e4SLinus Torvalds * Read 'len' bytes starting at 'offset'. 4171da177e4SLinus Torvalds */ 4181da177e4SLinus Torvalds static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds u_char gpcntl, gpreg; 4211da177e4SLinus Torvalds u_char old_gpcntl, old_gpreg; 4221da177e4SLinus Torvalds u_char ack_data; 4231da177e4SLinus Torvalds int retv = 1; 4241da177e4SLinus Torvalds int x; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /* save current state of GPCNTL and GPREG */ 4271da177e4SLinus Torvalds old_gpreg = INB(np, nc_gpreg); 4281da177e4SLinus Torvalds old_gpcntl = INB(np, nc_gpcntl); 4291da177e4SLinus Torvalds gpcntl = old_gpcntl & 0x1c; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 4321da177e4SLinus Torvalds OUTB(np, nc_gpreg, old_gpreg); 4331da177e4SLinus Torvalds OUTB(np, nc_gpcntl, gpcntl); 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds /* this is to set NVRAM into a known state with GPIO0/1 both low */ 4361da177e4SLinus Torvalds gpreg = old_gpreg; 4371da177e4SLinus Torvalds S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 4381da177e4SLinus Torvalds S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* now set NVRAM inactive with GPIO0/1 both high */ 4411da177e4SLinus Torvalds S24C16_stop(np, &gpreg); 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds /* activate NVRAM */ 4441da177e4SLinus Torvalds S24C16_start(np, &gpreg); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds /* write device code and random address MSB */ 4471da177e4SLinus Torvalds S24C16_write_byte(np, &ack_data, 4481da177e4SLinus Torvalds 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 4491da177e4SLinus Torvalds if (ack_data & 0x01) 4501da177e4SLinus Torvalds goto out; 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds /* write random address LSB */ 4531da177e4SLinus Torvalds S24C16_write_byte(np, &ack_data, 4541da177e4SLinus Torvalds offset & 0xff, &gpreg, &gpcntl); 4551da177e4SLinus Torvalds if (ack_data & 0x01) 4561da177e4SLinus Torvalds goto out; 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds /* regenerate START state to set up for reading */ 4591da177e4SLinus Torvalds S24C16_start(np, &gpreg); 4601da177e4SLinus Torvalds 4611da177e4SLinus Torvalds /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ 4621da177e4SLinus Torvalds S24C16_write_byte(np, &ack_data, 4631da177e4SLinus Torvalds 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 4641da177e4SLinus Torvalds if (ack_data & 0x01) 4651da177e4SLinus Torvalds goto out; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds /* now set up GPIO0 for inputting data */ 4681da177e4SLinus Torvalds gpcntl |= 0x01; 4691da177e4SLinus Torvalds OUTB(np, nc_gpcntl, gpcntl); 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds /* input all requested data - only part of total NVRAM */ 4721da177e4SLinus Torvalds for (x = 0; x < len; x++) 4731da177e4SLinus Torvalds S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds /* finally put NVRAM back in inactive mode */ 4761da177e4SLinus Torvalds gpcntl &= 0xfe; 4771da177e4SLinus Torvalds OUTB(np, nc_gpcntl, gpcntl); 4781da177e4SLinus Torvalds S24C16_stop(np, &gpreg); 4791da177e4SLinus Torvalds retv = 0; 4801da177e4SLinus Torvalds out: 4811da177e4SLinus Torvalds /* return GPIO0/1 to original states after having accessed NVRAM */ 4821da177e4SLinus Torvalds OUTB(np, nc_gpcntl, old_gpcntl); 4831da177e4SLinus Torvalds OUTB(np, nc_gpreg, old_gpreg); 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds return retv; 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds #undef SET_BIT 4891da177e4SLinus Torvalds #undef CLR_BIT 4901da177e4SLinus Torvalds #undef SET_CLK 4911da177e4SLinus Torvalds #undef CLR_CLK 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds /* 4941da177e4SLinus Torvalds * Try reading Symbios NVRAM. 4951da177e4SLinus Torvalds * Return 0 if OK. 4961da177e4SLinus Torvalds */ 4971da177e4SLinus Torvalds static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) 4981da177e4SLinus Torvalds { 4991da177e4SLinus Torvalds static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; 5001da177e4SLinus Torvalds u_char *data = (u_char *) nvram; 5011da177e4SLinus Torvalds int len = sizeof(*nvram); 5021da177e4SLinus Torvalds u_short csum; 5031da177e4SLinus Torvalds int x; 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds /* probe the 24c16 and read the SYMBIOS 24c16 area */ 5061da177e4SLinus Torvalds if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) 5071da177e4SLinus Torvalds return 1; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* check valid NVRAM signature, verify byte count and checksum */ 5101da177e4SLinus Torvalds if (nvram->type != 0 || 5111da177e4SLinus Torvalds memcmp(nvram->trailer, Symbios_trailer, 6) || 5121da177e4SLinus Torvalds nvram->byte_count != len - 12) 5131da177e4SLinus Torvalds return 1; 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds /* verify checksum */ 5161da177e4SLinus Torvalds for (x = 6, csum = 0; x < len - 6; x++) 5171da177e4SLinus Torvalds csum += data[x]; 5181da177e4SLinus Torvalds if (csum != nvram->checksum) 5191da177e4SLinus Torvalds return 1; 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds return 0; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds /* 5251da177e4SLinus Torvalds * 93C46 EEPROM reading. 5261da177e4SLinus Torvalds * 52708fcc87bSChen Zhou * GPIO0 - data in 5281da177e4SLinus Torvalds * GPIO1 - data out 5291da177e4SLinus Torvalds * GPIO2 - clock 5301da177e4SLinus Torvalds * GPIO4 - chip select 5311da177e4SLinus Torvalds * 5321da177e4SLinus Torvalds * Used by Tekram. 5331da177e4SLinus Torvalds */ 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds /* 5361da177e4SLinus Torvalds * Pulse clock bit in GPIO0 5371da177e4SLinus Torvalds */ 5381da177e4SLinus Torvalds static void T93C46_Clk(struct sym_device *np, u_char *gpreg) 5391da177e4SLinus Torvalds { 5401da177e4SLinus Torvalds OUTB(np, nc_gpreg, *gpreg | 0x04); 54153222b90SMatthew Wilcox INB(np, nc_mbox1); 5421da177e4SLinus Torvalds udelay(2); 5431da177e4SLinus Torvalds OUTB(np, nc_gpreg, *gpreg); 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds /* 5471da177e4SLinus Torvalds * Read bit from NVRAM 5481da177e4SLinus Torvalds */ 5491da177e4SLinus Torvalds static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg) 5501da177e4SLinus Torvalds { 5511da177e4SLinus Torvalds udelay(2); 5521da177e4SLinus Torvalds T93C46_Clk(np, gpreg); 5531da177e4SLinus Torvalds *read_bit = INB(np, nc_gpreg); 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds /* 5571da177e4SLinus Torvalds * Write bit to GPIO0 5581da177e4SLinus Torvalds */ 5591da177e4SLinus Torvalds static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg) 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds if (write_bit & 0x01) 5621da177e4SLinus Torvalds *gpreg |= 0x02; 5631da177e4SLinus Torvalds else 5641da177e4SLinus Torvalds *gpreg &= 0xfd; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds *gpreg |= 0x10; 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds OUTB(np, nc_gpreg, *gpreg); 56953222b90SMatthew Wilcox INB(np, nc_mbox1); 5701da177e4SLinus Torvalds udelay(2); 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds T93C46_Clk(np, gpreg); 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds /* 5761da177e4SLinus Torvalds * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! 5771da177e4SLinus Torvalds */ 5781da177e4SLinus Torvalds static void T93C46_Stop(struct sym_device *np, u_char *gpreg) 5791da177e4SLinus Torvalds { 5801da177e4SLinus Torvalds *gpreg &= 0xef; 5811da177e4SLinus Torvalds OUTB(np, nc_gpreg, *gpreg); 58253222b90SMatthew Wilcox INB(np, nc_mbox1); 5831da177e4SLinus Torvalds udelay(2); 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds T93C46_Clk(np, gpreg); 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds /* 5891da177e4SLinus Torvalds * Send read command and address to NVRAM 5901da177e4SLinus Torvalds */ 5911da177e4SLinus Torvalds static void T93C46_Send_Command(struct sym_device *np, u_short write_data, 5921da177e4SLinus Torvalds u_char *read_bit, u_char *gpreg) 5931da177e4SLinus Torvalds { 5941da177e4SLinus Torvalds int x; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds /* send 9 bits, start bit (1), command (2), address (6) */ 5971da177e4SLinus Torvalds for (x = 0; x < 9; x++) 5981da177e4SLinus Torvalds T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds *read_bit = INB(np, nc_gpreg); 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds /* 6041da177e4SLinus Torvalds * READ 2 bytes from the NVRAM 6051da177e4SLinus Torvalds */ 6061da177e4SLinus Torvalds static void T93C46_Read_Word(struct sym_device *np, 6071da177e4SLinus Torvalds unsigned short *nvram_data, unsigned char *gpreg) 6081da177e4SLinus Torvalds { 6091da177e4SLinus Torvalds int x; 6101da177e4SLinus Torvalds u_char read_bit; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds *nvram_data = 0; 6131da177e4SLinus Torvalds for (x = 0; x < 16; x++) { 6141da177e4SLinus Torvalds T93C46_Read_Bit(np, &read_bit, gpreg); 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds if (read_bit & 0x01) 6171da177e4SLinus Torvalds *nvram_data |= (0x01 << (15 - x)); 6181da177e4SLinus Torvalds else 6191da177e4SLinus Torvalds *nvram_data &= ~(0x01 << (15 - x)); 6201da177e4SLinus Torvalds } 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds /* 6241da177e4SLinus Torvalds * Read Tekram NvRAM data. 6251da177e4SLinus Torvalds */ 6261da177e4SLinus Torvalds static int T93C46_Read_Data(struct sym_device *np, unsigned short *data, 6271da177e4SLinus Torvalds int len, unsigned char *gpreg) 6281da177e4SLinus Torvalds { 6291da177e4SLinus Torvalds int x; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds for (x = 0; x < len; x++) { 6321da177e4SLinus Torvalds unsigned char read_bit; 6331da177e4SLinus Torvalds /* output read command and address */ 6341da177e4SLinus Torvalds T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); 6351da177e4SLinus Torvalds if (read_bit & 0x01) 6361da177e4SLinus Torvalds return 1; /* Bad */ 6371da177e4SLinus Torvalds T93C46_Read_Word(np, &data[x], gpreg); 6381da177e4SLinus Torvalds T93C46_Stop(np, gpreg); 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds return 0; 6421da177e4SLinus Torvalds } 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds /* 6451da177e4SLinus Torvalds * Try reading 93C46 Tekram NVRAM. 6461da177e4SLinus Torvalds */ 6471da177e4SLinus Torvalds static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram) 6481da177e4SLinus Torvalds { 6491da177e4SLinus Torvalds u_char gpcntl, gpreg; 6501da177e4SLinus Torvalds u_char old_gpcntl, old_gpreg; 6511d4f4a5eSColin Ian King int retv; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds /* save current state of GPCNTL and GPREG */ 6541da177e4SLinus Torvalds old_gpreg = INB(np, nc_gpreg); 6551da177e4SLinus Torvalds old_gpcntl = INB(np, nc_gpcntl); 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, 6581da177e4SLinus Torvalds 1/2/4 out */ 6591da177e4SLinus Torvalds gpreg = old_gpreg & 0xe9; 6601da177e4SLinus Torvalds OUTB(np, nc_gpreg, gpreg); 6611da177e4SLinus Torvalds gpcntl = (old_gpcntl & 0xe9) | 0x09; 6621da177e4SLinus Torvalds OUTB(np, nc_gpcntl, gpcntl); 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds /* input all of NVRAM, 64 words */ 6651da177e4SLinus Torvalds retv = T93C46_Read_Data(np, (u_short *) nvram, 6661da177e4SLinus Torvalds sizeof(*nvram) / sizeof(short), &gpreg); 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ 6691da177e4SLinus Torvalds OUTB(np, nc_gpcntl, old_gpcntl); 6701da177e4SLinus Torvalds OUTB(np, nc_gpreg, old_gpreg); 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds return retv; 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds /* 6761da177e4SLinus Torvalds * Try reading Tekram NVRAM. 6771da177e4SLinus Torvalds * Return 0 if OK. 6781da177e4SLinus Torvalds */ 6791da177e4SLinus Torvalds static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram) 6801da177e4SLinus Torvalds { 6811da177e4SLinus Torvalds u_char *data = (u_char *) nvram; 6821da177e4SLinus Torvalds int len = sizeof(*nvram); 6831da177e4SLinus Torvalds u_short csum; 6841da177e4SLinus Torvalds int x; 6851da177e4SLinus Torvalds 686e58bc06eSMatthew Wilcox switch (np->pdev->device) { 6871da177e4SLinus Torvalds case PCI_DEVICE_ID_NCR_53C885: 6881da177e4SLinus Torvalds case PCI_DEVICE_ID_NCR_53C895: 6891da177e4SLinus Torvalds case PCI_DEVICE_ID_NCR_53C896: 6901da177e4SLinus Torvalds x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 6911da177e4SLinus Torvalds data, len); 6921da177e4SLinus Torvalds break; 6931da177e4SLinus Torvalds case PCI_DEVICE_ID_NCR_53C875: 6941da177e4SLinus Torvalds x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 6951da177e4SLinus Torvalds data, len); 6961da177e4SLinus Torvalds if (!x) 6971da177e4SLinus Torvalds break; 6980779ad71SGustavo A. R. Silva /* fall through */ 6991da177e4SLinus Torvalds default: 7001da177e4SLinus Torvalds x = sym_read_T93C46_nvram(np, nvram); 7011da177e4SLinus Torvalds break; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds if (x) 7041da177e4SLinus Torvalds return 1; 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds /* verify checksum */ 7071da177e4SLinus Torvalds for (x = 0, csum = 0; x < len - 1; x += 2) 7081da177e4SLinus Torvalds csum += data[x] + (data[x+1] << 8); 7091da177e4SLinus Torvalds if (csum != 0x1234) 7101da177e4SLinus Torvalds return 1; 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds return 0; 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds #ifdef CONFIG_PARISC 7161da177e4SLinus Torvalds /* 7171da177e4SLinus Torvalds * Host firmware (PDC) keeps a table for altering SCSI capabilities. 7181da177e4SLinus Torvalds * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD. 7191da177e4SLinus Torvalds * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID. 7201da177e4SLinus Torvalds */ 7211da177e4SLinus Torvalds static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc) 7221da177e4SLinus Torvalds { 7231da177e4SLinus Torvalds struct hardware_path hwpath; 7241da177e4SLinus Torvalds get_pci_node_path(np->pdev, &hwpath); 7251da177e4SLinus Torvalds if (!pdc_get_initiator(&hwpath, pdc)) 7261da177e4SLinus Torvalds return 0; 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds return SYM_PARISC_PDC; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds #else 73153222b90SMatthew Wilcox static inline int sym_read_parisc_pdc(struct sym_device *np, 73253222b90SMatthew Wilcox struct pdc_initiator *x) 7331da177e4SLinus Torvalds { 7341da177e4SLinus Torvalds return 0; 7351da177e4SLinus Torvalds } 7361da177e4SLinus Torvalds #endif 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds /* 7391da177e4SLinus Torvalds * Try reading Symbios or Tekram NVRAM 7401da177e4SLinus Torvalds */ 7411da177e4SLinus Torvalds int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) 7421da177e4SLinus Torvalds { 7431da177e4SLinus Torvalds if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) { 7441da177e4SLinus Torvalds nvp->type = SYM_SYMBIOS_NVRAM; 7451da177e4SLinus Torvalds sym_display_Symbios_nvram(np, &nvp->data.Symbios); 7461da177e4SLinus Torvalds } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) { 7471da177e4SLinus Torvalds nvp->type = SYM_TEKRAM_NVRAM; 7481da177e4SLinus Torvalds sym_display_Tekram_nvram(np, &nvp->data.Tekram); 7491da177e4SLinus Torvalds } else { 7501da177e4SLinus Torvalds nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc); 7511da177e4SLinus Torvalds } 7521da177e4SLinus Torvalds return nvp->type; 7531da177e4SLinus Torvalds } 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds char *sym_nvram_type(struct sym_nvram *nvp) 7561da177e4SLinus Torvalds { 7571da177e4SLinus Torvalds switch (nvp->type) { 7581da177e4SLinus Torvalds case SYM_SYMBIOS_NVRAM: 7591da177e4SLinus Torvalds return "Symbios NVRAM"; 7601da177e4SLinus Torvalds case SYM_TEKRAM_NVRAM: 7611da177e4SLinus Torvalds return "Tekram NVRAM"; 7621da177e4SLinus Torvalds case SYM_PARISC_PDC: 7631da177e4SLinus Torvalds return "PA-RISC Firmware"; 7641da177e4SLinus Torvalds default: 7651da177e4SLinus Torvalds return "No NVRAM"; 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds } 768