298 lines
9.0 KiB
C
298 lines
9.0 KiB
C
/*
|
|
*
|
|
* Copyright 2017 NXP
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <asm/io.h>
|
|
#include <asm/mach-imx/sci/sci.h>
|
|
#include <common.h>
|
|
#include <linux/sizes.h>
|
|
#include <imx8_hsio.h>
|
|
|
|
void pcie_ctrlx2_rst(void)
|
|
{
|
|
/* gpio config */
|
|
/* dir wakeup input clkreq and pereset output */
|
|
writel(0x2d, HSIO_GPIO_BASE_ADDR + 0x4);
|
|
writel(0x24, HSIO_GPIO_BASE_ADDR + 0x0); /* do pereset 1 */
|
|
|
|
clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_BUTTON_RST_N);
|
|
clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_PERST_N);
|
|
clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_POWER_UP_RST_N);
|
|
udelay(10);
|
|
setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_BUTTON_RST_N);
|
|
setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_PERST_N);
|
|
setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_POWER_UP_RST_N);
|
|
}
|
|
|
|
void pcie_ctrlx1_rst(void)
|
|
{
|
|
/* gpio config */
|
|
/* dir wakeup input clkreq and pereset output */
|
|
writel(0x2d, HSIO_GPIO_BASE_ADDR + 0x4);
|
|
writel(0x24, HSIO_GPIO_BASE_ADDR + 0x0); /* do pereset 1 */
|
|
|
|
clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_BUTTON_RST_N);
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_BUTTON_RST_N);
|
|
clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
|
|
clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
|
|
}
|
|
|
|
int pcie_ctrla_init_rc(int lane)
|
|
{
|
|
u32 val, i = 0;
|
|
|
|
setbits_le32(HW_PHYX2_CTRL0_ADDR, HW_PHYX2_CTRL0_APB_RSTN_0
|
|
| HW_PHYX2_CTRL0_APB_RSTN_1); /* APB_RSTN_0/1 */
|
|
|
|
clrbits_le32(HW_PCIEX2_CTRL0_ADDR, HW_PCIEX2_CTRL0_DEVICE_TYPE_MASK);
|
|
setbits_le32(HW_PCIEX2_CTRL0_ADDR, HW_PCIEX2_CTRL0_DEVICE_TYPE_RC);
|
|
|
|
if (lane == 1) {
|
|
/*
|
|
* bit 0 rx ena. bit 11 fast_init.
|
|
* bit12 PHY_X1_EPCS_SEL 1.
|
|
* bit13 phy_ab_select 1.
|
|
*/
|
|
setbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_IOB_RXENA
|
|
| HW_MISC_CTRL0_PHY_X1_EPCS_SEL
|
|
| HW_MISC_CTRL0_PCIE_AB_SELECT);
|
|
/* pipe_ln2lk = 1001 */
|
|
clrbits_le32(HW_PHYX2_CTRL0_ADDR,
|
|
HW_PHYX2_CTRL0_PIPE_LN2LK_MASK);
|
|
setbits_le32(HW_PHYX2_CTRL0_ADDR, HW_PHYX2_CTRL0_PIPE_LN2LK_3
|
|
| HW_PHYX2_CTRL0_PIPE_LN2LK_0);
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PHYX2_STTS0_ADDR);
|
|
val &= HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK;
|
|
if (val == HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK)
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if (val != HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK) {
|
|
printf("TX PLL is not locked.\n");
|
|
return -ENODEV;
|
|
}
|
|
setbits_le32(GPR_LPCG_PHYX2APB_0_APB, BIT(1));
|
|
/* Set the link_capable to be lane1 */
|
|
clrbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_EN_MASK);
|
|
setbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_LANE1);
|
|
clrbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_MASK);
|
|
setbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_1);
|
|
} else if (lane == 2) {
|
|
/*
|
|
* bit 0 rx ena. bit 11 fast_init.
|
|
* bit12 PHY_X1_EPCS_SEL 1.
|
|
*/
|
|
setbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_IOB_RXENA
|
|
| HW_MISC_CTRL0_PHY_X1_EPCS_SEL);
|
|
/* pipe_ln2lk = 0011 */
|
|
clrbits_le32(HW_PHYX2_CTRL0_ADDR,
|
|
HW_PHYX2_CTRL0_PIPE_LN2LK_MASK);
|
|
setbits_le32(HW_PHYX2_CTRL0_ADDR, HW_PHYX2_CTRL0_PIPE_LN2LK_1
|
|
| HW_PHYX2_CTRL0_PIPE_LN2LK_0);
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PHYX2_STTS0_ADDR);
|
|
val &= (HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK | HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK);
|
|
if (val == (HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK | HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK))
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if (val != (HW_PHYX2_STTS0_LANE0_TX_PLL_LOCK | HW_PHYX2_STTS0_LANE1_TX_PLL_LOCK)) {
|
|
printf("TX PLL is not locked.\n");
|
|
return -ENODEV;
|
|
}
|
|
setbits_le32(GPR_LPCG_PHYX2APB_0_APB, BIT(1) + BIT(5));
|
|
/* Set the link_capable to be lane2 */
|
|
clrbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_EN_MASK);
|
|
setbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_LANE2);
|
|
clrbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_MASK);
|
|
setbits_le32(PORT0_GEN2_CTRL, PORT_GEN2_CTRL_NUM_LANES_2);
|
|
} else {
|
|
printf("%s %d lane %d is invalid.\n", __func__, __LINE__, lane);
|
|
}
|
|
|
|
/* bit19 PM_REQ_CORE_RST of pciex2_stts0 should be cleared. */
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PCIEX2_STTS0_ADDR);
|
|
if ((val & HW_PCIEX2_STTS0_PM_REQ_CORE_RST) == 0)
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if ((val & HW_PCIEX2_STTS0_PM_REQ_CORE_RST) != 0)
|
|
printf("ERROR PM_REQ_CORE_RST is set.\n");
|
|
|
|
/* DBI_RO_WR_EN =1 to write PF0_SPCIE_CAP_OFF_0CH_REG */
|
|
writel(0x1, PORT0_MISC_CONTROL_1);
|
|
writel(0x35353535, PF0_SPCIE_CAP_OFF_0CH_REG); /* set preset not golden */
|
|
setbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
|
|
setbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_APP_LTSSM_ENABLE);
|
|
|
|
do {
|
|
udelay(100);
|
|
val = readl(PORT0_LINK_DEBUG1);
|
|
} while (((val & PORT_LINK_DEBUG1_LINK_UP) == 0) && (i++ < 100));
|
|
|
|
if ((val & PORT_LINK_DEBUG1_LINK_UP) == PORT_LINK_DEBUG1_LINK_UP)
|
|
printf("[%s] LNK UP %x\r\n", __func__, val);
|
|
else {
|
|
printf("[%s] LNK DOWN %x\r\n", __func__, val);
|
|
clrbits_le32(HW_PCIEX2_CTRL2_ADDR, HW_PCIEX2_CTRL2_APP_LTSSM_ENABLE);
|
|
return -ENODEV;
|
|
}
|
|
|
|
clrbits_le32(PORT0_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
|
|
|
|
val = readl(PF0_LINK_CONTROL_LINK_STATUS_REG);
|
|
printf("[%s] PCIe GEN[%d] Lane[%d] is up.\n", __func__,
|
|
(val >> 16) & 0xF, (val >> 20) & 0x3F);
|
|
|
|
/* EQ phase 3 finish
|
|
* wait_read_check(LINK_CONTROL2_LINK_STATUS2_REG,BIT(17),BIT(17),1000);
|
|
*/
|
|
/* make sure that pciea is L0 state now */
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PCIEX2_STTS0_ADDR);
|
|
if ((val & 0x3f) == 0x11)
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if ((val & 0x3f) != 0x11)
|
|
printf("can't return back to L0 state.\n");
|
|
|
|
writel(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
|
|
PF0_TYPE1_STATUS_COMMAND_REG);
|
|
printf("pcie ctrla initialization is finished.\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pcie_ctrlb_sata_phy_init_rc(void)
|
|
{
|
|
u32 val, i = 0;
|
|
|
|
setbits_le32(HW_PHYX1_CTRL0_ADDR, HW_PHYX1_CTRL0_APB_RSTN); /* APB_RSTN */
|
|
|
|
clrbits_le32(HW_PCIEX1_CTRL0_ADDR, HW_PCIEX1_CTRL0_DEVICE_TYPE_MASK);
|
|
setbits_le32(HW_PCIEX1_CTRL0_ADDR, HW_PCIEX1_CTRL0_DEVICE_TYPE_RC);
|
|
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_BUTTON_RST_N);
|
|
clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_PERST_N);
|
|
clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_POWER_UP_RST_N);
|
|
|
|
/*
|
|
* bit 0 rx ena. bit 11 fast_init.
|
|
* bit13 phy_ab_select 1.
|
|
*/
|
|
setbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_IOB_RXENA);
|
|
clrbits_le32(HW_MISC_CTRL0_ADDR, HW_MISC_CTRL0_PHY_X1_EPCS_SEL);
|
|
|
|
/* pipe_ln2lk = 0011 */
|
|
clrbits_le32(HW_PHYX1_CTRL0_ADDR,
|
|
HW_PHYX1_CTRL0_PIPE_LN2LK_MASK);
|
|
setbits_le32(HW_PHYX1_CTRL0_ADDR, HW_PHYX1_CTRL0_PIPE_LN2LK_1
|
|
| HW_PHYX2_CTRL0_PIPE_LN2LK_0);
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PHYX1_STTS0_ADDR);
|
|
val &= HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK;
|
|
if (val == HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK)
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if (val != HW_PHYX1_STTS0_LANE0_TX_PLL_LOCK) {
|
|
printf("TX PLL is not locked.\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
setbits_le32(GPR_LPCG_PHYX1_APB, BIT(1));
|
|
|
|
/* bit19 PM_REQ_CORE_RST of pciex1_stts0 should be cleared. */
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PCIEX1_STTS0_ADDR);
|
|
if ((val & HW_PCIEX1_STTS0_PM_REQ_CORE_RST) == 0)
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if ((val & HW_PCIEX1_STTS0_PM_REQ_CORE_RST) != 0)
|
|
printf("ERROR PM_REQ_CORE_RST is set.\n");
|
|
|
|
/* DBI_RO_WR_EN =1 to write PF1_SPCIE_CAP_OFF_0CH_REG */
|
|
writel(0x1, PORT1_MISC_CONTROL_1);
|
|
writel(0x35353535, PF1_SPCIE_CAP_OFF_0CH_REG); /* set preset not golden */
|
|
setbits_le32(PORT1_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
|
|
setbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_APP_LTSSM_ENABLE);
|
|
|
|
do {
|
|
udelay(100);
|
|
val = readl(PORT1_LINK_DEBUG1);
|
|
} while (((val & PORT_LINK_DEBUG1_LINK_UP) == 0) && (i++ < 100));
|
|
|
|
if ((val & PORT_LINK_DEBUG1_LINK_UP) == PORT_LINK_DEBUG1_LINK_UP) {
|
|
printf("[%s] LNK UP %x\r\n", __func__, val);
|
|
} else {
|
|
printf("[%s] LNK DOWN %x\r\n", __func__, val);
|
|
clrbits_le32(HW_PCIEX1_CTRL2_ADDR, HW_PCIEX1_CTRL2_APP_LTSSM_ENABLE);
|
|
return -ENODEV;
|
|
}
|
|
clrbits_le32(PORT1_LINK_CTRL, PORT_LINK_CTRL_LNK_FAST_LNK);
|
|
|
|
val = readl(PF1_LINK_CONTROL_LINK_STATUS_REG);
|
|
printf("[%s] PCIe GEN[%d] Lane[%d] is up.\n", __func__,
|
|
(val >> 16) & 0xF, (val >> 20) & 0x3F);
|
|
|
|
/* EQ phase 3 finish
|
|
* wait_read_check(LINK_CONTROL2_LINK_STATUS2_REG,BIT(17),BIT(17),1000);
|
|
*/
|
|
/* make sure that pcieb is L0 state now */
|
|
for (i = 0; i < 100; i++) {
|
|
val = readl(HW_PCIEX1_STTS0_ADDR);
|
|
if ((val & 0x3f) == 0x11)
|
|
break;
|
|
udelay(10);
|
|
}
|
|
|
|
if ((val & 0x3f) != 0x11) {
|
|
printf("can't return back to L0 state.\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
writel(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
|
|
PF1_TYPE1_STATUS_COMMAND_REG);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
void mx8qxp_pcie_init(void)
|
|
{
|
|
pcie_ctrlx1_rst();
|
|
if (!pcie_ctrlb_sata_phy_init_rc())
|
|
mx8x_pcie_ctrlb_setup_regions();
|
|
}
|
|
|
|
void mx8qm_pcie_init(void)
|
|
{
|
|
pcie_ctrlx2_rst();
|
|
if (!pcie_ctrla_init_rc(1))
|
|
mx8x_pcie_ctrla_setup_regions();
|
|
|
|
#ifdef CONFIG_IMX_PCIEB
|
|
pcie_ctrlx1_rst();
|
|
if (!pcie_ctrlb_sata_phy_init_rc())
|
|
mx8x_pcie_ctrlb_setup_regions();
|
|
#endif
|
|
}
|