123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- /*
- mv_64xx.c - Marvell 88SE6440 SAS/SATA support
- Copyright 2007 Red Hat, Inc.
- Copyright 2008 Marvell. <kewei@marvell.com>
- 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; either version 2,
- or (at your option) any later version.
- 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; see the file COPYING. If not,
- write to the Free Software Foundation, 675 Mass Ave, Cambridge,
- MA 02139, USA.
- */
- #include "mv_sas.h"
- #include "mv_64xx.h"
- #include "mv_chips.h"
- void mvs_detect_porttype(struct mvs_info *mvi, int i)
- {
- void __iomem *regs = mvi->regs;
- u32 reg;
- struct mvs_phy *phy = &mvi->phy[i];
- /* TODO check & save device type */
- reg = mr32(GBL_PORT_TYPE);
- if (reg & MODE_SAS_SATA & (1 << i))
- phy->phy_type |= PORT_TYPE_SAS;
- else
- phy->phy_type |= PORT_TYPE_SATA;
- }
- void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
- {
- void __iomem *regs = mvi->regs;
- u32 tmp;
- tmp = mr32(PCS);
- if (mvi->chip->n_phy <= 4)
- tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
- else
- tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
- mw32(PCS, tmp);
- }
- void __devinit mvs_phy_hacks(struct mvs_info *mvi)
- {
- void __iomem *regs = mvi->regs;
- u32 tmp;
- /* workaround for SATA R-ERR, to ignore phy glitch */
- tmp = mvs_cr32(regs, CMD_PHY_TIMER);
- tmp &= ~(1 << 9);
- tmp |= (1 << 10);
- mvs_cw32(regs, CMD_PHY_TIMER, tmp);
- /* enable retry 127 times */
- mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
- /* extend open frame timeout to max */
- tmp = mvs_cr32(regs, CMD_SAS_CTL0);
- tmp &= ~0xffff;
- tmp |= 0x3fff;
- mvs_cw32(regs, CMD_SAS_CTL0, tmp);
- /* workaround for WDTIMEOUT , set to 550 ms */
- mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
- /* not to halt for different port op during wideport link change */
- mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
- /* workaround for Seagate disk not-found OOB sequence, recv
- * COMINIT before sending out COMWAKE */
- tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
- tmp &= 0x0000ffff;
- tmp |= 0x00fa0000;
- mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
- tmp = mvs_cr32(regs, CMD_PHY_TIMER);
- tmp &= 0x1fffffff;
- tmp |= (2U << 29); /* 8 ms retry */
- mvs_cw32(regs, CMD_PHY_TIMER, tmp);
- /* TEST - for phy decoding error, adjust voltage levels */
- mw32(P0_VSR_ADDR + 0, 0x8);
- mw32(P0_VSR_DATA + 0, 0x2F0);
- mw32(P0_VSR_ADDR + 8, 0x8);
- mw32(P0_VSR_DATA + 8, 0x2F0);
- mw32(P0_VSR_ADDR + 16, 0x8);
- mw32(P0_VSR_DATA + 16, 0x2F0);
- mw32(P0_VSR_ADDR + 24, 0x8);
- mw32(P0_VSR_DATA + 24, 0x2F0);
- }
- void mvs_hba_interrupt_enable(struct mvs_info *mvi)
- {
- void __iomem *regs = mvi->regs;
- u32 tmp;
- tmp = mr32(GBL_CTL);
- mw32(GBL_CTL, tmp | INT_EN);
- }
- void mvs_hba_interrupt_disable(struct mvs_info *mvi)
- {
- void __iomem *regs = mvi->regs;
- u32 tmp;
- tmp = mr32(GBL_CTL);
- mw32(GBL_CTL, tmp & ~INT_EN);
- }
- void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
- {
- void __iomem *regs = mvi->regs;
- u32 tmp, offs;
- u8 *tfs = &port->taskfileset;
- if (*tfs == MVS_ID_NOT_MAPPED)
- return;
- offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
- if (*tfs < 16) {
- tmp = mr32(PCS);
- mw32(PCS, tmp & ~offs);
- } else {
- tmp = mr32(CTL);
- mw32(CTL, tmp & ~offs);
- }
- tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
- if (tmp)
- mw32(INT_STAT_SRS, tmp);
- *tfs = MVS_ID_NOT_MAPPED;
- }
- u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
- {
- int i;
- u32 tmp, offs;
- void __iomem *regs = mvi->regs;
- if (port->taskfileset != MVS_ID_NOT_MAPPED)
- return 0;
- tmp = mr32(PCS);
- for (i = 0; i < mvi->chip->srs_sz; i++) {
- if (i == 16)
- tmp = mr32(CTL);
- offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
- if (!(tmp & offs)) {
- port->taskfileset = i;
- if (i < 16)
- mw32(PCS, tmp | offs);
- else
- mw32(CTL, tmp | offs);
- tmp = mr32(INT_STAT_SRS) & (1U << i);
- if (tmp)
- mw32(INT_STAT_SRS, tmp);
- return 0;
- }
- }
- return MVS_ID_NOT_MAPPED;
- }
|