18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell 88SE64xx hardware specific 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2007 Red Hat, Inc. 68c2ecf20Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com> 78c2ecf20Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 88c2ecf20Sopenharmony_ci*/ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "mv_sas.h" 118c2ecf20Sopenharmony_ci#include "mv_64xx.h" 128c2ecf20Sopenharmony_ci#include "mv_chips.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 178c2ecf20Sopenharmony_ci u32 reg; 188c2ecf20Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci reg = mr32(MVS_GBL_PORT_TYPE); 218c2ecf20Sopenharmony_ci phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 228c2ecf20Sopenharmony_ci if (reg & MODE_SAS_SATA & (1 << i)) 238c2ecf20Sopenharmony_ci phy->phy_type |= PORT_TYPE_SAS; 248c2ecf20Sopenharmony_ci else 258c2ecf20Sopenharmony_ci phy->phy_type |= PORT_TYPE_SATA; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 318c2ecf20Sopenharmony_ci u32 tmp; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 348c2ecf20Sopenharmony_ci if (mvi->chip->n_phy <= MVS_SOC_PORTS) 358c2ecf20Sopenharmony_ci tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT); 368c2ecf20Sopenharmony_ci else 378c2ecf20Sopenharmony_ci tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); 388c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void mvs_64xx_phy_hacks(struct mvs_info *mvi) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 448c2ecf20Sopenharmony_ci int i; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci mvs_phy_hacks(mvi); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 498c2ecf20Sopenharmony_ci for (i = 0; i < MVS_SOC_PORTS; i++) { 508c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE8); 518c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x2F0); 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } else { 548c2ecf20Sopenharmony_ci /* disable auto port detection */ 558c2ecf20Sopenharmony_ci mw32(MVS_GBL_PORT_TYPE, 0); 568c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 578c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7); 588c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x90000000); 598c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9); 608c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x50f2); 618c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11); 628c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, 0x0e); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 708c2ecf20Sopenharmony_ci u32 reg, tmp; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 738c2ecf20Sopenharmony_ci if (phy_id < MVS_SOC_PORTS) 748c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, ®); 758c2ecf20Sopenharmony_ci else 768c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, ®); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci } else 798c2ecf20Sopenharmony_ci reg = mr32(MVS_PHY_CTL); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci tmp = reg; 828c2ecf20Sopenharmony_ci if (phy_id < MVS_SOC_PORTS) 838c2ecf20Sopenharmony_ci tmp |= (1U << phy_id) << PCTL_LINK_OFFS; 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci tmp |= (1U << (phy_id - MVS_SOC_PORTS)) << PCTL_LINK_OFFS; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 888c2ecf20Sopenharmony_ci if (phy_id < MVS_SOC_PORTS) { 898c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 908c2ecf20Sopenharmony_ci mdelay(10); 918c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg); 928c2ecf20Sopenharmony_ci } else { 938c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 948c2ecf20Sopenharmony_ci mdelay(10); 958c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 998c2ecf20Sopenharmony_ci mdelay(10); 1008c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, reg); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u32 tmp; 1078c2ecf20Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, phy_id); 1088c2ecf20Sopenharmony_ci tmp &= ~PHYEV_RDY_CH; 1098c2ecf20Sopenharmony_ci mvs_write_port_irq_stat(mvi, phy_id, tmp); 1108c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 1118c2ecf20Sopenharmony_ci if (hard == MVS_HARD_RESET) 1128c2ecf20Sopenharmony_ci tmp |= PHY_RST_HARD; 1138c2ecf20Sopenharmony_ci else if (hard == MVS_SOFT_RESET) 1148c2ecf20Sopenharmony_ci tmp |= PHY_RST; 1158c2ecf20Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 1168c2ecf20Sopenharmony_ci if (hard) { 1178c2ecf20Sopenharmony_ci do { 1188c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 1198c2ecf20Sopenharmony_ci } while (tmp & PHY_RST_HARD); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void 1248c2ecf20Sopenharmony_cimvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 1278c2ecf20Sopenharmony_ci u32 tmp; 1288c2ecf20Sopenharmony_ci if (clear_all) { 1298c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 1308c2ecf20Sopenharmony_ci if (tmp) { 1318c2ecf20Sopenharmony_ci printk(KERN_DEBUG "check SRS 0 %08X.\n", tmp); 1328c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } else { 1358c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0); 1368c2ecf20Sopenharmony_ci if (tmp & (1 << (reg_set % 32))) { 1378c2ecf20Sopenharmony_ci printk(KERN_DEBUG "register set 0x%x was stopped.\n", 1388c2ecf20Sopenharmony_ci reg_set); 1398c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int mvs_64xx_chip_reset(struct mvs_info *mvi) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 1478c2ecf20Sopenharmony_ci u32 tmp; 1488c2ecf20Sopenharmony_ci int i; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* make sure interrupts are masked immediately (paranoia) */ 1518c2ecf20Sopenharmony_ci mw32(MVS_GBL_CTL, 0); 1528c2ecf20Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Reset Controller */ 1558c2ecf20Sopenharmony_ci if (!(tmp & HBA_RST)) { 1568c2ecf20Sopenharmony_ci if (mvi->flags & MVF_PHY_PWR_FIX) { 1578c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 1588c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 1598c2ecf20Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 1608c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 1638c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 1648c2ecf20Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 1658c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* make sure interrupts are masked immediately (paranoia) */ 1708c2ecf20Sopenharmony_ci mw32(MVS_GBL_CTL, 0); 1718c2ecf20Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Reset Controller */ 1748c2ecf20Sopenharmony_ci if (!(tmp & HBA_RST)) { 1758c2ecf20Sopenharmony_ci /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ 1768c2ecf20Sopenharmony_ci mw32_f(MVS_GBL_CTL, HBA_RST); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* wait for reset to finish; timeout is just a guess */ 1808c2ecf20Sopenharmony_ci i = 1000; 1818c2ecf20Sopenharmony_ci while (i-- > 0) { 1828c2ecf20Sopenharmony_ci msleep(10); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (!(mr32(MVS_GBL_CTL) & HBA_RST)) 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci if (mr32(MVS_GBL_CTL) & HBA_RST) { 1888c2ecf20Sopenharmony_ci dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n"); 1898c2ecf20Sopenharmony_ci return -EBUSY; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 1978c2ecf20Sopenharmony_ci u32 tmp; 1988c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 1998c2ecf20Sopenharmony_ci u32 offs; 2008c2ecf20Sopenharmony_ci if (phy_id < 4) 2018c2ecf20Sopenharmony_ci offs = PCR_PHY_CTL; 2028c2ecf20Sopenharmony_ci else { 2038c2ecf20Sopenharmony_ci offs = PCR_PHY_CTL2; 2048c2ecf20Sopenharmony_ci phy_id -= 4; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, offs, &tmp); 2078c2ecf20Sopenharmony_ci tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); 2088c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, offs, tmp); 2098c2ecf20Sopenharmony_ci } else { 2108c2ecf20Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 2118c2ecf20Sopenharmony_ci tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); 2128c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 2198c2ecf20Sopenharmony_ci u32 tmp; 2208c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 2218c2ecf20Sopenharmony_ci u32 offs; 2228c2ecf20Sopenharmony_ci if (phy_id < 4) 2238c2ecf20Sopenharmony_ci offs = PCR_PHY_CTL; 2248c2ecf20Sopenharmony_ci else { 2258c2ecf20Sopenharmony_ci offs = PCR_PHY_CTL2; 2268c2ecf20Sopenharmony_ci phy_id -= 4; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, offs, &tmp); 2298c2ecf20Sopenharmony_ci tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); 2308c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, offs, tmp); 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 2338c2ecf20Sopenharmony_ci tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); 2348c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int mvs_64xx_init(struct mvs_info *mvi) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 2418c2ecf20Sopenharmony_ci int i; 2428c2ecf20Sopenharmony_ci u32 tmp, cctl; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (mvi->pdev && mvi->pdev->revision == 0) 2458c2ecf20Sopenharmony_ci mvi->flags |= MVF_PHY_PWR_FIX; 2468c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 2478c2ecf20Sopenharmony_ci mvs_show_pcie_usage(mvi); 2488c2ecf20Sopenharmony_ci tmp = mvs_64xx_chip_reset(mvi); 2498c2ecf20Sopenharmony_ci if (tmp) 2508c2ecf20Sopenharmony_ci return tmp; 2518c2ecf20Sopenharmony_ci } else { 2528c2ecf20Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 2538c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 2548c2ecf20Sopenharmony_ci tmp |= PCTL_PHY_DSBL; 2558c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Init Chip */ 2598c2ecf20Sopenharmony_ci /* make sure RST is set; HBA_RST /should/ have done that for us */ 2608c2ecf20Sopenharmony_ci cctl = mr32(MVS_CTL) & 0xFFFF; 2618c2ecf20Sopenharmony_ci if (cctl & CCTL_RST) 2628c2ecf20Sopenharmony_ci cctl &= ~CCTL_RST; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci mw32_f(MVS_CTL, cctl | CCTL_RST); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 2678c2ecf20Sopenharmony_ci /* write to device control _AND_ device status register */ 2688c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); 2698c2ecf20Sopenharmony_ci tmp &= ~PRD_REQ_MASK; 2708c2ecf20Sopenharmony_ci tmp |= PRD_REQ_SIZE; 2718c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); 2748c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 2758c2ecf20Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 2768c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); 2798c2ecf20Sopenharmony_ci tmp &= PCTL_PWR_OFF; 2808c2ecf20Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 2818c2ecf20Sopenharmony_ci pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); 2828c2ecf20Sopenharmony_ci } else { 2838c2ecf20Sopenharmony_ci tmp = mr32(MVS_PHY_CTL); 2848c2ecf20Sopenharmony_ci tmp &= ~PCTL_PWR_OFF; 2858c2ecf20Sopenharmony_ci tmp |= PCTL_COM_ON; 2868c2ecf20Sopenharmony_ci tmp &= ~PCTL_PHY_DSBL; 2878c2ecf20Sopenharmony_ci tmp |= PCTL_LINK_RST; 2888c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 2898c2ecf20Sopenharmony_ci msleep(100); 2908c2ecf20Sopenharmony_ci tmp &= ~PCTL_LINK_RST; 2918c2ecf20Sopenharmony_ci mw32(MVS_PHY_CTL, tmp); 2928c2ecf20Sopenharmony_ci msleep(100); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* reset control */ 2968c2ecf20Sopenharmony_ci mw32(MVS_PCS, 0); /* MVS_PCS */ 2978c2ecf20Sopenharmony_ci /* init phys */ 2988c2ecf20Sopenharmony_ci mvs_64xx_phy_hacks(mvi); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, CMD_PHY_MODE_21); 3018c2ecf20Sopenharmony_ci tmp &= 0x0000ffff; 3028c2ecf20Sopenharmony_ci tmp |= 0x00fa0000; 3038c2ecf20Sopenharmony_ci mvs_cw32(mvi, CMD_PHY_MODE_21, tmp); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* enable auto port detection */ 3068c2ecf20Sopenharmony_ci mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci mw32(MVS_CMD_LIST_LO, mvi->slot_dma); 3098c2ecf20Sopenharmony_ci mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); 3128c2ecf20Sopenharmony_ci mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); 3158c2ecf20Sopenharmony_ci mw32(MVS_TX_LO, mvi->tx_dma); 3168c2ecf20Sopenharmony_ci mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ); 3198c2ecf20Sopenharmony_ci mw32(MVS_RX_LO, mvi->rx_dma); 3208c2ecf20Sopenharmony_ci mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 3238c2ecf20Sopenharmony_ci /* set phy local SAS address */ 3248c2ecf20Sopenharmony_ci /* should set little endian SAS address to 64xx chip */ 3258c2ecf20Sopenharmony_ci mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI, 3268c2ecf20Sopenharmony_ci cpu_to_be64(mvi->phy[i].dev_sas_addr)); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci mvs_64xx_enable_xmt(mvi, i); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci mvs_64xx_phy_reset(mvi, i, MVS_HARD_RESET); 3318c2ecf20Sopenharmony_ci msleep(500); 3328c2ecf20Sopenharmony_ci mvs_64xx_detect_porttype(mvi, i); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci if (mvi->flags & MVF_FLAG_SOC) { 3358c2ecf20Sopenharmony_ci /* set select registers */ 3368c2ecf20Sopenharmony_ci writel(0x0E008000, regs + 0x000); 3378c2ecf20Sopenharmony_ci writel(0x59000008, regs + 0x004); 3388c2ecf20Sopenharmony_ci writel(0x20, regs + 0x008); 3398c2ecf20Sopenharmony_ci writel(0x20, regs + 0x00c); 3408c2ecf20Sopenharmony_ci writel(0x20, regs + 0x010); 3418c2ecf20Sopenharmony_ci writel(0x20, regs + 0x014); 3428c2ecf20Sopenharmony_ci writel(0x20, regs + 0x018); 3438c2ecf20Sopenharmony_ci writel(0x20, regs + 0x01c); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->n_phy; i++) { 3468c2ecf20Sopenharmony_ci /* clear phy int status */ 3478c2ecf20Sopenharmony_ci tmp = mvs_read_port_irq_stat(mvi, i); 3488c2ecf20Sopenharmony_ci tmp &= ~PHYEV_SIG_FIS; 3498c2ecf20Sopenharmony_ci mvs_write_port_irq_stat(mvi, i, tmp); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* set phy int mask */ 3528c2ecf20Sopenharmony_ci tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | 3538c2ecf20Sopenharmony_ci PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR | 3548c2ecf20Sopenharmony_ci PHYEV_DEC_ERR; 3558c2ecf20Sopenharmony_ci mvs_write_port_irq_mask(mvi, i, tmp); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci msleep(100); 3588c2ecf20Sopenharmony_ci mvs_update_phyinfo(mvi, i, 1); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* little endian for open address and command table, etc. */ 3628c2ecf20Sopenharmony_ci cctl = mr32(MVS_CTL); 3638c2ecf20Sopenharmony_ci cctl |= CCTL_ENDIAN_CMD; 3648c2ecf20Sopenharmony_ci cctl |= CCTL_ENDIAN_DATA; 3658c2ecf20Sopenharmony_ci cctl &= ~CCTL_ENDIAN_OPEN; 3668c2ecf20Sopenharmony_ci cctl |= CCTL_ENDIAN_RSP; 3678c2ecf20Sopenharmony_ci mw32_f(MVS_CTL, cctl); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* reset CMD queue */ 3708c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 3718c2ecf20Sopenharmony_ci tmp |= PCS_CMD_RST; 3728c2ecf20Sopenharmony_ci tmp &= ~PCS_SELF_CLEAR; 3738c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 3748c2ecf20Sopenharmony_ci /* 3758c2ecf20Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 3768c2ecf20Sopenharmony_ci * it will make count 0. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci tmp = 0; 3798c2ecf20Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 3808c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff | COAL_EN); 3818c2ecf20Sopenharmony_ci else 3828c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci tmp = 0x10000 | interrupt_coalescing; 3858c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* ladies and gentlemen, start your engines */ 3888c2ecf20Sopenharmony_ci mw32(MVS_TX_CFG, 0); 3898c2ecf20Sopenharmony_ci mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); 3908c2ecf20Sopenharmony_ci mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); 3918c2ecf20Sopenharmony_ci /* enable CMD/CMPL_Q/RESP mode */ 3928c2ecf20Sopenharmony_ci mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | 3938c2ecf20Sopenharmony_ci PCS_CMD_EN | PCS_CMD_STOP_ERR); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* enable completion queue interrupt */ 3968c2ecf20Sopenharmony_ci tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | 3978c2ecf20Sopenharmony_ci CINT_DMA_PCIE); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci mw32(MVS_INT_MASK, tmp); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Enable SRS interrupt */ 4028c2ecf20Sopenharmony_ci mw32(MVS_INT_MASK_SRS_0, 0xFFFF); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int mvs_64xx_ioremap(struct mvs_info *mvi) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci if (!mvs_ioremap(mvi, 4, 2)) 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci return -1; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void mvs_64xx_iounmap(struct mvs_info *mvi) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci mvs_iounmap(mvi->regs); 4178c2ecf20Sopenharmony_ci mvs_iounmap(mvi->regs_ex); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void mvs_64xx_interrupt_enable(struct mvs_info *mvi) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 4238c2ecf20Sopenharmony_ci u32 tmp; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 4268c2ecf20Sopenharmony_ci mw32(MVS_GBL_CTL, tmp | INT_EN); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic void mvs_64xx_interrupt_disable(struct mvs_info *mvi) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 4328c2ecf20Sopenharmony_ci u32 tmp; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci tmp = mr32(MVS_GBL_CTL); 4358c2ecf20Sopenharmony_ci mw32(MVS_GBL_CTL, tmp & ~INT_EN); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 4418c2ecf20Sopenharmony_ci u32 stat; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!(mvi->flags & MVF_FLAG_SOC)) { 4448c2ecf20Sopenharmony_ci stat = mr32(MVS_GBL_INT_STAT); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (stat == 0 || stat == 0xffffffff) 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci } else 4498c2ecf20Sopenharmony_ci stat = 1; 4508c2ecf20Sopenharmony_ci return stat; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* clear CMD_CMPLT ASAP */ 4588c2ecf20Sopenharmony_ci mw32_f(MVS_INT_STAT, CINT_DONE); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci spin_lock(&mvi->lock); 4618c2ecf20Sopenharmony_ci mvs_int_full(mvi); 4628c2ecf20Sopenharmony_ci spin_unlock(&mvi->lock); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci u32 tmp; 4708c2ecf20Sopenharmony_ci mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32)); 4718c2ecf20Sopenharmony_ci mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32)); 4728c2ecf20Sopenharmony_ci do { 4738c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3)); 4748c2ecf20Sopenharmony_ci } while (tmp & 1 << (slot_idx % 32)); 4758c2ecf20Sopenharmony_ci do { 4768c2ecf20Sopenharmony_ci tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3)); 4778c2ecf20Sopenharmony_ci } while (tmp & 1 << (slot_idx % 32)); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, 4818c2ecf20Sopenharmony_ci u32 tfs) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 4848c2ecf20Sopenharmony_ci u32 tmp; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (type == PORT_TYPE_SATA) { 4878c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); 4888c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT, CINT_CI_STOP); 4918c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS) | 0xFF00; 4928c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 4988c2ecf20Sopenharmony_ci u32 tmp, offs; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (*tfs == MVS_ID_NOT_MAPPED) 5018c2ecf20Sopenharmony_ci return; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); 5048c2ecf20Sopenharmony_ci if (*tfs < 16) { 5058c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 5068c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp & ~offs); 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci tmp = mr32(MVS_CTL); 5098c2ecf20Sopenharmony_ci mw32(MVS_CTL, tmp & ~offs); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs); 5138c2ecf20Sopenharmony_ci if (tmp) 5148c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci *tfs = MVS_ID_NOT_MAPPED; 5178c2ecf20Sopenharmony_ci return; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci int i; 5238c2ecf20Sopenharmony_ci u32 tmp, offs; 5248c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (*tfs != MVS_ID_NOT_MAPPED) 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci for (i = 0; i < mvi->chip->srs_sz; i++) { 5328c2ecf20Sopenharmony_ci if (i == 16) 5338c2ecf20Sopenharmony_ci tmp = mr32(MVS_CTL); 5348c2ecf20Sopenharmony_ci offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); 5358c2ecf20Sopenharmony_ci if (!(tmp & offs)) { 5368c2ecf20Sopenharmony_ci *tfs = i; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (i < 16) 5398c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp | offs); 5408c2ecf20Sopenharmony_ci else 5418c2ecf20Sopenharmony_ci mw32(MVS_CTL, tmp | offs); 5428c2ecf20Sopenharmony_ci tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i); 5438c2ecf20Sopenharmony_ci if (tmp) 5448c2ecf20Sopenharmony_ci mw32(MVS_INT_STAT_SRS_0, tmp); 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci return MVS_ID_NOT_MAPPED; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci int i; 5548c2ecf20Sopenharmony_ci struct scatterlist *sg; 5558c2ecf20Sopenharmony_ci struct mvs_prd *buf_prd = prd; 5568c2ecf20Sopenharmony_ci for_each_sg(scatter, sg, nr, i) { 5578c2ecf20Sopenharmony_ci buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); 5588c2ecf20Sopenharmony_ci buf_prd->len = cpu_to_le32(sg_dma_len(sg)); 5598c2ecf20Sopenharmony_ci buf_prd++; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int mvs_64xx_oob_done(struct mvs_info *mvi, int i) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci u32 phy_st; 5668c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, 5678c2ecf20Sopenharmony_ci PHYR_PHY_STAT); 5688c2ecf20Sopenharmony_ci phy_st = mvs_read_port_cfg_data(mvi, i); 5698c2ecf20Sopenharmony_ci if (phy_st & PHY_OOB_DTCTD) 5708c2ecf20Sopenharmony_ci return 1; 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i, 5758c2ecf20Sopenharmony_ci struct sas_identify_frame *id) 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 5798c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci sas_phy->linkrate = 5828c2ecf20Sopenharmony_ci (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 5838c2ecf20Sopenharmony_ci PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci phy->minimum_linkrate = 5868c2ecf20Sopenharmony_ci (phy->phy_status & 5878c2ecf20Sopenharmony_ci PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; 5888c2ecf20Sopenharmony_ci phy->maximum_linkrate = 5898c2ecf20Sopenharmony_ci (phy->phy_status & 5908c2ecf20Sopenharmony_ci PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); 5938c2ecf20Sopenharmony_ci phy->dev_info = mvs_read_port_cfg_data(mvi, i); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); 5968c2ecf20Sopenharmony_ci phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); 5998c2ecf20Sopenharmony_ci phy->att_dev_sas_addr = 6008c2ecf20Sopenharmony_ci (u64) mvs_read_port_cfg_data(mvi, i) << 32; 6018c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); 6028c2ecf20Sopenharmony_ci phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); 6038c2ecf20Sopenharmony_ci phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci u32 tmp; 6098c2ecf20Sopenharmony_ci struct mvs_phy *phy = &mvi->phy[i]; 6108c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); 6118c2ecf20Sopenharmony_ci tmp = mvs_read_port_vsr_data(mvi, i); 6128c2ecf20Sopenharmony_ci if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> 6138c2ecf20Sopenharmony_ci PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == 6148c2ecf20Sopenharmony_ci SAS_LINK_RATE_1_5_GBPS) 6158c2ecf20Sopenharmony_ci tmp &= ~PHY_MODE6_LATECLK; 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci tmp |= PHY_MODE6_LATECLK; 6188c2ecf20Sopenharmony_ci mvs_write_port_vsr_data(mvi, i, tmp); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, 6228c2ecf20Sopenharmony_ci struct sas_phy_linkrates *rates) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci u32 lrmin = 0, lrmax = 0; 6258c2ecf20Sopenharmony_ci u32 tmp; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci tmp = mvs_read_phy_ctl(mvi, phy_id); 6288c2ecf20Sopenharmony_ci lrmin = (rates->minimum_linkrate << 8); 6298c2ecf20Sopenharmony_ci lrmax = (rates->maximum_linkrate << 12); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (lrmin) { 6328c2ecf20Sopenharmony_ci tmp &= ~(0xf << 8); 6338c2ecf20Sopenharmony_ci tmp |= lrmin; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci if (lrmax) { 6368c2ecf20Sopenharmony_ci tmp &= ~(0xf << 12); 6378c2ecf20Sopenharmony_ci tmp |= lrmax; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci mvs_write_phy_ctl(mvi, phy_id, tmp); 6408c2ecf20Sopenharmony_ci mvs_64xx_phy_reset(mvi, phy_id, MVS_HARD_RESET); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void mvs_64xx_clear_active_cmds(struct mvs_info *mvi) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci u32 tmp; 6468c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 6478c2ecf20Sopenharmony_ci tmp = mr32(MVS_PCS); 6488c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp & 0xFFFF); 6498c2ecf20Sopenharmony_ci mw32(MVS_PCS, tmp); 6508c2ecf20Sopenharmony_ci tmp = mr32(MVS_CTL); 6518c2ecf20Sopenharmony_ci mw32(MVS_CTL, tmp & 0xFFFF); 6528c2ecf20Sopenharmony_ci mw32(MVS_CTL, tmp); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic u32 mvs_64xx_spi_read_data(struct mvs_info *mvi) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 6598c2ecf20Sopenharmony_ci return ior32(SPI_DATA_REG_64XX); 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci iow32(SPI_DATA_REG_64XX, data); 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic int mvs_64xx_spi_buildcmd(struct mvs_info *mvi, 6718c2ecf20Sopenharmony_ci u32 *dwCmd, 6728c2ecf20Sopenharmony_ci u8 cmd, 6738c2ecf20Sopenharmony_ci u8 read, 6748c2ecf20Sopenharmony_ci u8 length, 6758c2ecf20Sopenharmony_ci u32 addr 6768c2ecf20Sopenharmony_ci ) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci u32 dwTmp; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci dwTmp = ((u32)cmd << 24) | ((u32)length << 19); 6818c2ecf20Sopenharmony_ci if (read) 6828c2ecf20Sopenharmony_ci dwTmp |= 1U<<23; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (addr != MV_MAX_U32) { 6858c2ecf20Sopenharmony_ci dwTmp |= 1U<<22; 6868c2ecf20Sopenharmony_ci dwTmp |= (addr & 0x0003FFFF); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci *dwCmd = dwTmp; 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 6978c2ecf20Sopenharmony_ci int retry; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci for (retry = 0; retry < 1; retry++) { 7008c2ecf20Sopenharmony_ci iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE); 7018c2ecf20Sopenharmony_ci iow32(SPI_CMD_REG_64XX, cmd); 7028c2ecf20Sopenharmony_ci iow32(SPI_CTRL_REG_64XX, 7038c2ecf20Sopenharmony_ci SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs_ex; 7128c2ecf20Sopenharmony_ci u32 i, dwTmp; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci for (i = 0; i < timeout; i++) { 7158c2ecf20Sopenharmony_ci dwTmp = ior32(SPI_CTRL_REG_64XX); 7168c2ecf20Sopenharmony_ci if (!(dwTmp & SPI_CTRL_SPISTART)) 7178c2ecf20Sopenharmony_ci return 0; 7188c2ecf20Sopenharmony_ci msleep(10); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return -1; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask, 7258c2ecf20Sopenharmony_ci int buf_len, int from, void *prd) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci int i; 7288c2ecf20Sopenharmony_ci struct mvs_prd *buf_prd = prd; 7298c2ecf20Sopenharmony_ci dma_addr_t buf_dma = mvi->bulk_buffer_dma; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci buf_prd += from; 7328c2ecf20Sopenharmony_ci for (i = 0; i < MAX_SG_ENTRY - from; i++) { 7338c2ecf20Sopenharmony_ci buf_prd->addr = cpu_to_le64(buf_dma); 7348c2ecf20Sopenharmony_ci buf_prd->len = cpu_to_le32(buf_len); 7358c2ecf20Sopenharmony_ci ++buf_prd; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic void mvs_64xx_tune_interrupt(struct mvs_info *mvi, u32 time) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci void __iomem *regs = mvi->regs; 7428c2ecf20Sopenharmony_ci u32 tmp = 0; 7438c2ecf20Sopenharmony_ci /* 7448c2ecf20Sopenharmony_ci * the max count is 0x1ff, while our max slot is 0x200, 7458c2ecf20Sopenharmony_ci * it will make count 0. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci if (time == 0) { 7488c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, 0); 7498c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, 0x10000); 7508c2ecf20Sopenharmony_ci } else { 7518c2ecf20Sopenharmony_ci if (MVS_CHIP_SLOT_SZ > 0x1ff) 7528c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, 0x1ff|COAL_EN); 7538c2ecf20Sopenharmony_ci else 7548c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci tmp = 0x10000 | time; 7578c2ecf20Sopenharmony_ci mw32(MVS_INT_COAL_TMOUT, tmp); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ciconst struct mvs_dispatch mvs_64xx_dispatch = { 7628c2ecf20Sopenharmony_ci "mv64xx", 7638c2ecf20Sopenharmony_ci mvs_64xx_init, 7648c2ecf20Sopenharmony_ci NULL, 7658c2ecf20Sopenharmony_ci mvs_64xx_ioremap, 7668c2ecf20Sopenharmony_ci mvs_64xx_iounmap, 7678c2ecf20Sopenharmony_ci mvs_64xx_isr, 7688c2ecf20Sopenharmony_ci mvs_64xx_isr_status, 7698c2ecf20Sopenharmony_ci mvs_64xx_interrupt_enable, 7708c2ecf20Sopenharmony_ci mvs_64xx_interrupt_disable, 7718c2ecf20Sopenharmony_ci mvs_read_phy_ctl, 7728c2ecf20Sopenharmony_ci mvs_write_phy_ctl, 7738c2ecf20Sopenharmony_ci mvs_read_port_cfg_data, 7748c2ecf20Sopenharmony_ci mvs_write_port_cfg_data, 7758c2ecf20Sopenharmony_ci mvs_write_port_cfg_addr, 7768c2ecf20Sopenharmony_ci mvs_read_port_vsr_data, 7778c2ecf20Sopenharmony_ci mvs_write_port_vsr_data, 7788c2ecf20Sopenharmony_ci mvs_write_port_vsr_addr, 7798c2ecf20Sopenharmony_ci mvs_read_port_irq_stat, 7808c2ecf20Sopenharmony_ci mvs_write_port_irq_stat, 7818c2ecf20Sopenharmony_ci mvs_read_port_irq_mask, 7828c2ecf20Sopenharmony_ci mvs_write_port_irq_mask, 7838c2ecf20Sopenharmony_ci mvs_64xx_command_active, 7848c2ecf20Sopenharmony_ci mvs_64xx_clear_srs_irq, 7858c2ecf20Sopenharmony_ci mvs_64xx_issue_stop, 7868c2ecf20Sopenharmony_ci mvs_start_delivery, 7878c2ecf20Sopenharmony_ci mvs_rx_update, 7888c2ecf20Sopenharmony_ci mvs_int_full, 7898c2ecf20Sopenharmony_ci mvs_64xx_assign_reg_set, 7908c2ecf20Sopenharmony_ci mvs_64xx_free_reg_set, 7918c2ecf20Sopenharmony_ci mvs_get_prd_size, 7928c2ecf20Sopenharmony_ci mvs_get_prd_count, 7938c2ecf20Sopenharmony_ci mvs_64xx_make_prd, 7948c2ecf20Sopenharmony_ci mvs_64xx_detect_porttype, 7958c2ecf20Sopenharmony_ci mvs_64xx_oob_done, 7968c2ecf20Sopenharmony_ci mvs_64xx_fix_phy_info, 7978c2ecf20Sopenharmony_ci mvs_64xx_phy_work_around, 7988c2ecf20Sopenharmony_ci mvs_64xx_phy_set_link_rate, 7998c2ecf20Sopenharmony_ci mvs_hw_max_link_rate, 8008c2ecf20Sopenharmony_ci mvs_64xx_phy_disable, 8018c2ecf20Sopenharmony_ci mvs_64xx_phy_enable, 8028c2ecf20Sopenharmony_ci mvs_64xx_phy_reset, 8038c2ecf20Sopenharmony_ci mvs_64xx_stp_reset, 8048c2ecf20Sopenharmony_ci mvs_64xx_clear_active_cmds, 8058c2ecf20Sopenharmony_ci mvs_64xx_spi_read_data, 8068c2ecf20Sopenharmony_ci mvs_64xx_spi_write_data, 8078c2ecf20Sopenharmony_ci mvs_64xx_spi_buildcmd, 8088c2ecf20Sopenharmony_ci mvs_64xx_spi_issuecmd, 8098c2ecf20Sopenharmony_ci mvs_64xx_spi_waitdataready, 8108c2ecf20Sopenharmony_ci mvs_64xx_fix_dma, 8118c2ecf20Sopenharmony_ci mvs_64xx_tune_interrupt, 8128c2ecf20Sopenharmony_ci NULL, 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_ci 815