Skip to content

Commit 4ff9f68

Browse files
superna9999Lorenzo Pieralisi
authored andcommitted
PCI: amlogic: meson: Add support for G12A
Add support for the Amlogic G12A SoC using a separate shared PHY. This adds support for fetching a PHY phandle and call the PHY init, reset and power on/off calls instead of writing in the PHY register or toggling the PHY reset line. The MIPI clock and the PHY memory resource are only required for the Amlogic AXG SoC PCIe PHY setup, thus these elements are ignored for the Amlogic G12A having a separate shared PHY. Signed-off-by: Neil Armstrong <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]> Reviewed-by: Andrew Murray <[email protected]>
1 parent eacaf7d commit 4ff9f68

File tree

1 file changed

+105
-23
lines changed

1 file changed

+105
-23
lines changed

drivers/pci/controller/dwc/pci-meson.c

Lines changed: 105 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/reset.h>
1717
#include <linux/resource.h>
1818
#include <linux/types.h>
19+
#include <linux/phy/phy.h>
1920

2021
#include "pcie-designware.h"
2122

@@ -96,12 +97,18 @@ struct meson_pcie_rc_reset {
9697
struct reset_control *apb;
9798
};
9899

100+
struct meson_pcie_param {
101+
bool has_shared_phy;
102+
};
103+
99104
struct meson_pcie {
100105
struct dw_pcie pci;
101106
struct meson_pcie_mem_res mem_res;
102107
struct meson_pcie_clk_res clk_res;
103108
struct meson_pcie_rc_reset mrst;
104109
struct gpio_desc *reset_gpio;
110+
struct phy *phy;
111+
const struct meson_pcie_param *param;
105112
};
106113

107114
static struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp,
@@ -123,10 +130,12 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
123130
{
124131
struct meson_pcie_rc_reset *mrst = &mp->mrst;
125132

126-
mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
127-
if (IS_ERR(mrst->phy))
128-
return PTR_ERR(mrst->phy);
129-
reset_control_deassert(mrst->phy);
133+
if (!mp->param->has_shared_phy) {
134+
mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
135+
if (IS_ERR(mrst->phy))
136+
return PTR_ERR(mrst->phy);
137+
reset_control_deassert(mrst->phy);
138+
}
130139

131140
mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET);
132141
if (IS_ERR(mrst->port))
@@ -180,34 +189,61 @@ static int meson_pcie_get_mems(struct platform_device *pdev,
180189
if (IS_ERR(mp->mem_res.cfg_base))
181190
return PTR_ERR(mp->mem_res.cfg_base);
182191

183-
/* Meson SoC has two PCI controllers use same phy register*/
184-
mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy");
185-
if (IS_ERR(mp->mem_res.phy_base))
186-
return PTR_ERR(mp->mem_res.phy_base);
192+
/* Meson AXG SoC has two PCI controllers use same phy register */
193+
if (!mp->param->has_shared_phy) {
194+
mp->mem_res.phy_base =
195+
meson_pcie_get_mem_shared(pdev, mp, "phy");
196+
if (IS_ERR(mp->mem_res.phy_base))
197+
return PTR_ERR(mp->mem_res.phy_base);
198+
}
187199

188200
return 0;
189201
}
190202

191-
static void meson_pcie_power_on(struct meson_pcie *mp)
203+
static int meson_pcie_power_on(struct meson_pcie *mp)
192204
{
193-
writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
205+
int ret = 0;
206+
207+
if (mp->param->has_shared_phy) {
208+
ret = phy_init(mp->phy);
209+
if (ret)
210+
return ret;
211+
212+
ret = phy_power_on(mp->phy);
213+
if (ret) {
214+
phy_exit(mp->phy);
215+
return ret;
216+
}
217+
} else
218+
writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
219+
220+
return 0;
194221
}
195222

196-
static void meson_pcie_reset(struct meson_pcie *mp)
223+
static int meson_pcie_reset(struct meson_pcie *mp)
197224
{
198225
struct meson_pcie_rc_reset *mrst = &mp->mrst;
199-
200-
reset_control_assert(mrst->phy);
201-
udelay(PCIE_RESET_DELAY);
202-
reset_control_deassert(mrst->phy);
203-
udelay(PCIE_RESET_DELAY);
226+
int ret = 0;
227+
228+
if (mp->param->has_shared_phy) {
229+
ret = phy_reset(mp->phy);
230+
if (ret)
231+
return ret;
232+
} else {
233+
reset_control_assert(mrst->phy);
234+
udelay(PCIE_RESET_DELAY);
235+
reset_control_deassert(mrst->phy);
236+
udelay(PCIE_RESET_DELAY);
237+
}
204238

205239
reset_control_assert(mrst->port);
206240
reset_control_assert(mrst->apb);
207241
udelay(PCIE_RESET_DELAY);
208242
reset_control_deassert(mrst->port);
209243
reset_control_deassert(mrst->apb);
210244
udelay(PCIE_RESET_DELAY);
245+
246+
return 0;
211247
}
212248

