18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCIe PHY driver for Lantiq VRX200 and ARX300 SoCs. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the BSP (called "UGW") driver: 88c2ecf20Sopenharmony_ci * Copyright (C) 2009-2015 Lei Chuanhua <chuanhua.lei@lantiq.com> 98c2ecf20Sopenharmony_ci * Copyright (C) 2016 Intel Corporation 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * TODO: PHY modes other than 36MHz (without "SSC") 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 158c2ecf20Sopenharmony_ci#include <linux/bits.h> 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci#include <linux/property.h> 248c2ecf20Sopenharmony_ci#include <linux/regmap.h> 258c2ecf20Sopenharmony_ci#include <linux/reset.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <dt-bindings/phy/phy-lantiq-vrx200-pcie.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL1 0x44 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2 0x46 328c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2_CONST_SDM_MASK GENMASK(7, 0) 338c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2_CONST_SDM_EN BIT(8) 348c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2_PLL_SDM_EN BIT(9) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL3 0x48 378c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_EN BIT(1) 388c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_MASK GENMASK(6, 4) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL4 0x4a 418c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL5 0x4c 428c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL6 0x4e 438c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_CTRL7 0x50 448c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL1 0x52 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL2 0x54 478c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL2_LF_MODE_EN BIT(14) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL3 0x56 508c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL3_MMD_MASK GENMASK(15, 13) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define PCIE_PHY_PLL_STATUS 0x58 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_CTRL1 0x60 558c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_CTRL1_FORCE_EN BIT(3) 568c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_CTRL1_LOAD_EN BIT(4) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_CTRL2 0x62 598c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_CTRL3 0x64 608c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_A_CTRL1 0x66 618c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_A_CTRL2 0x68 628c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_MOD1 0x6a 638c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_MOD2 0x6c 648c2ecf20Sopenharmony_ci#define PCIE_PHY_TX1_MOD3 0x6e 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_CTRL1 0x70 678c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_CTRL1_LOAD_EN BIT(4) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_CTRL2 0x72 708c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_A_CTRL1 0x76 718c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_A_CTRL2 0x78 728c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_MOD1 0x7a 738c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_MOD2 0x7c 748c2ecf20Sopenharmony_ci#define PCIE_PHY_TX2_MOD3 0x7e 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define PCIE_PHY_RX1_CTRL1 0xa0 778c2ecf20Sopenharmony_ci#define PCIE_PHY_RX1_CTRL1_LOAD_EN BIT(1) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define PCIE_PHY_RX1_CTRL2 0xa2 808c2ecf20Sopenharmony_ci#define PCIE_PHY_RX1_CDR 0xa4 818c2ecf20Sopenharmony_ci#define PCIE_PHY_RX1_EI 0xa6 828c2ecf20Sopenharmony_ci#define PCIE_PHY_RX1_A_CTRL 0xaa 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct ltq_vrx200_pcie_phy_priv { 858c2ecf20Sopenharmony_ci struct phy *phy; 868c2ecf20Sopenharmony_ci unsigned int mode; 878c2ecf20Sopenharmony_ci struct device *dev; 888c2ecf20Sopenharmony_ci struct regmap *phy_regmap; 898c2ecf20Sopenharmony_ci struct regmap *rcu_regmap; 908c2ecf20Sopenharmony_ci struct clk *pdi_clk; 918c2ecf20Sopenharmony_ci struct clk *phy_clk; 928c2ecf20Sopenharmony_ci struct reset_control *phy_reset; 938c2ecf20Sopenharmony_ci struct reset_control *pcie_reset; 948c2ecf20Sopenharmony_ci u32 rcu_ahb_endian_offset; 958c2ecf20Sopenharmony_ci u32 rcu_ahb_endian_big_endian_mask; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void ltq_vrx200_pcie_phy_common_setup(struct phy *phy) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* PLL Setting */ 1038c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL1, 0x120e); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* increase the bias reference voltage */ 1068c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL2, 0x39d7); 1078c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL3, 0x0900); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Endcnt */ 1108c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_RX1_EI, 0x0004); 1118c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_RX1_A_CTRL, 0x6803); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_TX1_CTRL1, 1148c2ecf20Sopenharmony_ci PCIE_PHY_TX1_CTRL1_FORCE_EN, 1158c2ecf20Sopenharmony_ci PCIE_PHY_TX1_CTRL1_FORCE_EN); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* predrv_ser_en */ 1188c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_A_CTRL2, 0x0706); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* ctrl_lim */ 1218c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_CTRL3, 0x1fff); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* ctrl */ 1248c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_A_CTRL1, 0x0810); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* predrv_ser_en */ 1278c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_TX2_A_CTRL2, 0x7f00, 1288c2ecf20Sopenharmony_ci 0x4700); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* RTERM */ 1318c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_CTRL2, 0x2e00); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Improved 100MHz clock output */ 1348c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_CTRL2, 0x3096); 1358c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_A_CTRL2, 0x4707); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Reduced CDR BW to avoid glitches */ 1388c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_RX1_CDR, 0x0235); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void pcie_phy_36mhz_mode_setup(struct phy *phy) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL3, 1468c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_EN, 0x0000); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL3, 1498c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_MASK, 0x0000); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL2, 1528c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL2_PLL_SDM_EN, 1538c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL2_PLL_SDM_EN); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL2, 1568c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL2_CONST_SDM_EN, 1578c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL2_CONST_SDM_EN); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL3, 1608c2ecf20Sopenharmony_ci PCIE_PHY_PLL_A_CTRL3_MMD_MASK, 1618c2ecf20Sopenharmony_ci FIELD_PREP(PCIE_PHY_PLL_A_CTRL3_MMD_MASK, 0x1)); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL2, 1648c2ecf20Sopenharmony_ci PCIE_PHY_PLL_A_CTRL2_LF_MODE_EN, 0x0000); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* const_sdm */ 1678c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL1, 0x38e4); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL2, 1708c2ecf20Sopenharmony_ci PCIE_PHY_PLL_CTRL2_CONST_SDM_MASK, 1718c2ecf20Sopenharmony_ci FIELD_PREP(PCIE_PHY_PLL_CTRL2_CONST_SDM_MASK, 1728c2ecf20Sopenharmony_ci 0xee)); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* pllmod */ 1758c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL7, 0x0002); 1768c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL6, 0x3a04); 1778c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL5, 0xfae3); 1788c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL4, 0x1b72); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int ltq_vrx200_pcie_phy_wait_for_pll(struct phy *phy) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 1848c2ecf20Sopenharmony_ci unsigned int tmp; 1858c2ecf20Sopenharmony_ci int ret; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(priv->phy_regmap, PCIE_PHY_PLL_STATUS, 1888c2ecf20Sopenharmony_ci tmp, ((tmp & 0x0070) == 0x0070), 10, 1898c2ecf20Sopenharmony_ci 10000); 1908c2ecf20Sopenharmony_ci if (ret) { 1918c2ecf20Sopenharmony_ci dev_err(priv->dev, "PLL Link timeout, PLL status = 0x%04x\n", 1928c2ecf20Sopenharmony_ci tmp); 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void ltq_vrx200_pcie_phy_apply_workarounds(struct phy *phy) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 2028c2ecf20Sopenharmony_ci static const struct reg_default slices[] = { 2038c2ecf20Sopenharmony_ci { 2048c2ecf20Sopenharmony_ci .reg = PCIE_PHY_TX1_CTRL1, 2058c2ecf20Sopenharmony_ci .def = PCIE_PHY_TX1_CTRL1_LOAD_EN, 2068c2ecf20Sopenharmony_ci }, 2078c2ecf20Sopenharmony_ci { 2088c2ecf20Sopenharmony_ci .reg = PCIE_PHY_TX2_CTRL1, 2098c2ecf20Sopenharmony_ci .def = PCIE_PHY_TX2_CTRL1_LOAD_EN, 2108c2ecf20Sopenharmony_ci }, 2118c2ecf20Sopenharmony_ci { 2128c2ecf20Sopenharmony_ci .reg = PCIE_PHY_RX1_CTRL1, 2138c2ecf20Sopenharmony_ci .def = PCIE_PHY_RX1_CTRL1_LOAD_EN, 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci }; 2168c2ecf20Sopenharmony_ci int i; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(slices); i++) { 2198c2ecf20Sopenharmony_ci /* enable load_en */ 2208c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, slices[i].reg, 2218c2ecf20Sopenharmony_ci slices[i].def, slices[i].def); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci udelay(1); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* disable load_en */ 2268c2ecf20Sopenharmony_ci regmap_update_bits(priv->phy_regmap, slices[i].reg, 2278c2ecf20Sopenharmony_ci slices[i].def, 0x0); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 2318c2ecf20Sopenharmony_ci /* TX2 modulation */ 2328c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD1, 0x1ffe); 2338c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD2, 0xfffe); 2348c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD3, 0x0601); 2358c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 2368c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD3, 0x0001); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* TX1 modulation */ 2398c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD1, 0x1ffe); 2408c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD2, 0xfffe); 2418c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD3, 0x0601); 2428c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 2438c2ecf20Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD3, 0x0001); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int ltq_vrx200_pcie_phy_init(struct phy *phy) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 2508c2ecf20Sopenharmony_ci int ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (of_device_is_big_endian(priv->dev->of_node)) 2538c2ecf20Sopenharmony_ci regmap_update_bits(priv->rcu_regmap, 2548c2ecf20Sopenharmony_ci priv->rcu_ahb_endian_offset, 2558c2ecf20Sopenharmony_ci priv->rcu_ahb_endian_big_endian_mask, 2568c2ecf20Sopenharmony_ci priv->rcu_ahb_endian_big_endian_mask); 2578c2ecf20Sopenharmony_ci else 2588c2ecf20Sopenharmony_ci regmap_update_bits(priv->rcu_regmap, 2598c2ecf20Sopenharmony_ci priv->rcu_ahb_endian_offset, 2608c2ecf20Sopenharmony_ci priv->rcu_ahb_endian_big_endian_mask, 0x0); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ret = reset_control_assert(priv->phy_reset); 2638c2ecf20Sopenharmony_ci if (ret) 2648c2ecf20Sopenharmony_ci goto err; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci udelay(1); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = reset_control_deassert(priv->phy_reset); 2698c2ecf20Sopenharmony_ci if (ret) 2708c2ecf20Sopenharmony_ci goto err; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci udelay(1); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = reset_control_deassert(priv->pcie_reset); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci goto err_assert_phy_reset; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Make sure PHY PLL is stable */ 2798c2ecf20Sopenharmony_ci usleep_range(20, 40); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cierr_assert_phy_reset: 2848c2ecf20Sopenharmony_ci reset_control_assert(priv->phy_reset); 2858c2ecf20Sopenharmony_cierr: 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int ltq_vrx200_pcie_phy_exit(struct phy *phy) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 2928c2ecf20Sopenharmony_ci int ret; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci ret = reset_control_assert(priv->pcie_reset); 2958c2ecf20Sopenharmony_ci if (ret) 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = reset_control_assert(priv->phy_reset); 2998c2ecf20Sopenharmony_ci if (ret) 3008c2ecf20Sopenharmony_ci return ret; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int ltq_vrx200_pcie_phy_power_on(struct phy *phy) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 3088c2ecf20Sopenharmony_ci int ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Enable PDI to access PCIe PHY register */ 3118c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->pdi_clk); 3128c2ecf20Sopenharmony_ci if (ret) 3138c2ecf20Sopenharmony_ci goto err; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Configure PLL and PHY clock */ 3168c2ecf20Sopenharmony_ci ltq_vrx200_pcie_phy_common_setup(phy); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci pcie_phy_36mhz_mode_setup(phy); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Enable the PCIe PHY and make PLL setting take effect */ 3218c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->phy_clk); 3228c2ecf20Sopenharmony_ci if (ret) 3238c2ecf20Sopenharmony_ci goto err_disable_pdi_clk; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Check if we are in "startup ready" status */ 3268c2ecf20Sopenharmony_ci ret = ltq_vrx200_pcie_phy_wait_for_pll(phy); 3278c2ecf20Sopenharmony_ci if (ret) 3288c2ecf20Sopenharmony_ci goto err_disable_phy_clk; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ltq_vrx200_pcie_phy_apply_workarounds(phy); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return 0; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cierr_disable_phy_clk: 3358c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->phy_clk); 3368c2ecf20Sopenharmony_cierr_disable_pdi_clk: 3378c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->pdi_clk); 3388c2ecf20Sopenharmony_cierr: 3398c2ecf20Sopenharmony_ci return ret; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int ltq_vrx200_pcie_phy_power_off(struct phy *phy) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->phy_clk); 3478c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->pdi_clk); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic const struct phy_ops ltq_vrx200_pcie_phy_ops = { 3538c2ecf20Sopenharmony_ci .init = ltq_vrx200_pcie_phy_init, 3548c2ecf20Sopenharmony_ci .exit = ltq_vrx200_pcie_phy_exit, 3558c2ecf20Sopenharmony_ci .power_on = ltq_vrx200_pcie_phy_power_on, 3568c2ecf20Sopenharmony_ci .power_off = ltq_vrx200_pcie_phy_power_off, 3578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3588c2ecf20Sopenharmony_ci}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic struct phy *ltq_vrx200_pcie_phy_xlate(struct device *dev, 3618c2ecf20Sopenharmony_ci struct of_phandle_args *args) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = dev_get_drvdata(dev); 3648c2ecf20Sopenharmony_ci unsigned int mode; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (args->args_count != 1) { 3678c2ecf20Sopenharmony_ci dev_err(dev, "invalid number of arguments\n"); 3688c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci mode = args->args[0]; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci switch (mode) { 3748c2ecf20Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_36MHZ: 3758c2ecf20Sopenharmony_ci priv->mode = mode; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_25MHZ: 3798c2ecf20Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_25MHZ_SSC: 3808c2ecf20Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_36MHZ_SSC: 3818c2ecf20Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_100MHZ: 3828c2ecf20Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_100MHZ_SSC: 3838c2ecf20Sopenharmony_ci dev_err(dev, "PHY mode not implemented yet: %u\n", mode); 3848c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci default: 3878c2ecf20Sopenharmony_ci dev_err(dev, "invalid PHY mode %u\n", mode); 3888c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return priv->phy; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int ltq_vrx200_pcie_phy_probe(struct platform_device *pdev) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci static const struct regmap_config regmap_config = { 3978c2ecf20Sopenharmony_ci .reg_bits = 8, 3988c2ecf20Sopenharmony_ci .val_bits = 16, 3998c2ecf20Sopenharmony_ci .reg_stride = 2, 4008c2ecf20Sopenharmony_ci .max_register = PCIE_PHY_RX1_A_CTRL, 4018c2ecf20Sopenharmony_ci }; 4028c2ecf20Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv; 4038c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4048c2ecf20Sopenharmony_ci struct phy_provider *provider; 4058c2ecf20Sopenharmony_ci struct resource *res; 4068c2ecf20Sopenharmony_ci void __iomem *base; 4078c2ecf20Sopenharmony_ci int ret; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 4108c2ecf20Sopenharmony_ci if (!priv) 4118c2ecf20Sopenharmony_ci return -ENOMEM; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4148c2ecf20Sopenharmony_ci base = devm_ioremap_resource(dev, res); 4158c2ecf20Sopenharmony_ci if (IS_ERR(base)) 4168c2ecf20Sopenharmony_ci return PTR_ERR(base); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci priv->phy_regmap = devm_regmap_init_mmio(dev, base, ®map_config); 4198c2ecf20Sopenharmony_ci if (IS_ERR(priv->phy_regmap)) 4208c2ecf20Sopenharmony_ci return PTR_ERR(priv->phy_regmap); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci priv->rcu_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 4238c2ecf20Sopenharmony_ci "lantiq,rcu"); 4248c2ecf20Sopenharmony_ci if (IS_ERR(priv->rcu_regmap)) 4258c2ecf20Sopenharmony_ci return PTR_ERR(priv->rcu_regmap); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "lantiq,rcu-endian-offset", 4288c2ecf20Sopenharmony_ci &priv->rcu_ahb_endian_offset); 4298c2ecf20Sopenharmony_ci if (ret) { 4308c2ecf20Sopenharmony_ci dev_err(dev, 4318c2ecf20Sopenharmony_ci "failed to parse the 'lantiq,rcu-endian-offset' property\n"); 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "lantiq,rcu-big-endian-mask", 4368c2ecf20Sopenharmony_ci &priv->rcu_ahb_endian_big_endian_mask); 4378c2ecf20Sopenharmony_ci if (ret) { 4388c2ecf20Sopenharmony_ci dev_err(dev, 4398c2ecf20Sopenharmony_ci "failed to parse the 'lantiq,rcu-big-endian-mask' property\n"); 4408c2ecf20Sopenharmony_ci return ret; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci priv->pdi_clk = devm_clk_get(dev, "pdi"); 4448c2ecf20Sopenharmony_ci if (IS_ERR(priv->pdi_clk)) 4458c2ecf20Sopenharmony_ci return PTR_ERR(priv->pdi_clk); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci priv->phy_clk = devm_clk_get(dev, "phy"); 4488c2ecf20Sopenharmony_ci if (IS_ERR(priv->phy_clk)) 4498c2ecf20Sopenharmony_ci return PTR_ERR(priv->phy_clk); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); 4528c2ecf20Sopenharmony_ci if (IS_ERR(priv->phy_reset)) 4538c2ecf20Sopenharmony_ci return PTR_ERR(priv->phy_reset); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci priv->pcie_reset = devm_reset_control_get_shared(dev, "pcie"); 4568c2ecf20Sopenharmony_ci if (IS_ERR(priv->pcie_reset)) 4578c2ecf20Sopenharmony_ci return PTR_ERR(priv->pcie_reset); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci priv->dev = dev; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci priv->phy = devm_phy_create(dev, dev->of_node, 4628c2ecf20Sopenharmony_ci <q_vrx200_pcie_phy_ops); 4638c2ecf20Sopenharmony_ci if (IS_ERR(priv->phy)) { 4648c2ecf20Sopenharmony_ci dev_err(dev, "failed to create PHY\n"); 4658c2ecf20Sopenharmony_ci return PTR_ERR(priv->phy); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci phy_set_drvdata(priv->phy, priv); 4698c2ecf20Sopenharmony_ci dev_set_drvdata(dev, priv); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci provider = devm_of_phy_provider_register(dev, 4728c2ecf20Sopenharmony_ci ltq_vrx200_pcie_phy_xlate); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(provider); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic const struct of_device_id ltq_vrx200_pcie_phy_of_match[] = { 4788c2ecf20Sopenharmony_ci { .compatible = "lantiq,vrx200-pcie-phy", }, 4798c2ecf20Sopenharmony_ci { .compatible = "lantiq,arx300-pcie-phy", }, 4808c2ecf20Sopenharmony_ci { /* sentinel */ }, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltq_vrx200_pcie_phy_of_match); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic struct platform_driver ltq_vrx200_pcie_phy_driver = { 4858c2ecf20Sopenharmony_ci .probe = ltq_vrx200_pcie_phy_probe, 4868c2ecf20Sopenharmony_ci .driver = { 4878c2ecf20Sopenharmony_ci .name = "ltq-vrx200-pcie-phy", 4888c2ecf20Sopenharmony_ci .of_match_table = ltq_vrx200_pcie_phy_of_match, 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci}; 4918c2ecf20Sopenharmony_cimodule_platform_driver(ltq_vrx200_pcie_phy_driver); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); 4948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Lantiq VRX200 and ARX300 PCIe PHY driver"); 4958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 496