120b09c29SAndy Yan /* 220b09c29SAndy Yan * Marvell 88SE94xx hardware specific 320b09c29SAndy Yan * 420b09c29SAndy Yan * Copyright 2007 Red Hat, Inc. 520b09c29SAndy Yan * Copyright 2008 Marvell. <kewei@marvell.com> 60b15fb1fSXiangliang Yu * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 720b09c29SAndy Yan * 820b09c29SAndy Yan * This file is licensed under GPLv2. 920b09c29SAndy Yan * 1020b09c29SAndy Yan * This program is free software; you can redistribute it and/or 1120b09c29SAndy Yan * modify it under the terms of the GNU General Public License as 1220b09c29SAndy Yan * published by the Free Software Foundation; version 2 of the 1320b09c29SAndy Yan * License. 1420b09c29SAndy Yan * 1520b09c29SAndy Yan * This program is distributed in the hope that it will be useful, 1620b09c29SAndy Yan * but WITHOUT ANY WARRANTY; without even the implied warranty of 1720b09c29SAndy Yan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1820b09c29SAndy Yan * General Public License for more details. 1920b09c29SAndy Yan * 2020b09c29SAndy Yan * You should have received a copy of the GNU General Public License 2120b09c29SAndy Yan * along with this program; if not, write to the Free Software 2220b09c29SAndy Yan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 2320b09c29SAndy Yan * USA 2420b09c29SAndy Yan */ 2520b09c29SAndy Yan 2620b09c29SAndy Yan #include "mv_sas.h" 2720b09c29SAndy Yan #include "mv_94xx.h" 2820b09c29SAndy Yan #include "mv_chips.h" 2920b09c29SAndy Yan 3020b09c29SAndy Yan static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i) 3120b09c29SAndy Yan { 3220b09c29SAndy Yan u32 reg; 3320b09c29SAndy Yan struct mvs_phy *phy = &mvi->phy[i]; 3420b09c29SAndy Yan u32 phy_status; 3520b09c29SAndy Yan 3620b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3); 3720b09c29SAndy Yan reg = mvs_read_port_vsr_data(mvi, i); 3820b09c29SAndy Yan phy_status = ((reg & 0x3f0000) >> 16) & 0xff; 3920b09c29SAndy Yan phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 4020b09c29SAndy Yan switch (phy_status) { 4120b09c29SAndy Yan case 0x10: 4220b09c29SAndy Yan phy->phy_type |= PORT_TYPE_SAS; 4320b09c29SAndy Yan break; 4420b09c29SAndy Yan case 0x1d: 4520b09c29SAndy Yan default: 4620b09c29SAndy Yan phy->phy_type |= PORT_TYPE_SATA; 4720b09c29SAndy Yan break; 4820b09c29SAndy Yan } 4920b09c29SAndy Yan } 5020b09c29SAndy Yan 51f1f82a91SXiangliang Yu void set_phy_tuning(struct mvs_info *mvi, int phy_id, 52f1f82a91SXiangliang Yu struct phy_tuning phy_tuning) 53f1f82a91SXiangliang Yu { 54f1f82a91SXiangliang Yu u32 tmp, setting_0 = 0, setting_1 = 0; 55f1f82a91SXiangliang Yu u8 i; 56f1f82a91SXiangliang Yu 57f1f82a91SXiangliang Yu /* Remap information for B0 chip: 58f1f82a91SXiangliang Yu * 59f1f82a91SXiangliang Yu * R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient) 60f1f82a91SXiangliang Yu * R0Dh -> R118h[31:16] (Generation 1 Setting 0) 61f1f82a91SXiangliang Yu * R0Eh -> R11Ch[15:0] (Generation 1 Setting 1) 62f1f82a91SXiangliang Yu * R0Fh -> R11Ch[31:16] (Generation 2 Setting 0) 63f1f82a91SXiangliang Yu * R10h -> R120h[15:0] (Generation 2 Setting 1) 64f1f82a91SXiangliang Yu * R11h -> R120h[31:16] (Generation 3 Setting 0) 65f1f82a91SXiangliang Yu * R12h -> R124h[15:0] (Generation 3 Setting 1) 66f1f82a91SXiangliang Yu * R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved)) 67f1f82a91SXiangliang Yu */ 68f1f82a91SXiangliang Yu 69f1f82a91SXiangliang Yu /* A0 has a different set of registers */ 70f1f82a91SXiangliang Yu if (mvi->pdev->revision == VANIR_A0_REV) 71f1f82a91SXiangliang Yu return; 72f1f82a91SXiangliang Yu 73f1f82a91SXiangliang Yu for (i = 0; i < 3; i++) { 74f1f82a91SXiangliang Yu /* loop 3 times, set Gen 1, Gen 2, Gen 3 */ 75f1f82a91SXiangliang Yu switch (i) { 76f1f82a91SXiangliang Yu case 0: 77f1f82a91SXiangliang Yu setting_0 = GENERATION_1_SETTING; 78f1f82a91SXiangliang Yu setting_1 = GENERATION_1_2_SETTING; 79f1f82a91SXiangliang Yu break; 80f1f82a91SXiangliang Yu case 1: 81f1f82a91SXiangliang Yu setting_0 = GENERATION_1_2_SETTING; 82f1f82a91SXiangliang Yu setting_1 = GENERATION_2_3_SETTING; 83f1f82a91SXiangliang Yu break; 84f1f82a91SXiangliang Yu case 2: 85f1f82a91SXiangliang Yu setting_0 = GENERATION_2_3_SETTING; 86f1f82a91SXiangliang Yu setting_1 = GENERATION_3_4_SETTING; 87f1f82a91SXiangliang Yu break; 88f1f82a91SXiangliang Yu } 89f1f82a91SXiangliang Yu 90f1f82a91SXiangliang Yu /* Set: 91f1f82a91SXiangliang Yu * 92f1f82a91SXiangliang Yu * Transmitter Emphasis Enable 93f1f82a91SXiangliang Yu * Transmitter Emphasis Amplitude 94f1f82a91SXiangliang Yu * Transmitter Amplitude 95f1f82a91SXiangliang Yu */ 96f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, setting_0); 97f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 98f1f82a91SXiangliang Yu tmp &= ~(0xFBE << 16); 99f1f82a91SXiangliang Yu tmp |= (((phy_tuning.trans_emp_en << 11) | 100f1f82a91SXiangliang Yu (phy_tuning.trans_emp_amp << 7) | 101f1f82a91SXiangliang Yu (phy_tuning.trans_amp << 1)) << 16); 102f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp); 103f1f82a91SXiangliang Yu 104f1f82a91SXiangliang Yu /* Set Transmitter Amplitude Adjust */ 105f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, setting_1); 106f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 107f1f82a91SXiangliang Yu tmp &= ~(0xC000); 108f1f82a91SXiangliang Yu tmp |= (phy_tuning.trans_amp_adj << 14); 109f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp); 110f1f82a91SXiangliang Yu } 111f1f82a91SXiangliang Yu } 112f1f82a91SXiangliang Yu 113f1f82a91SXiangliang Yu void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id, 114f1f82a91SXiangliang Yu struct ffe_control ffe) 115f1f82a91SXiangliang Yu { 116f1f82a91SXiangliang Yu u32 tmp; 117f1f82a91SXiangliang Yu 118f1f82a91SXiangliang Yu /* Don't run this if A0/B0 */ 119f1f82a91SXiangliang Yu if ((mvi->pdev->revision == VANIR_A0_REV) 120f1f82a91SXiangliang Yu || (mvi->pdev->revision == VANIR_B0_REV)) 121f1f82a91SXiangliang Yu return; 122f1f82a91SXiangliang Yu 123f1f82a91SXiangliang Yu /* FFE Resistor and Capacitor */ 124f1f82a91SXiangliang Yu /* R10Ch DFE Resolution Control/Squelch and FFE Setting 125f1f82a91SXiangliang Yu * 126f1f82a91SXiangliang Yu * FFE_FORCE [7] 127f1f82a91SXiangliang Yu * FFE_RES_SEL [6:4] 128f1f82a91SXiangliang Yu * FFE_CAP_SEL [3:0] 129f1f82a91SXiangliang Yu */ 130f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL); 131f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 132f1f82a91SXiangliang Yu tmp &= ~0xFF; 133f1f82a91SXiangliang Yu 134f1f82a91SXiangliang Yu /* Read from HBA_Info_Page */ 135f1f82a91SXiangliang Yu tmp |= ((0x1 << 7) | 136f1f82a91SXiangliang Yu (ffe.ffe_rss_sel << 4) | 137f1f82a91SXiangliang Yu (ffe.ffe_cap_sel << 0)); 138f1f82a91SXiangliang Yu 139f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp); 140f1f82a91SXiangliang Yu 141f1f82a91SXiangliang Yu /* R064h PHY Mode Register 1 142f1f82a91SXiangliang Yu * 143f1f82a91SXiangliang Yu * DFE_DIS 18 144f1f82a91SXiangliang Yu */ 145f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); 146f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 147f1f82a91SXiangliang Yu tmp &= ~0x40001; 148f1f82a91SXiangliang Yu /* Hard coding */ 149f1f82a91SXiangliang Yu /* No defines in HBA_Info_Page */ 150f1f82a91SXiangliang Yu tmp |= (0 << 18); 151f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp); 152f1f82a91SXiangliang Yu 153f1f82a91SXiangliang Yu /* R110h DFE F0-F1 Coefficient Control/DFE Update Control 154f1f82a91SXiangliang Yu * 155f1f82a91SXiangliang Yu * DFE_UPDATE_EN [11:6] 156f1f82a91SXiangliang Yu * DFE_FX_FORCE [5:0] 157f1f82a91SXiangliang Yu */ 158f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_DFE_UPDATE_CRTL); 159f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 160f1f82a91SXiangliang Yu tmp &= ~0xFFF; 161f1f82a91SXiangliang Yu /* Hard coding */ 162f1f82a91SXiangliang Yu /* No defines in HBA_Info_Page */ 163f1f82a91SXiangliang Yu tmp |= ((0x3F << 6) | (0x0 << 0)); 164f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp); 165f1f82a91SXiangliang Yu 166f1f82a91SXiangliang Yu /* R1A0h Interface and Digital Reference Clock Control/Reserved_50h 167f1f82a91SXiangliang Yu * 168f1f82a91SXiangliang Yu * FFE_TRAIN_EN 3 169f1f82a91SXiangliang Yu */ 170f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); 171f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 172f1f82a91SXiangliang Yu tmp &= ~0x8; 173f1f82a91SXiangliang Yu /* Hard coding */ 174f1f82a91SXiangliang Yu /* No defines in HBA_Info_Page */ 175f1f82a91SXiangliang Yu tmp |= (0 << 3); 176f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp); 177f1f82a91SXiangliang Yu } 178f1f82a91SXiangliang Yu 179f1f82a91SXiangliang Yu /*Notice: this function must be called when phy is disabled*/ 180f1f82a91SXiangliang Yu void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate) 181f1f82a91SXiangliang Yu { 182f1f82a91SXiangliang Yu union reg_phy_cfg phy_cfg, phy_cfg_tmp; 183f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 184f1f82a91SXiangliang Yu phy_cfg_tmp.v = mvs_read_port_vsr_data(mvi, phy_id); 185f1f82a91SXiangliang Yu phy_cfg.v = 0; 186f1f82a91SXiangliang Yu phy_cfg.u.disable_phy = phy_cfg_tmp.u.disable_phy; 187f1f82a91SXiangliang Yu phy_cfg.u.sas_support = 1; 188f1f82a91SXiangliang Yu phy_cfg.u.sata_support = 1; 189f1f82a91SXiangliang Yu phy_cfg.u.sata_host_mode = 1; 190f1f82a91SXiangliang Yu 191f1f82a91SXiangliang Yu switch (rate) { 192f1f82a91SXiangliang Yu case 0x0: 193f1f82a91SXiangliang Yu /* support 1.5 Gbps */ 194f1f82a91SXiangliang Yu phy_cfg.u.speed_support = 1; 195f1f82a91SXiangliang Yu phy_cfg.u.snw_3_support = 0; 196f1f82a91SXiangliang Yu phy_cfg.u.tx_lnk_parity = 1; 197f1f82a91SXiangliang Yu phy_cfg.u.tx_spt_phs_lnk_rate = 0x30; 198f1f82a91SXiangliang Yu break; 199f1f82a91SXiangliang Yu case 0x1: 200f1f82a91SXiangliang Yu 201f1f82a91SXiangliang Yu /* support 1.5, 3.0 Gbps */ 202f1f82a91SXiangliang Yu phy_cfg.u.speed_support = 3; 203f1f82a91SXiangliang Yu phy_cfg.u.tx_spt_phs_lnk_rate = 0x3c; 204f1f82a91SXiangliang Yu phy_cfg.u.tx_lgcl_lnk_rate = 0x08; 205f1f82a91SXiangliang Yu break; 206f1f82a91SXiangliang Yu case 0x2: 207f1f82a91SXiangliang Yu default: 208f1f82a91SXiangliang Yu /* support 1.5, 3.0, 6.0 Gbps */ 209f1f82a91SXiangliang Yu phy_cfg.u.speed_support = 7; 210f1f82a91SXiangliang Yu phy_cfg.u.snw_3_support = 1; 211f1f82a91SXiangliang Yu phy_cfg.u.tx_lnk_parity = 1; 212f1f82a91SXiangliang Yu phy_cfg.u.tx_spt_phs_lnk_rate = 0x3f; 213f1f82a91SXiangliang Yu phy_cfg.u.tx_lgcl_lnk_rate = 0x09; 214f1f82a91SXiangliang Yu break; 215f1f82a91SXiangliang Yu } 216f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v); 217f1f82a91SXiangliang Yu } 218f1f82a91SXiangliang Yu 219f1f82a91SXiangliang Yu static void __devinit 220f1f82a91SXiangliang Yu mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id) 221f1f82a91SXiangliang Yu { 222f1f82a91SXiangliang Yu u32 temp; 223f1f82a91SXiangliang Yu temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]); 224f1f82a91SXiangliang Yu if (temp == 0xFFFFFFFFL) { 225f1f82a91SXiangliang Yu mvi->hba_info_param.phy_tuning[phy_id].trans_emp_amp = 0x6; 226f1f82a91SXiangliang Yu mvi->hba_info_param.phy_tuning[phy_id].trans_amp = 0x1A; 227f1f82a91SXiangliang Yu mvi->hba_info_param.phy_tuning[phy_id].trans_amp_adj = 0x3; 228f1f82a91SXiangliang Yu } 229f1f82a91SXiangliang Yu 230f1f82a91SXiangliang Yu temp = (u8)(*(u8 *)&mvi->hba_info_param.ffe_ctl[phy_id]); 231f1f82a91SXiangliang Yu if (temp == 0xFFL) { 232f1f82a91SXiangliang Yu switch (mvi->pdev->revision) { 233f1f82a91SXiangliang Yu case VANIR_A0_REV: 234f1f82a91SXiangliang Yu case VANIR_B0_REV: 235f1f82a91SXiangliang Yu mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; 236f1f82a91SXiangliang Yu mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0x7; 237f1f82a91SXiangliang Yu break; 238f1f82a91SXiangliang Yu case VANIR_C0_REV: 239f1f82a91SXiangliang Yu case VANIR_C1_REV: 240f1f82a91SXiangliang Yu case VANIR_C2_REV: 241f1f82a91SXiangliang Yu default: 242f1f82a91SXiangliang Yu mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; 243f1f82a91SXiangliang Yu mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0xC; 244f1f82a91SXiangliang Yu break; 245f1f82a91SXiangliang Yu } 246f1f82a91SXiangliang Yu } 247f1f82a91SXiangliang Yu 248f1f82a91SXiangliang Yu temp = (u8)(*(u8 *)&mvi->hba_info_param.phy_rate[phy_id]); 249f1f82a91SXiangliang Yu if (temp == 0xFFL) 250f1f82a91SXiangliang Yu /*set default phy_rate = 6Gbps*/ 251f1f82a91SXiangliang Yu mvi->hba_info_param.phy_rate[phy_id] = 0x2; 252f1f82a91SXiangliang Yu 253f1f82a91SXiangliang Yu set_phy_tuning(mvi, phy_id, 254f1f82a91SXiangliang Yu mvi->hba_info_param.phy_tuning[phy_id]); 255f1f82a91SXiangliang Yu set_phy_ffe_tuning(mvi, phy_id, 256f1f82a91SXiangliang Yu mvi->hba_info_param.ffe_ctl[phy_id]); 257f1f82a91SXiangliang Yu set_phy_rate(mvi, phy_id, 258f1f82a91SXiangliang Yu mvi->hba_info_param.phy_rate[phy_id]); 259f1f82a91SXiangliang Yu } 260f1f82a91SXiangliang Yu 26120b09c29SAndy Yan static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id) 26220b09c29SAndy Yan { 26320b09c29SAndy Yan void __iomem *regs = mvi->regs; 26420b09c29SAndy Yan u32 tmp; 26520b09c29SAndy Yan 26620b09c29SAndy Yan tmp = mr32(MVS_PCS); 26720b09c29SAndy Yan tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); 26820b09c29SAndy Yan mw32(MVS_PCS, tmp); 26920b09c29SAndy Yan } 27020b09c29SAndy Yan 27120b09c29SAndy Yan static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) 27220b09c29SAndy Yan { 27320b09c29SAndy Yan u32 tmp; 27420b09c29SAndy Yan 27520b09c29SAndy Yan tmp = mvs_read_port_irq_stat(mvi, phy_id); 27620b09c29SAndy Yan tmp &= ~PHYEV_RDY_CH; 27720b09c29SAndy Yan mvs_write_port_irq_stat(mvi, phy_id, tmp); 27820b09c29SAndy Yan if (hard) { 27920b09c29SAndy Yan tmp = mvs_read_phy_ctl(mvi, phy_id); 28020b09c29SAndy Yan tmp |= PHY_RST_HARD; 28120b09c29SAndy Yan mvs_write_phy_ctl(mvi, phy_id, tmp); 28220b09c29SAndy Yan do { 28320b09c29SAndy Yan tmp = mvs_read_phy_ctl(mvi, phy_id); 28420b09c29SAndy Yan } while (tmp & PHY_RST_HARD); 28520b09c29SAndy Yan } else { 28620b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_STAT); 28720b09c29SAndy Yan tmp = mvs_read_port_vsr_data(mvi, phy_id); 28820b09c29SAndy Yan tmp |= PHY_RST; 28920b09c29SAndy Yan mvs_write_port_vsr_data(mvi, phy_id, tmp); 29020b09c29SAndy Yan } 29120b09c29SAndy Yan } 29220b09c29SAndy Yan 29320b09c29SAndy Yan static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id) 29420b09c29SAndy Yan { 29520b09c29SAndy Yan u32 tmp; 29620b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 29720b09c29SAndy Yan tmp = mvs_read_port_vsr_data(mvi, phy_id); 29820b09c29SAndy Yan mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000); 29920b09c29SAndy Yan } 30020b09c29SAndy Yan 30120b09c29SAndy Yan static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id) 30220b09c29SAndy Yan { 303f1f82a91SXiangliang Yu u32 tmp; 304f1f82a91SXiangliang Yu u8 revision = 0; 305f1f82a91SXiangliang Yu 306f1f82a91SXiangliang Yu revision = mvi->pdev->revision; 307f1f82a91SXiangliang Yu if (revision == VANIR_A0_REV) { 308f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); 30920b09c29SAndy Yan mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); 310f1f82a91SXiangliang Yu } 311f1f82a91SXiangliang Yu if (revision == VANIR_B0_REV) { 312f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, CMD_APP_MEM_CTL); 313f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, 0x08001006); 314f1f82a91SXiangliang Yu mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); 315f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f); 316f1f82a91SXiangliang Yu } 317f1f82a91SXiangliang Yu 31820b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); 319f1f82a91SXiangliang Yu tmp = mvs_read_port_vsr_data(mvi, phy_id); 320f1f82a91SXiangliang Yu tmp |= bit(0); 321f1f82a91SXiangliang Yu mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff); 32220b09c29SAndy Yan } 32320b09c29SAndy Yan 32420b09c29SAndy Yan static int __devinit mvs_94xx_init(struct mvs_info *mvi) 32520b09c29SAndy Yan { 32620b09c29SAndy Yan void __iomem *regs = mvi->regs; 32720b09c29SAndy Yan int i; 32820b09c29SAndy Yan u32 tmp, cctl; 329f1f82a91SXiangliang Yu u8 revision; 33020b09c29SAndy Yan 331f1f82a91SXiangliang Yu revision = mvi->pdev->revision; 33220b09c29SAndy Yan mvs_show_pcie_usage(mvi); 33320b09c29SAndy Yan if (mvi->flags & MVF_FLAG_SOC) { 33420b09c29SAndy Yan tmp = mr32(MVS_PHY_CTL); 33520b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 33620b09c29SAndy Yan tmp |= PCTL_PHY_DSBL; 33720b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 33820b09c29SAndy Yan } 33920b09c29SAndy Yan 34020b09c29SAndy Yan /* Init Chip */ 34120b09c29SAndy Yan /* make sure RST is set; HBA_RST /should/ have done that for us */ 34220b09c29SAndy Yan cctl = mr32(MVS_CTL) & 0xFFFF; 34320b09c29SAndy Yan if (cctl & CCTL_RST) 34420b09c29SAndy Yan cctl &= ~CCTL_RST; 34520b09c29SAndy Yan else 34620b09c29SAndy Yan mw32_f(MVS_CTL, cctl | CCTL_RST); 34720b09c29SAndy Yan 34820b09c29SAndy Yan if (mvi->flags & MVF_FLAG_SOC) { 34920b09c29SAndy Yan tmp = mr32(MVS_PHY_CTL); 35020b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 35120b09c29SAndy Yan tmp |= PCTL_COM_ON; 35220b09c29SAndy Yan tmp &= ~PCTL_PHY_DSBL; 35320b09c29SAndy Yan tmp |= PCTL_LINK_RST; 35420b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 35520b09c29SAndy Yan msleep(100); 35620b09c29SAndy Yan tmp &= ~PCTL_LINK_RST; 35720b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 35820b09c29SAndy Yan msleep(100); 35920b09c29SAndy Yan } 36020b09c29SAndy Yan 361f1f82a91SXiangliang Yu /* disable Multiplexing, enable phy implemented */ 362f1f82a91SXiangliang Yu mw32(MVS_PORTS_IMP, 0xFF); 363f1f82a91SXiangliang Yu 364f1f82a91SXiangliang Yu if (revision == VANIR_A0_REV) { 365f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_ADDR, CMD_CMWK_OOB_DET); 366f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_PORT, 0x00018080); 367f1f82a91SXiangliang Yu } 368f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE2); 369f1f82a91SXiangliang Yu if (revision == VANIR_A0_REV || revision == VANIR_B0_REV) 370f1f82a91SXiangliang Yu /* set 6G/3G/1.5G, multiplexing, without SSC */ 371f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_PORT, 0x0084d4fe); 372f1f82a91SXiangliang Yu else 373f1f82a91SXiangliang Yu /* set 6G/3G/1.5G, multiplexing, with and without SSC */ 374f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_PORT, 0x0084fffe); 375f1f82a91SXiangliang Yu 376f1f82a91SXiangliang Yu if (revision == VANIR_B0_REV) { 377f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_ADDR, CMD_APP_MEM_CTL); 378f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_PORT, 0x08001006); 379f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_ADDR, CMD_HOST_RD_DATA); 380f1f82a91SXiangliang Yu mw32(MVS_PA_VSR_PORT, 0x0000705f); 381f1f82a91SXiangliang Yu } 382f1f82a91SXiangliang Yu 38320b09c29SAndy Yan /* reset control */ 38420b09c29SAndy Yan mw32(MVS_PCS, 0); /* MVS_PCS */ 38520b09c29SAndy Yan mw32(MVS_STP_REG_SET_0, 0); 38620b09c29SAndy Yan mw32(MVS_STP_REG_SET_1, 0); 38720b09c29SAndy Yan 38820b09c29SAndy Yan /* init phys */ 38920b09c29SAndy Yan mvs_phy_hacks(mvi); 39020b09c29SAndy Yan 39120b09c29SAndy Yan /* set LED blink when IO*/ 39220b09c29SAndy Yan mw32(MVS_PA_VSR_ADDR, 0x00000030); 39320b09c29SAndy Yan tmp = mr32(MVS_PA_VSR_PORT); 39420b09c29SAndy Yan tmp &= 0xFFFF00FF; 39520b09c29SAndy Yan tmp |= 0x00003300; 39620b09c29SAndy Yan mw32(MVS_PA_VSR_PORT, tmp); 39720b09c29SAndy Yan 39820b09c29SAndy Yan mw32(MVS_CMD_LIST_LO, mvi->slot_dma); 39920b09c29SAndy Yan mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 40020b09c29SAndy Yan 40120b09c29SAndy Yan mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); 40220b09c29SAndy Yan mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 40320b09c29SAndy Yan 40420b09c29SAndy Yan mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); 40520b09c29SAndy Yan mw32(MVS_TX_LO, mvi->tx_dma); 40620b09c29SAndy Yan mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); 40720b09c29SAndy Yan 40820b09c29SAndy Yan mw32(MVS_RX_CFG, MVS_RX_RING_SZ); 40920b09c29SAndy Yan mw32(MVS_RX_LO, mvi->rx_dma); 41020b09c29SAndy Yan mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); 41120b09c29SAndy Yan 41220b09c29SAndy Yan for (i = 0; i < mvi->chip->n_phy; i++) { 41320b09c29SAndy Yan mvs_94xx_phy_disable(mvi, i); 41420b09c29SAndy Yan /* set phy local SAS address */ 41520b09c29SAndy Yan mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4, 41620b09c29SAndy Yan (mvi->phy[i].dev_sas_addr)); 41720b09c29SAndy Yan 41820b09c29SAndy Yan mvs_94xx_enable_xmt(mvi, i); 419f1f82a91SXiangliang Yu mvs_94xx_config_reg_from_hba(mvi, i); 42020b09c29SAndy Yan mvs_94xx_phy_enable(mvi, i); 42120b09c29SAndy Yan 42220b09c29SAndy Yan mvs_94xx_phy_reset(mvi, i, 1); 42320b09c29SAndy Yan msleep(500); 42420b09c29SAndy Yan mvs_94xx_detect_porttype(mvi, i); 42520b09c29SAndy Yan } 42620b09c29SAndy Yan 42720b09c29SAndy Yan if (mvi->flags & MVF_FLAG_SOC) { 42820b09c29SAndy Yan /* set select registers */ 42920b09c29SAndy Yan writel(0x0E008000, regs + 0x000); 43020b09c29SAndy Yan writel(0x59000008, regs + 0x004); 43120b09c29SAndy Yan writel(0x20, regs + 0x008); 43220b09c29SAndy Yan writel(0x20, regs + 0x00c); 43320b09c29SAndy Yan writel(0x20, regs + 0x010); 43420b09c29SAndy Yan writel(0x20, regs + 0x014); 43520b09c29SAndy Yan writel(0x20, regs + 0x018); 43620b09c29SAndy Yan writel(0x20, regs + 0x01c); 43720b09c29SAndy Yan } 43820b09c29SAndy Yan for (i = 0; i < mvi->chip->n_phy; i++) { 43920b09c29SAndy Yan /* clear phy int status */ 44020b09c29SAndy Yan tmp = mvs_read_port_irq_stat(mvi, i); 44120b09c29SAndy Yan tmp &= ~PHYEV_SIG_FIS; 44220b09c29SAndy Yan mvs_write_port_irq_stat(mvi, i, tmp); 44320b09c29SAndy Yan 44420b09c29SAndy Yan /* set phy int mask */ 44520b09c29SAndy Yan tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | 44620b09c29SAndy Yan PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ; 44720b09c29SAndy Yan mvs_write_port_irq_mask(mvi, i, tmp); 44820b09c29SAndy Yan 44920b09c29SAndy Yan msleep(100); 45020b09c29SAndy Yan mvs_update_phyinfo(mvi, i, 1); 45120b09c29SAndy Yan } 45220b09c29SAndy Yan 45320b09c29SAndy Yan /* FIXME: update wide port bitmaps */ 45420b09c29SAndy Yan 45520b09c29SAndy Yan /* little endian for open address and command table, etc. */ 45620b09c29SAndy Yan /* 45720b09c29SAndy Yan * it seems that ( from the spec ) turning on big-endian won't 45820b09c29SAndy Yan * do us any good on big-endian machines, need further confirmation 45920b09c29SAndy Yan */ 46020b09c29SAndy Yan cctl = mr32(MVS_CTL); 46120b09c29SAndy Yan cctl |= CCTL_ENDIAN_CMD; 46220b09c29SAndy Yan cctl |= CCTL_ENDIAN_DATA; 46320b09c29SAndy Yan cctl &= ~CCTL_ENDIAN_OPEN; 46420b09c29SAndy Yan cctl |= CCTL_ENDIAN_RSP; 46520b09c29SAndy Yan mw32_f(MVS_CTL, cctl); 46620b09c29SAndy Yan 46720b09c29SAndy Yan /* reset CMD queue */ 46820b09c29SAndy Yan tmp = mr32(MVS_PCS); 46920b09c29SAndy Yan tmp |= PCS_CMD_RST; 47020b09c29SAndy Yan mw32(MVS_PCS, tmp); 47120b09c29SAndy Yan /* interrupt coalescing may cause missing HW interrput in some case, 47220b09c29SAndy Yan * and the max count is 0x1ff, while our max slot is 0x200, 47320b09c29SAndy Yan * it will make count 0. 47420b09c29SAndy Yan */ 47520b09c29SAndy Yan tmp = 0; 47620b09c29SAndy Yan mw32(MVS_INT_COAL, tmp); 47720b09c29SAndy Yan 47820b09c29SAndy Yan tmp = 0x100; 47920b09c29SAndy Yan mw32(MVS_INT_COAL_TMOUT, tmp); 48020b09c29SAndy Yan 48120b09c29SAndy Yan /* ladies and gentlemen, start your engines */ 48220b09c29SAndy Yan mw32(MVS_TX_CFG, 0); 48320b09c29SAndy Yan mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 48420b09c29SAndy Yan mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); 48520b09c29SAndy Yan /* enable CMD/CMPL_Q/RESP mode */ 48620b09c29SAndy Yan mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN | 48720b09c29SAndy Yan PCS_CMD_EN | PCS_CMD_STOP_ERR); 48820b09c29SAndy Yan 48920b09c29SAndy Yan /* enable completion queue interrupt */ 49020b09c29SAndy Yan tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | 491534ff101SXiangliang Yu CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR); 49220b09c29SAndy Yan tmp |= CINT_PHY_MASK; 49320b09c29SAndy Yan mw32(MVS_INT_MASK, tmp); 49420b09c29SAndy Yan 49520b09c29SAndy Yan /* Enable SRS interrupt */ 49620b09c29SAndy Yan mw32(MVS_INT_MASK_SRS_0, 0xFFFF); 49720b09c29SAndy Yan 49820b09c29SAndy Yan return 0; 49920b09c29SAndy Yan } 50020b09c29SAndy Yan 50120b09c29SAndy Yan static int mvs_94xx_ioremap(struct mvs_info *mvi) 50220b09c29SAndy Yan { 50320b09c29SAndy Yan if (!mvs_ioremap(mvi, 2, -1)) { 50420b09c29SAndy Yan mvi->regs_ex = mvi->regs + 0x10200; 50520b09c29SAndy Yan mvi->regs += 0x20000; 50620b09c29SAndy Yan if (mvi->id == 1) 50720b09c29SAndy Yan mvi->regs += 0x4000; 50820b09c29SAndy Yan return 0; 50920b09c29SAndy Yan } 51020b09c29SAndy Yan return -1; 51120b09c29SAndy Yan } 51220b09c29SAndy Yan 51320b09c29SAndy Yan static void mvs_94xx_iounmap(struct mvs_info *mvi) 51420b09c29SAndy Yan { 51520b09c29SAndy Yan if (mvi->regs) { 51620b09c29SAndy Yan mvi->regs -= 0x20000; 51720b09c29SAndy Yan if (mvi->id == 1) 51820b09c29SAndy Yan mvi->regs -= 0x4000; 51920b09c29SAndy Yan mvs_iounmap(mvi->regs); 52020b09c29SAndy Yan } 52120b09c29SAndy Yan } 52220b09c29SAndy Yan 52320b09c29SAndy Yan static void mvs_94xx_interrupt_enable(struct mvs_info *mvi) 52420b09c29SAndy Yan { 52520b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 52620b09c29SAndy Yan u32 tmp; 52720b09c29SAndy Yan 52820b09c29SAndy Yan tmp = mr32(MVS_GBL_CTL); 52920b09c29SAndy Yan tmp |= (IRQ_SAS_A | IRQ_SAS_B); 53020b09c29SAndy Yan mw32(MVS_GBL_INT_STAT, tmp); 53120b09c29SAndy Yan writel(tmp, regs + 0x0C); 53220b09c29SAndy Yan writel(tmp, regs + 0x10); 53320b09c29SAndy Yan writel(tmp, regs + 0x14); 53420b09c29SAndy Yan writel(tmp, regs + 0x18); 53520b09c29SAndy Yan mw32(MVS_GBL_CTL, tmp); 53620b09c29SAndy Yan } 53720b09c29SAndy Yan 53820b09c29SAndy Yan static void mvs_94xx_interrupt_disable(struct mvs_info *mvi) 53920b09c29SAndy Yan { 54020b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 54120b09c29SAndy Yan u32 tmp; 54220b09c29SAndy Yan 54320b09c29SAndy Yan tmp = mr32(MVS_GBL_CTL); 54420b09c29SAndy Yan 54520b09c29SAndy Yan tmp &= ~(IRQ_SAS_A | IRQ_SAS_B); 54620b09c29SAndy Yan mw32(MVS_GBL_INT_STAT, tmp); 54720b09c29SAndy Yan writel(tmp, regs + 0x0C); 54820b09c29SAndy Yan writel(tmp, regs + 0x10); 54920b09c29SAndy Yan writel(tmp, regs + 0x14); 55020b09c29SAndy Yan writel(tmp, regs + 0x18); 55120b09c29SAndy Yan mw32(MVS_GBL_CTL, tmp); 55220b09c29SAndy Yan } 55320b09c29SAndy Yan 55420b09c29SAndy Yan static u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq) 55520b09c29SAndy Yan { 55620b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 55720b09c29SAndy Yan u32 stat = 0; 55820b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 55920b09c29SAndy Yan stat = mr32(MVS_GBL_INT_STAT); 56020b09c29SAndy Yan 56120b09c29SAndy Yan if (!(stat & (IRQ_SAS_A | IRQ_SAS_B))) 56220b09c29SAndy Yan return 0; 56320b09c29SAndy Yan } 56420b09c29SAndy Yan return stat; 56520b09c29SAndy Yan } 56620b09c29SAndy Yan 56720b09c29SAndy Yan static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat) 56820b09c29SAndy Yan { 56920b09c29SAndy Yan void __iomem *regs = mvi->regs; 57020b09c29SAndy Yan 57120b09c29SAndy Yan if (((stat & IRQ_SAS_A) && mvi->id == 0) || 57220b09c29SAndy Yan ((stat & IRQ_SAS_B) && mvi->id == 1)) { 57320b09c29SAndy Yan mw32_f(MVS_INT_STAT, CINT_DONE); 57420b09c29SAndy Yan #ifndef MVS_USE_TASKLET 57520b09c29SAndy Yan spin_lock(&mvi->lock); 57620b09c29SAndy Yan #endif 57720b09c29SAndy Yan mvs_int_full(mvi); 57820b09c29SAndy Yan #ifndef MVS_USE_TASKLET 57920b09c29SAndy Yan spin_unlock(&mvi->lock); 58020b09c29SAndy Yan #endif 58120b09c29SAndy Yan } 58220b09c29SAndy Yan return IRQ_HANDLED; 58320b09c29SAndy Yan } 58420b09c29SAndy Yan 58520b09c29SAndy Yan static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx) 58620b09c29SAndy Yan { 58720b09c29SAndy Yan u32 tmp; 58820b09c29SAndy Yan mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32)); 58920b09c29SAndy Yan do { 59020b09c29SAndy Yan tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3)); 59120b09c29SAndy Yan } while (tmp & 1 << (slot_idx % 32)); 59220b09c29SAndy Yan } 59320b09c29SAndy Yan 59420b09c29SAndy Yan static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, 59520b09c29SAndy Yan u32 tfs) 59620b09c29SAndy Yan { 59720b09c29SAndy Yan void __iomem *regs = mvi->regs; 59820b09c29SAndy Yan u32 tmp; 59920b09c29SAndy Yan 60020b09c29SAndy Yan if (type == PORT_TYPE_SATA) { 60120b09c29SAndy Yan tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); 60220b09c29SAndy Yan mw32(MVS_INT_STAT_SRS_0, tmp); 60320b09c29SAndy Yan } 60420b09c29SAndy Yan mw32(MVS_INT_STAT, CINT_CI_STOP); 60520b09c29SAndy Yan tmp = mr32(MVS_PCS) | 0xFF00; 60620b09c29SAndy Yan mw32(MVS_PCS, tmp); 60720b09c29SAndy Yan } 60820b09c29SAndy Yan 609534ff101SXiangliang Yu static void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi) 610534ff101SXiangliang Yu { 611534ff101SXiangliang Yu void __iomem *regs = mvi->regs; 612534ff101SXiangliang Yu u32 err_0, err_1; 613534ff101SXiangliang Yu u8 i; 614534ff101SXiangliang Yu struct mvs_device *device; 615534ff101SXiangliang Yu 616534ff101SXiangliang Yu err_0 = mr32(MVS_NON_NCQ_ERR_0); 617534ff101SXiangliang Yu err_1 = mr32(MVS_NON_NCQ_ERR_1); 618534ff101SXiangliang Yu 619534ff101SXiangliang Yu mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n", 620534ff101SXiangliang Yu err_0, err_1); 621534ff101SXiangliang Yu for (i = 0; i < 32; i++) { 622534ff101SXiangliang Yu if (err_0 & bit(i)) { 623534ff101SXiangliang Yu device = mvs_find_dev_by_reg_set(mvi, i); 624534ff101SXiangliang Yu if (device) 625534ff101SXiangliang Yu mvs_release_task(mvi, device->sas_device); 626534ff101SXiangliang Yu } 627534ff101SXiangliang Yu if (err_1 & bit(i)) { 628534ff101SXiangliang Yu device = mvs_find_dev_by_reg_set(mvi, i+32); 629534ff101SXiangliang Yu if (device) 630534ff101SXiangliang Yu mvs_release_task(mvi, device->sas_device); 631534ff101SXiangliang Yu } 632534ff101SXiangliang Yu } 633534ff101SXiangliang Yu 634534ff101SXiangliang Yu mw32(MVS_NON_NCQ_ERR_0, err_0); 635534ff101SXiangliang Yu mw32(MVS_NON_NCQ_ERR_1, err_1); 636534ff101SXiangliang Yu } 637534ff101SXiangliang Yu 63820b09c29SAndy Yan static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) 63920b09c29SAndy Yan { 64020b09c29SAndy Yan void __iomem *regs = mvi->regs; 64120b09c29SAndy Yan u32 tmp; 64220b09c29SAndy Yan u8 reg_set = *tfs; 64320b09c29SAndy Yan 64420b09c29SAndy Yan if (*tfs == MVS_ID_NOT_MAPPED) 64520b09c29SAndy Yan return; 64620b09c29SAndy Yan 64720b09c29SAndy Yan mvi->sata_reg_set &= ~bit(reg_set); 64820b09c29SAndy Yan if (reg_set < 32) { 64920b09c29SAndy Yan w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set); 65020b09c29SAndy Yan tmp = mr32(MVS_INT_STAT_SRS_0) & (u32)mvi->sata_reg_set; 65120b09c29SAndy Yan if (tmp) 65220b09c29SAndy Yan mw32(MVS_INT_STAT_SRS_0, tmp); 65320b09c29SAndy Yan } else { 65420b09c29SAndy Yan w_reg_set_enable(reg_set, mvi->sata_reg_set); 65520b09c29SAndy Yan tmp = mr32(MVS_INT_STAT_SRS_1) & mvi->sata_reg_set; 65620b09c29SAndy Yan if (tmp) 65720b09c29SAndy Yan mw32(MVS_INT_STAT_SRS_1, tmp); 65820b09c29SAndy Yan } 65920b09c29SAndy Yan 66020b09c29SAndy Yan *tfs = MVS_ID_NOT_MAPPED; 66120b09c29SAndy Yan 66220b09c29SAndy Yan return; 66320b09c29SAndy Yan } 66420b09c29SAndy Yan 66520b09c29SAndy Yan static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) 66620b09c29SAndy Yan { 66720b09c29SAndy Yan int i; 66820b09c29SAndy Yan void __iomem *regs = mvi->regs; 66920b09c29SAndy Yan 67020b09c29SAndy Yan if (*tfs != MVS_ID_NOT_MAPPED) 67120b09c29SAndy Yan return 0; 67220b09c29SAndy Yan 67320b09c29SAndy Yan i = mv_ffc64(mvi->sata_reg_set); 67420b09c29SAndy Yan if (i > 32) { 67520b09c29SAndy Yan mvi->sata_reg_set |= bit(i); 67620b09c29SAndy Yan w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32)); 67720b09c29SAndy Yan *tfs = i; 67820b09c29SAndy Yan return 0; 67920b09c29SAndy Yan } else if (i >= 0) { 68020b09c29SAndy Yan mvi->sata_reg_set |= bit(i); 68120b09c29SAndy Yan w_reg_set_enable(i, (u32)mvi->sata_reg_set); 68220b09c29SAndy Yan *tfs = i; 68320b09c29SAndy Yan return 0; 68420b09c29SAndy Yan } 68520b09c29SAndy Yan return MVS_ID_NOT_MAPPED; 68620b09c29SAndy Yan } 68720b09c29SAndy Yan 68820b09c29SAndy Yan static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd) 68920b09c29SAndy Yan { 69020b09c29SAndy Yan int i; 69120b09c29SAndy Yan struct scatterlist *sg; 69220b09c29SAndy Yan struct mvs_prd *buf_prd = prd; 69320b09c29SAndy Yan for_each_sg(scatter, sg, nr, i) { 69420b09c29SAndy Yan buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 69520b09c29SAndy Yan buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg)); 69620b09c29SAndy Yan buf_prd++; 69720b09c29SAndy Yan } 69820b09c29SAndy Yan } 69920b09c29SAndy Yan 70020b09c29SAndy Yan static int mvs_94xx_oob_done(struct mvs_info *mvi, int i) 70120b09c29SAndy Yan { 70220b09c29SAndy Yan u32 phy_st; 70320b09c29SAndy Yan phy_st = mvs_read_phy_ctl(mvi, i); 70420b09c29SAndy Yan if (phy_st & PHY_READY_MASK) /* phy ready */ 70520b09c29SAndy Yan return 1; 70620b09c29SAndy Yan return 0; 70720b09c29SAndy Yan } 70820b09c29SAndy Yan 70920b09c29SAndy Yan static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id, 71020b09c29SAndy Yan struct sas_identify_frame *id) 71120b09c29SAndy Yan { 71220b09c29SAndy Yan int i; 71320b09c29SAndy Yan u32 id_frame[7]; 71420b09c29SAndy Yan 71520b09c29SAndy Yan for (i = 0; i < 7; i++) { 71620b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, port_id, 71720b09c29SAndy Yan CONFIG_ID_FRAME0 + i * 4); 71820b09c29SAndy Yan id_frame[i] = mvs_read_port_cfg_data(mvi, port_id); 71920b09c29SAndy Yan } 72020b09c29SAndy Yan memcpy(id, id_frame, 28); 72120b09c29SAndy Yan } 72220b09c29SAndy Yan 72320b09c29SAndy Yan static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id, 72420b09c29SAndy Yan struct sas_identify_frame *id) 72520b09c29SAndy Yan { 72620b09c29SAndy Yan int i; 72720b09c29SAndy Yan u32 id_frame[7]; 72820b09c29SAndy Yan 72920b09c29SAndy Yan /* mvs_hexdump(28, (u8 *)id_frame, 0); */ 73020b09c29SAndy Yan for (i = 0; i < 7; i++) { 73120b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, port_id, 73220b09c29SAndy Yan CONFIG_ATT_ID_FRAME0 + i * 4); 73320b09c29SAndy Yan id_frame[i] = mvs_read_port_cfg_data(mvi, port_id); 73420b09c29SAndy Yan mv_dprintk("94xx phy %d atta frame %d %x.\n", 73520b09c29SAndy Yan port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]); 73620b09c29SAndy Yan } 73720b09c29SAndy Yan /* mvs_hexdump(28, (u8 *)id_frame, 0); */ 73820b09c29SAndy Yan memcpy(id, id_frame, 28); 73920b09c29SAndy Yan } 74020b09c29SAndy Yan 74120b09c29SAndy Yan static u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id) 74220b09c29SAndy Yan { 74320b09c29SAndy Yan u32 att_dev_info = 0; 74420b09c29SAndy Yan 74520b09c29SAndy Yan att_dev_info |= id->dev_type; 74620b09c29SAndy Yan if (id->stp_iport) 74720b09c29SAndy Yan att_dev_info |= PORT_DEV_STP_INIT; 74820b09c29SAndy Yan if (id->smp_iport) 74920b09c29SAndy Yan att_dev_info |= PORT_DEV_SMP_INIT; 75020b09c29SAndy Yan if (id->ssp_iport) 75120b09c29SAndy Yan att_dev_info |= PORT_DEV_SSP_INIT; 75220b09c29SAndy Yan if (id->stp_tport) 75320b09c29SAndy Yan att_dev_info |= PORT_DEV_STP_TRGT; 75420b09c29SAndy Yan if (id->smp_tport) 75520b09c29SAndy Yan att_dev_info |= PORT_DEV_SMP_TRGT; 75620b09c29SAndy Yan if (id->ssp_tport) 75720b09c29SAndy Yan att_dev_info |= PORT_DEV_SSP_TRGT; 75820b09c29SAndy Yan 75920b09c29SAndy Yan att_dev_info |= (u32)id->phy_id<<24; 76020b09c29SAndy Yan return att_dev_info; 76120b09c29SAndy Yan } 76220b09c29SAndy Yan 76320b09c29SAndy Yan static u32 mvs_94xx_make_att_info(struct sas_identify_frame *id) 76420b09c29SAndy Yan { 76520b09c29SAndy Yan return mvs_94xx_make_dev_info(id); 76620b09c29SAndy Yan } 76720b09c29SAndy Yan 76820b09c29SAndy Yan static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i, 76920b09c29SAndy Yan struct sas_identify_frame *id) 77020b09c29SAndy Yan { 77120b09c29SAndy Yan struct mvs_phy *phy = &mvi->phy[i]; 77220b09c29SAndy Yan struct asd_sas_phy *sas_phy = &phy->sas_phy; 77320b09c29SAndy Yan mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status); 77420b09c29SAndy Yan sas_phy->linkrate = 77520b09c29SAndy Yan (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 77620b09c29SAndy Yan PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 77720b09c29SAndy Yan sas_phy->linkrate += 0x8; 77820b09c29SAndy Yan mv_dprintk("get link rate is %d\n", sas_phy->linkrate); 77920b09c29SAndy Yan phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; 78020b09c29SAndy Yan phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS; 78120b09c29SAndy Yan mvs_94xx_get_dev_identify_frame(mvi, i, id); 78220b09c29SAndy Yan phy->dev_info = mvs_94xx_make_dev_info(id); 78320b09c29SAndy Yan 78420b09c29SAndy Yan if (phy->phy_type & PORT_TYPE_SAS) { 78520b09c29SAndy Yan mvs_94xx_get_att_identify_frame(mvi, i, id); 78620b09c29SAndy Yan phy->att_dev_info = mvs_94xx_make_att_info(id); 78720b09c29SAndy Yan phy->att_dev_sas_addr = *(u64 *)id->sas_addr; 78820b09c29SAndy Yan } else { 78920b09c29SAndy Yan phy->att_dev_info = PORT_DEV_STP_TRGT | 1; 79020b09c29SAndy Yan } 79120b09c29SAndy Yan 79220b09c29SAndy Yan } 79320b09c29SAndy Yan 79420b09c29SAndy Yan void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, 79520b09c29SAndy Yan struct sas_phy_linkrates *rates) 79620b09c29SAndy Yan { 79720b09c29SAndy Yan /* TODO */ 79820b09c29SAndy Yan } 79920b09c29SAndy Yan 80020b09c29SAndy Yan static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi) 80120b09c29SAndy Yan { 80220b09c29SAndy Yan u32 tmp; 80320b09c29SAndy Yan void __iomem *regs = mvi->regs; 80420b09c29SAndy Yan tmp = mr32(MVS_STP_REG_SET_0); 80520b09c29SAndy Yan mw32(MVS_STP_REG_SET_0, 0); 80620b09c29SAndy Yan mw32(MVS_STP_REG_SET_0, tmp); 80720b09c29SAndy Yan tmp = mr32(MVS_STP_REG_SET_1); 80820b09c29SAndy Yan mw32(MVS_STP_REG_SET_1, 0); 80920b09c29SAndy Yan mw32(MVS_STP_REG_SET_1, tmp); 81020b09c29SAndy Yan } 81120b09c29SAndy Yan 81220b09c29SAndy Yan 81320b09c29SAndy Yan u32 mvs_94xx_spi_read_data(struct mvs_info *mvi) 81420b09c29SAndy Yan { 81520b09c29SAndy Yan void __iomem *regs = mvi->regs_ex - 0x10200; 81620b09c29SAndy Yan return mr32(SPI_RD_DATA_REG_94XX); 81720b09c29SAndy Yan } 81820b09c29SAndy Yan 81920b09c29SAndy Yan void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data) 82020b09c29SAndy Yan { 82120b09c29SAndy Yan void __iomem *regs = mvi->regs_ex - 0x10200; 82220b09c29SAndy Yan mw32(SPI_RD_DATA_REG_94XX, data); 82320b09c29SAndy Yan } 82420b09c29SAndy Yan 82520b09c29SAndy Yan 82620b09c29SAndy Yan int mvs_94xx_spi_buildcmd(struct mvs_info *mvi, 82720b09c29SAndy Yan u32 *dwCmd, 82820b09c29SAndy Yan u8 cmd, 82920b09c29SAndy Yan u8 read, 83020b09c29SAndy Yan u8 length, 83120b09c29SAndy Yan u32 addr 83220b09c29SAndy Yan ) 83320b09c29SAndy Yan { 83420b09c29SAndy Yan void __iomem *regs = mvi->regs_ex - 0x10200; 83520b09c29SAndy Yan u32 dwTmp; 83620b09c29SAndy Yan 83720b09c29SAndy Yan dwTmp = ((u32)cmd << 8) | ((u32)length << 4); 83820b09c29SAndy Yan if (read) 83920b09c29SAndy Yan dwTmp |= SPI_CTRL_READ_94XX; 84020b09c29SAndy Yan 84120b09c29SAndy Yan if (addr != MV_MAX_U32) { 84220b09c29SAndy Yan mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL)); 84320b09c29SAndy Yan dwTmp |= SPI_ADDR_VLD_94XX; 84420b09c29SAndy Yan } 84520b09c29SAndy Yan 84620b09c29SAndy Yan *dwCmd = dwTmp; 84720b09c29SAndy Yan return 0; 84820b09c29SAndy Yan } 84920b09c29SAndy Yan 85020b09c29SAndy Yan 85120b09c29SAndy Yan int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) 85220b09c29SAndy Yan { 85320b09c29SAndy Yan void __iomem *regs = mvi->regs_ex - 0x10200; 85420b09c29SAndy Yan mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX); 85520b09c29SAndy Yan 85620b09c29SAndy Yan return 0; 85720b09c29SAndy Yan } 85820b09c29SAndy Yan 85920b09c29SAndy Yan int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) 86020b09c29SAndy Yan { 86120b09c29SAndy Yan void __iomem *regs = mvi->regs_ex - 0x10200; 86220b09c29SAndy Yan u32 i, dwTmp; 86320b09c29SAndy Yan 86420b09c29SAndy Yan for (i = 0; i < timeout; i++) { 86520b09c29SAndy Yan dwTmp = mr32(SPI_CTRL_REG_94XX); 86620b09c29SAndy Yan if (!(dwTmp & SPI_CTRL_SpiStart_94XX)) 86720b09c29SAndy Yan return 0; 86820b09c29SAndy Yan msleep(10); 86920b09c29SAndy Yan } 87020b09c29SAndy Yan 87120b09c29SAndy Yan return -1; 87220b09c29SAndy Yan } 87320b09c29SAndy Yan 87420b09c29SAndy Yan #ifndef DISABLE_HOTPLUG_DMA_FIX 87520b09c29SAndy Yan void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd) 87620b09c29SAndy Yan { 87720b09c29SAndy Yan int i; 87820b09c29SAndy Yan struct mvs_prd *buf_prd = prd; 87920b09c29SAndy Yan buf_prd += from; 88020b09c29SAndy Yan for (i = 0; i < MAX_SG_ENTRY - from; i++) { 88120b09c29SAndy Yan buf_prd->addr = cpu_to_le64(buf_dma); 88220b09c29SAndy Yan buf_prd->im_len.len = cpu_to_le32(buf_len); 88320b09c29SAndy Yan ++buf_prd; 88420b09c29SAndy Yan } 88520b09c29SAndy Yan } 88620b09c29SAndy Yan #endif 88720b09c29SAndy Yan 8889dc9fd94SSrinivas /* 8899dc9fd94SSrinivas * FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work 8909dc9fd94SSrinivas * with 64xx fixes 8919dc9fd94SSrinivas */ 8929dc9fd94SSrinivas static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, 8939dc9fd94SSrinivas u8 clear_all) 8949dc9fd94SSrinivas { 8959dc9fd94SSrinivas } 8969dc9fd94SSrinivas 89720b09c29SAndy Yan const struct mvs_dispatch mvs_94xx_dispatch = { 89820b09c29SAndy Yan "mv94xx", 89920b09c29SAndy Yan mvs_94xx_init, 90020b09c29SAndy Yan NULL, 90120b09c29SAndy Yan mvs_94xx_ioremap, 90220b09c29SAndy Yan mvs_94xx_iounmap, 90320b09c29SAndy Yan mvs_94xx_isr, 90420b09c29SAndy Yan mvs_94xx_isr_status, 90520b09c29SAndy Yan mvs_94xx_interrupt_enable, 90620b09c29SAndy Yan mvs_94xx_interrupt_disable, 90720b09c29SAndy Yan mvs_read_phy_ctl, 90820b09c29SAndy Yan mvs_write_phy_ctl, 90920b09c29SAndy Yan mvs_read_port_cfg_data, 91020b09c29SAndy Yan mvs_write_port_cfg_data, 91120b09c29SAndy Yan mvs_write_port_cfg_addr, 91220b09c29SAndy Yan mvs_read_port_vsr_data, 91320b09c29SAndy Yan mvs_write_port_vsr_data, 91420b09c29SAndy Yan mvs_write_port_vsr_addr, 91520b09c29SAndy Yan mvs_read_port_irq_stat, 91620b09c29SAndy Yan mvs_write_port_irq_stat, 91720b09c29SAndy Yan mvs_read_port_irq_mask, 91820b09c29SAndy Yan mvs_write_port_irq_mask, 91920b09c29SAndy Yan mvs_get_sas_addr, 92020b09c29SAndy Yan mvs_94xx_command_active, 9219dc9fd94SSrinivas mvs_94xx_clear_srs_irq, 92220b09c29SAndy Yan mvs_94xx_issue_stop, 92320b09c29SAndy Yan mvs_start_delivery, 92420b09c29SAndy Yan mvs_rx_update, 92520b09c29SAndy Yan mvs_int_full, 92620b09c29SAndy Yan mvs_94xx_assign_reg_set, 92720b09c29SAndy Yan mvs_94xx_free_reg_set, 92820b09c29SAndy Yan mvs_get_prd_size, 92920b09c29SAndy Yan mvs_get_prd_count, 93020b09c29SAndy Yan mvs_94xx_make_prd, 93120b09c29SAndy Yan mvs_94xx_detect_porttype, 93220b09c29SAndy Yan mvs_94xx_oob_done, 93320b09c29SAndy Yan mvs_94xx_fix_phy_info, 93420b09c29SAndy Yan NULL, 93520b09c29SAndy Yan mvs_94xx_phy_set_link_rate, 93620b09c29SAndy Yan mvs_hw_max_link_rate, 93720b09c29SAndy Yan mvs_94xx_phy_disable, 93820b09c29SAndy Yan mvs_94xx_phy_enable, 93920b09c29SAndy Yan mvs_94xx_phy_reset, 94020b09c29SAndy Yan NULL, 94120b09c29SAndy Yan mvs_94xx_clear_active_cmds, 94220b09c29SAndy Yan mvs_94xx_spi_read_data, 94320b09c29SAndy Yan mvs_94xx_spi_write_data, 94420b09c29SAndy Yan mvs_94xx_spi_buildcmd, 94520b09c29SAndy Yan mvs_94xx_spi_issuecmd, 94620b09c29SAndy Yan mvs_94xx_spi_waitdataready, 94720b09c29SAndy Yan #ifndef DISABLE_HOTPLUG_DMA_FIX 94820b09c29SAndy Yan mvs_94xx_fix_dma, 94920b09c29SAndy Yan #endif 950534ff101SXiangliang Yu mvs_94xx_non_spec_ncq_error, 95120b09c29SAndy Yan }; 95220b09c29SAndy Yan 953