213249
static inline struct clk *meson_pcie_probe_clock(struct device *dev,
@@ -250,9 +286,11 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
250286
if (IS_ERR(res->port_clk))
251287
return PTR_ERR(res->port_clk);
252288

253-
res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0);
254-
if (IS_ERR(res->mipi_gate))
255-
return PTR_ERR(res->mipi_gate);
289+
if (!mp->param->has_shared_phy) {
290+
res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0);
291+
if (IS_ERR(res->mipi_gate))
292+
return PTR_ERR(res->mipi_gate);
293+
}
256294

257295
res->general_clk = meson_pcie_probe_clock(dev, "general", 0);
258296
if (IS_ERR(res->general_clk))
@@ -524,6 +562,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
524562

525563
static int meson_pcie_probe(struct platform_device *pdev)
526564
{
565+
const struct meson_pcie_param *match_data;
527566
struct device *dev = &pdev->dev;
528567
struct dw_pcie *pci;
529568
struct meson_pcie *mp;
@@ -537,6 +576,19 @@ static int meson_pcie_probe(struct platform_device *pdev)
537576
pci->dev = dev;
538577
pci->ops = &dw_pcie_ops;
539578

579+
match_data = of_device_get_match_data(dev);
580+
if (!match_data) {
581+
dev_err(dev, "failed to get match data\n");
582+
return -ENODEV;
583+
}
584+
mp->param = match_data;
585+
586+
if (mp->param->has_shared_phy) {
587+
mp->phy = devm_phy_get(dev, "pcie");
588+
if (IS_ERR(mp->phy))
589+
return PTR_ERR(mp->phy);
590+
}
591+
540592
mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
541593
if (IS_ERR(mp->reset_gpio)) {
542594
dev_err(dev, "get reset gpio failed\n");
@@ -555,29 +607,59 @@ static int meson_pcie_probe(struct platform_device *pdev)
555607
return ret;
556608
}
557609

558-
meson_pcie_power_on(mp);
559-
meson_pcie_reset(mp);
610+
ret = meson_pcie_power_on(mp);
611+
if (ret) {
612+
dev_err(dev, "phy power on failed, %d\n", ret);
613+
return ret;
614+
}
615+
616+
ret = meson_pcie_reset(mp);
617+
if (ret) {
618+
dev_err(dev, "reset failed, %d\n", ret);
619+
goto err_phy;
620+
}
560621

561622
ret = meson_pcie_probe_clocks(mp);
562623
if (ret) {
563624
dev_err(dev, "init clock resources failed, %d\n", ret);
564-
return ret;
625+
goto err_phy;
565626
}
566627

567628
platform_set_drvdata(pdev, mp);
568629

569630
ret = meson_add_pcie_port(mp, pdev);
570631
if (ret < 0) {
571632
dev_err(dev, "Add PCIe port failed, %d\n", ret);
572-
return ret;
633+
goto err_phy;
573634
}
574635

575636
return 0;
637+
638+
err_phy:
639+
if (mp->param->has_shared_phy) {
640+
phy_power_off(mp->phy);
641+
phy_exit(mp->phy);
642+
}
643+
644+
return ret;
576645
}
577646

647+
static struct meson_pcie_param meson_pcie_axg_param = {
648+
.has_shared_phy = false,
649+
};
650+
651+
static struct meson_pcie_param meson_pcie_g12a_param = {
652+
.has_shared_phy = true,
653+
};
654+
578655
static const struct of_device_id meson_pcie_of_match[] = {
579656
{
580657
.compatible = "amlogic,axg-pcie",
658+
.data = &meson_pcie_axg_param,
659+
},
660+
{
661+
.compatible = "amlogic,g12a-pcie",
662+
.data = &meson_pcie_g12a_param,
581663
},
582664
{},
583665
};

0 commit comments

Comments
 (0)