pcie: enable pcie pm.

PD#147022: pcie: enable pcie pm.

Change-Id: Ide75af5cbe2bb840887e36a174cbfec33691534c
Signed-off-by: Yue Wang <yue.wang@amlogic.com>
This commit is contained in:
Yue Wang
2017-08-23 17:59:56 +08:00
committed by Jianxin Pan
parent 166baac573
commit b099141ced
12 changed files with 298 additions and 24 deletions

View File

@@ -245,6 +245,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {
@@ -313,10 +315,12 @@
num-lanes = <1>;
pcie-num = <1>;
clocks = <&clkc CLKID_PCIE_PLL
clocks = <&clkc CLKID_USB_GENERAL
&clkc CLKID_PCIE_PLL
&clkc CLKID_PCIE_A
&clkc CLKID_PCIE_CML_EN0>;
clock-names = "pcie_refpll",
clock-names = "pcie_general",
"pcie_refpll",
"pcie",
"port";
/*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/
@@ -346,10 +350,12 @@
num-lanes = <1>;
pcie-num = <2>;
clocks = <&clkc CLKID_PCIE_PLL
clocks = <&clkc CLKID_USB_GENERAL
&clkc CLKID_PCIE_PLL
&clkc CLKID_PCIE_B
&clkc CLKID_PCIE_CML_EN1>;
clock-names = "pcie_refpll",
clock-names = "pcie_general",
"pcie_refpll",
"pcie",
"port";
/*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/

View File

@@ -227,6 +227,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {

View File

@@ -251,6 +251,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {
@@ -320,10 +322,12 @@
num-lanes = <1>;
pcie-num = <1>;
clocks = <&clkc CLKID_PCIE_PLL
clocks = <&clkc CLKID_USB_GENERAL
&clkc CLKID_PCIE_PLL
&clkc CLKID_PCIE_A
&clkc CLKID_PCIE_CML_EN0>;
clock-names = "pcie_refpll",
clock-names = "pcie_general",
"pcie_refpll",
"pcie",
"port";
/*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/
@@ -353,10 +357,12 @@
num-lanes = <1>;
pcie-num = <2>;
clocks = <&clkc CLKID_PCIE_PLL
clocks = <&clkc CLKID_USB_GENERAL
&clkc CLKID_PCIE_PLL
&clkc CLKID_PCIE_B
&clkc CLKID_PCIE_CML_EN1>;
clock-names = "pcie_refpll",
clock-names = "pcie_general",
"pcie_refpll",
"pcie",
"port";
/*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/

View File

@@ -251,6 +251,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {
@@ -320,10 +322,12 @@
num-lanes = <1>;
pcie-num = <1>;
clocks = <&clkc CLKID_PCIE_PLL
clocks = <&clkc CLKID_USB_GENERAL
&clkc CLKID_PCIE_PLL
&clkc CLKID_PCIE_A
&clkc CLKID_PCIE_CML_EN0>;
clock-names = "pcie_refpll",
clock-names = "pcie_general",
"pcie_refpll",
"pcie",
"port";
/*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/
@@ -353,10 +357,12 @@
num-lanes = <1>;
pcie-num = <2>;
clocks = <&clkc CLKID_PCIE_PLL
clocks = <&clkc CLKID_USB_GENERAL
&clkc CLKID_PCIE_PLL
&clkc CLKID_PCIE_B
&clkc CLKID_PCIE_CML_EN1>;
clock-names = "pcie_refpll",
clock-names = "pcie_general",
"pcie_refpll",
"pcie",
"port";
/*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/

View File

@@ -227,6 +227,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {

View File

@@ -225,6 +225,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {

View File

@@ -227,6 +227,8 @@
usb-phy = <&usb2_phy>, <&usb3_phy>;
cpu-type = "gxl";
clock-src = "usb3.0";
clocks = <&clkc CLKID_USB_GENERAL>;
clock-names = "dwc_general";
};
usb2_phy: usb2phy@ffe09000 {

View File

@@ -311,8 +311,6 @@ static int meson_axg_pll_enable(struct clk_hw *hw)
void *cntlbase = pll->base + p->reg_off;
if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) {
clk_prepare_enable(clks[CLKID_MIPI_ENABLE_GATE]);
clk_prepare_enable(clks[CLKID_MIPI_BANDGAP_GATE]);
if (readl(cntlbase + (u64)(6*4)) == AXG_PCIE_PLL_CNTL6)
first_set = 0;
} else if (!strcmp(clk_hw_get_name(hw), "hifi_pll")) {
@@ -336,6 +334,11 @@ static int meson_axg_pll_enable(struct clk_hw *hw)
if (pll->lock)
spin_unlock_irqrestore(pll->lock, flags);
/*pcie pll: mipi enable and bandgap share with mipi clk */
if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) {
clk_prepare_enable(clks[CLKID_MIPI_ENABLE_GATE]);
clk_prepare_enable(clks[CLKID_MIPI_BANDGAP_GATE]);
}
ret = meson_axg_pll_set_rate(hw, rate, clk_get_rate(parent));
@@ -357,14 +360,14 @@ static void meson_axg_pll_disable(struct clk_hw *hw)
writel(readl(pll->base + p->reg_off) & (~MESON_PLL_ENABLE),
pll->base + p->reg_off);
if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) {
clk_disable_unprepare(clks[CLKID_MIPI_ENABLE_GATE]);
clk_disable_unprepare(clks[CLKID_MIPI_BANDGAP_GATE]);
};
if (pll->lock)
spin_unlock_irqrestore(pll->lock, flags);
}
/*pcie pll: mipi enable and bandgap share with mipi clk */
if (!strcmp(clk_hw_get_name(hw), "pcie_pll")) {
clk_disable_unprepare(clks[CLKID_MIPI_ENABLE_GATE]);
clk_disable_unprepare(clks[CLKID_MIPI_BANDGAP_GATE]);
};
}
const struct clk_ops meson_axg_pll_ops = {

View File

@@ -42,9 +42,12 @@ struct amlogic_pcie {
struct clk *clk;
struct clk *bus_clk;
struct clk *port_clk;
struct clk *general_clk;
int pcie_num;
int gpio_type;
u32 port_num;
u32 pm_enable;
u32 device_attch;
};
#define to_amlogic_pcie(x) container_of(x, struct amlogic_pcie, pp)
@@ -472,6 +475,10 @@ static int amlogic_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
u32 *val)
{
int ret;
struct amlogic_pcie *amlogic_pcie = to_amlogic_pcie(pp);
if (amlogic_pcie->device_attch == 0)
return 0;
/* the device class is not reported correctly from the register */
if (where == PCI_CLASS_REVISION) {
@@ -490,6 +497,10 @@ static int amlogic_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
u32 val)
{
int ret;
struct amlogic_pcie *amlogic_pcie = to_amlogic_pcie(pp);
if (amlogic_pcie->device_attch == 0)
return 0;
ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val);
return ret;
@@ -551,8 +562,17 @@ int amlogic_pcie_link_up(struct pcie_port *pp)
static void amlogic_pcie_host_init(struct pcie_port *pp)
{
struct amlogic_pcie *amlogic_pcie = to_amlogic_pcie(pp);
int ret;
ret = amlogic_pcie_establish_link(amlogic_pcie);
if (ret)
if (amlogic_pcie->phy->device_attch == 0)
return;
amlogic_pcie->phy->device_attch = 1;
if (!ret)
amlogic_pcie->device_attch = 1;
amlogic_pcie_establish_link(amlogic_pcie);
amlogic_pcie_enable_interrupts(amlogic_pcie);
}
@@ -611,6 +631,21 @@ static int __init amlogic_add_pcie_port(struct amlogic_pcie *amlogic_pcie,
return ret;
}
if (amlogic_pcie->device_attch == 0) {
dev_err(pp->dev, "link timeout, disable PCIE PLL\n");
clk_disable_unprepare(amlogic_pcie->port_clk);
clk_disable_unprepare(amlogic_pcie->general_clk);
clk_disable_unprepare(amlogic_pcie->bus_clk);
clk_disable_unprepare(amlogic_pcie->clk);
if (amlogic_pcie->pcie_num == 2) {
if (amlogic_pcie->phy->device_attch == 0) {
dev_err(pp->dev, "power down pcie phy\n");
writel(0x1d, pcie_aml_regs.pcie_phy_r[0]);
amlogic_pcie->phy->power_state = 0;
}
}
}
return 0;
}
@@ -634,6 +669,7 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev)
int j = 0;
u32 val = 0;
static u32 port_num;
u32 pm_enable = 1;
dev_info(&pdev->dev, "amlogic_pcie_probe!\n");
@@ -641,6 +677,7 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev)
if (!amlogic_pcie)
return -ENOMEM;
amlogic_pcie->device_attch = 0;
pp = &amlogic_pcie->pp;
pp->dev = dev;
port_num++;
@@ -662,6 +699,12 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev)
amlogic_pcie->pcie_num = pcie_num;
ret = of_property_read_u32(np, "pm-enable", &pm_enable);
if (ret)
amlogic_pcie->pm_enable = 1;
else
amlogic_pcie->pm_enable = pm_enable;
ret = of_property_read_u32(np, "num-lanes", &num_lanes);
if (ret)
pp->lanes = 0;
@@ -744,16 +787,27 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev)
mdelay(10);
}
amlogic_pcie->general_clk = devm_clk_get(dev, "pcie_general");
if (IS_ERR(amlogic_pcie->general_clk)) {
dev_err(dev, "Failed to get pcie general clock\n");
ret = PTR_ERR(amlogic_pcie->general_clk);
goto fail_bus_clk;
}
ret = clk_prepare_enable(amlogic_pcie->general_clk);
if (ret)
goto fail_bus_clk;
amlogic_pcie->clk = devm_clk_get(dev, "pcie");
if (IS_ERR(amlogic_pcie->clk)) {
dev_err(dev, "Failed to get pcie rc clock\n");
ret = PTR_ERR(amlogic_pcie->clk);
goto fail_bus_clk;
goto fail_general_clk;
}
ret = clk_prepare_enable(amlogic_pcie->clk);
if (ret)
goto fail_bus_clk;
goto fail_general_clk;
/*RESET0[1,2] = 1*/
if (amlogic_pcie->pcie_num == 1) {
@@ -808,6 +862,8 @@ fail_port_clk:
clk_disable_unprepare(amlogic_pcie->port_clk);
fail_clk:
clk_disable_unprepare(amlogic_pcie->clk);
fail_general_clk:
clk_disable_unprepare(amlogic_pcie->general_clk);
fail_bus_clk:
clk_disable_unprepare(amlogic_pcie->bus_clk);
fail_pcie:
@@ -819,15 +875,174 @@ static int __exit amlogic_pcie_remove(struct platform_device *pdev)
{
struct amlogic_pcie *amlogic_pcie = platform_get_drvdata(pdev);
if (amlogic_pcie->phy->power_state == 0) {
dev_info(&pdev->dev, "PCIE phy power off, no remove\n");
return 0;
}
device_remove_file(&pdev->dev, &dev_attr_phywrite);
device_remove_file(&pdev->dev, &dev_attr_phyread);
clk_disable_unprepare(amlogic_pcie->bus_clk);
clk_disable_unprepare(amlogic_pcie->port_clk);
clk_disable_unprepare(amlogic_pcie->clk);
clk_disable_unprepare(amlogic_pcie->general_clk);
clk_disable_unprepare(amlogic_pcie->bus_clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int amlogic_pcie_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct amlogic_pcie *amlogic_pcie = platform_get_drvdata(pdev);
struct pcie_port *pp = &amlogic_pcie->pp;
u32 val;
if (!amlogic_pcie->pm_enable) {
dev_info(dev, "don't suspend amlogic pcie\n");
return 0;
}
if (amlogic_pcie->device_attch == 0) {
dev_info(dev, "controller power off, no suspend\n");
return 0;
}
dev_info(dev, "amlogic_pcie_suspend\n");
/* clear MSE */
val = dw_pcie_readl_rc(pp, PCI_COMMAND);
val &= ~PCI_COMMAND_MEMORY;
dw_pcie_writel_rc(pp, PCI_COMMAND, val);
return 0;
}
static int amlogic_pcie_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct amlogic_pcie *amlogic_pcie = platform_get_drvdata(pdev);
struct pcie_port *pp = &amlogic_pcie->pp;
u32 val;
if (!amlogic_pcie->pm_enable) {
dev_info(dev, "don't resume amlogic pcie\n");
return 0;
}
if (amlogic_pcie->device_attch == 0) {
dev_info(dev, "controller power off, no resume\n");
return 0;
}
dev_info(dev, "amlogic_pcie_resume\n");
/* set MSE */
val = dw_pcie_readl_rc(pp, PCI_COMMAND);
val |= PCI_COMMAND_MEMORY;
dw_pcie_writel_rc(pp, PCI_COMMAND, val);
return 0;
}
static int amlogic_pcie_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct amlogic_pcie *amlogic_pcie = platform_get_drvdata(pdev);
if (!amlogic_pcie->pm_enable) {
dev_info(dev, "don't noirq suspend amlogic pcie\n");
return 0;
}
if (amlogic_pcie->phy->device_attch == 0) {
dev_info(dev, "PCIE phy power off, no suspend noirq\n");
return 0;
}
if (amlogic_pcie->device_attch == 0) {
dev_info(dev, "controller power off, no suspend noirq\n");
if (amlogic_pcie->pcie_num == 1) {
writel(0x1d, pcie_aml_regs.pcie_phy_r[0]);
amlogic_pcie->phy->power_state = 0;
}
return 0;
}
dev_info(dev, "amlogic_pcie_suspend_noirq\n");
clk_disable_unprepare(amlogic_pcie->port_clk);
clk_disable_unprepare(amlogic_pcie->clk);
clk_disable_unprepare(amlogic_pcie->general_clk);
clk_disable_unprepare(amlogic_pcie->bus_clk);
amlogic_pcie->phy->reset_state = 0;
if (amlogic_pcie->pcie_num == 1) {
writel(0x1d, pcie_aml_regs.pcie_phy_r[0]);
amlogic_pcie->phy->power_state = 0;
}
return 0;
}
static int amlogic_pcie_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct amlogic_pcie *amlogic_pcie = platform_get_drvdata(pdev);
unsigned long rate = 100000000;
if (!amlogic_pcie->pm_enable) {
dev_info(dev, "don't noirq resume amlogic pcie\n");
return 0;
}
if (amlogic_pcie->phy->device_attch == 0) {
dev_info(dev, "PCIE phy power off, no resume noirq\n");
return 0;
}
if (amlogic_pcie->pcie_num == 1) {
writel(0x1c, pcie_aml_regs.pcie_phy_r[0]);
amlogic_pcie->phy->power_state = 1;
udelay(500);
}
if (amlogic_pcie->device_attch == 0) {
dev_info(dev, "controller power off, no resume noirq\n");
return 0;
}
dev_info(dev, "amlogic_pcie_resume_noirq\n");
if (!amlogic_pcie->phy->reset_state)
clk_set_rate(amlogic_pcie->bus_clk, rate);
amlogic_pcie->phy->reset_state = 1;
clk_prepare_enable(amlogic_pcie->bus_clk);
clk_prepare_enable(amlogic_pcie->general_clk);
clk_prepare_enable(amlogic_pcie->clk);
clk_prepare_enable(amlogic_pcie->port_clk);
udelay(500);
return 0;
}
#else
#define amlogic_pcie_suspend NULL
#define amlogic_pcie_resume NULL
#define amlogic_pcie_suspend_noirq NULL
#define amlogic_pcie_resume_noirq NULL
#endif
static const struct dev_pm_ops amlogic_pcie_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(amlogic_pcie_suspend, amlogic_pcie_resume)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(amlogic_pcie_suspend_noirq,
amlogic_pcie_resume_noirq)
};
static const struct of_device_id amlogic_pcie_of_match[] = {
{ .compatible = "amlogic, amlogic-pcie", },
{},
@@ -838,6 +1053,7 @@ static struct platform_driver amlogic_pcie_driver = {
.driver = {
.name = "amlogic-pcie",
.of_match_table = amlogic_pcie_of_match,
.pm = &amlogic_pcie_pm_ops,
},
};

View File

@@ -33,7 +33,7 @@
#define PCIE_CFG_STATUS12 0x30
#define PCIE_CFG_STATUS17 0x44
#define WAIT_LINKUP_TIMEOUT 5000
#define WAIT_LINKUP_TIMEOUT 2000
enum pcie_data_rate {
PCIE_GEN1,
@@ -152,6 +152,7 @@ struct pcie_phy_aml_regs {
struct pcie_phy {
u32 power_state;
u32 device_attch;
u32 reset_state;
void __iomem *phy_base; /* DT 1st resource */
void __iomem *reset_base;/* DT 3nd resource */

View File

@@ -1056,6 +1056,14 @@ static int dwc3_probe(struct platform_device *pdev)
res->start += DWC3_GLOBALS_REGS_START;
#ifdef CONFIG_AMLOGIC_USB
dwc->general_clk = devm_clk_get(dev, "dwc_general");
if (IS_ERR(dwc->general_clk))
ret = PTR_ERR(dwc->general_clk);
else
clk_prepare_enable(dwc->general_clk);
#endif
/*
* Request memory region but exclude xHCI regs,
* since it will be requested by the xhci-plat driver.
@@ -1422,6 +1430,13 @@ static int dwc3_suspend(struct device *dev)
if (ret)
return ret;
#ifdef CONFIG_AMLOGIC_USB
if (IS_ERR(dwc->general_clk))
ret = PTR_ERR(dwc->general_clk);
else
clk_disable_unprepare(dwc->general_clk);
#endif
pinctrl_pm_select_sleep_state(dev);
return 0;
@@ -1434,6 +1449,13 @@ static int dwc3_resume(struct device *dev)
pinctrl_pm_select_default_state(dev);
#ifdef CONFIG_AMLOGIC_USB
if (IS_ERR(dwc->general_clk))
ret = PTR_ERR(dwc->general_clk);
else
clk_prepare_enable(dwc->general_clk);
#endif
ret = dwc3_resume_common(dwc);
if (ret)
return ret;

View File

@@ -33,6 +33,9 @@
#include <linux/ulpi/interface.h>
#include <linux/phy/phy.h>
#ifdef CONFIG_AMLOGIC_USB
#include <linux/clk.h>
#endif
#define DWC3_MSG_MAX 500
@@ -978,6 +981,9 @@ struct dwc3 {
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
#ifdef CONFIG_AMLOGIC_USB
struct clk *general_clk;
#endif
};
/* -------------------------------------------------------------------------- */