From 4d3186a525b3f6af7d5f468e94b79b9e92cf3853 Mon Sep 17 00:00:00 2001 From: Remi Pommarel Date: Sun, 1 Sep 2019 15:39:15 +0200 Subject: PCI: amlogic: Fix reset assertion via gpio descriptor Normally asserting reset signal on gpio would be achieved with: gpiod_set_value_cansleep(reset_gpio, 1); Meson PCI driver set reset value to '0' instead of '1' as it takes into account the PERST# signal polarity. The polarity should be taken care in the device tree instead. This fixes the reset assertion meaning and moves out the polarity configuration in DT (please note that there is no DT currently using this driver). Signed-off-by: Remi Pommarel Signed-off-by: Lorenzo Pieralisi Reviewed-by: Martin Blumenstingl Reviewed-by: Neil Armstrong --- drivers/pci/controller/dwc/pci-meson.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-meson.c') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index e35e9eaa50ee..541f37a6f6a5 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -287,9 +287,9 @@ static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg) static void meson_pcie_assert_reset(struct meson_pcie *mp) { - gpiod_set_value_cansleep(mp->reset_gpio, 0); - udelay(500); gpiod_set_value_cansleep(mp->reset_gpio, 1); + udelay(500); + gpiod_set_value_cansleep(mp->reset_gpio, 0); } static void meson_pcie_init_dw(struct meson_pcie *mp) -- cgit v1.2.3 From eacaf7dcf08eb062a1059c6c115fa3fced3374ae Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 16 Sep 2019 14:50:18 +0200 Subject: PCI: amlogic: Fix probed clock names Fix the clock names used in the probe function according to the bindings. Fixes: 9c0ef6d34fdb ("PCI: amlogic: Add the Amlogic Meson PCIe controller driver") Signed-off-by: Neil Armstrong Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/pci/controller/dwc/pci-meson.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-meson.c') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 541f37a6f6a5..ab79990798f8 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -250,15 +250,15 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp) if (IS_ERR(res->port_clk)) return PTR_ERR(res->port_clk); - res->mipi_gate = meson_pcie_probe_clock(dev, "pcie_mipi_en", 0); + res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0); if (IS_ERR(res->mipi_gate)) return PTR_ERR(res->mipi_gate); - res->general_clk = meson_pcie_probe_clock(dev, "pcie_general", 0); + res->general_clk = meson_pcie_probe_clock(dev, "general", 0); if (IS_ERR(res->general_clk)) return PTR_ERR(res->general_clk); - res->clk = meson_pcie_probe_clock(dev, "pcie", 0); + res->clk = meson_pcie_probe_clock(dev, "pclk", 0); if (IS_ERR(res->clk)) return PTR_ERR(res->clk); -- cgit v1.2.3 From 4ff9f68f8378baa8027426bb8a8853ae3f99ad6c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 16 Sep 2019 14:50:19 +0200 Subject: 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 Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/pci/controller/dwc/pci-meson.c | 128 +++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 23 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-meson.c') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index ab79990798f8..3772b02a5c55 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "pcie-designware.h" @@ -96,12 +97,18 @@ struct meson_pcie_rc_reset { struct reset_control *apb; }; +struct meson_pcie_param { + bool has_shared_phy; +}; + struct meson_pcie { struct dw_pcie pci; struct meson_pcie_mem_res mem_res; struct meson_pcie_clk_res clk_res; struct meson_pcie_rc_reset mrst; struct gpio_desc *reset_gpio; + struct phy *phy; + const struct meson_pcie_param *param; }; 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) { struct meson_pcie_rc_reset *mrst = &mp->mrst; - mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET); - if (IS_ERR(mrst->phy)) - return PTR_ERR(mrst->phy); - reset_control_deassert(mrst->phy); + if (!mp->param->has_shared_phy) { + mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET); + if (IS_ERR(mrst->phy)) + return PTR_ERR(mrst->phy); + reset_control_deassert(mrst->phy); + } mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET); if (IS_ERR(mrst->port)) @@ -180,27 +189,52 @@ static int meson_pcie_get_mems(struct platform_device *pdev, if (IS_ERR(mp->mem_res.cfg_base)) return PTR_ERR(mp->mem_res.cfg_base); - /* Meson SoC has two PCI controllers use same phy register*/ - mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy"); - if (IS_ERR(mp->mem_res.phy_base)) - return PTR_ERR(mp->mem_res.phy_base); + /* Meson AXG SoC has two PCI controllers use same phy register */ + if (!mp->param->has_shared_phy) { + mp->mem_res.phy_base = + meson_pcie_get_mem_shared(pdev, mp, "phy"); + if (IS_ERR(mp->mem_res.phy_base)) + return PTR_ERR(mp->mem_res.phy_base); + } return 0; } -static void meson_pcie_power_on(struct meson_pcie *mp) +static int meson_pcie_power_on(struct meson_pcie *mp) { - writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base); + int ret = 0; + + if (mp->param->has_shared_phy) { + ret = phy_init(mp->phy); + if (ret) + return ret; + + ret = phy_power_on(mp->phy); + if (ret) { + phy_exit(mp->phy); + return ret; + } + } else + writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base); + + return 0; } -static void meson_pcie_reset(struct meson_pcie *mp) +static int meson_pcie_reset(struct meson_pcie *mp) { struct meson_pcie_rc_reset *mrst = &mp->mrst; - - reset_control_assert(mrst->phy); - udelay(PCIE_RESET_DELAY); - reset_control_deassert(mrst->phy); - udelay(PCIE_RESET_DELAY); + int ret = 0; + + if (mp->param->has_shared_phy) { + ret = phy_reset(mp->phy); + if (ret) + return ret; + } else { + reset_control_assert(mrst->phy); + udelay(PCIE_RESET_DELAY); + reset_control_deassert(mrst->phy); + udelay(PCIE_RESET_DELAY); + } reset_control_assert(mrst->port); reset_control_assert(mrst->apb); @@ -208,6 +242,8 @@ static void meson_pcie_reset(struct meson_pcie *mp) reset_control_deassert(mrst->port); reset_control_deassert(mrst->apb); udelay(PCIE_RESET_DELAY); + + return 0; } 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) if (IS_ERR(res->port_clk)) return PTR_ERR(res->port_clk); - res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0); - if (IS_ERR(res->mipi_gate)) - return PTR_ERR(res->mipi_gate); + if (!mp->param->has_shared_phy) { + res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0); + if (IS_ERR(res->mipi_gate)) + return PTR_ERR(res->mipi_gate); + } res->general_clk = meson_pcie_probe_clock(dev, "general", 0); if (IS_ERR(res->general_clk)) @@ -524,6 +562,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { static int meson_pcie_probe(struct platform_device *pdev) { + const struct meson_pcie_param *match_data; struct device *dev = &pdev->dev; struct dw_pcie *pci; struct meson_pcie *mp; @@ -537,6 +576,19 @@ static int meson_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &dw_pcie_ops; + match_data = of_device_get_match_data(dev); + if (!match_data) { + dev_err(dev, "failed to get match data\n"); + return -ENODEV; + } + mp->param = match_data; + + if (mp->param->has_shared_phy) { + mp->phy = devm_phy_get(dev, "pcie"); + if (IS_ERR(mp->phy)) + return PTR_ERR(mp->phy); + } + mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(mp->reset_gpio)) { dev_err(dev, "get reset gpio failed\n"); @@ -555,13 +607,22 @@ static int meson_pcie_probe(struct platform_device *pdev) return ret; } - meson_pcie_power_on(mp); - meson_pcie_reset(mp); + ret = meson_pcie_power_on(mp); + if (ret) { + dev_err(dev, "phy power on failed, %d\n", ret); + return ret; + } + + ret = meson_pcie_reset(mp); + if (ret) { + dev_err(dev, "reset failed, %d\n", ret); + goto err_phy; + } ret = meson_pcie_probe_clocks(mp); if (ret) { dev_err(dev, "init clock resources failed, %d\n", ret); - return ret; + goto err_phy; } platform_set_drvdata(pdev, mp); @@ -569,15 +630,36 @@ static int meson_pcie_probe(struct platform_device *pdev) ret = meson_add_pcie_port(mp, pdev); if (ret < 0) { dev_err(dev, "Add PCIe port failed, %d\n", ret); - return ret; + goto err_phy; } return 0; + +err_phy: + if (mp->param->has_shared_phy) { + phy_power_off(mp->phy); + phy_exit(mp->phy); + } + + return ret; } +static struct meson_pcie_param meson_pcie_axg_param = { + .has_shared_phy = false, +}; + +static struct meson_pcie_param meson_pcie_g12a_param = { + .has_shared_phy = true, +}; + static const struct of_device_id meson_pcie_of_match[] = { { .compatible = "amlogic,axg-pcie", + .data = &meson_pcie_axg_param, + }, + { + .compatible = "amlogic,g12a-pcie", + .data = &meson_pcie_g12a_param, }, {}, }; -- cgit v1.2.3