PCIe PHY uses an external pll instead of the internal pll used by SATA and USB3. So added support in pipe3 PHY to use external pll. Signed-off-by: Kishon Vijay Abraham I <kishon@xxxxxx> Reviewed-by: Roger Quadros <rogerq@xxxxxx> --- Documentation/devicetree/bindings/phy/ti-phy.txt | 11 ++- drivers/phy/phy-ti-pipe3.c | 103 +++++++++++++++++----- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index 9ce458f..b50e1c1 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -56,8 +56,8 @@ usb2phy@4a0ad080 { TI PIPE3 PHY Required properties: - - compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata". - "ti,omap-usb3" is deprecated. + - compatible: Should be "ti,phy-usb3", "ti,phy-pipe3-sata" or + "ti,phy-pipe3-pcie. "ti,omap-usb3" is deprecated. - reg : Address and length of the register set for the device. - reg-names: The names of the register addresses corresponding to the registers filled in "reg". @@ -69,10 +69,17 @@ Required properties: * "wkupclk" - wakeup clock. * "sysclk" - system clock. * "refclk" - reference clock. + * "dpll_ref" - external dpll ref clk + * "dpll_ref_m2" - external dpll ref clk + * "phy-div" - divider for apll + * "div-clk" - apll clock Optional properties: - ctrl-module : phandle of the control module used by PHY driver to power on the PHY. + - id: If there are multiple instance of the same type, in order to + differentiate between each instance "id" can be used (e.g., multi-lane PCIe + PHY). If "id" is not provided, it is set to default value of '1'. This is usually a subnode of ocp2scp to which it is connected. diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 5913676..6174f4b 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -80,7 +80,9 @@ struct ti_pipe3 { struct clk *wkupclk; struct clk *sys_clk; struct clk *refclk; + struct clk *div_clk; struct pipe3_dpll_map *dpll_map; + u8 id; }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -215,6 +217,9 @@ static int ti_pipe3_init(struct phy *x) u32 val; int ret = 0; + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) + return 0; + /* Bring it out of IDLE if it is IDLE */ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); if (val & PLL_IDLE) { @@ -238,8 +243,11 @@ static int ti_pipe3_exit(struct phy *x) u32 val; unsigned long timeout; - /* SATA DPLL can't be powered down due to Errata i783 */ - if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) + /* SATA DPLL can't be powered down due to Errata i783 and PCIe + * does not have internal DPLL + */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") || + of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) return 0; /* Put DPLL in IDLE mode */ @@ -286,32 +294,41 @@ static int ti_pipe3_probe(struct platform_device *pdev) struct device_node *control_node; struct platform_device *control_pdev; const struct of_device_id *match; - - match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev); - if (!match) - return -EINVAL; + struct clk *clk; phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); if (!phy) { dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n"); return -ENOMEM; } + phy->dev = &pdev->dev; - phy->dpll_map = (struct pipe3_dpll_map *)match->data; - if (!phy->dpll_map) { - dev_err(&pdev->dev, "no DPLL data\n"); - return -EINVAL; - } + if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { + match = of_match_device(of_match_ptr(ti_pipe3_id_table), + &pdev->dev); + if (!match) + return -EINVAL; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); - phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(phy->pll_ctrl_base)) - return PTR_ERR(phy->pll_ctrl_base); + phy->dpll_map = (struct pipe3_dpll_map *)match->data; + if (!phy->dpll_map) { + dev_err(&pdev->dev, "no DPLL data\n"); + return -EINVAL; + } - phy->dev = &pdev->dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pll_ctrl"); + phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(phy->pll_ctrl_base)) + return PTR_ERR(phy->pll_ctrl_base); - if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { + phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); + if (IS_ERR(phy->sys_clk)) { + dev_err(&pdev->dev, "unable to get sysclk\n"); + return -EINVAL; + } + } + if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); if (IS_ERR(phy->wkupclk)) { dev_err(&pdev->dev, "unable to get wkupclk\n"); @@ -328,10 +345,38 @@ static int ti_pipe3_probe(struct platform_device *pdev) phy->refclk = ERR_PTR(-ENODEV); } - phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); - if (IS_ERR(phy->sys_clk)) { - dev_err(&pdev->dev, "unable to get sysclk\n"); - return -EINVAL; + if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { + if (of_property_read_u8(node, "id", &phy->id) < 0) + phy->id = 1; + + clk = devm_clk_get(phy->dev, "dpll_ref"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get dpll ref clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 1500000000); + + clk = devm_clk_get(phy->dev, "dpll_ref_m2"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get dpll ref m2 clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 100000000); + + clk = devm_clk_get(phy->dev, "phy-div"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get phy-div clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 100000000); + + phy->div_clk = devm_clk_get(phy->dev, "div-clk"); + if (IS_ERR(phy->div_clk)) { + dev_err(&pdev->dev, "unable to get div-clk\n"); + return PTR_ERR(phy->div_clk); + } + } else { + phy->div_clk = ERR_PTR(-ENODEV); } control_node = of_parse_phandle(node, "ctrl-module", 0); @@ -387,6 +432,8 @@ static int ti_pipe3_runtime_suspend(struct device *dev) clk_disable_unprepare(phy->wkupclk); if (!IS_ERR(phy->refclk)) clk_disable_unprepare(phy->refclk); + if (!IS_ERR(phy->div_clk)) + clk_disable_unprepare(phy->div_clk); return 0; } @@ -412,8 +459,19 @@ static int ti_pipe3_runtime_resume(struct device *dev) } } + if (!IS_ERR(phy->div_clk)) { + ret = clk_prepare_enable(phy->div_clk); + if (ret) { + dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); + goto err3; + } + } return 0; +err3: + if (!IS_ERR(phy->wkupclk)) + clk_disable_unprepare(phy->wkupclk); + err2: if (!IS_ERR(phy->refclk)) clk_disable_unprepare(phy->refclk); @@ -446,6 +504,9 @@ static const struct of_device_id ti_pipe3_id_table[] = { .compatible = "ti,phy-pipe3-sata", .data = dpll_map_sata, }, + { + .compatible = "ti,phy-pipe3-pcie", + }, {} }; MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html