162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Rockchip PCIE3.0 phy driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022 Rockchip Electronics Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/iopoll.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/phy/pcie.h> 1762306a36Sopenharmony_ci#include <linux/phy/phy.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/regmap.h> 2062306a36Sopenharmony_ci#include <linux/reset.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Register for RK3568 */ 2362306a36Sopenharmony_ci#define GRF_PCIE30PHY_CON1 0x4 2462306a36Sopenharmony_ci#define GRF_PCIE30PHY_CON6 0x18 2562306a36Sopenharmony_ci#define GRF_PCIE30PHY_CON9 0x24 2662306a36Sopenharmony_ci#define GRF_PCIE30PHY_DA_OCM (BIT(15) | BIT(31)) 2762306a36Sopenharmony_ci#define GRF_PCIE30PHY_STATUS0 0x80 2862306a36Sopenharmony_ci#define GRF_PCIE30PHY_WR_EN (0xf << 16) 2962306a36Sopenharmony_ci#define SRAM_INIT_DONE(reg) (reg & BIT(14)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define RK3568_BIFURCATION_LANE_0_1 BIT(0) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Register for RK3588 */ 3462306a36Sopenharmony_ci#define PHP_GRF_PCIESEL_CON 0x100 3562306a36Sopenharmony_ci#define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 3662306a36Sopenharmony_ci#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 3762306a36Sopenharmony_ci#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 3862306a36Sopenharmony_ci#define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define RK3588_BIFURCATION_LANE_0_1 BIT(0) 4162306a36Sopenharmony_ci#define RK3588_BIFURCATION_LANE_2_3 BIT(1) 4262306a36Sopenharmony_ci#define RK3588_LANE_AGGREGATION BIT(2) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct rockchip_p3phy_ops; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct rockchip_p3phy_priv { 4762306a36Sopenharmony_ci const struct rockchip_p3phy_ops *ops; 4862306a36Sopenharmony_ci void __iomem *mmio; 4962306a36Sopenharmony_ci /* mode: RC, EP */ 5062306a36Sopenharmony_ci int mode; 5162306a36Sopenharmony_ci /* pcie30_phymode: Aggregation, Bifurcation */ 5262306a36Sopenharmony_ci int pcie30_phymode; 5362306a36Sopenharmony_ci struct regmap *phy_grf; 5462306a36Sopenharmony_ci struct regmap *pipe_grf; 5562306a36Sopenharmony_ci struct reset_control *p30phy; 5662306a36Sopenharmony_ci struct phy *phy; 5762306a36Sopenharmony_ci struct clk_bulk_data *clks; 5862306a36Sopenharmony_ci int num_clks; 5962306a36Sopenharmony_ci int num_lanes; 6062306a36Sopenharmony_ci u32 lanes[4]; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct rockchip_p3phy_ops { 6462306a36Sopenharmony_ci int (*phy_init)(struct rockchip_p3phy_priv *priv); 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Actually We don't care EP/RC mode, but just record it */ 7262306a36Sopenharmony_ci switch (submode) { 7362306a36Sopenharmony_ci case PHY_MODE_PCIE_RC: 7462306a36Sopenharmony_ci priv->mode = PHY_MODE_PCIE_RC; 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci case PHY_MODE_PCIE_EP: 7762306a36Sopenharmony_ci priv->mode = PHY_MODE_PCIE_EP; 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci default: 8062306a36Sopenharmony_ci dev_err(&phy->dev, "%s, invalid mode\n", __func__); 8162306a36Sopenharmony_ci return -EINVAL; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int rockchip_p3phy_rk3568_init(struct rockchip_p3phy_priv *priv) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct phy *phy = priv->phy; 9062306a36Sopenharmony_ci bool bifurcation = false; 9162306a36Sopenharmony_ci int ret; 9262306a36Sopenharmony_ci u32 reg; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Deassert PCIe PMA output clamp mode */ 9562306a36Sopenharmony_ci regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (int i = 0; i < priv->num_lanes; i++) { 9862306a36Sopenharmony_ci dev_info(&phy->dev, "lane number %d, val %d\n", i, priv->lanes[i]); 9962306a36Sopenharmony_ci if (priv->lanes[i] > 1) 10062306a36Sopenharmony_ci bifurcation = true; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Set bifurcation if needed, and it doesn't care RC/EP */ 10462306a36Sopenharmony_ci if (bifurcation) { 10562306a36Sopenharmony_ci dev_info(&phy->dev, "bifurcation enabled\n"); 10662306a36Sopenharmony_ci regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, 10762306a36Sopenharmony_ci GRF_PCIE30PHY_WR_EN | RK3568_BIFURCATION_LANE_0_1); 10862306a36Sopenharmony_ci regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1, 10962306a36Sopenharmony_ci GRF_PCIE30PHY_DA_OCM); 11062306a36Sopenharmony_ci } else { 11162306a36Sopenharmony_ci dev_dbg(&phy->dev, "bifurcation disabled\n"); 11262306a36Sopenharmony_ci regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, 11362306a36Sopenharmony_ci GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci reset_control_deassert(priv->p30phy); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ret = regmap_read_poll_timeout(priv->phy_grf, 11962306a36Sopenharmony_ci GRF_PCIE30PHY_STATUS0, 12062306a36Sopenharmony_ci reg, SRAM_INIT_DONE(reg), 12162306a36Sopenharmony_ci 0, 500); 12262306a36Sopenharmony_ci if (ret) 12362306a36Sopenharmony_ci dev_err(&priv->phy->dev, "%s: lock failed 0x%x, check input refclk and power supply\n", 12462306a36Sopenharmony_ci __func__, reg); 12562306a36Sopenharmony_ci return ret; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic const struct rockchip_p3phy_ops rk3568_ops = { 12962306a36Sopenharmony_ci .phy_init = rockchip_p3phy_rk3568_init, 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci u32 reg = 0; 13562306a36Sopenharmony_ci u8 mode = 0; 13662306a36Sopenharmony_ci int ret; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Deassert PCIe PMA output clamp mode */ 13962306a36Sopenharmony_ci regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24)); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Set bifurcation if needed */ 14262306a36Sopenharmony_ci for (int i = 0; i < priv->num_lanes; i++) { 14362306a36Sopenharmony_ci if (!priv->lanes[i]) 14462306a36Sopenharmony_ci mode |= (BIT(i) << 3); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (priv->lanes[i] > 1) 14762306a36Sopenharmony_ci mode |= (BIT(i) >> 1); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (!mode) 15162306a36Sopenharmony_ci reg = RK3588_LANE_AGGREGATION; 15262306a36Sopenharmony_ci else { 15362306a36Sopenharmony_ci if (mode & (BIT(0) | BIT(1))) 15462306a36Sopenharmony_ci reg |= RK3588_BIFURCATION_LANE_0_1; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (mode & (BIT(2) | BIT(3))) 15762306a36Sopenharmony_ci reg |= RK3588_BIFURCATION_LANE_2_3; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, (0x7<<16) | reg); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ 16362306a36Sopenharmony_ci if (!IS_ERR(priv->pipe_grf)) { 16462306a36Sopenharmony_ci reg = (mode & (BIT(6) | BIT(7))) >> 6; 16562306a36Sopenharmony_ci if (reg) 16662306a36Sopenharmony_ci regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, 16762306a36Sopenharmony_ci (reg << 16) | reg); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci reset_control_deassert(priv->p30phy); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ret = regmap_read_poll_timeout(priv->phy_grf, 17362306a36Sopenharmony_ci RK3588_PCIE3PHY_GRF_PHY0_STATUS1, 17462306a36Sopenharmony_ci reg, RK3588_SRAM_INIT_DONE(reg), 17562306a36Sopenharmony_ci 0, 500); 17662306a36Sopenharmony_ci ret |= regmap_read_poll_timeout(priv->phy_grf, 17762306a36Sopenharmony_ci RK3588_PCIE3PHY_GRF_PHY1_STATUS1, 17862306a36Sopenharmony_ci reg, RK3588_SRAM_INIT_DONE(reg), 17962306a36Sopenharmony_ci 0, 500); 18062306a36Sopenharmony_ci if (ret) 18162306a36Sopenharmony_ci dev_err(&priv->phy->dev, "lock failed 0x%x, check input refclk and power supply\n", 18262306a36Sopenharmony_ci reg); 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic const struct rockchip_p3phy_ops rk3588_ops = { 18762306a36Sopenharmony_ci .phy_init = rockchip_p3phy_rk3588_init, 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int rochchip_p3phy_init(struct phy *phy) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); 19362306a36Sopenharmony_ci int ret; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); 19662306a36Sopenharmony_ci if (ret) { 19762306a36Sopenharmony_ci dev_err(&priv->phy->dev, "failed to enable PCIe bulk clks %d\n", ret); 19862306a36Sopenharmony_ci return ret; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci reset_control_assert(priv->p30phy); 20262306a36Sopenharmony_ci udelay(1); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (priv->ops->phy_init) { 20562306a36Sopenharmony_ci ret = priv->ops->phy_init(priv); 20662306a36Sopenharmony_ci if (ret) 20762306a36Sopenharmony_ci clk_bulk_disable_unprepare(priv->num_clks, priv->clks); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return ret; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int rochchip_p3phy_exit(struct phy *phy) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci clk_bulk_disable_unprepare(priv->num_clks, priv->clks); 21862306a36Sopenharmony_ci reset_control_assert(priv->p30phy); 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic const struct phy_ops rochchip_p3phy_ops = { 22362306a36Sopenharmony_ci .init = rochchip_p3phy_init, 22462306a36Sopenharmony_ci .exit = rochchip_p3phy_exit, 22562306a36Sopenharmony_ci .set_mode = rockchip_p3phy_set_mode, 22662306a36Sopenharmony_ci .owner = THIS_MODULE, 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int rockchip_p3phy_probe(struct platform_device *pdev) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct phy_provider *phy_provider; 23262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 23362306a36Sopenharmony_ci struct rockchip_p3phy_priv *priv; 23462306a36Sopenharmony_ci struct device_node *np = dev->of_node; 23562306a36Sopenharmony_ci int ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 23862306a36Sopenharmony_ci if (!priv) 23962306a36Sopenharmony_ci return -ENOMEM; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci priv->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 24262306a36Sopenharmony_ci if (IS_ERR(priv->mmio)) { 24362306a36Sopenharmony_ci ret = PTR_ERR(priv->mmio); 24462306a36Sopenharmony_ci return ret; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci priv->ops = of_device_get_match_data(&pdev->dev); 24862306a36Sopenharmony_ci if (!priv->ops) { 24962306a36Sopenharmony_ci dev_err(dev, "no of match data provided\n"); 25062306a36Sopenharmony_ci return -EINVAL; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci priv->phy_grf = syscon_regmap_lookup_by_phandle(np, "rockchip,phy-grf"); 25462306a36Sopenharmony_ci if (IS_ERR(priv->phy_grf)) { 25562306a36Sopenharmony_ci dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); 25662306a36Sopenharmony_ci return PTR_ERR(priv->phy_grf); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (of_device_is_compatible(np, "rockchip,rk3588-pcie3-phy")) { 26062306a36Sopenharmony_ci priv->pipe_grf = 26162306a36Sopenharmony_ci syscon_regmap_lookup_by_phandle(dev->of_node, 26262306a36Sopenharmony_ci "rockchip,pipe-grf"); 26362306a36Sopenharmony_ci if (IS_ERR(priv->pipe_grf)) 26462306a36Sopenharmony_ci dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); 26562306a36Sopenharmony_ci } else { 26662306a36Sopenharmony_ci priv->pipe_grf = NULL; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci priv->num_lanes = of_property_read_variable_u32_array(dev->of_node, "data-lanes", 27062306a36Sopenharmony_ci priv->lanes, 2, 27162306a36Sopenharmony_ci ARRAY_SIZE(priv->lanes)); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* if no data-lanes assume aggregation */ 27462306a36Sopenharmony_ci if (priv->num_lanes == -EINVAL) { 27562306a36Sopenharmony_ci dev_dbg(dev, "no data-lanes property found\n"); 27662306a36Sopenharmony_ci priv->num_lanes = 1; 27762306a36Sopenharmony_ci priv->lanes[0] = 1; 27862306a36Sopenharmony_ci } else if (priv->num_lanes < 0) { 27962306a36Sopenharmony_ci dev_err(dev, "failed to read data-lanes property %d\n", priv->num_lanes); 28062306a36Sopenharmony_ci return priv->num_lanes; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); 28462306a36Sopenharmony_ci if (IS_ERR(priv->phy)) { 28562306a36Sopenharmony_ci dev_err(dev, "failed to create combphy\n"); 28662306a36Sopenharmony_ci return PTR_ERR(priv->phy); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci priv->p30phy = devm_reset_control_get_optional_exclusive(dev, "phy"); 29062306a36Sopenharmony_ci if (IS_ERR(priv->p30phy)) { 29162306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->p30phy), 29262306a36Sopenharmony_ci "failed to get phy reset control\n"); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (!priv->p30phy) 29562306a36Sopenharmony_ci dev_info(dev, "no phy reset control specified\n"); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks); 29862306a36Sopenharmony_ci if (priv->num_clks < 1) 29962306a36Sopenharmony_ci return -ENODEV; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci dev_set_drvdata(dev, priv); 30262306a36Sopenharmony_ci phy_set_drvdata(priv->phy, priv); 30362306a36Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 30462306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic const struct of_device_id rockchip_p3phy_of_match[] = { 30862306a36Sopenharmony_ci { .compatible = "rockchip,rk3568-pcie3-phy", .data = &rk3568_ops }, 30962306a36Sopenharmony_ci { .compatible = "rockchip,rk3588-pcie3-phy", .data = &rk3588_ops }, 31062306a36Sopenharmony_ci { }, 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_p3phy_of_match); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic struct platform_driver rockchip_p3phy_driver = { 31562306a36Sopenharmony_ci .probe = rockchip_p3phy_probe, 31662306a36Sopenharmony_ci .driver = { 31762306a36Sopenharmony_ci .name = "rockchip-snps-pcie3-phy", 31862306a36Sopenharmony_ci .of_match_table = rockchip_p3phy_of_match, 31962306a36Sopenharmony_ci }, 32062306a36Sopenharmony_ci}; 32162306a36Sopenharmony_cimodule_platform_driver(rockchip_p3phy_driver); 32262306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip Synopsys PCIe 3.0 PHY driver"); 32362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 324