phy: phy-omap-pipe3: Add support for PCIe PHY

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: default avatarKishon Vijay Abraham I <kishon@ti.com>
Reviewed-by: default avatarRoger Quadros <rogerq@ti.com>
parent 57416c23
...@@ -56,8 +56,8 @@ usb2phy@4a0ad080 { ...@@ -56,8 +56,8 @@ usb2phy@4a0ad080 {
TI PIPE3 PHY TI PIPE3 PHY
Required properties: Required properties:
- compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata". - compatible: Should be "ti,phy-usb3", "ti,phy-pipe3-sata" or
"ti,omap-usb3" is deprecated. "ti,phy-pipe3-pcie. "ti,omap-usb3" is deprecated.
- reg : Address and length of the register set for the device. - reg : Address and length of the register set for the device.
- reg-names: The names of the register addresses corresponding to the registers - reg-names: The names of the register addresses corresponding to the registers
filled in "reg". filled in "reg".
...@@ -69,10 +69,17 @@ Required properties: ...@@ -69,10 +69,17 @@ Required properties:
* "wkupclk" - wakeup clock. * "wkupclk" - wakeup clock.
* "sysclk" - system clock. * "sysclk" - system clock.
* "refclk" - reference 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: Optional properties:
- ctrl-module : phandle of the control module used by PHY driver to power on - ctrl-module : phandle of the control module used by PHY driver to power on
the PHY. 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. This is usually a subnode of ocp2scp to which it is connected.
......
...@@ -80,7 +80,9 @@ struct ti_pipe3 { ...@@ -80,7 +80,9 @@ struct ti_pipe3 {
struct clk *wkupclk; struct clk *wkupclk;
struct clk *sys_clk; struct clk *sys_clk;
struct clk *refclk; struct clk *refclk;
struct clk *div_clk;
struct pipe3_dpll_map *dpll_map; struct pipe3_dpll_map *dpll_map;
u8 id;
}; };
static struct pipe3_dpll_map dpll_map_usb[] = { static struct pipe3_dpll_map dpll_map_usb[] = {
...@@ -215,6 +217,9 @@ static int ti_pipe3_init(struct phy *x) ...@@ -215,6 +217,9 @@ static int ti_pipe3_init(struct phy *x)
u32 val; u32 val;
int ret = 0; 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 */ /* Bring it out of IDLE if it is IDLE */
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
if (val & PLL_IDLE) { if (val & PLL_IDLE) {
...@@ -238,8 +243,11 @@ static int ti_pipe3_exit(struct phy *x) ...@@ -238,8 +243,11 @@ static int ti_pipe3_exit(struct phy *x)
u32 val; u32 val;
unsigned long timeout; unsigned long timeout;
/* SATA DPLL can't be powered down due to Errata i783 */ /* SATA DPLL can't be powered down due to Errata i783 and PCIe
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) * 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; return 0;
/* Put DPLL in IDLE mode */ /* Put DPLL in IDLE mode */
...@@ -286,32 +294,41 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -286,32 +294,41 @@ static int ti_pipe3_probe(struct platform_device *pdev)
struct device_node *control_node; struct device_node *control_node;
struct platform_device *control_pdev; struct platform_device *control_pdev;
const struct of_device_id *match; const struct of_device_id *match;
struct clk *clk;
match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev);
if (!match)
return -EINVAL;
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
if (!phy) { if (!phy) {
dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n"); dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n");
return -ENOMEM; return -ENOMEM;
} }
phy->dev = &pdev->dev;
phy->dpll_map = (struct pipe3_dpll_map *)match->data; if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
if (!phy->dpll_map) { match = of_match_device(of_match_ptr(ti_pipe3_id_table),
dev_err(&pdev->dev, "no DPLL data\n"); &pdev->dev);
return -EINVAL; if (!match)
} return -EINVAL;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); phy->dpll_map = (struct pipe3_dpll_map *)match->data;
phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); if (!phy->dpll_map) {
if (IS_ERR(phy->pll_ctrl_base)) dev_err(&pdev->dev, "no DPLL data\n");
return PTR_ERR(phy->pll_ctrl_base); 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"); phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
if (IS_ERR(phy->wkupclk)) { if (IS_ERR(phy->wkupclk)) {
dev_err(&pdev->dev, "unable to get wkupclk\n"); dev_err(&pdev->dev, "unable to get wkupclk\n");
...@@ -328,10 +345,38 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -328,10 +345,38 @@ static int ti_pipe3_probe(struct platform_device *pdev)
phy->refclk = ERR_PTR(-ENODEV); phy->refclk = ERR_PTR(-ENODEV);
} }
phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
if (IS_ERR(phy->sys_clk)) { if (of_property_read_u8(node, "id", &phy->id) < 0)
dev_err(&pdev->dev, "unable to get sysclk\n"); phy->id = 1;
return -EINVAL;
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); control_node = of_parse_phandle(node, "ctrl-module", 0);
...@@ -387,6 +432,8 @@ static int ti_pipe3_runtime_suspend(struct device *dev) ...@@ -387,6 +432,8 @@ static int ti_pipe3_runtime_suspend(struct device *dev)
clk_disable_unprepare(phy->wkupclk); clk_disable_unprepare(phy->wkupclk);
if (!IS_ERR(phy->refclk)) if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk); clk_disable_unprepare(phy->refclk);
if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk);
return 0; return 0;
} }
...@@ -412,8 +459,19 @@ static int ti_pipe3_runtime_resume(struct device *dev) ...@@ -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; return 0;
err3:
if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk);
err2: err2:
if (!IS_ERR(phy->refclk)) if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk); clk_disable_unprepare(phy->refclk);
...@@ -446,6 +504,9 @@ static const struct of_device_id ti_pipe3_id_table[] = { ...@@ -446,6 +504,9 @@ static const struct of_device_id ti_pipe3_id_table[] = {
.compatible = "ti,phy-pipe3-sata", .compatible = "ti,phy-pipe3-sata",
.data = dpll_map_sata, .data = dpll_map_sata,
}, },
{
.compatible = "ti,phy-pipe3-pcie",
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment