162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCIe PHY driver for Lantiq VRX200 and ARX300 SoCs. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on the BSP (called "UGW") driver: 862306a36Sopenharmony_ci * Copyright (C) 2009-2015 Lei Chuanhua <chuanhua.lei@lantiq.com> 962306a36Sopenharmony_ci * Copyright (C) 2016 Intel Corporation 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * TODO: PHY modes other than 36MHz (without "SSC") 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/bitfield.h> 1562306a36Sopenharmony_ci#include <linux/bits.h> 1662306a36Sopenharmony_ci#include <linux/clk.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/phy/phy.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/property.h> 2462306a36Sopenharmony_ci#include <linux/regmap.h> 2562306a36Sopenharmony_ci#include <linux/reset.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <dt-bindings/phy/phy-lantiq-vrx200-pcie.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL1 0x44 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2 0x46 3262306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2_CONST_SDM_MASK GENMASK(7, 0) 3362306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2_CONST_SDM_EN BIT(8) 3462306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL2_PLL_SDM_EN BIT(9) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL3 0x48 3762306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_EN BIT(1) 3862306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_MASK GENMASK(6, 4) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL4 0x4a 4162306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL5 0x4c 4262306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL6 0x4e 4362306a36Sopenharmony_ci#define PCIE_PHY_PLL_CTRL7 0x50 4462306a36Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL1 0x52 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL2 0x54 4762306a36Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL2_LF_MODE_EN BIT(14) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL3 0x56 5062306a36Sopenharmony_ci#define PCIE_PHY_PLL_A_CTRL3_MMD_MASK GENMASK(15, 13) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define PCIE_PHY_PLL_STATUS 0x58 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define PCIE_PHY_TX1_CTRL1 0x60 5562306a36Sopenharmony_ci#define PCIE_PHY_TX1_CTRL1_FORCE_EN BIT(3) 5662306a36Sopenharmony_ci#define PCIE_PHY_TX1_CTRL1_LOAD_EN BIT(4) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define PCIE_PHY_TX1_CTRL2 0x62 5962306a36Sopenharmony_ci#define PCIE_PHY_TX1_CTRL3 0x64 6062306a36Sopenharmony_ci#define PCIE_PHY_TX1_A_CTRL1 0x66 6162306a36Sopenharmony_ci#define PCIE_PHY_TX1_A_CTRL2 0x68 6262306a36Sopenharmony_ci#define PCIE_PHY_TX1_MOD1 0x6a 6362306a36Sopenharmony_ci#define PCIE_PHY_TX1_MOD2 0x6c 6462306a36Sopenharmony_ci#define PCIE_PHY_TX1_MOD3 0x6e 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define PCIE_PHY_TX2_CTRL1 0x70 6762306a36Sopenharmony_ci#define PCIE_PHY_TX2_CTRL1_LOAD_EN BIT(4) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define PCIE_PHY_TX2_CTRL2 0x72 7062306a36Sopenharmony_ci#define PCIE_PHY_TX2_A_CTRL1 0x76 7162306a36Sopenharmony_ci#define PCIE_PHY_TX2_A_CTRL2 0x78 7262306a36Sopenharmony_ci#define PCIE_PHY_TX2_MOD1 0x7a 7362306a36Sopenharmony_ci#define PCIE_PHY_TX2_MOD2 0x7c 7462306a36Sopenharmony_ci#define PCIE_PHY_TX2_MOD3 0x7e 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define PCIE_PHY_RX1_CTRL1 0xa0 7762306a36Sopenharmony_ci#define PCIE_PHY_RX1_CTRL1_LOAD_EN BIT(1) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define PCIE_PHY_RX1_CTRL2 0xa2 8062306a36Sopenharmony_ci#define PCIE_PHY_RX1_CDR 0xa4 8162306a36Sopenharmony_ci#define PCIE_PHY_RX1_EI 0xa6 8262306a36Sopenharmony_ci#define PCIE_PHY_RX1_A_CTRL 0xaa 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct ltq_vrx200_pcie_phy_priv { 8562306a36Sopenharmony_ci struct phy *phy; 8662306a36Sopenharmony_ci unsigned int mode; 8762306a36Sopenharmony_ci struct device *dev; 8862306a36Sopenharmony_ci struct regmap *phy_regmap; 8962306a36Sopenharmony_ci struct regmap *rcu_regmap; 9062306a36Sopenharmony_ci struct clk *pdi_clk; 9162306a36Sopenharmony_ci struct clk *phy_clk; 9262306a36Sopenharmony_ci struct reset_control *phy_reset; 9362306a36Sopenharmony_ci struct reset_control *pcie_reset; 9462306a36Sopenharmony_ci u32 rcu_ahb_endian_offset; 9562306a36Sopenharmony_ci u32 rcu_ahb_endian_big_endian_mask; 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void ltq_vrx200_pcie_phy_common_setup(struct phy *phy) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* PLL Setting */ 10362306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL1, 0x120e); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* increase the bias reference voltage */ 10662306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL2, 0x39d7); 10762306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL3, 0x0900); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Endcnt */ 11062306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_RX1_EI, 0x0004); 11162306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_RX1_A_CTRL, 0x6803); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_TX1_CTRL1, 11462306a36Sopenharmony_ci PCIE_PHY_TX1_CTRL1_FORCE_EN, 11562306a36Sopenharmony_ci PCIE_PHY_TX1_CTRL1_FORCE_EN); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* predrv_ser_en */ 11862306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_A_CTRL2, 0x0706); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* ctrl_lim */ 12162306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_CTRL3, 0x1fff); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* ctrl */ 12462306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_A_CTRL1, 0x0810); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* predrv_ser_en */ 12762306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_TX2_A_CTRL2, 0x7f00, 12862306a36Sopenharmony_ci 0x4700); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* RTERM */ 13162306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_CTRL2, 0x2e00); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Improved 100MHz clock output */ 13462306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_CTRL2, 0x3096); 13562306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_A_CTRL2, 0x4707); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Reduced CDR BW to avoid glitches */ 13862306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_RX1_CDR, 0x0235); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void pcie_phy_36mhz_mode_setup(struct phy *phy) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL3, 14662306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_EN, 0x0000); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL3, 14962306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL3_EXT_MMD_DIV_RATIO_MASK, 0x0000); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL2, 15262306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL2_PLL_SDM_EN, 15362306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL2_PLL_SDM_EN); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL2, 15662306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL2_CONST_SDM_EN, 15762306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL2_CONST_SDM_EN); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL3, 16062306a36Sopenharmony_ci PCIE_PHY_PLL_A_CTRL3_MMD_MASK, 16162306a36Sopenharmony_ci FIELD_PREP(PCIE_PHY_PLL_A_CTRL3_MMD_MASK, 0x1)); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_A_CTRL2, 16462306a36Sopenharmony_ci PCIE_PHY_PLL_A_CTRL2_LF_MODE_EN, 0x0000); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* const_sdm */ 16762306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL1, 0x38e4); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, PCIE_PHY_PLL_CTRL2, 17062306a36Sopenharmony_ci PCIE_PHY_PLL_CTRL2_CONST_SDM_MASK, 17162306a36Sopenharmony_ci FIELD_PREP(PCIE_PHY_PLL_CTRL2_CONST_SDM_MASK, 17262306a36Sopenharmony_ci 0xee)); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* pllmod */ 17562306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL7, 0x0002); 17662306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL6, 0x3a04); 17762306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL5, 0xfae3); 17862306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_PLL_CTRL4, 0x1b72); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int ltq_vrx200_pcie_phy_wait_for_pll(struct phy *phy) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 18462306a36Sopenharmony_ci unsigned int tmp; 18562306a36Sopenharmony_ci int ret; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ret = regmap_read_poll_timeout(priv->phy_regmap, PCIE_PHY_PLL_STATUS, 18862306a36Sopenharmony_ci tmp, ((tmp & 0x0070) == 0x0070), 10, 18962306a36Sopenharmony_ci 10000); 19062306a36Sopenharmony_ci if (ret) { 19162306a36Sopenharmony_ci dev_err(priv->dev, "PLL Link timeout, PLL status = 0x%04x\n", 19262306a36Sopenharmony_ci tmp); 19362306a36Sopenharmony_ci return ret; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void ltq_vrx200_pcie_phy_apply_workarounds(struct phy *phy) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 20262306a36Sopenharmony_ci static const struct reg_default slices[] = { 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci .reg = PCIE_PHY_TX1_CTRL1, 20562306a36Sopenharmony_ci .def = PCIE_PHY_TX1_CTRL1_LOAD_EN, 20662306a36Sopenharmony_ci }, 20762306a36Sopenharmony_ci { 20862306a36Sopenharmony_ci .reg = PCIE_PHY_TX2_CTRL1, 20962306a36Sopenharmony_ci .def = PCIE_PHY_TX2_CTRL1_LOAD_EN, 21062306a36Sopenharmony_ci }, 21162306a36Sopenharmony_ci { 21262306a36Sopenharmony_ci .reg = PCIE_PHY_RX1_CTRL1, 21362306a36Sopenharmony_ci .def = PCIE_PHY_RX1_CTRL1_LOAD_EN, 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci }; 21662306a36Sopenharmony_ci int i; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(slices); i++) { 21962306a36Sopenharmony_ci /* enable load_en */ 22062306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, slices[i].reg, 22162306a36Sopenharmony_ci slices[i].def, slices[i].def); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci udelay(1); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* disable load_en */ 22662306a36Sopenharmony_ci regmap_update_bits(priv->phy_regmap, slices[i].reg, 22762306a36Sopenharmony_ci slices[i].def, 0x0); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 23162306a36Sopenharmony_ci /* TX2 modulation */ 23262306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD1, 0x1ffe); 23362306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD2, 0xfffe); 23462306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD3, 0x0601); 23562306a36Sopenharmony_ci usleep_range(1000, 2000); 23662306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX2_MOD3, 0x0001); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* TX1 modulation */ 23962306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD1, 0x1ffe); 24062306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD2, 0xfffe); 24162306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD3, 0x0601); 24262306a36Sopenharmony_ci usleep_range(1000, 2000); 24362306a36Sopenharmony_ci regmap_write(priv->phy_regmap, PCIE_PHY_TX1_MOD3, 0x0001); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int ltq_vrx200_pcie_phy_init(struct phy *phy) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 25062306a36Sopenharmony_ci int ret; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (of_device_is_big_endian(priv->dev->of_node)) 25362306a36Sopenharmony_ci regmap_update_bits(priv->rcu_regmap, 25462306a36Sopenharmony_ci priv->rcu_ahb_endian_offset, 25562306a36Sopenharmony_ci priv->rcu_ahb_endian_big_endian_mask, 25662306a36Sopenharmony_ci priv->rcu_ahb_endian_big_endian_mask); 25762306a36Sopenharmony_ci else 25862306a36Sopenharmony_ci regmap_update_bits(priv->rcu_regmap, 25962306a36Sopenharmony_ci priv->rcu_ahb_endian_offset, 26062306a36Sopenharmony_ci priv->rcu_ahb_endian_big_endian_mask, 0x0); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci ret = reset_control_assert(priv->phy_reset); 26362306a36Sopenharmony_ci if (ret) 26462306a36Sopenharmony_ci goto err; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci udelay(1); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci ret = reset_control_deassert(priv->phy_reset); 26962306a36Sopenharmony_ci if (ret) 27062306a36Sopenharmony_ci goto err; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci udelay(1); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ret = reset_control_deassert(priv->pcie_reset); 27562306a36Sopenharmony_ci if (ret) 27662306a36Sopenharmony_ci goto err_assert_phy_reset; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Make sure PHY PLL is stable */ 27962306a36Sopenharmony_ci usleep_range(20, 40); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cierr_assert_phy_reset: 28462306a36Sopenharmony_ci reset_control_assert(priv->phy_reset); 28562306a36Sopenharmony_cierr: 28662306a36Sopenharmony_ci return ret; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int ltq_vrx200_pcie_phy_exit(struct phy *phy) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 29262306a36Sopenharmony_ci int ret; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ret = reset_control_assert(priv->pcie_reset); 29562306a36Sopenharmony_ci if (ret) 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ret = reset_control_assert(priv->phy_reset); 29962306a36Sopenharmony_ci if (ret) 30062306a36Sopenharmony_ci return ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int ltq_vrx200_pcie_phy_power_on(struct phy *phy) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 30862306a36Sopenharmony_ci int ret; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Enable PDI to access PCIe PHY register */ 31162306a36Sopenharmony_ci ret = clk_prepare_enable(priv->pdi_clk); 31262306a36Sopenharmony_ci if (ret) 31362306a36Sopenharmony_ci goto err; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Configure PLL and PHY clock */ 31662306a36Sopenharmony_ci ltq_vrx200_pcie_phy_common_setup(phy); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci pcie_phy_36mhz_mode_setup(phy); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Enable the PCIe PHY and make PLL setting take effect */ 32162306a36Sopenharmony_ci ret = clk_prepare_enable(priv->phy_clk); 32262306a36Sopenharmony_ci if (ret) 32362306a36Sopenharmony_ci goto err_disable_pdi_clk; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* Check if we are in "startup ready" status */ 32662306a36Sopenharmony_ci ret = ltq_vrx200_pcie_phy_wait_for_pll(phy); 32762306a36Sopenharmony_ci if (ret) 32862306a36Sopenharmony_ci goto err_disable_phy_clk; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ltq_vrx200_pcie_phy_apply_workarounds(phy); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cierr_disable_phy_clk: 33562306a36Sopenharmony_ci clk_disable_unprepare(priv->phy_clk); 33662306a36Sopenharmony_cierr_disable_pdi_clk: 33762306a36Sopenharmony_ci clk_disable_unprepare(priv->pdi_clk); 33862306a36Sopenharmony_cierr: 33962306a36Sopenharmony_ci return ret; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int ltq_vrx200_pcie_phy_power_off(struct phy *phy) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = phy_get_drvdata(phy); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci clk_disable_unprepare(priv->phy_clk); 34762306a36Sopenharmony_ci clk_disable_unprepare(priv->pdi_clk); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic const struct phy_ops ltq_vrx200_pcie_phy_ops = { 35362306a36Sopenharmony_ci .init = ltq_vrx200_pcie_phy_init, 35462306a36Sopenharmony_ci .exit = ltq_vrx200_pcie_phy_exit, 35562306a36Sopenharmony_ci .power_on = ltq_vrx200_pcie_phy_power_on, 35662306a36Sopenharmony_ci .power_off = ltq_vrx200_pcie_phy_power_off, 35762306a36Sopenharmony_ci .owner = THIS_MODULE, 35862306a36Sopenharmony_ci}; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic struct phy *ltq_vrx200_pcie_phy_xlate(struct device *dev, 36162306a36Sopenharmony_ci struct of_phandle_args *args) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv = dev_get_drvdata(dev); 36462306a36Sopenharmony_ci unsigned int mode; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (args->args_count != 1) { 36762306a36Sopenharmony_ci dev_err(dev, "invalid number of arguments\n"); 36862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci mode = args->args[0]; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci switch (mode) { 37462306a36Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_36MHZ: 37562306a36Sopenharmony_ci priv->mode = mode; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_25MHZ: 37962306a36Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_25MHZ_SSC: 38062306a36Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_36MHZ_SSC: 38162306a36Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_100MHZ: 38262306a36Sopenharmony_ci case LANTIQ_PCIE_PHY_MODE_100MHZ_SSC: 38362306a36Sopenharmony_ci dev_err(dev, "PHY mode not implemented yet: %u\n", mode); 38462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci default: 38762306a36Sopenharmony_ci dev_err(dev, "invalid PHY mode %u\n", mode); 38862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return priv->phy; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int ltq_vrx200_pcie_phy_probe(struct platform_device *pdev) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci static const struct regmap_config regmap_config = { 39762306a36Sopenharmony_ci .reg_bits = 8, 39862306a36Sopenharmony_ci .val_bits = 16, 39962306a36Sopenharmony_ci .reg_stride = 2, 40062306a36Sopenharmony_ci .max_register = PCIE_PHY_RX1_A_CTRL, 40162306a36Sopenharmony_ci }; 40262306a36Sopenharmony_ci struct ltq_vrx200_pcie_phy_priv *priv; 40362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 40462306a36Sopenharmony_ci struct phy_provider *provider; 40562306a36Sopenharmony_ci void __iomem *base; 40662306a36Sopenharmony_ci int ret; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 40962306a36Sopenharmony_ci if (!priv) 41062306a36Sopenharmony_ci return -ENOMEM; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 41362306a36Sopenharmony_ci if (IS_ERR(base)) 41462306a36Sopenharmony_ci return PTR_ERR(base); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci priv->phy_regmap = devm_regmap_init_mmio(dev, base, ®map_config); 41762306a36Sopenharmony_ci if (IS_ERR(priv->phy_regmap)) 41862306a36Sopenharmony_ci return PTR_ERR(priv->phy_regmap); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci priv->rcu_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, 42162306a36Sopenharmony_ci "lantiq,rcu"); 42262306a36Sopenharmony_ci if (IS_ERR(priv->rcu_regmap)) 42362306a36Sopenharmony_ci return PTR_ERR(priv->rcu_regmap); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ret = device_property_read_u32(dev, "lantiq,rcu-endian-offset", 42662306a36Sopenharmony_ci &priv->rcu_ahb_endian_offset); 42762306a36Sopenharmony_ci if (ret) { 42862306a36Sopenharmony_ci dev_err(dev, 42962306a36Sopenharmony_ci "failed to parse the 'lantiq,rcu-endian-offset' property\n"); 43062306a36Sopenharmony_ci return ret; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ret = device_property_read_u32(dev, "lantiq,rcu-big-endian-mask", 43462306a36Sopenharmony_ci &priv->rcu_ahb_endian_big_endian_mask); 43562306a36Sopenharmony_ci if (ret) { 43662306a36Sopenharmony_ci dev_err(dev, 43762306a36Sopenharmony_ci "failed to parse the 'lantiq,rcu-big-endian-mask' property\n"); 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci priv->pdi_clk = devm_clk_get(dev, "pdi"); 44262306a36Sopenharmony_ci if (IS_ERR(priv->pdi_clk)) 44362306a36Sopenharmony_ci return PTR_ERR(priv->pdi_clk); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci priv->phy_clk = devm_clk_get(dev, "phy"); 44662306a36Sopenharmony_ci if (IS_ERR(priv->phy_clk)) 44762306a36Sopenharmony_ci return PTR_ERR(priv->phy_clk); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); 45062306a36Sopenharmony_ci if (IS_ERR(priv->phy_reset)) 45162306a36Sopenharmony_ci return PTR_ERR(priv->phy_reset); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci priv->pcie_reset = devm_reset_control_get_shared(dev, "pcie"); 45462306a36Sopenharmony_ci if (IS_ERR(priv->pcie_reset)) 45562306a36Sopenharmony_ci return PTR_ERR(priv->pcie_reset); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci priv->dev = dev; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci priv->phy = devm_phy_create(dev, dev->of_node, 46062306a36Sopenharmony_ci <q_vrx200_pcie_phy_ops); 46162306a36Sopenharmony_ci if (IS_ERR(priv->phy)) { 46262306a36Sopenharmony_ci dev_err(dev, "failed to create PHY\n"); 46362306a36Sopenharmony_ci return PTR_ERR(priv->phy); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci phy_set_drvdata(priv->phy, priv); 46762306a36Sopenharmony_ci dev_set_drvdata(dev, priv); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci provider = devm_of_phy_provider_register(dev, 47062306a36Sopenharmony_ci ltq_vrx200_pcie_phy_xlate); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(provider); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic const struct of_device_id ltq_vrx200_pcie_phy_of_match[] = { 47662306a36Sopenharmony_ci { .compatible = "lantiq,vrx200-pcie-phy", }, 47762306a36Sopenharmony_ci { .compatible = "lantiq,arx300-pcie-phy", }, 47862306a36Sopenharmony_ci { /* sentinel */ }, 47962306a36Sopenharmony_ci}; 48062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltq_vrx200_pcie_phy_of_match); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic struct platform_driver ltq_vrx200_pcie_phy_driver = { 48362306a36Sopenharmony_ci .probe = ltq_vrx200_pcie_phy_probe, 48462306a36Sopenharmony_ci .driver = { 48562306a36Sopenharmony_ci .name = "ltq-vrx200-pcie-phy", 48662306a36Sopenharmony_ci .of_match_table = ltq_vrx200_pcie_phy_of_match, 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci}; 48962306a36Sopenharmony_cimodule_platform_driver(ltq_vrx200_pcie_phy_driver); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ciMODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); 49262306a36Sopenharmony_ciMODULE_DESCRIPTION("Lantiq VRX200 and ARX300 PCIe PHY driver"); 49362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 494