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 
291da177e4SLinus Torvalds /*
301da177e4SLinus Torvalds  *  Macros used for all firmwares.
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds #define	SYM_GEN_A(s, label)	((short) offsetof(s, label)),
331da177e4SLinus Torvalds #define	SYM_GEN_B(s, label)	((short) offsetof(s, label)),
341da177e4SLinus Torvalds #define	SYM_GEN_Z(s, label)	((short) offsetof(s, label)),
351da177e4SLinus Torvalds #define	PADDR_A(label)		SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
361da177e4SLinus Torvalds #define	PADDR_B(label)		SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #if	SYM_CONF_GENERIC_SUPPORT
401da177e4SLinus Torvalds /*
411da177e4SLinus Torvalds  *  Allocate firmware #1 script area.
421da177e4SLinus Torvalds  */
431da177e4SLinus Torvalds #define	SYM_FWA_SCR		sym_fw1a_scr
441da177e4SLinus Torvalds #define	SYM_FWB_SCR		sym_fw1b_scr
451da177e4SLinus Torvalds #define	SYM_FWZ_SCR		sym_fw1z_scr
461da177e4SLinus Torvalds #include "sym_fw1.h"
471da177e4SLinus Torvalds static struct sym_fwa_ofs sym_fw1a_ofs = {
481da177e4SLinus Torvalds 	SYM_GEN_FW_A(struct SYM_FWA_SCR)
491da177e4SLinus Torvalds };
501da177e4SLinus Torvalds static struct sym_fwb_ofs sym_fw1b_ofs = {
511da177e4SLinus Torvalds 	SYM_GEN_FW_B(struct SYM_FWB_SCR)
521da177e4SLinus Torvalds };
531da177e4SLinus Torvalds static struct sym_fwz_ofs sym_fw1z_ofs = {
541da177e4SLinus Torvalds 	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
551da177e4SLinus Torvalds };
561da177e4SLinus Torvalds #undef	SYM_FWA_SCR
571da177e4SLinus Torvalds #undef	SYM_FWB_SCR
581da177e4SLinus Torvalds #undef	SYM_FWZ_SCR
591da177e4SLinus Torvalds #endif	/* SYM_CONF_GENERIC_SUPPORT */
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds  *  Allocate firmware #2 script area.
631da177e4SLinus Torvalds  */
641da177e4SLinus Torvalds #define	SYM_FWA_SCR		sym_fw2a_scr
651da177e4SLinus Torvalds #define	SYM_FWB_SCR		sym_fw2b_scr
661da177e4SLinus Torvalds #define	SYM_FWZ_SCR		sym_fw2z_scr
671da177e4SLinus Torvalds #include "sym_fw2.h"
681da177e4SLinus Torvalds static struct sym_fwa_ofs sym_fw2a_ofs = {
691da177e4SLinus Torvalds 	SYM_GEN_FW_A(struct SYM_FWA_SCR)
701da177e4SLinus Torvalds };
711da177e4SLinus Torvalds static struct sym_fwb_ofs sym_fw2b_ofs = {
721da177e4SLinus Torvalds 	SYM_GEN_FW_B(struct SYM_FWB_SCR)
731da177e4SLinus Torvalds 	SYM_GEN_B(struct SYM_FWB_SCR, start64)
741da177e4SLinus Torvalds 	SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
751da177e4SLinus Torvalds };
761da177e4SLinus Torvalds static struct sym_fwz_ofs sym_fw2z_ofs = {
771da177e4SLinus Torvalds 	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
781da177e4SLinus Torvalds };
791da177e4SLinus Torvalds #undef	SYM_FWA_SCR
801da177e4SLinus Torvalds #undef	SYM_FWB_SCR
811da177e4SLinus Torvalds #undef	SYM_FWZ_SCR
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds #undef	SYM_GEN_A
841da177e4SLinus Torvalds #undef	SYM_GEN_B
851da177e4SLinus Torvalds #undef	SYM_GEN_Z
861da177e4SLinus Torvalds #undef	PADDR_A
871da177e4SLinus Torvalds #undef	PADDR_B
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds #if	SYM_CONF_GENERIC_SUPPORT
901da177e4SLinus Torvalds /*
911da177e4SLinus Torvalds  *  Patch routine for firmware #1.
921da177e4SLinus Torvalds  */
931da177e4SLinus Torvalds static void
sym_fw1_patch(struct Scsi_Host * shost)945111eefaSMatthew Wilcox sym_fw1_patch(struct Scsi_Host *shost)
951da177e4SLinus Torvalds {
965111eefaSMatthew Wilcox 	struct sym_hcb *np = sym_get_hcb(shost);
971da177e4SLinus Torvalds 	struct sym_fw1a_scr *scripta0;
981da177e4SLinus Torvalds 	struct sym_fw1b_scr *scriptb0;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
1011da177e4SLinus Torvalds 	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	/*
1041da177e4SLinus Torvalds 	 *  Remove LED support if not needed.
1051da177e4SLinus Torvalds 	 */
1061da177e4SLinus Torvalds 	if (!(np->features & FE_LED0)) {
1071da177e4SLinus Torvalds 		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
1081da177e4SLinus Torvalds 		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
1091da177e4SLinus Torvalds 		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
1101da177e4SLinus Torvalds 	}
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds #ifdef SYM_CONF_IARB_SUPPORT
1131da177e4SLinus Torvalds 	/*
1141da177e4SLinus Torvalds 	 *    If user does not want to use IMMEDIATE ARBITRATION
1151da177e4SLinus Torvalds 	 *    when we are reselected while attempting to arbitrate,
1161da177e4SLinus Torvalds 	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1171da177e4SLinus Torvalds 	 */
1181da177e4SLinus Torvalds 	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1191da177e4SLinus Torvalds 		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1201da177e4SLinus Torvalds #endif
1211da177e4SLinus Torvalds 	/*
1221da177e4SLinus Torvalds 	 *  Patch some data in SCRIPTS.
1231da177e4SLinus Torvalds 	 *  - start and done queue initial bus address.
1241da177e4SLinus Torvalds 	 *  - target bus address table bus address.
1251da177e4SLinus Torvalds 	 */
1261da177e4SLinus Torvalds 	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
1271da177e4SLinus Torvalds 	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
1281da177e4SLinus Torvalds 	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds #endif	/* SYM_CONF_GENERIC_SUPPORT */
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds /*
1331da177e4SLinus Torvalds  *  Patch routine for firmware #2.
1341da177e4SLinus Torvalds  */
1351da177e4SLinus Torvalds static void
sym_fw2_patch(struct Scsi_Host * shost)1365111eefaSMatthew Wilcox sym_fw2_patch(struct Scsi_Host *shost)
1371da177e4SLinus Torvalds {
1385111eefaSMatthew Wilcox 	struct sym_data *sym_data = shost_priv(shost);
1395111eefaSMatthew Wilcox 	struct pci_dev *pdev = sym_data->pdev;
1405111eefaSMatthew Wilcox 	struct sym_hcb *np = sym_data->ncb;
1411da177e4SLinus Torvalds 	struct sym_fw2a_scr *scripta0;
1421da177e4SLinus Torvalds 	struct sym_fw2b_scr *scriptb0;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
1451da177e4SLinus Torvalds 	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	/*
1481da177e4SLinus Torvalds 	 *  Remove LED support if not needed.
1491da177e4SLinus Torvalds 	 */
1501da177e4SLinus Torvalds 	if (!(np->features & FE_LED0)) {
1511da177e4SLinus Torvalds 		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
1521da177e4SLinus Torvalds 		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
1531da177e4SLinus Torvalds 		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
1541da177e4SLinus Torvalds 	}
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds #if   SYM_CONF_DMA_ADDRESSING_MODE == 2
1571da177e4SLinus Torvalds 	/*
1581da177e4SLinus Torvalds 	 *  Remove useless 64 bit DMA specific SCRIPTS,
1591da177e4SLinus Torvalds 	 *  when this feature is not available.
1601da177e4SLinus Torvalds 	 */
1614d85b471SMatthew Wilcox 	if (!use_dac(np)) {
1621da177e4SLinus Torvalds 		scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
1631da177e4SLinus Torvalds 		scripta0->is_dmap_dirty[1] = 0;
1641da177e4SLinus Torvalds 		scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
1651da177e4SLinus Torvalds 		scripta0->is_dmap_dirty[3] = 0;
1661da177e4SLinus Torvalds 	}
1671da177e4SLinus Torvalds #endif
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds #ifdef SYM_CONF_IARB_SUPPORT
1701da177e4SLinus Torvalds 	/*
1711da177e4SLinus Torvalds 	 *    If user does not want to use IMMEDIATE ARBITRATION
1721da177e4SLinus Torvalds 	 *    when we are reselected while attempting to arbitrate,
1731da177e4SLinus Torvalds 	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1741da177e4SLinus Torvalds 	 */
1751da177e4SLinus Torvalds 	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1761da177e4SLinus Torvalds 		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1771da177e4SLinus Torvalds #endif
1781da177e4SLinus Torvalds 	/*
1791da177e4SLinus Torvalds 	 *  Patch some variable in SCRIPTS.
1801da177e4SLinus Torvalds 	 *  - start and done queue initial bus address.
1811da177e4SLinus Torvalds 	 *  - target bus address table bus address.
1821da177e4SLinus Torvalds 	 */
1831da177e4SLinus Torvalds 	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
1841da177e4SLinus Torvalds 	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
1851da177e4SLinus Torvalds 	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	/*
1881da177e4SLinus Torvalds 	 *  Remove the load of SCNTL4 on reselection if not a C10.
1891da177e4SLinus Torvalds 	 */
1901da177e4SLinus Torvalds 	if (!(np->features & FE_C10)) {
1911da177e4SLinus Torvalds 		scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
1921da177e4SLinus Torvalds 		scripta0->resel_scntl4[1] = cpu_to_scr(0);
1931da177e4SLinus Torvalds 	}
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	/*
1961da177e4SLinus Torvalds 	 *  Remove a couple of work-arounds specific to C1010 if
1971da177e4SLinus Torvalds 	 *  they are not desirable. See `sym_fw2.h' for more details.
1981da177e4SLinus Torvalds 	 */
1995111eefaSMatthew Wilcox 	if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
2005111eefaSMatthew Wilcox 	      pdev->revision < 0x1 &&
2011da177e4SLinus Torvalds 	      np->pciclk_khz < 60000)) {
2021da177e4SLinus Torvalds 		scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
2031da177e4SLinus Torvalds 		scripta0->datao_phase[1] = cpu_to_scr(0);
2041da177e4SLinus Torvalds 	}
2055111eefaSMatthew Wilcox 	if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
2065111eefaSMatthew Wilcox 	      pdev->revision < 0xff */)) {
2071da177e4SLinus Torvalds 		scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
2081da177e4SLinus Torvalds 		scripta0->sel_done[1] = cpu_to_scr(0);
2091da177e4SLinus Torvalds 	}
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	/*
2121da177e4SLinus Torvalds 	 *  Patch some other variables in SCRIPTS.
2131da177e4SLinus Torvalds 	 *  These ones are loaded by the SCRIPTS processor.
2141da177e4SLinus Torvalds 	 */
2151da177e4SLinus Torvalds 	scriptb0->pm0_data_addr[0] =
2161da177e4SLinus Torvalds 		cpu_to_scr(np->scripta_ba +
2171da177e4SLinus Torvalds 			   offsetof(struct sym_fw2a_scr, pm0_data));
2181da177e4SLinus Torvalds 	scriptb0->pm1_data_addr[0] =
2191da177e4SLinus Torvalds 		cpu_to_scr(np->scripta_ba +
2201da177e4SLinus Torvalds 			   offsetof(struct sym_fw2a_scr, pm1_data));
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds /*
2241da177e4SLinus Torvalds  *  Fill the data area in scripts.
2251da177e4SLinus Torvalds  *  To be done for all firmwares.
2261da177e4SLinus Torvalds  */
2271da177e4SLinus Torvalds static void
sym_fw_fill_data(u32 * in,u32 * out)2281da177e4SLinus Torvalds sym_fw_fill_data (u32 *in, u32 *out)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	int	i;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	for (i = 0; i < SYM_CONF_MAX_SG; i++) {
2331da177e4SLinus Torvalds 		*in++  = SCR_CHMOV_TBL ^ SCR_DATA_IN;
2341da177e4SLinus Torvalds 		*in++  = offsetof (struct sym_dsb, data[i]);
2351da177e4SLinus Torvalds 		*out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
2361da177e4SLinus Torvalds 		*out++ = offsetof (struct sym_dsb, data[i]);
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds /*
2411da177e4SLinus Torvalds  *  Setup useful script bus addresses.
2421da177e4SLinus Torvalds  *  To be done for all firmwares.
2431da177e4SLinus Torvalds  */
2441da177e4SLinus Torvalds static void
sym_fw_setup_bus_addresses(struct sym_hcb * np,struct sym_fw * fw)2451da177e4SLinus Torvalds sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds 	u32 *pa;
2481da177e4SLinus Torvalds 	u_short *po;
2491da177e4SLinus Torvalds 	int i;
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	/*
2521da177e4SLinus Torvalds 	 *  Build the bus address table for script A
2531da177e4SLinus Torvalds 	 *  from the script A offset table.
2541da177e4SLinus Torvalds 	 */
2551da177e4SLinus Torvalds 	po = (u_short *) fw->a_ofs;
2561da177e4SLinus Torvalds 	pa = (u32 *) &np->fwa_bas;
2571da177e4SLinus Torvalds 	for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
2581da177e4SLinus Torvalds 		pa[i] = np->scripta_ba + po[i];
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	/*
2611da177e4SLinus Torvalds 	 *  Same for script B.
2621da177e4SLinus Torvalds 	 */
2631da177e4SLinus Torvalds 	po = (u_short *) fw->b_ofs;
2641da177e4SLinus Torvalds 	pa = (u32 *) &np->fwb_bas;
2651da177e4SLinus Torvalds 	for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
2661da177e4SLinus Torvalds 		pa[i] = np->scriptb_ba + po[i];
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	/*
2691da177e4SLinus Torvalds 	 *  Same for script Z.
2701da177e4SLinus Torvalds 	 */
2711da177e4SLinus Torvalds 	po = (u_short *) fw->z_ofs;
2721da177e4SLinus Torvalds 	pa = (u32 *) &np->fwz_bas;
2731da177e4SLinus Torvalds 	for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
2741da177e4SLinus Torvalds 		pa[i] = np->scriptz_ba + po[i];
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds #if	SYM_CONF_GENERIC_SUPPORT
2781da177e4SLinus Torvalds /*
2791da177e4SLinus Torvalds  *  Setup routine for firmware #1.
2801da177e4SLinus Torvalds  */
2811da177e4SLinus Torvalds static void
sym_fw1_setup(struct sym_hcb * np,struct sym_fw * fw)2821da177e4SLinus Torvalds sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
2831da177e4SLinus Torvalds {
2841da177e4SLinus Torvalds 	struct sym_fw1a_scr *scripta0;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	/*
2891da177e4SLinus Torvalds 	 *  Fill variable parts in scripts.
2901da177e4SLinus Torvalds 	 */
2911da177e4SLinus Torvalds 	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	/*
2941da177e4SLinus Torvalds 	 *  Setup bus addresses used from the C code..
2951da177e4SLinus Torvalds 	 */
2961da177e4SLinus Torvalds 	sym_fw_setup_bus_addresses(np, fw);
2971da177e4SLinus Torvalds }
2981da177e4SLinus Torvalds #endif	/* SYM_CONF_GENERIC_SUPPORT */
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds /*
3011da177e4SLinus Torvalds  *  Setup routine for firmware #2.
3021da177e4SLinus Torvalds  */
3031da177e4SLinus Torvalds static void
sym_fw2_setup(struct sym_hcb * np,struct sym_fw * fw)3041da177e4SLinus Torvalds sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
3051da177e4SLinus Torvalds {
3061da177e4SLinus Torvalds 	struct sym_fw2a_scr *scripta0;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	/*
3111da177e4SLinus Torvalds 	 *  Fill variable parts in scripts.
3121da177e4SLinus Torvalds 	 */
3131da177e4SLinus Torvalds 	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	/*
3161da177e4SLinus Torvalds 	 *  Setup bus addresses used from the C code..
3171da177e4SLinus Torvalds 	 */
3181da177e4SLinus Torvalds 	sym_fw_setup_bus_addresses(np, fw);
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds /*
3221da177e4SLinus Torvalds  *  Allocate firmware descriptors.
3231da177e4SLinus Torvalds  */
3241da177e4SLinus Torvalds #if	SYM_CONF_GENERIC_SUPPORT
3251da177e4SLinus Torvalds static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
3261da177e4SLinus Torvalds #endif	/* SYM_CONF_GENERIC_SUPPORT */
3271da177e4SLinus Torvalds static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds /*
3301da177e4SLinus Torvalds  *  Find the most appropriate firmware for a chip.
3311da177e4SLinus Torvalds  */
3321da177e4SLinus Torvalds struct sym_fw *
sym_find_firmware(struct sym_chip * chip)3331da177e4SLinus Torvalds sym_find_firmware(struct sym_chip *chip)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds 	if (chip->features & FE_LDSTR)
3361da177e4SLinus Torvalds 		return &sym_fw2;
3371da177e4SLinus Torvalds #if	SYM_CONF_GENERIC_SUPPORT
3381da177e4SLinus Torvalds 	else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
3391da177e4SLinus Torvalds 		return &sym_fw1;
3401da177e4SLinus Torvalds #endif
3411da177e4SLinus Torvalds 	else
3421da177e4SLinus Torvalds 		return NULL;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds /*
3461da177e4SLinus Torvalds  *  Bind a script to physical addresses.
3471da177e4SLinus Torvalds  */
sym_fw_bind_script(struct sym_hcb * np,u32 * start,int len)3481da177e4SLinus Torvalds void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	u32 opcode, new, old, tmp1, tmp2;
3511da177e4SLinus Torvalds 	u32 *end, *cur;
3521da177e4SLinus Torvalds 	int relocs;
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	cur = start;
3551da177e4SLinus Torvalds 	end = start + len/4;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	while (cur < end) {
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 		opcode = *cur;
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 		/*
3621da177e4SLinus Torvalds 		 *  If we forget to change the length
3631da177e4SLinus Torvalds 		 *  in scripts, a field will be
3641da177e4SLinus Torvalds 		 *  padded with 0. This is an illegal
3651da177e4SLinus Torvalds 		 *  command.
3661da177e4SLinus Torvalds 		 */
3671da177e4SLinus Torvalds 		if (opcode == 0) {
3681da177e4SLinus Torvalds 			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
3691da177e4SLinus Torvalds 				sym_name(np), (int) (cur-start));
3701da177e4SLinus Torvalds 			++cur;
3711da177e4SLinus Torvalds 			continue;
3728d4089cdSJason Yan 		}
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 		/*
3751da177e4SLinus Torvalds 		 *  We use the bogus value 0xf00ff00f ;-)
3761da177e4SLinus Torvalds 		 *  to reserve data area in SCRIPTS.
3771da177e4SLinus Torvalds 		 */
3781da177e4SLinus Torvalds 		if (opcode == SCR_DATA_ZERO) {
3791da177e4SLinus Torvalds 			*cur++ = 0;
3801da177e4SLinus Torvalds 			continue;
3811da177e4SLinus Torvalds 		}
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 		if (DEBUG_FLAGS & DEBUG_SCRIPT)
3841da177e4SLinus Torvalds 			printf ("%d:  <%x>\n", (int) (cur-start),
3851da177e4SLinus Torvalds 				(unsigned)opcode);
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 		/*
3881da177e4SLinus Torvalds 		 *  We don't have to decode ALL commands
3891da177e4SLinus Torvalds 		 */
3901da177e4SLinus Torvalds 		switch (opcode >> 28) {
3911da177e4SLinus Torvalds 		case 0xf:
3921da177e4SLinus Torvalds 			/*
3931da177e4SLinus Torvalds 			 *  LOAD / STORE DSA relative, don't relocate.
3941da177e4SLinus Torvalds 			 */
3951da177e4SLinus Torvalds 			relocs = 0;
3961da177e4SLinus Torvalds 			break;
3971da177e4SLinus Torvalds 		case 0xe:
3981da177e4SLinus Torvalds 			/*
3991da177e4SLinus Torvalds 			 *  LOAD / STORE absolute.
4001da177e4SLinus Torvalds 			 */
4011da177e4SLinus Torvalds 			relocs = 1;
4021da177e4SLinus Torvalds 			break;
4031da177e4SLinus Torvalds 		case 0xc:
4041da177e4SLinus Torvalds 			/*
4051da177e4SLinus Torvalds 			 *  COPY has TWO arguments.
4061da177e4SLinus Torvalds 			 */
4071da177e4SLinus Torvalds 			relocs = 2;
4081da177e4SLinus Torvalds 			tmp1 = cur[1];
4091da177e4SLinus Torvalds 			tmp2 = cur[2];
4101da177e4SLinus Torvalds 			if ((tmp1 ^ tmp2) & 3) {
4111da177e4SLinus Torvalds 				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
4121da177e4SLinus Torvalds 					sym_name(np), (int) (cur-start));
4131da177e4SLinus Torvalds 			}
4141da177e4SLinus Torvalds 			/*
4151da177e4SLinus Torvalds 			 *  If PREFETCH feature not enabled, remove
4161da177e4SLinus Torvalds 			 *  the NO FLUSH bit if present.
4171da177e4SLinus Torvalds 			 */
4181da177e4SLinus Torvalds 			if ((opcode & SCR_NO_FLUSH) &&
4191da177e4SLinus Torvalds 			    !(np->features & FE_PFEN)) {
4201da177e4SLinus Torvalds 				opcode = (opcode & ~SCR_NO_FLUSH);
4211da177e4SLinus Torvalds 			}
4221da177e4SLinus Torvalds 			break;
4231da177e4SLinus Torvalds 		case 0x0:
4241da177e4SLinus Torvalds 			/*
4251da177e4SLinus Torvalds 			 *  MOVE/CHMOV (absolute address)
4261da177e4SLinus Torvalds 			 */
4271da177e4SLinus Torvalds 			if (!(np->features & FE_WIDE))
4281da177e4SLinus Torvalds 				opcode = (opcode | OPC_MOVE);
4291da177e4SLinus Torvalds 			relocs = 1;
4301da177e4SLinus Torvalds 			break;
4311da177e4SLinus Torvalds 		case 0x1:
4321da177e4SLinus Torvalds 			/*
4331da177e4SLinus Torvalds 			 *  MOVE/CHMOV (table indirect)
4341da177e4SLinus Torvalds 			 */
4351da177e4SLinus Torvalds 			if (!(np->features & FE_WIDE))
4361da177e4SLinus Torvalds 				opcode = (opcode | OPC_MOVE);
4371da177e4SLinus Torvalds 			relocs = 0;
4381da177e4SLinus Torvalds 			break;
4391da177e4SLinus Torvalds #ifdef SYM_CONF_TARGET_ROLE_SUPPORT
4401da177e4SLinus Torvalds 		case 0x2:
4411da177e4SLinus Torvalds 			/*
4421da177e4SLinus Torvalds 			 *  MOVE/CHMOV in target role (absolute address)
4431da177e4SLinus Torvalds 			 */
4441da177e4SLinus Torvalds 			opcode &= ~0x20000000;
4451da177e4SLinus Torvalds 			if (!(np->features & FE_WIDE))
4461da177e4SLinus Torvalds 				opcode = (opcode & ~OPC_TCHMOVE);
4471da177e4SLinus Torvalds 			relocs = 1;
4481da177e4SLinus Torvalds 			break;
4491da177e4SLinus Torvalds 		case 0x3:
4501da177e4SLinus Torvalds 			/*
4511da177e4SLinus Torvalds 			 *  MOVE/CHMOV in target role (table indirect)
4521da177e4SLinus Torvalds 			 */
4531da177e4SLinus Torvalds 			opcode &= ~0x20000000;
4541da177e4SLinus Torvalds 			if (!(np->features & FE_WIDE))
4551da177e4SLinus Torvalds 				opcode = (opcode & ~OPC_TCHMOVE);
4561da177e4SLinus Torvalds 			relocs = 0;
4571da177e4SLinus Torvalds 			break;
4581da177e4SLinus Torvalds #endif
4591da177e4SLinus Torvalds 		case 0x8:
4601da177e4SLinus Torvalds 			/*
4611da177e4SLinus Torvalds 			 *  JUMP / CALL
4621da177e4SLinus Torvalds 			 *  don't relocate if relative :-)
4631da177e4SLinus Torvalds 			 */
4641da177e4SLinus Torvalds 			if (opcode & 0x00800000)
4651da177e4SLinus Torvalds 				relocs = 0;
4661da177e4SLinus Torvalds 			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
4671da177e4SLinus Torvalds 				relocs = 2;
4681da177e4SLinus Torvalds 			else
4691da177e4SLinus Torvalds 				relocs = 1;
4701da177e4SLinus Torvalds 			break;
4711da177e4SLinus Torvalds 		case 0x4:
4721da177e4SLinus Torvalds 		case 0x5:
4731da177e4SLinus Torvalds 		case 0x6:
4741da177e4SLinus Torvalds 		case 0x7:
4751da177e4SLinus Torvalds 			relocs = 1;
4761da177e4SLinus Torvalds 			break;
4771da177e4SLinus Torvalds 		default:
4781da177e4SLinus Torvalds 			relocs = 0;
4791da177e4SLinus Torvalds 			break;
4808d4089cdSJason Yan 		}
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 		/*
4831da177e4SLinus Torvalds 		 *  Scriptify:) the opcode.
4841da177e4SLinus Torvalds 		 */
4851da177e4SLinus Torvalds 		*cur++ = cpu_to_scr(opcode);
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 		/*
4881da177e4SLinus Torvalds 		 *  If no relocation, assume 1 argument
4891da177e4SLinus Torvalds 		 *  and just scriptize:) it.
4901da177e4SLinus Torvalds 		 */
4911da177e4SLinus Torvalds 		if (!relocs) {
4921da177e4SLinus Torvalds 			*cur = cpu_to_scr(*cur);
4931da177e4SLinus Torvalds 			++cur;
4941da177e4SLinus Torvalds 			continue;
4951da177e4SLinus Torvalds 		}
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 		/*
4981da177e4SLinus Torvalds 		 *  Otherwise performs all needed relocations.
4991da177e4SLinus Torvalds 		 */
5001da177e4SLinus Torvalds 		while (relocs--) {
5011da177e4SLinus Torvalds 			old = *cur;
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 			switch (old & RELOC_MASK) {
5041da177e4SLinus Torvalds 			case RELOC_REGISTER:
5051da177e4SLinus Torvalds 				new = (old & ~RELOC_MASK) + np->mmio_ba;
5061da177e4SLinus Torvalds 				break;
5071da177e4SLinus Torvalds 			case RELOC_LABEL_A:
5081da177e4SLinus Torvalds 				new = (old & ~RELOC_MASK) + np->scripta_ba;
5091da177e4SLinus Torvalds 				break;
5101da177e4SLinus Torvalds 			case RELOC_LABEL_B:
5111da177e4SLinus Torvalds 				new = (old & ~RELOC_MASK) + np->scriptb_ba;
5121da177e4SLinus Torvalds 				break;
5131da177e4SLinus Torvalds 			case RELOC_SOFTC:
5141da177e4SLinus Torvalds 				new = (old & ~RELOC_MASK) + np->hcb_ba;
5151da177e4SLinus Torvalds 				break;
5161da177e4SLinus Torvalds 			case 0:
5171da177e4SLinus Torvalds 				/*
5181da177e4SLinus Torvalds 				 *  Don't relocate a 0 address.
5191da177e4SLinus Torvalds 				 *  They are mostly used for patched or
5201da177e4SLinus Torvalds 				 *  script self-modified areas.
5211da177e4SLinus Torvalds 				 */
5221da177e4SLinus Torvalds 				if (old == 0) {
5231da177e4SLinus Torvalds 					new = old;
5241da177e4SLinus Torvalds 					break;
5251da177e4SLinus Torvalds 				}
5261da177e4SLinus Torvalds 				fallthrough;
5271da177e4SLinus Torvalds 			default:
5281da177e4SLinus Torvalds 				new = 0;
5291da177e4SLinus Torvalds 				panic("sym_fw_bind_script: "
5301da177e4SLinus Torvalds 				      "weird relocation %x\n", old);
5311da177e4SLinus Torvalds 				break;
5321da177e4SLinus Torvalds 			}
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 			*cur++ = cpu_to_scr(new);
5351da177e4SLinus Torvalds 		}
5368d4089cdSJason Yan 	}
5371da177e4SLinus Torvalds }
538