162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Marvell 88SE94xx hardware specific 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2007 Red Hat, Inc. 662306a36Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com> 762306a36Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 862306a36Sopenharmony_ci*/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "mv_sas.h" 1162306a36Sopenharmony_ci#include "mv_94xx.h" 1262306a36Sopenharmony_ci#include "mv_chips.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci u32 reg; 1762306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 1862306a36Sopenharmony_ci u32 phy_status; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3); 2162306a36Sopenharmony_ci reg = mvs_read_port_vsr_data(mvi, i); 2262306a36Sopenharmony_ci phy_status = ((reg & 0x3f0000) >> 16) & 0xff; 2362306a36Sopenharmony_ci phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 2462306a36Sopenharmony_ci switch (phy_status) { 2562306a36Sopenharmony_ci case 0x10: 2662306a36Sopenharmony_ci phy->phy_type |= PORT_TYPE_SAS; 2762306a36Sopenharmony_ci break; 2862306a36Sopenharmony_ci case 0x1d: 2962306a36Sopenharmony_ci default: 3062306a36Sopenharmony_ci phy->phy_type |= PORT_TYPE_SATA; 3162306a36Sopenharmony_ci break; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void set_phy_tuning(struct mvs_info *mvi, int phy_id, 3662306a36Sopenharmony_ci struct phy_tuning phy_tuning) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci u32 tmp, setting_0 = 0, setting_1 = 0; 3962306a36Sopenharmony_ci u8 i; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* Remap information for B0 chip: 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient) 4462306a36Sopenharmony_ci * R0Dh -> R118h[31:16] (Generation 1 Setting 0) 4562306a36Sopenharmony_ci * R0Eh -> R11Ch[15:0] (Generation 1 Setting 1) 4662306a36Sopenharmony_ci * R0Fh -> R11Ch[31:16] (Generation 2 Setting 0) 4762306a36Sopenharmony_ci * R10h -> R120h[15:0] (Generation 2 Setting 1) 4862306a36Sopenharmony_ci * R11h -> R120h[31:16] (Generation 3 Setting 0) 4962306a36Sopenharmony_ci * R12h -> R124h[15:0] (Generation 3 Setting 1) 5062306a36Sopenharmony_ci * R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved)) 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* A0 has a different set of registers */ 5462306a36Sopenharmony_ci if (mvi->pdev->revision == VANIR_A0_REV) 5562306a36Sopenharmony_ci return; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 5862306a36Sopenharmony_ci /* loop 3 times, set Gen 1, Gen 2, Gen 3 */ 5962306a36Sopenharmony_ci switch (i) { 6062306a36Sopenharmony_ci case 0: 6162306a36Sopenharmony_ci setting_0 = GENERATION_1_SETTING; 6262306a36Sopenharmony_ci setting_1 = GENERATION_1_2_SETTING; 6362306a36Sopenharmony_ci break; 6462306a36Sopenharmony_ci case 1: 6562306a36Sopenharmony_ci setting_0 = GENERATION_1_2_SETTING; 6662306a36Sopenharmony_ci setting_1 = GENERATION_2_3_SETTING; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci case 2: 6962306a36Sopenharmony_ci setting_0 = GENERATION_2_3_SETTING; 7062306a36Sopenharmony_ci setting_1 = GENERATION_3_4_SETTING; 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Set: 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * Transmitter Emphasis Enable 7762306a36Sopenharmony_ci * Transmitter Emphasis Amplitude 7862306a36Sopenharmony_ci * Transmitter Amplitude 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, setting_0); 8162306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 8262306a36Sopenharmony_ci tmp &= ~(0xFBE << 16); 8362306a36Sopenharmony_ci tmp |= (((phy_tuning.trans_emp_en << 11) | 8462306a36Sopenharmony_ci (phy_tuning.trans_emp_amp << 7) | 8562306a36Sopenharmony_ci (phy_tuning.trans_amp << 1)) << 16); 8662306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Set Transmitter Amplitude Adjust */ 8962306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, setting_1); 9062306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 9162306a36Sopenharmony_ci tmp &= ~(0xC000); 9262306a36Sopenharmony_ci tmp |= (phy_tuning.trans_amp_adj << 14); 9362306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id, 9862306a36Sopenharmony_ci struct ffe_control ffe) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci u32 tmp; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Don't run this if A0/B0 */ 10362306a36Sopenharmony_ci if ((mvi->pdev->revision == VANIR_A0_REV) 10462306a36Sopenharmony_ci || (mvi->pdev->revision == VANIR_B0_REV)) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* FFE Resistor and Capacitor */ 10862306a36Sopenharmony_ci /* R10Ch DFE Resolution Control/Squelch and FFE Setting 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * FFE_FORCE [7] 11162306a36Sopenharmony_ci * FFE_RES_SEL [6:4] 11262306a36Sopenharmony_ci * FFE_CAP_SEL [3:0] 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL); 11562306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 11662306a36Sopenharmony_ci tmp &= ~0xFF; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Read from HBA_Info_Page */ 11962306a36Sopenharmony_ci tmp |= ((0x1 << 7) | 12062306a36Sopenharmony_ci (ffe.ffe_rss_sel << 4) | 12162306a36Sopenharmony_ci (ffe.ffe_cap_sel << 0)); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* R064h PHY Mode Register 1 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * DFE_DIS 18 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); 13062306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 13162306a36Sopenharmony_ci tmp &= ~0x40001; 13262306a36Sopenharmony_ci /* Hard coding */ 13362306a36Sopenharmony_ci /* No defines in HBA_Info_Page */ 13462306a36Sopenharmony_ci tmp |= (0 << 18); 13562306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* R110h DFE F0-F1 Coefficient Control/DFE Update Control 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * DFE_UPDATE_EN [11:6] 14062306a36Sopenharmony_ci * DFE_FX_FORCE [5:0] 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_DFE_UPDATE_CRTL); 14362306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 14462306a36Sopenharmony_ci tmp &= ~0xFFF; 14562306a36Sopenharmony_ci /* Hard coding */ 14662306a36Sopenharmony_ci /* No defines in HBA_Info_Page */ 14762306a36Sopenharmony_ci tmp |= ((0x3F << 6) | (0x0 << 0)); 14862306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* R1A0h Interface and Digital Reference Clock Control/Reserved_50h 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * FFE_TRAIN_EN 3 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); 15562306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 15662306a36Sopenharmony_ci tmp &= ~0x8; 15762306a36Sopenharmony_ci /* Hard coding */ 15862306a36Sopenharmony_ci /* No defines in HBA_Info_Page */ 15962306a36Sopenharmony_ci tmp |= (0 << 3); 16062306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/*Notice: this function must be called when phy is disabled*/ 16462306a36Sopenharmony_cistatic void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci union reg_phy_cfg phy_cfg, phy_cfg_tmp; 16762306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 16862306a36Sopenharmony_ci phy_cfg_tmp.v = mvs_read_port_vsr_data(mvi, phy_id); 16962306a36Sopenharmony_ci phy_cfg.v = 0; 17062306a36Sopenharmony_ci phy_cfg.u.disable_phy = phy_cfg_tmp.u.disable_phy; 17162306a36Sopenharmony_ci phy_cfg.u.sas_support = 1; 17262306a36Sopenharmony_ci phy_cfg.u.sata_support = 1; 17362306a36Sopenharmony_ci phy_cfg.u.sata_host_mode = 1; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci switch (rate) { 17662306a36Sopenharmony_ci case 0x0: 17762306a36Sopenharmony_ci /* support 1.5 Gbps */ 17862306a36Sopenharmony_ci phy_cfg.u.speed_support = 1; 17962306a36Sopenharmony_ci phy_cfg.u.snw_3_support = 0; 18062306a36Sopenharmony_ci phy_cfg.u.tx_lnk_parity = 1; 18162306a36Sopenharmony_ci phy_cfg.u.tx_spt_phs_lnk_rate = 0x30; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case 0x1: 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* support 1.5, 3.0 Gbps */ 18662306a36Sopenharmony_ci phy_cfg.u.speed_support = 3; 18762306a36Sopenharmony_ci phy_cfg.u.tx_spt_phs_lnk_rate = 0x3c; 18862306a36Sopenharmony_ci phy_cfg.u.tx_lgcl_lnk_rate = 0x08; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci case 0x2: 19162306a36Sopenharmony_ci default: 19262306a36Sopenharmony_ci /* support 1.5, 3.0, 6.0 Gbps */ 19362306a36Sopenharmony_ci phy_cfg.u.speed_support = 7; 19462306a36Sopenharmony_ci phy_cfg.u.snw_3_support = 1; 19562306a36Sopenharmony_ci phy_cfg.u.tx_lnk_parity = 1; 19662306a36Sopenharmony_ci phy_cfg.u.tx_spt_phs_lnk_rate = 0x3f; 19762306a36Sopenharmony_ci phy_cfg.u.tx_lgcl_lnk_rate = 0x09; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci u32 temp; 20662306a36Sopenharmony_ci temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]); 20762306a36Sopenharmony_ci if (temp == 0xFFFFFFFFL) { 20862306a36Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id].trans_emp_amp = 0x6; 20962306a36Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id].trans_amp = 0x1A; 21062306a36Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id].trans_amp_adj = 0x3; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci temp = (u8)(*(u8 *)&mvi->hba_info_param.ffe_ctl[phy_id]); 21462306a36Sopenharmony_ci if (temp == 0xFFL) { 21562306a36Sopenharmony_ci switch (mvi->pdev->revision) { 21662306a36Sopenharmony_ci case VANIR_A0_REV: 21762306a36Sopenharmony_ci case VANIR_B0_REV: 21862306a36Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; 21962306a36Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0x7; 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci case VANIR_C0_REV: 22262306a36Sopenharmony_ci case VANIR_C1_REV: 22362306a36Sopenharmony_ci case VANIR_C2_REV: 22462306a36Sopenharmony_ci default: 22562306a36Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; 22662306a36Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0xC; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci temp = (u8)(*(u8 *)&mvi->hba_info_param.phy_rate[phy_id]); 23262306a36Sopenharmony_ci if (temp == 0xFFL) 23362306a36Sopenharmony_ci /*set default phy_rate = 6Gbps*/ 23462306a36Sopenharmony_ci mvi->hba_info_param.phy_rate[phy_id] = 0x2; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci set_phy_tuning(mvi, phy_id, 23762306a36Sopenharmony_ci mvi->hba_info_param.phy_tuning[phy_id]); 23862306a36Sopenharmony_ci set_phy_ffe_tuning(mvi, phy_id, 23962306a36Sopenharmony_ci mvi->hba_info_param.ffe_ctl[phy_id]); 24062306a36Sopenharmony_ci set_phy_rate(mvi, phy_id, 24162306a36Sopenharmony_ci mvi->hba_info_param.phy_rate[phy_id]); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 24762306a36Sopenharmony_ci u32 tmp; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 25062306a36Sopenharmony_ci tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); 25162306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci u32 tmp; 25762306a36Sopenharmony_ci u32 delay = 5000; 25862306a36Sopenharmony_ci if (hard == MVS_PHY_TUNE) { 25962306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, phy_id, PHYR_SATA_CTL); 26062306a36Sopenharmony_ci tmp = mvs_read_port_cfg_data(mvi, phy_id); 26162306a36Sopenharmony_ci mvs_write_port_cfg_data(mvi, phy_id, tmp|0x20000000); 26262306a36Sopenharmony_ci mvs_write_port_cfg_data(mvi, phy_id, tmp|0x100000); 26362306a36Sopenharmony_ci return; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, phy_id); 26662306a36Sopenharmony_ci tmp &= ~PHYEV_RDY_CH; 26762306a36Sopenharmony_ci mvs_write_port_irq_stat(mvi, phy_id, tmp); 26862306a36Sopenharmony_ci if (hard) { 26962306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 27062306a36Sopenharmony_ci tmp |= PHY_RST_HARD; 27162306a36Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 27262306a36Sopenharmony_ci do { 27362306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 27462306a36Sopenharmony_ci udelay(10); 27562306a36Sopenharmony_ci delay--; 27662306a36Sopenharmony_ci } while ((tmp & PHY_RST_HARD) && delay); 27762306a36Sopenharmony_ci if (!delay) 27862306a36Sopenharmony_ci mv_dprintk("phy hard reset failed.\n"); 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 28162306a36Sopenharmony_ci tmp |= PHY_RST; 28262306a36Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci u32 tmp; 28962306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 29062306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 29162306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci u32 tmp; 29762306a36Sopenharmony_ci u8 revision = 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci revision = mvi->pdev->revision; 30062306a36Sopenharmony_ci if (revision == VANIR_A0_REV) { 30162306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); 30262306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci if (revision == VANIR_B0_REV) { 30562306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, CMD_APP_MEM_CTL); 30662306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, 0x08001006); 30762306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); 30862306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 31262306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, phy_id); 31362306a36Sopenharmony_ci tmp |= bit(0); 31462306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void mvs_94xx_sgpio_init(struct mvs_info *mvi) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 32062306a36Sopenharmony_ci u32 tmp; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci tmp = mr32(MVS_HST_CHIP_CONFIG); 32362306a36Sopenharmony_ci tmp |= 0x100; 32462306a36Sopenharmony_ci mw32(MVS_HST_CHIP_CONFIG, tmp); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, 32762306a36Sopenharmony_ci MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id, 33062306a36Sopenharmony_ci 8 << MVS_SGPIO_CFG1_LOWA_SHIFT | 33162306a36Sopenharmony_ci 8 << MVS_SGPIO_CFG1_HIA_SHIFT | 33262306a36Sopenharmony_ci 4 << MVS_SGPIO_CFG1_LOWB_SHIFT | 33362306a36Sopenharmony_ci 4 << MVS_SGPIO_CFG1_HIB_SHIFT | 33462306a36Sopenharmony_ci 2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT | 33562306a36Sopenharmony_ci 1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT 33662306a36Sopenharmony_ci ); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id, 33962306a36Sopenharmony_ci (300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */ 34062306a36Sopenharmony_ci 66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/ 34162306a36Sopenharmony_ci ); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id, 34462306a36Sopenharmony_ci MVS_SGPIO_CFG0_ENABLE | 34562306a36Sopenharmony_ci MVS_SGPIO_CFG0_BLINKA | 34662306a36Sopenharmony_ci MVS_SGPIO_CFG0_BLINKB | 34762306a36Sopenharmony_ci /* 3*4 data bits / PDU */ 34862306a36Sopenharmony_ci (12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT 34962306a36Sopenharmony_ci ); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, 35262306a36Sopenharmony_ci DEFAULT_SGPIO_BITS); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id, 35562306a36Sopenharmony_ci ((mvi->id * 4) + 3) << (8 * 3) | 35662306a36Sopenharmony_ci ((mvi->id * 4) + 2) << (8 * 2) | 35762306a36Sopenharmony_ci ((mvi->id * 4) + 1) << (8 * 1) | 35862306a36Sopenharmony_ci ((mvi->id * 4) + 0) << (8 * 0)); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int mvs_94xx_init(struct mvs_info *mvi) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 36562306a36Sopenharmony_ci int i; 36662306a36Sopenharmony_ci u32 tmp, cctl; 36762306a36Sopenharmony_ci u8 revision; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci revision = mvi->pdev->revision; 37062306a36Sopenharmony_ci mvs_show_pcie_usage(mvi); 37162306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 37262306a36Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 37362306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 37462306a36Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 37562306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Init Chip */ 37962306a36Sopenharmony_ci /* make sure RST is set; HBA_RST /should/ have done that for us */ 38062306a36Sopenharmony_ci cctl = mr32(MVS_CTL) & 0xFFFF; 38162306a36Sopenharmony_ci if (cctl & CCTL_RST) 38262306a36Sopenharmony_ci cctl &= ~CCTL_RST; 38362306a36Sopenharmony_ci else 38462306a36Sopenharmony_ci mw32_f(MVS_CTL, cctl | CCTL_RST); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 38762306a36Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 38862306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 38962306a36Sopenharmony_ci tmp |= PCTL_COM_ON; 39062306a36Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 39162306a36Sopenharmony_ci tmp |= PCTL_LINK_RST; 39262306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 39362306a36Sopenharmony_ci msleep(100); 39462306a36Sopenharmony_ci tmp &= ~PCTL_LINK_RST; 39562306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 39662306a36Sopenharmony_ci msleep(100); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* disable Multiplexing, enable phy implemented */ 40062306a36Sopenharmony_ci mw32(MVS_PORTS_IMP, 0xFF); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (revision == VANIR_A0_REV) { 40362306a36Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, CMD_CMWK_OOB_DET); 40462306a36Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x00018080); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE2); 40762306a36Sopenharmony_ci if (revision == VANIR_A0_REV || revision == VANIR_B0_REV) 40862306a36Sopenharmony_ci /* set 6G/3G/1.5G, multiplexing, without SSC */ 40962306a36Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x0084d4fe); 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci /* set 6G/3G/1.5G, multiplexing, with and without SSC */ 41262306a36Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x0084fffe); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (revision == VANIR_B0_REV) { 41562306a36Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, CMD_APP_MEM_CTL); 41662306a36Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x08001006); 41762306a36Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, CMD_HOST_RD_DATA); 41862306a36Sopenharmony_ci mw32(MVS_PA_VSR_PORT, 0x0000705f); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* reset control */ 42262306a36Sopenharmony_ci mw32(MVS_PCS, 0); /* MVS_PCS */ 42362306a36Sopenharmony_ci mw32(MVS_STP_REG_SET_0, 0); 42462306a36Sopenharmony_ci mw32(MVS_STP_REG_SET_1, 0); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* init phys */ 42762306a36Sopenharmony_ci mvs_phy_hacks(mvi); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* disable non data frame retry */ 43062306a36Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_SAS_CTL1); 43162306a36Sopenharmony_ci if ((revision == VANIR_A0_REV) || 43262306a36Sopenharmony_ci (revision == VANIR_B0_REV) || 43362306a36Sopenharmony_ci (revision == VANIR_C0_REV)) { 43462306a36Sopenharmony_ci tmp &= ~0xffff; 43562306a36Sopenharmony_ci tmp |= 0x007f; 43662306a36Sopenharmony_ci mvs_cw32(mvi, CMD_SAS_CTL1, tmp); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* set LED blink when IO*/ 44062306a36Sopenharmony_ci mw32(MVS_PA_VSR_ADDR, VSR_PHY_ACT_LED); 44162306a36Sopenharmony_ci tmp = mr32(MVS_PA_VSR_PORT); 44262306a36Sopenharmony_ci tmp &= 0xFFFF00FF; 44362306a36Sopenharmony_ci tmp |= 0x00003300; 44462306a36Sopenharmony_ci mw32(MVS_PA_VSR_PORT, tmp); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci mw32(MVS_CMD_LIST_LO, mvi->slot_dma); 44762306a36Sopenharmony_ci mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); 45062306a36Sopenharmony_ci mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); 45362306a36Sopenharmony_ci mw32(MVS_TX_LO, mvi->tx_dma); 45462306a36Sopenharmony_ci mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ); 45762306a36Sopenharmony_ci mw32(MVS_RX_LO, mvi->rx_dma); 45862306a36Sopenharmony_ci mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 46162306a36Sopenharmony_ci mvs_94xx_phy_disable(mvi, i); 46262306a36Sopenharmony_ci /* set phy local SAS address */ 46362306a36Sopenharmony_ci mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4, 46462306a36Sopenharmony_ci cpu_to_le64(mvi->phy[i].dev_sas_addr)); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci mvs_94xx_enable_xmt(mvi, i); 46762306a36Sopenharmony_ci mvs_94xx_config_reg_from_hba(mvi, i); 46862306a36Sopenharmony_ci mvs_94xx_phy_enable(mvi, i); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci mvs_94xx_phy_reset(mvi, i, PHY_RST_HARD); 47162306a36Sopenharmony_ci msleep(500); 47262306a36Sopenharmony_ci mvs_94xx_detect_porttype(mvi, i); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 47662306a36Sopenharmony_ci /* set select registers */ 47762306a36Sopenharmony_ci writel(0x0E008000, regs + 0x000); 47862306a36Sopenharmony_ci writel(0x59000008, regs + 0x004); 47962306a36Sopenharmony_ci writel(0x20, regs + 0x008); 48062306a36Sopenharmony_ci writel(0x20, regs + 0x00c); 48162306a36Sopenharmony_ci writel(0x20, regs + 0x010); 48262306a36Sopenharmony_ci writel(0x20, regs + 0x014); 48362306a36Sopenharmony_ci writel(0x20, regs + 0x018); 48462306a36Sopenharmony_ci writel(0x20, regs + 0x01c); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 48762306a36Sopenharmony_ci /* clear phy int status */ 48862306a36Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, i); 48962306a36Sopenharmony_ci tmp &= ~PHYEV_SIG_FIS; 49062306a36Sopenharmony_ci mvs_write_port_irq_stat(mvi, i, tmp); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* set phy int mask */ 49362306a36Sopenharmony_ci tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | 49462306a36Sopenharmony_ci PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ; 49562306a36Sopenharmony_ci mvs_write_port_irq_mask(mvi, i, tmp); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci msleep(100); 49862306a36Sopenharmony_ci mvs_update_phyinfo(mvi, i, 1); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* little endian for open address and command table, etc. */ 50262306a36Sopenharmony_ci cctl = mr32(MVS_CTL); 50362306a36Sopenharmony_ci cctl |= CCTL_ENDIAN_CMD; 50462306a36Sopenharmony_ci cctl &= ~CCTL_ENDIAN_OPEN; 50562306a36Sopenharmony_ci cctl |= CCTL_ENDIAN_RSP; 50662306a36Sopenharmony_ci mw32_f(MVS_CTL, cctl); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* reset CMD queue */ 50962306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 51062306a36Sopenharmony_ci tmp |= PCS_CMD_RST; 51162306a36Sopenharmony_ci tmp &= ~PCS_SELF_CLEAR; 51262306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 51362306a36Sopenharmony_ci /* 51462306a36Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 51562306a36Sopenharmony_ci * it will make count 0. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci tmp = 0; 51862306a36Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 51962306a36Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff | COAL_EN); 52062306a36Sopenharmony_ci else 52162306a36Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* default interrupt coalescing time is 128us */ 52462306a36Sopenharmony_ci tmp = 0x10000 | interrupt_coalescing; 52562306a36Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* ladies and gentlemen, start your engines */ 52862306a36Sopenharmony_ci mw32(MVS_TX_CFG, 0); 52962306a36Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 53062306a36Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); 53162306a36Sopenharmony_ci /* enable CMD/CMPL_Q/RESP mode */ 53262306a36Sopenharmony_ci mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN | 53362306a36Sopenharmony_ci PCS_CMD_EN | PCS_CMD_STOP_ERR); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* enable completion queue interrupt */ 53662306a36Sopenharmony_ci tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | 53762306a36Sopenharmony_ci CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR); 53862306a36Sopenharmony_ci tmp |= CINT_PHY_MASK; 53962306a36Sopenharmony_ci mw32(MVS_INT_MASK, tmp); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_LINK_TIMER); 54262306a36Sopenharmony_ci tmp |= 0xFFFF0000; 54362306a36Sopenharmony_ci mvs_cw32(mvi, CMD_LINK_TIMER, tmp); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* tune STP performance */ 54662306a36Sopenharmony_ci tmp = 0x003F003F; 54762306a36Sopenharmony_ci mvs_cw32(mvi, CMD_PL_TIMER, tmp); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* This can improve expander large block size seq write performance */ 55062306a36Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_PORT_LAYER_TIMER1); 55162306a36Sopenharmony_ci tmp |= 0xFFFF007F; 55262306a36Sopenharmony_ci mvs_cw32(mvi, CMD_PORT_LAYER_TIMER1, tmp); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* change the connection open-close behavior (bit 9) 55562306a36Sopenharmony_ci * set bit8 to 1 for performance tuning */ 55662306a36Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_SL_MODE0); 55762306a36Sopenharmony_ci tmp |= 0x00000300; 55862306a36Sopenharmony_ci /* set bit0 to 0 to enable retry for no_dest reject case */ 55962306a36Sopenharmony_ci tmp &= 0xFFFFFFFE; 56062306a36Sopenharmony_ci mvs_cw32(mvi, CMD_SL_MODE0, tmp); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Enable SRS interrupt */ 56362306a36Sopenharmony_ci mw32(MVS_INT_MASK_SRS_0, 0xFFFF); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci mvs_94xx_sgpio_init(mvi); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int mvs_94xx_ioremap(struct mvs_info *mvi) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci if (!mvs_ioremap(mvi, 2, -1)) { 57362306a36Sopenharmony_ci mvi->regs_ex = mvi->regs + 0x10200; 57462306a36Sopenharmony_ci mvi->regs += 0x20000; 57562306a36Sopenharmony_ci if (mvi->id == 1) 57662306a36Sopenharmony_ci mvi->regs += 0x4000; 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci return -1; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void mvs_94xx_iounmap(struct mvs_info *mvi) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci if (mvi->regs) { 58562306a36Sopenharmony_ci mvi->regs -= 0x20000; 58662306a36Sopenharmony_ci if (mvi->id == 1) 58762306a36Sopenharmony_ci mvi->regs -= 0x4000; 58862306a36Sopenharmony_ci mvs_iounmap(mvi->regs); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic void mvs_94xx_interrupt_enable(struct mvs_info *mvi) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 59562306a36Sopenharmony_ci u32 tmp; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 59862306a36Sopenharmony_ci tmp |= (MVS_IRQ_SAS_A | MVS_IRQ_SAS_B); 59962306a36Sopenharmony_ci mw32(MVS_GBL_INT_STAT, tmp); 60062306a36Sopenharmony_ci writel(tmp, regs + 0x0C); 60162306a36Sopenharmony_ci writel(tmp, regs + 0x10); 60262306a36Sopenharmony_ci writel(tmp, regs + 0x14); 60362306a36Sopenharmony_ci writel(tmp, regs + 0x18); 60462306a36Sopenharmony_ci mw32(MVS_GBL_CTL, tmp); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void mvs_94xx_interrupt_disable(struct mvs_info *mvi) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 61062306a36Sopenharmony_ci u32 tmp; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci tmp &= ~(MVS_IRQ_SAS_A | MVS_IRQ_SAS_B); 61562306a36Sopenharmony_ci mw32(MVS_GBL_INT_STAT, tmp); 61662306a36Sopenharmony_ci writel(tmp, regs + 0x0C); 61762306a36Sopenharmony_ci writel(tmp, regs + 0x10); 61862306a36Sopenharmony_ci writel(tmp, regs + 0x14); 61962306a36Sopenharmony_ci writel(tmp, regs + 0x18); 62062306a36Sopenharmony_ci mw32(MVS_GBL_CTL, tmp); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 62662306a36Sopenharmony_ci u32 stat = 0; 62762306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 62862306a36Sopenharmony_ci stat = mr32(MVS_GBL_INT_STAT); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!(stat & (MVS_IRQ_SAS_A | MVS_IRQ_SAS_B))) 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci return stat; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (((stat & MVS_IRQ_SAS_A) && mvi->id == 0) || 64162306a36Sopenharmony_ci ((stat & MVS_IRQ_SAS_B) && mvi->id == 1)) { 64262306a36Sopenharmony_ci mw32_f(MVS_INT_STAT, CINT_DONE); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci spin_lock(&mvi->lock); 64562306a36Sopenharmony_ci mvs_int_full(mvi); 64662306a36Sopenharmony_ci spin_unlock(&mvi->lock); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci return IRQ_HANDLED; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci u32 tmp; 65462306a36Sopenharmony_ci tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3)); 65562306a36Sopenharmony_ci if (tmp & 1 << (slot_idx % 32)) { 65662306a36Sopenharmony_ci mv_printk("command active %08X, slot [%x].\n", tmp, slot_idx); 65762306a36Sopenharmony_ci mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3), 65862306a36Sopenharmony_ci 1 << (slot_idx % 32)); 65962306a36Sopenharmony_ci do { 66062306a36Sopenharmony_ci tmp = mvs_cr32(mvi, 66162306a36Sopenharmony_ci MVS_COMMAND_ACTIVE + (slot_idx >> 3)); 66262306a36Sopenharmony_ci } while (tmp & 1 << (slot_idx % 32)); 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void 66762306a36Sopenharmony_cimvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 67062306a36Sopenharmony_ci u32 tmp; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (clear_all) { 67362306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 67462306a36Sopenharmony_ci if (tmp) { 67562306a36Sopenharmony_ci mv_dprintk("check SRS 0 %08X.\n", tmp); 67662306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_1); 67962306a36Sopenharmony_ci if (tmp) { 68062306a36Sopenharmony_ci mv_dprintk("check SRS 1 %08X.\n", tmp); 68162306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_1, tmp); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci } else { 68462306a36Sopenharmony_ci if (reg_set > 31) 68562306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_1); 68662306a36Sopenharmony_ci else 68762306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (tmp & (1 << (reg_set % 32))) { 69062306a36Sopenharmony_ci mv_dprintk("register set 0x%x was stopped.\n", reg_set); 69162306a36Sopenharmony_ci if (reg_set > 31) 69262306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_1, 1 << (reg_set % 32)); 69362306a36Sopenharmony_ci else 69462306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, 70062306a36Sopenharmony_ci u32 tfs) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 70362306a36Sopenharmony_ci u32 tmp; 70462306a36Sopenharmony_ci mvs_94xx_clear_srs_irq(mvi, 0, 1); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT); 70762306a36Sopenharmony_ci mw32(MVS_INT_STAT, tmp | CINT_CI_STOP); 70862306a36Sopenharmony_ci tmp = mr32(MVS_PCS) | 0xFF00; 70962306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 71562306a36Sopenharmony_ci u32 err_0, err_1; 71662306a36Sopenharmony_ci u8 i; 71762306a36Sopenharmony_ci struct mvs_device *device; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci err_0 = mr32(MVS_NON_NCQ_ERR_0); 72062306a36Sopenharmony_ci err_1 = mr32(MVS_NON_NCQ_ERR_1); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n", 72362306a36Sopenharmony_ci err_0, err_1); 72462306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 72562306a36Sopenharmony_ci if (err_0 & bit(i)) { 72662306a36Sopenharmony_ci device = mvs_find_dev_by_reg_set(mvi, i); 72762306a36Sopenharmony_ci if (device) 72862306a36Sopenharmony_ci mvs_release_task(mvi, device->sas_device); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci if (err_1 & bit(i)) { 73162306a36Sopenharmony_ci device = mvs_find_dev_by_reg_set(mvi, i+32); 73262306a36Sopenharmony_ci if (device) 73362306a36Sopenharmony_ci mvs_release_task(mvi, device->sas_device); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci mw32(MVS_NON_NCQ_ERR_0, err_0); 73862306a36Sopenharmony_ci mw32(MVS_NON_NCQ_ERR_1, err_1); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 74462306a36Sopenharmony_ci u8 reg_set = *tfs; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (*tfs == MVS_ID_NOT_MAPPED) 74762306a36Sopenharmony_ci return; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci mvi->sata_reg_set &= ~bit(reg_set); 75062306a36Sopenharmony_ci if (reg_set < 32) 75162306a36Sopenharmony_ci w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set); 75262306a36Sopenharmony_ci else 75362306a36Sopenharmony_ci w_reg_set_enable(reg_set, (u32)(mvi->sata_reg_set >> 32)); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci *tfs = MVS_ID_NOT_MAPPED; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci int i; 76362306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (*tfs != MVS_ID_NOT_MAPPED) 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci i = mv_ffc64(mvi->sata_reg_set); 76962306a36Sopenharmony_ci if (i >= 32) { 77062306a36Sopenharmony_ci mvi->sata_reg_set |= bit(i); 77162306a36Sopenharmony_ci w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32)); 77262306a36Sopenharmony_ci *tfs = i; 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci } else if (i >= 0) { 77562306a36Sopenharmony_ci mvi->sata_reg_set |= bit(i); 77662306a36Sopenharmony_ci w_reg_set_enable(i, (u32)mvi->sata_reg_set); 77762306a36Sopenharmony_ci *tfs = i; 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci return MVS_ID_NOT_MAPPED; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci int i; 78662306a36Sopenharmony_ci struct scatterlist *sg; 78762306a36Sopenharmony_ci struct mvs_prd *buf_prd = prd; 78862306a36Sopenharmony_ci struct mvs_prd_imt im_len; 78962306a36Sopenharmony_ci *(u32 *)&im_len = 0; 79062306a36Sopenharmony_ci for_each_sg(scatter, sg, nr, i) { 79162306a36Sopenharmony_ci buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 79262306a36Sopenharmony_ci im_len.len = sg_dma_len(sg); 79362306a36Sopenharmony_ci buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len); 79462306a36Sopenharmony_ci buf_prd++; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int mvs_94xx_oob_done(struct mvs_info *mvi, int i) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci u32 phy_st; 80162306a36Sopenharmony_ci phy_st = mvs_read_phy_ctl(mvi, i); 80262306a36Sopenharmony_ci if (phy_st & PHY_READY_MASK) 80362306a36Sopenharmony_ci return 1; 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id, 80862306a36Sopenharmony_ci struct sas_identify_frame *id) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci int i; 81162306a36Sopenharmony_ci u32 id_frame[7]; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 81462306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, port_id, 81562306a36Sopenharmony_ci CONFIG_ID_FRAME0 + i * 4); 81662306a36Sopenharmony_ci id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci memcpy(id, id_frame, 28); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id, 82262306a36Sopenharmony_ci struct sas_identify_frame *id) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int i; 82562306a36Sopenharmony_ci u32 id_frame[7]; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 82862306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, port_id, 82962306a36Sopenharmony_ci CONFIG_ATT_ID_FRAME0 + i * 4); 83062306a36Sopenharmony_ci id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); 83162306a36Sopenharmony_ci mv_dprintk("94xx phy %d atta frame %d %x.\n", 83262306a36Sopenharmony_ci port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci memcpy(id, id_frame, 28); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci u32 att_dev_info = 0; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci att_dev_info |= id->dev_type; 84262306a36Sopenharmony_ci if (id->stp_iport) 84362306a36Sopenharmony_ci att_dev_info |= PORT_DEV_STP_INIT; 84462306a36Sopenharmony_ci if (id->smp_iport) 84562306a36Sopenharmony_ci att_dev_info |= PORT_DEV_SMP_INIT; 84662306a36Sopenharmony_ci if (id->ssp_iport) 84762306a36Sopenharmony_ci att_dev_info |= PORT_DEV_SSP_INIT; 84862306a36Sopenharmony_ci if (id->stp_tport) 84962306a36Sopenharmony_ci att_dev_info |= PORT_DEV_STP_TRGT; 85062306a36Sopenharmony_ci if (id->smp_tport) 85162306a36Sopenharmony_ci att_dev_info |= PORT_DEV_SMP_TRGT; 85262306a36Sopenharmony_ci if (id->ssp_tport) 85362306a36Sopenharmony_ci att_dev_info |= PORT_DEV_SSP_TRGT; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci att_dev_info |= (u32)id->phy_id<<24; 85662306a36Sopenharmony_ci return att_dev_info; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic u32 mvs_94xx_make_att_info(struct sas_identify_frame *id) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci return mvs_94xx_make_dev_info(id); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i, 86562306a36Sopenharmony_ci struct sas_identify_frame *id) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 86862306a36Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 86962306a36Sopenharmony_ci mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status); 87062306a36Sopenharmony_ci sas_phy->linkrate = 87162306a36Sopenharmony_ci (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 87262306a36Sopenharmony_ci PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 87362306a36Sopenharmony_ci sas_phy->linkrate += 0x8; 87462306a36Sopenharmony_ci mv_dprintk("get link rate is %d\n", sas_phy->linkrate); 87562306a36Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; 87662306a36Sopenharmony_ci phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS; 87762306a36Sopenharmony_ci mvs_94xx_get_dev_identify_frame(mvi, i, id); 87862306a36Sopenharmony_ci phy->dev_info = mvs_94xx_make_dev_info(id); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 88162306a36Sopenharmony_ci mvs_94xx_get_att_identify_frame(mvi, i, id); 88262306a36Sopenharmony_ci phy->att_dev_info = mvs_94xx_make_att_info(id); 88362306a36Sopenharmony_ci phy->att_dev_sas_addr = *(u64 *)id->sas_addr; 88462306a36Sopenharmony_ci } else { 88562306a36Sopenharmony_ci phy->att_dev_info = PORT_DEV_STP_TRGT | 1; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* enable spin up bit */ 88962306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 89062306a36Sopenharmony_ci mvs_write_port_cfg_data(mvi, i, 0x04); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, 89562306a36Sopenharmony_ci struct sas_phy_linkrates *rates) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci u32 lrmax = 0; 89862306a36Sopenharmony_ci u32 tmp; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 90162306a36Sopenharmony_ci lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (lrmax) { 90462306a36Sopenharmony_ci tmp &= ~(0x3 << 12); 90562306a36Sopenharmony_ci tmp |= lrmax; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 90862306a36Sopenharmony_ci mvs_94xx_phy_reset(mvi, phy_id, PHY_RST_HARD); 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic void mvs_94xx_clear_active_cmds(struct mvs_info *mvi) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci u32 tmp; 91462306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 91562306a36Sopenharmony_ci tmp = mr32(MVS_STP_REG_SET_0); 91662306a36Sopenharmony_ci mw32(MVS_STP_REG_SET_0, 0); 91762306a36Sopenharmony_ci mw32(MVS_STP_REG_SET_0, tmp); 91862306a36Sopenharmony_ci tmp = mr32(MVS_STP_REG_SET_1); 91962306a36Sopenharmony_ci mw32(MVS_STP_REG_SET_1, 0); 92062306a36Sopenharmony_ci mw32(MVS_STP_REG_SET_1, tmp); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic u32 mvs_94xx_spi_read_data(struct mvs_info *mvi) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 92762306a36Sopenharmony_ci return mr32(SPI_RD_DATA_REG_94XX); 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci mw32(SPI_RD_DATA_REG_94XX, data); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic int mvs_94xx_spi_buildcmd(struct mvs_info *mvi, 93962306a36Sopenharmony_ci u32 *dwCmd, 94062306a36Sopenharmony_ci u8 cmd, 94162306a36Sopenharmony_ci u8 read, 94262306a36Sopenharmony_ci u8 length, 94362306a36Sopenharmony_ci u32 addr 94462306a36Sopenharmony_ci ) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 94762306a36Sopenharmony_ci u32 dwTmp; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci dwTmp = ((u32)cmd << 8) | ((u32)length << 4); 95062306a36Sopenharmony_ci if (read) 95162306a36Sopenharmony_ci dwTmp |= SPI_CTRL_READ_94XX; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (addr != MV_MAX_U32) { 95462306a36Sopenharmony_ci mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL)); 95562306a36Sopenharmony_ci dwTmp |= SPI_ADDR_VLD_94XX; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci *dwCmd = dwTmp; 95962306a36Sopenharmony_ci return 0; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 96662306a36Sopenharmony_ci mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci return 0; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 97462306a36Sopenharmony_ci u32 i, dwTmp; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 97762306a36Sopenharmony_ci dwTmp = mr32(SPI_CTRL_REG_94XX); 97862306a36Sopenharmony_ci if (!(dwTmp & SPI_CTRL_SpiStart_94XX)) 97962306a36Sopenharmony_ci return 0; 98062306a36Sopenharmony_ci msleep(10); 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci return -1; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask, 98762306a36Sopenharmony_ci int buf_len, int from, void *prd) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci int i; 99062306a36Sopenharmony_ci struct mvs_prd *buf_prd = prd; 99162306a36Sopenharmony_ci dma_addr_t buf_dma; 99262306a36Sopenharmony_ci struct mvs_prd_imt im_len; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci *(u32 *)&im_len = 0; 99562306a36Sopenharmony_ci buf_prd += from; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci#define PRD_CHAINED_ENTRY 0x01 99862306a36Sopenharmony_ci if ((mvi->pdev->revision == VANIR_A0_REV) || 99962306a36Sopenharmony_ci (mvi->pdev->revision == VANIR_B0_REV)) 100062306a36Sopenharmony_ci buf_dma = (phy_mask <= 0x08) ? 100162306a36Sopenharmony_ci mvi->bulk_buffer_dma : mvi->bulk_buffer_dma1; 100262306a36Sopenharmony_ci else 100362306a36Sopenharmony_ci return; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci for (i = from; i < MAX_SG_ENTRY; i++, ++buf_prd) { 100662306a36Sopenharmony_ci if (i == MAX_SG_ENTRY - 1) { 100762306a36Sopenharmony_ci buf_prd->addr = cpu_to_le64(virt_to_phys(buf_prd - 1)); 100862306a36Sopenharmony_ci im_len.len = 2; 100962306a36Sopenharmony_ci im_len.misc_ctl = PRD_CHAINED_ENTRY; 101062306a36Sopenharmony_ci } else { 101162306a36Sopenharmony_ci buf_prd->addr = cpu_to_le64(buf_dma); 101262306a36Sopenharmony_ci im_len.len = buf_len; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 102162306a36Sopenharmony_ci u32 tmp = 0; 102262306a36Sopenharmony_ci /* 102362306a36Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 102462306a36Sopenharmony_ci * it will make count 0. 102562306a36Sopenharmony_ci */ 102662306a36Sopenharmony_ci if (time == 0) { 102762306a36Sopenharmony_ci mw32(MVS_INT_COAL, 0); 102862306a36Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, 0x10000); 102962306a36Sopenharmony_ci } else { 103062306a36Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 103162306a36Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff|COAL_EN); 103262306a36Sopenharmony_ci else 103362306a36Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci tmp = 0x10000 | time; 103662306a36Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, 104262306a36Sopenharmony_ci u8 reg_type, u8 reg_index, 104362306a36Sopenharmony_ci u8 reg_count, u8 *write_data) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci int i; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci switch (reg_type) { 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci case SAS_GPIO_REG_TX_GP: 105062306a36Sopenharmony_ci if (reg_index == 0) 105162306a36Sopenharmony_ci return -EINVAL; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (reg_count > 1) 105462306a36Sopenharmony_ci return -EINVAL; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (reg_count == 0) 105762306a36Sopenharmony_ci return 0; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* maximum supported bits = hosts * 4 drives * 3 bits */ 106062306a36Sopenharmony_ci for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) { 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* select host */ 106362306a36Sopenharmony_ci struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)]; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci int drive = (i/3) & (4-1); /* drive number on host */ 106862306a36Sopenharmony_ci int driveshift = drive * 8; /* bit offset of drive */ 106962306a36Sopenharmony_ci u32 block = ioread32be(regs + MVS_SGPIO_DCTRL + 107062306a36Sopenharmony_ci MVS_SGPIO_HOST_OFFSET * mvi->id); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* 107362306a36Sopenharmony_ci * if bit is set then create a mask with the first 107462306a36Sopenharmony_ci * bit of the drive set in the mask ... 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci u32 bit = get_unaligned_be32(write_data) & (1 << i) ? 107762306a36Sopenharmony_ci 1 << driveshift : 0; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* 108062306a36Sopenharmony_ci * ... and then shift it to the right position based 108162306a36Sopenharmony_ci * on the led type (activity/id/fail) 108262306a36Sopenharmony_ci */ 108362306a36Sopenharmony_ci switch (i%3) { 108462306a36Sopenharmony_ci case 0: /* activity */ 108562306a36Sopenharmony_ci block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT) 108662306a36Sopenharmony_ci << driveshift); 108762306a36Sopenharmony_ci /* hardwire activity bit to SOF */ 108862306a36Sopenharmony_ci block |= LED_BLINKA_SOF << ( 108962306a36Sopenharmony_ci MVS_SGPIO_DCTRL_ACT_SHIFT + 109062306a36Sopenharmony_ci driveshift); 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci case 1: /* id */ 109362306a36Sopenharmony_ci block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT) 109462306a36Sopenharmony_ci << driveshift); 109562306a36Sopenharmony_ci block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT; 109662306a36Sopenharmony_ci break; 109762306a36Sopenharmony_ci case 2: /* fail */ 109862306a36Sopenharmony_ci block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT) 109962306a36Sopenharmony_ci << driveshift); 110062306a36Sopenharmony_ci block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT; 110162306a36Sopenharmony_ci break; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci iowrite32be(block, 110562306a36Sopenharmony_ci regs + MVS_SGPIO_DCTRL + 110662306a36Sopenharmony_ci MVS_SGPIO_HOST_OFFSET * mvi->id); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return reg_count; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci case SAS_GPIO_REG_TX: 111362306a36Sopenharmony_ci if (reg_index + reg_count > mvs_prv->n_host) 111462306a36Sopenharmony_ci return -EINVAL; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci for (i = 0; i < reg_count; i++) { 111762306a36Sopenharmony_ci struct mvs_info *mvi = mvs_prv->mvi[i+reg_index]; 111862306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex - 0x10200; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, 112162306a36Sopenharmony_ci ((u32 *) write_data)[i]); 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci return reg_count; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci return -ENOSYS; 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ciconst struct mvs_dispatch mvs_94xx_dispatch = { 112962306a36Sopenharmony_ci "mv94xx", 113062306a36Sopenharmony_ci mvs_94xx_init, 113162306a36Sopenharmony_ci NULL, 113262306a36Sopenharmony_ci mvs_94xx_ioremap, 113362306a36Sopenharmony_ci mvs_94xx_iounmap, 113462306a36Sopenharmony_ci mvs_94xx_isr, 113562306a36Sopenharmony_ci mvs_94xx_isr_status, 113662306a36Sopenharmony_ci mvs_94xx_interrupt_enable, 113762306a36Sopenharmony_ci mvs_94xx_interrupt_disable, 113862306a36Sopenharmony_ci mvs_read_phy_ctl, 113962306a36Sopenharmony_ci mvs_write_phy_ctl, 114062306a36Sopenharmony_ci mvs_read_port_cfg_data, 114162306a36Sopenharmony_ci mvs_write_port_cfg_data, 114262306a36Sopenharmony_ci mvs_write_port_cfg_addr, 114362306a36Sopenharmony_ci mvs_read_port_vsr_data, 114462306a36Sopenharmony_ci mvs_write_port_vsr_data, 114562306a36Sopenharmony_ci mvs_write_port_vsr_addr, 114662306a36Sopenharmony_ci mvs_read_port_irq_stat, 114762306a36Sopenharmony_ci mvs_write_port_irq_stat, 114862306a36Sopenharmony_ci mvs_read_port_irq_mask, 114962306a36Sopenharmony_ci mvs_write_port_irq_mask, 115062306a36Sopenharmony_ci mvs_94xx_command_active, 115162306a36Sopenharmony_ci mvs_94xx_clear_srs_irq, 115262306a36Sopenharmony_ci mvs_94xx_issue_stop, 115362306a36Sopenharmony_ci mvs_start_delivery, 115462306a36Sopenharmony_ci mvs_rx_update, 115562306a36Sopenharmony_ci mvs_int_full, 115662306a36Sopenharmony_ci mvs_94xx_assign_reg_set, 115762306a36Sopenharmony_ci mvs_94xx_free_reg_set, 115862306a36Sopenharmony_ci mvs_get_prd_size, 115962306a36Sopenharmony_ci mvs_get_prd_count, 116062306a36Sopenharmony_ci mvs_94xx_make_prd, 116162306a36Sopenharmony_ci mvs_94xx_detect_porttype, 116262306a36Sopenharmony_ci mvs_94xx_oob_done, 116362306a36Sopenharmony_ci mvs_94xx_fix_phy_info, 116462306a36Sopenharmony_ci NULL, 116562306a36Sopenharmony_ci mvs_94xx_phy_set_link_rate, 116662306a36Sopenharmony_ci mvs_hw_max_link_rate, 116762306a36Sopenharmony_ci mvs_94xx_phy_disable, 116862306a36Sopenharmony_ci mvs_94xx_phy_enable, 116962306a36Sopenharmony_ci mvs_94xx_phy_reset, 117062306a36Sopenharmony_ci NULL, 117162306a36Sopenharmony_ci mvs_94xx_clear_active_cmds, 117262306a36Sopenharmony_ci mvs_94xx_spi_read_data, 117362306a36Sopenharmony_ci mvs_94xx_spi_write_data, 117462306a36Sopenharmony_ci mvs_94xx_spi_buildcmd, 117562306a36Sopenharmony_ci mvs_94xx_spi_issuecmd, 117662306a36Sopenharmony_ci mvs_94xx_spi_waitdataready, 117762306a36Sopenharmony_ci mvs_94xx_fix_dma, 117862306a36Sopenharmony_ci mvs_94xx_tune_interrupt, 117962306a36Sopenharmony_ci mvs_94xx_non_spec_ncq_error, 118062306a36Sopenharmony_ci mvs_94xx_gpio_write, 118162306a36Sopenharmony_ci}; 118262306a36Sopenharmony_ci 1183