|
|
|
|
@@ -135,6 +135,9 @@ struct rk_pcie {
|
|
|
|
|
bool slot_pluggable;
|
|
|
|
|
struct gpio_hotplug_slot hp_slot;
|
|
|
|
|
bool hp_no_link;
|
|
|
|
|
bool is_lpbk;
|
|
|
|
|
bool is_comp;
|
|
|
|
|
bool have_rasdes;
|
|
|
|
|
struct regulator *vpcie3v3;
|
|
|
|
|
struct irq_domain *irq_domain;
|
|
|
|
|
raw_spinlock_t intx_lock;
|
|
|
|
|
@@ -153,8 +156,6 @@ struct rk_pcie_of_data {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define to_rk_pcie(x) dev_get_drvdata((x)->dev)
|
|
|
|
|
static int rk_pcie_disable_power(struct rk_pcie *rk_pcie);
|
|
|
|
|
static int rk_pcie_enable_power(struct rk_pcie *rk_pcie);
|
|
|
|
|
|
|
|
|
|
static inline u32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, u32 reg)
|
|
|
|
|
{
|
|
|
|
|
@@ -201,7 +202,7 @@ static void disable_aspm_l1ss(struct rk_pcie *rk_pcie)
|
|
|
|
|
static inline void disable_aspm_l1ss(struct rk_pcie *rk_pcie) { return; }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static inline void rk_pcie_set_mode(struct rk_pcie *rk_pcie)
|
|
|
|
|
static inline void rk_pcie_set_rc_mode(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
if (rk_pcie->supports_clkreq) {
|
|
|
|
|
/* Application is ready to have reference clock removed */
|
|
|
|
|
@@ -272,6 +273,36 @@ static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie)
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_enable_power(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
|
|
|
|
|
if (IS_ERR(rk_pcie->vpcie3v3))
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = regulator_enable(rk_pcie->vpcie3v3);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(dev, "fail to enable vpcie3v3 regulator\n");
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_disable_power(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
|
|
|
|
|
if (IS_ERR(rk_pcie->vpcie3v3))
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = regulator_disable(rk_pcie->vpcie3v3);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(dev, "fail to disable vpcie3v3 regulator\n");
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_establish_link(struct dw_pcie *pci)
|
|
|
|
|
{
|
|
|
|
|
int retries, power;
|
|
|
|
|
@@ -392,182 +423,6 @@ static bool rk_pcie_udma_enabled(struct rk_pcie *rk_pcie)
|
|
|
|
|
PCIE_DMA_CTRL_OFF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_init_dma_trx(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
if (!rk_pcie_udma_enabled(rk_pcie))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
rk_pcie->dma_obj = pcie_dw_dmatest_register(rk_pcie->pci->dev, true);
|
|
|
|
|
if (IS_ERR(rk_pcie->dma_obj)) {
|
|
|
|
|
dev_err(rk_pcie->pci->dev, "failed to prepare dmatest\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Enable client write and read interrupt */
|
|
|
|
|
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000);
|
|
|
|
|
|
|
|
|
|
/* Enable core write interrupt */
|
|
|
|
|
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_MASK,
|
|
|
|
|
0x0);
|
|
|
|
|
/* Enable core read interrupt */
|
|
|
|
|
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK,
|
|
|
|
|
0x0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef MODULE
|
|
|
|
|
void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (pci->ops && pci->ops->write_dbi2) {
|
|
|
|
|
pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(pci->dev, "write DBI address failed\n");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static struct dw_pcie_host_ops rk_pcie_host_ops;
|
|
|
|
|
|
|
|
|
|
static int rk_add_pcie_port(struct rk_pcie *rk_pcie, struct platform_device *pdev)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
struct dw_pcie *pci = rk_pcie->pci;
|
|
|
|
|
struct dw_pcie_rp *pp = &pci->pp;
|
|
|
|
|
struct device *dev = pci->dev;
|
|
|
|
|
|
|
|
|
|
pp->ops = &rk_pcie_host_ops;
|
|
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
|
|
|
|
if (rk_pcie->msi_vector_num > 0) {
|
|
|
|
|
dev_info(dev, "max MSI vector is %d\n", rk_pcie->msi_vector_num);
|
|
|
|
|
pp->num_vectors = rk_pcie->msi_vector_num;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = dw_pcie_host_init(pp);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "failed to initialize host\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disable BAR0 BAR1 */
|
|
|
|
|
dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0x0);
|
|
|
|
|
dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_1, 0x0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_clk_init(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
rk_pcie->clk_cnt = devm_clk_bulk_get_all(dev, &rk_pcie->clks);
|
|
|
|
|
if (rk_pcie->clk_cnt < 1)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
ret = clk_bulk_prepare_enable(rk_pcie->clk_cnt, rk_pcie->clks);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "failed to prepare enable pcie bulk clks: %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_resource_get(struct platform_device *pdev,
|
|
|
|
|
struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
struct resource *dbi_base;
|
|
|
|
|
struct resource *apb_base;
|
|
|
|
|
|
|
|
|
|
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
|
|
|
|
"pcie-dbi");
|
|
|
|
|
if (!dbi_base) {
|
|
|
|
|
dev_err(&pdev->dev, "get pcie-dbi failed\n");
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rk_pcie->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
|
|
|
|
|
if (IS_ERR(rk_pcie->dbi_base))
|
|
|
|
|
return PTR_ERR(rk_pcie->dbi_base);
|
|
|
|
|
|
|
|
|
|
rk_pcie->pci->dbi_base = rk_pcie->dbi_base;
|
|
|
|
|
rk_pcie->pci->dbi_base2 = rk_pcie->pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET;
|
|
|
|
|
|
|
|
|
|
apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
|
|
|
|
"pcie-apb");
|
|
|
|
|
if (!apb_base) {
|
|
|
|
|
dev_err(&pdev->dev, "get pcie-apb failed\n");
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
rk_pcie->apb_base = devm_ioremap_resource(&pdev->dev, apb_base);
|
|
|
|
|
if (IS_ERR(rk_pcie->apb_base))
|
|
|
|
|
return PTR_ERR(rk_pcie->apb_base);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Rest the device before enabling power because some of the
|
|
|
|
|
* platforms may use external refclk input with the some power
|
|
|
|
|
* rail connect to 100MHz OSC chip. So once the power is up for
|
|
|
|
|
* the slot and the refclk is available, which isn't quite follow
|
|
|
|
|
* the spec. We should make sure it is in reset state before
|
|
|
|
|
* everthing's ready.
|
|
|
|
|
*/
|
|
|
|
|
rk_pcie->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
|
|
|
|
|
GPIOD_OUT_LOW);
|
|
|
|
|
if (IS_ERR(rk_pcie->rst_gpio)) {
|
|
|
|
|
dev_err(&pdev->dev, "invalid reset-gpios property in node\n");
|
|
|
|
|
return PTR_ERR(rk_pcie->rst_gpio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device_property_read_u32(&pdev->dev, "rockchip,perst-inactive-ms",
|
|
|
|
|
&rk_pcie->perst_inactive_ms))
|
|
|
|
|
rk_pcie->perst_inactive_ms = 200;
|
|
|
|
|
|
|
|
|
|
rk_pcie->prsnt_gpio = devm_gpiod_get_optional(&pdev->dev, "prsnt", GPIOD_IN);
|
|
|
|
|
if (IS_ERR_OR_NULL(rk_pcie->prsnt_gpio))
|
|
|
|
|
dev_info(&pdev->dev, "invalid prsnt-gpios property in node\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_phy_init(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
|
|
|
|
|
rk_pcie->phy = devm_phy_optional_get(dev, "pcie-phy");
|
|
|
|
|
if (IS_ERR(rk_pcie->phy)) {
|
|
|
|
|
if (PTR_ERR(rk_pcie->phy) != -EPROBE_DEFER)
|
|
|
|
|
dev_info(dev, "missing phy\n");
|
|
|
|
|
return PTR_ERR(rk_pcie->phy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = phy_set_mode_ext(rk_pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "fail to set phy to rc mode, err %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rk_pcie->bifurcation)
|
|
|
|
|
phy_set_mode_ext(rk_pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_BIFURCATION);
|
|
|
|
|
|
|
|
|
|
ret = phy_init(rk_pcie->phy);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(dev, "fail to init phy, err %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
phy_power_on(rk_pcie->phy);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, struct dma_table *cur, int ctr_off)
|
|
|
|
|
{
|
|
|
|
|
struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev);
|
|
|
|
|
@@ -655,6 +510,237 @@ static void rk_pcie_config_dma_dwc(struct dma_table *table)
|
|
|
|
|
table->start.chnl = table->chn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_init_dma_trx(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
if (!rk_pcie_udma_enabled(rk_pcie))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
rk_pcie->dma_obj = pcie_dw_dmatest_register(rk_pcie->pci->dev, true);
|
|
|
|
|
if (IS_ERR(rk_pcie->dma_obj)) {
|
|
|
|
|
dev_err(rk_pcie->pci->dev, "failed to prepare dmatest\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Enable client write and read interrupt */
|
|
|
|
|
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000);
|
|
|
|
|
|
|
|
|
|
/* Enable core write interrupt */
|
|
|
|
|
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_MASK,
|
|
|
|
|
0x0);
|
|
|
|
|
/* Enable core read interrupt */
|
|
|
|
|
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK,
|
|
|
|
|
0x0);
|
|
|
|
|
|
|
|
|
|
rk_pcie->dma_obj->start_dma_func = rk_pcie_start_dma_dwc;
|
|
|
|
|
rk_pcie->dma_obj->config_dma_func = rk_pcie_config_dma_dwc;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef MODULE
|
|
|
|
|
void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (pci->ops && pci->ops->write_dbi2) {
|
|
|
|
|
pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(pci->dev, "write DBI address failed\n");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static struct dw_pcie_host_ops rk_pcie_host_ops;
|
|
|
|
|
|
|
|
|
|
static int rk_add_pcie_port(struct rk_pcie *rk_pcie, struct platform_device *pdev)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
struct dw_pcie *pci = rk_pcie->pci;
|
|
|
|
|
struct dw_pcie_rp *pp = &pci->pp;
|
|
|
|
|
struct device *dev = pci->dev;
|
|
|
|
|
|
|
|
|
|
pp->ops = &rk_pcie_host_ops;
|
|
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
|
|
|
|
if (rk_pcie->msi_vector_num > 0) {
|
|
|
|
|
dev_info(dev, "max MSI vector is %d\n", rk_pcie->msi_vector_num);
|
|
|
|
|
pp->num_vectors = rk_pcie->msi_vector_num;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = dw_pcie_host_init(pp);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "failed to initialize host\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disable BAR0 BAR1 */
|
|
|
|
|
dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0x0);
|
|
|
|
|
dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_1, 0x0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_resource_get(struct platform_device *pdev,
|
|
|
|
|
struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
struct resource *dbi_base;
|
|
|
|
|
struct resource *apb_base;
|
|
|
|
|
u32 val = 0;
|
|
|
|
|
|
|
|
|
|
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
|
|
|
|
"pcie-dbi");
|
|
|
|
|
if (!dbi_base) {
|
|
|
|
|
dev_err(&pdev->dev, "get pcie-dbi failed\n");
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rk_pcie->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
|
|
|
|
|
if (IS_ERR(rk_pcie->dbi_base))
|
|
|
|
|
return PTR_ERR(rk_pcie->dbi_base);
|
|
|
|
|
|
|
|
|
|
rk_pcie->pci->dbi_base = rk_pcie->dbi_base;
|
|
|
|
|
rk_pcie->pci->dbi_base2 = rk_pcie->pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET;
|
|
|
|
|
|
|
|
|
|
apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
|
|
|
|
"pcie-apb");
|
|
|
|
|
if (!apb_base) {
|
|
|
|
|
dev_err(&pdev->dev, "get pcie-apb failed\n");
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
rk_pcie->apb_base = devm_ioremap_resource(&pdev->dev, apb_base);
|
|
|
|
|
if (IS_ERR(rk_pcie->apb_base))
|
|
|
|
|
return PTR_ERR(rk_pcie->apb_base);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Rest the device before enabling power because some of the
|
|
|
|
|
* platforms may use external refclk input with the some power
|
|
|
|
|
* rail connect to 100MHz OSC chip. So once the power is up for
|
|
|
|
|
* the slot and the refclk is available, which isn't quite follow
|
|
|
|
|
* the spec. We should make sure it is in reset state before
|
|
|
|
|
* everthing's ready.
|
|
|
|
|
*/
|
|
|
|
|
rk_pcie->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
|
|
|
|
|
GPIOD_OUT_LOW);
|
|
|
|
|
if (IS_ERR(rk_pcie->rst_gpio)) {
|
|
|
|
|
dev_err(&pdev->dev, "invalid reset-gpios property in node\n");
|
|
|
|
|
return PTR_ERR(rk_pcie->rst_gpio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device_property_read_u32(&pdev->dev, "rockchip,perst-inactive-ms",
|
|
|
|
|
&rk_pcie->perst_inactive_ms))
|
|
|
|
|
rk_pcie->perst_inactive_ms = 200;
|
|
|
|
|
|
|
|
|
|
rk_pcie->prsnt_gpio = devm_gpiod_get_optional(&pdev->dev, "prsnt", GPIOD_IN);
|
|
|
|
|
if (IS_ERR_OR_NULL(rk_pcie->prsnt_gpio))
|
|
|
|
|
dev_info(&pdev->dev, "invalid prsnt-gpios property in node\n");
|
|
|
|
|
|
|
|
|
|
rk_pcie->clk_cnt = devm_clk_bulk_get_all(&pdev->dev, &rk_pcie->clks);
|
|
|
|
|
if (rk_pcie->clk_cnt < 1)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
rk_pcie->rsts = devm_reset_control_array_get_exclusive(&pdev->dev);
|
|
|
|
|
if (IS_ERR(rk_pcie->rsts)) {
|
|
|
|
|
dev_err(&pdev->dev, "failed to get reset lines\n");
|
|
|
|
|
return PTR_ERR(rk_pcie->rsts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device_property_read_bool(&pdev->dev, "rockchip,bifurcation"))
|
|
|
|
|
rk_pcie->bifurcation = true;
|
|
|
|
|
|
|
|
|
|
rk_pcie->supports_clkreq = device_property_read_bool(&pdev->dev, "supports-clkreq");
|
|
|
|
|
|
|
|
|
|
if (device_property_read_bool(&pdev->dev, "hotplug-gpios") ||
|
|
|
|
|
device_property_read_bool(&pdev->dev, "hotplug-gpio")) {
|
|
|
|
|
rk_pcie->slot_pluggable = true;
|
|
|
|
|
dev_info(&pdev->dev, "support hotplug-gpios!\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip waiting for training to pass in system PM routine */
|
|
|
|
|
if (device_property_read_bool(&pdev->dev, "rockchip,skip-scan-in-resume"))
|
|
|
|
|
rk_pcie->skip_scan_in_resume = true;
|
|
|
|
|
|
|
|
|
|
/* Force into loopback master mode */
|
|
|
|
|
if (device_property_read_bool(&pdev->dev, "rockchip,lpbk-master")) {
|
|
|
|
|
rk_pcie->is_lpbk = true;
|
|
|
|
|
rk_pcie->is_signal_test = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Force into compliance mode
|
|
|
|
|
* comp_prst is a two dimensional array of which the first element
|
|
|
|
|
* stands for speed mode, and the second one is preset value encoding:
|
|
|
|
|
* [0] 0->SMA tool control the signal switch, 1/2/3 is for manual Gen setting
|
|
|
|
|
* [1] transmitter setting for manual Gen setting, valid only if [0] isn't zero.
|
|
|
|
|
*/
|
|
|
|
|
if (!device_property_read_u32_array(&pdev->dev, "rockchip,compliance-mode",
|
|
|
|
|
rk_pcie->comp_prst, 2)) {
|
|
|
|
|
WARN_ON_ONCE(rk_pcie->comp_prst[0] > 3 || rk_pcie->comp_prst[1] > 10);
|
|
|
|
|
if (!rk_pcie->comp_prst[0])
|
|
|
|
|
dev_info(&pdev->dev, "Auto compliance mode for SMA tool.\n");
|
|
|
|
|
else
|
|
|
|
|
dev_info(&pdev->dev, "compliance mode for soldered board Gen%d, P%d.\n",
|
|
|
|
|
rk_pcie->comp_prst[0], rk_pcie->comp_prst[1]);
|
|
|
|
|
|
|
|
|
|
rk_pcie->is_comp = true;
|
|
|
|
|
rk_pcie->is_signal_test = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retry_regulator:
|
|
|
|
|
rk_pcie->vpcie3v3 = devm_regulator_get_optional(&pdev->dev, "vpcie3v3");
|
|
|
|
|
if (IS_ERR(rk_pcie->vpcie3v3)) {
|
|
|
|
|
if (PTR_ERR(rk_pcie->vpcie3v3) != -ENODEV) {
|
|
|
|
|
if (IS_ENABLED(CONFIG_PCIE_RK_THREADED_INIT)) {
|
|
|
|
|
/* Deferred but in threaded context for most 10s */
|
|
|
|
|
msleep(20);
|
|
|
|
|
if (++val < 500)
|
|
|
|
|
goto retry_regulator;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PTR_ERR(rk_pcie->vpcie3v3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_info(&pdev->dev, "no vpcie3v3 regulator found\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_phy_init(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
|
|
|
|
|
rk_pcie->phy = devm_phy_optional_get(dev, "pcie-phy");
|
|
|
|
|
if (IS_ERR(rk_pcie->phy)) {
|
|
|
|
|
if (PTR_ERR(rk_pcie->phy) != -EPROBE_DEFER)
|
|
|
|
|
dev_info(dev, "missing phy\n");
|
|
|
|
|
return PTR_ERR(rk_pcie->phy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = phy_set_mode_ext(rk_pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "fail to set phy to rc mode, err %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rk_pcie->bifurcation)
|
|
|
|
|
phy_set_mode_ext(rk_pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_BIFURCATION);
|
|
|
|
|
|
|
|
|
|
ret = phy_init(rk_pcie->phy);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
dev_err(dev, "fail to init phy, err %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
phy_power_on(rk_pcie->phy);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void rk_pcie_hot_rst_work(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
struct rk_pcie *rk_pcie = container_of(work, struct rk_pcie, hot_rst_work);
|
|
|
|
|
@@ -893,36 +979,6 @@ static int rk_pcie_init_irq_domain(struct rk_pcie *rockchip)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_enable_power(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
|
|
|
|
|
if (IS_ERR(rk_pcie->vpcie3v3))
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = regulator_enable(rk_pcie->vpcie3v3);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(dev, "fail to enable vpcie3v3 regulator\n");
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_disable_power(struct rk_pcie *rk_pcie)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
|
|
|
|
|
if (IS_ERR(rk_pcie->vpcie3v3))
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = regulator_disable(rk_pcie->vpcie3v3);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(dev, "fail to disable vpcie3v3 regulator\n");
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define RAS_DES_EVENT(ss, v) \
|
|
|
|
|
do { \
|
|
|
|
|
dw_pcie_writel_dbi(pcie->pci, cap_base + 8, v); \
|
|
|
|
|
@@ -1061,6 +1117,9 @@ static int rockchip_pcie_debugfs_init(struct rk_pcie *pcie)
|
|
|
|
|
{
|
|
|
|
|
struct dentry *file;
|
|
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_DEBUG_FS) || !pcie->have_rasdes)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
pcie->debugfs = debugfs_create_dir(dev_name(pcie->pci->dev), NULL);
|
|
|
|
|
if (!pcie->debugfs)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
@@ -1115,6 +1174,50 @@ static const struct gpio_hotplug_slot_plat_ops rk_pcie_gpio_hp_plat_ops = {
|
|
|
|
|
.disable = rk_pcie_slot_disable,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_init_irq_and_wq(struct rk_pcie *rk_pcie, struct platform_device *pdev)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = rk_pcie->pci->dev;
|
|
|
|
|
int ret, irq;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Misc interrupts was masked by default. However, they will be
|
|
|
|
|
* unmasked by FW before jumpping into kernel. Mask all misc interrupts,
|
|
|
|
|
* as we don't need to ack them before registering irq. And they will be
|
|
|
|
|
* unmasked later.
|
|
|
|
|
*/
|
|
|
|
|
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xffffffff);
|
|
|
|
|
|
|
|
|
|
ret = rk_pcie_request_sys_irq(rk_pcie, pdev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "pcie irq init failed\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Legacy interrupt is optional */
|
|
|
|
|
ret = rk_pcie_init_irq_domain(rk_pcie);
|
|
|
|
|
if (!ret) {
|
|
|
|
|
irq = platform_get_irq_byname(pdev, "legacy");
|
|
|
|
|
if (irq >= 0) {
|
|
|
|
|
irq_set_chained_handler_and_data(irq, rk_pcie_legacy_int_handler,
|
|
|
|
|
rk_pcie);
|
|
|
|
|
/* Unmask all legacy interrupt from INTA~INTD */
|
|
|
|
|
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY,
|
|
|
|
|
UNMASK_ALL_LEGACY_INT);
|
|
|
|
|
} else {
|
|
|
|
|
dev_info(dev, "missing legacy IRQ resource\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rk_pcie->hot_rst_wq = create_singlethread_workqueue("rk_pcie_hot_rst_wq");
|
|
|
|
|
if (!rk_pcie->hot_rst_wq) {
|
|
|
|
|
dev_err(dev, "failed to create hot_rst workqueue\n");
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
INIT_WORK(&rk_pcie->hot_rst_work, rk_pcie_hot_rst_work);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rk_pcie_really_probe(void *p)
|
|
|
|
|
{
|
|
|
|
|
struct platform_device *pdev = p;
|
|
|
|
|
@@ -1125,8 +1228,8 @@ static int rk_pcie_really_probe(void *p)
|
|
|
|
|
const struct of_device_id *match;
|
|
|
|
|
const struct rk_pcie_of_data *data;
|
|
|
|
|
u32 val = 0;
|
|
|
|
|
int irq;
|
|
|
|
|
|
|
|
|
|
/* 1. resource initialization */
|
|
|
|
|
match = of_match_device(rk_pcie_of_match, dev);
|
|
|
|
|
if (!match) {
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
@@ -1147,22 +1250,21 @@ static int rk_pcie_really_probe(void *p)
|
|
|
|
|
goto release_driver;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 2. variables assignment */
|
|
|
|
|
rk_pcie->pci = pci;
|
|
|
|
|
rk_pcie->msi_vector_num = data ? data->msi_vector_num : 0;
|
|
|
|
|
pci->dev = dev;
|
|
|
|
|
pci->ops = &dw_pcie_ops;
|
|
|
|
|
platform_set_drvdata(pdev, rk_pcie);
|
|
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
|
rk_pcie->msi_vector_num = data->msi_vector_num;
|
|
|
|
|
rk_pcie->pci = pci;
|
|
|
|
|
|
|
|
|
|
if (device_property_read_bool(dev, "rockchip,bifurcation"))
|
|
|
|
|
rk_pcie->bifurcation = true;
|
|
|
|
|
|
|
|
|
|
/* 3. firmware resource */
|
|
|
|
|
ret = rk_pcie_resource_get(pdev, rk_pcie);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "resource init failed\n");
|
|
|
|
|
dev_err_probe(dev, ret, "resource init failed\n");
|
|
|
|
|
goto release_driver;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 4. hardware io settings */
|
|
|
|
|
if (!IS_ERR_OR_NULL(rk_pcie->prsnt_gpio)) {
|
|
|
|
|
if (!gpiod_get_value(rk_pcie->prsnt_gpio)) {
|
|
|
|
|
dev_info(dev, "device isn't present\n");
|
|
|
|
|
@@ -1171,137 +1273,57 @@ static int rk_pcie_really_probe(void *p)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rk_pcie->supports_clkreq = device_property_read_bool(dev, "supports-clkreq");
|
|
|
|
|
|
|
|
|
|
if (device_property_read_bool(dev, "hotplug-gpios") ||
|
|
|
|
|
device_property_read_bool(dev, "hotplug-gpio")) {
|
|
|
|
|
rk_pcie->slot_pluggable = true;
|
|
|
|
|
dev_info(dev, "support hotplug-gpios!\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retry_regulator:
|
|
|
|
|
/* DON'T MOVE ME: must be enable before phy init */
|
|
|
|
|
rk_pcie->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3");
|
|
|
|
|
if (IS_ERR(rk_pcie->vpcie3v3)) {
|
|
|
|
|
if (PTR_ERR(rk_pcie->vpcie3v3) != -ENODEV) {
|
|
|
|
|
if (IS_ENABLED(CONFIG_PCIE_RK_THREADED_INIT)) {
|
|
|
|
|
/* Deferred but in threaded context for most 10s */
|
|
|
|
|
msleep(20);
|
|
|
|
|
if (++val < 500)
|
|
|
|
|
goto retry_regulator;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = PTR_ERR(rk_pcie->vpcie3v3);
|
|
|
|
|
goto release_driver;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_info(dev, "no vpcie3v3 regulator found\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = rk_pcie_enable_power(rk_pcie);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto release_driver;
|
|
|
|
|
|
|
|
|
|
ret = rk_pcie_phy_init(rk_pcie);
|
|
|
|
|
reset_control_deassert(rk_pcie->rsts);
|
|
|
|
|
|
|
|
|
|
ret = clk_bulk_prepare_enable(rk_pcie->clk_cnt, rk_pcie->clks);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "phy init failed\n");
|
|
|
|
|
dev_err_probe(dev, ret, "clock init failed\n");
|
|
|
|
|
goto disable_vpcie3v3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rk_pcie->rsts = devm_reset_control_array_get_exclusive(dev);
|
|
|
|
|
if (IS_ERR(rk_pcie->rsts)) {
|
|
|
|
|
ret = PTR_ERR(rk_pcie->rsts);
|
|
|
|
|
dev_err(dev, "failed to get reset lines\n");
|
|
|
|
|
goto disable_phy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reset_control_deassert(rk_pcie->rsts);
|
|
|
|
|
|
|
|
|
|
ret = rk_pcie_clk_init(rk_pcie);
|
|
|
|
|
ret = rk_pcie_phy_init(rk_pcie);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "clock init failed\n");
|
|
|
|
|
goto disable_phy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Misc interrupts was masked by default. However, they will be
|
|
|
|
|
* unmasked by FW before jumpping into kernel. Mask all misc interrupts,
|
|
|
|
|
* as we don't need to ack them before registering irq. And they will be
|
|
|
|
|
* unmasked later.
|
|
|
|
|
*/
|
|
|
|
|
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xffffffff);
|
|
|
|
|
|
|
|
|
|
ret = rk_pcie_request_sys_irq(rk_pcie, pdev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "pcie irq init failed\n");
|
|
|
|
|
dev_err_probe(dev, ret, "phy init failed\n");
|
|
|
|
|
goto disable_clk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
platform_set_drvdata(pdev, rk_pcie);
|
|
|
|
|
/* 5. signal test and capability settings */
|
|
|
|
|
if (rk_pcie->is_lpbk) {
|
|
|
|
|
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
|
|
|
|
val |= PORT_LINK_LPBK_ENABLE;
|
|
|
|
|
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rk_pcie->is_comp && rk_pcie->comp_prst[0]) {
|
|
|
|
|
val = dw_pcie_readl_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS);
|
|
|
|
|
val |= BIT(4) | rk_pcie->comp_prst[0] | (rk_pcie->comp_prst[1] << 12);
|
|
|
|
|
dw_pcie_writel_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Enable RASDES Error event by default */
|
|
|
|
|
val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_VNDR);
|
|
|
|
|
if (!val) {
|
|
|
|
|
dev_err(pci->dev, "Unable to find RASDES CAP!\n");
|
|
|
|
|
} else {
|
|
|
|
|
dw_pcie_writel_dbi(pci, val + 8, 0x1c);
|
|
|
|
|
dw_pcie_writel_dbi(pci, val + 8, 0x3);
|
|
|
|
|
rk_pcie->have_rasdes = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 6. software process */
|
|
|
|
|
ret = rk_pcie_init_irq_and_wq(rk_pcie, pdev);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto disable_phy;
|
|
|
|
|
|
|
|
|
|
dw_pcie_dbi_ro_wr_en(pci);
|
|
|
|
|
|
|
|
|
|
rk_pcie_fast_link_setup(rk_pcie);
|
|
|
|
|
|
|
|
|
|
/* Legacy interrupt is optional */
|
|
|
|
|
ret = rk_pcie_init_irq_domain(rk_pcie);
|
|
|
|
|
if (!ret) {
|
|
|
|
|
irq = platform_get_irq_byname(pdev, "legacy");
|
|
|
|
|
if (irq >= 0) {
|
|
|
|
|
irq_set_chained_handler_and_data(irq, rk_pcie_legacy_int_handler,
|
|
|
|
|
rk_pcie);
|
|
|
|
|
/* Unmask all legacy interrupt from INTA~INTD */
|
|
|
|
|
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY,
|
|
|
|
|
UNMASK_ALL_LEGACY_INT);
|
|
|
|
|
} else {
|
|
|
|
|
dev_info(dev, "missing legacy IRQ resource\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set PCIe RC mode */
|
|
|
|
|
rk_pcie_set_mode(rk_pcie);
|
|
|
|
|
|
|
|
|
|
/* Force into loopback master mode */
|
|
|
|
|
if (device_property_read_bool(dev, "rockchip,lpbk-master")) {
|
|
|
|
|
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
|
|
|
|
val |= PORT_LINK_LPBK_ENABLE;
|
|
|
|
|
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
|
|
|
|
rk_pcie->is_signal_test = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Force into compliance mode
|
|
|
|
|
* comp_prst is a two dimensional array of which the first element
|
|
|
|
|
* stands for speed mode, and the second one is preset value encoding:
|
|
|
|
|
* [0] 0->SMA tool control the signal switch, 1/2/3 is for manual Gen setting
|
|
|
|
|
* [1] transmitter setting for manual Gen setting, valid only if [0] isn't zero.
|
|
|
|
|
*/
|
|
|
|
|
if (!device_property_read_u32_array(dev, "rockchip,compliance-mode",
|
|
|
|
|
rk_pcie->comp_prst, 2)) {
|
|
|
|
|
BUG_ON(rk_pcie->comp_prst[0] > 3 || rk_pcie->comp_prst[1] > 10);
|
|
|
|
|
if (!rk_pcie->comp_prst[0]) {
|
|
|
|
|
dev_info(dev, "Auto compliance mode for SMA tool.\n");
|
|
|
|
|
} else {
|
|
|
|
|
dev_info(dev, "compliance mode for soldered board Gen%d, P%d.\n",
|
|
|
|
|
rk_pcie->comp_prst[0], rk_pcie->comp_prst[1]);
|
|
|
|
|
val = dw_pcie_readl_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS);
|
|
|
|
|
val |= BIT(4) | rk_pcie->comp_prst[0] | (rk_pcie->comp_prst[1] << 12);
|
|
|
|
|
dw_pcie_writel_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS, val);
|
|
|
|
|
}
|
|
|
|
|
rk_pcie->is_signal_test = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip waiting for training to pass in system PM routine */
|
|
|
|
|
if (device_property_read_bool(dev, "rockchip,skip-scan-in-resume"))
|
|
|
|
|
rk_pcie->skip_scan_in_resume = true;
|
|
|
|
|
|
|
|
|
|
rk_pcie->hot_rst_wq = create_singlethread_workqueue("rk_pcie_hot_rst_wq");
|
|
|
|
|
if (!rk_pcie->hot_rst_wq) {
|
|
|
|
|
dev_err(dev, "failed to create hot_rst workqueue\n");
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
|
goto remove_irq_domain;
|
|
|
|
|
}
|
|
|
|
|
INIT_WORK(&rk_pcie->hot_rst_work, rk_pcie_hot_rst_work);
|
|
|
|
|
rk_pcie_set_rc_mode(rk_pcie);
|
|
|
|
|
|
|
|
|
|
ret = rk_add_pcie_port(rk_pcie, pdev);
|
|
|
|
|
|
|
|
|
|
@@ -1309,7 +1331,7 @@ retry_regulator:
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (ret && !rk_pcie->slot_pluggable)
|
|
|
|
|
goto remove_rst_wq;
|
|
|
|
|
goto deinit_irq_and_wq;
|
|
|
|
|
|
|
|
|
|
if (rk_pcie->slot_pluggable) {
|
|
|
|
|
rk_pcie->hp_slot.plat_ops = &rk_pcie_gpio_hp_plat_ops;
|
|
|
|
|
@@ -1327,50 +1349,31 @@ retry_regulator:
|
|
|
|
|
|
|
|
|
|
ret = rk_pcie_init_dma_trx(rk_pcie);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "failed to add dma extension\n");
|
|
|
|
|
goto remove_rst_wq;
|
|
|
|
|
dev_err_probe(dev, ret, "failed to add dma extension\n");
|
|
|
|
|
goto deinit_irq_and_wq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rk_pcie->dma_obj) {
|
|
|
|
|
rk_pcie->dma_obj->start_dma_func = rk_pcie_start_dma_dwc;
|
|
|
|
|
rk_pcie->dma_obj->config_dma_func = rk_pcie_config_dma_dwc;
|
|
|
|
|
}
|
|
|
|
|
ret = rockchip_pcie_debugfs_init(rk_pcie);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
dev_err_probe(dev, ret, "failed to setup debugfs\n");
|
|
|
|
|
|
|
|
|
|
dw_pcie_dbi_ro_wr_dis(pci);
|
|
|
|
|
|
|
|
|
|
/* 7. framework misc settings */
|
|
|
|
|
device_init_wakeup(dev, true);
|
|
|
|
|
|
|
|
|
|
/* Enable async system PM for multiports SoC */
|
|
|
|
|
device_enable_async_suspend(dev);
|
|
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
|
|
|
|
|
ret = rockchip_pcie_debugfs_init(rk_pcie);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
dev_err(dev, "failed to setup debugfs: %d\n", ret);
|
|
|
|
|
|
|
|
|
|
/* Enable RASDES Error event by default */
|
|
|
|
|
val = dw_pcie_find_ext_capability(rk_pcie->pci, PCI_EXT_CAP_ID_VNDR);
|
|
|
|
|
if (!val) {
|
|
|
|
|
dev_err(dev, "Not able to find RASDES CAP!\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dw_pcie_writel_dbi(rk_pcie->pci, val + 8, 0x1c);
|
|
|
|
|
dw_pcie_writel_dbi(rk_pcie->pci, val + 8, 0x3);
|
|
|
|
|
}
|
|
|
|
|
device_enable_async_suspend(dev); /* Enable async system PM for multiports SoC */
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
remove_rst_wq:
|
|
|
|
|
deinit_irq_and_wq:
|
|
|
|
|
destroy_workqueue(rk_pcie->hot_rst_wq);
|
|
|
|
|
remove_irq_domain:
|
|
|
|
|
if (rk_pcie->irq_domain)
|
|
|
|
|
irq_domain_remove(rk_pcie->irq_domain);
|
|
|
|
|
disable_clk:
|
|
|
|
|
clk_bulk_disable_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
|
|
|
|
|
disable_phy:
|
|
|
|
|
phy_power_off(rk_pcie->phy);
|
|
|
|
|
phy_exit(rk_pcie->phy);
|
|
|
|
|
disable_clk:
|
|
|
|
|
clk_bulk_disable_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
|
|
|
|
|
disable_vpcie3v3:
|
|
|
|
|
rk_pcie_disable_power(rk_pcie);
|
|
|
|
|
release_driver:
|
|
|
|
|
@@ -1386,10 +1389,8 @@ static int rk_pcie_probe(struct platform_device *pdev)
|
|
|
|
|
struct task_struct *tsk;
|
|
|
|
|
|
|
|
|
|
tsk = kthread_run(rk_pcie_really_probe, pdev, "rk-pcie");
|
|
|
|
|
if (IS_ERR(tsk)) {
|
|
|
|
|
dev_err(&pdev->dev, "start rk-pcie thread failed\n");
|
|
|
|
|
return PTR_ERR(tsk);
|
|
|
|
|
}
|
|
|
|
|
if (IS_ERR(tsk))
|
|
|
|
|
return dev_err_probe(&pdev->dev, PTR_ERR(tsk), "start rk-pcie thread failed\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -1601,8 +1602,7 @@ static int __maybe_unused rockchip_dw_pcie_resume(struct device *dev)
|
|
|
|
|
|
|
|
|
|
rk_pcie_fast_link_setup(rk_pcie);
|
|
|
|
|
|
|
|
|
|
/* Set PCIe RC mode */
|
|
|
|
|
rk_pcie_set_mode(rk_pcie);
|
|
|
|
|
rk_pcie_set_rc_mode(rk_pcie);
|
|
|
|
|
|
|
|
|
|
dw_pcie_setup_rc(&rk_pcie->pci->pp);
|
|
|
|
|
|
|
|
|
|
|