1*dd4969a8SJeff Garzik /* 2*dd4969a8SJeff Garzik mv_64xx.c - Marvell 88SE6440 SAS/SATA support 3*dd4969a8SJeff Garzik 4*dd4969a8SJeff Garzik Copyright 2007 Red Hat, Inc. 5*dd4969a8SJeff Garzik Copyright 2008 Marvell. <kewei@marvell.com> 6*dd4969a8SJeff Garzik 7*dd4969a8SJeff Garzik This program is free software; you can redistribute it and/or 8*dd4969a8SJeff Garzik modify it under the terms of the GNU General Public License as 9*dd4969a8SJeff Garzik published by the Free Software Foundation; either version 2, 10*dd4969a8SJeff Garzik or (at your option) any later version. 11*dd4969a8SJeff Garzik 12*dd4969a8SJeff Garzik This program is distributed in the hope that it will be useful, 13*dd4969a8SJeff Garzik but WITHOUT ANY WARRANTY; without even the implied warranty 14*dd4969a8SJeff Garzik of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15*dd4969a8SJeff Garzik See the GNU General Public License for more details. 16*dd4969a8SJeff Garzik 17*dd4969a8SJeff Garzik You should have received a copy of the GNU General Public 18*dd4969a8SJeff Garzik License along with this program; see the file COPYING. If not, 19*dd4969a8SJeff Garzik write to the Free Software Foundation, 675 Mass Ave, Cambridge, 20*dd4969a8SJeff Garzik MA 02139, USA. 21*dd4969a8SJeff Garzik 22*dd4969a8SJeff Garzik */ 23*dd4969a8SJeff Garzik 24*dd4969a8SJeff Garzik #include "mv_sas.h" 25*dd4969a8SJeff Garzik #include "mv_64xx.h" 26*dd4969a8SJeff Garzik #include "mv_chips.h" 27*dd4969a8SJeff Garzik 28*dd4969a8SJeff Garzik void mvs_detect_porttype(struct mvs_info *mvi, int i) 29*dd4969a8SJeff Garzik { 30*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 31*dd4969a8SJeff Garzik u32 reg; 32*dd4969a8SJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 33*dd4969a8SJeff Garzik 34*dd4969a8SJeff Garzik /* TODO check & save device type */ 35*dd4969a8SJeff Garzik reg = mr32(GBL_PORT_TYPE); 36*dd4969a8SJeff Garzik 37*dd4969a8SJeff Garzik if (reg & MODE_SAS_SATA & (1 << i)) 38*dd4969a8SJeff Garzik phy->phy_type |= PORT_TYPE_SAS; 39*dd4969a8SJeff Garzik else 40*dd4969a8SJeff Garzik phy->phy_type |= PORT_TYPE_SATA; 41*dd4969a8SJeff Garzik } 42*dd4969a8SJeff Garzik 43*dd4969a8SJeff Garzik void mvs_enable_xmt(struct mvs_info *mvi, int PhyId) 44*dd4969a8SJeff Garzik { 45*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 46*dd4969a8SJeff Garzik u32 tmp; 47*dd4969a8SJeff Garzik 48*dd4969a8SJeff Garzik tmp = mr32(PCS); 49*dd4969a8SJeff Garzik if (mvi->chip->n_phy <= 4) 50*dd4969a8SJeff Garzik tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT); 51*dd4969a8SJeff Garzik else 52*dd4969a8SJeff Garzik tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2); 53*dd4969a8SJeff Garzik mw32(PCS, tmp); 54*dd4969a8SJeff Garzik } 55*dd4969a8SJeff Garzik 56*dd4969a8SJeff Garzik void __devinit mvs_phy_hacks(struct mvs_info *mvi) 57*dd4969a8SJeff Garzik { 58*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 59*dd4969a8SJeff Garzik u32 tmp; 60*dd4969a8SJeff Garzik 61*dd4969a8SJeff Garzik /* workaround for SATA R-ERR, to ignore phy glitch */ 62*dd4969a8SJeff Garzik tmp = mvs_cr32(regs, CMD_PHY_TIMER); 63*dd4969a8SJeff Garzik tmp &= ~(1 << 9); 64*dd4969a8SJeff Garzik tmp |= (1 << 10); 65*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_PHY_TIMER, tmp); 66*dd4969a8SJeff Garzik 67*dd4969a8SJeff Garzik /* enable retry 127 times */ 68*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f); 69*dd4969a8SJeff Garzik 70*dd4969a8SJeff Garzik /* extend open frame timeout to max */ 71*dd4969a8SJeff Garzik tmp = mvs_cr32(regs, CMD_SAS_CTL0); 72*dd4969a8SJeff Garzik tmp &= ~0xffff; 73*dd4969a8SJeff Garzik tmp |= 0x3fff; 74*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_SAS_CTL0, tmp); 75*dd4969a8SJeff Garzik 76*dd4969a8SJeff Garzik /* workaround for WDTIMEOUT , set to 550 ms */ 77*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_WD_TIMER, 0x86470); 78*dd4969a8SJeff Garzik 79*dd4969a8SJeff Garzik /* not to halt for different port op during wideport link change */ 80*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d); 81*dd4969a8SJeff Garzik 82*dd4969a8SJeff Garzik /* workaround for Seagate disk not-found OOB sequence, recv 83*dd4969a8SJeff Garzik * COMINIT before sending out COMWAKE */ 84*dd4969a8SJeff Garzik tmp = mvs_cr32(regs, CMD_PHY_MODE_21); 85*dd4969a8SJeff Garzik tmp &= 0x0000ffff; 86*dd4969a8SJeff Garzik tmp |= 0x00fa0000; 87*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_PHY_MODE_21, tmp); 88*dd4969a8SJeff Garzik 89*dd4969a8SJeff Garzik tmp = mvs_cr32(regs, CMD_PHY_TIMER); 90*dd4969a8SJeff Garzik tmp &= 0x1fffffff; 91*dd4969a8SJeff Garzik tmp |= (2U << 29); /* 8 ms retry */ 92*dd4969a8SJeff Garzik mvs_cw32(regs, CMD_PHY_TIMER, tmp); 93*dd4969a8SJeff Garzik 94*dd4969a8SJeff Garzik /* TEST - for phy decoding error, adjust voltage levels */ 95*dd4969a8SJeff Garzik mw32(P0_VSR_ADDR + 0, 0x8); 96*dd4969a8SJeff Garzik mw32(P0_VSR_DATA + 0, 0x2F0); 97*dd4969a8SJeff Garzik 98*dd4969a8SJeff Garzik mw32(P0_VSR_ADDR + 8, 0x8); 99*dd4969a8SJeff Garzik mw32(P0_VSR_DATA + 8, 0x2F0); 100*dd4969a8SJeff Garzik 101*dd4969a8SJeff Garzik mw32(P0_VSR_ADDR + 16, 0x8); 102*dd4969a8SJeff Garzik mw32(P0_VSR_DATA + 16, 0x2F0); 103*dd4969a8SJeff Garzik 104*dd4969a8SJeff Garzik mw32(P0_VSR_ADDR + 24, 0x8); 105*dd4969a8SJeff Garzik mw32(P0_VSR_DATA + 24, 0x2F0); 106*dd4969a8SJeff Garzik 107*dd4969a8SJeff Garzik } 108*dd4969a8SJeff Garzik 109*dd4969a8SJeff Garzik void mvs_hba_interrupt_enable(struct mvs_info *mvi) 110*dd4969a8SJeff Garzik { 111*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 112*dd4969a8SJeff Garzik u32 tmp; 113*dd4969a8SJeff Garzik 114*dd4969a8SJeff Garzik tmp = mr32(GBL_CTL); 115*dd4969a8SJeff Garzik 116*dd4969a8SJeff Garzik mw32(GBL_CTL, tmp | INT_EN); 117*dd4969a8SJeff Garzik } 118*dd4969a8SJeff Garzik 119*dd4969a8SJeff Garzik void mvs_hba_interrupt_disable(struct mvs_info *mvi) 120*dd4969a8SJeff Garzik { 121*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 122*dd4969a8SJeff Garzik u32 tmp; 123*dd4969a8SJeff Garzik 124*dd4969a8SJeff Garzik tmp = mr32(GBL_CTL); 125*dd4969a8SJeff Garzik 126*dd4969a8SJeff Garzik mw32(GBL_CTL, tmp & ~INT_EN); 127*dd4969a8SJeff Garzik } 128*dd4969a8SJeff Garzik 129*dd4969a8SJeff Garzik void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port) 130*dd4969a8SJeff Garzik { 131*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 132*dd4969a8SJeff Garzik u32 tmp, offs; 133*dd4969a8SJeff Garzik u8 *tfs = &port->taskfileset; 134*dd4969a8SJeff Garzik 135*dd4969a8SJeff Garzik if (*tfs == MVS_ID_NOT_MAPPED) 136*dd4969a8SJeff Garzik return; 137*dd4969a8SJeff Garzik 138*dd4969a8SJeff Garzik offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); 139*dd4969a8SJeff Garzik if (*tfs < 16) { 140*dd4969a8SJeff Garzik tmp = mr32(PCS); 141*dd4969a8SJeff Garzik mw32(PCS, tmp & ~offs); 142*dd4969a8SJeff Garzik } else { 143*dd4969a8SJeff Garzik tmp = mr32(CTL); 144*dd4969a8SJeff Garzik mw32(CTL, tmp & ~offs); 145*dd4969a8SJeff Garzik } 146*dd4969a8SJeff Garzik 147*dd4969a8SJeff Garzik tmp = mr32(INT_STAT_SRS) & (1U << *tfs); 148*dd4969a8SJeff Garzik if (tmp) 149*dd4969a8SJeff Garzik mw32(INT_STAT_SRS, tmp); 150*dd4969a8SJeff Garzik 151*dd4969a8SJeff Garzik *tfs = MVS_ID_NOT_MAPPED; 152*dd4969a8SJeff Garzik } 153*dd4969a8SJeff Garzik 154*dd4969a8SJeff Garzik u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port) 155*dd4969a8SJeff Garzik { 156*dd4969a8SJeff Garzik int i; 157*dd4969a8SJeff Garzik u32 tmp, offs; 158*dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 159*dd4969a8SJeff Garzik 160*dd4969a8SJeff Garzik if (port->taskfileset != MVS_ID_NOT_MAPPED) 161*dd4969a8SJeff Garzik return 0; 162*dd4969a8SJeff Garzik 163*dd4969a8SJeff Garzik tmp = mr32(PCS); 164*dd4969a8SJeff Garzik 165*dd4969a8SJeff Garzik for (i = 0; i < mvi->chip->srs_sz; i++) { 166*dd4969a8SJeff Garzik if (i == 16) 167*dd4969a8SJeff Garzik tmp = mr32(CTL); 168*dd4969a8SJeff Garzik offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); 169*dd4969a8SJeff Garzik if (!(tmp & offs)) { 170*dd4969a8SJeff Garzik port->taskfileset = i; 171*dd4969a8SJeff Garzik 172*dd4969a8SJeff Garzik if (i < 16) 173*dd4969a8SJeff Garzik mw32(PCS, tmp | offs); 174*dd4969a8SJeff Garzik else 175*dd4969a8SJeff Garzik mw32(CTL, tmp | offs); 176*dd4969a8SJeff Garzik tmp = mr32(INT_STAT_SRS) & (1U << i); 177*dd4969a8SJeff Garzik if (tmp) 178*dd4969a8SJeff Garzik mw32(INT_STAT_SRS, tmp); 179*dd4969a8SJeff Garzik return 0; 180*dd4969a8SJeff Garzik } 181*dd4969a8SJeff Garzik } 182*dd4969a8SJeff Garzik return MVS_ID_NOT_MAPPED; 183*dd4969a8SJeff Garzik } 184*dd4969a8SJeff Garzik 185