|
|
|
@ -53,6 +53,7 @@
|
|
|
|
|
#define PCIE_CLIENT_ARI_ENABLE HIWORD_UPDATE_BIT(0x0008)
|
|
|
|
|
#define PCIE_CLIENT_CONF_LANE_NUM(x) HIWORD_UPDATE(0x0030, ENCODE_LANES(x))
|
|
|
|
|
#define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040)
|
|
|
|
|
#define PCIE_CLIENT_GEN_SEL_1 HIWORD_UPDATE(0x0080, 0)
|
|
|
|
|
#define PCIE_CLIENT_GEN_SEL_2 HIWORD_UPDATE_BIT(0x0080)
|
|
|
|
|
#define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48)
|
|
|
|
|
#define PCIE_CLIENT_LINK_STATUS_UP 0x00300000
|
|
|
|
@ -135,13 +136,14 @@
|
|
|
|
|
#define PCIE_RC_CONFIG_VENDOR (PCIE_RC_CONFIG_BASE + 0x00)
|
|
|
|
|
#define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08)
|
|
|
|
|
#define PCIE_RC_CONFIG_SCC_SHIFT 16
|
|
|
|
|
#define PCIE_RC_CONFIG_DCR (PCIE_RC_CONFIG_BASE + 0xc4)
|
|
|
|
|
#define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18
|
|
|
|
|
#define PCIE_RC_CONFIG_DCR_CSPL_LIMIT 0xff
|
|
|
|
|
#define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26
|
|
|
|
|
#define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0)
|
|
|
|
|
#define PCIE_RC_CONFIG_LCS_RETRAIN_LINK BIT(5)
|
|
|
|
|
#define PCIE_RC_CONFIG_LCS_LBMIE BIT(10)
|
|
|
|
|
#define PCIE_RC_CONFIG_LCS_LABIE BIT(11)
|
|
|
|
|
#define PCIE_RC_CONFIG_LCS_LBMS BIT(30)
|
|
|
|
|
#define PCIE_RC_CONFIG_LCS_LAMS BIT(31)
|
|
|
|
|
#define PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 (PCIE_RC_CONFIG_BASE + 0x90c)
|
|
|
|
|
#define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274)
|
|
|
|
|
#define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20)
|
|
|
|
|
|
|
|
|
|
#define PCIE_CORE_AXI_CONF_BASE 0xc00000
|
|
|
|
|
#define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0)
|
|
|
|
@ -190,6 +192,9 @@ struct rockchip_pcie {
|
|
|
|
|
struct reset_control *mgmt_rst;
|
|
|
|
|
struct reset_control *mgmt_sticky_rst;
|
|
|
|
|
struct reset_control *pipe_rst;
|
|
|
|
|
struct reset_control *pm_rst;
|
|
|
|
|
struct reset_control *aclk_rst;
|
|
|
|
|
struct reset_control *pclk_rst;
|
|
|
|
|
struct clk *aclk_pcie;
|
|
|
|
|
struct clk *aclk_perf_pcie;
|
|
|
|
|
struct clk *hclk_pcie;
|
|
|
|
@ -200,8 +205,14 @@ struct rockchip_pcie {
|
|
|
|
|
struct gpio_desc *ep_gpio;
|
|
|
|
|
u32 lanes;
|
|
|
|
|
u8 root_bus_nr;
|
|
|
|
|
int link_gen;
|
|
|
|
|
struct device *dev;
|
|
|
|
|
struct irq_domain *irq_domain;
|
|
|
|
|
u32 io_size;
|
|
|
|
|
int offset;
|
|
|
|
|
phys_addr_t io_bus_addr;
|
|
|
|
|
u32 mem_size;
|
|
|
|
|
phys_addr_t mem_bus_addr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg)
|
|
|
|
@ -220,7 +231,7 @@ static void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rockchip)
|
|
|
|
|
u32 status;
|
|
|
|
|
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
status |= (PCIE_RC_CONFIG_LCS_LBMIE | PCIE_RC_CONFIG_LCS_LABIE);
|
|
|
|
|
status |= (PCI_EXP_LNKCTL_LBMIE | PCI_EXP_LNKCTL_LABIE);
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -229,7 +240,7 @@ static void rockchip_pcie_clr_bw_int(struct rockchip_pcie *rockchip)
|
|
|
|
|
u32 status;
|
|
|
|
|
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
status |= (PCIE_RC_CONFIG_LCS_LBMS | PCIE_RC_CONFIG_LCS_LAMS);
|
|
|
|
|
status |= (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_LABS) << 16;
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -395,6 +406,40 @@ static struct pci_ops rockchip_pcie_ops = {
|
|
|
|
|
.write = rockchip_pcie_wr_conf,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip)
|
|
|
|
|
{
|
|
|
|
|
u32 status, curr, scale, power;
|
|
|
|
|
|
|
|
|
|
if (IS_ERR(rockchip->vpcie3v3))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set RC's captured slot power limit and scale if
|
|
|
|
|
* vpcie3v3 available. The default values are both zero
|
|
|
|
|
* which means the software should set these two according
|
|
|
|
|
* to the actual power supply.
|
|
|
|
|
*/
|
|
|
|
|
curr = regulator_get_current_limit(rockchip->vpcie3v3);
|
|
|
|
|
if (curr > 0) {
|
|
|
|
|
scale = 3; /* 0.001x */
|
|
|
|
|
curr = curr / 1000; /* convert to mA */
|
|
|
|
|
power = (curr * 3300) / 1000; /* milliwatt */
|
|
|
|
|
while (power > PCIE_RC_CONFIG_DCR_CSPL_LIMIT) {
|
|
|
|
|
if (!scale) {
|
|
|
|
|
dev_warn(rockchip->dev, "invalid power supply\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
scale--;
|
|
|
|
|
power = power / 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCR);
|
|
|
|
|
status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) |
|
|
|
|
|
(scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT);
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* rockchip_pcie_init_port - Initialize hardware
|
|
|
|
|
* @rockchip: PCIe port information
|
|
|
|
@ -408,6 +453,24 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
|
|
|
|
|
|
|
|
|
|
gpiod_set_value(rockchip->ep_gpio, 0);
|
|
|
|
|
|
|
|
|
|
err = reset_control_assert(rockchip->aclk_rst);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "assert aclk_rst err %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = reset_control_assert(rockchip->pclk_rst);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "assert pclk_rst err %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = reset_control_assert(rockchip->pm_rst);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "assert pm_rst err %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = phy_init(rockchip->phy);
|
|
|
|
|
if (err < 0) {
|
|
|
|
|
dev_err(dev, "fail to init phy, err %d\n", err);
|
|
|
|
@ -438,14 +501,40 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
udelay(10);
|
|
|
|
|
|
|
|
|
|
err = reset_control_deassert(rockchip->pm_rst);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "deassert pm_rst err %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = reset_control_deassert(rockchip->aclk_rst);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "deassert aclk_rst err %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = reset_control_deassert(rockchip->pclk_rst);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "deassert pclk_rst err %d\n", err);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rockchip->link_gen == 2)
|
|
|
|
|
rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
|
|
|
|
|
PCIE_CLIENT_CONFIG);
|
|
|
|
|
else
|
|
|
|
|
rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
|
|
|
|
|
PCIE_CLIENT_CONFIG);
|
|
|
|
|
|
|
|
|
|
rockchip_pcie_write(rockchip,
|
|
|
|
|
PCIE_CLIENT_CONF_ENABLE |
|
|
|
|
|
PCIE_CLIENT_LINK_TRAIN_ENABLE |
|
|
|
|
|
PCIE_CLIENT_ARI_ENABLE |
|
|
|
|
|
PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes) |
|
|
|
|
|
PCIE_CLIENT_MODE_RC |
|
|
|
|
|
PCIE_CLIENT_GEN_SEL_2,
|
|
|
|
|
PCIE_CLIENT_CONFIG);
|
|
|
|
|
PCIE_CLIENT_MODE_RC,
|
|
|
|
|
PCIE_CLIENT_CONFIG);
|
|
|
|
|
|
|
|
|
|
err = phy_power_on(rockchip->phy);
|
|
|
|
|
if (err) {
|
|
|
|
@ -481,21 +570,19 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We need to read/write PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 before
|
|
|
|
|
* enabling ASPM. Otherwise L1PwrOnSc and L1PwrOnVal isn't
|
|
|
|
|
* reliable and enabling ASPM doesn't work. This is a controller
|
|
|
|
|
* bug we need to work around.
|
|
|
|
|
*/
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2);
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2);
|
|
|
|
|
|
|
|
|
|
/* Fix the transmitted FTS count desired to exit from L0s. */
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL_PLC1);
|
|
|
|
|
status = (status & PCIE_CORE_CTRL_PLC1_FTS_MASK) |
|
|
|
|
|
status = (status & ~PCIE_CORE_CTRL_PLC1_FTS_MASK) |
|
|
|
|
|
(PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT);
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_CORE_CTRL_PLC1);
|
|
|
|
|
|
|
|
|
|
rockchip_pcie_set_power_limit(rockchip);
|
|
|
|
|
|
|
|
|
|
/* Set RC's clock architecture as common clock */
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
status |= PCI_EXP_LNKCTL_CCC;
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
|
|
|
|
|
/* Enable Gen1 training */
|
|
|
|
|
rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE,
|
|
|
|
|
PCIE_CLIENT_CONFIG);
|
|
|
|
@ -522,35 +609,37 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
|
|
|
|
|
msleep(20);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable retrain for gen2. This should be configured only after
|
|
|
|
|
* gen1 finished.
|
|
|
|
|
*/
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
status |= PCIE_RC_CONFIG_LCS_RETRAIN_LINK;
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
if (rockchip->link_gen == 2) {
|
|
|
|
|
/*
|
|
|
|
|
* Enable retrain for gen2. This should be configured only after
|
|
|
|
|
* gen1 finished.
|
|
|
|
|
*/
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
status |= PCI_EXP_LNKCTL_RL;
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
|
|
|
|
|
|
|
|
|
|
timeout = jiffies + msecs_to_jiffies(500);
|
|
|
|
|
for (;;) {
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
|
|
|
|
|
if ((status & PCIE_CORE_PL_CONF_SPEED_MASK) ==
|
|
|
|
|
PCIE_CORE_PL_CONF_SPEED_5G) {
|
|
|
|
|
dev_dbg(dev, "PCIe link training gen2 pass!\n");
|
|
|
|
|
break;
|
|
|
|
|
timeout = jiffies + msecs_to_jiffies(500);
|
|
|
|
|
for (;;) {
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
|
|
|
|
|
if ((status & PCIE_CORE_PL_CONF_SPEED_MASK) ==
|
|
|
|
|
PCIE_CORE_PL_CONF_SPEED_5G) {
|
|
|
|
|
dev_dbg(dev, "PCIe link training gen2 pass!\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (time_after(jiffies, timeout)) {
|
|
|
|
|
dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msleep(20);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (time_after(jiffies, timeout)) {
|
|
|
|
|
dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msleep(20);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check the final link width from negotiated lane counter from MGMT */
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
|
|
|
|
|
status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>
|
|
|
|
|
PCIE_CORE_PL_CONF_LANE_MASK);
|
|
|
|
|
status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>
|
|
|
|
|
PCIE_CORE_PL_CONF_LANE_SHIFT);
|
|
|
|
|
dev_dbg(dev, "current link width is x%d\n", status);
|
|
|
|
|
|
|
|
|
|
rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID,
|
|
|
|
@ -558,6 +647,12 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
|
|
|
|
|
rockchip_pcie_write(rockchip,
|
|
|
|
|
PCI_CLASS_BRIDGE_PCI << PCIE_RC_CONFIG_SCC_SHIFT,
|
|
|
|
|
PCIE_RC_CONFIG_RID_CCR);
|
|
|
|
|
|
|
|
|
|
/* Clear THP cap's next cap pointer to remove L1 substate cap */
|
|
|
|
|
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_THP_CAP);
|
|
|
|
|
status &= ~PCIE_RC_CONFIG_THP_CAP_NEXT_MASK;
|
|
|
|
|
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_THP_CAP);
|
|
|
|
|
|
|
|
|
|
rockchip_pcie_write(rockchip, 0x0, PCIE_RC_BAR_CONF);
|
|
|
|
|
|
|
|
|
|
rockchip_pcie_write(rockchip,
|
|
|
|
@ -753,6 +848,10 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
|
|
|
|
rockchip->lanes = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rockchip->link_gen = of_pci_get_max_link_speed(node);
|
|
|
|
|
if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
|
|
|
|
|
rockchip->link_gen = 2;
|
|
|
|
|
|
|
|
|
|
rockchip->core_rst = devm_reset_control_get(dev, "core");
|
|
|
|
|
if (IS_ERR(rockchip->core_rst)) {
|
|
|
|
|
if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER)
|
|
|
|
@ -781,6 +880,27 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
|
|
|
|
return PTR_ERR(rockchip->pipe_rst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rockchip->pm_rst = devm_reset_control_get(dev, "pm");
|
|
|
|
|
if (IS_ERR(rockchip->pm_rst)) {
|
|
|
|
|
if (PTR_ERR(rockchip->pm_rst) != -EPROBE_DEFER)
|
|
|
|
|
dev_err(dev, "missing pm reset property in node\n");
|
|
|
|
|
return PTR_ERR(rockchip->pm_rst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rockchip->pclk_rst = devm_reset_control_get(dev, "pclk");
|
|
|
|
|
if (IS_ERR(rockchip->pclk_rst)) {
|
|
|
|
|
if (PTR_ERR(rockchip->pclk_rst) != -EPROBE_DEFER)
|
|
|
|
|
dev_err(dev, "missing pclk reset property in node\n");
|
|
|
|
|
return PTR_ERR(rockchip->pclk_rst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rockchip->aclk_rst = devm_reset_control_get(dev, "aclk");
|
|
|
|
|
if (IS_ERR(rockchip->aclk_rst)) {
|
|
|
|
|
if (PTR_ERR(rockchip->aclk_rst) != -EPROBE_DEFER)
|
|
|
|
|
dev_err(dev, "missing aclk reset property in node\n");
|
|
|
|
|
return PTR_ERR(rockchip->aclk_rst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rockchip->ep_gpio = devm_gpiod_get(dev, "ep", GPIOD_OUT_HIGH);
|
|
|
|
|
if (IS_ERR(rockchip->ep_gpio)) {
|
|
|
|
|
dev_err(dev, "missing ep-gpios property in node\n");
|
|
|
|
@ -1025,6 +1145,50 @@ static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie *rockchip,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rockchip_cfg_atu(struct rockchip_pcie *rockchip)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = rockchip->dev;
|
|
|
|
|
int offset;
|
|
|
|
|
int err;
|
|
|
|
|
int reg_no;
|
|
|
|
|
|
|
|
|
|
for (reg_no = 0; reg_no < (rockchip->mem_size >> 20); reg_no++) {
|
|
|
|
|
err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1,
|
|
|
|
|
AXI_WRAPPER_MEM_WRITE,
|
|
|
|
|
20 - 1,
|
|
|
|
|
rockchip->mem_bus_addr +
|
|
|
|
|
(reg_no << 20),
|
|
|
|
|
0);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "program RC mem outbound ATU failed\n");
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "program RC mem inbound ATU failed\n");
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset = rockchip->mem_size >> 20;
|
|
|
|
|
for (reg_no = 0; reg_no < (rockchip->io_size >> 20); reg_no++) {
|
|
|
|
|
err = rockchip_pcie_prog_ob_atu(rockchip,
|
|
|
|
|
reg_no + 1 + offset,
|
|
|
|
|
AXI_WRAPPER_IO_WRITE,
|
|
|
|
|
20 - 1,
|
|
|
|
|
rockchip->io_bus_addr +
|
|
|
|
|
(reg_no << 20),
|
|
|
|
|
0);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "program RC io outbound ATU failed\n");
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rockchip_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
{
|
|
|
|
|
struct rockchip_pcie *rockchip;
|
|
|
|
@ -1034,13 +1198,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
resource_size_t io_base;
|
|
|
|
|
struct resource *mem;
|
|
|
|
|
struct resource *io;
|
|
|
|
|
phys_addr_t io_bus_addr = 0;
|
|
|
|
|
u32 io_size;
|
|
|
|
|
phys_addr_t mem_bus_addr = 0;
|
|
|
|
|
u32 mem_size = 0;
|
|
|
|
|
int reg_no;
|
|
|
|
|
int err;
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
|
LIST_HEAD(res);
|
|
|
|
|
|
|
|
|
@ -1107,14 +1265,13 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
goto err_vpcie;
|
|
|
|
|
|
|
|
|
|
/* Get the I/O and memory ranges from DT */
|
|
|
|
|
io_size = 0;
|
|
|
|
|
resource_list_for_each_entry(win, &res) {
|
|
|
|
|
switch (resource_type(win->res)) {
|
|
|
|
|
case IORESOURCE_IO:
|
|
|
|
|
io = win->res;
|
|
|
|
|
io->name = "I/O";
|
|
|
|
|
io_size = resource_size(io);
|
|
|
|
|
io_bus_addr = io->start - win->offset;
|
|
|
|
|
rockchip->io_size = resource_size(io);
|
|
|
|
|
rockchip->io_bus_addr = io->start - win->offset;
|
|
|
|
|
err = pci_remap_iospace(io, io_base);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_warn(dev, "error %d: failed to map resource %pR\n",
|
|
|
|
@ -1125,8 +1282,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
case IORESOURCE_MEM:
|
|
|
|
|
mem = win->res;
|
|
|
|
|
mem->name = "MEM";
|
|
|
|
|
mem_size = resource_size(mem);
|
|
|
|
|
mem_bus_addr = mem->start - win->offset;
|
|
|
|
|
rockchip->mem_size = resource_size(mem);
|
|
|
|
|
rockchip->mem_bus_addr = mem->start - win->offset;
|
|
|
|
|
break;
|
|
|
|
|
case IORESOURCE_BUS:
|
|
|
|
|
rockchip->root_bus_nr = win->res->start;
|
|
|
|
@ -1136,45 +1293,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mem_size) {
|
|
|
|
|
for (reg_no = 0; reg_no < (mem_size >> 20); reg_no++) {
|
|
|
|
|
err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1,
|
|
|
|
|
AXI_WRAPPER_MEM_WRITE,
|
|
|
|
|
20 - 1,
|
|
|
|
|
mem_bus_addr +
|
|
|
|
|
(reg_no << 20),
|
|
|
|
|
0);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "program RC mem outbound ATU failed\n");
|
|
|
|
|
goto err_vpcie;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "program RC mem inbound ATU failed\n");
|
|
|
|
|
err = rockchip_cfg_atu(rockchip);
|
|
|
|
|
if (err)
|
|
|
|
|
goto err_vpcie;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset = mem_size >> 20;
|
|
|
|
|
|
|
|
|
|
if (io_size) {
|
|
|
|
|
for (reg_no = 0; reg_no < (io_size >> 20); reg_no++) {
|
|
|
|
|
err = rockchip_pcie_prog_ob_atu(rockchip,
|
|
|
|
|
reg_no + 1 + offset,
|
|
|
|
|
AXI_WRAPPER_IO_WRITE,
|
|
|
|
|
20 - 1,
|
|
|
|
|
io_bus_addr +
|
|
|
|
|
(reg_no << 20),
|
|
|
|
|
0);
|
|
|
|
|
if (err) {
|
|
|
|
|
dev_err(dev, "program RC io outbound ATU failed\n");
|
|
|
|
|
goto err_vpcie;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res);
|
|
|
|
|
if (!bus) {
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|