xref: /OK3568_Linux_fs/kernel/drivers/scsi/sym53c8xx_2/sym_fw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
4*4882a593Smuzhiyun  * of PCI-SCSI IO processors.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This driver is derived from the Linux sym53c8xx driver.
9*4882a593Smuzhiyun  * Copyright (C) 1998-2000  Gerard Roudier
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
12*4882a593Smuzhiyun  * a port of the FreeBSD ncr driver to Linux-1.2.13.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * The original ncr driver has been written for 386bsd and FreeBSD by
15*4882a593Smuzhiyun  *         Wolfgang Stanglmeier        <wolf@cologne.de>
16*4882a593Smuzhiyun  *         Stefan Esser                <se@mi.Uni-Koeln.de>
17*4882a593Smuzhiyun  * Copyright (C) 1994  Wolfgang Stanglmeier
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * Other major contributions:
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * NVRAM detection and reading.
22*4882a593Smuzhiyun  * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  *-----------------------------------------------------------------------------
25*4882a593Smuzhiyun  */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "sym_glue.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun  *  Macros used for all firmwares.
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun #define	SYM_GEN_A(s, label)	((short) offsetof(s, label)),
33*4882a593Smuzhiyun #define	SYM_GEN_B(s, label)	((short) offsetof(s, label)),
34*4882a593Smuzhiyun #define	SYM_GEN_Z(s, label)	((short) offsetof(s, label)),
35*4882a593Smuzhiyun #define	PADDR_A(label)		SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
36*4882a593Smuzhiyun #define	PADDR_B(label)		SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #if	SYM_CONF_GENERIC_SUPPORT
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun  *  Allocate firmware #1 script area.
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun #define	SYM_FWA_SCR		sym_fw1a_scr
44*4882a593Smuzhiyun #define	SYM_FWB_SCR		sym_fw1b_scr
45*4882a593Smuzhiyun #define	SYM_FWZ_SCR		sym_fw1z_scr
46*4882a593Smuzhiyun #include "sym_fw1.h"
47*4882a593Smuzhiyun static struct sym_fwa_ofs sym_fw1a_ofs = {
48*4882a593Smuzhiyun 	SYM_GEN_FW_A(struct SYM_FWA_SCR)
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun static struct sym_fwb_ofs sym_fw1b_ofs = {
51*4882a593Smuzhiyun 	SYM_GEN_FW_B(struct SYM_FWB_SCR)
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun static struct sym_fwz_ofs sym_fw1z_ofs = {
54*4882a593Smuzhiyun 	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun #undef	SYM_FWA_SCR
57*4882a593Smuzhiyun #undef	SYM_FWB_SCR
58*4882a593Smuzhiyun #undef	SYM_FWZ_SCR
59*4882a593Smuzhiyun #endif	/* SYM_CONF_GENERIC_SUPPORT */
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun  *  Allocate firmware #2 script area.
63*4882a593Smuzhiyun  */
64*4882a593Smuzhiyun #define	SYM_FWA_SCR		sym_fw2a_scr
65*4882a593Smuzhiyun #define	SYM_FWB_SCR		sym_fw2b_scr
66*4882a593Smuzhiyun #define	SYM_FWZ_SCR		sym_fw2z_scr
67*4882a593Smuzhiyun #include "sym_fw2.h"
68*4882a593Smuzhiyun static struct sym_fwa_ofs sym_fw2a_ofs = {
69*4882a593Smuzhiyun 	SYM_GEN_FW_A(struct SYM_FWA_SCR)
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun static struct sym_fwb_ofs sym_fw2b_ofs = {
72*4882a593Smuzhiyun 	SYM_GEN_FW_B(struct SYM_FWB_SCR)
73*4882a593Smuzhiyun 	SYM_GEN_B(struct SYM_FWB_SCR, start64)
74*4882a593Smuzhiyun 	SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun static struct sym_fwz_ofs sym_fw2z_ofs = {
77*4882a593Smuzhiyun 	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun #undef	SYM_FWA_SCR
80*4882a593Smuzhiyun #undef	SYM_FWB_SCR
81*4882a593Smuzhiyun #undef	SYM_FWZ_SCR
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #undef	SYM_GEN_A
84*4882a593Smuzhiyun #undef	SYM_GEN_B
85*4882a593Smuzhiyun #undef	SYM_GEN_Z
86*4882a593Smuzhiyun #undef	PADDR_A
87*4882a593Smuzhiyun #undef	PADDR_B
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun #if	SYM_CONF_GENERIC_SUPPORT
90*4882a593Smuzhiyun /*
91*4882a593Smuzhiyun  *  Patch routine for firmware #1.
92*4882a593Smuzhiyun  */
93*4882a593Smuzhiyun static void
sym_fw1_patch(struct Scsi_Host * shost)94*4882a593Smuzhiyun sym_fw1_patch(struct Scsi_Host *shost)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct sym_hcb *np = sym_get_hcb(shost);
97*4882a593Smuzhiyun 	struct sym_fw1a_scr *scripta0;
98*4882a593Smuzhiyun 	struct sym_fw1b_scr *scriptb0;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
101*4882a593Smuzhiyun 	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	/*
104*4882a593Smuzhiyun 	 *  Remove LED support if not needed.
105*4882a593Smuzhiyun 	 */
106*4882a593Smuzhiyun 	if (!(np->features & FE_LED0)) {
107*4882a593Smuzhiyun 		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
108*4882a593Smuzhiyun 		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
109*4882a593Smuzhiyun 		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun #ifdef SYM_CONF_IARB_SUPPORT
113*4882a593Smuzhiyun 	/*
114*4882a593Smuzhiyun 	 *    If user does not want to use IMMEDIATE ARBITRATION
115*4882a593Smuzhiyun 	 *    when we are reselected while attempting to arbitrate,
116*4882a593Smuzhiyun 	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
117*4882a593Smuzhiyun 	 */
118*4882a593Smuzhiyun 	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
119*4882a593Smuzhiyun 		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
120*4882a593Smuzhiyun #endif
121*4882a593Smuzhiyun 	/*
122*4882a593Smuzhiyun 	 *  Patch some data in SCRIPTS.
123*4882a593Smuzhiyun 	 *  - start and done queue initial bus address.
124*4882a593Smuzhiyun 	 *  - target bus address table bus address.
125*4882a593Smuzhiyun 	 */
126*4882a593Smuzhiyun 	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
127*4882a593Smuzhiyun 	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
128*4882a593Smuzhiyun 	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun #endif	/* SYM_CONF_GENERIC_SUPPORT */
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun  *  Patch routine for firmware #2.
134*4882a593Smuzhiyun  */
135*4882a593Smuzhiyun static void
sym_fw2_patch(struct Scsi_Host * shost)136*4882a593Smuzhiyun sym_fw2_patch(struct Scsi_Host *shost)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct sym_data *sym_data = shost_priv(shost);
139*4882a593Smuzhiyun 	struct pci_dev *pdev = sym_data->pdev;
140*4882a593Smuzhiyun 	struct sym_hcb *np = sym_data->ncb;
141*4882a593Smuzhiyun 	struct sym_fw2a_scr *scripta0;
142*4882a593Smuzhiyun 	struct sym_fw2b_scr *scriptb0;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
145*4882a593Smuzhiyun 	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/*
148*4882a593Smuzhiyun 	 *  Remove LED support if not needed.
149*4882a593Smuzhiyun 	 */
150*4882a593Smuzhiyun 	if (!(np->features & FE_LED0)) {
151*4882a593Smuzhiyun 		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
152*4882a593Smuzhiyun 		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
153*4882a593Smuzhiyun 		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun #if   SYM_CONF_DMA_ADDRESSING_MODE == 2
157*4882a593Smuzhiyun 	/*
158*4882a593Smuzhiyun 	 *  Remove useless 64 bit DMA specific SCRIPTS,
159*4882a593Smuzhiyun 	 *  when this feature is not available.
160*4882a593Smuzhiyun 	 */
161*4882a593Smuzhiyun 	if (!use_dac(np)) {
162*4882a593Smuzhiyun 		scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
163*4882a593Smuzhiyun 		scripta0->is_dmap_dirty[1] = 0;
164*4882a593Smuzhiyun 		scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
165*4882a593Smuzhiyun 		scripta0->is_dmap_dirty[3] = 0;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun #endif
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun #ifdef SYM_CONF_IARB_SUPPORT
170*4882a593Smuzhiyun 	/*
171*4882a593Smuzhiyun 	 *    If user does not want to use IMMEDIATE ARBITRATION
172*4882a593Smuzhiyun 	 *    when we are reselected while attempting to arbitrate,
173*4882a593Smuzhiyun 	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
174*4882a593Smuzhiyun 	 */
175*4882a593Smuzhiyun 	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
176*4882a593Smuzhiyun 		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
177*4882a593Smuzhiyun #endif
178*4882a593Smuzhiyun 	/*
179*4882a593Smuzhiyun 	 *  Patch some variable in SCRIPTS.
180*4882a593Smuzhiyun 	 *  - start and done queue initial bus address.
181*4882a593Smuzhiyun 	 *  - target bus address table bus address.
182*4882a593Smuzhiyun 	 */
183*4882a593Smuzhiyun 	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
184*4882a593Smuzhiyun 	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
185*4882a593Smuzhiyun 	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/*
188*4882a593Smuzhiyun 	 *  Remove the load of SCNTL4 on reselection if not a C10.
189*4882a593Smuzhiyun 	 */
190*4882a593Smuzhiyun 	if (!(np->features & FE_C10)) {
191*4882a593Smuzhiyun 		scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
192*4882a593Smuzhiyun 		scripta0->resel_scntl4[1] = cpu_to_scr(0);
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/*
196*4882a593Smuzhiyun 	 *  Remove a couple of work-arounds specific to C1010 if
197*4882a593Smuzhiyun 	 *  they are not desirable. See `sym_fw2.h' for more details.
198*4882a593Smuzhiyun 	 */
199*4882a593Smuzhiyun 	if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
200*4882a593Smuzhiyun 	      pdev->revision < 0x1 &&
201*4882a593Smuzhiyun 	      np->pciclk_khz < 60000)) {
202*4882a593Smuzhiyun 		scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
203*4882a593Smuzhiyun 		scripta0->datao_phase[1] = cpu_to_scr(0);
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 	if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
206*4882a593Smuzhiyun 	      pdev->revision < 0xff */)) {
207*4882a593Smuzhiyun 		scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
208*4882a593Smuzhiyun 		scripta0->sel_done[1] = cpu_to_scr(0);
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	/*
212*4882a593Smuzhiyun 	 *  Patch some other variables in SCRIPTS.
213*4882a593Smuzhiyun 	 *  These ones are loaded by the SCRIPTS processor.
214*4882a593Smuzhiyun 	 */
215*4882a593Smuzhiyun 	scriptb0->pm0_data_addr[0] =
216*4882a593Smuzhiyun 		cpu_to_scr(np->scripta_ba +
217*4882a593Smuzhiyun 			   offsetof(struct sym_fw2a_scr, pm0_data));
218*4882a593Smuzhiyun 	scriptb0->pm1_data_addr[0] =
219*4882a593Smuzhiyun 		cpu_to_scr(np->scripta_ba +
220*4882a593Smuzhiyun 			   offsetof(struct sym_fw2a_scr, pm1_data));
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun  *  Fill the data area in scripts.
225*4882a593Smuzhiyun  *  To be done for all firmwares.
226*4882a593Smuzhiyun  */
227*4882a593Smuzhiyun static void
sym_fw_fill_data(u32 * in,u32 * out)228*4882a593Smuzhiyun sym_fw_fill_data (u32 *in, u32 *out)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	int	i;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	for (i = 0; i < SYM_CONF_MAX_SG; i++) {
233*4882a593Smuzhiyun 		*in++  = SCR_CHMOV_TBL ^ SCR_DATA_IN;
234*4882a593Smuzhiyun 		*in++  = offsetof (struct sym_dsb, data[i]);
235*4882a593Smuzhiyun 		*out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
236*4882a593Smuzhiyun 		*out++ = offsetof (struct sym_dsb, data[i]);
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun  *  Setup useful script bus addresses.
242*4882a593Smuzhiyun  *  To be done for all firmwares.
243*4882a593Smuzhiyun  */
244*4882a593Smuzhiyun static void
sym_fw_setup_bus_addresses(struct sym_hcb * np,struct sym_fw * fw)245*4882a593Smuzhiyun sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	u32 *pa;
248*4882a593Smuzhiyun 	u_short *po;
249*4882a593Smuzhiyun 	int i;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/*
252*4882a593Smuzhiyun 	 *  Build the bus address table for script A
253*4882a593Smuzhiyun 	 *  from the script A offset table.
254*4882a593Smuzhiyun 	 */
255*4882a593Smuzhiyun 	po = (u_short *) fw->a_ofs;
256*4882a593Smuzhiyun 	pa = (u32 *) &np->fwa_bas;
257*4882a593Smuzhiyun 	for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
258*4882a593Smuzhiyun 		pa[i] = np->scripta_ba + po[i];
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/*
261*4882a593Smuzhiyun 	 *  Same for script B.
262*4882a593Smuzhiyun 	 */
263*4882a593Smuzhiyun 	po = (u_short *) fw->b_ofs;
264*4882a593Smuzhiyun 	pa = (u32 *) &np->fwb_bas;
265*4882a593Smuzhiyun 	for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
266*4882a593Smuzhiyun 		pa[i] = np->scriptb_ba + po[i];
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/*
269*4882a593Smuzhiyun 	 *  Same for script Z.
270*4882a593Smuzhiyun 	 */
271*4882a593Smuzhiyun 	po = (u_short *) fw->z_ofs;
272*4882a593Smuzhiyun 	pa = (u32 *) &np->fwz_bas;
273*4882a593Smuzhiyun 	for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
274*4882a593Smuzhiyun 		pa[i] = np->scriptz_ba + po[i];
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun #if	SYM_CONF_GENERIC_SUPPORT
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun  *  Setup routine for firmware #1.
280*4882a593Smuzhiyun  */
281*4882a593Smuzhiyun static void
sym_fw1_setup(struct sym_hcb * np,struct sym_fw * fw)282*4882a593Smuzhiyun sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	struct sym_fw1a_scr *scripta0;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/*
289*4882a593Smuzhiyun 	 *  Fill variable parts in scripts.
290*4882a593Smuzhiyun 	 */
291*4882a593Smuzhiyun 	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/*
294*4882a593Smuzhiyun 	 *  Setup bus addresses used from the C code..
295*4882a593Smuzhiyun 	 */
296*4882a593Smuzhiyun 	sym_fw_setup_bus_addresses(np, fw);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun #endif	/* SYM_CONF_GENERIC_SUPPORT */
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun /*
301*4882a593Smuzhiyun  *  Setup routine for firmware #2.
302*4882a593Smuzhiyun  */
303*4882a593Smuzhiyun static void
sym_fw2_setup(struct sym_hcb * np,struct sym_fw * fw)304*4882a593Smuzhiyun sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun 	struct sym_fw2a_scr *scripta0;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	/*
311*4882a593Smuzhiyun 	 *  Fill variable parts in scripts.
312*4882a593Smuzhiyun 	 */
313*4882a593Smuzhiyun 	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/*
316*4882a593Smuzhiyun 	 *  Setup bus addresses used from the C code..
317*4882a593Smuzhiyun 	 */
318*4882a593Smuzhiyun 	sym_fw_setup_bus_addresses(np, fw);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun  *  Allocate firmware descriptors.
323*4882a593Smuzhiyun  */
324*4882a593Smuzhiyun #if	SYM_CONF_GENERIC_SUPPORT
325*4882a593Smuzhiyun static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
326*4882a593Smuzhiyun #endif	/* SYM_CONF_GENERIC_SUPPORT */
327*4882a593Smuzhiyun static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun /*
330*4882a593Smuzhiyun  *  Find the most appropriate firmware for a chip.
331*4882a593Smuzhiyun  */
332*4882a593Smuzhiyun struct sym_fw *
sym_find_firmware(struct sym_chip * chip)333*4882a593Smuzhiyun sym_find_firmware(struct sym_chip *chip)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	if (chip->features & FE_LDSTR)
336*4882a593Smuzhiyun 		return &sym_fw2;
337*4882a593Smuzhiyun #if	SYM_CONF_GENERIC_SUPPORT
338*4882a593Smuzhiyun 	else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
339*4882a593Smuzhiyun 		return &sym_fw1;
340*4882a593Smuzhiyun #endif
341*4882a593Smuzhiyun 	else
342*4882a593Smuzhiyun 		return NULL;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun /*
346*4882a593Smuzhiyun  *  Bind a script to physical addresses.
347*4882a593Smuzhiyun  */
sym_fw_bind_script(struct sym_hcb * np,u32 * start,int len)348*4882a593Smuzhiyun void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	u32 opcode, new, old, tmp1, tmp2;
351*4882a593Smuzhiyun 	u32 *end, *cur;
352*4882a593Smuzhiyun 	int relocs;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	cur = start;
355*4882a593Smuzhiyun 	end = start + len/4;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	while (cur < end) {
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		opcode = *cur;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		/*
362*4882a593Smuzhiyun 		 *  If we forget to change the length
363*4882a593Smuzhiyun 		 *  in scripts, a field will be
364*4882a593Smuzhiyun 		 *  padded with 0. This is an illegal
365*4882a593Smuzhiyun 		 *  command.
366*4882a593Smuzhiyun 		 */
367*4882a593Smuzhiyun 		if (opcode == 0) {
368*4882a593Smuzhiyun 			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
369*4882a593Smuzhiyun 				sym_name(np), (int) (cur-start));
370*4882a593Smuzhiyun 			++cur;
371*4882a593Smuzhiyun 			continue;
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		/*
375*4882a593Smuzhiyun 		 *  We use the bogus value 0xf00ff00f ;-)
376*4882a593Smuzhiyun 		 *  to reserve data area in SCRIPTS.
377*4882a593Smuzhiyun 		 */
378*4882a593Smuzhiyun 		if (opcode == SCR_DATA_ZERO) {
379*4882a593Smuzhiyun 			*cur++ = 0;
380*4882a593Smuzhiyun 			continue;
381*4882a593Smuzhiyun 		}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		if (DEBUG_FLAGS & DEBUG_SCRIPT)
384*4882a593Smuzhiyun 			printf ("%d:  <%x>\n", (int) (cur-start),
385*4882a593Smuzhiyun 				(unsigned)opcode);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 		/*
388*4882a593Smuzhiyun 		 *  We don't have to decode ALL commands
389*4882a593Smuzhiyun 		 */
390*4882a593Smuzhiyun 		switch (opcode >> 28) {
391*4882a593Smuzhiyun 		case 0xf:
392*4882a593Smuzhiyun 			/*
393*4882a593Smuzhiyun 			 *  LOAD / STORE DSA relative, don't relocate.
394*4882a593Smuzhiyun 			 */
395*4882a593Smuzhiyun 			relocs = 0;
396*4882a593Smuzhiyun 			break;
397*4882a593Smuzhiyun 		case 0xe:
398*4882a593Smuzhiyun 			/*
399*4882a593Smuzhiyun 			 *  LOAD / STORE absolute.
400*4882a593Smuzhiyun 			 */
401*4882a593Smuzhiyun 			relocs = 1;
402*4882a593Smuzhiyun 			break;
403*4882a593Smuzhiyun 		case 0xc:
404*4882a593Smuzhiyun 			/*
405*4882a593Smuzhiyun 			 *  COPY has TWO arguments.
406*4882a593Smuzhiyun 			 */
407*4882a593Smuzhiyun 			relocs = 2;
408*4882a593Smuzhiyun 			tmp1 = cur[1];
409*4882a593Smuzhiyun 			tmp2 = cur[2];
410*4882a593Smuzhiyun 			if ((tmp1 ^ tmp2) & 3) {
411*4882a593Smuzhiyun 				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
412*4882a593Smuzhiyun 					sym_name(np), (int) (cur-start));
413*4882a593Smuzhiyun 			}
414*4882a593Smuzhiyun 			/*
415*4882a593Smuzhiyun 			 *  If PREFETCH feature not enabled, remove
416*4882a593Smuzhiyun 			 *  the NO FLUSH bit if present.
417*4882a593Smuzhiyun 			 */
418*4882a593Smuzhiyun 			if ((opcode & SCR_NO_FLUSH) &&
419*4882a593Smuzhiyun 			    !(np->features & FE_PFEN)) {
420*4882a593Smuzhiyun 				opcode = (opcode & ~SCR_NO_FLUSH);
421*4882a593Smuzhiyun 			}
422*4882a593Smuzhiyun 			break;
423*4882a593Smuzhiyun 		case 0x0:
424*4882a593Smuzhiyun 			/*
425*4882a593Smuzhiyun 			 *  MOVE/CHMOV (absolute address)
426*4882a593Smuzhiyun 			 */
427*4882a593Smuzhiyun 			if (!(np->features & FE_WIDE))
428*4882a593Smuzhiyun 				opcode = (opcode | OPC_MOVE);
429*4882a593Smuzhiyun 			relocs = 1;
430*4882a593Smuzhiyun 			break;
431*4882a593Smuzhiyun 		case 0x1:
432*4882a593Smuzhiyun 			/*
433*4882a593Smuzhiyun 			 *  MOVE/CHMOV (table indirect)
434*4882a593Smuzhiyun 			 */
435*4882a593Smuzhiyun 			if (!(np->features & FE_WIDE))
436*4882a593Smuzhiyun 				opcode = (opcode | OPC_MOVE);
437*4882a593Smuzhiyun 			relocs = 0;
438*4882a593Smuzhiyun 			break;
439*4882a593Smuzhiyun #ifdef SYM_CONF_TARGET_ROLE_SUPPORT
440*4882a593Smuzhiyun 		case 0x2:
441*4882a593Smuzhiyun 			/*
442*4882a593Smuzhiyun 			 *  MOVE/CHMOV in target role (absolute address)
443*4882a593Smuzhiyun 			 */
444*4882a593Smuzhiyun 			opcode &= ~0x20000000;
445*4882a593Smuzhiyun 			if (!(np->features & FE_WIDE))
446*4882a593Smuzhiyun 				opcode = (opcode & ~OPC_TCHMOVE);
447*4882a593Smuzhiyun 			relocs = 1;
448*4882a593Smuzhiyun 			break;
449*4882a593Smuzhiyun 		case 0x3:
450*4882a593Smuzhiyun 			/*
451*4882a593Smuzhiyun 			 *  MOVE/CHMOV in target role (table indirect)
452*4882a593Smuzhiyun 			 */
453*4882a593Smuzhiyun 			opcode &= ~0x20000000;
454*4882a593Smuzhiyun 			if (!(np->features & FE_WIDE))
455*4882a593Smuzhiyun 				opcode = (opcode & ~OPC_TCHMOVE);
456*4882a593Smuzhiyun 			relocs = 0;
457*4882a593Smuzhiyun 			break;
458*4882a593Smuzhiyun #endif
459*4882a593Smuzhiyun 		case 0x8:
460*4882a593Smuzhiyun 			/*
461*4882a593Smuzhiyun 			 *  JUMP / CALL
462*4882a593Smuzhiyun 			 *  don't relocate if relative :-)
463*4882a593Smuzhiyun 			 */
464*4882a593Smuzhiyun 			if (opcode & 0x00800000)
465*4882a593Smuzhiyun 				relocs = 0;
466*4882a593Smuzhiyun 			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
467*4882a593Smuzhiyun 				relocs = 2;
468*4882a593Smuzhiyun 			else
469*4882a593Smuzhiyun 				relocs = 1;
470*4882a593Smuzhiyun 			break;
471*4882a593Smuzhiyun 		case 0x4:
472*4882a593Smuzhiyun 		case 0x5:
473*4882a593Smuzhiyun 		case 0x6:
474*4882a593Smuzhiyun 		case 0x7:
475*4882a593Smuzhiyun 			relocs = 1;
476*4882a593Smuzhiyun 			break;
477*4882a593Smuzhiyun 		default:
478*4882a593Smuzhiyun 			relocs = 0;
479*4882a593Smuzhiyun 			break;
480*4882a593Smuzhiyun 		}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 		/*
483*4882a593Smuzhiyun 		 *  Scriptify:) the opcode.
484*4882a593Smuzhiyun 		 */
485*4882a593Smuzhiyun 		*cur++ = cpu_to_scr(opcode);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 		/*
488*4882a593Smuzhiyun 		 *  If no relocation, assume 1 argument
489*4882a593Smuzhiyun 		 *  and just scriptize:) it.
490*4882a593Smuzhiyun 		 */
491*4882a593Smuzhiyun 		if (!relocs) {
492*4882a593Smuzhiyun 			*cur = cpu_to_scr(*cur);
493*4882a593Smuzhiyun 			++cur;
494*4882a593Smuzhiyun 			continue;
495*4882a593Smuzhiyun 		}
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 		/*
498*4882a593Smuzhiyun 		 *  Otherwise performs all needed relocations.
499*4882a593Smuzhiyun 		 */
500*4882a593Smuzhiyun 		while (relocs--) {
501*4882a593Smuzhiyun 			old = *cur;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 			switch (old & RELOC_MASK) {
504*4882a593Smuzhiyun 			case RELOC_REGISTER:
505*4882a593Smuzhiyun 				new = (old & ~RELOC_MASK) + np->mmio_ba;
506*4882a593Smuzhiyun 				break;
507*4882a593Smuzhiyun 			case RELOC_LABEL_A:
508*4882a593Smuzhiyun 				new = (old & ~RELOC_MASK) + np->scripta_ba;
509*4882a593Smuzhiyun 				break;
510*4882a593Smuzhiyun 			case RELOC_LABEL_B:
511*4882a593Smuzhiyun 				new = (old & ~RELOC_MASK) + np->scriptb_ba;
512*4882a593Smuzhiyun 				break;
513*4882a593Smuzhiyun 			case RELOC_SOFTC:
514*4882a593Smuzhiyun 				new = (old & ~RELOC_MASK) + np->hcb_ba;
515*4882a593Smuzhiyun 				break;
516*4882a593Smuzhiyun 			case 0:
517*4882a593Smuzhiyun 				/*
518*4882a593Smuzhiyun 				 *  Don't relocate a 0 address.
519*4882a593Smuzhiyun 				 *  They are mostly used for patched or
520*4882a593Smuzhiyun 				 *  script self-modified areas.
521*4882a593Smuzhiyun 				 */
522*4882a593Smuzhiyun 				if (old == 0) {
523*4882a593Smuzhiyun 					new = old;
524*4882a593Smuzhiyun 					break;
525*4882a593Smuzhiyun 				}
526*4882a593Smuzhiyun 				fallthrough;
527*4882a593Smuzhiyun 			default:
528*4882a593Smuzhiyun 				new = 0;
529*4882a593Smuzhiyun 				panic("sym_fw_bind_script: "
530*4882a593Smuzhiyun 				      "weird relocation %x\n", old);
531*4882a593Smuzhiyun 				break;
532*4882a593Smuzhiyun 			}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 			*cur++ = cpu_to_scr(new);
535*4882a593Smuzhiyun 		}
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun }
538