xref: /openbmc/linux/drivers/scsi/mvsas/mv_94xx.c (revision f1f82a91)
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