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