162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 462306a36Sopenharmony_ci * of PCI-SCSI IO processors. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This driver is derived from the Linux sym53c8xx driver. 962306a36Sopenharmony_ci * Copyright (C) 1998-2000 Gerard Roudier 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 1262306a36Sopenharmony_ci * a port of the FreeBSD ncr driver to Linux-1.2.13. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The original ncr driver has been written for 386bsd and FreeBSD by 1562306a36Sopenharmony_ci * Wolfgang Stanglmeier <wolf@cologne.de> 1662306a36Sopenharmony_ci * Stefan Esser <se@mi.Uni-Koeln.de> 1762306a36Sopenharmony_ci * Copyright (C) 1994 Wolfgang Stanglmeier 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Other major contributions: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * NVRAM detection and reading. 2262306a36Sopenharmony_ci * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci *----------------------------------------------------------------------------- 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "sym_glue.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * Macros used for all firmwares. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#define SYM_GEN_A(s, label) ((short) offsetof(s, label)), 3362306a36Sopenharmony_ci#define SYM_GEN_B(s, label) ((short) offsetof(s, label)), 3462306a36Sopenharmony_ci#define SYM_GEN_Z(s, label) ((short) offsetof(s, label)), 3562306a36Sopenharmony_ci#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label) 3662306a36Sopenharmony_ci#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#if SYM_CONF_GENERIC_SUPPORT 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Allocate firmware #1 script area. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci#define SYM_FWA_SCR sym_fw1a_scr 4462306a36Sopenharmony_ci#define SYM_FWB_SCR sym_fw1b_scr 4562306a36Sopenharmony_ci#define SYM_FWZ_SCR sym_fw1z_scr 4662306a36Sopenharmony_ci#include "sym_fw1.h" 4762306a36Sopenharmony_cistatic struct sym_fwa_ofs sym_fw1a_ofs = { 4862306a36Sopenharmony_ci SYM_GEN_FW_A(struct SYM_FWA_SCR) 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_cistatic struct sym_fwb_ofs sym_fw1b_ofs = { 5162306a36Sopenharmony_ci SYM_GEN_FW_B(struct SYM_FWB_SCR) 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_cistatic struct sym_fwz_ofs sym_fw1z_ofs = { 5462306a36Sopenharmony_ci SYM_GEN_FW_Z(struct SYM_FWZ_SCR) 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci#undef SYM_FWA_SCR 5762306a36Sopenharmony_ci#undef SYM_FWB_SCR 5862306a36Sopenharmony_ci#undef SYM_FWZ_SCR 5962306a36Sopenharmony_ci#endif /* SYM_CONF_GENERIC_SUPPORT */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Allocate firmware #2 script area. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci#define SYM_FWA_SCR sym_fw2a_scr 6562306a36Sopenharmony_ci#define SYM_FWB_SCR sym_fw2b_scr 6662306a36Sopenharmony_ci#define SYM_FWZ_SCR sym_fw2z_scr 6762306a36Sopenharmony_ci#include "sym_fw2.h" 6862306a36Sopenharmony_cistatic struct sym_fwa_ofs sym_fw2a_ofs = { 6962306a36Sopenharmony_ci SYM_GEN_FW_A(struct SYM_FWA_SCR) 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_cistatic struct sym_fwb_ofs sym_fw2b_ofs = { 7262306a36Sopenharmony_ci SYM_GEN_FW_B(struct SYM_FWB_SCR) 7362306a36Sopenharmony_ci SYM_GEN_B(struct SYM_FWB_SCR, start64) 7462306a36Sopenharmony_ci SYM_GEN_B(struct SYM_FWB_SCR, pm_handle) 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_cistatic struct sym_fwz_ofs sym_fw2z_ofs = { 7762306a36Sopenharmony_ci SYM_GEN_FW_Z(struct SYM_FWZ_SCR) 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci#undef SYM_FWA_SCR 8062306a36Sopenharmony_ci#undef SYM_FWB_SCR 8162306a36Sopenharmony_ci#undef SYM_FWZ_SCR 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#undef SYM_GEN_A 8462306a36Sopenharmony_ci#undef SYM_GEN_B 8562306a36Sopenharmony_ci#undef SYM_GEN_Z 8662306a36Sopenharmony_ci#undef PADDR_A 8762306a36Sopenharmony_ci#undef PADDR_B 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#if SYM_CONF_GENERIC_SUPPORT 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * Patch routine for firmware #1. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic void 9462306a36Sopenharmony_cisym_fw1_patch(struct Scsi_Host *shost) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct sym_hcb *np = sym_get_hcb(shost); 9762306a36Sopenharmony_ci struct sym_fw1a_scr *scripta0; 9862306a36Sopenharmony_ci struct sym_fw1b_scr *scriptb0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci scripta0 = (struct sym_fw1a_scr *) np->scripta0; 10162306a36Sopenharmony_ci scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* 10462306a36Sopenharmony_ci * Remove LED support if not needed. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci if (!(np->features & FE_LED0)) { 10762306a36Sopenharmony_ci scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); 10862306a36Sopenharmony_ci scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); 10962306a36Sopenharmony_ci scripta0->start[0] = cpu_to_scr(SCR_NO_OP); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#ifdef SYM_CONF_IARB_SUPPORT 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * If user does not want to use IMMEDIATE ARBITRATION 11562306a36Sopenharmony_ci * when we are reselected while attempting to arbitrate, 11662306a36Sopenharmony_ci * patch the SCRIPTS accordingly with a SCRIPT NO_OP. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci if (!SYM_CONF_SET_IARB_ON_ARB_LOST) 11962306a36Sopenharmony_ci scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); 12062306a36Sopenharmony_ci#endif 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * Patch some data in SCRIPTS. 12362306a36Sopenharmony_ci * - start and done queue initial bus address. 12462306a36Sopenharmony_ci * - target bus address table bus address. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); 12762306a36Sopenharmony_ci scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); 12862306a36Sopenharmony_ci scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci#endif /* SYM_CONF_GENERIC_SUPPORT */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * Patch routine for firmware #2. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistatic void 13662306a36Sopenharmony_cisym_fw2_patch(struct Scsi_Host *shost) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct sym_data *sym_data = shost_priv(shost); 13962306a36Sopenharmony_ci struct pci_dev *pdev = sym_data->pdev; 14062306a36Sopenharmony_ci struct sym_hcb *np = sym_data->ncb; 14162306a36Sopenharmony_ci struct sym_fw2a_scr *scripta0; 14262306a36Sopenharmony_ci struct sym_fw2b_scr *scriptb0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci scripta0 = (struct sym_fw2a_scr *) np->scripta0; 14562306a36Sopenharmony_ci scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Remove LED support if not needed. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci if (!(np->features & FE_LED0)) { 15162306a36Sopenharmony_ci scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); 15262306a36Sopenharmony_ci scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); 15362306a36Sopenharmony_ci scripta0->start[0] = cpu_to_scr(SCR_NO_OP); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#if SYM_CONF_DMA_ADDRESSING_MODE == 2 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * Remove useless 64 bit DMA specific SCRIPTS, 15962306a36Sopenharmony_ci * when this feature is not available. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci if (!use_dac(np)) { 16262306a36Sopenharmony_ci scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP); 16362306a36Sopenharmony_ci scripta0->is_dmap_dirty[1] = 0; 16462306a36Sopenharmony_ci scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP); 16562306a36Sopenharmony_ci scripta0->is_dmap_dirty[3] = 0; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci#endif 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#ifdef SYM_CONF_IARB_SUPPORT 17062306a36Sopenharmony_ci /* 17162306a36Sopenharmony_ci * If user does not want to use IMMEDIATE ARBITRATION 17262306a36Sopenharmony_ci * when we are reselected while attempting to arbitrate, 17362306a36Sopenharmony_ci * patch the SCRIPTS accordingly with a SCRIPT NO_OP. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci if (!SYM_CONF_SET_IARB_ON_ARB_LOST) 17662306a36Sopenharmony_ci scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); 17762306a36Sopenharmony_ci#endif 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * Patch some variable in SCRIPTS. 18062306a36Sopenharmony_ci * - start and done queue initial bus address. 18162306a36Sopenharmony_ci * - target bus address table bus address. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); 18462306a36Sopenharmony_ci scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); 18562306a36Sopenharmony_ci scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * Remove the load of SCNTL4 on reselection if not a C10. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci if (!(np->features & FE_C10)) { 19162306a36Sopenharmony_ci scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP); 19262306a36Sopenharmony_ci scripta0->resel_scntl4[1] = cpu_to_scr(0); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* 19662306a36Sopenharmony_ci * Remove a couple of work-arounds specific to C1010 if 19762306a36Sopenharmony_ci * they are not desirable. See `sym_fw2.h' for more details. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 && 20062306a36Sopenharmony_ci pdev->revision < 0x1 && 20162306a36Sopenharmony_ci np->pciclk_khz < 60000)) { 20262306a36Sopenharmony_ci scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP); 20362306a36Sopenharmony_ci scripta0->datao_phase[1] = cpu_to_scr(0); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* && 20662306a36Sopenharmony_ci pdev->revision < 0xff */)) { 20762306a36Sopenharmony_ci scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP); 20862306a36Sopenharmony_ci scripta0->sel_done[1] = cpu_to_scr(0); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* 21262306a36Sopenharmony_ci * Patch some other variables in SCRIPTS. 21362306a36Sopenharmony_ci * These ones are loaded by the SCRIPTS processor. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci scriptb0->pm0_data_addr[0] = 21662306a36Sopenharmony_ci cpu_to_scr(np->scripta_ba + 21762306a36Sopenharmony_ci offsetof(struct sym_fw2a_scr, pm0_data)); 21862306a36Sopenharmony_ci scriptb0->pm1_data_addr[0] = 21962306a36Sopenharmony_ci cpu_to_scr(np->scripta_ba + 22062306a36Sopenharmony_ci offsetof(struct sym_fw2a_scr, pm1_data)); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* 22462306a36Sopenharmony_ci * Fill the data area in scripts. 22562306a36Sopenharmony_ci * To be done for all firmwares. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_cistatic void 22862306a36Sopenharmony_cisym_fw_fill_data (u32 *in, u32 *out) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci int i; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci for (i = 0; i < SYM_CONF_MAX_SG; i++) { 23362306a36Sopenharmony_ci *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN; 23462306a36Sopenharmony_ci *in++ = offsetof (struct sym_dsb, data[i]); 23562306a36Sopenharmony_ci *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT; 23662306a36Sopenharmony_ci *out++ = offsetof (struct sym_dsb, data[i]); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * Setup useful script bus addresses. 24262306a36Sopenharmony_ci * To be done for all firmwares. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_cistatic void 24562306a36Sopenharmony_cisym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci u32 *pa; 24862306a36Sopenharmony_ci u_short *po; 24962306a36Sopenharmony_ci int i; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* 25262306a36Sopenharmony_ci * Build the bus address table for script A 25362306a36Sopenharmony_ci * from the script A offset table. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci po = (u_short *) fw->a_ofs; 25662306a36Sopenharmony_ci pa = (u32 *) &np->fwa_bas; 25762306a36Sopenharmony_ci for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++) 25862306a36Sopenharmony_ci pa[i] = np->scripta_ba + po[i]; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * Same for script B. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci po = (u_short *) fw->b_ofs; 26462306a36Sopenharmony_ci pa = (u32 *) &np->fwb_bas; 26562306a36Sopenharmony_ci for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++) 26662306a36Sopenharmony_ci pa[i] = np->scriptb_ba + po[i]; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * Same for script Z. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci po = (u_short *) fw->z_ofs; 27262306a36Sopenharmony_ci pa = (u32 *) &np->fwz_bas; 27362306a36Sopenharmony_ci for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++) 27462306a36Sopenharmony_ci pa[i] = np->scriptz_ba + po[i]; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci#if SYM_CONF_GENERIC_SUPPORT 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * Setup routine for firmware #1. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic void 28262306a36Sopenharmony_cisym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct sym_fw1a_scr *scripta0; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci scripta0 = (struct sym_fw1a_scr *) np->scripta0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * Fill variable parts in scripts. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci sym_fw_fill_data(scripta0->data_in, scripta0->data_out); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * Setup bus addresses used from the C code.. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci sym_fw_setup_bus_addresses(np, fw); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci#endif /* SYM_CONF_GENERIC_SUPPORT */ 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* 30162306a36Sopenharmony_ci * Setup routine for firmware #2. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_cistatic void 30462306a36Sopenharmony_cisym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct sym_fw2a_scr *scripta0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci scripta0 = (struct sym_fw2a_scr *) np->scripta0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* 31162306a36Sopenharmony_ci * Fill variable parts in scripts. 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_ci sym_fw_fill_data(scripta0->data_in, scripta0->data_out); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * Setup bus addresses used from the C code.. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci sym_fw_setup_bus_addresses(np, fw); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/* 32262306a36Sopenharmony_ci * Allocate firmware descriptors. 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci#if SYM_CONF_GENERIC_SUPPORT 32562306a36Sopenharmony_cistatic struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic"); 32662306a36Sopenharmony_ci#endif /* SYM_CONF_GENERIC_SUPPORT */ 32762306a36Sopenharmony_cistatic struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based"); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* 33062306a36Sopenharmony_ci * Find the most appropriate firmware for a chip. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_cistruct sym_fw * 33362306a36Sopenharmony_cisym_find_firmware(struct sym_chip *chip) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci if (chip->features & FE_LDSTR) 33662306a36Sopenharmony_ci return &sym_fw2; 33762306a36Sopenharmony_ci#if SYM_CONF_GENERIC_SUPPORT 33862306a36Sopenharmony_ci else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC))) 33962306a36Sopenharmony_ci return &sym_fw1; 34062306a36Sopenharmony_ci#endif 34162306a36Sopenharmony_ci else 34262306a36Sopenharmony_ci return NULL; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci/* 34662306a36Sopenharmony_ci * Bind a script to physical addresses. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_civoid sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci u32 opcode, new, old, tmp1, tmp2; 35162306a36Sopenharmony_ci u32 *end, *cur; 35262306a36Sopenharmony_ci int relocs; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci cur = start; 35562306a36Sopenharmony_ci end = start + len/4; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci while (cur < end) { 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci opcode = *cur; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* 36262306a36Sopenharmony_ci * If we forget to change the length 36362306a36Sopenharmony_ci * in scripts, a field will be 36462306a36Sopenharmony_ci * padded with 0. This is an illegal 36562306a36Sopenharmony_ci * command. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci if (opcode == 0) { 36862306a36Sopenharmony_ci printf ("%s: ERROR0 IN SCRIPT at %d.\n", 36962306a36Sopenharmony_ci sym_name(np), (int) (cur-start)); 37062306a36Sopenharmony_ci ++cur; 37162306a36Sopenharmony_ci continue; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * We use the bogus value 0xf00ff00f ;-) 37662306a36Sopenharmony_ci * to reserve data area in SCRIPTS. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci if (opcode == SCR_DATA_ZERO) { 37962306a36Sopenharmony_ci *cur++ = 0; 38062306a36Sopenharmony_ci continue; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (DEBUG_FLAGS & DEBUG_SCRIPT) 38462306a36Sopenharmony_ci printf ("%d: <%x>\n", (int) (cur-start), 38562306a36Sopenharmony_ci (unsigned)opcode); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* 38862306a36Sopenharmony_ci * We don't have to decode ALL commands 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci switch (opcode >> 28) { 39162306a36Sopenharmony_ci case 0xf: 39262306a36Sopenharmony_ci /* 39362306a36Sopenharmony_ci * LOAD / STORE DSA relative, don't relocate. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci relocs = 0; 39662306a36Sopenharmony_ci break; 39762306a36Sopenharmony_ci case 0xe: 39862306a36Sopenharmony_ci /* 39962306a36Sopenharmony_ci * LOAD / STORE absolute. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci relocs = 1; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci case 0xc: 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * COPY has TWO arguments. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci relocs = 2; 40862306a36Sopenharmony_ci tmp1 = cur[1]; 40962306a36Sopenharmony_ci tmp2 = cur[2]; 41062306a36Sopenharmony_ci if ((tmp1 ^ tmp2) & 3) { 41162306a36Sopenharmony_ci printf ("%s: ERROR1 IN SCRIPT at %d.\n", 41262306a36Sopenharmony_ci sym_name(np), (int) (cur-start)); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci /* 41562306a36Sopenharmony_ci * If PREFETCH feature not enabled, remove 41662306a36Sopenharmony_ci * the NO FLUSH bit if present. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci if ((opcode & SCR_NO_FLUSH) && 41962306a36Sopenharmony_ci !(np->features & FE_PFEN)) { 42062306a36Sopenharmony_ci opcode = (opcode & ~SCR_NO_FLUSH); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case 0x0: 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * MOVE/CHMOV (absolute address) 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (!(np->features & FE_WIDE)) 42862306a36Sopenharmony_ci opcode = (opcode | OPC_MOVE); 42962306a36Sopenharmony_ci relocs = 1; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case 0x1: 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * MOVE/CHMOV (table indirect) 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci if (!(np->features & FE_WIDE)) 43662306a36Sopenharmony_ci opcode = (opcode | OPC_MOVE); 43762306a36Sopenharmony_ci relocs = 0; 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci#ifdef SYM_CONF_TARGET_ROLE_SUPPORT 44062306a36Sopenharmony_ci case 0x2: 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * MOVE/CHMOV in target role (absolute address) 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_ci opcode &= ~0x20000000; 44562306a36Sopenharmony_ci if (!(np->features & FE_WIDE)) 44662306a36Sopenharmony_ci opcode = (opcode & ~OPC_TCHMOVE); 44762306a36Sopenharmony_ci relocs = 1; 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case 0x3: 45062306a36Sopenharmony_ci /* 45162306a36Sopenharmony_ci * MOVE/CHMOV in target role (table indirect) 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci opcode &= ~0x20000000; 45462306a36Sopenharmony_ci if (!(np->features & FE_WIDE)) 45562306a36Sopenharmony_ci opcode = (opcode & ~OPC_TCHMOVE); 45662306a36Sopenharmony_ci relocs = 0; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci#endif 45962306a36Sopenharmony_ci case 0x8: 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * JUMP / CALL 46262306a36Sopenharmony_ci * don't relocate if relative :-) 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci if (opcode & 0x00800000) 46562306a36Sopenharmony_ci relocs = 0; 46662306a36Sopenharmony_ci else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ 46762306a36Sopenharmony_ci relocs = 2; 46862306a36Sopenharmony_ci else 46962306a36Sopenharmony_ci relocs = 1; 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci case 0x4: 47262306a36Sopenharmony_ci case 0x5: 47362306a36Sopenharmony_ci case 0x6: 47462306a36Sopenharmony_ci case 0x7: 47562306a36Sopenharmony_ci relocs = 1; 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci default: 47862306a36Sopenharmony_ci relocs = 0; 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * Scriptify:) the opcode. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_ci *cur++ = cpu_to_scr(opcode); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* 48862306a36Sopenharmony_ci * If no relocation, assume 1 argument 48962306a36Sopenharmony_ci * and just scriptize:) it. 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci if (!relocs) { 49262306a36Sopenharmony_ci *cur = cpu_to_scr(*cur); 49362306a36Sopenharmony_ci ++cur; 49462306a36Sopenharmony_ci continue; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * Otherwise performs all needed relocations. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_ci while (relocs--) { 50162306a36Sopenharmony_ci old = *cur; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci switch (old & RELOC_MASK) { 50462306a36Sopenharmony_ci case RELOC_REGISTER: 50562306a36Sopenharmony_ci new = (old & ~RELOC_MASK) + np->mmio_ba; 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci case RELOC_LABEL_A: 50862306a36Sopenharmony_ci new = (old & ~RELOC_MASK) + np->scripta_ba; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci case RELOC_LABEL_B: 51162306a36Sopenharmony_ci new = (old & ~RELOC_MASK) + np->scriptb_ba; 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci case RELOC_SOFTC: 51462306a36Sopenharmony_ci new = (old & ~RELOC_MASK) + np->hcb_ba; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci case 0: 51762306a36Sopenharmony_ci /* 51862306a36Sopenharmony_ci * Don't relocate a 0 address. 51962306a36Sopenharmony_ci * They are mostly used for patched or 52062306a36Sopenharmony_ci * script self-modified areas. 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_ci if (old == 0) { 52362306a36Sopenharmony_ci new = old; 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci fallthrough; 52762306a36Sopenharmony_ci default: 52862306a36Sopenharmony_ci new = 0; 52962306a36Sopenharmony_ci panic("sym_fw_bind_script: " 53062306a36Sopenharmony_ci "weird relocation %x\n", old); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci *cur++ = cpu_to_scr(new); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci} 538