18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 48c2ecf20Sopenharmony_ci * of PCI-SCSI IO processors. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This driver is derived from the Linux sym53c8xx driver. 98c2ecf20Sopenharmony_ci * Copyright (C) 1998-2000 Gerard Roudier 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 128c2ecf20Sopenharmony_ci * a port of the FreeBSD ncr driver to Linux-1.2.13. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The original ncr driver has been written for 386bsd and FreeBSD by 158c2ecf20Sopenharmony_ci * Wolfgang Stanglmeier <wolf@cologne.de> 168c2ecf20Sopenharmony_ci * Stefan Esser <se@mi.Uni-Koeln.de> 178c2ecf20Sopenharmony_ci * Copyright (C) 1994 Wolfgang Stanglmeier 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Other major contributions: 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * NVRAM detection and reading. 228c2ecf20Sopenharmony_ci * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------- 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "sym_glue.h" 288c2ecf20Sopenharmony_ci#include "sym_nvram.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifdef SYM_CONF_DEBUG_NVRAM 318c2ecf20Sopenharmony_cistatic u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Get host setup from NVRAM. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_civoid sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * Get parity checking, host ID, verbose mode 418c2ecf20Sopenharmony_ci * and miscellaneous host flags from NVRAM. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci switch (nvram->type) { 448c2ecf20Sopenharmony_ci case SYM_SYMBIOS_NVRAM: 458c2ecf20Sopenharmony_ci if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) 468c2ecf20Sopenharmony_ci np->rv_scntl0 &= ~0x0a; 478c2ecf20Sopenharmony_ci np->myaddr = nvram->data.Symbios.host_id & 0x0f; 488c2ecf20Sopenharmony_ci if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) 498c2ecf20Sopenharmony_ci np->verbose += 1; 508c2ecf20Sopenharmony_ci if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) 518c2ecf20Sopenharmony_ci shost->reverse_ordering = 1; 528c2ecf20Sopenharmony_ci if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) 538c2ecf20Sopenharmony_ci np->usrflags |= SYM_AVOID_BUS_RESET; 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci case SYM_TEKRAM_NVRAM: 568c2ecf20Sopenharmony_ci np->myaddr = nvram->data.Tekram.host_id & 0x0f; 578c2ecf20Sopenharmony_ci break; 588c2ecf20Sopenharmony_ci#ifdef CONFIG_PARISC 598c2ecf20Sopenharmony_ci case SYM_PARISC_PDC: 608c2ecf20Sopenharmony_ci if (nvram->data.parisc.host_id != -1) 618c2ecf20Sopenharmony_ci np->myaddr = nvram->data.parisc.host_id; 628c2ecf20Sopenharmony_ci if (nvram->data.parisc.factor != -1) 638c2ecf20Sopenharmony_ci np->minsync = nvram->data.parisc.factor; 648c2ecf20Sopenharmony_ci if (nvram->data.parisc.width != -1) 658c2ecf20Sopenharmony_ci np->maxwide = nvram->data.parisc.width; 668c2ecf20Sopenharmony_ci switch (nvram->data.parisc.mode) { 678c2ecf20Sopenharmony_ci case 0: np->scsi_mode = SMODE_SE; break; 688c2ecf20Sopenharmony_ci case 1: np->scsi_mode = SMODE_HVD; break; 698c2ecf20Sopenharmony_ci case 2: np->scsi_mode = SMODE_LVD; break; 708c2ecf20Sopenharmony_ci default: break; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci default: 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Get target set-up from Symbios format NVRAM. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic void 828c2ecf20Sopenharmony_cisym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci Symbios_target *tn = &nvram->target[target]; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)) 878c2ecf20Sopenharmony_ci tp->usrtags = 0; 888c2ecf20Sopenharmony_ci if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) 898c2ecf20Sopenharmony_ci tp->usrflags &= ~SYM_DISC_ENABLED; 908c2ecf20Sopenharmony_ci if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) 918c2ecf20Sopenharmony_ci tp->usrflags |= SYM_SCAN_BOOT_DISABLED; 928c2ecf20Sopenharmony_ci if (!(tn->flags & SYMBIOS_SCAN_LUNS)) 938c2ecf20Sopenharmony_ci tp->usrflags |= SYM_SCAN_LUNS_DISABLED; 948c2ecf20Sopenharmony_ci tp->usr_period = (tn->sync_period + 3) / 4; 958c2ecf20Sopenharmony_ci tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const unsigned char Tekram_sync[16] = { 998c2ecf20Sopenharmony_ci 25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * Get target set-up from Tekram format NVRAM. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic void 1068c2ecf20Sopenharmony_cisym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct Tekram_target *tn = &nvram->target[target]; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (tn->flags & TEKRAM_TAGGED_COMMANDS) { 1118c2ecf20Sopenharmony_ci tp->usrtags = 2 << nvram->max_tags_index; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (tn->flags & TEKRAM_DISCONNECT_ENABLE) 1158c2ecf20Sopenharmony_ci tp->usrflags |= SYM_DISC_ENABLED; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (tn->flags & TEKRAM_SYNC_NEGO) 1188c2ecf20Sopenharmony_ci tp->usr_period = Tekram_sync[tn->sync_index & 0xf]; 1198c2ecf20Sopenharmony_ci tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* 1238c2ecf20Sopenharmony_ci * Get target setup from NVRAM. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_civoid sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci switch (nvp->type) { 1288c2ecf20Sopenharmony_ci case SYM_SYMBIOS_NVRAM: 1298c2ecf20Sopenharmony_ci sym_Symbios_setup_target(tp, target, &nvp->data.Symbios); 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case SYM_TEKRAM_NVRAM: 1328c2ecf20Sopenharmony_ci sym_Tekram_setup_target(tp, target, &nvp->data.Tekram); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci default: 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#ifdef SYM_CONF_DEBUG_NVRAM 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * Dump Symbios format NVRAM for debugging purpose. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci int i; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* display Symbios nvram host data */ 1488c2ecf20Sopenharmony_ci printf("%s: HOST ID=%d%s%s%s%s%s%s\n", 1498c2ecf20Sopenharmony_ci sym_name(np), nvram->host_id & 0x0f, 1508c2ecf20Sopenharmony_ci (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 1518c2ecf20Sopenharmony_ci (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", 1528c2ecf20Sopenharmony_ci (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", 1538c2ecf20Sopenharmony_ci (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", 1548c2ecf20Sopenharmony_ci (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"", 1558c2ecf20Sopenharmony_ci (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* display Symbios nvram drive data */ 1588c2ecf20Sopenharmony_ci for (i = 0 ; i < 15 ; i++) { 1598c2ecf20Sopenharmony_ci struct Symbios_target *tn = &nvram->target[i]; 1608c2ecf20Sopenharmony_ci printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", 1618c2ecf20Sopenharmony_ci sym_name(np), i, 1628c2ecf20Sopenharmony_ci (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", 1638c2ecf20Sopenharmony_ci (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", 1648c2ecf20Sopenharmony_ci (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", 1658c2ecf20Sopenharmony_ci (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", 1668c2ecf20Sopenharmony_ci tn->bus_width, 1678c2ecf20Sopenharmony_ci tn->sync_period / 4, 1688c2ecf20Sopenharmony_ci tn->timeout); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * Dump TEKRAM format NVRAM for debugging purpose. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci int i, tags, boot_delay; 1788c2ecf20Sopenharmony_ci char *rem; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* display Tekram nvram host data */ 1818c2ecf20Sopenharmony_ci tags = 2 << nvram->max_tags_index; 1828c2ecf20Sopenharmony_ci boot_delay = 0; 1838c2ecf20Sopenharmony_ci if (nvram->boot_delay_index < 6) 1848c2ecf20Sopenharmony_ci boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; 1858c2ecf20Sopenharmony_ci switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { 1868c2ecf20Sopenharmony_ci default: 1878c2ecf20Sopenharmony_ci case 0: rem = ""; break; 1888c2ecf20Sopenharmony_ci case 1: rem = " REMOVABLE=boot device"; break; 1898c2ecf20Sopenharmony_ci case 2: rem = " REMOVABLE=all"; break; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", 1938c2ecf20Sopenharmony_ci sym_name(np), nvram->host_id & 0x0f, 1948c2ecf20Sopenharmony_ci (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 1958c2ecf20Sopenharmony_ci (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"", 1968c2ecf20Sopenharmony_ci (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", 1978c2ecf20Sopenharmony_ci (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", 1988c2ecf20Sopenharmony_ci (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", 1998c2ecf20Sopenharmony_ci (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", 2008c2ecf20Sopenharmony_ci (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", 2018c2ecf20Sopenharmony_ci (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", 2028c2ecf20Sopenharmony_ci rem, boot_delay, tags); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* display Tekram nvram drive data */ 2058c2ecf20Sopenharmony_ci for (i = 0; i <= 15; i++) { 2068c2ecf20Sopenharmony_ci int sync, j; 2078c2ecf20Sopenharmony_ci struct Tekram_target *tn = &nvram->target[i]; 2088c2ecf20Sopenharmony_ci j = tn->sync_index & 0xf; 2098c2ecf20Sopenharmony_ci sync = Tekram_sync[j]; 2108c2ecf20Sopenharmony_ci printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", 2118c2ecf20Sopenharmony_ci sym_name(np), i, 2128c2ecf20Sopenharmony_ci (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", 2138c2ecf20Sopenharmony_ci (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", 2148c2ecf20Sopenharmony_ci (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", 2158c2ecf20Sopenharmony_ci (tn->flags & TEKRAM_START_CMD) ? " START" : "", 2168c2ecf20Sopenharmony_ci (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", 2178c2ecf20Sopenharmony_ci (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", 2188c2ecf20Sopenharmony_ci sync); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci#else 2228c2ecf20Sopenharmony_cistatic void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; } 2238c2ecf20Sopenharmony_cistatic void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; } 2248c2ecf20Sopenharmony_ci#endif /* SYM_CONF_DEBUG_NVRAM */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/* 2288c2ecf20Sopenharmony_ci * 24C16 EEPROM reading. 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * GPIO0 - data in/data out 2318c2ecf20Sopenharmony_ci * GPIO1 - clock 2328c2ecf20Sopenharmony_ci * Symbios NVRAM wiring now also used by Tekram. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define SET_BIT 0 2368c2ecf20Sopenharmony_ci#define CLR_BIT 1 2378c2ecf20Sopenharmony_ci#define SET_CLK 2 2388c2ecf20Sopenharmony_ci#define CLR_CLK 3 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* 2418c2ecf20Sopenharmony_ci * Set/clear data/clock bit in GPIO0 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, 2448c2ecf20Sopenharmony_ci int bit_mode) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci udelay(5); 2478c2ecf20Sopenharmony_ci switch (bit_mode) { 2488c2ecf20Sopenharmony_ci case SET_BIT: 2498c2ecf20Sopenharmony_ci *gpreg |= write_bit; 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case CLR_BIT: 2528c2ecf20Sopenharmony_ci *gpreg &= 0xfe; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case SET_CLK: 2558c2ecf20Sopenharmony_ci *gpreg |= 0x02; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case CLR_CLK: 2588c2ecf20Sopenharmony_ci *gpreg &= 0xfd; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 2638c2ecf20Sopenharmony_ci INB(np, nc_mbox1); 2648c2ecf20Sopenharmony_ci udelay(5); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* 2688c2ecf20Sopenharmony_ci * Send START condition to NVRAM to wake it up. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_cistatic void S24C16_start(struct sym_device *np, u_char *gpreg) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci S24C16_set_bit(np, 1, gpreg, SET_BIT); 2738c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, SET_CLK); 2748c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_BIT); 2758c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_CLK); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* 2798c2ecf20Sopenharmony_ci * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_cistatic void S24C16_stop(struct sym_device *np, u_char *gpreg) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, SET_CLK); 2848c2ecf20Sopenharmony_ci S24C16_set_bit(np, 1, gpreg, SET_BIT); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * Read or write a bit to the NVRAM, 2898c2ecf20Sopenharmony_ci * read if GPIO0 input else write if GPIO0 output 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit, 2928c2ecf20Sopenharmony_ci u_char *gpreg) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci S24C16_set_bit(np, write_bit, gpreg, SET_BIT); 2958c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, SET_CLK); 2968c2ecf20Sopenharmony_ci if (read_bit) 2978c2ecf20Sopenharmony_ci *read_bit = INB(np, nc_gpreg); 2988c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_CLK); 2998c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, gpreg, CLR_BIT); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* 3038c2ecf20Sopenharmony_ci * Output an ACK to the NVRAM after reading, 3048c2ecf20Sopenharmony_ci * change GPIO0 to output and when done back to an input 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistatic void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, 3078c2ecf20Sopenharmony_ci u_char *gpcntl) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl & 0xfe); 3108c2ecf20Sopenharmony_ci S24C16_do_bit(np, NULL, write_bit, gpreg); 3118c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* 3158c2ecf20Sopenharmony_ci * Input an ACK from NVRAM after writing, 3168c2ecf20Sopenharmony_ci * change GPIO0 to input and when done back to an output 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_cistatic void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, 3198c2ecf20Sopenharmony_ci u_char *gpcntl) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl | 0x01); 3228c2ecf20Sopenharmony_ci S24C16_do_bit(np, read_bit, 1, gpreg); 3238c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, *gpcntl); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/* 3278c2ecf20Sopenharmony_ci * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, 3288c2ecf20Sopenharmony_ci * GPIO0 must already be set as an output 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data, 3318c2ecf20Sopenharmony_ci u_char *gpreg, u_char *gpcntl) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int x; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci for (x = 0; x < 8; x++) 3368c2ecf20Sopenharmony_ci S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci S24C16_read_ack(np, ack_data, gpreg, gpcntl); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/* 3428c2ecf20Sopenharmony_ci * READ a byte from the NVRAM and then send an ACK to say we have got it, 3438c2ecf20Sopenharmony_ci * GPIO0 must already be set as an input 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_cistatic void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data, 3468c2ecf20Sopenharmony_ci u_char *gpreg, u_char *gpcntl) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci int x; 3498c2ecf20Sopenharmony_ci u_char read_bit; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci *read_data = 0; 3528c2ecf20Sopenharmony_ci for (x = 0; x < 8; x++) { 3538c2ecf20Sopenharmony_ci S24C16_do_bit(np, &read_bit, 1, gpreg); 3548c2ecf20Sopenharmony_ci *read_data |= ((read_bit & 0x01) << (7 - x)); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci S24C16_write_ack(np, ack_data, gpreg, gpcntl); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT 3618c2ecf20Sopenharmony_ci/* 3628c2ecf20Sopenharmony_ci * Write 'len' bytes starting at 'offset'. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic int sym_write_S24C16_nvram(struct sym_device *np, int offset, 3658c2ecf20Sopenharmony_ci u_char *data, int len) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci u_char gpcntl, gpreg; 3688c2ecf20Sopenharmony_ci u_char old_gpcntl, old_gpreg; 3698c2ecf20Sopenharmony_ci u_char ack_data; 3708c2ecf20Sopenharmony_ci int x; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* save current state of GPCNTL and GPREG */ 3738c2ecf20Sopenharmony_ci old_gpreg = INB(np, nc_gpreg); 3748c2ecf20Sopenharmony_ci old_gpcntl = INB(np, nc_gpcntl); 3758c2ecf20Sopenharmony_ci gpcntl = old_gpcntl & 0x1c; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 3788c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 3798c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* this is to set NVRAM into a known state with GPIO0/1 both low */ 3828c2ecf20Sopenharmony_ci gpreg = old_gpreg; 3838c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 3848c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* now set NVRAM inactive with GPIO0/1 both high */ 3878c2ecf20Sopenharmony_ci S24C16_stop(np, &gpreg); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* NVRAM has to be written in segments of 16 bytes */ 3908c2ecf20Sopenharmony_ci for (x = 0; x < len ; x += 16) { 3918c2ecf20Sopenharmony_ci do { 3928c2ecf20Sopenharmony_ci S24C16_start(np, &gpreg); 3938c2ecf20Sopenharmony_ci S24C16_write_byte(np, &ack_data, 3948c2ecf20Sopenharmony_ci 0xa0 | (((offset+x) >> 7) & 0x0e), 3958c2ecf20Sopenharmony_ci &gpreg, &gpcntl); 3968c2ecf20Sopenharmony_ci } while (ack_data & 0x01); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, 3998c2ecf20Sopenharmony_ci &gpreg, &gpcntl); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci for (y = 0; y < 16; y++) 4028c2ecf20Sopenharmony_ci S24C16_write_byte(np, &ack_data, data[x+y], 4038c2ecf20Sopenharmony_ci &gpreg, &gpcntl); 4048c2ecf20Sopenharmony_ci S24C16_stop(np, &gpreg); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* return GPIO0/1 to original states after having accessed NVRAM */ 4088c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, old_gpcntl); 4098c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */ 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci/* 4168c2ecf20Sopenharmony_ci * Read 'len' bytes starting at 'offset'. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_cistatic int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci u_char gpcntl, gpreg; 4218c2ecf20Sopenharmony_ci u_char old_gpcntl, old_gpreg; 4228c2ecf20Sopenharmony_ci u_char ack_data; 4238c2ecf20Sopenharmony_ci int retv = 1; 4248c2ecf20Sopenharmony_ci int x; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* save current state of GPCNTL and GPREG */ 4278c2ecf20Sopenharmony_ci old_gpreg = INB(np, nc_gpreg); 4288c2ecf20Sopenharmony_ci old_gpcntl = INB(np, nc_gpcntl); 4298c2ecf20Sopenharmony_ci gpcntl = old_gpcntl & 0x1c; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 4328c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 4338c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* this is to set NVRAM into a known state with GPIO0/1 both low */ 4368c2ecf20Sopenharmony_ci gpreg = old_gpreg; 4378c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 4388c2ecf20Sopenharmony_ci S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* now set NVRAM inactive with GPIO0/1 both high */ 4418c2ecf20Sopenharmony_ci S24C16_stop(np, &gpreg); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* activate NVRAM */ 4448c2ecf20Sopenharmony_ci S24C16_start(np, &gpreg); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* write device code and random address MSB */ 4478c2ecf20Sopenharmony_ci S24C16_write_byte(np, &ack_data, 4488c2ecf20Sopenharmony_ci 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 4498c2ecf20Sopenharmony_ci if (ack_data & 0x01) 4508c2ecf20Sopenharmony_ci goto out; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* write random address LSB */ 4538c2ecf20Sopenharmony_ci S24C16_write_byte(np, &ack_data, 4548c2ecf20Sopenharmony_ci offset & 0xff, &gpreg, &gpcntl); 4558c2ecf20Sopenharmony_ci if (ack_data & 0x01) 4568c2ecf20Sopenharmony_ci goto out; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* regenerate START state to set up for reading */ 4598c2ecf20Sopenharmony_ci S24C16_start(np, &gpreg); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ 4628c2ecf20Sopenharmony_ci S24C16_write_byte(np, &ack_data, 4638c2ecf20Sopenharmony_ci 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 4648c2ecf20Sopenharmony_ci if (ack_data & 0x01) 4658c2ecf20Sopenharmony_ci goto out; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* now set up GPIO0 for inputting data */ 4688c2ecf20Sopenharmony_ci gpcntl |= 0x01; 4698c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* input all requested data - only part of total NVRAM */ 4728c2ecf20Sopenharmony_ci for (x = 0; x < len; x++) 4738c2ecf20Sopenharmony_ci S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* finally put NVRAM back in inactive mode */ 4768c2ecf20Sopenharmony_ci gpcntl &= 0xfe; 4778c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 4788c2ecf20Sopenharmony_ci S24C16_stop(np, &gpreg); 4798c2ecf20Sopenharmony_ci retv = 0; 4808c2ecf20Sopenharmony_ciout: 4818c2ecf20Sopenharmony_ci /* return GPIO0/1 to original states after having accessed NVRAM */ 4828c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, old_gpcntl); 4838c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return retv; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci#undef SET_BIT 4898c2ecf20Sopenharmony_ci#undef CLR_BIT 4908c2ecf20Sopenharmony_ci#undef SET_CLK 4918c2ecf20Sopenharmony_ci#undef CLR_CLK 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/* 4948c2ecf20Sopenharmony_ci * Try reading Symbios NVRAM. 4958c2ecf20Sopenharmony_ci * Return 0 if OK. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_cistatic int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; 5008c2ecf20Sopenharmony_ci u_char *data = (u_char *) nvram; 5018c2ecf20Sopenharmony_ci int len = sizeof(*nvram); 5028c2ecf20Sopenharmony_ci u_short csum; 5038c2ecf20Sopenharmony_ci int x; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* probe the 24c16 and read the SYMBIOS 24c16 area */ 5068c2ecf20Sopenharmony_ci if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) 5078c2ecf20Sopenharmony_ci return 1; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* check valid NVRAM signature, verify byte count and checksum */ 5108c2ecf20Sopenharmony_ci if (nvram->type != 0 || 5118c2ecf20Sopenharmony_ci memcmp(nvram->trailer, Symbios_trailer, 6) || 5128c2ecf20Sopenharmony_ci nvram->byte_count != len - 12) 5138c2ecf20Sopenharmony_ci return 1; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* verify checksum */ 5168c2ecf20Sopenharmony_ci for (x = 6, csum = 0; x < len - 6; x++) 5178c2ecf20Sopenharmony_ci csum += data[x]; 5188c2ecf20Sopenharmony_ci if (csum != nvram->checksum) 5198c2ecf20Sopenharmony_ci return 1; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/* 5258c2ecf20Sopenharmony_ci * 93C46 EEPROM reading. 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci * GPIO0 - data in 5288c2ecf20Sopenharmony_ci * GPIO1 - data out 5298c2ecf20Sopenharmony_ci * GPIO2 - clock 5308c2ecf20Sopenharmony_ci * GPIO4 - chip select 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * Used by Tekram. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/* 5368c2ecf20Sopenharmony_ci * Pulse clock bit in GPIO0 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_cistatic void T93C46_Clk(struct sym_device *np, u_char *gpreg) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg | 0x04); 5418c2ecf20Sopenharmony_ci INB(np, nc_mbox1); 5428c2ecf20Sopenharmony_ci udelay(2); 5438c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci/* 5478c2ecf20Sopenharmony_ci * Read bit from NVRAM 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_cistatic void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci udelay(2); 5528c2ecf20Sopenharmony_ci T93C46_Clk(np, gpreg); 5538c2ecf20Sopenharmony_ci *read_bit = INB(np, nc_gpreg); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* 5578c2ecf20Sopenharmony_ci * Write bit to GPIO0 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_cistatic void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci if (write_bit & 0x01) 5628c2ecf20Sopenharmony_ci *gpreg |= 0x02; 5638c2ecf20Sopenharmony_ci else 5648c2ecf20Sopenharmony_ci *gpreg &= 0xfd; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci *gpreg |= 0x10; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 5698c2ecf20Sopenharmony_ci INB(np, nc_mbox1); 5708c2ecf20Sopenharmony_ci udelay(2); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci T93C46_Clk(np, gpreg); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* 5768c2ecf20Sopenharmony_ci * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistatic void T93C46_Stop(struct sym_device *np, u_char *gpreg) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci *gpreg &= 0xef; 5818c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, *gpreg); 5828c2ecf20Sopenharmony_ci INB(np, nc_mbox1); 5838c2ecf20Sopenharmony_ci udelay(2); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci T93C46_Clk(np, gpreg); 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/* 5898c2ecf20Sopenharmony_ci * Send read command and address to NVRAM 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_cistatic void T93C46_Send_Command(struct sym_device *np, u_short write_data, 5928c2ecf20Sopenharmony_ci u_char *read_bit, u_char *gpreg) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci int x; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* send 9 bits, start bit (1), command (2), address (6) */ 5978c2ecf20Sopenharmony_ci for (x = 0; x < 9; x++) 5988c2ecf20Sopenharmony_ci T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci *read_bit = INB(np, nc_gpreg); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/* 6048c2ecf20Sopenharmony_ci * READ 2 bytes from the NVRAM 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_cistatic void T93C46_Read_Word(struct sym_device *np, 6078c2ecf20Sopenharmony_ci unsigned short *nvram_data, unsigned char *gpreg) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci int x; 6108c2ecf20Sopenharmony_ci u_char read_bit; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci *nvram_data = 0; 6138c2ecf20Sopenharmony_ci for (x = 0; x < 16; x++) { 6148c2ecf20Sopenharmony_ci T93C46_Read_Bit(np, &read_bit, gpreg); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (read_bit & 0x01) 6178c2ecf20Sopenharmony_ci *nvram_data |= (0x01 << (15 - x)); 6188c2ecf20Sopenharmony_ci else 6198c2ecf20Sopenharmony_ci *nvram_data &= ~(0x01 << (15 - x)); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* 6248c2ecf20Sopenharmony_ci * Read Tekram NvRAM data. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_cistatic int T93C46_Read_Data(struct sym_device *np, unsigned short *data, 6278c2ecf20Sopenharmony_ci int len, unsigned char *gpreg) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci int x; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci for (x = 0; x < len; x++) { 6328c2ecf20Sopenharmony_ci unsigned char read_bit; 6338c2ecf20Sopenharmony_ci /* output read command and address */ 6348c2ecf20Sopenharmony_ci T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); 6358c2ecf20Sopenharmony_ci if (read_bit & 0x01) 6368c2ecf20Sopenharmony_ci return 1; /* Bad */ 6378c2ecf20Sopenharmony_ci T93C46_Read_Word(np, &data[x], gpreg); 6388c2ecf20Sopenharmony_ci T93C46_Stop(np, gpreg); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci/* 6458c2ecf20Sopenharmony_ci * Try reading 93C46 Tekram NVRAM. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_cistatic int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci u_char gpcntl, gpreg; 6508c2ecf20Sopenharmony_ci u_char old_gpcntl, old_gpreg; 6518c2ecf20Sopenharmony_ci int retv; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* save current state of GPCNTL and GPREG */ 6548c2ecf20Sopenharmony_ci old_gpreg = INB(np, nc_gpreg); 6558c2ecf20Sopenharmony_ci old_gpcntl = INB(np, nc_gpcntl); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, 6588c2ecf20Sopenharmony_ci 1/2/4 out */ 6598c2ecf20Sopenharmony_ci gpreg = old_gpreg & 0xe9; 6608c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, gpreg); 6618c2ecf20Sopenharmony_ci gpcntl = (old_gpcntl & 0xe9) | 0x09; 6628c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, gpcntl); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* input all of NVRAM, 64 words */ 6658c2ecf20Sopenharmony_ci retv = T93C46_Read_Data(np, (u_short *) nvram, 6668c2ecf20Sopenharmony_ci sizeof(*nvram) / sizeof(short), &gpreg); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ 6698c2ecf20Sopenharmony_ci OUTB(np, nc_gpcntl, old_gpcntl); 6708c2ecf20Sopenharmony_ci OUTB(np, nc_gpreg, old_gpreg); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return retv; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci/* 6768c2ecf20Sopenharmony_ci * Try reading Tekram NVRAM. 6778c2ecf20Sopenharmony_ci * Return 0 if OK. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_cistatic int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci u_char *data = (u_char *) nvram; 6828c2ecf20Sopenharmony_ci int len = sizeof(*nvram); 6838c2ecf20Sopenharmony_ci u_short csum; 6848c2ecf20Sopenharmony_ci int x; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci switch (np->pdev->device) { 6878c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C885: 6888c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C895: 6898c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C896: 6908c2ecf20Sopenharmony_ci x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 6918c2ecf20Sopenharmony_ci data, len); 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NCR_53C875: 6948c2ecf20Sopenharmony_ci x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 6958c2ecf20Sopenharmony_ci data, len); 6968c2ecf20Sopenharmony_ci if (!x) 6978c2ecf20Sopenharmony_ci break; 6988c2ecf20Sopenharmony_ci fallthrough; 6998c2ecf20Sopenharmony_ci default: 7008c2ecf20Sopenharmony_ci x = sym_read_T93C46_nvram(np, nvram); 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci if (x) 7048c2ecf20Sopenharmony_ci return 1; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* verify checksum */ 7078c2ecf20Sopenharmony_ci for (x = 0, csum = 0; x < len - 1; x += 2) 7088c2ecf20Sopenharmony_ci csum += data[x] + (data[x+1] << 8); 7098c2ecf20Sopenharmony_ci if (csum != 0x1234) 7108c2ecf20Sopenharmony_ci return 1; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci#ifdef CONFIG_PARISC 7168c2ecf20Sopenharmony_ci/* 7178c2ecf20Sopenharmony_ci * Host firmware (PDC) keeps a table for altering SCSI capabilities. 7188c2ecf20Sopenharmony_ci * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD. 7198c2ecf20Sopenharmony_ci * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_cistatic int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct hardware_path hwpath; 7248c2ecf20Sopenharmony_ci get_pci_node_path(np->pdev, &hwpath); 7258c2ecf20Sopenharmony_ci if (!pdc_get_initiator(&hwpath, pdc)) 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return SYM_PARISC_PDC; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci#else 7318c2ecf20Sopenharmony_cistatic inline int sym_read_parisc_pdc(struct sym_device *np, 7328c2ecf20Sopenharmony_ci struct pdc_initiator *x) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci#endif 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci/* 7398c2ecf20Sopenharmony_ci * Try reading Symbios or Tekram NVRAM 7408c2ecf20Sopenharmony_ci */ 7418c2ecf20Sopenharmony_ciint sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) { 7448c2ecf20Sopenharmony_ci nvp->type = SYM_SYMBIOS_NVRAM; 7458c2ecf20Sopenharmony_ci sym_display_Symbios_nvram(np, &nvp->data.Symbios); 7468c2ecf20Sopenharmony_ci } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) { 7478c2ecf20Sopenharmony_ci nvp->type = SYM_TEKRAM_NVRAM; 7488c2ecf20Sopenharmony_ci sym_display_Tekram_nvram(np, &nvp->data.Tekram); 7498c2ecf20Sopenharmony_ci } else { 7508c2ecf20Sopenharmony_ci nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci return nvp->type; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cichar *sym_nvram_type(struct sym_nvram *nvp) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci switch (nvp->type) { 7588c2ecf20Sopenharmony_ci case SYM_SYMBIOS_NVRAM: 7598c2ecf20Sopenharmony_ci return "Symbios NVRAM"; 7608c2ecf20Sopenharmony_ci case SYM_TEKRAM_NVRAM: 7618c2ecf20Sopenharmony_ci return "Tekram NVRAM"; 7628c2ecf20Sopenharmony_ci case SYM_PARISC_PDC: 7638c2ecf20Sopenharmony_ci return "PA-RISC Firmware"; 7648c2ecf20Sopenharmony_ci default: 7658c2ecf20Sopenharmony_ci return "No NVRAM"; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci} 768