162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Marvell 88SE64xx hardware specific 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2007 Red Hat, Inc. 662306a36Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com> 762306a36Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 862306a36Sopenharmony_ci*/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "mv_sas.h" 1162306a36Sopenharmony_ci#include "mv_64xx.h" 1262306a36Sopenharmony_ci#include "mv_chips.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 1762306a36Sopenharmony_ci u32 reg; 1862306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci reg = mr32(MVS_GBL_PORT_TYPE); 2162306a36Sopenharmony_ci phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 2262306a36Sopenharmony_ci if (reg & MODE_SAS_SATA & (1 << i)) 2362306a36Sopenharmony_ci phy->phy_type |= PORT_TYPE_SAS; 2462306a36Sopenharmony_ci else 2562306a36Sopenharmony_ci phy->phy_type |= PORT_TYPE_SATA; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 3162306a36Sopenharmony_ci u32 tmp; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 3462306a36Sopenharmony_ci if (mvi->chip->n_phy <= MVS_SOC_PORTS) 3562306a36Sopenharmony_ci tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT); 3662306a36Sopenharmony_ci else 3762306a36Sopenharmony_ci tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); 3862306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void mvs_64xx_phy_hacks(struct mvs_info *mvi) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 4462306a36Sopenharmony_ci int i; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci mvs_phy_hacks(mvi); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 4962306a36Sopenharmony_ci for (i = 0; i < MVS_SOC_PORTS; i++) { 5062306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE8); 5162306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x2F0); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } else { 5462306a36Sopenharmony_ci /* disable auto port detection */ 5562306a36Sopenharmony_ci mw32(MVS_GBL_PORT_TYPE, 0); 5662306a36Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 5762306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7); 5862306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x90000000); 5962306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9); 6062306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x50f2); 6162306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11); 6262306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x0e); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 7062306a36Sopenharmony_ci u32 reg, tmp; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 7362306a36Sopenharmony_ci if (phy_id < MVS_SOC_PORTS) 7462306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, ®); 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, ®); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci } else 7962306a36Sopenharmony_ci reg = mr32(MVS_PHY_CTL); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci tmp = reg; 8262306a36Sopenharmony_ci if (phy_id < MVS_SOC_PORTS) 8362306a36Sopenharmony_ci tmp |= (1U << phy_id) << PCTL_LINK_OFFS; 8462306a36Sopenharmony_ci else 8562306a36Sopenharmony_ci tmp |= (1U << (phy_id - MVS_SOC_PORTS)) << PCTL_LINK_OFFS; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 8862306a36Sopenharmony_ci if (phy_id < MVS_SOC_PORTS) { 8962306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 9062306a36Sopenharmony_ci mdelay(10); 9162306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg); 9262306a36Sopenharmony_ci } else { 9362306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 9462306a36Sopenharmony_ci mdelay(10); 9562306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci } else { 9862306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 9962306a36Sopenharmony_ci mdelay(10); 10062306a36Sopenharmony_ci mw32(MVS_PHY_CTL, reg); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci u32 tmp; 10762306a36Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, phy_id); 10862306a36Sopenharmony_ci tmp &= ~PHYEV_RDY_CH; 10962306a36Sopenharmony_ci mvs_write_port_irq_stat(mvi, phy_id, tmp); 11062306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 11162306a36Sopenharmony_ci if (hard == MVS_HARD_RESET) 11262306a36Sopenharmony_ci tmp |= PHY_RST_HARD; 11362306a36Sopenharmony_ci else if (hard == MVS_SOFT_RESET) 11462306a36Sopenharmony_ci tmp |= PHY_RST; 11562306a36Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 11662306a36Sopenharmony_ci if (hard) { 11762306a36Sopenharmony_ci do { 11862306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 11962306a36Sopenharmony_ci } while (tmp & PHY_RST_HARD); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void 12462306a36Sopenharmony_cimvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 12762306a36Sopenharmony_ci u32 tmp; 12862306a36Sopenharmony_ci if (clear_all) { 12962306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 13062306a36Sopenharmony_ci if (tmp) { 13162306a36Sopenharmony_ci printk(KERN_DEBUG "check SRS 0 %08X.\n", tmp); 13262306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } else { 13562306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 13662306a36Sopenharmony_ci if (tmp & (1 << (reg_set % 32))) { 13762306a36Sopenharmony_ci printk(KERN_DEBUG "register set 0x%x was stopped.\n", 13862306a36Sopenharmony_ci reg_set); 13962306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int mvs_64xx_chip_reset(struct mvs_info *mvi) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 14762306a36Sopenharmony_ci u32 tmp; 14862306a36Sopenharmony_ci int i; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* make sure interrupts are masked immediately (paranoia) */ 15162306a36Sopenharmony_ci mw32(MVS_GBL_CTL, 0); 15262306a36Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Reset Controller */ 15562306a36Sopenharmony_ci if (!(tmp & HBA_RST)) { 15662306a36Sopenharmony_ci if (mvi->flags & MVF_PHY_PWR_FIX) { 15762306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 15862306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 15962306a36Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 16062306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 16362306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 16462306a36Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 16562306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* make sure interrupts are masked immediately (paranoia) */ 17062306a36Sopenharmony_ci mw32(MVS_GBL_CTL, 0); 17162306a36Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Reset Controller */ 17462306a36Sopenharmony_ci if (!(tmp & HBA_RST)) { 17562306a36Sopenharmony_ci /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ 17662306a36Sopenharmony_ci mw32_f(MVS_GBL_CTL, HBA_RST); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* wait for reset to finish; timeout is just a guess */ 18062306a36Sopenharmony_ci i = 1000; 18162306a36Sopenharmony_ci while (i-- > 0) { 18262306a36Sopenharmony_ci msleep(10); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (!(mr32(MVS_GBL_CTL) & HBA_RST)) 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci if (mr32(MVS_GBL_CTL) & HBA_RST) { 18862306a36Sopenharmony_ci dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n"); 18962306a36Sopenharmony_ci return -EBUSY; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 19762306a36Sopenharmony_ci u32 tmp; 19862306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 19962306a36Sopenharmony_ci u32 offs; 20062306a36Sopenharmony_ci if (phy_id < 4) 20162306a36Sopenharmony_ci offs = PCR_PHY_CTL; 20262306a36Sopenharmony_ci else { 20362306a36Sopenharmony_ci offs = PCR_PHY_CTL2; 20462306a36Sopenharmony_ci phy_id -= 4; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, offs, &tmp); 20762306a36Sopenharmony_ci tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); 20862306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, offs, tmp); 20962306a36Sopenharmony_ci } else { 21062306a36Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 21162306a36Sopenharmony_ci tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); 21262306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 21962306a36Sopenharmony_ci u32 tmp; 22062306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 22162306a36Sopenharmony_ci u32 offs; 22262306a36Sopenharmony_ci if (phy_id < 4) 22362306a36Sopenharmony_ci offs = PCR_PHY_CTL; 22462306a36Sopenharmony_ci else { 22562306a36Sopenharmony_ci offs = PCR_PHY_CTL2; 22662306a36Sopenharmony_ci phy_id -= 4; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, offs, &tmp); 22962306a36Sopenharmony_ci tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); 23062306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, offs, tmp); 23162306a36Sopenharmony_ci } else { 23262306a36Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 23362306a36Sopenharmony_ci tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); 23462306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int mvs_64xx_init(struct mvs_info *mvi) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 24162306a36Sopenharmony_ci int i; 24262306a36Sopenharmony_ci u32 tmp, cctl; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (mvi->pdev && mvi->pdev->revision == 0) 24562306a36Sopenharmony_ci mvi->flags |= MVF_PHY_PWR_FIX; 24662306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 24762306a36Sopenharmony_ci mvs_show_pcie_usage(mvi); 24862306a36Sopenharmony_ci tmp = mvs_64xx_chip_reset(mvi); 24962306a36Sopenharmony_ci if (tmp) 25062306a36Sopenharmony_ci return tmp; 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 25362306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 25462306a36Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 25562306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Init Chip */ 25962306a36Sopenharmony_ci /* make sure RST is set; HBA_RST /should/ have done that for us */ 26062306a36Sopenharmony_ci cctl = mr32(MVS_CTL) & 0xFFFF; 26162306a36Sopenharmony_ci if (cctl & CCTL_RST) 26262306a36Sopenharmony_ci cctl &= ~CCTL_RST; 26362306a36Sopenharmony_ci else 26462306a36Sopenharmony_ci mw32_f(MVS_CTL, cctl | CCTL_RST); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 26762306a36Sopenharmony_ci /* write to device control _AND_ device status register */ 26862306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); 26962306a36Sopenharmony_ci tmp &= ~PRD_REQ_MASK; 27062306a36Sopenharmony_ci tmp |= PRD_REQ_SIZE; 27162306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 27462306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 27562306a36Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 27662306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 27962306a36Sopenharmony_ci tmp &= PCTL_PWR_OFF; 28062306a36Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 28162306a36Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 28462306a36Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 28562306a36Sopenharmony_ci tmp |= PCTL_COM_ON; 28662306a36Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 28762306a36Sopenharmony_ci tmp |= PCTL_LINK_RST; 28862306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 28962306a36Sopenharmony_ci msleep(100); 29062306a36Sopenharmony_ci tmp &= ~PCTL_LINK_RST; 29162306a36Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 29262306a36Sopenharmony_ci msleep(100); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* reset control */ 29662306a36Sopenharmony_ci mw32(MVS_PCS, 0); /* MVS_PCS */ 29762306a36Sopenharmony_ci /* init phys */ 29862306a36Sopenharmony_ci mvs_64xx_phy_hacks(mvi); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_PHY_MODE_21); 30162306a36Sopenharmony_ci tmp &= 0x0000ffff; 30262306a36Sopenharmony_ci tmp |= 0x00fa0000; 30362306a36Sopenharmony_ci mvs_cw32(mvi, CMD_PHY_MODE_21, tmp); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* enable auto port detection */ 30662306a36Sopenharmony_ci mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci mw32(MVS_CMD_LIST_LO, mvi->slot_dma); 30962306a36Sopenharmony_ci mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); 31262306a36Sopenharmony_ci mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); 31562306a36Sopenharmony_ci mw32(MVS_TX_LO, mvi->tx_dma); 31662306a36Sopenharmony_ci mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ); 31962306a36Sopenharmony_ci mw32(MVS_RX_LO, mvi->rx_dma); 32062306a36Sopenharmony_ci mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 32362306a36Sopenharmony_ci /* set phy local SAS address */ 32462306a36Sopenharmony_ci /* should set little endian SAS address to 64xx chip */ 32562306a36Sopenharmony_ci mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI, 32662306a36Sopenharmony_ci cpu_to_be64(mvi->phy[i].dev_sas_addr)); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci mvs_64xx_enable_xmt(mvi, i); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci mvs_64xx_phy_reset(mvi, i, MVS_HARD_RESET); 33162306a36Sopenharmony_ci msleep(500); 33262306a36Sopenharmony_ci mvs_64xx_detect_porttype(mvi, i); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 33562306a36Sopenharmony_ci /* set select registers */ 33662306a36Sopenharmony_ci writel(0x0E008000, regs + 0x000); 33762306a36Sopenharmony_ci writel(0x59000008, regs + 0x004); 33862306a36Sopenharmony_ci writel(0x20, regs + 0x008); 33962306a36Sopenharmony_ci writel(0x20, regs + 0x00c); 34062306a36Sopenharmony_ci writel(0x20, regs + 0x010); 34162306a36Sopenharmony_ci writel(0x20, regs + 0x014); 34262306a36Sopenharmony_ci writel(0x20, regs + 0x018); 34362306a36Sopenharmony_ci writel(0x20, regs + 0x01c); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 34662306a36Sopenharmony_ci /* clear phy int status */ 34762306a36Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, i); 34862306a36Sopenharmony_ci tmp &= ~PHYEV_SIG_FIS; 34962306a36Sopenharmony_ci mvs_write_port_irq_stat(mvi, i, tmp); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* set phy int mask */ 35262306a36Sopenharmony_ci tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | 35362306a36Sopenharmony_ci PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR | 35462306a36Sopenharmony_ci PHYEV_DEC_ERR; 35562306a36Sopenharmony_ci mvs_write_port_irq_mask(mvi, i, tmp); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci msleep(100); 35862306a36Sopenharmony_ci mvs_update_phyinfo(mvi, i, 1); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* little endian for open address and command table, etc. */ 36262306a36Sopenharmony_ci cctl = mr32(MVS_CTL); 36362306a36Sopenharmony_ci cctl |= CCTL_ENDIAN_CMD; 36462306a36Sopenharmony_ci cctl |= CCTL_ENDIAN_DATA; 36562306a36Sopenharmony_ci cctl &= ~CCTL_ENDIAN_OPEN; 36662306a36Sopenharmony_ci cctl |= CCTL_ENDIAN_RSP; 36762306a36Sopenharmony_ci mw32_f(MVS_CTL, cctl); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* reset CMD queue */ 37062306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 37162306a36Sopenharmony_ci tmp |= PCS_CMD_RST; 37262306a36Sopenharmony_ci tmp &= ~PCS_SELF_CLEAR; 37362306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 37662306a36Sopenharmony_ci * it will make count 0. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci tmp = 0; 37962306a36Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 38062306a36Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff | COAL_EN); 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci tmp = 0x10000 | interrupt_coalescing; 38562306a36Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* ladies and gentlemen, start your engines */ 38862306a36Sopenharmony_ci mw32(MVS_TX_CFG, 0); 38962306a36Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 39062306a36Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); 39162306a36Sopenharmony_ci /* enable CMD/CMPL_Q/RESP mode */ 39262306a36Sopenharmony_ci mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | 39362306a36Sopenharmony_ci PCS_CMD_EN | PCS_CMD_STOP_ERR); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* enable completion queue interrupt */ 39662306a36Sopenharmony_ci tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | 39762306a36Sopenharmony_ci CINT_DMA_PCIE); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci mw32(MVS_INT_MASK, tmp); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Enable SRS interrupt */ 40262306a36Sopenharmony_ci mw32(MVS_INT_MASK_SRS_0, 0xFFFF); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int mvs_64xx_ioremap(struct mvs_info *mvi) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci if (!mvs_ioremap(mvi, 4, 2)) 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci return -1; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void mvs_64xx_iounmap(struct mvs_info *mvi) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci mvs_iounmap(mvi->regs); 41762306a36Sopenharmony_ci mvs_iounmap(mvi->regs_ex); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic void mvs_64xx_interrupt_enable(struct mvs_info *mvi) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 42362306a36Sopenharmony_ci u32 tmp; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 42662306a36Sopenharmony_ci mw32(MVS_GBL_CTL, tmp | INT_EN); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic void mvs_64xx_interrupt_disable(struct mvs_info *mvi) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 43262306a36Sopenharmony_ci u32 tmp; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 43562306a36Sopenharmony_ci mw32(MVS_GBL_CTL, tmp & ~INT_EN); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 44162306a36Sopenharmony_ci u32 stat; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 44462306a36Sopenharmony_ci stat = mr32(MVS_GBL_INT_STAT); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (stat == 0 || stat == 0xffffffff) 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci } else 44962306a36Sopenharmony_ci stat = 1; 45062306a36Sopenharmony_ci return stat; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* clear CMD_CMPLT ASAP */ 45862306a36Sopenharmony_ci mw32_f(MVS_INT_STAT, CINT_DONE); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci spin_lock(&mvi->lock); 46162306a36Sopenharmony_ci mvs_int_full(mvi); 46262306a36Sopenharmony_ci spin_unlock(&mvi->lock); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return IRQ_HANDLED; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci u32 tmp; 47062306a36Sopenharmony_ci mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32)); 47162306a36Sopenharmony_ci mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32)); 47262306a36Sopenharmony_ci do { 47362306a36Sopenharmony_ci tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3)); 47462306a36Sopenharmony_ci } while (tmp & 1 << (slot_idx % 32)); 47562306a36Sopenharmony_ci do { 47662306a36Sopenharmony_ci tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3)); 47762306a36Sopenharmony_ci } while (tmp & 1 << (slot_idx % 32)); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, 48162306a36Sopenharmony_ci u32 tfs) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 48462306a36Sopenharmony_ci u32 tmp; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (type == PORT_TYPE_SATA) { 48762306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); 48862306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci mw32(MVS_INT_STAT, CINT_CI_STOP); 49162306a36Sopenharmony_ci tmp = mr32(MVS_PCS) | 0xFF00; 49262306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 49862306a36Sopenharmony_ci u32 tmp, offs; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (*tfs == MVS_ID_NOT_MAPPED) 50162306a36Sopenharmony_ci return; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); 50462306a36Sopenharmony_ci if (*tfs < 16) { 50562306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 50662306a36Sopenharmony_ci mw32(MVS_PCS, tmp & ~offs); 50762306a36Sopenharmony_ci } else { 50862306a36Sopenharmony_ci tmp = mr32(MVS_CTL); 50962306a36Sopenharmony_ci mw32(MVS_CTL, tmp & ~offs); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs); 51362306a36Sopenharmony_ci if (tmp) 51462306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci *tfs = MVS_ID_NOT_MAPPED; 51762306a36Sopenharmony_ci return; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci int i; 52362306a36Sopenharmony_ci u32 tmp, offs; 52462306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (*tfs != MVS_ID_NOT_MAPPED) 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci for (i = 0; i < mvi->chip->srs_sz; i++) { 53262306a36Sopenharmony_ci if (i == 16) 53362306a36Sopenharmony_ci tmp = mr32(MVS_CTL); 53462306a36Sopenharmony_ci offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); 53562306a36Sopenharmony_ci if (!(tmp & offs)) { 53662306a36Sopenharmony_ci *tfs = i; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (i < 16) 53962306a36Sopenharmony_ci mw32(MVS_PCS, tmp | offs); 54062306a36Sopenharmony_ci else 54162306a36Sopenharmony_ci mw32(MVS_CTL, tmp | offs); 54262306a36Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i); 54362306a36Sopenharmony_ci if (tmp) 54462306a36Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci return MVS_ID_NOT_MAPPED; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci int i; 55462306a36Sopenharmony_ci struct scatterlist *sg; 55562306a36Sopenharmony_ci struct mvs_prd *buf_prd = prd; 55662306a36Sopenharmony_ci for_each_sg(scatter, sg, nr, i) { 55762306a36Sopenharmony_ci buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 55862306a36Sopenharmony_ci buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 55962306a36Sopenharmony_ci buf_prd++; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int mvs_64xx_oob_done(struct mvs_info *mvi, int i) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci u32 phy_st; 56662306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, 56762306a36Sopenharmony_ci PHYR_PHY_STAT); 56862306a36Sopenharmony_ci phy_st = mvs_read_port_cfg_data(mvi, i); 56962306a36Sopenharmony_ci if (phy_st & PHY_OOB_DTCTD) 57062306a36Sopenharmony_ci return 1; 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i, 57562306a36Sopenharmony_ci struct sas_identify_frame *id) 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 57962306a36Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci sas_phy->linkrate = 58262306a36Sopenharmony_ci (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 58362306a36Sopenharmony_ci PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci phy->minimum_linkrate = 58662306a36Sopenharmony_ci (phy->phy_status & 58762306a36Sopenharmony_ci PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; 58862306a36Sopenharmony_ci phy->maximum_linkrate = 58962306a36Sopenharmony_ci (phy->phy_status & 59062306a36Sopenharmony_ci PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); 59362306a36Sopenharmony_ci phy->dev_info = mvs_read_port_cfg_data(mvi, i); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); 59662306a36Sopenharmony_ci phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); 59962306a36Sopenharmony_ci phy->att_dev_sas_addr = 60062306a36Sopenharmony_ci (u64) mvs_read_port_cfg_data(mvi, i) << 32; 60162306a36Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); 60262306a36Sopenharmony_ci phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); 60362306a36Sopenharmony_ci phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci u32 tmp; 60962306a36Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 61062306a36Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); 61162306a36Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, i); 61262306a36Sopenharmony_ci if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 61362306a36Sopenharmony_ci PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == 61462306a36Sopenharmony_ci SAS_LINK_RATE_1_5_GBPS) 61562306a36Sopenharmony_ci tmp &= ~PHY_MODE6_LATECLK; 61662306a36Sopenharmony_ci else 61762306a36Sopenharmony_ci tmp |= PHY_MODE6_LATECLK; 61862306a36Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, tmp); 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, 62262306a36Sopenharmony_ci struct sas_phy_linkrates *rates) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci u32 lrmin = 0, lrmax = 0; 62562306a36Sopenharmony_ci u32 tmp; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 62862306a36Sopenharmony_ci lrmin = (rates->minimum_linkrate << 8); 62962306a36Sopenharmony_ci lrmax = (rates->maximum_linkrate << 12); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (lrmin) { 63262306a36Sopenharmony_ci tmp &= ~(0xf << 8); 63362306a36Sopenharmony_ci tmp |= lrmin; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci if (lrmax) { 63662306a36Sopenharmony_ci tmp &= ~(0xf << 12); 63762306a36Sopenharmony_ci tmp |= lrmax; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 64062306a36Sopenharmony_ci mvs_64xx_phy_reset(mvi, phy_id, MVS_HARD_RESET); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic void mvs_64xx_clear_active_cmds(struct mvs_info *mvi) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci u32 tmp; 64662306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 64762306a36Sopenharmony_ci tmp = mr32(MVS_PCS); 64862306a36Sopenharmony_ci mw32(MVS_PCS, tmp & 0xFFFF); 64962306a36Sopenharmony_ci mw32(MVS_PCS, tmp); 65062306a36Sopenharmony_ci tmp = mr32(MVS_CTL); 65162306a36Sopenharmony_ci mw32(MVS_CTL, tmp & 0xFFFF); 65262306a36Sopenharmony_ci mw32(MVS_CTL, tmp); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic u32 mvs_64xx_spi_read_data(struct mvs_info *mvi) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 65962306a36Sopenharmony_ci return ior32(SPI_DATA_REG_64XX); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci iow32(SPI_DATA_REG_64XX, data); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic int mvs_64xx_spi_buildcmd(struct mvs_info *mvi, 67162306a36Sopenharmony_ci u32 *dwCmd, 67262306a36Sopenharmony_ci u8 cmd, 67362306a36Sopenharmony_ci u8 read, 67462306a36Sopenharmony_ci u8 length, 67562306a36Sopenharmony_ci u32 addr 67662306a36Sopenharmony_ci ) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci u32 dwTmp; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci dwTmp = ((u32)cmd << 24) | ((u32)length << 19); 68162306a36Sopenharmony_ci if (read) 68262306a36Sopenharmony_ci dwTmp |= 1U<<23; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (addr != MV_MAX_U32) { 68562306a36Sopenharmony_ci dwTmp |= 1U<<22; 68662306a36Sopenharmony_ci dwTmp |= (addr & 0x0003FFFF); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci *dwCmd = dwTmp; 69062306a36Sopenharmony_ci return 0; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 69762306a36Sopenharmony_ci int retry; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci for (retry = 0; retry < 1; retry++) { 70062306a36Sopenharmony_ci iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE); 70162306a36Sopenharmony_ci iow32(SPI_CMD_REG_64XX, cmd); 70262306a36Sopenharmony_ci iow32(SPI_CTRL_REG_64XX, 70362306a36Sopenharmony_ci SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 71262306a36Sopenharmony_ci u32 i, dwTmp; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 71562306a36Sopenharmony_ci dwTmp = ior32(SPI_CTRL_REG_64XX); 71662306a36Sopenharmony_ci if (!(dwTmp & SPI_CTRL_SPISTART)) 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci msleep(10); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return -1; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask, 72562306a36Sopenharmony_ci int buf_len, int from, void *prd) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci int i; 72862306a36Sopenharmony_ci struct mvs_prd *buf_prd = prd; 72962306a36Sopenharmony_ci dma_addr_t buf_dma = mvi->bulk_buffer_dma; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci buf_prd += from; 73262306a36Sopenharmony_ci for (i = 0; i < MAX_SG_ENTRY - from; i++) { 73362306a36Sopenharmony_ci buf_prd->addr = cpu_to_le64(buf_dma); 73462306a36Sopenharmony_ci buf_prd->len = cpu_to_le32(buf_len); 73562306a36Sopenharmony_ci ++buf_prd; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic void mvs_64xx_tune_interrupt(struct mvs_info *mvi, u32 time) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci void __iomem *regs = mvi->regs; 74262306a36Sopenharmony_ci u32 tmp = 0; 74362306a36Sopenharmony_ci /* 74462306a36Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 74562306a36Sopenharmony_ci * it will make count 0. 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_ci if (time == 0) { 74862306a36Sopenharmony_ci mw32(MVS_INT_COAL, 0); 74962306a36Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, 0x10000); 75062306a36Sopenharmony_ci } else { 75162306a36Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 75262306a36Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff|COAL_EN); 75362306a36Sopenharmony_ci else 75462306a36Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci tmp = 0x10000 | time; 75762306a36Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ciconst struct mvs_dispatch mvs_64xx_dispatch = { 76262306a36Sopenharmony_ci "mv64xx", 76362306a36Sopenharmony_ci mvs_64xx_init, 76462306a36Sopenharmony_ci NULL, 76562306a36Sopenharmony_ci mvs_64xx_ioremap, 76662306a36Sopenharmony_ci mvs_64xx_iounmap, 76762306a36Sopenharmony_ci mvs_64xx_isr, 76862306a36Sopenharmony_ci mvs_64xx_isr_status, 76962306a36Sopenharmony_ci mvs_64xx_interrupt_enable, 77062306a36Sopenharmony_ci mvs_64xx_interrupt_disable, 77162306a36Sopenharmony_ci mvs_read_phy_ctl, 77262306a36Sopenharmony_ci mvs_write_phy_ctl, 77362306a36Sopenharmony_ci mvs_read_port_cfg_data, 77462306a36Sopenharmony_ci mvs_write_port_cfg_data, 77562306a36Sopenharmony_ci mvs_write_port_cfg_addr, 77662306a36Sopenharmony_ci mvs_read_port_vsr_data, 77762306a36Sopenharmony_ci mvs_write_port_vsr_data, 77862306a36Sopenharmony_ci mvs_write_port_vsr_addr, 77962306a36Sopenharmony_ci mvs_read_port_irq_stat, 78062306a36Sopenharmony_ci mvs_write_port_irq_stat, 78162306a36Sopenharmony_ci mvs_read_port_irq_mask, 78262306a36Sopenharmony_ci mvs_write_port_irq_mask, 78362306a36Sopenharmony_ci mvs_64xx_command_active, 78462306a36Sopenharmony_ci mvs_64xx_clear_srs_irq, 78562306a36Sopenharmony_ci mvs_64xx_issue_stop, 78662306a36Sopenharmony_ci mvs_start_delivery, 78762306a36Sopenharmony_ci mvs_rx_update, 78862306a36Sopenharmony_ci mvs_int_full, 78962306a36Sopenharmony_ci mvs_64xx_assign_reg_set, 79062306a36Sopenharmony_ci mvs_64xx_free_reg_set, 79162306a36Sopenharmony_ci mvs_get_prd_size, 79262306a36Sopenharmony_ci mvs_get_prd_count, 79362306a36Sopenharmony_ci mvs_64xx_make_prd, 79462306a36Sopenharmony_ci mvs_64xx_detect_porttype, 79562306a36Sopenharmony_ci mvs_64xx_oob_done, 79662306a36Sopenharmony_ci mvs_64xx_fix_phy_info, 79762306a36Sopenharmony_ci mvs_64xx_phy_work_around, 79862306a36Sopenharmony_ci mvs_64xx_phy_set_link_rate, 79962306a36Sopenharmony_ci mvs_hw_max_link_rate, 80062306a36Sopenharmony_ci mvs_64xx_phy_disable, 80162306a36Sopenharmony_ci mvs_64xx_phy_enable, 80262306a36Sopenharmony_ci mvs_64xx_phy_reset, 80362306a36Sopenharmony_ci mvs_64xx_stp_reset, 80462306a36Sopenharmony_ci mvs_64xx_clear_active_cmds, 80562306a36Sopenharmony_ci mvs_64xx_spi_read_data, 80662306a36Sopenharmony_ci mvs_64xx_spi_write_data, 80762306a36Sopenharmony_ci mvs_64xx_spi_buildcmd, 80862306a36Sopenharmony_ci mvs_64xx_spi_issuecmd, 80962306a36Sopenharmony_ci mvs_64xx_spi_waitdataready, 81062306a36Sopenharmony_ci mvs_64xx_fix_dma, 81162306a36Sopenharmony_ci mvs_64xx_tune_interrupt, 81262306a36Sopenharmony_ci NULL, 81362306a36Sopenharmony_ci}; 81462306a36Sopenharmony_ci 815