blob: 37223d8fc5c59981835ac81438c9a818d6b1d97a [file] [log] [blame]
/*
*
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/arch/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
}