162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 462306a36Sopenharmony_ci * of PCI-SCSI IO processors. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This driver is derived from the Linux sym53c8xx driver. 962306a36Sopenharmony_ci * Copyright (C) 1998-2000 Gerard Roudier 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 1262306a36Sopenharmony_ci * a port of the FreeBSD ncr driver to Linux-1.2.13. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The original ncr driver has been written for 386bsd and FreeBSD by 1562306a36Sopenharmony_ci * Wolfgang Stanglmeier <wolf@cologne.de> 1662306a36Sopenharmony_ci * Stefan Esser <se@mi.Uni-Koeln.de> 1762306a36Sopenharmony_ci * Copyright (C) 1994 Wolfgang Stanglmeier 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Other major contributions: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * NVRAM detection and reading. 2262306a36Sopenharmony_ci * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci *----------------------------------------------------------------------------- 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "sym_glue.h" 2862306a36Sopenharmony_ci#include "sym_nvram.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#ifdef SYM_CONF_DEBUG_NVRAM 3162306a36Sopenharmony_cistatic u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Get host setup from NVRAM. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_civoid sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci /* 4062306a36Sopenharmony_ci * Get parity checking, host ID, verbose mode 4162306a36Sopenharmony_ci * and miscellaneous host flags from NVRAM. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci switch (nvram->type) { 4462306a36Sopenharmony_ci case SYM_SYMBIOS_NVRAM: 4562306a36Sopenharmony_ci if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) 4662306a36Sopenharmony_ci np->rv_scntl0 &= ~0x0a; 4762306a36Sopenharmony_ci np->myaddr = nvram->data.Symbios.host_id & 0x0f; 4862306a36Sopenharmony_ci if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) 4962306a36Sopenharmony_ci np->verbose += 1; 5062306a36Sopenharmony_ci if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) 5162306a36Sopenharmony_ci shost->reverse_ordering = 1; 5262306a36Sopenharmony_ci if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) 5362306a36Sopenharmony_ci np->usrflags |= SYM_AVOID_BUS_RESET; 5462306a36Sopenharmony_ci break; 5562306a36Sopenharmony_ci case SYM_TEKRAM_NVRAM: 5662306a36Sopenharmony_ci np->myaddr = nvram->data.Tekram.host_id & 0x0f; 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci#ifdef CONFIG_PARISC 5962306a36Sopenharmony_ci case SYM_PARISC_PDC: 6062306a36Sopenharmony_ci if (nvram->data.parisc.host_id != -1) 6162306a36Sopenharmony_ci np->myaddr = nvram->data.parisc.host_id; 6262306a36Sopenharmony_ci if (nvram->data.parisc.factor != -1) 6362306a36Sopenharmony_ci np->minsync = nvram->data.parisc.factor; 6462306a36Sopenharmony_ci if (nvram->data.parisc.width != -1) 6562306a36Sopenharmony_ci np->maxwide = nvram->data.parisc.width; 6662306a36Sopenharmony_ci switch (nvram->data.parisc.mode) { 6762306a36Sopenharmony_ci case 0: np->scsi_mode = SMODE_SE; break; 6862306a36Sopenharmony_ci case 1: np->scsi_mode = SMODE_HVD; break; 6962306a36Sopenharmony_ci case 2: np->scsi_mode = SMODE_LVD; break; 7062306a36Sopenharmony_ci default: break; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci#endif 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * Get target set-up from Symbios format NVRAM. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistatic void 8262306a36Sopenharmony_cisym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci Symbios_target *tn = &nvram->target[target]; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)) 8762306a36Sopenharmony_ci tp->usrtags = 0; 8862306a36Sopenharmony_ci if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) 8962306a36Sopenharmony_ci tp->usrflags &= ~SYM_DISC_ENABLED; 9062306a36Sopenharmony_ci if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) 9162306a36Sopenharmony_ci tp->usrflags |= SYM_SCAN_BOOT_DISABLED; 9262306a36Sopenharmony_ci if (!(tn->flags & SYMBIOS_SCAN_LUNS)) 9362306a36Sopenharmony_ci tp->usrflags |= SYM_SCAN_LUNS_DISABLED; 9462306a36Sopenharmony_ci tp->usr_period = (tn->sync_period + 3) / 4; 9562306a36Sopenharmony_ci tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const unsigned char Tekram_sync[16] = { 9962306a36Sopenharmony_ci 25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * Get target set-up from Tekram format NVRAM. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic void 10662306a36Sopenharmony_cisym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct Tekram_target *tn = &nvram->target[target]; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (tn->flags & TEKRAM_TAGGED_COMMANDS) { 11162306a36Sopenharmony_ci tp->usrtags = 2 << nvram->max_tags_index; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (tn->flags & TEKRAM_DISCONNECT_ENABLE) 11562306a36Sopenharmony_ci tp->usrflags |= SYM_DISC_ENABLED; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (tn->flags & TEKRAM_SYNC_NEGO) 11862306a36Sopenharmony_ci tp->usr_period = Tekram_sync[tn->sync_index & 0xf]; 11962306a36Sopenharmony_ci tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Get target setup from NVRAM. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_civoid sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci switch (nvp->type) { 12862306a36Sopenharmony_ci case SYM_SYMBIOS_NVRAM: 12962306a36Sopenharmony_ci sym_Symbios_setup_target(tp, target, &nvp->data.Symbios); 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci case SYM_TEKRAM_NVRAM: 13262306a36Sopenharmony_ci sym_Tekram_setup_target(tp, target, &nvp->data.Tekram); 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci default: 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#ifdef SYM_CONF_DEBUG_NVRAM 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * Dump Symbios format NVRAM for debugging purpose. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistatic void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci int i; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* display Symbios nvram host data */ 14862306a36Sopenharmony_ci printf("%s: HOST ID=%d%s%s%s%s%s%s\n", 14962306a36Sopenharmony_ci sym_name(np), nvram->host_id & 0x0f, 15062306a36Sopenharmony_ci (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 15162306a36Sopenharmony_ci (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", 15262306a36Sopenharmony_ci (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", 15362306a36Sopenharmony_ci (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", 15462306a36Sopenharmony_ci (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"", 15562306a36Sopenharmony_ci (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* display Symbios nvram drive data */ 15862306a36Sopenharmony_ci for (i = 0 ; i < 15 ; i++) { 15962306a36Sopenharmony_ci struct Symbios_target *tn = &nvram->target[i]; 16062306a36Sopenharmony_ci printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", 16162306a36Sopenharmony_ci sym_name(np), i, 16262306a36Sopenharmony_ci (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", 16362306a36Sopenharmony_ci (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", 16462306a36Sopenharmony_ci (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", 16562306a36Sopenharmony_ci (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", 16662306a36Sopenharmony_ci tn->bus_width, 16762306a36Sopenharmony_ci tn->sync_period / 4, 16862306a36Sopenharmony_ci tn->timeout); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * Dump TEKRAM format NVRAM for debugging purpose. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistatic void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci int i, tags, boot_delay; 17862306a36Sopenharmony_ci char *rem; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* display Tekram nvram host data */ 18162306a36Sopenharmony_ci tags = 2 << nvram->max_tags_index; 18262306a36Sopenharmony_ci boot_delay = 0; 18362306a36Sopenharmony_ci if (nvram->boot_delay_index < 6) 18462306a36Sopenharmony_ci boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; 18562306a36Sopenharmony_ci switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { 18662306a36Sopenharmony_ci default: 18762306a36Sopenharmony_ci case 0: rem = ""; break; 18862306a36Sopenharmony_ci case 1: rem = " REMOVABLE=boot device"; break; 18962306a36Sopenharmony_ci case 2: rem = " REMOVABLE=all"; break; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", 19362306a36Sopenharmony_ci sym_name(np), nvram->host_id & 0x0f, 19462306a36Sopenharmony_ci (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 19562306a36Sopenharmony_ci (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"", 19662306a36Sopenharmony_ci (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", 19762306a36Sopenharmony_ci (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", 19862306a36Sopenharmony_ci (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", 19962306a36Sopenharmony_ci (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", 20062306a36Sopenharmony_ci (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", 20162306a36Sopenharmony_ci (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", 20262306a36Sopenharmony_ci rem, boot_delay, tags); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* display Tekram nvram drive data */ 20562306a36Sopenharmony_ci for (i = 0; i <= 15; i++) { 20662306a36Sopenharmony_ci int sync, j; 20762306a36Sopenharmony_ci struct Tekram_target *tn = &nvram->target[i]; 20862306a36Sopenharmony_ci j = tn->sync_index & 0xf; 20962306a36Sopenharmony_ci sync = Tekram_sync[j]; 21062306a36Sopenharmony_ci printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", 21162306a36Sopenharmony_ci sym_name(np), i, 21262306a36Sopenharmony_ci (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", 21362306a36Sopenharmony_ci (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", 21462306a36Sopenharmony_ci (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", 21562306a36Sopenharmony_ci (tn->flags & TEKRAM_START_CMD) ? " START" : "", 21662306a36Sopenharmony_ci (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", 21762306a36Sopenharmony_ci (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", 21862306a36Sopenharmony_ci sync); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci#else 22262306a36Sopenharmony_cistatic void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; } 22362306a36Sopenharmony_cistatic void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; } 22462306a36Sopenharmony_ci#endif /* SYM_CONF_DEBUG_NVRAM */ 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* 22862306a36Sopenharmony_ci * 24C16 EEPROM reading. 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * GPIO0 - data in/data out 23162306a36Sopenharmony_ci * GPIO1 - clock 23262306a36Sopenharmony_ci * Symbios NVRAM wiring now also used by Tekram. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define SET_BIT 0 23662306a36Sopenharmony_ci#define CLR_BIT 1 23762306a36Sopenharmony_ci#define SET_CLK 2 23862306a36Sopenharmony_ci#define CLR_CLK 3 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * Set/clear data/clock bit in GPIO0 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, 24462306a36Sopenharmony_ci int bit_mode) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci udelay(5); 24762306a36Sopenharmony_ci switch (bit_mode) { 24862306a36Sopenharmony_ci case SET_BIT: 24962306a36Sopenharmony_ci *gpreg |= write_bit; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case CLR_BIT: 25262306a36Sopenharmony_ci *gpreg &= 0xfe; 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case SET_CLK: 25562306a36Sopenharmony_ci *gpreg |= 0x02; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case CLR_CLK: 25862306a36Sopenharmony_ci *gpreg &= 0xfd; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 26362306a36Sopenharmony_ci INB(np, nc_mbox1); 26462306a36Sopenharmony_ci udelay(5); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* 26862306a36Sopenharmony_ci * Send START condition to NVRAM to wake it up. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cistatic void S24C16_start(struct sym_device *np, u_char *gpreg) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci S24C16_set_bit(np, 1, gpreg, SET_BIT); 27362306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, SET_CLK); 27462306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_BIT); 27562306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_CLK); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic void S24C16_stop(struct sym_device *np, u_char *gpreg) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, SET_CLK); 28462306a36Sopenharmony_ci S24C16_set_bit(np, 1, gpreg, SET_BIT); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* 28862306a36Sopenharmony_ci * Read or write a bit to the NVRAM, 28962306a36Sopenharmony_ci * read if GPIO0 input else write if GPIO0 output 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_cistatic void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit, 29262306a36Sopenharmony_ci u_char *gpreg) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci S24C16_set_bit(np, write_bit, gpreg, SET_BIT); 29562306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, SET_CLK); 29662306a36Sopenharmony_ci if (read_bit) 29762306a36Sopenharmony_ci *read_bit = INB(np, nc_gpreg); 29862306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_CLK); 29962306a36Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_BIT); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * Output an ACK to the NVRAM after reading, 30462306a36Sopenharmony_ci * change GPIO0 to output and when done back to an input 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_cistatic void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, 30762306a36Sopenharmony_ci u_char *gpcntl) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl & 0xfe); 31062306a36Sopenharmony_ci S24C16_do_bit(np, NULL, write_bit, gpreg); 31162306a36Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* 31562306a36Sopenharmony_ci * Input an ACK from NVRAM after writing, 31662306a36Sopenharmony_ci * change GPIO0 to input and when done back to an output 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, 31962306a36Sopenharmony_ci u_char *gpcntl) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl | 0x01); 32262306a36Sopenharmony_ci S24C16_do_bit(np, read_bit, 1, gpreg); 32362306a36Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/* 32762306a36Sopenharmony_ci * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, 32862306a36Sopenharmony_ci * GPIO0 must already be set as an output 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistatic void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data, 33162306a36Sopenharmony_ci u_char *gpreg, u_char *gpcntl) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int x; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci for (x = 0; x < 8; x++) 33662306a36Sopenharmony_ci S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci S24C16_read_ack(np, ack_data, gpreg, gpcntl); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * READ a byte from the NVRAM and then send an ACK to say we have got it, 34362306a36Sopenharmony_ci * GPIO0 must already be set as an input 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_cistatic void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data, 34662306a36Sopenharmony_ci u_char *gpreg, u_char *gpcntl) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci int x; 34962306a36Sopenharmony_ci u_char read_bit; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci *read_data = 0; 35262306a36Sopenharmony_ci for (x = 0; x < 8; x++) { 35362306a36Sopenharmony_ci S24C16_do_bit(np, &read_bit, 1, gpreg); 35462306a36Sopenharmony_ci *read_data |= ((read_bit & 0x01) << (7 - x)); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci S24C16_write_ack(np, ack_data, gpreg, gpcntl); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT 36162306a36Sopenharmony_ci/* 36262306a36Sopenharmony_ci * Write 'len' bytes starting at 'offset'. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_cistatic int sym_write_S24C16_nvram(struct sym_device *np, int offset, 36562306a36Sopenharmony_ci u_char *data, int len) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci u_char gpcntl, gpreg; 36862306a36Sopenharmony_ci u_char old_gpcntl, old_gpreg; 36962306a36Sopenharmony_ci u_char ack_data; 37062306a36Sopenharmony_ci int x; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* save current state of GPCNTL and GPREG */ 37362306a36Sopenharmony_ci old_gpreg = INB(np, nc_gpreg); 37462306a36Sopenharmony_ci old_gpcntl = INB(np, nc_gpcntl); 37562306a36Sopenharmony_ci gpcntl = old_gpcntl & 0x1c; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 37862306a36Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 37962306a36Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* this is to set NVRAM into a known state with GPIO0/1 both low */ 38262306a36Sopenharmony_ci gpreg = old_gpreg; 38362306a36Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 38462306a36Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* now set NVRAM inactive with GPIO0/1 both high */ 38762306a36Sopenharmony_ci S24C16_stop(np, &gpreg); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* NVRAM has to be written in segments of 16 bytes */ 39062306a36Sopenharmony_ci for (x = 0; x < len ; x += 16) { 39162306a36Sopenharmony_ci do { 39262306a36Sopenharmony_ci S24C16_start(np, &gpreg); 39362306a36Sopenharmony_ci S24C16_write_byte(np, &ack_data, 39462306a36Sopenharmony_ci 0xa0 | (((offset+x) >> 7) & 0x0e), 39562306a36Sopenharmony_ci &gpreg, &gpcntl); 39662306a36Sopenharmony_ci } while (ack_data & 0x01); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, 39962306a36Sopenharmony_ci &gpreg, &gpcntl); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci for (y = 0; y < 16; y++) 40262306a36Sopenharmony_ci S24C16_write_byte(np, &ack_data, data[x+y], 40362306a36Sopenharmony_ci &gpreg, &gpcntl); 40462306a36Sopenharmony_ci S24C16_stop(np, &gpreg); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* return GPIO0/1 to original states after having accessed NVRAM */ 40862306a36Sopenharmony_ci OUTB(np, nc_gpcntl, old_gpcntl); 40962306a36Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/* 41662306a36Sopenharmony_ci * Read 'len' bytes starting at 'offset'. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_cistatic int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci u_char gpcntl, gpreg; 42162306a36Sopenharmony_ci u_char old_gpcntl, old_gpreg; 42262306a36Sopenharmony_ci u_char ack_data; 42362306a36Sopenharmony_ci int retv = 1; 42462306a36Sopenharmony_ci int x; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* save current state of GPCNTL and GPREG */ 42762306a36Sopenharmony_ci old_gpreg = INB(np, nc_gpreg); 42862306a36Sopenharmony_ci old_gpcntl = INB(np, nc_gpcntl); 42962306a36Sopenharmony_ci gpcntl = old_gpcntl & 0x1c; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 43262306a36Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 43362306a36Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* this is to set NVRAM into a known state with GPIO0/1 both low */ 43662306a36Sopenharmony_ci gpreg = old_gpreg; 43762306a36Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 43862306a36Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* now set NVRAM inactive with GPIO0/1 both high */ 44162306a36Sopenharmony_ci S24C16_stop(np, &gpreg); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* activate NVRAM */ 44462306a36Sopenharmony_ci S24C16_start(np, &gpreg); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* write device code and random address MSB */ 44762306a36Sopenharmony_ci S24C16_write_byte(np, &ack_data, 44862306a36Sopenharmony_ci 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 44962306a36Sopenharmony_ci if (ack_data & 0x01) 45062306a36Sopenharmony_ci goto out; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* write random address LSB */ 45362306a36Sopenharmony_ci S24C16_write_byte(np, &ack_data, 45462306a36Sopenharmony_ci offset & 0xff, &gpreg, &gpcntl); 45562306a36Sopenharmony_ci if (ack_data & 0x01) 45662306a36Sopenharmony_ci goto out; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* regenerate START state to set up for reading */ 45962306a36Sopenharmony_ci S24C16_start(np, &gpreg); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ 46262306a36Sopenharmony_ci S24C16_write_byte(np, &ack_data, 46362306a36Sopenharmony_ci 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 46462306a36Sopenharmony_ci if (ack_data & 0x01) 46562306a36Sopenharmony_ci goto out; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* now set up GPIO0 for inputting data */ 46862306a36Sopenharmony_ci gpcntl |= 0x01; 46962306a36Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* input all requested data - only part of total NVRAM */ 47262306a36Sopenharmony_ci for (x = 0; x < len; x++) 47362306a36Sopenharmony_ci S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* finally put NVRAM back in inactive mode */ 47662306a36Sopenharmony_ci gpcntl &= 0xfe; 47762306a36Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 47862306a36Sopenharmony_ci S24C16_stop(np, &gpreg); 47962306a36Sopenharmony_ci retv = 0; 48062306a36Sopenharmony_ciout: 48162306a36Sopenharmony_ci /* return GPIO0/1 to original states after having accessed NVRAM */ 48262306a36Sopenharmony_ci OUTB(np, nc_gpcntl, old_gpcntl); 48362306a36Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return retv; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci#undef SET_BIT 48962306a36Sopenharmony_ci#undef CLR_BIT 49062306a36Sopenharmony_ci#undef SET_CLK 49162306a36Sopenharmony_ci#undef CLR_CLK 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci/* 49462306a36Sopenharmony_ci * Try reading Symbios NVRAM. 49562306a36Sopenharmony_ci * Return 0 if OK. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_cistatic int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; 50062306a36Sopenharmony_ci u_char *data = (u_char *) nvram; 50162306a36Sopenharmony_ci int len = sizeof(*nvram); 50262306a36Sopenharmony_ci u_short csum; 50362306a36Sopenharmony_ci int x; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* probe the 24c16 and read the SYMBIOS 24c16 area */ 50662306a36Sopenharmony_ci if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) 50762306a36Sopenharmony_ci return 1; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* check valid NVRAM signature, verify byte count and checksum */ 51062306a36Sopenharmony_ci if (nvram->type != 0 || 51162306a36Sopenharmony_ci memcmp(nvram->trailer, Symbios_trailer, 6) || 51262306a36Sopenharmony_ci nvram->byte_count != len - 12) 51362306a36Sopenharmony_ci return 1; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* verify checksum */ 51662306a36Sopenharmony_ci for (x = 6, csum = 0; x < len - 6; x++) 51762306a36Sopenharmony_ci csum += data[x]; 51862306a36Sopenharmony_ci if (csum != nvram->checksum) 51962306a36Sopenharmony_ci return 1; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/* 52562306a36Sopenharmony_ci * 93C46 EEPROM reading. 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * GPIO0 - data in 52862306a36Sopenharmony_ci * GPIO1 - data out 52962306a36Sopenharmony_ci * GPIO2 - clock 53062306a36Sopenharmony_ci * GPIO4 - chip select 53162306a36Sopenharmony_ci * 53262306a36Sopenharmony_ci * Used by Tekram. 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* 53662306a36Sopenharmony_ci * Pulse clock bit in GPIO0 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_cistatic void T93C46_Clk(struct sym_device *np, u_char *gpreg) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg | 0x04); 54162306a36Sopenharmony_ci INB(np, nc_mbox1); 54262306a36Sopenharmony_ci udelay(2); 54362306a36Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/* 54762306a36Sopenharmony_ci * Read bit from NVRAM 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci udelay(2); 55262306a36Sopenharmony_ci T93C46_Clk(np, gpreg); 55362306a36Sopenharmony_ci *read_bit = INB(np, nc_gpreg); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/* 55762306a36Sopenharmony_ci * Write bit to GPIO0 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_cistatic void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (write_bit & 0x01) 56262306a36Sopenharmony_ci *gpreg |= 0x02; 56362306a36Sopenharmony_ci else 56462306a36Sopenharmony_ci *gpreg &= 0xfd; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci *gpreg |= 0x10; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 56962306a36Sopenharmony_ci INB(np, nc_mbox1); 57062306a36Sopenharmony_ci udelay(2); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci T93C46_Clk(np, gpreg); 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/* 57662306a36Sopenharmony_ci * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_cistatic void T93C46_Stop(struct sym_device *np, u_char *gpreg) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci *gpreg &= 0xef; 58162306a36Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 58262306a36Sopenharmony_ci INB(np, nc_mbox1); 58362306a36Sopenharmony_ci udelay(2); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci T93C46_Clk(np, gpreg); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* 58962306a36Sopenharmony_ci * Send read command and address to NVRAM 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_cistatic void T93C46_Send_Command(struct sym_device *np, u_short write_data, 59262306a36Sopenharmony_ci u_char *read_bit, u_char *gpreg) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci int x; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* send 9 bits, start bit (1), command (2), address (6) */ 59762306a36Sopenharmony_ci for (x = 0; x < 9; x++) 59862306a36Sopenharmony_ci T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci *read_bit = INB(np, nc_gpreg); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* 60462306a36Sopenharmony_ci * READ 2 bytes from the NVRAM 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_cistatic void T93C46_Read_Word(struct sym_device *np, 60762306a36Sopenharmony_ci unsigned short *nvram_data, unsigned char *gpreg) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int x; 61062306a36Sopenharmony_ci u_char read_bit; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci *nvram_data = 0; 61362306a36Sopenharmony_ci for (x = 0; x < 16; x++) { 61462306a36Sopenharmony_ci T93C46_Read_Bit(np, &read_bit, gpreg); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (read_bit & 0x01) 61762306a36Sopenharmony_ci *nvram_data |= (0x01 << (15 - x)); 61862306a36Sopenharmony_ci else 61962306a36Sopenharmony_ci *nvram_data &= ~(0x01 << (15 - x)); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci/* 62462306a36Sopenharmony_ci * Read Tekram NvRAM data. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_cistatic int T93C46_Read_Data(struct sym_device *np, unsigned short *data, 62762306a36Sopenharmony_ci int len, unsigned char *gpreg) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int x; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci for (x = 0; x < len; x++) { 63262306a36Sopenharmony_ci unsigned char read_bit; 63362306a36Sopenharmony_ci /* output read command and address */ 63462306a36Sopenharmony_ci T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); 63562306a36Sopenharmony_ci if (read_bit & 0x01) 63662306a36Sopenharmony_ci return 1; /* Bad */ 63762306a36Sopenharmony_ci T93C46_Read_Word(np, &data[x], gpreg); 63862306a36Sopenharmony_ci T93C46_Stop(np, gpreg); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci/* 64562306a36Sopenharmony_ci * Try reading 93C46 Tekram NVRAM. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_cistatic int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci u_char gpcntl, gpreg; 65062306a36Sopenharmony_ci u_char old_gpcntl, old_gpreg; 65162306a36Sopenharmony_ci int retv; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* save current state of GPCNTL and GPREG */ 65462306a36Sopenharmony_ci old_gpreg = INB(np, nc_gpreg); 65562306a36Sopenharmony_ci old_gpcntl = INB(np, nc_gpcntl); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, 65862306a36Sopenharmony_ci 1/2/4 out */ 65962306a36Sopenharmony_ci gpreg = old_gpreg & 0xe9; 66062306a36Sopenharmony_ci OUTB(np, nc_gpreg, gpreg); 66162306a36Sopenharmony_ci gpcntl = (old_gpcntl & 0xe9) | 0x09; 66262306a36Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* input all of NVRAM, 64 words */ 66562306a36Sopenharmony_ci retv = T93C46_Read_Data(np, (u_short *) nvram, 66662306a36Sopenharmony_ci sizeof(*nvram) / sizeof(short), &gpreg); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ 66962306a36Sopenharmony_ci OUTB(np, nc_gpcntl, old_gpcntl); 67062306a36Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return retv; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci/* 67662306a36Sopenharmony_ci * Try reading Tekram NVRAM. 67762306a36Sopenharmony_ci * Return 0 if OK. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_cistatic int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci u_char *data = (u_char *) nvram; 68262306a36Sopenharmony_ci int len = sizeof(*nvram); 68362306a36Sopenharmony_ci u_short csum; 68462306a36Sopenharmony_ci int x; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci switch (np->pdev->device) { 68762306a36Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C885: 68862306a36Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C895: 68962306a36Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C896: 69062306a36Sopenharmony_ci x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 69162306a36Sopenharmony_ci data, len); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C875: 69462306a36Sopenharmony_ci x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 69562306a36Sopenharmony_ci data, len); 69662306a36Sopenharmony_ci if (!x) 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci fallthrough; 69962306a36Sopenharmony_ci default: 70062306a36Sopenharmony_ci x = sym_read_T93C46_nvram(np, nvram); 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci if (x) 70462306a36Sopenharmony_ci return 1; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* verify checksum */ 70762306a36Sopenharmony_ci for (x = 0, csum = 0; x < len - 1; x += 2) 70862306a36Sopenharmony_ci csum += data[x] + (data[x+1] << 8); 70962306a36Sopenharmony_ci if (csum != 0x1234) 71062306a36Sopenharmony_ci return 1; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci#ifdef CONFIG_PARISC 71662306a36Sopenharmony_ci/* 71762306a36Sopenharmony_ci * Host firmware (PDC) keeps a table for altering SCSI capabilities. 71862306a36Sopenharmony_ci * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD. 71962306a36Sopenharmony_ci * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_cistatic int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct hardware_path hwpath; 72462306a36Sopenharmony_ci get_pci_node_path(np->pdev, &hwpath); 72562306a36Sopenharmony_ci if (!pdc_get_initiator(&hwpath, pdc)) 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return SYM_PARISC_PDC; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci#else 73162306a36Sopenharmony_cistatic inline int sym_read_parisc_pdc(struct sym_device *np, 73262306a36Sopenharmony_ci struct pdc_initiator *x) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci#endif 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/* 73962306a36Sopenharmony_ci * Try reading Symbios or Tekram NVRAM 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ciint sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) { 74462306a36Sopenharmony_ci nvp->type = SYM_SYMBIOS_NVRAM; 74562306a36Sopenharmony_ci sym_display_Symbios_nvram(np, &nvp->data.Symbios); 74662306a36Sopenharmony_ci } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) { 74762306a36Sopenharmony_ci nvp->type = SYM_TEKRAM_NVRAM; 74862306a36Sopenharmony_ci sym_display_Tekram_nvram(np, &nvp->data.Tekram); 74962306a36Sopenharmony_ci } else { 75062306a36Sopenharmony_ci nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci return nvp->type; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cichar *sym_nvram_type(struct sym_nvram *nvp) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci switch (nvp->type) { 75862306a36Sopenharmony_ci case SYM_SYMBIOS_NVRAM: 75962306a36Sopenharmony_ci return "Symbios NVRAM"; 76062306a36Sopenharmony_ci case SYM_TEKRAM_NVRAM: 76162306a36Sopenharmony_ci return "Tekram NVRAM"; 76262306a36Sopenharmony_ci case SYM_PARISC_PDC: 76362306a36Sopenharmony_ci return "PA-RISC Firmware"; 76462306a36Sopenharmony_ci default: 76562306a36Sopenharmony_ci return "No NVRAM"; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci} 768