1dd4969a8SJeff Garzik /* 2*20b09c29SAndy Yan * Marvell 88SE64xx hardware specific 3*20b09c29SAndy Yan * 4*20b09c29SAndy Yan * Copyright 2007 Red Hat, Inc. 5*20b09c29SAndy Yan * Copyright 2008 Marvell. <kewei@marvell.com> 6*20b09c29SAndy Yan * 7*20b09c29SAndy Yan * This file is licensed under GPLv2. 8*20b09c29SAndy Yan * 9*20b09c29SAndy Yan * This program is free software; you can redistribute it and/or 10*20b09c29SAndy Yan * modify it under the terms of the GNU General Public License as 11*20b09c29SAndy Yan * published by the Free Software Foundation; version 2 of the 12*20b09c29SAndy Yan * License. 13*20b09c29SAndy Yan * 14*20b09c29SAndy Yan * This program is distributed in the hope that it will be useful, 15*20b09c29SAndy Yan * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*20b09c29SAndy Yan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17*20b09c29SAndy Yan * General Public License for more details. 18*20b09c29SAndy Yan * 19*20b09c29SAndy Yan * You should have received a copy of the GNU General Public License 20*20b09c29SAndy Yan * along with this program; if not, write to the Free Software 21*20b09c29SAndy Yan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 22*20b09c29SAndy Yan * USA 23dd4969a8SJeff Garzik */ 24dd4969a8SJeff Garzik 25dd4969a8SJeff Garzik #include "mv_sas.h" 26dd4969a8SJeff Garzik #include "mv_64xx.h" 27dd4969a8SJeff Garzik #include "mv_chips.h" 28dd4969a8SJeff Garzik 29*20b09c29SAndy Yan static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i) 30dd4969a8SJeff Garzik { 31dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 32dd4969a8SJeff Garzik u32 reg; 33dd4969a8SJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 34dd4969a8SJeff Garzik 35dd4969a8SJeff Garzik /* TODO check & save device type */ 36*20b09c29SAndy Yan reg = mr32(MVS_GBL_PORT_TYPE); 37*20b09c29SAndy Yan phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 38dd4969a8SJeff Garzik if (reg & MODE_SAS_SATA & (1 << i)) 39dd4969a8SJeff Garzik phy->phy_type |= PORT_TYPE_SAS; 40dd4969a8SJeff Garzik else 41dd4969a8SJeff Garzik phy->phy_type |= PORT_TYPE_SATA; 42dd4969a8SJeff Garzik } 43dd4969a8SJeff Garzik 44*20b09c29SAndy Yan static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id) 45dd4969a8SJeff Garzik { 46dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 47dd4969a8SJeff Garzik u32 tmp; 48dd4969a8SJeff Garzik 49*20b09c29SAndy Yan tmp = mr32(MVS_PCS); 50dd4969a8SJeff Garzik if (mvi->chip->n_phy <= 4) 51*20b09c29SAndy Yan tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT); 52dd4969a8SJeff Garzik else 53*20b09c29SAndy Yan tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); 54*20b09c29SAndy Yan mw32(MVS_PCS, tmp); 55dd4969a8SJeff Garzik } 56dd4969a8SJeff Garzik 57*20b09c29SAndy Yan static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi) 58dd4969a8SJeff Garzik { 59dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 60dd4969a8SJeff Garzik 61*20b09c29SAndy Yan mvs_phy_hacks(mvi); 62dd4969a8SJeff Garzik 63*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 64dd4969a8SJeff Garzik /* TEST - for phy decoding error, adjust voltage levels */ 65*20b09c29SAndy Yan mw32(MVS_P0_VSR_ADDR + 0, 0x8); 66*20b09c29SAndy Yan mw32(MVS_P0_VSR_DATA + 0, 0x2F0); 67dd4969a8SJeff Garzik 68*20b09c29SAndy Yan mw32(MVS_P0_VSR_ADDR + 8, 0x8); 69*20b09c29SAndy Yan mw32(MVS_P0_VSR_DATA + 8, 0x2F0); 70dd4969a8SJeff Garzik 71*20b09c29SAndy Yan mw32(MVS_P0_VSR_ADDR + 16, 0x8); 72*20b09c29SAndy Yan mw32(MVS_P0_VSR_DATA + 16, 0x2F0); 73dd4969a8SJeff Garzik 74*20b09c29SAndy Yan mw32(MVS_P0_VSR_ADDR + 24, 0x8); 75*20b09c29SAndy Yan mw32(MVS_P0_VSR_DATA + 24, 0x2F0); 76*20b09c29SAndy Yan } else { 77*20b09c29SAndy Yan int i; 78*20b09c29SAndy Yan /* disable auto port detection */ 79*20b09c29SAndy Yan mw32(MVS_GBL_PORT_TYPE, 0); 80*20b09c29SAndy Yan for (i = 0; i < mvi->chip->n_phy; i++) { 81*20b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7); 82*20b09c29SAndy Yan mvs_write_port_vsr_data(mvi, i, 0x90000000); 83*20b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9); 84*20b09c29SAndy Yan mvs_write_port_vsr_data(mvi, i, 0x50f2); 85*20b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11); 86*20b09c29SAndy Yan mvs_write_port_vsr_data(mvi, i, 0x0e); 87*20b09c29SAndy Yan } 88*20b09c29SAndy Yan } 89dd4969a8SJeff Garzik } 90dd4969a8SJeff Garzik 91*20b09c29SAndy Yan static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id) 92*20b09c29SAndy Yan { 93*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 94*20b09c29SAndy Yan u32 reg, tmp; 95*20b09c29SAndy Yan 96*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 97*20b09c29SAndy Yan if (phy_id < 4) 98*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, ®); 99*20b09c29SAndy Yan else 100*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, ®); 101*20b09c29SAndy Yan 102*20b09c29SAndy Yan } else 103*20b09c29SAndy Yan reg = mr32(MVS_PHY_CTL); 104*20b09c29SAndy Yan 105*20b09c29SAndy Yan tmp = reg; 106*20b09c29SAndy Yan if (phy_id < 4) 107*20b09c29SAndy Yan tmp |= (1U << phy_id) << PCTL_LINK_OFFS; 108*20b09c29SAndy Yan else 109*20b09c29SAndy Yan tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS; 110*20b09c29SAndy Yan 111*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 112*20b09c29SAndy Yan if (phy_id < 4) { 113*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 114*20b09c29SAndy Yan mdelay(10); 115*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg); 116*20b09c29SAndy Yan } else { 117*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 118*20b09c29SAndy Yan mdelay(10); 119*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg); 120*20b09c29SAndy Yan } 121*20b09c29SAndy Yan } else { 122*20b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 123*20b09c29SAndy Yan mdelay(10); 124*20b09c29SAndy Yan mw32(MVS_PHY_CTL, reg); 125*20b09c29SAndy Yan } 126*20b09c29SAndy Yan } 127*20b09c29SAndy Yan 128*20b09c29SAndy Yan static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) 129*20b09c29SAndy Yan { 130*20b09c29SAndy Yan u32 tmp; 131*20b09c29SAndy Yan tmp = mvs_read_port_irq_stat(mvi, phy_id); 132*20b09c29SAndy Yan tmp &= ~PHYEV_RDY_CH; 133*20b09c29SAndy Yan mvs_write_port_irq_stat(mvi, phy_id, tmp); 134*20b09c29SAndy Yan tmp = mvs_read_phy_ctl(mvi, phy_id); 135*20b09c29SAndy Yan if (hard) 136*20b09c29SAndy Yan tmp |= PHY_RST_HARD; 137*20b09c29SAndy Yan else 138*20b09c29SAndy Yan tmp |= PHY_RST; 139*20b09c29SAndy Yan mvs_write_phy_ctl(mvi, phy_id, tmp); 140*20b09c29SAndy Yan if (hard) { 141*20b09c29SAndy Yan do { 142*20b09c29SAndy Yan tmp = mvs_read_phy_ctl(mvi, phy_id); 143*20b09c29SAndy Yan } while (tmp & PHY_RST_HARD); 144*20b09c29SAndy Yan } 145*20b09c29SAndy Yan } 146*20b09c29SAndy Yan 147*20b09c29SAndy Yan static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi) 148*20b09c29SAndy Yan { 149*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 150*20b09c29SAndy Yan u32 tmp; 151*20b09c29SAndy Yan int i; 152*20b09c29SAndy Yan 153*20b09c29SAndy Yan /* make sure interrupts are masked immediately (paranoia) */ 154*20b09c29SAndy Yan mw32(MVS_GBL_CTL, 0); 155*20b09c29SAndy Yan tmp = mr32(MVS_GBL_CTL); 156*20b09c29SAndy Yan 157*20b09c29SAndy Yan /* Reset Controller */ 158*20b09c29SAndy Yan if (!(tmp & HBA_RST)) { 159*20b09c29SAndy Yan if (mvi->flags & MVF_PHY_PWR_FIX) { 160*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 161*20b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 162*20b09c29SAndy Yan tmp |= PCTL_PHY_DSBL; 163*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 164*20b09c29SAndy Yan 165*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 166*20b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 167*20b09c29SAndy Yan tmp |= PCTL_PHY_DSBL; 168*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 169*20b09c29SAndy Yan } 170*20b09c29SAndy Yan } 171*20b09c29SAndy Yan 172*20b09c29SAndy Yan /* make sure interrupts are masked immediately (paranoia) */ 173*20b09c29SAndy Yan mw32(MVS_GBL_CTL, 0); 174*20b09c29SAndy Yan tmp = mr32(MVS_GBL_CTL); 175*20b09c29SAndy Yan 176*20b09c29SAndy Yan /* Reset Controller */ 177*20b09c29SAndy Yan if (!(tmp & HBA_RST)) { 178*20b09c29SAndy Yan /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ 179*20b09c29SAndy Yan mw32_f(MVS_GBL_CTL, HBA_RST); 180*20b09c29SAndy Yan } 181*20b09c29SAndy Yan 182*20b09c29SAndy Yan /* wait for reset to finish; timeout is just a guess */ 183*20b09c29SAndy Yan i = 1000; 184*20b09c29SAndy Yan while (i-- > 0) { 185*20b09c29SAndy Yan msleep(10); 186*20b09c29SAndy Yan 187*20b09c29SAndy Yan if (!(mr32(MVS_GBL_CTL) & HBA_RST)) 188*20b09c29SAndy Yan break; 189*20b09c29SAndy Yan } 190*20b09c29SAndy Yan if (mr32(MVS_GBL_CTL) & HBA_RST) { 191*20b09c29SAndy Yan dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n"); 192*20b09c29SAndy Yan return -EBUSY; 193*20b09c29SAndy Yan } 194*20b09c29SAndy Yan return 0; 195*20b09c29SAndy Yan } 196*20b09c29SAndy Yan 197*20b09c29SAndy Yan static void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id) 198*20b09c29SAndy Yan { 199*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 200*20b09c29SAndy Yan u32 tmp; 201*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 202*20b09c29SAndy Yan u32 offs; 203*20b09c29SAndy Yan if (phy_id < 4) 204*20b09c29SAndy Yan offs = PCR_PHY_CTL; 205*20b09c29SAndy Yan else { 206*20b09c29SAndy Yan offs = PCR_PHY_CTL2; 207*20b09c29SAndy Yan phy_id -= 4; 208*20b09c29SAndy Yan } 209*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, offs, &tmp); 210*20b09c29SAndy Yan tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); 211*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, offs, tmp); 212*20b09c29SAndy Yan } else { 213*20b09c29SAndy Yan tmp = mr32(MVS_PHY_CTL); 214*20b09c29SAndy Yan tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); 215*20b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 216*20b09c29SAndy Yan } 217*20b09c29SAndy Yan } 218*20b09c29SAndy Yan 219*20b09c29SAndy Yan static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id) 220*20b09c29SAndy Yan { 221*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 222*20b09c29SAndy Yan u32 tmp; 223*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 224*20b09c29SAndy Yan u32 offs; 225*20b09c29SAndy Yan if (phy_id < 4) 226*20b09c29SAndy Yan offs = PCR_PHY_CTL; 227*20b09c29SAndy Yan else { 228*20b09c29SAndy Yan offs = PCR_PHY_CTL2; 229*20b09c29SAndy Yan phy_id -= 4; 230*20b09c29SAndy Yan } 231*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, offs, &tmp); 232*20b09c29SAndy Yan tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); 233*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, offs, tmp); 234*20b09c29SAndy Yan } else { 235*20b09c29SAndy Yan tmp = mr32(MVS_PHY_CTL); 236*20b09c29SAndy Yan tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); 237*20b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 238*20b09c29SAndy Yan } 239*20b09c29SAndy Yan } 240*20b09c29SAndy Yan 241*20b09c29SAndy Yan static int __devinit mvs_64xx_init(struct mvs_info *mvi) 242*20b09c29SAndy Yan { 243*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 244*20b09c29SAndy Yan int i; 245*20b09c29SAndy Yan u32 tmp, cctl; 246*20b09c29SAndy Yan 247*20b09c29SAndy Yan if (mvi->pdev && mvi->pdev->revision == 0) 248*20b09c29SAndy Yan mvi->flags |= MVF_PHY_PWR_FIX; 249*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 250*20b09c29SAndy Yan mvs_show_pcie_usage(mvi); 251*20b09c29SAndy Yan tmp = mvs_64xx_chip_reset(mvi); 252*20b09c29SAndy Yan if (tmp) 253*20b09c29SAndy Yan return tmp; 254*20b09c29SAndy Yan } else { 255*20b09c29SAndy Yan tmp = mr32(MVS_PHY_CTL); 256*20b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 257*20b09c29SAndy Yan tmp |= PCTL_PHY_DSBL; 258*20b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 259*20b09c29SAndy Yan } 260*20b09c29SAndy Yan 261*20b09c29SAndy Yan /* Init Chip */ 262*20b09c29SAndy Yan /* make sure RST is set; HBA_RST /should/ have done that for us */ 263*20b09c29SAndy Yan cctl = mr32(MVS_CTL) & 0xFFFF; 264*20b09c29SAndy Yan if (cctl & CCTL_RST) 265*20b09c29SAndy Yan cctl &= ~CCTL_RST; 266*20b09c29SAndy Yan else 267*20b09c29SAndy Yan mw32_f(MVS_CTL, cctl | CCTL_RST); 268*20b09c29SAndy Yan 269*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 270*20b09c29SAndy Yan /* write to device control _AND_ device status register */ 271*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); 272*20b09c29SAndy Yan tmp &= ~PRD_REQ_MASK; 273*20b09c29SAndy Yan tmp |= PRD_REQ_SIZE; 274*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); 275*20b09c29SAndy Yan 276*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 277*20b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 278*20b09c29SAndy Yan tmp &= ~PCTL_PHY_DSBL; 279*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 280*20b09c29SAndy Yan 281*20b09c29SAndy Yan pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 282*20b09c29SAndy Yan tmp &= PCTL_PWR_OFF; 283*20b09c29SAndy Yan tmp &= ~PCTL_PHY_DSBL; 284*20b09c29SAndy Yan pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 285*20b09c29SAndy Yan } else { 286*20b09c29SAndy Yan tmp = mr32(MVS_PHY_CTL); 287*20b09c29SAndy Yan tmp &= ~PCTL_PWR_OFF; 288*20b09c29SAndy Yan tmp |= PCTL_COM_ON; 289*20b09c29SAndy Yan tmp &= ~PCTL_PHY_DSBL; 290*20b09c29SAndy Yan tmp |= PCTL_LINK_RST; 291*20b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 292*20b09c29SAndy Yan msleep(100); 293*20b09c29SAndy Yan tmp &= ~PCTL_LINK_RST; 294*20b09c29SAndy Yan mw32(MVS_PHY_CTL, tmp); 295*20b09c29SAndy Yan msleep(100); 296*20b09c29SAndy Yan } 297*20b09c29SAndy Yan 298*20b09c29SAndy Yan /* reset control */ 299*20b09c29SAndy Yan mw32(MVS_PCS, 0); /* MVS_PCS */ 300*20b09c29SAndy Yan /* init phys */ 301*20b09c29SAndy Yan mvs_64xx_phy_hacks(mvi); 302*20b09c29SAndy Yan 303*20b09c29SAndy Yan /* enable auto port detection */ 304*20b09c29SAndy Yan mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN); 305*20b09c29SAndy Yan 306*20b09c29SAndy Yan mw32(MVS_CMD_LIST_LO, mvi->slot_dma); 307*20b09c29SAndy Yan mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 308*20b09c29SAndy Yan 309*20b09c29SAndy Yan mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); 310*20b09c29SAndy Yan mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 311*20b09c29SAndy Yan 312*20b09c29SAndy Yan mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); 313*20b09c29SAndy Yan mw32(MVS_TX_LO, mvi->tx_dma); 314*20b09c29SAndy Yan mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); 315*20b09c29SAndy Yan 316*20b09c29SAndy Yan mw32(MVS_RX_CFG, MVS_RX_RING_SZ); 317*20b09c29SAndy Yan mw32(MVS_RX_LO, mvi->rx_dma); 318*20b09c29SAndy Yan mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); 319*20b09c29SAndy Yan 320*20b09c29SAndy Yan for (i = 0; i < mvi->chip->n_phy; i++) { 321*20b09c29SAndy Yan /* set phy local SAS address */ 322*20b09c29SAndy Yan /* should set little endian SAS address to 64xx chip */ 323*20b09c29SAndy Yan mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI, 324*20b09c29SAndy Yan cpu_to_be64(mvi->phy[i].dev_sas_addr)); 325*20b09c29SAndy Yan 326*20b09c29SAndy Yan mvs_64xx_enable_xmt(mvi, i); 327*20b09c29SAndy Yan 328*20b09c29SAndy Yan mvs_64xx_phy_reset(mvi, i, 1); 329*20b09c29SAndy Yan msleep(500); 330*20b09c29SAndy Yan mvs_64xx_detect_porttype(mvi, i); 331*20b09c29SAndy Yan } 332*20b09c29SAndy Yan if (mvi->flags & MVF_FLAG_SOC) { 333*20b09c29SAndy Yan /* set select registers */ 334*20b09c29SAndy Yan writel(0x0E008000, regs + 0x000); 335*20b09c29SAndy Yan writel(0x59000008, regs + 0x004); 336*20b09c29SAndy Yan writel(0x20, regs + 0x008); 337*20b09c29SAndy Yan writel(0x20, regs + 0x00c); 338*20b09c29SAndy Yan writel(0x20, regs + 0x010); 339*20b09c29SAndy Yan writel(0x20, regs + 0x014); 340*20b09c29SAndy Yan writel(0x20, regs + 0x018); 341*20b09c29SAndy Yan writel(0x20, regs + 0x01c); 342*20b09c29SAndy Yan } 343*20b09c29SAndy Yan for (i = 0; i < mvi->chip->n_phy; i++) { 344*20b09c29SAndy Yan /* clear phy int status */ 345*20b09c29SAndy Yan tmp = mvs_read_port_irq_stat(mvi, i); 346*20b09c29SAndy Yan tmp &= ~PHYEV_SIG_FIS; 347*20b09c29SAndy Yan mvs_write_port_irq_stat(mvi, i, tmp); 348*20b09c29SAndy Yan 349*20b09c29SAndy Yan /* set phy int mask */ 350*20b09c29SAndy Yan tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | 351*20b09c29SAndy Yan PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR | 352*20b09c29SAndy Yan PHYEV_DEC_ERR; 353*20b09c29SAndy Yan mvs_write_port_irq_mask(mvi, i, tmp); 354*20b09c29SAndy Yan 355*20b09c29SAndy Yan msleep(100); 356*20b09c29SAndy Yan mvs_update_phyinfo(mvi, i, 1); 357*20b09c29SAndy Yan } 358*20b09c29SAndy Yan 359*20b09c29SAndy Yan /* FIXME: update wide port bitmaps */ 360*20b09c29SAndy Yan 361*20b09c29SAndy Yan /* little endian for open address and command table, etc. */ 362*20b09c29SAndy Yan /* 363*20b09c29SAndy Yan * it seems that ( from the spec ) turning on big-endian won't 364*20b09c29SAndy Yan * do us any good on big-endian machines, need further confirmation 365*20b09c29SAndy Yan */ 366*20b09c29SAndy Yan cctl = mr32(MVS_CTL); 367*20b09c29SAndy Yan cctl |= CCTL_ENDIAN_CMD; 368*20b09c29SAndy Yan cctl |= CCTL_ENDIAN_DATA; 369*20b09c29SAndy Yan cctl &= ~CCTL_ENDIAN_OPEN; 370*20b09c29SAndy Yan cctl |= CCTL_ENDIAN_RSP; 371*20b09c29SAndy Yan mw32_f(MVS_CTL, cctl); 372*20b09c29SAndy Yan 373*20b09c29SAndy Yan /* reset CMD queue */ 374*20b09c29SAndy Yan tmp = mr32(MVS_PCS); 375*20b09c29SAndy Yan tmp |= PCS_CMD_RST; 376*20b09c29SAndy Yan mw32(MVS_PCS, tmp); 377*20b09c29SAndy Yan /* interrupt coalescing may cause missing HW interrput in some case, 378*20b09c29SAndy Yan * and the max count is 0x1ff, while our max slot is 0x200, 379*20b09c29SAndy Yan * it will make count 0. 380*20b09c29SAndy Yan */ 381*20b09c29SAndy Yan tmp = 0; 382*20b09c29SAndy Yan mw32(MVS_INT_COAL, tmp); 383*20b09c29SAndy Yan 384*20b09c29SAndy Yan tmp = 0x100; 385*20b09c29SAndy Yan mw32(MVS_INT_COAL_TMOUT, tmp); 386*20b09c29SAndy Yan 387*20b09c29SAndy Yan /* ladies and gentlemen, start your engines */ 388*20b09c29SAndy Yan mw32(MVS_TX_CFG, 0); 389*20b09c29SAndy Yan mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 390*20b09c29SAndy Yan mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); 391*20b09c29SAndy Yan /* enable CMD/CMPL_Q/RESP mode */ 392*20b09c29SAndy Yan mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | 393*20b09c29SAndy Yan PCS_CMD_EN | PCS_CMD_STOP_ERR); 394*20b09c29SAndy Yan 395*20b09c29SAndy Yan /* enable completion queue interrupt */ 396*20b09c29SAndy Yan tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | 397*20b09c29SAndy Yan CINT_DMA_PCIE); 398*20b09c29SAndy Yan 399*20b09c29SAndy Yan mw32(MVS_INT_MASK, tmp); 400*20b09c29SAndy Yan 401*20b09c29SAndy Yan /* Enable SRS interrupt */ 402*20b09c29SAndy Yan mw32(MVS_INT_MASK_SRS_0, 0xFFFF); 403*20b09c29SAndy Yan 404*20b09c29SAndy Yan return 0; 405*20b09c29SAndy Yan } 406*20b09c29SAndy Yan 407*20b09c29SAndy Yan static int mvs_64xx_ioremap(struct mvs_info *mvi) 408*20b09c29SAndy Yan { 409*20b09c29SAndy Yan if (!mvs_ioremap(mvi, 4, 2)) 410*20b09c29SAndy Yan return 0; 411*20b09c29SAndy Yan return -1; 412*20b09c29SAndy Yan } 413*20b09c29SAndy Yan 414*20b09c29SAndy Yan static void mvs_64xx_iounmap(struct mvs_info *mvi) 415*20b09c29SAndy Yan { 416*20b09c29SAndy Yan mvs_iounmap(mvi->regs); 417*20b09c29SAndy Yan mvs_iounmap(mvi->regs_ex); 418*20b09c29SAndy Yan } 419*20b09c29SAndy Yan 420*20b09c29SAndy Yan static void mvs_64xx_interrupt_enable(struct mvs_info *mvi) 421dd4969a8SJeff Garzik { 422dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 423dd4969a8SJeff Garzik u32 tmp; 424dd4969a8SJeff Garzik 425*20b09c29SAndy Yan tmp = mr32(MVS_GBL_CTL); 426*20b09c29SAndy Yan mw32(MVS_GBL_CTL, tmp | INT_EN); 427dd4969a8SJeff Garzik } 428dd4969a8SJeff Garzik 429*20b09c29SAndy Yan static void mvs_64xx_interrupt_disable(struct mvs_info *mvi) 430dd4969a8SJeff Garzik { 431dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 432dd4969a8SJeff Garzik u32 tmp; 433dd4969a8SJeff Garzik 434*20b09c29SAndy Yan tmp = mr32(MVS_GBL_CTL); 435*20b09c29SAndy Yan mw32(MVS_GBL_CTL, tmp & ~INT_EN); 436dd4969a8SJeff Garzik } 437dd4969a8SJeff Garzik 438*20b09c29SAndy Yan static u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq) 439*20b09c29SAndy Yan { 440*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 441*20b09c29SAndy Yan u32 stat; 442*20b09c29SAndy Yan 443*20b09c29SAndy Yan if (!(mvi->flags & MVF_FLAG_SOC)) { 444*20b09c29SAndy Yan stat = mr32(MVS_GBL_INT_STAT); 445*20b09c29SAndy Yan 446*20b09c29SAndy Yan if (stat == 0 || stat == 0xffffffff) 447*20b09c29SAndy Yan return 0; 448*20b09c29SAndy Yan } else 449*20b09c29SAndy Yan stat = 1; 450*20b09c29SAndy Yan return stat; 451*20b09c29SAndy Yan } 452*20b09c29SAndy Yan 453*20b09c29SAndy Yan static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat) 454*20b09c29SAndy Yan { 455*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 456*20b09c29SAndy Yan 457*20b09c29SAndy Yan /* clear CMD_CMPLT ASAP */ 458*20b09c29SAndy Yan mw32_f(MVS_INT_STAT, CINT_DONE); 459*20b09c29SAndy Yan #ifndef MVS_USE_TASKLET 460*20b09c29SAndy Yan spin_lock(&mvi->lock); 461*20b09c29SAndy Yan #endif 462*20b09c29SAndy Yan mvs_int_full(mvi); 463*20b09c29SAndy Yan #ifndef MVS_USE_TASKLET 464*20b09c29SAndy Yan spin_unlock(&mvi->lock); 465*20b09c29SAndy Yan #endif 466*20b09c29SAndy Yan return IRQ_HANDLED; 467*20b09c29SAndy Yan } 468*20b09c29SAndy Yan 469*20b09c29SAndy Yan static void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx) 470*20b09c29SAndy Yan { 471*20b09c29SAndy Yan u32 tmp; 472*20b09c29SAndy Yan mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32)); 473*20b09c29SAndy Yan mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32)); 474*20b09c29SAndy Yan do { 475*20b09c29SAndy Yan tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3)); 476*20b09c29SAndy Yan } while (tmp & 1 << (slot_idx % 32)); 477*20b09c29SAndy Yan do { 478*20b09c29SAndy Yan tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3)); 479*20b09c29SAndy Yan } while (tmp & 1 << (slot_idx % 32)); 480*20b09c29SAndy Yan } 481*20b09c29SAndy Yan 482*20b09c29SAndy Yan static void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, 483*20b09c29SAndy Yan u32 tfs) 484*20b09c29SAndy Yan { 485*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 486*20b09c29SAndy Yan u32 tmp; 487*20b09c29SAndy Yan 488*20b09c29SAndy Yan if (type == PORT_TYPE_SATA) { 489*20b09c29SAndy Yan tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); 490*20b09c29SAndy Yan mw32(MVS_INT_STAT_SRS_0, tmp); 491*20b09c29SAndy Yan } 492*20b09c29SAndy Yan mw32(MVS_INT_STAT, CINT_CI_STOP); 493*20b09c29SAndy Yan tmp = mr32(MVS_PCS) | 0xFF00; 494*20b09c29SAndy Yan mw32(MVS_PCS, tmp); 495*20b09c29SAndy Yan } 496*20b09c29SAndy Yan 497*20b09c29SAndy Yan static void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) 498dd4969a8SJeff Garzik { 499dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 500dd4969a8SJeff Garzik u32 tmp, offs; 501dd4969a8SJeff Garzik 502dd4969a8SJeff Garzik if (*tfs == MVS_ID_NOT_MAPPED) 503dd4969a8SJeff Garzik return; 504dd4969a8SJeff Garzik 505dd4969a8SJeff Garzik offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); 506dd4969a8SJeff Garzik if (*tfs < 16) { 507*20b09c29SAndy Yan tmp = mr32(MVS_PCS); 508*20b09c29SAndy Yan mw32(MVS_PCS, tmp & ~offs); 509dd4969a8SJeff Garzik } else { 510*20b09c29SAndy Yan tmp = mr32(MVS_CTL); 511*20b09c29SAndy Yan mw32(MVS_CTL, tmp & ~offs); 512dd4969a8SJeff Garzik } 513dd4969a8SJeff Garzik 514*20b09c29SAndy Yan tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs); 515dd4969a8SJeff Garzik if (tmp) 516*20b09c29SAndy Yan mw32(MVS_INT_STAT_SRS_0, tmp); 517dd4969a8SJeff Garzik 518dd4969a8SJeff Garzik *tfs = MVS_ID_NOT_MAPPED; 519*20b09c29SAndy Yan return; 520dd4969a8SJeff Garzik } 521dd4969a8SJeff Garzik 522*20b09c29SAndy Yan static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) 523dd4969a8SJeff Garzik { 524dd4969a8SJeff Garzik int i; 525dd4969a8SJeff Garzik u32 tmp, offs; 526dd4969a8SJeff Garzik void __iomem *regs = mvi->regs; 527dd4969a8SJeff Garzik 528*20b09c29SAndy Yan if (*tfs != MVS_ID_NOT_MAPPED) 529dd4969a8SJeff Garzik return 0; 530dd4969a8SJeff Garzik 531*20b09c29SAndy Yan tmp = mr32(MVS_PCS); 532dd4969a8SJeff Garzik 533dd4969a8SJeff Garzik for (i = 0; i < mvi->chip->srs_sz; i++) { 534dd4969a8SJeff Garzik if (i == 16) 535*20b09c29SAndy Yan tmp = mr32(MVS_CTL); 536dd4969a8SJeff Garzik offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); 537dd4969a8SJeff Garzik if (!(tmp & offs)) { 538*20b09c29SAndy Yan *tfs = i; 539dd4969a8SJeff Garzik 540dd4969a8SJeff Garzik if (i < 16) 541*20b09c29SAndy Yan mw32(MVS_PCS, tmp | offs); 542dd4969a8SJeff Garzik else 543*20b09c29SAndy Yan mw32(MVS_CTL, tmp | offs); 544*20b09c29SAndy Yan tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i); 545dd4969a8SJeff Garzik if (tmp) 546*20b09c29SAndy Yan mw32(MVS_INT_STAT_SRS_0, tmp); 547dd4969a8SJeff Garzik return 0; 548dd4969a8SJeff Garzik } 549dd4969a8SJeff Garzik } 550dd4969a8SJeff Garzik return MVS_ID_NOT_MAPPED; 551dd4969a8SJeff Garzik } 552dd4969a8SJeff Garzik 553*20b09c29SAndy Yan void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd) 554*20b09c29SAndy Yan { 555*20b09c29SAndy Yan int i; 556*20b09c29SAndy Yan struct scatterlist *sg; 557*20b09c29SAndy Yan struct mvs_prd *buf_prd = prd; 558*20b09c29SAndy Yan for_each_sg(scatter, sg, nr, i) { 559*20b09c29SAndy Yan buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 560*20b09c29SAndy Yan buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 561*20b09c29SAndy Yan buf_prd++; 562*20b09c29SAndy Yan } 563*20b09c29SAndy Yan } 564*20b09c29SAndy Yan 565*20b09c29SAndy Yan static int mvs_64xx_oob_done(struct mvs_info *mvi, int i) 566*20b09c29SAndy Yan { 567*20b09c29SAndy Yan u32 phy_st; 568*20b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, i, 569*20b09c29SAndy Yan PHYR_PHY_STAT); 570*20b09c29SAndy Yan phy_st = mvs_read_port_cfg_data(mvi, i); 571*20b09c29SAndy Yan if (phy_st & PHY_OOB_DTCTD) 572*20b09c29SAndy Yan return 1; 573*20b09c29SAndy Yan return 0; 574*20b09c29SAndy Yan } 575*20b09c29SAndy Yan 576*20b09c29SAndy Yan static void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i, 577*20b09c29SAndy Yan struct sas_identify_frame *id) 578*20b09c29SAndy Yan 579*20b09c29SAndy Yan { 580*20b09c29SAndy Yan struct mvs_phy *phy = &mvi->phy[i]; 581*20b09c29SAndy Yan struct asd_sas_phy *sas_phy = &phy->sas_phy; 582*20b09c29SAndy Yan 583*20b09c29SAndy Yan sas_phy->linkrate = 584*20b09c29SAndy Yan (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 585*20b09c29SAndy Yan PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 586*20b09c29SAndy Yan 587*20b09c29SAndy Yan phy->minimum_linkrate = 588*20b09c29SAndy Yan (phy->phy_status & 589*20b09c29SAndy Yan PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; 590*20b09c29SAndy Yan phy->maximum_linkrate = 591*20b09c29SAndy Yan (phy->phy_status & 592*20b09c29SAndy Yan PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; 593*20b09c29SAndy Yan 594*20b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); 595*20b09c29SAndy Yan phy->dev_info = mvs_read_port_cfg_data(mvi, i); 596*20b09c29SAndy Yan 597*20b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); 598*20b09c29SAndy Yan phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); 599*20b09c29SAndy Yan 600*20b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); 601*20b09c29SAndy Yan phy->att_dev_sas_addr = 602*20b09c29SAndy Yan (u64) mvs_read_port_cfg_data(mvi, i) << 32; 603*20b09c29SAndy Yan mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); 604*20b09c29SAndy Yan phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); 605*20b09c29SAndy Yan phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr); 606*20b09c29SAndy Yan } 607*20b09c29SAndy Yan 608*20b09c29SAndy Yan static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i) 609*20b09c29SAndy Yan { 610*20b09c29SAndy Yan u32 tmp; 611*20b09c29SAndy Yan struct mvs_phy *phy = &mvi->phy[i]; 612*20b09c29SAndy Yan /* workaround for HW phy decoding error on 1.5g disk drive */ 613*20b09c29SAndy Yan mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); 614*20b09c29SAndy Yan tmp = mvs_read_port_vsr_data(mvi, i); 615*20b09c29SAndy Yan if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 616*20b09c29SAndy Yan PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == 617*20b09c29SAndy Yan SAS_LINK_RATE_1_5_GBPS) 618*20b09c29SAndy Yan tmp &= ~PHY_MODE6_LATECLK; 619*20b09c29SAndy Yan else 620*20b09c29SAndy Yan tmp |= PHY_MODE6_LATECLK; 621*20b09c29SAndy Yan mvs_write_port_vsr_data(mvi, i, tmp); 622*20b09c29SAndy Yan } 623*20b09c29SAndy Yan 624*20b09c29SAndy Yan void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, 625*20b09c29SAndy Yan struct sas_phy_linkrates *rates) 626*20b09c29SAndy Yan { 627*20b09c29SAndy Yan u32 lrmin = 0, lrmax = 0; 628*20b09c29SAndy Yan u32 tmp; 629*20b09c29SAndy Yan 630*20b09c29SAndy Yan tmp = mvs_read_phy_ctl(mvi, phy_id); 631*20b09c29SAndy Yan lrmin = (rates->minimum_linkrate << 8); 632*20b09c29SAndy Yan lrmax = (rates->maximum_linkrate << 12); 633*20b09c29SAndy Yan 634*20b09c29SAndy Yan if (lrmin) { 635*20b09c29SAndy Yan tmp &= ~(0xf << 8); 636*20b09c29SAndy Yan tmp |= lrmin; 637*20b09c29SAndy Yan } 638*20b09c29SAndy Yan if (lrmax) { 639*20b09c29SAndy Yan tmp &= ~(0xf << 12); 640*20b09c29SAndy Yan tmp |= lrmax; 641*20b09c29SAndy Yan } 642*20b09c29SAndy Yan mvs_write_phy_ctl(mvi, phy_id, tmp); 643*20b09c29SAndy Yan mvs_64xx_phy_reset(mvi, phy_id, 1); 644*20b09c29SAndy Yan } 645*20b09c29SAndy Yan 646*20b09c29SAndy Yan static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi) 647*20b09c29SAndy Yan { 648*20b09c29SAndy Yan u32 tmp; 649*20b09c29SAndy Yan void __iomem *regs = mvi->regs; 650*20b09c29SAndy Yan tmp = mr32(MVS_PCS); 651*20b09c29SAndy Yan mw32(MVS_PCS, tmp & 0xFFFF); 652*20b09c29SAndy Yan mw32(MVS_PCS, tmp); 653*20b09c29SAndy Yan tmp = mr32(MVS_CTL); 654*20b09c29SAndy Yan mw32(MVS_CTL, tmp & 0xFFFF); 655*20b09c29SAndy Yan mw32(MVS_CTL, tmp); 656*20b09c29SAndy Yan } 657*20b09c29SAndy Yan 658*20b09c29SAndy Yan 659*20b09c29SAndy Yan u32 mvs_64xx_spi_read_data(struct mvs_info *mvi) 660*20b09c29SAndy Yan { 661*20b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 662*20b09c29SAndy Yan return ior32(SPI_DATA_REG_64XX); 663*20b09c29SAndy Yan } 664*20b09c29SAndy Yan 665*20b09c29SAndy Yan void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data) 666*20b09c29SAndy Yan { 667*20b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 668*20b09c29SAndy Yan iow32(SPI_DATA_REG_64XX, data); 669*20b09c29SAndy Yan } 670*20b09c29SAndy Yan 671*20b09c29SAndy Yan 672*20b09c29SAndy Yan int mvs_64xx_spi_buildcmd(struct mvs_info *mvi, 673*20b09c29SAndy Yan u32 *dwCmd, 674*20b09c29SAndy Yan u8 cmd, 675*20b09c29SAndy Yan u8 read, 676*20b09c29SAndy Yan u8 length, 677*20b09c29SAndy Yan u32 addr 678*20b09c29SAndy Yan ) 679*20b09c29SAndy Yan { 680*20b09c29SAndy Yan u32 dwTmp; 681*20b09c29SAndy Yan 682*20b09c29SAndy Yan dwTmp = ((u32)cmd << 24) | ((u32)length << 19); 683*20b09c29SAndy Yan if (read) 684*20b09c29SAndy Yan dwTmp |= 1U<<23; 685*20b09c29SAndy Yan 686*20b09c29SAndy Yan if (addr != MV_MAX_U32) { 687*20b09c29SAndy Yan dwTmp |= 1U<<22; 688*20b09c29SAndy Yan dwTmp |= (addr & 0x0003FFFF); 689*20b09c29SAndy Yan } 690*20b09c29SAndy Yan 691*20b09c29SAndy Yan *dwCmd = dwTmp; 692*20b09c29SAndy Yan return 0; 693*20b09c29SAndy Yan } 694*20b09c29SAndy Yan 695*20b09c29SAndy Yan 696*20b09c29SAndy Yan int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) 697*20b09c29SAndy Yan { 698*20b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 699*20b09c29SAndy Yan int retry; 700*20b09c29SAndy Yan 701*20b09c29SAndy Yan for (retry = 0; retry < 1; retry++) { 702*20b09c29SAndy Yan iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE); 703*20b09c29SAndy Yan iow32(SPI_CMD_REG_64XX, cmd); 704*20b09c29SAndy Yan iow32(SPI_CTRL_REG_64XX, 705*20b09c29SAndy Yan SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART); 706*20b09c29SAndy Yan } 707*20b09c29SAndy Yan 708*20b09c29SAndy Yan return 0; 709*20b09c29SAndy Yan } 710*20b09c29SAndy Yan 711*20b09c29SAndy Yan int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) 712*20b09c29SAndy Yan { 713*20b09c29SAndy Yan void __iomem *regs = mvi->regs_ex; 714*20b09c29SAndy Yan u32 i, dwTmp; 715*20b09c29SAndy Yan 716*20b09c29SAndy Yan for (i = 0; i < timeout; i++) { 717*20b09c29SAndy Yan dwTmp = ior32(SPI_CTRL_REG_64XX); 718*20b09c29SAndy Yan if (!(dwTmp & SPI_CTRL_SPISTART)) 719*20b09c29SAndy Yan return 0; 720*20b09c29SAndy Yan msleep(10); 721*20b09c29SAndy Yan } 722*20b09c29SAndy Yan 723*20b09c29SAndy Yan return -1; 724*20b09c29SAndy Yan } 725*20b09c29SAndy Yan 726*20b09c29SAndy Yan #ifndef DISABLE_HOTPLUG_DMA_FIX 727*20b09c29SAndy Yan void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd) 728*20b09c29SAndy Yan { 729*20b09c29SAndy Yan int i; 730*20b09c29SAndy Yan struct mvs_prd *buf_prd = prd; 731*20b09c29SAndy Yan buf_prd += from; 732*20b09c29SAndy Yan for (i = 0; i < MAX_SG_ENTRY - from; i++) { 733*20b09c29SAndy Yan buf_prd->addr = cpu_to_le64(buf_dma); 734*20b09c29SAndy Yan buf_prd->len = cpu_to_le32(buf_len); 735*20b09c29SAndy Yan ++buf_prd; 736*20b09c29SAndy Yan } 737*20b09c29SAndy Yan } 738*20b09c29SAndy Yan #endif 739*20b09c29SAndy Yan 740*20b09c29SAndy Yan const struct mvs_dispatch mvs_64xx_dispatch = { 741*20b09c29SAndy Yan "mv64xx", 742*20b09c29SAndy Yan mvs_64xx_init, 743*20b09c29SAndy Yan NULL, 744*20b09c29SAndy Yan mvs_64xx_ioremap, 745*20b09c29SAndy Yan mvs_64xx_iounmap, 746*20b09c29SAndy Yan mvs_64xx_isr, 747*20b09c29SAndy Yan mvs_64xx_isr_status, 748*20b09c29SAndy Yan mvs_64xx_interrupt_enable, 749*20b09c29SAndy Yan mvs_64xx_interrupt_disable, 750*20b09c29SAndy Yan mvs_read_phy_ctl, 751*20b09c29SAndy Yan mvs_write_phy_ctl, 752*20b09c29SAndy Yan mvs_read_port_cfg_data, 753*20b09c29SAndy Yan mvs_write_port_cfg_data, 754*20b09c29SAndy Yan mvs_write_port_cfg_addr, 755*20b09c29SAndy Yan mvs_read_port_vsr_data, 756*20b09c29SAndy Yan mvs_write_port_vsr_data, 757*20b09c29SAndy Yan mvs_write_port_vsr_addr, 758*20b09c29SAndy Yan mvs_read_port_irq_stat, 759*20b09c29SAndy Yan mvs_write_port_irq_stat, 760*20b09c29SAndy Yan mvs_read_port_irq_mask, 761*20b09c29SAndy Yan mvs_write_port_irq_mask, 762*20b09c29SAndy Yan mvs_get_sas_addr, 763*20b09c29SAndy Yan mvs_64xx_command_active, 764*20b09c29SAndy Yan mvs_64xx_issue_stop, 765*20b09c29SAndy Yan mvs_start_delivery, 766*20b09c29SAndy Yan mvs_rx_update, 767*20b09c29SAndy Yan mvs_int_full, 768*20b09c29SAndy Yan mvs_64xx_assign_reg_set, 769*20b09c29SAndy Yan mvs_64xx_free_reg_set, 770*20b09c29SAndy Yan mvs_get_prd_size, 771*20b09c29SAndy Yan mvs_get_prd_count, 772*20b09c29SAndy Yan mvs_64xx_make_prd, 773*20b09c29SAndy Yan mvs_64xx_detect_porttype, 774*20b09c29SAndy Yan mvs_64xx_oob_done, 775*20b09c29SAndy Yan mvs_64xx_fix_phy_info, 776*20b09c29SAndy Yan mvs_64xx_phy_work_around, 777*20b09c29SAndy Yan mvs_64xx_phy_set_link_rate, 778*20b09c29SAndy Yan mvs_hw_max_link_rate, 779*20b09c29SAndy Yan mvs_64xx_phy_disable, 780*20b09c29SAndy Yan mvs_64xx_phy_enable, 781*20b09c29SAndy Yan mvs_64xx_phy_reset, 782*20b09c29SAndy Yan mvs_64xx_stp_reset, 783*20b09c29SAndy Yan mvs_64xx_clear_active_cmds, 784*20b09c29SAndy Yan mvs_64xx_spi_read_data, 785*20b09c29SAndy Yan mvs_64xx_spi_write_data, 786*20b09c29SAndy Yan mvs_64xx_spi_buildcmd, 787*20b09c29SAndy Yan mvs_64xx_spi_issuecmd, 788*20b09c29SAndy Yan mvs_64xx_spi_waitdataready, 789*20b09c29SAndy Yan #ifndef DISABLE_HOTPLUG_DMA_FIX 790*20b09c29SAndy Yan mvs_64xx_fix_dma, 791*20b09c29SAndy Yan #endif 792*20b09c29SAndy Yan }; 793*20b09c29SAndy Yan 794