18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell 88SE94xx hardware specific 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2007 Red Hat, Inc. 68c2ecf20Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com> 78c2ecf20Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "mv_sas.h" 118c2ecf20Sopenharmony_ci#include "mv_94xx.h" 128c2ecf20Sopenharmony_ci#include "mv_chips.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci u32 reg; 178c2ecf20Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 188c2ecf20Sopenharmony_ci u32 phy_status; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3); 218c2ecf20Sopenharmony_ci reg = mvs_read_port_vsr_data(mvi, i); 228c2ecf20Sopenharmony_ci phy_status = ((reg & 0x3f0000) >> 16) & 0xff; 238c2ecf20Sopenharmony_ci phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 248c2ecf20Sopenharmony_ci switch (phy_status) { 258c2ecf20Sopenharmony_ci case 0x10: 268c2ecf20Sopenharmony_ci phy->phy_type |= PORT_TYPE_SAS; 278c2ecf20Sopenharmony_ci break; 288c2ecf20Sopenharmony_ci case 0x1d: 298c2ecf20Sopenharmony_ci default: 308c2ecf20Sopenharmony_ci phy->phy_type |= PORT_TYPE_SATA; 318c2ecf20Sopenharmony_ci break; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void set_phy_tuning(struct mvs_info *mvi, int phy_id, 368c2ecf20Sopenharmony_ci struct phy_tuning phy_tuning) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci u32 tmp, setting_0 = 0, setting_1 = 0; 398c2ecf20Sopenharmony_ci u8 i; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Remap information for B0 chip: 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient) 448c2ecf20Sopenharmony_ci * R0Dh -> R118h[31:16] (Generation 1 Setting 0) 458c2ecf20Sopenharmony_ci * R0Eh -> R11Ch[15:0] (Generation 1 Setting 1) 468c2ecf20Sopenharmony_ci * R0Fh -> R11Ch[31:16] (Generation 2 Setting 0) 478c2ecf20Sopenharmony_ci * R10h -> R120h[15:0] (Generation 2 Setting 1) 488c2ecf20Sopenharmony_ci * R11h -> R120h[31:16] (Generation 3 Setting 0) 498c2ecf20Sopenharmony_ci * R12h -> R124h[15:0] (Generation 3 Setting 1) 508c2ecf20Sopenharmony_ci * R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved)) 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* A0 has a different set of registers */ 548c2ecf20Sopenharmony_ci if (mvi->pdev->revision == VANIR_A0_REV) 558c2ecf20Sopenharmony_ci return; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 588c2ecf20Sopenharmony_ci /* loop 3 times, set Gen 1, Gen 2, Gen 3 */ 598c2ecf20Sopenharmony_ci switch (i) { 608c2ecf20Sopenharmony_ci case 0: 618c2ecf20Sopenharmony_ci setting_0 = GENERATION_1_SETTING; 628c2ecf20Sopenharmony_ci setting_1 = GENERATION_1_2_SETTING; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case 1: 658c2ecf20Sopenharmony_ci setting_0 = GENERATION_1_2_SETTING; 668c2ecf20Sopenharmony_ci setting_1 = GENERATION_2_3_SETTING; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case 2: 698c2ecf20Sopenharmony_ci setting_0 = GENERATION_2_3_SETTING; 708c2ecf20Sopenharmony_ci setting_1 = GENERATION_3_4_SETTING; 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Set: 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Transmitter Emphasis Enable 778c2ecf20Sopenharmony_ci * Transmitter Emphasis Amplitude 788c2ecf20Sopenharmony_ci * Transmitter Amplitude 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, setting_0); 818c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 828c2ecf20Sopenharmony_ci tmp &= ~(0xFBE << 16); 838c2ecf20Sopenharmony_ci tmp |= (((phy_tuning.trans_emp_en << 11) | 848c2ecf20Sopenharmony_ci (phy_tuning.trans_emp_amp << 7) | 858c2ecf20Sopenharmony_ci (phy_tuning.trans_amp << 1)) << 16); 868c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Set Transmitter Amplitude Adjust */ 898c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, setting_1); 908c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 918c2ecf20Sopenharmony_ci tmp &= ~(0xC000); 928c2ecf20Sopenharmony_ci tmp |= (phy_tuning.trans_amp_adj << 14); 938c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id, 988c2ecf20Sopenharmony_ci struct ffe_control ffe) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci u32 tmp; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Don't run this if A0/B0 */ 1038c2ecf20Sopenharmony_ci if ((mvi->pdev->revision == VANIR_A0_REV) 1048c2ecf20Sopenharmony_ci || (mvi->pdev->revision == VANIR_B0_REV)) 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* FFE Resistor and Capacitor */ 1088c2ecf20Sopenharmony_ci /* R10Ch DFE Resolution Control/Squelch and FFE Setting 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * FFE_FORCE [7] 1118c2ecf20Sopenharmony_ci * FFE_RES_SEL [6:4] 1128c2ecf20Sopenharmony_ci * FFE_CAP_SEL [3:0] 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL); 1158c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 1168c2ecf20Sopenharmony_ci tmp &= ~0xFF; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Read from HBA_Info_Page */ 1198c2ecf20Sopenharmony_ci tmp |= ((0x1 << 7) | 1208c2ecf20Sopenharmony_ci (ffe.ffe_rss_sel << 4) | 1218c2ecf20Sopenharmony_ci (ffe.ffe_cap_sel << 0)); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* R064h PHY Mode Register 1 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * DFE_DIS 18 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); 1308c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 1318c2ecf20Sopenharmony_ci tmp &= ~0x40001; 1328c2ecf20Sopenharmony_ci /* Hard coding */ 1338c2ecf20Sopenharmony_ci /* No defines in HBA_Info_Page */ 1348c2ecf20Sopenharmony_ci tmp |= (0 << 18); 1358c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* R110h DFE F0-F1 Coefficient Control/DFE Update Control 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * DFE_UPDATE_EN [11:6] 1408c2ecf20Sopenharmony_ci * DFE_FX_FORCE [5:0] 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_DFE_UPDATE_CRTL); 1438c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 1448c2ecf20Sopenharmony_ci tmp &= ~0xFFF; 1458c2ecf20Sopenharmony_ci /* Hard coding */ 1468c2ecf20Sopenharmony_ci /* No defines in HBA_Info_Page */ 1478c2ecf20Sopenharmony_ci tmp |= ((0x3F << 6) | (0x0 << 0)); 1488c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* R1A0h Interface and Digital Reference Clock Control/Reserved_50h 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * FFE_TRAIN_EN 3 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); 1558c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 1568c2ecf20Sopenharmony_ci tmp &= ~0x8; 1578c2ecf20Sopenharmony_ci /* Hard coding */ 1588c2ecf20Sopenharmony_ci /* No defines in HBA_Info_Page */ 1598c2ecf20Sopenharmony_ci tmp |= (0 << 3); 1608c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/*Notice: this function must be called when phy is disabled*/ 1648c2ecf20Sopenharmony_cistatic void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci union reg_phy_cfg phy_cfg, phy_cfg_tmp; 1678c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 1688c2ecf20Sopenharmony_ci phy_cfg_tmp.v = mvs_read_port_vsr_data(mvi, phy_id); 1698c2ecf20Sopenharmony_ci phy_cfg.v = 0; 1708c2ecf20Sopenharmony_ci phy_cfg.u.disable_phy = phy_cfg_tmp.u.disable_phy; 1718c2ecf20Sopenharmony_ci phy_cfg.u.sas_support = 1; 1728c2ecf20Sopenharmony_ci phy_cfg.u.sata_support = 1; 1738c2ecf20Sopenharmony_ci phy_cfg.u.sata_host_mode = 1; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci switch (rate) { 1768c2ecf20Sopenharmony_ci case 0x0: 1778c2ecf20Sopenharmony_ci /* support 1.5 Gbps */ 1788c2ecf20Sopenharmony_ci phy_cfg.u.speed_support = 1; 1798c2ecf20Sopenharmony_ci phy_cfg.u.snw_3_support = 0; 1808c2ecf20Sopenharmony_ci phy_cfg.u.tx_lnk_parity = 1; 1818c2ecf20Sopenharmony_ci phy_cfg.u.tx_spt_phs_lnk_rate = 0x30; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case 0x1: 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* support 1.5, 3.0 Gbps */ 1868c2ecf20Sopenharmony_ci phy_cfg.u.speed_support = 3; 1878c2ecf20Sopenharmony_ci phy_cfg.u.tx_spt_phs_lnk_rate = 0x3c; 1888c2ecf20Sopenharmony_ci phy_cfg.u.tx_lgcl_lnk_rate = 0x08; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case 0x2: 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci /* support 1.5, 3.0, 6.0 Gbps */ 1938c2ecf20Sopenharmony_ci phy_cfg.u.speed_support = 7; 1948c2ecf20Sopenharmony_ci phy_cfg.u.snw_3_support = 1; 1958c2ecf20Sopenharmony_ci phy_cfg.u.tx_lnk_parity = 1; 1968c2ecf20Sopenharmony_ci phy_cfg.u.tx_spt_phs_lnk_rate = 0x3f; 1978c2ecf20Sopenharmony_ci phy_cfg.u.tx_lgcl_lnk_rate = 0x09; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci u32 temp; 2068c2ecf20Sopenharmony_ci temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]); 2078c2ecf20Sopenharmony_ci if (temp == 0xFFFFFFFFL) { 2088c2ecf20Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id].trans_emp_amp = 0x6; 2098c2ecf20Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id].trans_amp = 0x1A; 2108c2ecf20Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id].trans_amp_adj = 0x3; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci temp = (u8)(*(u8 *)&mvi->hba_info_param.ffe_ctl[phy_id]); 2148c2ecf20Sopenharmony_ci if (temp == 0xFFL) { 2158c2ecf20Sopenharmony_ci switch (mvi->pdev->revision) { 2168c2ecf20Sopenharmony_ci case VANIR_A0_REV: 2178c2ecf20Sopenharmony_ci case VANIR_B0_REV: 2188c2ecf20Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; 2198c2ecf20Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0x7; 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case VANIR_C0_REV: 2228c2ecf20Sopenharmony_ci case VANIR_C1_REV: 2238c2ecf20Sopenharmony_ci case VANIR_C2_REV: 2248c2ecf20Sopenharmony_ci default: 2258c2ecf20Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; 2268c2ecf20Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0xC; 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci temp = (u8)(*(u8 *)&mvi->hba_info_param.phy_rate[phy_id]); 2328c2ecf20Sopenharmony_ci if (temp == 0xFFL) 2338c2ecf20Sopenharmony_ci /*set default phy_rate = 6Gbps*/ 2348c2ecf20Sopenharmony_ci mvi->hba_info_param.phy_rate[phy_id] = 0x2; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci set_phy_tuning(mvi, phy_id, 2378c2ecf20Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id]); 2388c2ecf20Sopenharmony_ci set_phy_ffe_tuning(mvi, phy_id, 2398c2ecf20Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id]); 2408c2ecf20Sopenharmony_ci set_phy_rate(mvi, phy_id, 2418c2ecf20Sopenharmony_ci mvi->hba_info_param.phy_rate[phy_id]); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 2478c2ecf20Sopenharmony_ci u32 tmp; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 2508c2ecf20Sopenharmony_ci tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); 2518c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci u32 tmp; 2578c2ecf20Sopenharmony_ci u32 delay = 5000; 2588c2ecf20Sopenharmony_ci if (hard == MVS_PHY_TUNE) { 2598c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, phy_id, PHYR_SATA_CTL); 2608c2ecf20Sopenharmony_ci tmp = mvs_read_port_cfg_data(mvi, phy_id); 2618c2ecf20Sopenharmony_ci mvs_write_port_cfg_data(mvi, phy_id, tmp|0x20000000); 2628c2ecf20Sopenharmony_ci mvs_write_port_cfg_data(mvi, phy_id, tmp|0x100000); 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, phy_id); 2668c2ecf20Sopenharmony_ci tmp &= ~PHYEV_RDY_CH; 2678c2ecf20Sopenharmony_ci mvs_write_port_irq_stat(mvi, phy_id, tmp); 2688c2ecf20Sopenharmony_ci if (hard) { 2698c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 2708c2ecf20Sopenharmony_ci tmp |= PHY_RST_HARD; 2718c2ecf20Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 2728c2ecf20Sopenharmony_ci do { 2738c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 2748c2ecf20Sopenharmony_ci udelay(10); 2758c2ecf20Sopenharmony_ci delay--; 2768c2ecf20Sopenharmony_ci } while ((tmp & PHY_RST_HARD) && delay); 2778c2ecf20Sopenharmony_ci if (!delay) 2788c2ecf20Sopenharmony_ci mv_dprintk("phy hard reset failed.\n"); 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 2818c2ecf20Sopenharmony_ci tmp |= PHY_RST; 2828c2ecf20Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci u32 tmp; 2898c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 2908c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 2918c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci u32 tmp; 2978c2ecf20Sopenharmony_ci u8 revision = 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci revision = mvi->pdev->revision; 3008c2ecf20Sopenharmony_ci if (revision == VANIR_A0_REV) { 3018c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); 3028c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci if (revision == VANIR_B0_REV) { 3058c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, CMD_APP_MEM_CTL); 3068c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, 0x08001006); 3078c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); 3088c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 3128c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 3138c2ecf20Sopenharmony_ci tmp |= bit(0); 3148c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void mvs_94xx_sgpio_init(struct mvs_info *mvi) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 3208c2ecf20Sopenharmony_ci u32 tmp; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci tmp = mr32(MVS_HST_CHIP_CONFIG); 3238c2ecf20Sopenharmony_ci tmp |= 0x100; 3248c2ecf20Sopenharmony_ci mw32(MVS_HST_CHIP_CONFIG, tmp); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, 3278c2ecf20Sopenharmony_ci MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id, 3308c2ecf20Sopenharmony_ci 8 << MVS_SGPIO_CFG1_LOWA_SHIFT | 3318c2ecf20Sopenharmony_ci 8 << MVS_SGPIO_CFG1_HIA_SHIFT | 3328c2ecf20Sopenharmony_ci 4 << MVS_SGPIO_CFG1_LOWB_SHIFT | 3338c2ecf20Sopenharmony_ci 4 << MVS_SGPIO_CFG1_HIB_SHIFT | 3348c2ecf20Sopenharmony_ci 2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT | 3358c2ecf20Sopenharmony_ci 1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT 3368c2ecf20Sopenharmony_ci ); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id, 3398c2ecf20Sopenharmony_ci (300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */ 3408c2ecf20Sopenharmony_ci 66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/ 3418c2ecf20Sopenharmony_ci ); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id, 3448c2ecf20Sopenharmony_ci MVS_SGPIO_CFG0_ENABLE | 3458c2ecf20Sopenharmony_ci MVS_SGPIO_CFG0_BLINKA | 3468c2ecf20Sopenharmony_ci MVS_SGPIO_CFG0_BLINKB | 3478c2ecf20Sopenharmony_ci /* 3*4 data bits / PDU */ 3488c2ecf20Sopenharmony_ci (12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT 3498c2ecf20Sopenharmony_ci ); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, 3528c2ecf20Sopenharmony_ci DEFAULT_SGPIO_BITS); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id, 3558c2ecf20Sopenharmony_ci ((mvi->id * 4) + 3) << (8 * 3) | 3568c2ecf20Sopenharmony_ci ((mvi->id * 4) + 2) << (8 * 2) | 3578c2ecf20Sopenharmony_ci ((mvi->id * 4) + 1) << (8 * 1) | 3588c2ecf20Sopenharmony_ci ((mvi->id * 4) + 0) << (8 * 0)); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int mvs_94xx_init(struct mvs_info *mvi) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 3658c2ecf20Sopenharmony_ci int i; 3668c2ecf20Sopenharmony_ci u32 tmp, cctl; 3678c2ecf20Sopenharmony_ci u8 revision; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci revision = mvi->pdev->revision; 3708c2ecf20Sopenharmony_ci mvs_show_pcie_usage(mvi); 3718c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 3728c2ecf20Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 3738c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 3748c2ecf20Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 3758c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Init Chip */ 3798c2ecf20Sopenharmony_ci /* make sure RST is set; HBA_RST /should/ have done that for us */ 3808c2ecf20Sopenharmony_ci cctl = mr32(MVS_CTL) & 0xFFFF; 3818c2ecf20Sopenharmony_ci if (cctl & CCTL_RST) 3828c2ecf20Sopenharmony_ci cctl &= ~CCTL_RST; 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci mw32_f(MVS_CTL, cctl | CCTL_RST); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 3878c2ecf20Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 3888c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 3898c2ecf20Sopenharmony_ci tmp |= PCTL_COM_ON; 3908c2ecf20Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 3918c2ecf20Sopenharmony_ci tmp |= PCTL_LINK_RST; 3928c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 3938c2ecf20Sopenharmony_ci msleep(100); 3948c2ecf20Sopenharmony_ci tmp &= ~PCTL_LINK_RST; 3958c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 3968c2ecf20Sopenharmony_ci msleep(100); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* disable Multiplexing, enable phy implemented */ 4008c2ecf20Sopenharmony_ci mw32(MVS_PORTS_IMP, 0xFF); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (revision == VANIR_A0_REV) { 4038c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, CMD_CMWK_OOB_DET); 4048c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x00018080); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE2); 4078c2ecf20Sopenharmony_ci if (revision == VANIR_A0_REV || revision == VANIR_B0_REV) 4088c2ecf20Sopenharmony_ci /* set 6G/3G/1.5G, multiplexing, without SSC */ 4098c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x0084d4fe); 4108c2ecf20Sopenharmony_ci else 4118c2ecf20Sopenharmony_ci /* set 6G/3G/1.5G, multiplexing, with and without SSC */ 4128c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x0084fffe); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (revision == VANIR_B0_REV) { 4158c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, CMD_APP_MEM_CTL); 4168c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x08001006); 4178c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, CMD_HOST_RD_DATA); 4188c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x0000705f); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* reset control */ 4228c2ecf20Sopenharmony_ci mw32(MVS_PCS, 0); /* MVS_PCS */ 4238c2ecf20Sopenharmony_ci mw32(MVS_STP_REG_SET_0, 0); 4248c2ecf20Sopenharmony_ci mw32(MVS_STP_REG_SET_1, 0); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* init phys */ 4278c2ecf20Sopenharmony_ci mvs_phy_hacks(mvi); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* disable non data frame retry */ 4308c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_SAS_CTL1); 4318c2ecf20Sopenharmony_ci if ((revision == VANIR_A0_REV) || 4328c2ecf20Sopenharmony_ci (revision == VANIR_B0_REV) || 4338c2ecf20Sopenharmony_ci (revision == VANIR_C0_REV)) { 4348c2ecf20Sopenharmony_ci tmp &= ~0xffff; 4358c2ecf20Sopenharmony_ci tmp |= 0x007f; 4368c2ecf20Sopenharmony_ci mvs_cw32(mvi, CMD_SAS_CTL1, tmp); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* set LED blink when IO*/ 4408c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, VSR_PHY_ACT_LED); 4418c2ecf20Sopenharmony_ci tmp = mr32(MVS_PA_VSR_PORT); 4428c2ecf20Sopenharmony_ci tmp &= 0xFFFF00FF; 4438c2ecf20Sopenharmony_ci tmp |= 0x00003300; 4448c2ecf20Sopenharmony_ci mw32(MVS_PA_VSR_PORT, tmp); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci mw32(MVS_CMD_LIST_LO, mvi->slot_dma); 4478c2ecf20Sopenharmony_ci mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); 4508c2ecf20Sopenharmony_ci mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); 4538c2ecf20Sopenharmony_ci mw32(MVS_TX_LO, mvi->tx_dma); 4548c2ecf20Sopenharmony_ci mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ); 4578c2ecf20Sopenharmony_ci mw32(MVS_RX_LO, mvi->rx_dma); 4588c2ecf20Sopenharmony_ci mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 4618c2ecf20Sopenharmony_ci mvs_94xx_phy_disable(mvi, i); 4628c2ecf20Sopenharmony_ci /* set phy local SAS address */ 4638c2ecf20Sopenharmony_ci mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4, 4648c2ecf20Sopenharmony_ci cpu_to_le64(mvi->phy[i].dev_sas_addr)); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci mvs_94xx_enable_xmt(mvi, i); 4678c2ecf20Sopenharmony_ci mvs_94xx_config_reg_from_hba(mvi, i); 4688c2ecf20Sopenharmony_ci mvs_94xx_phy_enable(mvi, i); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci mvs_94xx_phy_reset(mvi, i, PHY_RST_HARD); 4718c2ecf20Sopenharmony_ci msleep(500); 4728c2ecf20Sopenharmony_ci mvs_94xx_detect_porttype(mvi, i); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 4768c2ecf20Sopenharmony_ci /* set select registers */ 4778c2ecf20Sopenharmony_ci writel(0x0E008000, regs + 0x000); 4788c2ecf20Sopenharmony_ci writel(0x59000008, regs + 0x004); 4798c2ecf20Sopenharmony_ci writel(0x20, regs + 0x008); 4808c2ecf20Sopenharmony_ci writel(0x20, regs + 0x00c); 4818c2ecf20Sopenharmony_ci writel(0x20, regs + 0x010); 4828c2ecf20Sopenharmony_ci writel(0x20, regs + 0x014); 4838c2ecf20Sopenharmony_ci writel(0x20, regs + 0x018); 4848c2ecf20Sopenharmony_ci writel(0x20, regs + 0x01c); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 4878c2ecf20Sopenharmony_ci /* clear phy int status */ 4888c2ecf20Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, i); 4898c2ecf20Sopenharmony_ci tmp &= ~PHYEV_SIG_FIS; 4908c2ecf20Sopenharmony_ci mvs_write_port_irq_stat(mvi, i, tmp); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* set phy int mask */ 4938c2ecf20Sopenharmony_ci tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | 4948c2ecf20Sopenharmony_ci PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ; 4958c2ecf20Sopenharmony_ci mvs_write_port_irq_mask(mvi, i, tmp); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci msleep(100); 4988c2ecf20Sopenharmony_ci mvs_update_phyinfo(mvi, i, 1); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* little endian for open address and command table, etc. */ 5028c2ecf20Sopenharmony_ci cctl = mr32(MVS_CTL); 5038c2ecf20Sopenharmony_ci cctl |= CCTL_ENDIAN_CMD; 5048c2ecf20Sopenharmony_ci cctl &= ~CCTL_ENDIAN_OPEN; 5058c2ecf20Sopenharmony_ci cctl |= CCTL_ENDIAN_RSP; 5068c2ecf20Sopenharmony_ci mw32_f(MVS_CTL, cctl); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* reset CMD queue */ 5098c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 5108c2ecf20Sopenharmony_ci tmp |= PCS_CMD_RST; 5118c2ecf20Sopenharmony_ci tmp &= ~PCS_SELF_CLEAR; 5128c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 5138c2ecf20Sopenharmony_ci /* 5148c2ecf20Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 5158c2ecf20Sopenharmony_ci * it will make count 0. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci tmp = 0; 5188c2ecf20Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 5198c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff | COAL_EN); 5208c2ecf20Sopenharmony_ci else 5218c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* default interrupt coalescing time is 128us */ 5248c2ecf20Sopenharmony_ci tmp = 0x10000 | interrupt_coalescing; 5258c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* ladies and gentlemen, start your engines */ 5288c2ecf20Sopenharmony_ci mw32(MVS_TX_CFG, 0); 5298c2ecf20Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 5308c2ecf20Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); 5318c2ecf20Sopenharmony_ci /* enable CMD/CMPL_Q/RESP mode */ 5328c2ecf20Sopenharmony_ci mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN | 5338c2ecf20Sopenharmony_ci PCS_CMD_EN | PCS_CMD_STOP_ERR); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* enable completion queue interrupt */ 5368c2ecf20Sopenharmony_ci tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | 5378c2ecf20Sopenharmony_ci CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR); 5388c2ecf20Sopenharmony_ci tmp |= CINT_PHY_MASK; 5398c2ecf20Sopenharmony_ci mw32(MVS_INT_MASK, tmp); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_LINK_TIMER); 5428c2ecf20Sopenharmony_ci tmp |= 0xFFFF0000; 5438c2ecf20Sopenharmony_ci mvs_cw32(mvi, CMD_LINK_TIMER, tmp); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* tune STP performance */ 5468c2ecf20Sopenharmony_ci tmp = 0x003F003F; 5478c2ecf20Sopenharmony_ci mvs_cw32(mvi, CMD_PL_TIMER, tmp); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* This can improve expander large block size seq write performance */ 5508c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_PORT_LAYER_TIMER1); 5518c2ecf20Sopenharmony_ci tmp |= 0xFFFF007F; 5528c2ecf20Sopenharmony_ci mvs_cw32(mvi, CMD_PORT_LAYER_TIMER1, tmp); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* change the connection open-close behavior (bit 9) 5558c2ecf20Sopenharmony_ci * set bit8 to 1 for performance tuning */ 5568c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_SL_MODE0); 5578c2ecf20Sopenharmony_ci tmp |= 0x00000300; 5588c2ecf20Sopenharmony_ci /* set bit0 to 0 to enable retry for no_dest reject case */ 5598c2ecf20Sopenharmony_ci tmp &= 0xFFFFFFFE; 5608c2ecf20Sopenharmony_ci mvs_cw32(mvi, CMD_SL_MODE0, tmp); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Enable SRS interrupt */ 5638c2ecf20Sopenharmony_ci mw32(MVS_INT_MASK_SRS_0, 0xFFFF); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci mvs_94xx_sgpio_init(mvi); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic int mvs_94xx_ioremap(struct mvs_info *mvi) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci if (!mvs_ioremap(mvi, 2, -1)) { 5738c2ecf20Sopenharmony_ci mvi->regs_ex = mvi->regs + 0x10200; 5748c2ecf20Sopenharmony_ci mvi->regs += 0x20000; 5758c2ecf20Sopenharmony_ci if (mvi->id == 1) 5768c2ecf20Sopenharmony_ci mvi->regs += 0x4000; 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci return -1; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void mvs_94xx_iounmap(struct mvs_info *mvi) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci if (mvi->regs) { 5858c2ecf20Sopenharmony_ci mvi->regs -= 0x20000; 5868c2ecf20Sopenharmony_ci if (mvi->id == 1) 5878c2ecf20Sopenharmony_ci mvi->regs -= 0x4000; 5888c2ecf20Sopenharmony_ci mvs_iounmap(mvi->regs); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic void mvs_94xx_interrupt_enable(struct mvs_info *mvi) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 5958c2ecf20Sopenharmony_ci u32 tmp; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 5988c2ecf20Sopenharmony_ci tmp |= (MVS_IRQ_SAS_A | MVS_IRQ_SAS_B); 5998c2ecf20Sopenharmony_ci mw32(MVS_GBL_INT_STAT, tmp); 6008c2ecf20Sopenharmony_ci writel(tmp, regs + 0x0C); 6018c2ecf20Sopenharmony_ci writel(tmp, regs + 0x10); 6028c2ecf20Sopenharmony_ci writel(tmp, regs + 0x14); 6038c2ecf20Sopenharmony_ci writel(tmp, regs + 0x18); 6048c2ecf20Sopenharmony_ci mw32(MVS_GBL_CTL, tmp); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void mvs_94xx_interrupt_disable(struct mvs_info *mvi) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 6108c2ecf20Sopenharmony_ci u32 tmp; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci tmp &= ~(MVS_IRQ_SAS_A | MVS_IRQ_SAS_B); 6158c2ecf20Sopenharmony_ci mw32(MVS_GBL_INT_STAT, tmp); 6168c2ecf20Sopenharmony_ci writel(tmp, regs + 0x0C); 6178c2ecf20Sopenharmony_ci writel(tmp, regs + 0x10); 6188c2ecf20Sopenharmony_ci writel(tmp, regs + 0x14); 6198c2ecf20Sopenharmony_ci writel(tmp, regs + 0x18); 6208c2ecf20Sopenharmony_ci mw32(MVS_GBL_CTL, tmp); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 6268c2ecf20Sopenharmony_ci u32 stat = 0; 6278c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 6288c2ecf20Sopenharmony_ci stat = mr32(MVS_GBL_INT_STAT); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!(stat & (MVS_IRQ_SAS_A | MVS_IRQ_SAS_B))) 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci return stat; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (((stat & MVS_IRQ_SAS_A) && mvi->id == 0) || 6418c2ecf20Sopenharmony_ci ((stat & MVS_IRQ_SAS_B) && mvi->id == 1)) { 6428c2ecf20Sopenharmony_ci mw32_f(MVS_INT_STAT, CINT_DONE); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci spin_lock(&mvi->lock); 6458c2ecf20Sopenharmony_ci mvs_int_full(mvi); 6468c2ecf20Sopenharmony_ci spin_unlock(&mvi->lock); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci u32 tmp; 6548c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3)); 6558c2ecf20Sopenharmony_ci if (tmp & 1 << (slot_idx % 32)) { 6568c2ecf20Sopenharmony_ci mv_printk("command active %08X, slot [%x].\n", tmp, slot_idx); 6578c2ecf20Sopenharmony_ci mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3), 6588c2ecf20Sopenharmony_ci 1 << (slot_idx % 32)); 6598c2ecf20Sopenharmony_ci do { 6608c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, 6618c2ecf20Sopenharmony_ci MVS_COMMAND_ACTIVE + (slot_idx >> 3)); 6628c2ecf20Sopenharmony_ci } while (tmp & 1 << (slot_idx % 32)); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic void 6678c2ecf20Sopenharmony_cimvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 6708c2ecf20Sopenharmony_ci u32 tmp; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (clear_all) { 6738c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 6748c2ecf20Sopenharmony_ci if (tmp) { 6758c2ecf20Sopenharmony_ci mv_dprintk("check SRS 0 %08X.\n", tmp); 6768c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_1); 6798c2ecf20Sopenharmony_ci if (tmp) { 6808c2ecf20Sopenharmony_ci mv_dprintk("check SRS 1 %08X.\n", tmp); 6818c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_1, tmp); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } else { 6848c2ecf20Sopenharmony_ci if (reg_set > 31) 6858c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_1); 6868c2ecf20Sopenharmony_ci else 6878c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (tmp & (1 << (reg_set % 32))) { 6908c2ecf20Sopenharmony_ci mv_dprintk("register set 0x%x was stopped.\n", reg_set); 6918c2ecf20Sopenharmony_ci if (reg_set > 31) 6928c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_1, 1 << (reg_set % 32)); 6938c2ecf20Sopenharmony_ci else 6948c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, 7008c2ecf20Sopenharmony_ci u32 tfs) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 7038c2ecf20Sopenharmony_ci u32 tmp; 7048c2ecf20Sopenharmony_ci mvs_94xx_clear_srs_irq(mvi, 0, 1); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT); 7078c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT, tmp | CINT_CI_STOP); 7088c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS) | 0xFF00; 7098c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 7158c2ecf20Sopenharmony_ci u32 err_0, err_1; 7168c2ecf20Sopenharmony_ci u8 i; 7178c2ecf20Sopenharmony_ci struct mvs_device *device; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci err_0 = mr32(MVS_NON_NCQ_ERR_0); 7208c2ecf20Sopenharmony_ci err_1 = mr32(MVS_NON_NCQ_ERR_1); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n", 7238c2ecf20Sopenharmony_ci err_0, err_1); 7248c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 7258c2ecf20Sopenharmony_ci if (err_0 & bit(i)) { 7268c2ecf20Sopenharmony_ci device = mvs_find_dev_by_reg_set(mvi, i); 7278c2ecf20Sopenharmony_ci if (device) 7288c2ecf20Sopenharmony_ci mvs_release_task(mvi, device->sas_device); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci if (err_1 & bit(i)) { 7318c2ecf20Sopenharmony_ci device = mvs_find_dev_by_reg_set(mvi, i+32); 7328c2ecf20Sopenharmony_ci if (device) 7338c2ecf20Sopenharmony_ci mvs_release_task(mvi, device->sas_device); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci mw32(MVS_NON_NCQ_ERR_0, err_0); 7388c2ecf20Sopenharmony_ci mw32(MVS_NON_NCQ_ERR_1, err_1); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 7448c2ecf20Sopenharmony_ci u8 reg_set = *tfs; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (*tfs == MVS_ID_NOT_MAPPED) 7478c2ecf20Sopenharmony_ci return; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci mvi->sata_reg_set &= ~bit(reg_set); 7508c2ecf20Sopenharmony_ci if (reg_set < 32) 7518c2ecf20Sopenharmony_ci w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set); 7528c2ecf20Sopenharmony_ci else 7538c2ecf20Sopenharmony_ci w_reg_set_enable(reg_set, (u32)(mvi->sata_reg_set >> 32)); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci *tfs = MVS_ID_NOT_MAPPED; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci return; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci int i; 7638c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (*tfs != MVS_ID_NOT_MAPPED) 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci i = mv_ffc64(mvi->sata_reg_set); 7698c2ecf20Sopenharmony_ci if (i >= 32) { 7708c2ecf20Sopenharmony_ci mvi->sata_reg_set |= bit(i); 7718c2ecf20Sopenharmony_ci w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32)); 7728c2ecf20Sopenharmony_ci *tfs = i; 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci } else if (i >= 0) { 7758c2ecf20Sopenharmony_ci mvi->sata_reg_set |= bit(i); 7768c2ecf20Sopenharmony_ci w_reg_set_enable(i, (u32)mvi->sata_reg_set); 7778c2ecf20Sopenharmony_ci *tfs = i; 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci return MVS_ID_NOT_MAPPED; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci int i; 7868c2ecf20Sopenharmony_ci struct scatterlist *sg; 7878c2ecf20Sopenharmony_ci struct mvs_prd *buf_prd = prd; 7888c2ecf20Sopenharmony_ci struct mvs_prd_imt im_len; 7898c2ecf20Sopenharmony_ci *(u32 *)&im_len = 0; 7908c2ecf20Sopenharmony_ci for_each_sg(scatter, sg, nr, i) { 7918c2ecf20Sopenharmony_ci buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 7928c2ecf20Sopenharmony_ci im_len.len = sg_dma_len(sg); 7938c2ecf20Sopenharmony_ci buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len); 7948c2ecf20Sopenharmony_ci buf_prd++; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int mvs_94xx_oob_done(struct mvs_info *mvi, int i) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci u32 phy_st; 8018c2ecf20Sopenharmony_ci phy_st = mvs_read_phy_ctl(mvi, i); 8028c2ecf20Sopenharmony_ci if (phy_st & PHY_READY_MASK) 8038c2ecf20Sopenharmony_ci return 1; 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id, 8088c2ecf20Sopenharmony_ci struct sas_identify_frame *id) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci int i; 8118c2ecf20Sopenharmony_ci u32 id_frame[7]; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 8148c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, port_id, 8158c2ecf20Sopenharmony_ci CONFIG_ID_FRAME0 + i * 4); 8168c2ecf20Sopenharmony_ci id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci memcpy(id, id_frame, 28); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id, 8228c2ecf20Sopenharmony_ci struct sas_identify_frame *id) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci int i; 8258c2ecf20Sopenharmony_ci u32 id_frame[7]; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 8288c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, port_id, 8298c2ecf20Sopenharmony_ci CONFIG_ATT_ID_FRAME0 + i * 4); 8308c2ecf20Sopenharmony_ci id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); 8318c2ecf20Sopenharmony_ci mv_dprintk("94xx phy %d atta frame %d %x.\n", 8328c2ecf20Sopenharmony_ci port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]); 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci memcpy(id, id_frame, 28); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci u32 att_dev_info = 0; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci att_dev_info |= id->dev_type; 8428c2ecf20Sopenharmony_ci if (id->stp_iport) 8438c2ecf20Sopenharmony_ci att_dev_info |= PORT_DEV_STP_INIT; 8448c2ecf20Sopenharmony_ci if (id->smp_iport) 8458c2ecf20Sopenharmony_ci att_dev_info |= PORT_DEV_SMP_INIT; 8468c2ecf20Sopenharmony_ci if (id->ssp_iport) 8478c2ecf20Sopenharmony_ci att_dev_info |= PORT_DEV_SSP_INIT; 8488c2ecf20Sopenharmony_ci if (id->stp_tport) 8498c2ecf20Sopenharmony_ci att_dev_info |= PORT_DEV_STP_TRGT; 8508c2ecf20Sopenharmony_ci if (id->smp_tport) 8518c2ecf20Sopenharmony_ci att_dev_info |= PORT_DEV_SMP_TRGT; 8528c2ecf20Sopenharmony_ci if (id->ssp_tport) 8538c2ecf20Sopenharmony_ci att_dev_info |= PORT_DEV_SSP_TRGT; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci att_dev_info |= (u32)id->phy_id<<24; 8568c2ecf20Sopenharmony_ci return att_dev_info; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic u32 mvs_94xx_make_att_info(struct sas_identify_frame *id) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci return mvs_94xx_make_dev_info(id); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i, 8658c2ecf20Sopenharmony_ci struct sas_identify_frame *id) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 8688c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 8698c2ecf20Sopenharmony_ci mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status); 8708c2ecf20Sopenharmony_ci sas_phy->linkrate = 8718c2ecf20Sopenharmony_ci (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 8728c2ecf20Sopenharmony_ci PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 8738c2ecf20Sopenharmony_ci sas_phy->linkrate += 0x8; 8748c2ecf20Sopenharmony_ci mv_dprintk("get link rate is %d\n", sas_phy->linkrate); 8758c2ecf20Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; 8768c2ecf20Sopenharmony_ci phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS; 8778c2ecf20Sopenharmony_ci mvs_94xx_get_dev_identify_frame(mvi, i, id); 8788c2ecf20Sopenharmony_ci phy->dev_info = mvs_94xx_make_dev_info(id); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 8818c2ecf20Sopenharmony_ci mvs_94xx_get_att_identify_frame(mvi, i, id); 8828c2ecf20Sopenharmony_ci phy->att_dev_info = mvs_94xx_make_att_info(id); 8838c2ecf20Sopenharmony_ci phy->att_dev_sas_addr = *(u64 *)id->sas_addr; 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci phy->att_dev_info = PORT_DEV_STP_TRGT | 1; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* enable spin up bit */ 8898c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 8908c2ecf20Sopenharmony_ci mvs_write_port_cfg_data(mvi, i, 0x04); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, 8958c2ecf20Sopenharmony_ci struct sas_phy_linkrates *rates) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci u32 lrmax = 0; 8988c2ecf20Sopenharmony_ci u32 tmp; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 9018c2ecf20Sopenharmony_ci lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (lrmax) { 9048c2ecf20Sopenharmony_ci tmp &= ~(0x3 << 12); 9058c2ecf20Sopenharmony_ci tmp |= lrmax; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 9088c2ecf20Sopenharmony_ci mvs_94xx_phy_reset(mvi, phy_id, PHY_RST_HARD); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void mvs_94xx_clear_active_cmds(struct mvs_info *mvi) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci u32 tmp; 9148c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 9158c2ecf20Sopenharmony_ci tmp = mr32(MVS_STP_REG_SET_0); 9168c2ecf20Sopenharmony_ci mw32(MVS_STP_REG_SET_0, 0); 9178c2ecf20Sopenharmony_ci mw32(MVS_STP_REG_SET_0, tmp); 9188c2ecf20Sopenharmony_ci tmp = mr32(MVS_STP_REG_SET_1); 9198c2ecf20Sopenharmony_ci mw32(MVS_STP_REG_SET_1, 0); 9208c2ecf20Sopenharmony_ci mw32(MVS_STP_REG_SET_1, tmp); 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic u32 mvs_94xx_spi_read_data(struct mvs_info *mvi) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 9278c2ecf20Sopenharmony_ci return mr32(SPI_RD_DATA_REG_94XX); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci mw32(SPI_RD_DATA_REG_94XX, data); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic int mvs_94xx_spi_buildcmd(struct mvs_info *mvi, 9398c2ecf20Sopenharmony_ci u32 *dwCmd, 9408c2ecf20Sopenharmony_ci u8 cmd, 9418c2ecf20Sopenharmony_ci u8 read, 9428c2ecf20Sopenharmony_ci u8 length, 9438c2ecf20Sopenharmony_ci u32 addr 9448c2ecf20Sopenharmony_ci ) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 9478c2ecf20Sopenharmony_ci u32 dwTmp; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci dwTmp = ((u32)cmd << 8) | ((u32)length << 4); 9508c2ecf20Sopenharmony_ci if (read) 9518c2ecf20Sopenharmony_ci dwTmp |= SPI_CTRL_READ_94XX; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (addr != MV_MAX_U32) { 9548c2ecf20Sopenharmony_ci mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL)); 9558c2ecf20Sopenharmony_ci dwTmp |= SPI_ADDR_VLD_94XX; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci *dwCmd = dwTmp; 9598c2ecf20Sopenharmony_ci return 0; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 9668c2ecf20Sopenharmony_ci mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 9748c2ecf20Sopenharmony_ci u32 i, dwTmp; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 9778c2ecf20Sopenharmony_ci dwTmp = mr32(SPI_CTRL_REG_94XX); 9788c2ecf20Sopenharmony_ci if (!(dwTmp & SPI_CTRL_SpiStart_94XX)) 9798c2ecf20Sopenharmony_ci return 0; 9808c2ecf20Sopenharmony_ci msleep(10); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return -1; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask, 9878c2ecf20Sopenharmony_ci int buf_len, int from, void *prd) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci int i; 9908c2ecf20Sopenharmony_ci struct mvs_prd *buf_prd = prd; 9918c2ecf20Sopenharmony_ci dma_addr_t buf_dma; 9928c2ecf20Sopenharmony_ci struct mvs_prd_imt im_len; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci *(u32 *)&im_len = 0; 9958c2ecf20Sopenharmony_ci buf_prd += from; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci#define PRD_CHAINED_ENTRY 0x01 9988c2ecf20Sopenharmony_ci if ((mvi->pdev->revision == VANIR_A0_REV) || 9998c2ecf20Sopenharmony_ci (mvi->pdev->revision == VANIR_B0_REV)) 10008c2ecf20Sopenharmony_ci buf_dma = (phy_mask <= 0x08) ? 10018c2ecf20Sopenharmony_ci mvi->bulk_buffer_dma : mvi->bulk_buffer_dma1; 10028c2ecf20Sopenharmony_ci else 10038c2ecf20Sopenharmony_ci return; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci for (i = from; i < MAX_SG_ENTRY; i++, ++buf_prd) { 10068c2ecf20Sopenharmony_ci if (i == MAX_SG_ENTRY - 1) { 10078c2ecf20Sopenharmony_ci buf_prd->addr = cpu_to_le64(virt_to_phys(buf_prd - 1)); 10088c2ecf20Sopenharmony_ci im_len.len = 2; 10098c2ecf20Sopenharmony_ci im_len.misc_ctl = PRD_CHAINED_ENTRY; 10108c2ecf20Sopenharmony_ci } else { 10118c2ecf20Sopenharmony_ci buf_prd->addr = cpu_to_le64(buf_dma); 10128c2ecf20Sopenharmony_ci im_len.len = buf_len; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 10218c2ecf20Sopenharmony_ci u32 tmp = 0; 10228c2ecf20Sopenharmony_ci /* 10238c2ecf20Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 10248c2ecf20Sopenharmony_ci * it will make count 0. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_ci if (time == 0) { 10278c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, 0); 10288c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, 0x10000); 10298c2ecf20Sopenharmony_ci } else { 10308c2ecf20Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 10318c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff|COAL_EN); 10328c2ecf20Sopenharmony_ci else 10338c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci tmp = 0x10000 | time; 10368c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, 10428c2ecf20Sopenharmony_ci u8 reg_type, u8 reg_index, 10438c2ecf20Sopenharmony_ci u8 reg_count, u8 *write_data) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci int i; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci switch (reg_type) { 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci case SAS_GPIO_REG_TX_GP: 10508c2ecf20Sopenharmony_ci if (reg_index == 0) 10518c2ecf20Sopenharmony_ci return -EINVAL; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (reg_count > 1) 10548c2ecf20Sopenharmony_ci return -EINVAL; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (reg_count == 0) 10578c2ecf20Sopenharmony_ci return 0; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* maximum supported bits = hosts * 4 drives * 3 bits */ 10608c2ecf20Sopenharmony_ci for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) { 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* select host */ 10638c2ecf20Sopenharmony_ci struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)]; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci int drive = (i/3) & (4-1); /* drive number on host */ 10688c2ecf20Sopenharmony_ci int driveshift = drive * 8; /* bit offset of drive */ 10698c2ecf20Sopenharmony_ci u32 block = ioread32be(regs + MVS_SGPIO_DCTRL + 10708c2ecf20Sopenharmony_ci MVS_SGPIO_HOST_OFFSET * mvi->id); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* 10738c2ecf20Sopenharmony_ci * if bit is set then create a mask with the first 10748c2ecf20Sopenharmony_ci * bit of the drive set in the mask ... 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ci u32 bit = get_unaligned_be32(write_data) & (1 << i) ? 10778c2ecf20Sopenharmony_ci 1 << driveshift : 0; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* 10808c2ecf20Sopenharmony_ci * ... and then shift it to the right position based 10818c2ecf20Sopenharmony_ci * on the led type (activity/id/fail) 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_ci switch (i%3) { 10848c2ecf20Sopenharmony_ci case 0: /* activity */ 10858c2ecf20Sopenharmony_ci block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT) 10868c2ecf20Sopenharmony_ci << driveshift); 10878c2ecf20Sopenharmony_ci /* hardwire activity bit to SOF */ 10888c2ecf20Sopenharmony_ci block |= LED_BLINKA_SOF << ( 10898c2ecf20Sopenharmony_ci MVS_SGPIO_DCTRL_ACT_SHIFT + 10908c2ecf20Sopenharmony_ci driveshift); 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci case 1: /* id */ 10938c2ecf20Sopenharmony_ci block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT) 10948c2ecf20Sopenharmony_ci << driveshift); 10958c2ecf20Sopenharmony_ci block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT; 10968c2ecf20Sopenharmony_ci break; 10978c2ecf20Sopenharmony_ci case 2: /* fail */ 10988c2ecf20Sopenharmony_ci block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT) 10998c2ecf20Sopenharmony_ci << driveshift); 11008c2ecf20Sopenharmony_ci block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT; 11018c2ecf20Sopenharmony_ci break; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci iowrite32be(block, 11058c2ecf20Sopenharmony_ci regs + MVS_SGPIO_DCTRL + 11068c2ecf20Sopenharmony_ci MVS_SGPIO_HOST_OFFSET * mvi->id); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci return reg_count; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci case SAS_GPIO_REG_TX: 11138c2ecf20Sopenharmony_ci if (reg_index + reg_count > mvs_prv->n_host) 11148c2ecf20Sopenharmony_ci return -EINVAL; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci for (i = 0; i < reg_count; i++) { 11178c2ecf20Sopenharmony_ci struct mvs_info *mvi = mvs_prv->mvi[i+reg_index]; 11188c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, 11218c2ecf20Sopenharmony_ci ((u32 *) write_data)[i]); 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci return reg_count; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci return -ENOSYS; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ciconst struct mvs_dispatch mvs_94xx_dispatch = { 11298c2ecf20Sopenharmony_ci "mv94xx", 11308c2ecf20Sopenharmony_ci mvs_94xx_init, 11318c2ecf20Sopenharmony_ci NULL, 11328c2ecf20Sopenharmony_ci mvs_94xx_ioremap, 11338c2ecf20Sopenharmony_ci mvs_94xx_iounmap, 11348c2ecf20Sopenharmony_ci mvs_94xx_isr, 11358c2ecf20Sopenharmony_ci mvs_94xx_isr_status, 11368c2ecf20Sopenharmony_ci mvs_94xx_interrupt_enable, 11378c2ecf20Sopenharmony_ci mvs_94xx_interrupt_disable, 11388c2ecf20Sopenharmony_ci mvs_read_phy_ctl, 11398c2ecf20Sopenharmony_ci mvs_write_phy_ctl, 11408c2ecf20Sopenharmony_ci mvs_read_port_cfg_data, 11418c2ecf20Sopenharmony_ci mvs_write_port_cfg_data, 11428c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr, 11438c2ecf20Sopenharmony_ci mvs_read_port_vsr_data, 11448c2ecf20Sopenharmony_ci mvs_write_port_vsr_data, 11458c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr, 11468c2ecf20Sopenharmony_ci mvs_read_port_irq_stat, 11478c2ecf20Sopenharmony_ci mvs_write_port_irq_stat, 11488c2ecf20Sopenharmony_ci mvs_read_port_irq_mask, 11498c2ecf20Sopenharmony_ci mvs_write_port_irq_mask, 11508c2ecf20Sopenharmony_ci mvs_94xx_command_active, 11518c2ecf20Sopenharmony_ci mvs_94xx_clear_srs_irq, 11528c2ecf20Sopenharmony_ci mvs_94xx_issue_stop, 11538c2ecf20Sopenharmony_ci mvs_start_delivery, 11548c2ecf20Sopenharmony_ci mvs_rx_update, 11558c2ecf20Sopenharmony_ci mvs_int_full, 11568c2ecf20Sopenharmony_ci mvs_94xx_assign_reg_set, 11578c2ecf20Sopenharmony_ci mvs_94xx_free_reg_set, 11588c2ecf20Sopenharmony_ci mvs_get_prd_size, 11598c2ecf20Sopenharmony_ci mvs_get_prd_count, 11608c2ecf20Sopenharmony_ci mvs_94xx_make_prd, 11618c2ecf20Sopenharmony_ci mvs_94xx_detect_porttype, 11628c2ecf20Sopenharmony_ci mvs_94xx_oob_done, 11638c2ecf20Sopenharmony_ci mvs_94xx_fix_phy_info, 11648c2ecf20Sopenharmony_ci NULL, 11658c2ecf20Sopenharmony_ci mvs_94xx_phy_set_link_rate, 11668c2ecf20Sopenharmony_ci mvs_hw_max_link_rate, 11678c2ecf20Sopenharmony_ci mvs_94xx_phy_disable, 11688c2ecf20Sopenharmony_ci mvs_94xx_phy_enable, 11698c2ecf20Sopenharmony_ci mvs_94xx_phy_reset, 11708c2ecf20Sopenharmony_ci NULL, 11718c2ecf20Sopenharmony_ci mvs_94xx_clear_active_cmds, 11728c2ecf20Sopenharmony_ci mvs_94xx_spi_read_data, 11738c2ecf20Sopenharmony_ci mvs_94xx_spi_write_data, 11748c2ecf20Sopenharmony_ci mvs_94xx_spi_buildcmd, 11758c2ecf20Sopenharmony_ci mvs_94xx_spi_issuecmd, 11768c2ecf20Sopenharmony_ci mvs_94xx_spi_waitdataready, 11778c2ecf20Sopenharmony_ci mvs_94xx_fix_dma, 11788c2ecf20Sopenharmony_ci mvs_94xx_tune_interrupt, 11798c2ecf20Sopenharmony_ci mvs_94xx_non_spec_ncq_error, 11808c2ecf20Sopenharmony_ci mvs_94xx_gpio_write, 11818c2ecf20Sopenharmony_ci}; 11828c2ecf20Sopenharmony_ci 1183