/*
* Marvell 88SE94xx hardware specific
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
*
* This file is licensed under GPLv2.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the
* License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "mv_sas.h"
#include "mv_94xx.h"
#include "mv_chips.h"
static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i)
{
u32 reg;
struct mvs_phy *phy = &mvi->phy[i];
u32 phy_status;
mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3);
reg = mvs_read_port_vsr_data(mvi, i);
phy_status = ((reg & 0x3f0000) >> 16) & 0xff;
phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
switch (phy_status) {
case 0x10:
phy->phy_type |= PORT_TYPE_SAS;
break;
case 0x1d:
default:
phy->phy_type |= PORT_TYPE_SATA;
break;
}
}
void set_phy_tuning(struct mvs_info *mvi, int phy_id,
struct phy_tuning phy_tuning)
{
u32 tmp, setting_0 = 0, setting_1 = 0;
u8 i;
/* Remap information for B0 chip:
*
* R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient)
* R0Dh -> R118h[31:16] (Generation 1 Setting 0)
* R0Eh -> R11Ch[15:0] (Generation 1 Setting 1)
* R0Fh -> R11Ch[31:16] (Generation 2 Setting 0)
* R10h -> R120h[15:0] (Generation 2 Setting 1)
* R11h -> R120h[31:16] (Generation 3 Setting 0)
* R12h -> R124h[15:0] (Generation 3 Setting 1)
* R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved))
*/
/* A0 has a different set of registers */
if (mvi->pdev->revision == VANIR_A0_REV)
return;
for (i = 0; i < 3; i++) {
/* loop 3 times, set Gen 1, Gen 2, Gen 3 */
switch (i) {
case 0:
setting_0 = GENERATION_1_SETTING;
setting_1 = GENERATION_1_2_SETTING;
break;
case 1:
setting_0 = GENERATION_1_2_SETTING;
setting_1 = GENERATION_2_3_SETTING;
break;
case 2:
setting_0 = GENERATION_2_3_SETTING;
setting_1 = GENERATION_3_4_SETTING;
break;
}
/* Set:
*
* Transmitter Emphasis Enable
* Transmitter Emphasis Amplitude
* Transmitter Amplitude
*/
mvs_write_port_vsr_addr(mvi, phy_id, setting_0);
tmp = mvs_read_port_vsr_data(mvi, phy_id);
tmp &= ~(0xFBE << 16);
tmp |= (((phy_tuning.trans_emp_en << 11) |
(phy_tuning.trans_emp_amp << 7) |
(phy_tuning.trans_amp << 1)) << 16);
mvs_write_port_vsr_data(mvi, phy_id, tmp);
/* Set Transmitter Amplitude Adjust */
mvs_write_port_vsr_addr(mvi, phy_id, setting_1);
tmp = mvs_read_port_vsr_data(mvi, phy_id);
tmp &= ~(0xC000);
tmp |= (phy_tuning.trans_amp_adj << 14);
mvs_write_port_vsr_data(mvi, phy_id, tmp);
}
}
void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id,
struct ffe_control ffe)
{
u32 tmp;
/* Don't run this if A0/B0 */
if ((mvi->pdev->revision == VANIR_A0_REV)
|| (mvi->pdev->revision == VANIR_B0_REV))
return;
/* FFE Resistor and Capacitor */
/* R10Ch DFE Resolution Control/Squelch and FFE Setting
*
* FFE_FORCE [7]
* FFE_RES_SEL [6:4]
* FFE_CAP_SEL [3:0]
*/
mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL);
tmp = mvs_read_port_vsr_data(mvi, phy_id);
tmp &= ~0xFF;
/* Read from HBA_Info_Page */
tmp |= ((0x1 << 7) |
(ffe.ffe_rss_sel << 4) |
(ffe.ffe_cap_sel << 0));
mvs_write_port_vsr_data(mvi, phy_id, tmp);
/* R064h PHY Mode Register 1
*
* DFE_DIS 18
*/
mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL);
tmp = mvs_read_port_vsr_data(mvi, phy_id);
tmp &= ~0x40001;
/* Hard coding */