162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCIe phy driver for Kirin 970 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 HiSilicon Electronics Co., Ltd. 662306a36Sopenharmony_ci * https://www.huawei.com 762306a36Sopenharmony_ci * Copyright (C) 2021 Huawei Technologies Co., Ltd. 862306a36Sopenharmony_ci * https://www.huawei.com 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Authors: 1162306a36Sopenharmony_ci * Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 1262306a36Sopenharmony_ci * Manivannan Sadhasivam <mani@kernel.org> 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Based on: 1562306a36Sopenharmony_ci * https://lore.kernel.org/lkml/4c9d6581478aa966698758c0420933f5defab4dd.1612335031.git.mchehab+huawei@kernel.org/ 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/bitfield.h> 1962306a36Sopenharmony_ci#include <linux/clk.h> 2062306a36Sopenharmony_ci#include <linux/gpio.h> 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/of_gpio.h> 2562306a36Sopenharmony_ci#include <linux/phy/phy.h> 2662306a36Sopenharmony_ci#include <linux/platform_device.h> 2762306a36Sopenharmony_ci#include <linux/regmap.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define AXI_CLK_FREQ 207500000 3062306a36Sopenharmony_ci#define REF_CLK_FREQ 100000000 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* PCIe CTRL registers */ 3362306a36Sopenharmony_ci#define SOC_PCIECTRL_CTRL7_ADDR 0x01c 3462306a36Sopenharmony_ci#define SOC_PCIECTRL_CTRL12_ADDR 0x030 3562306a36Sopenharmony_ci#define SOC_PCIECTRL_CTRL20_ADDR 0x050 3662306a36Sopenharmony_ci#define SOC_PCIECTRL_CTRL21_ADDR 0x054 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define PCIE_OUTPUT_PULL_BITS GENMASK(3, 0) 3962306a36Sopenharmony_ci#define SOC_PCIECTRL_CTRL20_2P_MEM_CTRL 0x02605550 4062306a36Sopenharmony_ci#define SOC_PCIECTRL_CTRL21_DEFAULT 0x20000070 4162306a36Sopenharmony_ci#define PCIE_PULL_UP_SYS_AUX_PWR_DET BIT(10) 4262306a36Sopenharmony_ci#define PCIE_OUTPUT_PULL_DOWN BIT(1) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* PCIe PHY registers */ 4562306a36Sopenharmony_ci#define SOC_PCIEPHY_CTRL0_ADDR 0x000 4662306a36Sopenharmony_ci#define SOC_PCIEPHY_CTRL1_ADDR 0x004 4762306a36Sopenharmony_ci#define SOC_PCIEPHY_CTRL38_ADDR 0x0098 4862306a36Sopenharmony_ci#define SOC_PCIEPHY_STATE0_ADDR 0x400 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1 0xc004 5162306a36Sopenharmony_ci#define SUP_DIG_LVL_OVRD_IN 0x003c 5262306a36Sopenharmony_ci#define LANEN_DIG_ASIC_TX_OVRD_IN_1 0x4008 5362306a36Sopenharmony_ci#define LANEN_DIG_ASIC_TX_OVRD_IN_2 0x400c 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define PCIEPHY_RESET_BIT BIT(17) 5662306a36Sopenharmony_ci#define PCIEPHY_PIPE_LINE0_RESET_BIT BIT(19) 5762306a36Sopenharmony_ci#define PCIE_TXDETECT_RX_FAIL BIT(2) 5862306a36Sopenharmony_ci#define PCIE_CLK_SOURCE BIT(8) 5962306a36Sopenharmony_ci#define PCIE_IS_CLOCK_STABLE BIT(19) 6062306a36Sopenharmony_ci#define PCIE_PULL_DOWN_PHY_TEST_POWERDOWN BIT(22) 6162306a36Sopenharmony_ci#define PCIE_DEASSERT_CONTROLLER_PERST BIT(2) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define EYEPARAM_NOCFG 0xffffffff 6462306a36Sopenharmony_ci#define EYE_PARM0_MASK GENMASK(8, 6) 6562306a36Sopenharmony_ci#define EYE_PARM1_MASK GENMASK(11, 8) 6662306a36Sopenharmony_ci#define EYE_PARM2_MASK GENMASK(5, 0) 6762306a36Sopenharmony_ci#define EYE_PARM3_MASK GENMASK(12, 7) 6862306a36Sopenharmony_ci#define EYE_PARM4_MASK GENMASK(14, 9) 6962306a36Sopenharmony_ci#define EYE_PARM0_EN BIT(9) 7062306a36Sopenharmony_ci#define EYE_PARM1_EN BIT(12) 7162306a36Sopenharmony_ci#define EYE_PARM2_EN BIT(6) 7262306a36Sopenharmony_ci#define EYE_PARM3_EN BIT(13) 7362306a36Sopenharmony_ci#define EYE_PARM4_EN BIT(15) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* hi3670 pciephy register */ 7662306a36Sopenharmony_ci#define APB_PHY_START_ADDR 0x40000 7762306a36Sopenharmony_ci#define SOC_PCIEPHY_MMC1PLL_CTRL1 0xc04 7862306a36Sopenharmony_ci#define SOC_PCIEPHY_MMC1PLL_CTRL16 0xC40 7962306a36Sopenharmony_ci#define SOC_PCIEPHY_MMC1PLL_CTRL17 0xC44 8062306a36Sopenharmony_ci#define SOC_PCIEPHY_MMC1PLL_CTRL20 0xC50 8162306a36Sopenharmony_ci#define SOC_PCIEPHY_MMC1PLL_CTRL21 0xC54 8262306a36Sopenharmony_ci#define SOC_PCIEPHY_MMC1PLL_STAT0 0xE00 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define CRGPERIPH_PEREN12 0x470 8562306a36Sopenharmony_ci#define CRGPERIPH_PERDIS12 0x474 8662306a36Sopenharmony_ci#define CRGPERIPH_PCIECTRL0 0x800 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define PCIE_FNPLL_FBDIV_MASK GENMASK(27, 16) 8962306a36Sopenharmony_ci#define PCIE_FNPLL_FRACDIV_MASK GENMASK(23, 0) 9062306a36Sopenharmony_ci#define PCIE_FNPLL_POSTDIV1_MASK GENMASK(10, 8) 9162306a36Sopenharmony_ci#define PCIE_FNPLL_POSTDIV2_MASK GENMASK(14, 12) 9262306a36Sopenharmony_ci#define PCIE_FNPLL_PLL_MODE_MASK BIT(25) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define PCIE_FNPLL_DLL_EN BIT(27) 9562306a36Sopenharmony_ci#define PCIE_FNPLL_FBDIV 0xd0 9662306a36Sopenharmony_ci#define PCIE_FNPLL_FRACDIV 0x555555 9762306a36Sopenharmony_ci#define PCIE_FNPLL_POSTDIV1 0x5 9862306a36Sopenharmony_ci#define PCIE_FNPLL_POSTDIV2 0x4 9962306a36Sopenharmony_ci#define PCIE_FNPLL_PLL_MODE 0x0 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define PCIE_PHY_MMC1PLL 0x20 10262306a36Sopenharmony_ci#define PCIE_PHY_CHOOSE_FNPLL BIT(27) 10362306a36Sopenharmony_ci#define PCIE_PHY_MMC1PLL_DISABLE BIT(0) 10462306a36Sopenharmony_ci#define PCIE_PHY_PCIEPL_BP BIT(16) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* define ie,oe cfg */ 10762306a36Sopenharmony_ci#define IO_OE_HARD_GT_MODE BIT(1) 10862306a36Sopenharmony_ci#define IO_IE_EN_HARD_BYPASS BIT(27) 10962306a36Sopenharmony_ci#define IO_OE_EN_HARD_BYPASS BIT(11) 11062306a36Sopenharmony_ci#define IO_HARD_CTRL_DEBOUNCE_BYPASS BIT(10) 11162306a36Sopenharmony_ci#define IO_OE_GT_MODE BIT(8) 11262306a36Sopenharmony_ci#define DEBOUNCE_WAITCFG_IN GENMASK(23, 20) 11362306a36Sopenharmony_ci#define DEBOUNCE_WAITCFG_OUT GENMASK(16, 13) 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define IO_HP_DEBOUNCE_GT (BIT(12) | BIT(15)) 11662306a36Sopenharmony_ci#define IO_PHYREF_SOFT_GT_MODE BIT(14) 11762306a36Sopenharmony_ci#define IO_REF_SOFT_GT_MODE BIT(13) 11862306a36Sopenharmony_ci#define IO_REF_HARD_GT_MODE BIT(0) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* noc power domain */ 12162306a36Sopenharmony_ci#define NOC_POWER_IDLEREQ_1 0x38c 12262306a36Sopenharmony_ci#define NOC_POWER_IDLE_1 0x394 12362306a36Sopenharmony_ci#define NOC_PW_MASK 0x10000 12462306a36Sopenharmony_ci#define NOC_PW_SET_BIT 0x1 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define NUM_EYEPARAM 5 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* info located in sysctrl */ 12962306a36Sopenharmony_ci#define SCTRL_PCIE_CMOS_OFFSET 0x60 13062306a36Sopenharmony_ci#define SCTRL_PCIE_CMOS_BIT 0x10 13162306a36Sopenharmony_ci#define SCTRL_PCIE_ISO_OFFSET 0x44 13262306a36Sopenharmony_ci#define SCTRL_PCIE_ISO_BIT 0x30 13362306a36Sopenharmony_ci#define SCTRL_PCIE_HPCLK_OFFSET 0x190 13462306a36Sopenharmony_ci#define SCTRL_PCIE_HPCLK_BIT 0x184000 13562306a36Sopenharmony_ci#define SCTRL_PCIE_OE_OFFSET 0x14a 13662306a36Sopenharmony_ci#define PCIE_DEBOUNCE_PARAM 0xf0f400 13762306a36Sopenharmony_ci#define PCIE_OE_BYPASS GENMASK(29, 28) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* peri_crg ctrl */ 14062306a36Sopenharmony_ci#define CRGCTRL_PCIE_ASSERT_OFFSET 0x88 14162306a36Sopenharmony_ci#define CRGCTRL_PCIE_ASSERT_BIT 0x8c000000 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define FNPLL_HAS_LOCKED BIT(4) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* Time for delay */ 14662306a36Sopenharmony_ci#define TIME_CMOS_MIN 100 14762306a36Sopenharmony_ci#define TIME_CMOS_MAX 105 14862306a36Sopenharmony_ci#define PIPE_CLK_STABLE_TIME 100 14962306a36Sopenharmony_ci#define PLL_CTRL_WAIT_TIME 200 15062306a36Sopenharmony_ci#define NOC_POWER_TIME 100 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct hi3670_pcie_phy { 15362306a36Sopenharmony_ci struct device *dev; 15462306a36Sopenharmony_ci void __iomem *base; 15562306a36Sopenharmony_ci struct regmap *apb; 15662306a36Sopenharmony_ci struct regmap *crgctrl; 15762306a36Sopenharmony_ci struct regmap *sysctrl; 15862306a36Sopenharmony_ci struct regmap *pmctrl; 15962306a36Sopenharmony_ci struct clk *apb_sys_clk; 16062306a36Sopenharmony_ci struct clk *apb_phy_clk; 16162306a36Sopenharmony_ci struct clk *phy_ref_clk; 16262306a36Sopenharmony_ci struct clk *aclk; 16362306a36Sopenharmony_ci struct clk *aux_clk; 16462306a36Sopenharmony_ci u32 eye_param[NUM_EYEPARAM]; 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* Registers in PCIePHY */ 16862306a36Sopenharmony_cistatic inline void hi3670_apb_phy_writel(struct hi3670_pcie_phy *phy, u32 val, 16962306a36Sopenharmony_ci u32 reg) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci writel(val, phy->base + APB_PHY_START_ADDR + reg); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline u32 hi3670_apb_phy_readl(struct hi3670_pcie_phy *phy, u32 reg) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return readl(phy->base + APB_PHY_START_ADDR + reg); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic inline void hi3670_apb_phy_updatel(struct hi3670_pcie_phy *phy, 18062306a36Sopenharmony_ci u32 val, u32 mask, u32 reg) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci u32 regval; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci regval = hi3670_apb_phy_readl(phy, reg); 18562306a36Sopenharmony_ci regval &= ~mask; 18662306a36Sopenharmony_ci regval |= val; 18762306a36Sopenharmony_ci hi3670_apb_phy_writel(phy, regval, reg); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic inline void kirin_apb_natural_phy_writel(struct hi3670_pcie_phy *phy, 19162306a36Sopenharmony_ci u32 val, u32 reg) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci writel(val, phy->base + reg); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic inline u32 kirin_apb_natural_phy_readl(struct hi3670_pcie_phy *phy, 19762306a36Sopenharmony_ci u32 reg) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci return readl(phy->base + reg); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void hi3670_pcie_phy_oe_enable(struct hi3670_pcie_phy *phy, bool enable) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci u32 val; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci regmap_read(phy->sysctrl, SCTRL_PCIE_OE_OFFSET, &val); 20762306a36Sopenharmony_ci val |= PCIE_DEBOUNCE_PARAM; 20862306a36Sopenharmony_ci if (enable) 20962306a36Sopenharmony_ci val &= ~PCIE_OE_BYPASS; 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci val |= PCIE_OE_BYPASS; 21262306a36Sopenharmony_ci regmap_write(phy->sysctrl, SCTRL_PCIE_OE_OFFSET, val); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void hi3670_pcie_get_eyeparam(struct hi3670_pcie_phy *phy) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct device *dev = phy->dev; 21862306a36Sopenharmony_ci struct device_node *np; 21962306a36Sopenharmony_ci int ret, i; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci np = dev->of_node; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = of_property_read_u32_array(np, "hisilicon,eye-diagram-param", 22462306a36Sopenharmony_ci phy->eye_param, NUM_EYEPARAM); 22562306a36Sopenharmony_ci if (!ret) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* There's no optional eye_param property. Set array to default */ 22962306a36Sopenharmony_ci for (i = 0; i < NUM_EYEPARAM; i++) 23062306a36Sopenharmony_ci phy->eye_param[i] = EYEPARAM_NOCFG; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void hi3670_pcie_set_eyeparam(struct hi3670_pcie_phy *phy) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci u32 val; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci val = kirin_apb_natural_phy_readl(phy, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (phy->eye_param[1] != EYEPARAM_NOCFG) { 24062306a36Sopenharmony_ci val &= ~EYE_PARM1_MASK; 24162306a36Sopenharmony_ci val |= FIELD_PREP(EYE_PARM1_MASK, phy->eye_param[1]); 24262306a36Sopenharmony_ci val |= EYE_PARM1_EN; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci kirin_apb_natural_phy_writel(phy, val, 24562306a36Sopenharmony_ci RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci val = kirin_apb_natural_phy_readl(phy, LANEN_DIG_ASIC_TX_OVRD_IN_2); 24862306a36Sopenharmony_ci val &= ~(EYE_PARM2_MASK | EYE_PARM3_MASK); 24962306a36Sopenharmony_ci if (phy->eye_param[2] != EYEPARAM_NOCFG) { 25062306a36Sopenharmony_ci val |= FIELD_PREP(EYE_PARM2_MASK, phy->eye_param[2]); 25162306a36Sopenharmony_ci val |= EYE_PARM2_EN; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (phy->eye_param[3] != EYEPARAM_NOCFG) { 25562306a36Sopenharmony_ci val |= FIELD_PREP(EYE_PARM3_MASK, phy->eye_param[3]); 25662306a36Sopenharmony_ci val |= EYE_PARM3_EN; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci kirin_apb_natural_phy_writel(phy, val, LANEN_DIG_ASIC_TX_OVRD_IN_2); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci val = kirin_apb_natural_phy_readl(phy, SUP_DIG_LVL_OVRD_IN); 26262306a36Sopenharmony_ci if (phy->eye_param[0] != EYEPARAM_NOCFG) { 26362306a36Sopenharmony_ci val &= ~EYE_PARM0_MASK; 26462306a36Sopenharmony_ci val |= FIELD_PREP(EYE_PARM0_MASK, phy->eye_param[0]); 26562306a36Sopenharmony_ci val |= EYE_PARM0_EN; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci kirin_apb_natural_phy_writel(phy, val, SUP_DIG_LVL_OVRD_IN); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci val = kirin_apb_natural_phy_readl(phy, LANEN_DIG_ASIC_TX_OVRD_IN_1); 27062306a36Sopenharmony_ci if (phy->eye_param[4] != EYEPARAM_NOCFG) { 27162306a36Sopenharmony_ci val &= ~EYE_PARM4_MASK; 27262306a36Sopenharmony_ci val |= FIELD_PREP(EYE_PARM4_MASK, phy->eye_param[4]); 27362306a36Sopenharmony_ci val |= EYE_PARM4_EN; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci kirin_apb_natural_phy_writel(phy, val, LANEN_DIG_ASIC_TX_OVRD_IN_1); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void hi3670_pcie_natural_cfg(struct hi3670_pcie_phy *phy) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci u32 val; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* change 2p mem_ctrl */ 28362306a36Sopenharmony_ci regmap_write(phy->apb, SOC_PCIECTRL_CTRL20_ADDR, 28462306a36Sopenharmony_ci SOC_PCIECTRL_CTRL20_2P_MEM_CTRL); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci regmap_read(phy->apb, SOC_PCIECTRL_CTRL7_ADDR, &val); 28762306a36Sopenharmony_ci val |= PCIE_PULL_UP_SYS_AUX_PWR_DET; 28862306a36Sopenharmony_ci regmap_write(phy->apb, SOC_PCIECTRL_CTRL7_ADDR, val); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* output, pull down */ 29162306a36Sopenharmony_ci regmap_read(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, &val); 29262306a36Sopenharmony_ci val &= ~PCIE_OUTPUT_PULL_BITS; 29362306a36Sopenharmony_ci val |= PCIE_OUTPUT_PULL_DOWN; 29462306a36Sopenharmony_ci regmap_write(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* Handle phy_reset and lane0_reset to HW */ 29762306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, PCIEPHY_RESET_BIT, 29862306a36Sopenharmony_ci PCIEPHY_PIPE_LINE0_RESET_BIT | PCIEPHY_RESET_BIT, 29962306a36Sopenharmony_ci SOC_PCIEPHY_CTRL1_ADDR); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* fix chip bug: TxDetectRx fail */ 30262306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, PCIE_TXDETECT_RX_FAIL, PCIE_TXDETECT_RX_FAIL, 30362306a36Sopenharmony_ci SOC_PCIEPHY_CTRL38_ADDR); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void hi3670_pcie_pll_init(struct hi3670_pcie_phy *phy) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, PCIE_PHY_CHOOSE_FNPLL, PCIE_PHY_CHOOSE_FNPLL, 30962306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL1); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 31262306a36Sopenharmony_ci FIELD_PREP(PCIE_FNPLL_FBDIV_MASK, PCIE_FNPLL_FBDIV), 31362306a36Sopenharmony_ci PCIE_FNPLL_FBDIV_MASK, 31462306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL16); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 31762306a36Sopenharmony_ci FIELD_PREP(PCIE_FNPLL_FRACDIV_MASK, PCIE_FNPLL_FRACDIV), 31862306a36Sopenharmony_ci PCIE_FNPLL_FRACDIV_MASK, SOC_PCIEPHY_MMC1PLL_CTRL17); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 32162306a36Sopenharmony_ci PCIE_FNPLL_DLL_EN | 32262306a36Sopenharmony_ci FIELD_PREP(PCIE_FNPLL_POSTDIV1_MASK, PCIE_FNPLL_POSTDIV1) | 32362306a36Sopenharmony_ci FIELD_PREP(PCIE_FNPLL_POSTDIV2_MASK, PCIE_FNPLL_POSTDIV2) | 32462306a36Sopenharmony_ci FIELD_PREP(PCIE_FNPLL_PLL_MODE_MASK, PCIE_FNPLL_PLL_MODE), 32562306a36Sopenharmony_ci PCIE_FNPLL_POSTDIV1_MASK | 32662306a36Sopenharmony_ci PCIE_FNPLL_POSTDIV2_MASK | 32762306a36Sopenharmony_ci PCIE_FNPLL_PLL_MODE_MASK | PCIE_FNPLL_DLL_EN, 32862306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL20); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci hi3670_apb_phy_writel(phy, PCIE_PHY_MMC1PLL, 33162306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL21); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int hi3670_pcie_pll_ctrl(struct hi3670_pcie_phy *phy, bool enable) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct device *dev = phy->dev; 33762306a36Sopenharmony_ci u32 val; 33862306a36Sopenharmony_ci int time = PLL_CTRL_WAIT_TIME; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (enable) { 34162306a36Sopenharmony_ci /* pd = 0 */ 34262306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 0, PCIE_PHY_MMC1PLL_DISABLE, 34362306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL16); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* choose FNPLL */ 34662306a36Sopenharmony_ci val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_MMC1PLL_STAT0); 34762306a36Sopenharmony_ci while (!(val & FNPLL_HAS_LOCKED)) { 34862306a36Sopenharmony_ci if (!time) { 34962306a36Sopenharmony_ci dev_err(dev, "wait for pll_lock timeout\n"); 35062306a36Sopenharmony_ci return -EINVAL; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci time--; 35362306a36Sopenharmony_ci udelay(1); 35462306a36Sopenharmony_ci val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_MMC1PLL_STAT0); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 0, PCIE_PHY_PCIEPL_BP, 35862306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL20); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci } else { 36162306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 36262306a36Sopenharmony_ci PCIE_PHY_MMC1PLL_DISABLE, 36362306a36Sopenharmony_ci PCIE_PHY_MMC1PLL_DISABLE, 36462306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL16); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, PCIE_PHY_PCIEPL_BP, 36762306a36Sopenharmony_ci PCIE_PHY_PCIEPL_BP, 36862306a36Sopenharmony_ci SOC_PCIEPHY_MMC1PLL_CTRL20); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void hi3670_pcie_hp_debounce_gt(struct hi3670_pcie_phy *phy, bool open) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci if (open) 37762306a36Sopenharmony_ci /* gt_clk_pcie_hp/gt_clk_pcie_debounce open */ 37862306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PEREN12, 37962306a36Sopenharmony_ci IO_HP_DEBOUNCE_GT); 38062306a36Sopenharmony_ci else 38162306a36Sopenharmony_ci /* gt_clk_pcie_hp/gt_clk_pcie_debounce close */ 38262306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, 38362306a36Sopenharmony_ci IO_HP_DEBOUNCE_GT); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void hi3670_pcie_phyref_gt(struct hi3670_pcie_phy *phy, bool open) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci unsigned int val; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (open) 39362306a36Sopenharmony_ci val &= ~IO_OE_HARD_GT_MODE; /* enable hard gt mode */ 39462306a36Sopenharmony_ci else 39562306a36Sopenharmony_ci val |= IO_OE_HARD_GT_MODE; /* disable hard gt mode */ 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* disable soft gt mode */ 40062306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, IO_PHYREF_SOFT_GT_MODE); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void hi3670_pcie_oe_ctrl(struct hi3670_pcie_phy *phy, bool en_flag) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci unsigned int val; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* set ie cfg */ 41062306a36Sopenharmony_ci val |= IO_IE_EN_HARD_BYPASS; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* set oe cfg */ 41362306a36Sopenharmony_ci val &= ~IO_HARD_CTRL_DEBOUNCE_BYPASS; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* set phy_debounce in&out time */ 41662306a36Sopenharmony_ci val |= (DEBOUNCE_WAITCFG_IN | DEBOUNCE_WAITCFG_OUT); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* select oe_gt_mode */ 41962306a36Sopenharmony_ci val |= IO_OE_GT_MODE; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (en_flag) 42262306a36Sopenharmony_ci val &= ~IO_OE_EN_HARD_BYPASS; 42362306a36Sopenharmony_ci else 42462306a36Sopenharmony_ci val |= IO_OE_EN_HARD_BYPASS; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic void hi3670_pcie_ioref_gt(struct hi3670_pcie_phy *phy, bool open) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci unsigned int val; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (open) { 43462306a36Sopenharmony_ci regmap_write(phy->apb, SOC_PCIECTRL_CTRL21_ADDR, 43562306a36Sopenharmony_ci SOC_PCIECTRL_CTRL21_DEFAULT); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci hi3670_pcie_oe_ctrl(phy, true); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* en hard gt mode */ 44062306a36Sopenharmony_ci regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 44162306a36Sopenharmony_ci val &= ~IO_REF_HARD_GT_MODE; 44262306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* disable soft gt mode */ 44562306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, 44662306a36Sopenharmony_ci IO_REF_SOFT_GT_MODE); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci /* disable hard gt mode */ 45062306a36Sopenharmony_ci regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 45162306a36Sopenharmony_ci val |= IO_REF_HARD_GT_MODE; 45262306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* disable soft gt mode */ 45562306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, 45662306a36Sopenharmony_ci IO_REF_SOFT_GT_MODE); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci hi3670_pcie_oe_ctrl(phy, false); 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int hi3670_pcie_allclk_ctrl(struct hi3670_pcie_phy *phy, bool clk_on) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct device *dev = phy->dev; 46562306a36Sopenharmony_ci int ret = 0; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!clk_on) 46862306a36Sopenharmony_ci goto close_clocks; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* choose 100MHz clk src: Bit[8]==1 pad, Bit[8]==0 pll */ 47162306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 0, PCIE_CLK_SOURCE, 47262306a36Sopenharmony_ci SOC_PCIEPHY_CTRL1_ADDR); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci hi3670_pcie_pll_init(phy); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci ret = hi3670_pcie_pll_ctrl(phy, true); 47762306a36Sopenharmony_ci if (ret) { 47862306a36Sopenharmony_ci dev_err(dev, "Failed to enable pll\n"); 47962306a36Sopenharmony_ci return -EINVAL; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci hi3670_pcie_hp_debounce_gt(phy, true); 48262306a36Sopenharmony_ci hi3670_pcie_phyref_gt(phy, true); 48362306a36Sopenharmony_ci hi3670_pcie_ioref_gt(phy, true); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ret = clk_set_rate(phy->aclk, AXI_CLK_FREQ); 48662306a36Sopenharmony_ci if (ret) { 48762306a36Sopenharmony_ci dev_err(dev, "Failed to set rate\n"); 48862306a36Sopenharmony_ci goto close_clocks; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ciclose_clocks: 49462306a36Sopenharmony_ci hi3670_pcie_ioref_gt(phy, false); 49562306a36Sopenharmony_ci hi3670_pcie_phyref_gt(phy, false); 49662306a36Sopenharmony_ci hi3670_pcie_hp_debounce_gt(phy, false); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci hi3670_pcie_pll_ctrl(phy, false); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return ret; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic bool is_pipe_clk_stable(struct hi3670_pcie_phy *phy) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct device *dev = phy->dev; 50662306a36Sopenharmony_ci u32 val; 50762306a36Sopenharmony_ci u32 time = PIPE_CLK_STABLE_TIME; 50862306a36Sopenharmony_ci u32 pipe_clk_stable = PCIE_IS_CLOCK_STABLE; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_STATE0_ADDR); 51162306a36Sopenharmony_ci while (val & pipe_clk_stable) { 51262306a36Sopenharmony_ci mdelay(1); 51362306a36Sopenharmony_ci if (!time) { 51462306a36Sopenharmony_ci dev_err(dev, "PIPE clk is not stable\n"); 51562306a36Sopenharmony_ci return false; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci time--; 51862306a36Sopenharmony_ci val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_STATE0_ADDR); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return true; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int hi3670_pcie_noc_power(struct hi3670_pcie_phy *phy, bool enable) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct device *dev = phy->dev; 52762306a36Sopenharmony_ci u32 time = NOC_POWER_TIME; 52862306a36Sopenharmony_ci unsigned int val = NOC_PW_MASK; 52962306a36Sopenharmony_ci int rst; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (enable) 53262306a36Sopenharmony_ci val = NOC_PW_MASK | NOC_PW_SET_BIT; 53362306a36Sopenharmony_ci else 53462306a36Sopenharmony_ci val = NOC_PW_MASK; 53562306a36Sopenharmony_ci rst = enable ? 1 : 0; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci regmap_write(phy->pmctrl, NOC_POWER_IDLEREQ_1, val); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci time = NOC_POWER_TIME; 54062306a36Sopenharmony_ci regmap_read(phy->pmctrl, NOC_POWER_IDLE_1, &val); 54162306a36Sopenharmony_ci while ((val & NOC_PW_SET_BIT) != rst) { 54262306a36Sopenharmony_ci udelay(10); 54362306a36Sopenharmony_ci if (!time) { 54462306a36Sopenharmony_ci dev_err(dev, "Failed to reverse noc power-status\n"); 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci time--; 54862306a36Sopenharmony_ci regmap_read(phy->pmctrl, NOC_POWER_IDLE_1, &val); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic int hi3670_pcie_get_resources_from_pcie(struct hi3670_pcie_phy *phy) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct device_node *pcie_port; 55762306a36Sopenharmony_ci struct device *dev = phy->dev; 55862306a36Sopenharmony_ci struct device *pcie_dev; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci pcie_port = of_get_child_by_name(dev->parent->of_node, "pcie"); 56162306a36Sopenharmony_ci if (!pcie_port) { 56262306a36Sopenharmony_ci dev_err(dev, "no pcie node found in %s\n", 56362306a36Sopenharmony_ci dev->parent->of_node->full_name); 56462306a36Sopenharmony_ci return -ENODEV; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci pcie_dev = bus_find_device_by_of_node(&platform_bus_type, pcie_port); 56862306a36Sopenharmony_ci if (!pcie_dev) { 56962306a36Sopenharmony_ci dev_err(dev, "Didn't find pcie device\n"); 57062306a36Sopenharmony_ci return -ENODEV; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * We might just use NULL instead of the APB name, as the 57562306a36Sopenharmony_ci * pcie-kirin currently registers directly just one regmap (although 57662306a36Sopenharmony_ci * the DWC driver register other regmaps). 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * Yet, it sounds safer to warrant that it will be accessing the 57962306a36Sopenharmony_ci * right regmap. So, let's use the named version. 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci phy->apb = dev_get_regmap(pcie_dev, "kirin_pcie_apb"); 58262306a36Sopenharmony_ci if (!phy->apb) { 58362306a36Sopenharmony_ci dev_err(dev, "Failed to get APB regmap\n"); 58462306a36Sopenharmony_ci return -ENODEV; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return 0; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int kirin_pcie_clk_ctrl(struct hi3670_pcie_phy *phy, bool enable) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci int ret = 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!enable) 59562306a36Sopenharmony_ci goto close_clk; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ret = clk_set_rate(phy->phy_ref_clk, REF_CLK_FREQ); 59862306a36Sopenharmony_ci if (ret) 59962306a36Sopenharmony_ci return ret; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci ret = clk_prepare_enable(phy->phy_ref_clk); 60262306a36Sopenharmony_ci if (ret) 60362306a36Sopenharmony_ci return ret; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci ret = clk_prepare_enable(phy->apb_sys_clk); 60662306a36Sopenharmony_ci if (ret) 60762306a36Sopenharmony_ci goto apb_sys_fail; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci ret = clk_prepare_enable(phy->apb_phy_clk); 61062306a36Sopenharmony_ci if (ret) 61162306a36Sopenharmony_ci goto apb_phy_fail; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ret = clk_prepare_enable(phy->aclk); 61462306a36Sopenharmony_ci if (ret) 61562306a36Sopenharmony_ci goto aclk_fail; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = clk_prepare_enable(phy->aux_clk); 61862306a36Sopenharmony_ci if (ret) 61962306a36Sopenharmony_ci goto aux_clk_fail; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ciclose_clk: 62462306a36Sopenharmony_ci clk_disable_unprepare(phy->aux_clk); 62562306a36Sopenharmony_ciaux_clk_fail: 62662306a36Sopenharmony_ci clk_disable_unprepare(phy->aclk); 62762306a36Sopenharmony_ciaclk_fail: 62862306a36Sopenharmony_ci clk_disable_unprepare(phy->apb_phy_clk); 62962306a36Sopenharmony_ciapb_phy_fail: 63062306a36Sopenharmony_ci clk_disable_unprepare(phy->apb_sys_clk); 63162306a36Sopenharmony_ciapb_sys_fail: 63262306a36Sopenharmony_ci clk_disable_unprepare(phy->phy_ref_clk); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return ret; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int hi3670_pcie_phy_init(struct phy *generic_phy) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct hi3670_pcie_phy *phy = phy_get_drvdata(generic_phy); 64062306a36Sopenharmony_ci int ret; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* 64362306a36Sopenharmony_ci * The code under hi3670_pcie_get_resources_from_pcie() need to 64462306a36Sopenharmony_ci * access the reset-gpios and the APB registers, both from the 64562306a36Sopenharmony_ci * pcie-kirin driver. 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * The APB is obtained via the pcie driver's regmap 64862306a36Sopenharmony_ci * Such kind of resource can only be obtained during the PCIe 64962306a36Sopenharmony_ci * power_on sequence, as the code inside pcie-kirin needs to 65062306a36Sopenharmony_ci * be already probed, as it needs to register the APB regmap. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci ret = hi3670_pcie_get_resources_from_pcie(phy); 65462306a36Sopenharmony_ci if (ret) 65562306a36Sopenharmony_ci return ret; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int hi3670_pcie_phy_power_on(struct phy *generic_phy) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct hi3670_pcie_phy *phy = phy_get_drvdata(generic_phy); 66362306a36Sopenharmony_ci int val, ret; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Power supply for Host */ 66662306a36Sopenharmony_ci regmap_write(phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, SCTRL_PCIE_CMOS_BIT); 66762306a36Sopenharmony_ci usleep_range(TIME_CMOS_MIN, TIME_CMOS_MAX); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci hi3670_pcie_phy_oe_enable(phy, true); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ret = kirin_pcie_clk_ctrl(phy, true); 67262306a36Sopenharmony_ci if (ret) 67362306a36Sopenharmony_ci return ret; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* ISO disable, PCIeCtrl, PHY assert and clk gate clear */ 67662306a36Sopenharmony_ci regmap_write(phy->sysctrl, SCTRL_PCIE_ISO_OFFSET, SCTRL_PCIE_ISO_BIT); 67762306a36Sopenharmony_ci regmap_write(phy->crgctrl, CRGCTRL_PCIE_ASSERT_OFFSET, 67862306a36Sopenharmony_ci CRGCTRL_PCIE_ASSERT_BIT); 67962306a36Sopenharmony_ci regmap_write(phy->sysctrl, SCTRL_PCIE_HPCLK_OFFSET, 68062306a36Sopenharmony_ci SCTRL_PCIE_HPCLK_BIT); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci hi3670_pcie_natural_cfg(phy); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ret = hi3670_pcie_allclk_ctrl(phy, true); 68562306a36Sopenharmony_ci if (ret) 68662306a36Sopenharmony_ci goto disable_clks; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* pull down phy_test_powerdown signal */ 68962306a36Sopenharmony_ci hi3670_apb_phy_updatel(phy, 0, PCIE_PULL_DOWN_PHY_TEST_POWERDOWN, 69062306a36Sopenharmony_ci SOC_PCIEPHY_CTRL0_ADDR); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* deassert controller perst_n */ 69362306a36Sopenharmony_ci regmap_read(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, &val); 69462306a36Sopenharmony_ci val |= PCIE_DEASSERT_CONTROLLER_PERST; 69562306a36Sopenharmony_ci regmap_write(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val); 69662306a36Sopenharmony_ci udelay(10); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci ret = is_pipe_clk_stable(phy); 69962306a36Sopenharmony_ci if (!ret) 70062306a36Sopenharmony_ci goto disable_clks; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci hi3670_pcie_set_eyeparam(phy); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = hi3670_pcie_noc_power(phy, false); 70562306a36Sopenharmony_ci if (ret) 70662306a36Sopenharmony_ci goto disable_clks; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cidisable_clks: 71162306a36Sopenharmony_ci kirin_pcie_clk_ctrl(phy, false); 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int hi3670_pcie_phy_power_off(struct phy *generic_phy) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct hi3670_pcie_phy *phy = phy_get_drvdata(generic_phy); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci hi3670_pcie_phy_oe_enable(phy, false); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci hi3670_pcie_allclk_ctrl(phy, false); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* Drop power supply for Host */ 72462306a36Sopenharmony_ci regmap_write(phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, 0); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* 72762306a36Sopenharmony_ci * FIXME: The enabled clocks should be disabled here by calling 72862306a36Sopenharmony_ci * kirin_pcie_clk_ctrl(phy, false); 72962306a36Sopenharmony_ci * However, some clocks used at Kirin 970 should be marked as 73062306a36Sopenharmony_ci * CLK_IS_CRITICAL at clk-hi3670 driver, as powering such clocks off 73162306a36Sopenharmony_ci * cause an Asynchronous SError interrupt, which produces panic(). 73262306a36Sopenharmony_ci * While clk-hi3670 is not fixed, we cannot risk disabling clocks here. 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic const struct phy_ops hi3670_phy_ops = { 73962306a36Sopenharmony_ci .init = hi3670_pcie_phy_init, 74062306a36Sopenharmony_ci .power_on = hi3670_pcie_phy_power_on, 74162306a36Sopenharmony_ci .power_off = hi3670_pcie_phy_power_off, 74262306a36Sopenharmony_ci .owner = THIS_MODULE, 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int hi3670_pcie_phy_get_resources(struct hi3670_pcie_phy *phy, 74662306a36Sopenharmony_ci struct platform_device *pdev) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* syscon */ 75162306a36Sopenharmony_ci phy->crgctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-crgctrl"); 75262306a36Sopenharmony_ci if (IS_ERR(phy->crgctrl)) 75362306a36Sopenharmony_ci return PTR_ERR(phy->crgctrl); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci phy->sysctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-sctrl"); 75662306a36Sopenharmony_ci if (IS_ERR(phy->sysctrl)) 75762306a36Sopenharmony_ci return PTR_ERR(phy->sysctrl); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci phy->pmctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-pmctrl"); 76062306a36Sopenharmony_ci if (IS_ERR(phy->pmctrl)) 76162306a36Sopenharmony_ci return PTR_ERR(phy->pmctrl); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* clocks */ 76462306a36Sopenharmony_ci phy->phy_ref_clk = devm_clk_get(dev, "phy_ref"); 76562306a36Sopenharmony_ci if (IS_ERR(phy->phy_ref_clk)) 76662306a36Sopenharmony_ci return PTR_ERR(phy->phy_ref_clk); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci phy->aux_clk = devm_clk_get(dev, "aux"); 76962306a36Sopenharmony_ci if (IS_ERR(phy->aux_clk)) 77062306a36Sopenharmony_ci return PTR_ERR(phy->aux_clk); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci phy->apb_phy_clk = devm_clk_get(dev, "apb_phy"); 77362306a36Sopenharmony_ci if (IS_ERR(phy->apb_phy_clk)) 77462306a36Sopenharmony_ci return PTR_ERR(phy->apb_phy_clk); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci phy->apb_sys_clk = devm_clk_get(dev, "apb_sys"); 77762306a36Sopenharmony_ci if (IS_ERR(phy->apb_sys_clk)) 77862306a36Sopenharmony_ci return PTR_ERR(phy->apb_sys_clk); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci phy->aclk = devm_clk_get(dev, "aclk"); 78162306a36Sopenharmony_ci if (IS_ERR(phy->aclk)) 78262306a36Sopenharmony_ci return PTR_ERR(phy->aclk); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* registers */ 78562306a36Sopenharmony_ci phy->base = devm_platform_ioremap_resource(pdev, 0); 78662306a36Sopenharmony_ci if (IS_ERR(phy->base)) 78762306a36Sopenharmony_ci return PTR_ERR(phy->base); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci hi3670_pcie_get_eyeparam(phy); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic int hi3670_pcie_phy_probe(struct platform_device *pdev) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct phy_provider *phy_provider; 79762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 79862306a36Sopenharmony_ci struct hi3670_pcie_phy *phy; 79962306a36Sopenharmony_ci struct phy *generic_phy; 80062306a36Sopenharmony_ci int ret; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 80362306a36Sopenharmony_ci if (!phy) 80462306a36Sopenharmony_ci return -ENOMEM; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci phy->dev = dev; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci ret = hi3670_pcie_phy_get_resources(phy, pdev); 80962306a36Sopenharmony_ci if (ret) 81062306a36Sopenharmony_ci return ret; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci generic_phy = devm_phy_create(dev, dev->of_node, &hi3670_phy_ops); 81362306a36Sopenharmony_ci if (IS_ERR(generic_phy)) { 81462306a36Sopenharmony_ci dev_err(dev, "failed to create PHY\n"); 81562306a36Sopenharmony_ci return PTR_ERR(generic_phy); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci phy_set_drvdata(generic_phy, phy); 81962306a36Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic const struct of_device_id hi3670_pcie_phy_match[] = { 82562306a36Sopenharmony_ci { 82662306a36Sopenharmony_ci .compatible = "hisilicon,hi970-pcie-phy", 82762306a36Sopenharmony_ci }, 82862306a36Sopenharmony_ci {}, 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic struct platform_driver hi3670_pcie_phy_driver = { 83262306a36Sopenharmony_ci .probe = hi3670_pcie_phy_probe, 83362306a36Sopenharmony_ci .driver = { 83462306a36Sopenharmony_ci .of_match_table = hi3670_pcie_phy_match, 83562306a36Sopenharmony_ci .name = "hi3670_pcie_phy", 83662306a36Sopenharmony_ci .suppress_bind_attrs = true, 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci}; 83962306a36Sopenharmony_cibuiltin_platform_driver(hi3670_pcie_phy_driver); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, hi3670_pcie_phy_match); 84262306a36Sopenharmony_ciMODULE_DESCRIPTION("PCIe phy driver for Kirin 970"); 84362306a36Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); 84462306a36Sopenharmony_ciMODULE_AUTHOR("Manivannan Sadhasivam <mani@kernel.org>"); 84562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 846