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
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci *  Macros used for all firmwares.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci#define	SYM_GEN_A(s, label)	((short) offsetof(s, label)),
338c2ecf20Sopenharmony_ci#define	SYM_GEN_B(s, label)	((short) offsetof(s, label)),
348c2ecf20Sopenharmony_ci#define	SYM_GEN_Z(s, label)	((short) offsetof(s, label)),
358c2ecf20Sopenharmony_ci#define	PADDR_A(label)		SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
368c2ecf20Sopenharmony_ci#define	PADDR_B(label)		SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#if	SYM_CONF_GENERIC_SUPPORT
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci *  Allocate firmware #1 script area.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci#define	SYM_FWA_SCR		sym_fw1a_scr
448c2ecf20Sopenharmony_ci#define	SYM_FWB_SCR		sym_fw1b_scr
458c2ecf20Sopenharmony_ci#define	SYM_FWZ_SCR		sym_fw1z_scr
468c2ecf20Sopenharmony_ci#include "sym_fw1.h"
478c2ecf20Sopenharmony_cistatic struct sym_fwa_ofs sym_fw1a_ofs = {
488c2ecf20Sopenharmony_ci	SYM_GEN_FW_A(struct SYM_FWA_SCR)
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_cistatic struct sym_fwb_ofs sym_fw1b_ofs = {
518c2ecf20Sopenharmony_ci	SYM_GEN_FW_B(struct SYM_FWB_SCR)
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_cistatic struct sym_fwz_ofs sym_fw1z_ofs = {
548c2ecf20Sopenharmony_ci	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci#undef	SYM_FWA_SCR
578c2ecf20Sopenharmony_ci#undef	SYM_FWB_SCR
588c2ecf20Sopenharmony_ci#undef	SYM_FWZ_SCR
598c2ecf20Sopenharmony_ci#endif	/* SYM_CONF_GENERIC_SUPPORT */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci *  Allocate firmware #2 script area.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_ci#define	SYM_FWA_SCR		sym_fw2a_scr
658c2ecf20Sopenharmony_ci#define	SYM_FWB_SCR		sym_fw2b_scr
668c2ecf20Sopenharmony_ci#define	SYM_FWZ_SCR		sym_fw2z_scr
678c2ecf20Sopenharmony_ci#include "sym_fw2.h"
688c2ecf20Sopenharmony_cistatic struct sym_fwa_ofs sym_fw2a_ofs = {
698c2ecf20Sopenharmony_ci	SYM_GEN_FW_A(struct SYM_FWA_SCR)
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_cistatic struct sym_fwb_ofs sym_fw2b_ofs = {
728c2ecf20Sopenharmony_ci	SYM_GEN_FW_B(struct SYM_FWB_SCR)
738c2ecf20Sopenharmony_ci	SYM_GEN_B(struct SYM_FWB_SCR, start64)
748c2ecf20Sopenharmony_ci	SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_cistatic struct sym_fwz_ofs sym_fw2z_ofs = {
778c2ecf20Sopenharmony_ci	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci#undef	SYM_FWA_SCR
808c2ecf20Sopenharmony_ci#undef	SYM_FWB_SCR
818c2ecf20Sopenharmony_ci#undef	SYM_FWZ_SCR
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#undef	SYM_GEN_A
848c2ecf20Sopenharmony_ci#undef	SYM_GEN_B
858c2ecf20Sopenharmony_ci#undef	SYM_GEN_Z
868c2ecf20Sopenharmony_ci#undef	PADDR_A
878c2ecf20Sopenharmony_ci#undef	PADDR_B
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#if	SYM_CONF_GENERIC_SUPPORT
908c2ecf20Sopenharmony_ci/*
918c2ecf20Sopenharmony_ci *  Patch routine for firmware #1.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_cistatic void
948c2ecf20Sopenharmony_cisym_fw1_patch(struct Scsi_Host *shost)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct sym_hcb *np = sym_get_hcb(shost);
978c2ecf20Sopenharmony_ci	struct sym_fw1a_scr *scripta0;
988c2ecf20Sopenharmony_ci	struct sym_fw1b_scr *scriptb0;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
1018c2ecf20Sopenharmony_ci	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/*
1048c2ecf20Sopenharmony_ci	 *  Remove LED support if not needed.
1058c2ecf20Sopenharmony_ci	 */
1068c2ecf20Sopenharmony_ci	if (!(np->features & FE_LED0)) {
1078c2ecf20Sopenharmony_ci		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
1088c2ecf20Sopenharmony_ci		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
1098c2ecf20Sopenharmony_ci		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#ifdef SYM_CONF_IARB_SUPPORT
1138c2ecf20Sopenharmony_ci	/*
1148c2ecf20Sopenharmony_ci	 *    If user does not want to use IMMEDIATE ARBITRATION
1158c2ecf20Sopenharmony_ci	 *    when we are reselected while attempting to arbitrate,
1168c2ecf20Sopenharmony_ci	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1178c2ecf20Sopenharmony_ci	 */
1188c2ecf20Sopenharmony_ci	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1198c2ecf20Sopenharmony_ci		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1208c2ecf20Sopenharmony_ci#endif
1218c2ecf20Sopenharmony_ci	/*
1228c2ecf20Sopenharmony_ci	 *  Patch some data in SCRIPTS.
1238c2ecf20Sopenharmony_ci	 *  - start and done queue initial bus address.
1248c2ecf20Sopenharmony_ci	 *  - target bus address table bus address.
1258c2ecf20Sopenharmony_ci	 */
1268c2ecf20Sopenharmony_ci	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
1278c2ecf20Sopenharmony_ci	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
1288c2ecf20Sopenharmony_ci	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci#endif	/* SYM_CONF_GENERIC_SUPPORT */
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/*
1338c2ecf20Sopenharmony_ci *  Patch routine for firmware #2.
1348c2ecf20Sopenharmony_ci */
1358c2ecf20Sopenharmony_cistatic void
1368c2ecf20Sopenharmony_cisym_fw2_patch(struct Scsi_Host *shost)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct sym_data *sym_data = shost_priv(shost);
1398c2ecf20Sopenharmony_ci	struct pci_dev *pdev = sym_data->pdev;
1408c2ecf20Sopenharmony_ci	struct sym_hcb *np = sym_data->ncb;
1418c2ecf20Sopenharmony_ci	struct sym_fw2a_scr *scripta0;
1428c2ecf20Sopenharmony_ci	struct sym_fw2b_scr *scriptb0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
1458c2ecf20Sopenharmony_ci	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/*
1488c2ecf20Sopenharmony_ci	 *  Remove LED support if not needed.
1498c2ecf20Sopenharmony_ci	 */
1508c2ecf20Sopenharmony_ci	if (!(np->features & FE_LED0)) {
1518c2ecf20Sopenharmony_ci		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
1528c2ecf20Sopenharmony_ci		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
1538c2ecf20Sopenharmony_ci		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#if   SYM_CONF_DMA_ADDRESSING_MODE == 2
1578c2ecf20Sopenharmony_ci	/*
1588c2ecf20Sopenharmony_ci	 *  Remove useless 64 bit DMA specific SCRIPTS,
1598c2ecf20Sopenharmony_ci	 *  when this feature is not available.
1608c2ecf20Sopenharmony_ci	 */
1618c2ecf20Sopenharmony_ci	if (!use_dac(np)) {
1628c2ecf20Sopenharmony_ci		scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
1638c2ecf20Sopenharmony_ci		scripta0->is_dmap_dirty[1] = 0;
1648c2ecf20Sopenharmony_ci		scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
1658c2ecf20Sopenharmony_ci		scripta0->is_dmap_dirty[3] = 0;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci#endif
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci#ifdef SYM_CONF_IARB_SUPPORT
1708c2ecf20Sopenharmony_ci	/*
1718c2ecf20Sopenharmony_ci	 *    If user does not want to use IMMEDIATE ARBITRATION
1728c2ecf20Sopenharmony_ci	 *    when we are reselected while attempting to arbitrate,
1738c2ecf20Sopenharmony_ci	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1748c2ecf20Sopenharmony_ci	 */
1758c2ecf20Sopenharmony_ci	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1768c2ecf20Sopenharmony_ci		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1778c2ecf20Sopenharmony_ci#endif
1788c2ecf20Sopenharmony_ci	/*
1798c2ecf20Sopenharmony_ci	 *  Patch some variable in SCRIPTS.
1808c2ecf20Sopenharmony_ci	 *  - start and done queue initial bus address.
1818c2ecf20Sopenharmony_ci	 *  - target bus address table bus address.
1828c2ecf20Sopenharmony_ci	 */
1838c2ecf20Sopenharmony_ci	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
1848c2ecf20Sopenharmony_ci	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
1858c2ecf20Sopenharmony_ci	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/*
1888c2ecf20Sopenharmony_ci	 *  Remove the load of SCNTL4 on reselection if not a C10.
1898c2ecf20Sopenharmony_ci	 */
1908c2ecf20Sopenharmony_ci	if (!(np->features & FE_C10)) {
1918c2ecf20Sopenharmony_ci		scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
1928c2ecf20Sopenharmony_ci		scripta0->resel_scntl4[1] = cpu_to_scr(0);
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/*
1968c2ecf20Sopenharmony_ci	 *  Remove a couple of work-arounds specific to C1010 if
1978c2ecf20Sopenharmony_ci	 *  they are not desirable. See `sym_fw2.h' for more details.
1988c2ecf20Sopenharmony_ci	 */
1998c2ecf20Sopenharmony_ci	if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
2008c2ecf20Sopenharmony_ci	      pdev->revision < 0x1 &&
2018c2ecf20Sopenharmony_ci	      np->pciclk_khz < 60000)) {
2028c2ecf20Sopenharmony_ci		scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
2038c2ecf20Sopenharmony_ci		scripta0->datao_phase[1] = cpu_to_scr(0);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci	if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
2068c2ecf20Sopenharmony_ci	      pdev->revision < 0xff */)) {
2078c2ecf20Sopenharmony_ci		scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
2088c2ecf20Sopenharmony_ci		scripta0->sel_done[1] = cpu_to_scr(0);
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/*
2128c2ecf20Sopenharmony_ci	 *  Patch some other variables in SCRIPTS.
2138c2ecf20Sopenharmony_ci	 *  These ones are loaded by the SCRIPTS processor.
2148c2ecf20Sopenharmony_ci	 */
2158c2ecf20Sopenharmony_ci	scriptb0->pm0_data_addr[0] =
2168c2ecf20Sopenharmony_ci		cpu_to_scr(np->scripta_ba +
2178c2ecf20Sopenharmony_ci			   offsetof(struct sym_fw2a_scr, pm0_data));
2188c2ecf20Sopenharmony_ci	scriptb0->pm1_data_addr[0] =
2198c2ecf20Sopenharmony_ci		cpu_to_scr(np->scripta_ba +
2208c2ecf20Sopenharmony_ci			   offsetof(struct sym_fw2a_scr, pm1_data));
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/*
2248c2ecf20Sopenharmony_ci *  Fill the data area in scripts.
2258c2ecf20Sopenharmony_ci *  To be done for all firmwares.
2268c2ecf20Sopenharmony_ci */
2278c2ecf20Sopenharmony_cistatic void
2288c2ecf20Sopenharmony_cisym_fw_fill_data (u32 *in, u32 *out)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	int	i;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	for (i = 0; i < SYM_CONF_MAX_SG; i++) {
2338c2ecf20Sopenharmony_ci		*in++  = SCR_CHMOV_TBL ^ SCR_DATA_IN;
2348c2ecf20Sopenharmony_ci		*in++  = offsetof (struct sym_dsb, data[i]);
2358c2ecf20Sopenharmony_ci		*out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
2368c2ecf20Sopenharmony_ci		*out++ = offsetof (struct sym_dsb, data[i]);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/*
2418c2ecf20Sopenharmony_ci *  Setup useful script bus addresses.
2428c2ecf20Sopenharmony_ci *  To be done for all firmwares.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_cistatic void
2458c2ecf20Sopenharmony_cisym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	u32 *pa;
2488c2ecf20Sopenharmony_ci	u_short *po;
2498c2ecf20Sopenharmony_ci	int i;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/*
2528c2ecf20Sopenharmony_ci	 *  Build the bus address table for script A
2538c2ecf20Sopenharmony_ci	 *  from the script A offset table.
2548c2ecf20Sopenharmony_ci	 */
2558c2ecf20Sopenharmony_ci	po = (u_short *) fw->a_ofs;
2568c2ecf20Sopenharmony_ci	pa = (u32 *) &np->fwa_bas;
2578c2ecf20Sopenharmony_ci	for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
2588c2ecf20Sopenharmony_ci		pa[i] = np->scripta_ba + po[i];
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/*
2618c2ecf20Sopenharmony_ci	 *  Same for script B.
2628c2ecf20Sopenharmony_ci	 */
2638c2ecf20Sopenharmony_ci	po = (u_short *) fw->b_ofs;
2648c2ecf20Sopenharmony_ci	pa = (u32 *) &np->fwb_bas;
2658c2ecf20Sopenharmony_ci	for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
2668c2ecf20Sopenharmony_ci		pa[i] = np->scriptb_ba + po[i];
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/*
2698c2ecf20Sopenharmony_ci	 *  Same for script Z.
2708c2ecf20Sopenharmony_ci	 */
2718c2ecf20Sopenharmony_ci	po = (u_short *) fw->z_ofs;
2728c2ecf20Sopenharmony_ci	pa = (u32 *) &np->fwz_bas;
2738c2ecf20Sopenharmony_ci	for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
2748c2ecf20Sopenharmony_ci		pa[i] = np->scriptz_ba + po[i];
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci#if	SYM_CONF_GENERIC_SUPPORT
2788c2ecf20Sopenharmony_ci/*
2798c2ecf20Sopenharmony_ci *  Setup routine for firmware #1.
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic void
2828c2ecf20Sopenharmony_cisym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct sym_fw1a_scr *scripta0;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/*
2898c2ecf20Sopenharmony_ci	 *  Fill variable parts in scripts.
2908c2ecf20Sopenharmony_ci	 */
2918c2ecf20Sopenharmony_ci	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/*
2948c2ecf20Sopenharmony_ci	 *  Setup bus addresses used from the C code..
2958c2ecf20Sopenharmony_ci	 */
2968c2ecf20Sopenharmony_ci	sym_fw_setup_bus_addresses(np, fw);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci#endif	/* SYM_CONF_GENERIC_SUPPORT */
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci/*
3018c2ecf20Sopenharmony_ci *  Setup routine for firmware #2.
3028c2ecf20Sopenharmony_ci */
3038c2ecf20Sopenharmony_cistatic void
3048c2ecf20Sopenharmony_cisym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct sym_fw2a_scr *scripta0;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 *  Fill variable parts in scripts.
3128c2ecf20Sopenharmony_ci	 */
3138c2ecf20Sopenharmony_ci	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/*
3168c2ecf20Sopenharmony_ci	 *  Setup bus addresses used from the C code..
3178c2ecf20Sopenharmony_ci	 */
3188c2ecf20Sopenharmony_ci	sym_fw_setup_bus_addresses(np, fw);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/*
3228c2ecf20Sopenharmony_ci *  Allocate firmware descriptors.
3238c2ecf20Sopenharmony_ci */
3248c2ecf20Sopenharmony_ci#if	SYM_CONF_GENERIC_SUPPORT
3258c2ecf20Sopenharmony_cistatic struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
3268c2ecf20Sopenharmony_ci#endif	/* SYM_CONF_GENERIC_SUPPORT */
3278c2ecf20Sopenharmony_cistatic struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci/*
3308c2ecf20Sopenharmony_ci *  Find the most appropriate firmware for a chip.
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_cistruct sym_fw *
3338c2ecf20Sopenharmony_cisym_find_firmware(struct sym_chip *chip)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	if (chip->features & FE_LDSTR)
3368c2ecf20Sopenharmony_ci		return &sym_fw2;
3378c2ecf20Sopenharmony_ci#if	SYM_CONF_GENERIC_SUPPORT
3388c2ecf20Sopenharmony_ci	else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
3398c2ecf20Sopenharmony_ci		return &sym_fw1;
3408c2ecf20Sopenharmony_ci#endif
3418c2ecf20Sopenharmony_ci	else
3428c2ecf20Sopenharmony_ci		return NULL;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci/*
3468c2ecf20Sopenharmony_ci *  Bind a script to physical addresses.
3478c2ecf20Sopenharmony_ci */
3488c2ecf20Sopenharmony_civoid sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	u32 opcode, new, old, tmp1, tmp2;
3518c2ecf20Sopenharmony_ci	u32 *end, *cur;
3528c2ecf20Sopenharmony_ci	int relocs;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	cur = start;
3558c2ecf20Sopenharmony_ci	end = start + len/4;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	while (cur < end) {
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		opcode = *cur;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		/*
3628c2ecf20Sopenharmony_ci		 *  If we forget to change the length
3638c2ecf20Sopenharmony_ci		 *  in scripts, a field will be
3648c2ecf20Sopenharmony_ci		 *  padded with 0. This is an illegal
3658c2ecf20Sopenharmony_ci		 *  command.
3668c2ecf20Sopenharmony_ci		 */
3678c2ecf20Sopenharmony_ci		if (opcode == 0) {
3688c2ecf20Sopenharmony_ci			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
3698c2ecf20Sopenharmony_ci				sym_name(np), (int) (cur-start));
3708c2ecf20Sopenharmony_ci			++cur;
3718c2ecf20Sopenharmony_ci			continue;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		/*
3758c2ecf20Sopenharmony_ci		 *  We use the bogus value 0xf00ff00f ;-)
3768c2ecf20Sopenharmony_ci		 *  to reserve data area in SCRIPTS.
3778c2ecf20Sopenharmony_ci		 */
3788c2ecf20Sopenharmony_ci		if (opcode == SCR_DATA_ZERO) {
3798c2ecf20Sopenharmony_ci			*cur++ = 0;
3808c2ecf20Sopenharmony_ci			continue;
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		if (DEBUG_FLAGS & DEBUG_SCRIPT)
3848c2ecf20Sopenharmony_ci			printf ("%d:  <%x>\n", (int) (cur-start),
3858c2ecf20Sopenharmony_ci				(unsigned)opcode);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		/*
3888c2ecf20Sopenharmony_ci		 *  We don't have to decode ALL commands
3898c2ecf20Sopenharmony_ci		 */
3908c2ecf20Sopenharmony_ci		switch (opcode >> 28) {
3918c2ecf20Sopenharmony_ci		case 0xf:
3928c2ecf20Sopenharmony_ci			/*
3938c2ecf20Sopenharmony_ci			 *  LOAD / STORE DSA relative, don't relocate.
3948c2ecf20Sopenharmony_ci			 */
3958c2ecf20Sopenharmony_ci			relocs = 0;
3968c2ecf20Sopenharmony_ci			break;
3978c2ecf20Sopenharmony_ci		case 0xe:
3988c2ecf20Sopenharmony_ci			/*
3998c2ecf20Sopenharmony_ci			 *  LOAD / STORE absolute.
4008c2ecf20Sopenharmony_ci			 */
4018c2ecf20Sopenharmony_ci			relocs = 1;
4028c2ecf20Sopenharmony_ci			break;
4038c2ecf20Sopenharmony_ci		case 0xc:
4048c2ecf20Sopenharmony_ci			/*
4058c2ecf20Sopenharmony_ci			 *  COPY has TWO arguments.
4068c2ecf20Sopenharmony_ci			 */
4078c2ecf20Sopenharmony_ci			relocs = 2;
4088c2ecf20Sopenharmony_ci			tmp1 = cur[1];
4098c2ecf20Sopenharmony_ci			tmp2 = cur[2];
4108c2ecf20Sopenharmony_ci			if ((tmp1 ^ tmp2) & 3) {
4118c2ecf20Sopenharmony_ci				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
4128c2ecf20Sopenharmony_ci					sym_name(np), (int) (cur-start));
4138c2ecf20Sopenharmony_ci			}
4148c2ecf20Sopenharmony_ci			/*
4158c2ecf20Sopenharmony_ci			 *  If PREFETCH feature not enabled, remove
4168c2ecf20Sopenharmony_ci			 *  the NO FLUSH bit if present.
4178c2ecf20Sopenharmony_ci			 */
4188c2ecf20Sopenharmony_ci			if ((opcode & SCR_NO_FLUSH) &&
4198c2ecf20Sopenharmony_ci			    !(np->features & FE_PFEN)) {
4208c2ecf20Sopenharmony_ci				opcode = (opcode & ~SCR_NO_FLUSH);
4218c2ecf20Sopenharmony_ci			}
4228c2ecf20Sopenharmony_ci			break;
4238c2ecf20Sopenharmony_ci		case 0x0:
4248c2ecf20Sopenharmony_ci			/*
4258c2ecf20Sopenharmony_ci			 *  MOVE/CHMOV (absolute address)
4268c2ecf20Sopenharmony_ci			 */
4278c2ecf20Sopenharmony_ci			if (!(np->features & FE_WIDE))
4288c2ecf20Sopenharmony_ci				opcode = (opcode | OPC_MOVE);
4298c2ecf20Sopenharmony_ci			relocs = 1;
4308c2ecf20Sopenharmony_ci			break;
4318c2ecf20Sopenharmony_ci		case 0x1:
4328c2ecf20Sopenharmony_ci			/*
4338c2ecf20Sopenharmony_ci			 *  MOVE/CHMOV (table indirect)
4348c2ecf20Sopenharmony_ci			 */
4358c2ecf20Sopenharmony_ci			if (!(np->features & FE_WIDE))
4368c2ecf20Sopenharmony_ci				opcode = (opcode | OPC_MOVE);
4378c2ecf20Sopenharmony_ci			relocs = 0;
4388c2ecf20Sopenharmony_ci			break;
4398c2ecf20Sopenharmony_ci#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
4408c2ecf20Sopenharmony_ci		case 0x2:
4418c2ecf20Sopenharmony_ci			/*
4428c2ecf20Sopenharmony_ci			 *  MOVE/CHMOV in target role (absolute address)
4438c2ecf20Sopenharmony_ci			 */
4448c2ecf20Sopenharmony_ci			opcode &= ~0x20000000;
4458c2ecf20Sopenharmony_ci			if (!(np->features & FE_WIDE))
4468c2ecf20Sopenharmony_ci				opcode = (opcode & ~OPC_TCHMOVE);
4478c2ecf20Sopenharmony_ci			relocs = 1;
4488c2ecf20Sopenharmony_ci			break;
4498c2ecf20Sopenharmony_ci		case 0x3:
4508c2ecf20Sopenharmony_ci			/*
4518c2ecf20Sopenharmony_ci			 *  MOVE/CHMOV in target role (table indirect)
4528c2ecf20Sopenharmony_ci			 */
4538c2ecf20Sopenharmony_ci			opcode &= ~0x20000000;
4548c2ecf20Sopenharmony_ci			if (!(np->features & FE_WIDE))
4558c2ecf20Sopenharmony_ci				opcode = (opcode & ~OPC_TCHMOVE);
4568c2ecf20Sopenharmony_ci			relocs = 0;
4578c2ecf20Sopenharmony_ci			break;
4588c2ecf20Sopenharmony_ci#endif
4598c2ecf20Sopenharmony_ci		case 0x8:
4608c2ecf20Sopenharmony_ci			/*
4618c2ecf20Sopenharmony_ci			 *  JUMP / CALL
4628c2ecf20Sopenharmony_ci			 *  don't relocate if relative :-)
4638c2ecf20Sopenharmony_ci			 */
4648c2ecf20Sopenharmony_ci			if (opcode & 0x00800000)
4658c2ecf20Sopenharmony_ci				relocs = 0;
4668c2ecf20Sopenharmony_ci			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
4678c2ecf20Sopenharmony_ci				relocs = 2;
4688c2ecf20Sopenharmony_ci			else
4698c2ecf20Sopenharmony_ci				relocs = 1;
4708c2ecf20Sopenharmony_ci			break;
4718c2ecf20Sopenharmony_ci		case 0x4:
4728c2ecf20Sopenharmony_ci		case 0x5:
4738c2ecf20Sopenharmony_ci		case 0x6:
4748c2ecf20Sopenharmony_ci		case 0x7:
4758c2ecf20Sopenharmony_ci			relocs = 1;
4768c2ecf20Sopenharmony_ci			break;
4778c2ecf20Sopenharmony_ci		default:
4788c2ecf20Sopenharmony_ci			relocs = 0;
4798c2ecf20Sopenharmony_ci			break;
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		/*
4838c2ecf20Sopenharmony_ci		 *  Scriptify:) the opcode.
4848c2ecf20Sopenharmony_ci		 */
4858c2ecf20Sopenharmony_ci		*cur++ = cpu_to_scr(opcode);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		/*
4888c2ecf20Sopenharmony_ci		 *  If no relocation, assume 1 argument
4898c2ecf20Sopenharmony_ci		 *  and just scriptize:) it.
4908c2ecf20Sopenharmony_ci		 */
4918c2ecf20Sopenharmony_ci		if (!relocs) {
4928c2ecf20Sopenharmony_ci			*cur = cpu_to_scr(*cur);
4938c2ecf20Sopenharmony_ci			++cur;
4948c2ecf20Sopenharmony_ci			continue;
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		/*
4988c2ecf20Sopenharmony_ci		 *  Otherwise performs all needed relocations.
4998c2ecf20Sopenharmony_ci		 */
5008c2ecf20Sopenharmony_ci		while (relocs--) {
5018c2ecf20Sopenharmony_ci			old = *cur;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci			switch (old & RELOC_MASK) {
5048c2ecf20Sopenharmony_ci			case RELOC_REGISTER:
5058c2ecf20Sopenharmony_ci				new = (old & ~RELOC_MASK) + np->mmio_ba;
5068c2ecf20Sopenharmony_ci				break;
5078c2ecf20Sopenharmony_ci			case RELOC_LABEL_A:
5088c2ecf20Sopenharmony_ci				new = (old & ~RELOC_MASK) + np->scripta_ba;
5098c2ecf20Sopenharmony_ci				break;
5108c2ecf20Sopenharmony_ci			case RELOC_LABEL_B:
5118c2ecf20Sopenharmony_ci				new = (old & ~RELOC_MASK) + np->scriptb_ba;
5128c2ecf20Sopenharmony_ci				break;
5138c2ecf20Sopenharmony_ci			case RELOC_SOFTC:
5148c2ecf20Sopenharmony_ci				new = (old & ~RELOC_MASK) + np->hcb_ba;
5158c2ecf20Sopenharmony_ci				break;
5168c2ecf20Sopenharmony_ci			case 0:
5178c2ecf20Sopenharmony_ci				/*
5188c2ecf20Sopenharmony_ci				 *  Don't relocate a 0 address.
5198c2ecf20Sopenharmony_ci				 *  They are mostly used for patched or
5208c2ecf20Sopenharmony_ci				 *  script self-modified areas.
5218c2ecf20Sopenharmony_ci				 */
5228c2ecf20Sopenharmony_ci				if (old == 0) {
5238c2ecf20Sopenharmony_ci					new = old;
5248c2ecf20Sopenharmony_ci					break;
5258c2ecf20Sopenharmony_ci				}
5268c2ecf20Sopenharmony_ci				fallthrough;
5278c2ecf20Sopenharmony_ci			default:
5288c2ecf20Sopenharmony_ci				new = 0;
5298c2ecf20Sopenharmony_ci				panic("sym_fw_bind_script: "
5308c2ecf20Sopenharmony_ci				      "weird relocation %x\n", old);
5318c2ecf20Sopenharmony_ci				break;
5328c2ecf20Sopenharmony_ci			}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci			*cur++ = cpu_to_scr(new);
5358c2ecf20Sopenharmony_ci		}
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci}
538