// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. * * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> * * This driver is derived from the Linux sym53c8xx driver. * Copyright (C) 1998-2000 Gerard Roudier * * The sym53c8xx driver is derived from the ncr53c8xx driver that had been * a port of the FreeBSD ncr driver to Linux-1.2.13. * * The original ncr driver has been written for 386bsd and FreeBSD by * Wolfgang Stanglmeier <wolf@cologne.de> * Stefan Esser <se@mi.Uni-Koeln.de> * Copyright (C) 1994 Wolfgang Stanglmeier * * Other major contributions: * * NVRAM detection and reading. * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> * *-----------------------------------------------------------------------------
*/
/* * Read or write a bit to the NVRAM, * read if GPIO0 input else write if GPIO0 output
*/ staticvoid S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit,
u_char *gpreg)
{
S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
S24C16_set_bit(np, 0, gpreg, SET_CLK); if (read_bit)
*read_bit = INB(np, nc_gpreg);
S24C16_set_bit(np, 0, gpreg, CLR_CLK);
S24C16_set_bit(np, 0, gpreg, CLR_BIT);
}
/* * Output an ACK to the NVRAM after reading, * change GPIO0 to output and when done back to an input
*/ staticvoid S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
u_char *gpcntl)
{
OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
S24C16_do_bit(np, NULL, write_bit, gpreg);
OUTB(np, nc_gpcntl, *gpcntl);
}
/* * Input an ACK from NVRAM after writing, * change GPIO0 to input and when done back to an output
*/ staticvoid S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
u_char *gpcntl)
{
OUTB(np, nc_gpcntl, *gpcntl | 0x01);
S24C16_do_bit(np, read_bit, 1, gpreg);
OUTB(np, nc_gpcntl, *gpcntl);
}
/* * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, * GPIO0 must already be set as an output
*/ staticvoid S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data,
u_char *gpreg, u_char *gpcntl)
{ int x;
for (x = 0; x < 8; x++)
S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
S24C16_read_ack(np, ack_data, gpreg, gpcntl);
}
/* * READ a byte from the NVRAM and then send an ACK to say we have got it, * GPIO0 must already be set as an input
*/ staticvoid S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data,
u_char *gpreg, u_char *gpcntl)
{ int x;
u_char read_bit;
#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT /* * Write 'len' bytes starting at 'offset'.
*/ staticint sym_write_S24C16_nvram(struct sym_device *np, int offset,
u_char *data, int len)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
u_char ack_data; int x;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB(np, nc_gpreg, old_gpreg);
OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg;
S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
/* now set NVRAM inactive with GPIO0/1 both high */
S24C16_stop(np, &gpreg);
/* NVRAM has to be written in segments of 16 bytes */ for (x = 0; x < len ; x += 16) { do {
S24C16_start(np, &gpreg);
S24C16_write_byte(np, &ack_data,
0xa0 | (((offset+x) >> 7) & 0x0e),
&gpreg, &gpcntl);
} while (ack_data & 0x01);
/* * Read 'len' bytes starting at 'offset'.
*/ staticint sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
u_char ack_data; int retv = 1; int x;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB(np, nc_gpreg, old_gpreg);
OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg;
S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
/* now set NVRAM inactive with GPIO0/1 both high */
S24C16_stop(np, &gpreg);
/* activate NVRAM */
S24C16_start(np, &gpreg);
/* write device code and random address MSB */
S24C16_write_byte(np, &ack_data,
0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); if (ack_data & 0x01) goto out;
/* write random address LSB */
S24C16_write_byte(np, &ack_data,
offset & 0xff, &gpreg, &gpcntl); if (ack_data & 0x01) goto out;
/* regenerate START state to set up for reading */
S24C16_start(np, &gpreg);
/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
S24C16_write_byte(np, &ack_data,
0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); if (ack_data & 0x01) goto out;
/* now set up GPIO0 for inputting data */
gpcntl |= 0x01;
OUTB(np, nc_gpcntl, gpcntl);
/* input all requested data - only part of total NVRAM */ for (x = 0; x < len; x++)
S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
/* finally put NVRAM back in inactive mode */
gpcntl &= 0xfe;
OUTB(np, nc_gpcntl, gpcntl);
S24C16_stop(np, &gpreg);
retv = 0;
out: /* return GPIO0/1 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
1/2/4 out */
gpreg = old_gpreg & 0xe9;
OUTB(np, nc_gpreg, gpreg);
gpcntl = (old_gpcntl & 0xe9) | 0x09;
OUTB(np, nc_gpcntl, gpcntl);
/* input all of NVRAM, 64 words */
retv = T93C46_Read_Data(np, (u_short *) nvram, sizeof(*nvram) / sizeof(short), &gpreg);
/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return retv;
}
/* * Try reading Tekram NVRAM. * Return 0 if OK.
*/ staticint sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
{
u_char *data = (u_char *) nvram; int len = sizeof(*nvram);
u_short csum; int x;
switch (np->pdev->device) { case PCI_DEVICE_ID_NCR_53C885: case PCI_DEVICE_ID_NCR_53C895: case PCI_DEVICE_ID_NCR_53C896:
x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
data, len); break; case PCI_DEVICE_ID_NCR_53C875:
x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
data, len); if (!x) break;
fallthrough; default:
x = sym_read_T93C46_nvram(np, nvram); break;
} if (x) return 1;
/* verify checksum */ for (x = 0, csum = 0; x < len - 1; x += 2)
csum += data[x] + (data[x+1] << 8); if (csum != 0x1234) return 1;
return 0;
}
#ifdef CONFIG_PARISC /* * Host firmware (PDC) keeps a table for altering SCSI capabilities. * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD. * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID.
*/ staticint sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
{ struct hardware_path hwpath;
get_pci_node_path(np->pdev, &hwpath); if (!pdc_get_initiator(&hwpath, pdc)) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.