1*73075011SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0 2*73075011SMauro Carvalho Chehab /* 3*73075011SMauro Carvalho Chehab * PCIe phy driver for Kirin 970 4*73075011SMauro Carvalho Chehab * 5*73075011SMauro Carvalho Chehab * Copyright (C) 2017 HiSilicon Electronics Co., Ltd. 6*73075011SMauro Carvalho Chehab * https://www.huawei.com 7*73075011SMauro Carvalho Chehab * Copyright (C) 2021 Huawei Technologies Co., Ltd. 8*73075011SMauro Carvalho Chehab * https://www.huawei.com 9*73075011SMauro Carvalho Chehab * 10*73075011SMauro Carvalho Chehab * Authors: 11*73075011SMauro Carvalho Chehab * Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 12*73075011SMauro Carvalho Chehab * Manivannan Sadhasivam <mani@kernel.org> 13*73075011SMauro Carvalho Chehab * 14*73075011SMauro Carvalho Chehab * Based on: 15*73075011SMauro Carvalho Chehab * https://lore.kernel.org/lkml/4c9d6581478aa966698758c0420933f5defab4dd.1612335031.git.mchehab+huawei@kernel.org/ 16*73075011SMauro Carvalho Chehab */ 17*73075011SMauro Carvalho Chehab 18*73075011SMauro Carvalho Chehab #include <linux/bitfield.h> 19*73075011SMauro Carvalho Chehab #include <linux/clk.h> 20*73075011SMauro Carvalho Chehab #include <linux/gpio.h> 21*73075011SMauro Carvalho Chehab #include <linux/kernel.h> 22*73075011SMauro Carvalho Chehab #include <linux/mfd/syscon.h> 23*73075011SMauro Carvalho Chehab #include <linux/module.h> 24*73075011SMauro Carvalho Chehab #include <linux/of_gpio.h> 25*73075011SMauro Carvalho Chehab #include <linux/phy/phy.h> 26*73075011SMauro Carvalho Chehab #include <linux/platform_device.h> 27*73075011SMauro Carvalho Chehab #include <linux/regmap.h> 28*73075011SMauro Carvalho Chehab 29*73075011SMauro Carvalho Chehab #define AXI_CLK_FREQ 207500000 30*73075011SMauro Carvalho Chehab #define REF_CLK_FREQ 100000000 31*73075011SMauro Carvalho Chehab 32*73075011SMauro Carvalho Chehab /* PCIe CTRL registers */ 33*73075011SMauro Carvalho Chehab #define SOC_PCIECTRL_CTRL7_ADDR 0x01c 34*73075011SMauro Carvalho Chehab #define SOC_PCIECTRL_CTRL12_ADDR 0x030 35*73075011SMauro Carvalho Chehab #define SOC_PCIECTRL_CTRL20_ADDR 0x050 36*73075011SMauro Carvalho Chehab #define SOC_PCIECTRL_CTRL21_ADDR 0x054 37*73075011SMauro Carvalho Chehab 38*73075011SMauro Carvalho Chehab #define PCIE_OUTPUT_PULL_BITS GENMASK(3, 0) 39*73075011SMauro Carvalho Chehab #define SOC_PCIECTRL_CTRL20_2P_MEM_CTRL 0x02605550 40*73075011SMauro Carvalho Chehab #define SOC_PCIECTRL_CTRL21_DEFAULT 0x20000070 41*73075011SMauro Carvalho Chehab #define PCIE_PULL_UP_SYS_AUX_PWR_DET BIT(10) 42*73075011SMauro Carvalho Chehab #define PCIE_OUTPUT_PULL_DOWN BIT(1) 43*73075011SMauro Carvalho Chehab 44*73075011SMauro Carvalho Chehab /* PCIe PHY registers */ 45*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_CTRL0_ADDR 0x000 46*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_CTRL1_ADDR 0x004 47*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_CTRL38_ADDR 0x0098 48*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_STATE0_ADDR 0x400 49*73075011SMauro Carvalho Chehab 50*73075011SMauro Carvalho Chehab #define RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1 0xc004 51*73075011SMauro Carvalho Chehab #define SUP_DIG_LVL_OVRD_IN 0x003c 52*73075011SMauro Carvalho Chehab #define LANEN_DIG_ASIC_TX_OVRD_IN_1 0x4008 53*73075011SMauro Carvalho Chehab #define LANEN_DIG_ASIC_TX_OVRD_IN_2 0x400c 54*73075011SMauro Carvalho Chehab 55*73075011SMauro Carvalho Chehab #define PCIEPHY_RESET_BIT BIT(17) 56*73075011SMauro Carvalho Chehab #define PCIEPHY_PIPE_LINE0_RESET_BIT BIT(19) 57*73075011SMauro Carvalho Chehab #define PCIE_TXDETECT_RX_FAIL BIT(2) 58*73075011SMauro Carvalho Chehab #define PCIE_CLK_SOURCE BIT(8) 59*73075011SMauro Carvalho Chehab #define PCIE_IS_CLOCK_STABLE BIT(19) 60*73075011SMauro Carvalho Chehab #define PCIE_PULL_DOWN_PHY_TEST_POWERDOWN BIT(22) 61*73075011SMauro Carvalho Chehab #define PCIE_DEASSERT_CONTROLLER_PERST BIT(2) 62*73075011SMauro Carvalho Chehab 63*73075011SMauro Carvalho Chehab #define EYEPARAM_NOCFG 0xffffffff 64*73075011SMauro Carvalho Chehab #define EYE_PARM0_MASK GENMASK(8, 6) 65*73075011SMauro Carvalho Chehab #define EYE_PARM1_MASK GENMASK(11, 8) 66*73075011SMauro Carvalho Chehab #define EYE_PARM2_MASK GENMASK(5, 0) 67*73075011SMauro Carvalho Chehab #define EYE_PARM3_MASK GENMASK(12, 7) 68*73075011SMauro Carvalho Chehab #define EYE_PARM4_MASK GENMASK(14, 9) 69*73075011SMauro Carvalho Chehab #define EYE_PARM0_EN BIT(9) 70*73075011SMauro Carvalho Chehab #define EYE_PARM1_EN BIT(12) 71*73075011SMauro Carvalho Chehab #define EYE_PARM2_EN BIT(6) 72*73075011SMauro Carvalho Chehab #define EYE_PARM3_EN BIT(13) 73*73075011SMauro Carvalho Chehab #define EYE_PARM4_EN BIT(15) 74*73075011SMauro Carvalho Chehab 75*73075011SMauro Carvalho Chehab /* hi3670 pciephy register */ 76*73075011SMauro Carvalho Chehab #define APB_PHY_START_ADDR 0x40000 77*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_MMC1PLL_CTRL1 0xc04 78*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_MMC1PLL_CTRL16 0xC40 79*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_MMC1PLL_CTRL17 0xC44 80*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_MMC1PLL_CTRL20 0xC50 81*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_MMC1PLL_CTRL21 0xC54 82*73075011SMauro Carvalho Chehab #define SOC_PCIEPHY_MMC1PLL_STAT0 0xE00 83*73075011SMauro Carvalho Chehab 84*73075011SMauro Carvalho Chehab #define CRGPERIPH_PEREN12 0x470 85*73075011SMauro Carvalho Chehab #define CRGPERIPH_PERDIS12 0x474 86*73075011SMauro Carvalho Chehab #define CRGPERIPH_PCIECTRL0 0x800 87*73075011SMauro Carvalho Chehab 88*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_FBDIV_MASK GENMASK(27, 16) 89*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_FRACDIV_MASK GENMASK(23, 0) 90*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_POSTDIV1_MASK GENMASK(10, 8) 91*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_POSTDIV2_MASK GENMASK(14, 12) 92*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_PLL_MODE_MASK BIT(25) 93*73075011SMauro Carvalho Chehab 94*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_DLL_EN BIT(27) 95*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_FBDIV 0xd0 96*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_FRACDIV 0x555555 97*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_POSTDIV1 0x5 98*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_POSTDIV2 0x4 99*73075011SMauro Carvalho Chehab #define PCIE_FNPLL_PLL_MODE 0x0 100*73075011SMauro Carvalho Chehab 101*73075011SMauro Carvalho Chehab #define PCIE_PHY_MMC1PLL 0x20 102*73075011SMauro Carvalho Chehab #define PCIE_PHY_CHOOSE_FNPLL BIT(27) 103*73075011SMauro Carvalho Chehab #define PCIE_PHY_MMC1PLL_DISABLE BIT(0) 104*73075011SMauro Carvalho Chehab #define PCIE_PHY_PCIEPL_BP BIT(16) 105*73075011SMauro Carvalho Chehab 106*73075011SMauro Carvalho Chehab /* define ie,oe cfg */ 107*73075011SMauro Carvalho Chehab #define IO_OE_HARD_GT_MODE BIT(1) 108*73075011SMauro Carvalho Chehab #define IO_IE_EN_HARD_BYPASS BIT(27) 109*73075011SMauro Carvalho Chehab #define IO_OE_EN_HARD_BYPASS BIT(11) 110*73075011SMauro Carvalho Chehab #define IO_HARD_CTRL_DEBOUNCE_BYPASS BIT(10) 111*73075011SMauro Carvalho Chehab #define IO_OE_GT_MODE BIT(8) 112*73075011SMauro Carvalho Chehab #define DEBOUNCE_WAITCFG_IN GENMASK(23, 20) 113*73075011SMauro Carvalho Chehab #define DEBOUNCE_WAITCFG_OUT GENMASK(16, 13) 114*73075011SMauro Carvalho Chehab 115*73075011SMauro Carvalho Chehab #define IO_HP_DEBOUNCE_GT (BIT(12) | BIT(15)) 116*73075011SMauro Carvalho Chehab #define IO_PHYREF_SOFT_GT_MODE BIT(14) 117*73075011SMauro Carvalho Chehab #define IO_REF_SOFT_GT_MODE BIT(13) 118*73075011SMauro Carvalho Chehab #define IO_REF_HARD_GT_MODE BIT(0) 119*73075011SMauro Carvalho Chehab 120*73075011SMauro Carvalho Chehab /* noc power domain */ 121*73075011SMauro Carvalho Chehab #define NOC_POWER_IDLEREQ_1 0x38c 122*73075011SMauro Carvalho Chehab #define NOC_POWER_IDLE_1 0x394 123*73075011SMauro Carvalho Chehab #define NOC_PW_MASK 0x10000 124*73075011SMauro Carvalho Chehab #define NOC_PW_SET_BIT 0x1 125*73075011SMauro Carvalho Chehab 126*73075011SMauro Carvalho Chehab #define NUM_EYEPARAM 5 127*73075011SMauro Carvalho Chehab 128*73075011SMauro Carvalho Chehab /* info located in sysctrl */ 129*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_CMOS_OFFSET 0x60 130*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_CMOS_BIT 0x10 131*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_ISO_OFFSET 0x44 132*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_ISO_BIT 0x30 133*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_HPCLK_OFFSET 0x190 134*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_HPCLK_BIT 0x184000 135*73075011SMauro Carvalho Chehab #define SCTRL_PCIE_OE_OFFSET 0x14a 136*73075011SMauro Carvalho Chehab #define PCIE_DEBOUNCE_PARAM 0xf0f400 137*73075011SMauro Carvalho Chehab #define PCIE_OE_BYPASS GENMASK(29, 28) 138*73075011SMauro Carvalho Chehab 139*73075011SMauro Carvalho Chehab /* peri_crg ctrl */ 140*73075011SMauro Carvalho Chehab #define CRGCTRL_PCIE_ASSERT_OFFSET 0x88 141*73075011SMauro Carvalho Chehab #define CRGCTRL_PCIE_ASSERT_BIT 0x8c000000 142*73075011SMauro Carvalho Chehab 143*73075011SMauro Carvalho Chehab #define FNPLL_HAS_LOCKED BIT(4) 144*73075011SMauro Carvalho Chehab 145*73075011SMauro Carvalho Chehab /* Time for delay */ 146*73075011SMauro Carvalho Chehab #define TIME_CMOS_MIN 100 147*73075011SMauro Carvalho Chehab #define TIME_CMOS_MAX 105 148*73075011SMauro Carvalho Chehab #define PIPE_CLK_STABLE_TIME 100 149*73075011SMauro Carvalho Chehab #define PLL_CTRL_WAIT_TIME 200 150*73075011SMauro Carvalho Chehab #define NOC_POWER_TIME 100 151*73075011SMauro Carvalho Chehab 152*73075011SMauro Carvalho Chehab struct hi3670_pcie_phy { 153*73075011SMauro Carvalho Chehab struct device *dev; 154*73075011SMauro Carvalho Chehab void __iomem *base; 155*73075011SMauro Carvalho Chehab struct regmap *apb; 156*73075011SMauro Carvalho Chehab struct regmap *crgctrl; 157*73075011SMauro Carvalho Chehab struct regmap *sysctrl; 158*73075011SMauro Carvalho Chehab struct regmap *pmctrl; 159*73075011SMauro Carvalho Chehab struct clk *apb_sys_clk; 160*73075011SMauro Carvalho Chehab struct clk *apb_phy_clk; 161*73075011SMauro Carvalho Chehab struct clk *phy_ref_clk; 162*73075011SMauro Carvalho Chehab struct clk *aclk; 163*73075011SMauro Carvalho Chehab struct clk *aux_clk; 164*73075011SMauro Carvalho Chehab u32 eye_param[NUM_EYEPARAM]; 165*73075011SMauro Carvalho Chehab }; 166*73075011SMauro Carvalho Chehab 167*73075011SMauro Carvalho Chehab /* Registers in PCIePHY */ 168*73075011SMauro Carvalho Chehab static inline void hi3670_apb_phy_writel(struct hi3670_pcie_phy *phy, u32 val, 169*73075011SMauro Carvalho Chehab u32 reg) 170*73075011SMauro Carvalho Chehab { 171*73075011SMauro Carvalho Chehab writel(val, phy->base + APB_PHY_START_ADDR + reg); 172*73075011SMauro Carvalho Chehab } 173*73075011SMauro Carvalho Chehab 174*73075011SMauro Carvalho Chehab static inline u32 hi3670_apb_phy_readl(struct hi3670_pcie_phy *phy, u32 reg) 175*73075011SMauro Carvalho Chehab { 176*73075011SMauro Carvalho Chehab return readl(phy->base + APB_PHY_START_ADDR + reg); 177*73075011SMauro Carvalho Chehab } 178*73075011SMauro Carvalho Chehab 179*73075011SMauro Carvalho Chehab static inline void hi3670_apb_phy_updatel(struct hi3670_pcie_phy *phy, 180*73075011SMauro Carvalho Chehab u32 val, u32 mask, u32 reg) 181*73075011SMauro Carvalho Chehab { 182*73075011SMauro Carvalho Chehab u32 regval; 183*73075011SMauro Carvalho Chehab 184*73075011SMauro Carvalho Chehab regval = hi3670_apb_phy_readl(phy, reg); 185*73075011SMauro Carvalho Chehab regval &= ~mask; 186*73075011SMauro Carvalho Chehab regval |= val; 187*73075011SMauro Carvalho Chehab hi3670_apb_phy_writel(phy, regval, reg); 188*73075011SMauro Carvalho Chehab } 189*73075011SMauro Carvalho Chehab 190*73075011SMauro Carvalho Chehab static inline void kirin_apb_natural_phy_writel(struct hi3670_pcie_phy *phy, 191*73075011SMauro Carvalho Chehab u32 val, u32 reg) 192*73075011SMauro Carvalho Chehab { 193*73075011SMauro Carvalho Chehab writel(val, phy->base + reg); 194*73075011SMauro Carvalho Chehab } 195*73075011SMauro Carvalho Chehab 196*73075011SMauro Carvalho Chehab static inline u32 kirin_apb_natural_phy_readl(struct hi3670_pcie_phy *phy, 197*73075011SMauro Carvalho Chehab u32 reg) 198*73075011SMauro Carvalho Chehab { 199*73075011SMauro Carvalho Chehab return readl(phy->base + reg); 200*73075011SMauro Carvalho Chehab } 201*73075011SMauro Carvalho Chehab 202*73075011SMauro Carvalho Chehab static void hi3670_pcie_phy_oe_enable(struct hi3670_pcie_phy *phy, bool enable) 203*73075011SMauro Carvalho Chehab { 204*73075011SMauro Carvalho Chehab u32 val; 205*73075011SMauro Carvalho Chehab 206*73075011SMauro Carvalho Chehab regmap_read(phy->sysctrl, SCTRL_PCIE_OE_OFFSET, &val); 207*73075011SMauro Carvalho Chehab val |= PCIE_DEBOUNCE_PARAM; 208*73075011SMauro Carvalho Chehab if (enable) 209*73075011SMauro Carvalho Chehab val &= ~PCIE_OE_BYPASS; 210*73075011SMauro Carvalho Chehab else 211*73075011SMauro Carvalho Chehab val |= PCIE_OE_BYPASS; 212*73075011SMauro Carvalho Chehab regmap_write(phy->sysctrl, SCTRL_PCIE_OE_OFFSET, val); 213*73075011SMauro Carvalho Chehab } 214*73075011SMauro Carvalho Chehab 215*73075011SMauro Carvalho Chehab static void hi3670_pcie_get_eyeparam(struct hi3670_pcie_phy *phy) 216*73075011SMauro Carvalho Chehab { 217*73075011SMauro Carvalho Chehab struct device *dev = phy->dev; 218*73075011SMauro Carvalho Chehab struct device_node *np; 219*73075011SMauro Carvalho Chehab int ret, i; 220*73075011SMauro Carvalho Chehab 221*73075011SMauro Carvalho Chehab np = dev->of_node; 222*73075011SMauro Carvalho Chehab 223*73075011SMauro Carvalho Chehab ret = of_property_read_u32_array(np, "hisilicon,eye-diagram-param", 224*73075011SMauro Carvalho Chehab phy->eye_param, NUM_EYEPARAM); 225*73075011SMauro Carvalho Chehab if (!ret) 226*73075011SMauro Carvalho Chehab return; 227*73075011SMauro Carvalho Chehab 228*73075011SMauro Carvalho Chehab /* There's no optional eye_param property. Set array to default */ 229*73075011SMauro Carvalho Chehab for (i = 0; i < NUM_EYEPARAM; i++) 230*73075011SMauro Carvalho Chehab phy->eye_param[i] = EYEPARAM_NOCFG; 231*73075011SMauro Carvalho Chehab } 232*73075011SMauro Carvalho Chehab 233*73075011SMauro Carvalho Chehab static void hi3670_pcie_set_eyeparam(struct hi3670_pcie_phy *phy) 234*73075011SMauro Carvalho Chehab { 235*73075011SMauro Carvalho Chehab u32 val; 236*73075011SMauro Carvalho Chehab 237*73075011SMauro Carvalho Chehab val = kirin_apb_natural_phy_readl(phy, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1); 238*73075011SMauro Carvalho Chehab 239*73075011SMauro Carvalho Chehab if (phy->eye_param[1] != EYEPARAM_NOCFG) { 240*73075011SMauro Carvalho Chehab val &= ~EYE_PARM1_MASK; 241*73075011SMauro Carvalho Chehab val |= FIELD_PREP(EYE_PARM1_MASK, phy->eye_param[1]); 242*73075011SMauro Carvalho Chehab val |= EYE_PARM1_EN; 243*73075011SMauro Carvalho Chehab } 244*73075011SMauro Carvalho Chehab kirin_apb_natural_phy_writel(phy, val, 245*73075011SMauro Carvalho Chehab RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1); 246*73075011SMauro Carvalho Chehab 247*73075011SMauro Carvalho Chehab val = kirin_apb_natural_phy_readl(phy, LANEN_DIG_ASIC_TX_OVRD_IN_2); 248*73075011SMauro Carvalho Chehab val &= ~(EYE_PARM2_MASK | EYE_PARM3_MASK); 249*73075011SMauro Carvalho Chehab if (phy->eye_param[2] != EYEPARAM_NOCFG) { 250*73075011SMauro Carvalho Chehab val |= FIELD_PREP(EYE_PARM2_MASK, phy->eye_param[2]); 251*73075011SMauro Carvalho Chehab val |= EYE_PARM2_EN; 252*73075011SMauro Carvalho Chehab } 253*73075011SMauro Carvalho Chehab 254*73075011SMauro Carvalho Chehab if (phy->eye_param[3] != EYEPARAM_NOCFG) { 255*73075011SMauro Carvalho Chehab val |= FIELD_PREP(EYE_PARM3_MASK, phy->eye_param[3]); 256*73075011SMauro Carvalho Chehab val |= EYE_PARM3_EN; 257*73075011SMauro Carvalho Chehab } 258*73075011SMauro Carvalho Chehab 259*73075011SMauro Carvalho Chehab kirin_apb_natural_phy_writel(phy, val, LANEN_DIG_ASIC_TX_OVRD_IN_2); 260*73075011SMauro Carvalho Chehab 261*73075011SMauro Carvalho Chehab val = kirin_apb_natural_phy_readl(phy, SUP_DIG_LVL_OVRD_IN); 262*73075011SMauro Carvalho Chehab if (phy->eye_param[0] != EYEPARAM_NOCFG) { 263*73075011SMauro Carvalho Chehab val &= ~EYE_PARM0_MASK; 264*73075011SMauro Carvalho Chehab val |= FIELD_PREP(EYE_PARM0_MASK, phy->eye_param[0]); 265*73075011SMauro Carvalho Chehab val |= EYE_PARM0_EN; 266*73075011SMauro Carvalho Chehab } 267*73075011SMauro Carvalho Chehab kirin_apb_natural_phy_writel(phy, val, SUP_DIG_LVL_OVRD_IN); 268*73075011SMauro Carvalho Chehab 269*73075011SMauro Carvalho Chehab val = kirin_apb_natural_phy_readl(phy, LANEN_DIG_ASIC_TX_OVRD_IN_1); 270*73075011SMauro Carvalho Chehab if (phy->eye_param[4] != EYEPARAM_NOCFG) { 271*73075011SMauro Carvalho Chehab val &= ~EYE_PARM4_MASK; 272*73075011SMauro Carvalho Chehab val |= FIELD_PREP(EYE_PARM4_MASK, phy->eye_param[4]); 273*73075011SMauro Carvalho Chehab val |= EYE_PARM4_EN; 274*73075011SMauro Carvalho Chehab } 275*73075011SMauro Carvalho Chehab kirin_apb_natural_phy_writel(phy, val, LANEN_DIG_ASIC_TX_OVRD_IN_1); 276*73075011SMauro Carvalho Chehab } 277*73075011SMauro Carvalho Chehab 278*73075011SMauro Carvalho Chehab static void hi3670_pcie_natural_cfg(struct hi3670_pcie_phy *phy) 279*73075011SMauro Carvalho Chehab { 280*73075011SMauro Carvalho Chehab u32 val; 281*73075011SMauro Carvalho Chehab 282*73075011SMauro Carvalho Chehab /* change 2p mem_ctrl */ 283*73075011SMauro Carvalho Chehab regmap_write(phy->apb, SOC_PCIECTRL_CTRL20_ADDR, 284*73075011SMauro Carvalho Chehab SOC_PCIECTRL_CTRL20_2P_MEM_CTRL); 285*73075011SMauro Carvalho Chehab 286*73075011SMauro Carvalho Chehab regmap_read(phy->apb, SOC_PCIECTRL_CTRL7_ADDR, &val); 287*73075011SMauro Carvalho Chehab val |= PCIE_PULL_UP_SYS_AUX_PWR_DET; 288*73075011SMauro Carvalho Chehab regmap_write(phy->apb, SOC_PCIECTRL_CTRL7_ADDR, val); 289*73075011SMauro Carvalho Chehab 290*73075011SMauro Carvalho Chehab /* output, pull down */ 291*73075011SMauro Carvalho Chehab regmap_read(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, &val); 292*73075011SMauro Carvalho Chehab val &= ~PCIE_OUTPUT_PULL_BITS; 293*73075011SMauro Carvalho Chehab val |= PCIE_OUTPUT_PULL_DOWN; 294*73075011SMauro Carvalho Chehab regmap_write(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val); 295*73075011SMauro Carvalho Chehab 296*73075011SMauro Carvalho Chehab /* Handle phy_reset and lane0_reset to HW */ 297*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, PCIEPHY_RESET_BIT, 298*73075011SMauro Carvalho Chehab PCIEPHY_PIPE_LINE0_RESET_BIT | PCIEPHY_RESET_BIT, 299*73075011SMauro Carvalho Chehab SOC_PCIEPHY_CTRL1_ADDR); 300*73075011SMauro Carvalho Chehab 301*73075011SMauro Carvalho Chehab /* fix chip bug: TxDetectRx fail */ 302*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, PCIE_TXDETECT_RX_FAIL, PCIE_TXDETECT_RX_FAIL, 303*73075011SMauro Carvalho Chehab SOC_PCIEPHY_CTRL38_ADDR); 304*73075011SMauro Carvalho Chehab } 305*73075011SMauro Carvalho Chehab 306*73075011SMauro Carvalho Chehab static void hi3670_pcie_pll_init(struct hi3670_pcie_phy *phy) 307*73075011SMauro Carvalho Chehab { 308*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, PCIE_PHY_CHOOSE_FNPLL, PCIE_PHY_CHOOSE_FNPLL, 309*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL1); 310*73075011SMauro Carvalho Chehab 311*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 312*73075011SMauro Carvalho Chehab FIELD_PREP(PCIE_FNPLL_FBDIV_MASK, PCIE_FNPLL_FBDIV), 313*73075011SMauro Carvalho Chehab PCIE_FNPLL_FBDIV_MASK, 314*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL16); 315*73075011SMauro Carvalho Chehab 316*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 317*73075011SMauro Carvalho Chehab FIELD_PREP(PCIE_FNPLL_FRACDIV_MASK, PCIE_FNPLL_FRACDIV), 318*73075011SMauro Carvalho Chehab PCIE_FNPLL_FRACDIV_MASK, SOC_PCIEPHY_MMC1PLL_CTRL17); 319*73075011SMauro Carvalho Chehab 320*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 321*73075011SMauro Carvalho Chehab PCIE_FNPLL_DLL_EN | 322*73075011SMauro Carvalho Chehab FIELD_PREP(PCIE_FNPLL_POSTDIV1_MASK, PCIE_FNPLL_POSTDIV1) | 323*73075011SMauro Carvalho Chehab FIELD_PREP(PCIE_FNPLL_POSTDIV2_MASK, PCIE_FNPLL_POSTDIV2) | 324*73075011SMauro Carvalho Chehab FIELD_PREP(PCIE_FNPLL_PLL_MODE_MASK, PCIE_FNPLL_PLL_MODE), 325*73075011SMauro Carvalho Chehab PCIE_FNPLL_POSTDIV1_MASK | 326*73075011SMauro Carvalho Chehab PCIE_FNPLL_POSTDIV2_MASK | 327*73075011SMauro Carvalho Chehab PCIE_FNPLL_PLL_MODE_MASK | PCIE_FNPLL_DLL_EN, 328*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL20); 329*73075011SMauro Carvalho Chehab 330*73075011SMauro Carvalho Chehab hi3670_apb_phy_writel(phy, PCIE_PHY_MMC1PLL, 331*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL21); 332*73075011SMauro Carvalho Chehab } 333*73075011SMauro Carvalho Chehab 334*73075011SMauro Carvalho Chehab static int hi3670_pcie_pll_ctrl(struct hi3670_pcie_phy *phy, bool enable) 335*73075011SMauro Carvalho Chehab { 336*73075011SMauro Carvalho Chehab struct device *dev = phy->dev; 337*73075011SMauro Carvalho Chehab u32 val; 338*73075011SMauro Carvalho Chehab int time = PLL_CTRL_WAIT_TIME; 339*73075011SMauro Carvalho Chehab 340*73075011SMauro Carvalho Chehab if (enable) { 341*73075011SMauro Carvalho Chehab /* pd = 0 */ 342*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 0, PCIE_PHY_MMC1PLL_DISABLE, 343*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL16); 344*73075011SMauro Carvalho Chehab 345*73075011SMauro Carvalho Chehab /* choose FNPLL */ 346*73075011SMauro Carvalho Chehab val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_MMC1PLL_STAT0); 347*73075011SMauro Carvalho Chehab while (!(val & FNPLL_HAS_LOCKED)) { 348*73075011SMauro Carvalho Chehab if (!time) { 349*73075011SMauro Carvalho Chehab dev_err(dev, "wait for pll_lock timeout\n"); 350*73075011SMauro Carvalho Chehab return -EINVAL; 351*73075011SMauro Carvalho Chehab } 352*73075011SMauro Carvalho Chehab time--; 353*73075011SMauro Carvalho Chehab udelay(1); 354*73075011SMauro Carvalho Chehab val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_MMC1PLL_STAT0); 355*73075011SMauro Carvalho Chehab } 356*73075011SMauro Carvalho Chehab 357*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 0, PCIE_PHY_PCIEPL_BP, 358*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL20); 359*73075011SMauro Carvalho Chehab 360*73075011SMauro Carvalho Chehab } else { 361*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 362*73075011SMauro Carvalho Chehab PCIE_PHY_MMC1PLL_DISABLE, 363*73075011SMauro Carvalho Chehab PCIE_PHY_MMC1PLL_DISABLE, 364*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL16); 365*73075011SMauro Carvalho Chehab 366*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, PCIE_PHY_PCIEPL_BP, 367*73075011SMauro Carvalho Chehab PCIE_PHY_PCIEPL_BP, 368*73075011SMauro Carvalho Chehab SOC_PCIEPHY_MMC1PLL_CTRL20); 369*73075011SMauro Carvalho Chehab } 370*73075011SMauro Carvalho Chehab 371*73075011SMauro Carvalho Chehab return 0; 372*73075011SMauro Carvalho Chehab } 373*73075011SMauro Carvalho Chehab 374*73075011SMauro Carvalho Chehab static void hi3670_pcie_hp_debounce_gt(struct hi3670_pcie_phy *phy, bool open) 375*73075011SMauro Carvalho Chehab { 376*73075011SMauro Carvalho Chehab if (open) 377*73075011SMauro Carvalho Chehab /* gt_clk_pcie_hp/gt_clk_pcie_debounce open */ 378*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PEREN12, 379*73075011SMauro Carvalho Chehab IO_HP_DEBOUNCE_GT); 380*73075011SMauro Carvalho Chehab else 381*73075011SMauro Carvalho Chehab /* gt_clk_pcie_hp/gt_clk_pcie_debounce close */ 382*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, 383*73075011SMauro Carvalho Chehab IO_HP_DEBOUNCE_GT); 384*73075011SMauro Carvalho Chehab } 385*73075011SMauro Carvalho Chehab 386*73075011SMauro Carvalho Chehab static void hi3670_pcie_phyref_gt(struct hi3670_pcie_phy *phy, bool open) 387*73075011SMauro Carvalho Chehab { 388*73075011SMauro Carvalho Chehab unsigned int val; 389*73075011SMauro Carvalho Chehab 390*73075011SMauro Carvalho Chehab regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 391*73075011SMauro Carvalho Chehab 392*73075011SMauro Carvalho Chehab if (open) 393*73075011SMauro Carvalho Chehab val &= ~IO_OE_HARD_GT_MODE; /* enable hard gt mode */ 394*73075011SMauro Carvalho Chehab else 395*73075011SMauro Carvalho Chehab val |= IO_OE_HARD_GT_MODE; /* disable hard gt mode */ 396*73075011SMauro Carvalho Chehab 397*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 398*73075011SMauro Carvalho Chehab 399*73075011SMauro Carvalho Chehab /* disable soft gt mode */ 400*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, IO_PHYREF_SOFT_GT_MODE); 401*73075011SMauro Carvalho Chehab } 402*73075011SMauro Carvalho Chehab 403*73075011SMauro Carvalho Chehab static void hi3670_pcie_oe_ctrl(struct hi3670_pcie_phy *phy, bool en_flag) 404*73075011SMauro Carvalho Chehab { 405*73075011SMauro Carvalho Chehab unsigned int val; 406*73075011SMauro Carvalho Chehab 407*73075011SMauro Carvalho Chehab regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 408*73075011SMauro Carvalho Chehab 409*73075011SMauro Carvalho Chehab /* set ie cfg */ 410*73075011SMauro Carvalho Chehab val |= IO_IE_EN_HARD_BYPASS; 411*73075011SMauro Carvalho Chehab 412*73075011SMauro Carvalho Chehab /* set oe cfg */ 413*73075011SMauro Carvalho Chehab val &= ~IO_HARD_CTRL_DEBOUNCE_BYPASS; 414*73075011SMauro Carvalho Chehab 415*73075011SMauro Carvalho Chehab /* set phy_debounce in&out time */ 416*73075011SMauro Carvalho Chehab val |= (DEBOUNCE_WAITCFG_IN | DEBOUNCE_WAITCFG_OUT); 417*73075011SMauro Carvalho Chehab 418*73075011SMauro Carvalho Chehab /* select oe_gt_mode */ 419*73075011SMauro Carvalho Chehab val |= IO_OE_GT_MODE; 420*73075011SMauro Carvalho Chehab 421*73075011SMauro Carvalho Chehab if (en_flag) 422*73075011SMauro Carvalho Chehab val &= ~IO_OE_EN_HARD_BYPASS; 423*73075011SMauro Carvalho Chehab else 424*73075011SMauro Carvalho Chehab val |= IO_OE_EN_HARD_BYPASS; 425*73075011SMauro Carvalho Chehab 426*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 427*73075011SMauro Carvalho Chehab } 428*73075011SMauro Carvalho Chehab 429*73075011SMauro Carvalho Chehab static void hi3670_pcie_ioref_gt(struct hi3670_pcie_phy *phy, bool open) 430*73075011SMauro Carvalho Chehab { 431*73075011SMauro Carvalho Chehab unsigned int val; 432*73075011SMauro Carvalho Chehab 433*73075011SMauro Carvalho Chehab if (open) { 434*73075011SMauro Carvalho Chehab regmap_write(phy->apb, SOC_PCIECTRL_CTRL21_ADDR, 435*73075011SMauro Carvalho Chehab SOC_PCIECTRL_CTRL21_DEFAULT); 436*73075011SMauro Carvalho Chehab 437*73075011SMauro Carvalho Chehab hi3670_pcie_oe_ctrl(phy, true); 438*73075011SMauro Carvalho Chehab 439*73075011SMauro Carvalho Chehab /* en hard gt mode */ 440*73075011SMauro Carvalho Chehab regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 441*73075011SMauro Carvalho Chehab val &= ~IO_REF_HARD_GT_MODE; 442*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 443*73075011SMauro Carvalho Chehab 444*73075011SMauro Carvalho Chehab /* disable soft gt mode */ 445*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, 446*73075011SMauro Carvalho Chehab IO_REF_SOFT_GT_MODE); 447*73075011SMauro Carvalho Chehab 448*73075011SMauro Carvalho Chehab } else { 449*73075011SMauro Carvalho Chehab /* disable hard gt mode */ 450*73075011SMauro Carvalho Chehab regmap_read(phy->crgctrl, CRGPERIPH_PCIECTRL0, &val); 451*73075011SMauro Carvalho Chehab val |= IO_REF_HARD_GT_MODE; 452*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PCIECTRL0, val); 453*73075011SMauro Carvalho Chehab 454*73075011SMauro Carvalho Chehab /* disable soft gt mode */ 455*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGPERIPH_PERDIS12, 456*73075011SMauro Carvalho Chehab IO_REF_SOFT_GT_MODE); 457*73075011SMauro Carvalho Chehab 458*73075011SMauro Carvalho Chehab hi3670_pcie_oe_ctrl(phy, false); 459*73075011SMauro Carvalho Chehab } 460*73075011SMauro Carvalho Chehab } 461*73075011SMauro Carvalho Chehab 462*73075011SMauro Carvalho Chehab static int hi3670_pcie_allclk_ctrl(struct hi3670_pcie_phy *phy, bool clk_on) 463*73075011SMauro Carvalho Chehab { 464*73075011SMauro Carvalho Chehab struct device *dev = phy->dev; 465*73075011SMauro Carvalho Chehab int ret = 0; 466*73075011SMauro Carvalho Chehab 467*73075011SMauro Carvalho Chehab if (!clk_on) 468*73075011SMauro Carvalho Chehab goto close_clocks; 469*73075011SMauro Carvalho Chehab 470*73075011SMauro Carvalho Chehab /* choose 100MHz clk src: Bit[8]==1 pad, Bit[8]==0 pll */ 471*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 0, PCIE_CLK_SOURCE, 472*73075011SMauro Carvalho Chehab SOC_PCIEPHY_CTRL1_ADDR); 473*73075011SMauro Carvalho Chehab 474*73075011SMauro Carvalho Chehab hi3670_pcie_pll_init(phy); 475*73075011SMauro Carvalho Chehab 476*73075011SMauro Carvalho Chehab ret = hi3670_pcie_pll_ctrl(phy, true); 477*73075011SMauro Carvalho Chehab if (ret) { 478*73075011SMauro Carvalho Chehab dev_err(dev, "Failed to enable pll\n"); 479*73075011SMauro Carvalho Chehab return -EINVAL; 480*73075011SMauro Carvalho Chehab } 481*73075011SMauro Carvalho Chehab hi3670_pcie_hp_debounce_gt(phy, true); 482*73075011SMauro Carvalho Chehab hi3670_pcie_phyref_gt(phy, true); 483*73075011SMauro Carvalho Chehab hi3670_pcie_ioref_gt(phy, true); 484*73075011SMauro Carvalho Chehab 485*73075011SMauro Carvalho Chehab ret = clk_set_rate(phy->aclk, AXI_CLK_FREQ); 486*73075011SMauro Carvalho Chehab if (ret) { 487*73075011SMauro Carvalho Chehab dev_err(dev, "Failed to set rate\n"); 488*73075011SMauro Carvalho Chehab goto close_clocks; 489*73075011SMauro Carvalho Chehab } 490*73075011SMauro Carvalho Chehab 491*73075011SMauro Carvalho Chehab return 0; 492*73075011SMauro Carvalho Chehab 493*73075011SMauro Carvalho Chehab close_clocks: 494*73075011SMauro Carvalho Chehab hi3670_pcie_ioref_gt(phy, false); 495*73075011SMauro Carvalho Chehab hi3670_pcie_phyref_gt(phy, false); 496*73075011SMauro Carvalho Chehab hi3670_pcie_hp_debounce_gt(phy, false); 497*73075011SMauro Carvalho Chehab 498*73075011SMauro Carvalho Chehab hi3670_pcie_pll_ctrl(phy, false); 499*73075011SMauro Carvalho Chehab 500*73075011SMauro Carvalho Chehab return ret; 501*73075011SMauro Carvalho Chehab } 502*73075011SMauro Carvalho Chehab 503*73075011SMauro Carvalho Chehab static bool is_pipe_clk_stable(struct hi3670_pcie_phy *phy) 504*73075011SMauro Carvalho Chehab { 505*73075011SMauro Carvalho Chehab struct device *dev = phy->dev; 506*73075011SMauro Carvalho Chehab u32 val; 507*73075011SMauro Carvalho Chehab u32 time = PIPE_CLK_STABLE_TIME; 508*73075011SMauro Carvalho Chehab u32 pipe_clk_stable = PCIE_IS_CLOCK_STABLE; 509*73075011SMauro Carvalho Chehab 510*73075011SMauro Carvalho Chehab val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_STATE0_ADDR); 511*73075011SMauro Carvalho Chehab while (val & pipe_clk_stable) { 512*73075011SMauro Carvalho Chehab mdelay(1); 513*73075011SMauro Carvalho Chehab if (!time) { 514*73075011SMauro Carvalho Chehab dev_err(dev, "PIPE clk is not stable\n"); 515*73075011SMauro Carvalho Chehab return false; 516*73075011SMauro Carvalho Chehab } 517*73075011SMauro Carvalho Chehab time--; 518*73075011SMauro Carvalho Chehab val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_STATE0_ADDR); 519*73075011SMauro Carvalho Chehab } 520*73075011SMauro Carvalho Chehab 521*73075011SMauro Carvalho Chehab return true; 522*73075011SMauro Carvalho Chehab } 523*73075011SMauro Carvalho Chehab 524*73075011SMauro Carvalho Chehab static int hi3670_pcie_noc_power(struct hi3670_pcie_phy *phy, bool enable) 525*73075011SMauro Carvalho Chehab { 526*73075011SMauro Carvalho Chehab struct device *dev = phy->dev; 527*73075011SMauro Carvalho Chehab u32 time = NOC_POWER_TIME; 528*73075011SMauro Carvalho Chehab unsigned int val = NOC_PW_MASK; 529*73075011SMauro Carvalho Chehab int rst; 530*73075011SMauro Carvalho Chehab 531*73075011SMauro Carvalho Chehab if (enable) 532*73075011SMauro Carvalho Chehab val = NOC_PW_MASK | NOC_PW_SET_BIT; 533*73075011SMauro Carvalho Chehab else 534*73075011SMauro Carvalho Chehab val = NOC_PW_MASK; 535*73075011SMauro Carvalho Chehab rst = enable ? 1 : 0; 536*73075011SMauro Carvalho Chehab 537*73075011SMauro Carvalho Chehab regmap_write(phy->pmctrl, NOC_POWER_IDLEREQ_1, val); 538*73075011SMauro Carvalho Chehab 539*73075011SMauro Carvalho Chehab time = NOC_POWER_TIME; 540*73075011SMauro Carvalho Chehab regmap_read(phy->pmctrl, NOC_POWER_IDLE_1, &val); 541*73075011SMauro Carvalho Chehab while ((val & NOC_PW_SET_BIT) != rst) { 542*73075011SMauro Carvalho Chehab udelay(10); 543*73075011SMauro Carvalho Chehab if (!time) { 544*73075011SMauro Carvalho Chehab dev_err(dev, "Failed to reverse noc power-status\n"); 545*73075011SMauro Carvalho Chehab return -EINVAL; 546*73075011SMauro Carvalho Chehab } 547*73075011SMauro Carvalho Chehab time--; 548*73075011SMauro Carvalho Chehab regmap_read(phy->pmctrl, NOC_POWER_IDLE_1, &val); 549*73075011SMauro Carvalho Chehab } 550*73075011SMauro Carvalho Chehab 551*73075011SMauro Carvalho Chehab return 0; 552*73075011SMauro Carvalho Chehab } 553*73075011SMauro Carvalho Chehab 554*73075011SMauro Carvalho Chehab static int hi3670_pcie_get_resources_from_pcie(struct hi3670_pcie_phy *phy) 555*73075011SMauro Carvalho Chehab { 556*73075011SMauro Carvalho Chehab struct device_node *pcie_port; 557*73075011SMauro Carvalho Chehab struct device *dev = phy->dev; 558*73075011SMauro Carvalho Chehab struct device *pcie_dev; 559*73075011SMauro Carvalho Chehab 560*73075011SMauro Carvalho Chehab pcie_port = of_get_child_by_name(dev->parent->of_node, "pcie"); 561*73075011SMauro Carvalho Chehab if (!pcie_port) { 562*73075011SMauro Carvalho Chehab dev_err(dev, "no pcie node found in %s\n", 563*73075011SMauro Carvalho Chehab dev->parent->of_node->full_name); 564*73075011SMauro Carvalho Chehab return -ENODEV; 565*73075011SMauro Carvalho Chehab } 566*73075011SMauro Carvalho Chehab 567*73075011SMauro Carvalho Chehab pcie_dev = bus_find_device_by_of_node(&platform_bus_type, pcie_port); 568*73075011SMauro Carvalho Chehab if (!pcie_dev) { 569*73075011SMauro Carvalho Chehab dev_err(dev, "Didn't find pcie device\n"); 570*73075011SMauro Carvalho Chehab return -ENODEV; 571*73075011SMauro Carvalho Chehab } 572*73075011SMauro Carvalho Chehab 573*73075011SMauro Carvalho Chehab /* 574*73075011SMauro Carvalho Chehab * We might just use NULL instead of the APB name, as the 575*73075011SMauro Carvalho Chehab * pcie-kirin currently registers directly just one regmap (although 576*73075011SMauro Carvalho Chehab * the DWC driver register other regmaps). 577*73075011SMauro Carvalho Chehab * 578*73075011SMauro Carvalho Chehab * Yet, it sounds safer to warrant that it will be accessing the 579*73075011SMauro Carvalho Chehab * right regmap. So, let's use the named version. 580*73075011SMauro Carvalho Chehab */ 581*73075011SMauro Carvalho Chehab phy->apb = dev_get_regmap(pcie_dev, "kirin_pcie_apb"); 582*73075011SMauro Carvalho Chehab if (!phy->apb) { 583*73075011SMauro Carvalho Chehab dev_err(dev, "Failed to get APB regmap\n"); 584*73075011SMauro Carvalho Chehab return -ENODEV; 585*73075011SMauro Carvalho Chehab } 586*73075011SMauro Carvalho Chehab 587*73075011SMauro Carvalho Chehab return 0; 588*73075011SMauro Carvalho Chehab } 589*73075011SMauro Carvalho Chehab 590*73075011SMauro Carvalho Chehab static int kirin_pcie_clk_ctrl(struct hi3670_pcie_phy *phy, bool enable) 591*73075011SMauro Carvalho Chehab { 592*73075011SMauro Carvalho Chehab int ret = 0; 593*73075011SMauro Carvalho Chehab 594*73075011SMauro Carvalho Chehab if (!enable) 595*73075011SMauro Carvalho Chehab goto close_clk; 596*73075011SMauro Carvalho Chehab 597*73075011SMauro Carvalho Chehab ret = clk_set_rate(phy->phy_ref_clk, REF_CLK_FREQ); 598*73075011SMauro Carvalho Chehab if (ret) 599*73075011SMauro Carvalho Chehab return ret; 600*73075011SMauro Carvalho Chehab 601*73075011SMauro Carvalho Chehab ret = clk_prepare_enable(phy->phy_ref_clk); 602*73075011SMauro Carvalho Chehab if (ret) 603*73075011SMauro Carvalho Chehab return ret; 604*73075011SMauro Carvalho Chehab 605*73075011SMauro Carvalho Chehab ret = clk_prepare_enable(phy->apb_sys_clk); 606*73075011SMauro Carvalho Chehab if (ret) 607*73075011SMauro Carvalho Chehab goto apb_sys_fail; 608*73075011SMauro Carvalho Chehab 609*73075011SMauro Carvalho Chehab ret = clk_prepare_enable(phy->apb_phy_clk); 610*73075011SMauro Carvalho Chehab if (ret) 611*73075011SMauro Carvalho Chehab goto apb_phy_fail; 612*73075011SMauro Carvalho Chehab 613*73075011SMauro Carvalho Chehab ret = clk_prepare_enable(phy->aclk); 614*73075011SMauro Carvalho Chehab if (ret) 615*73075011SMauro Carvalho Chehab goto aclk_fail; 616*73075011SMauro Carvalho Chehab 617*73075011SMauro Carvalho Chehab ret = clk_prepare_enable(phy->aux_clk); 618*73075011SMauro Carvalho Chehab if (ret) 619*73075011SMauro Carvalho Chehab goto aux_clk_fail; 620*73075011SMauro Carvalho Chehab 621*73075011SMauro Carvalho Chehab return 0; 622*73075011SMauro Carvalho Chehab 623*73075011SMauro Carvalho Chehab close_clk: 624*73075011SMauro Carvalho Chehab clk_disable_unprepare(phy->aux_clk); 625*73075011SMauro Carvalho Chehab aux_clk_fail: 626*73075011SMauro Carvalho Chehab clk_disable_unprepare(phy->aclk); 627*73075011SMauro Carvalho Chehab aclk_fail: 628*73075011SMauro Carvalho Chehab clk_disable_unprepare(phy->apb_phy_clk); 629*73075011SMauro Carvalho Chehab apb_phy_fail: 630*73075011SMauro Carvalho Chehab clk_disable_unprepare(phy->apb_sys_clk); 631*73075011SMauro Carvalho Chehab apb_sys_fail: 632*73075011SMauro Carvalho Chehab clk_disable_unprepare(phy->phy_ref_clk); 633*73075011SMauro Carvalho Chehab 634*73075011SMauro Carvalho Chehab return ret; 635*73075011SMauro Carvalho Chehab } 636*73075011SMauro Carvalho Chehab 637*73075011SMauro Carvalho Chehab static int hi3670_pcie_phy_init(struct phy *generic_phy) 638*73075011SMauro Carvalho Chehab { 639*73075011SMauro Carvalho Chehab struct hi3670_pcie_phy *phy = phy_get_drvdata(generic_phy); 640*73075011SMauro Carvalho Chehab int ret; 641*73075011SMauro Carvalho Chehab 642*73075011SMauro Carvalho Chehab /* 643*73075011SMauro Carvalho Chehab * The code under hi3670_pcie_get_resources_from_pcie() need to 644*73075011SMauro Carvalho Chehab * access the reset-gpios and the APB registers, both from the 645*73075011SMauro Carvalho Chehab * pcie-kirin driver. 646*73075011SMauro Carvalho Chehab * 647*73075011SMauro Carvalho Chehab * The APB is obtained via the pcie driver's regmap 648*73075011SMauro Carvalho Chehab * Such kind of resource can only be obtained during the PCIe 649*73075011SMauro Carvalho Chehab * power_on sequence, as the code inside pcie-kirin needs to 650*73075011SMauro Carvalho Chehab * be already probed, as it needs to register the APB regmap. 651*73075011SMauro Carvalho Chehab */ 652*73075011SMauro Carvalho Chehab 653*73075011SMauro Carvalho Chehab ret = hi3670_pcie_get_resources_from_pcie(phy); 654*73075011SMauro Carvalho Chehab if (ret) 655*73075011SMauro Carvalho Chehab return ret; 656*73075011SMauro Carvalho Chehab 657*73075011SMauro Carvalho Chehab return 0; 658*73075011SMauro Carvalho Chehab } 659*73075011SMauro Carvalho Chehab 660*73075011SMauro Carvalho Chehab static int hi3670_pcie_phy_power_on(struct phy *generic_phy) 661*73075011SMauro Carvalho Chehab { 662*73075011SMauro Carvalho Chehab struct hi3670_pcie_phy *phy = phy_get_drvdata(generic_phy); 663*73075011SMauro Carvalho Chehab int val, ret; 664*73075011SMauro Carvalho Chehab 665*73075011SMauro Carvalho Chehab /* Power supply for Host */ 666*73075011SMauro Carvalho Chehab regmap_write(phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, SCTRL_PCIE_CMOS_BIT); 667*73075011SMauro Carvalho Chehab usleep_range(TIME_CMOS_MIN, TIME_CMOS_MAX); 668*73075011SMauro Carvalho Chehab 669*73075011SMauro Carvalho Chehab hi3670_pcie_phy_oe_enable(phy, true); 670*73075011SMauro Carvalho Chehab 671*73075011SMauro Carvalho Chehab ret = kirin_pcie_clk_ctrl(phy, true); 672*73075011SMauro Carvalho Chehab if (ret) 673*73075011SMauro Carvalho Chehab return ret; 674*73075011SMauro Carvalho Chehab 675*73075011SMauro Carvalho Chehab /* ISO disable, PCIeCtrl, PHY assert and clk gate clear */ 676*73075011SMauro Carvalho Chehab regmap_write(phy->sysctrl, SCTRL_PCIE_ISO_OFFSET, SCTRL_PCIE_ISO_BIT); 677*73075011SMauro Carvalho Chehab regmap_write(phy->crgctrl, CRGCTRL_PCIE_ASSERT_OFFSET, 678*73075011SMauro Carvalho Chehab CRGCTRL_PCIE_ASSERT_BIT); 679*73075011SMauro Carvalho Chehab regmap_write(phy->sysctrl, SCTRL_PCIE_HPCLK_OFFSET, 680*73075011SMauro Carvalho Chehab SCTRL_PCIE_HPCLK_BIT); 681*73075011SMauro Carvalho Chehab 682*73075011SMauro Carvalho Chehab hi3670_pcie_natural_cfg(phy); 683*73075011SMauro Carvalho Chehab 684*73075011SMauro Carvalho Chehab ret = hi3670_pcie_allclk_ctrl(phy, true); 685*73075011SMauro Carvalho Chehab if (ret) 686*73075011SMauro Carvalho Chehab goto disable_clks; 687*73075011SMauro Carvalho Chehab 688*73075011SMauro Carvalho Chehab /* pull down phy_test_powerdown signal */ 689*73075011SMauro Carvalho Chehab hi3670_apb_phy_updatel(phy, 0, PCIE_PULL_DOWN_PHY_TEST_POWERDOWN, 690*73075011SMauro Carvalho Chehab SOC_PCIEPHY_CTRL0_ADDR); 691*73075011SMauro Carvalho Chehab 692*73075011SMauro Carvalho Chehab /* deassert controller perst_n */ 693*73075011SMauro Carvalho Chehab regmap_read(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, &val); 694*73075011SMauro Carvalho Chehab val |= PCIE_DEASSERT_CONTROLLER_PERST; 695*73075011SMauro Carvalho Chehab regmap_write(phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val); 696*73075011SMauro Carvalho Chehab udelay(10); 697*73075011SMauro Carvalho Chehab 698*73075011SMauro Carvalho Chehab ret = is_pipe_clk_stable(phy); 699*73075011SMauro Carvalho Chehab if (!ret) 700*73075011SMauro Carvalho Chehab goto disable_clks; 701*73075011SMauro Carvalho Chehab 702*73075011SMauro Carvalho Chehab hi3670_pcie_set_eyeparam(phy); 703*73075011SMauro Carvalho Chehab 704*73075011SMauro Carvalho Chehab ret = hi3670_pcie_noc_power(phy, false); 705*73075011SMauro Carvalho Chehab if (ret) 706*73075011SMauro Carvalho Chehab goto disable_clks; 707*73075011SMauro Carvalho Chehab 708*73075011SMauro Carvalho Chehab return 0; 709*73075011SMauro Carvalho Chehab 710*73075011SMauro Carvalho Chehab disable_clks: 711*73075011SMauro Carvalho Chehab kirin_pcie_clk_ctrl(phy, false); 712*73075011SMauro Carvalho Chehab return ret; 713*73075011SMauro Carvalho Chehab } 714*73075011SMauro Carvalho Chehab 715*73075011SMauro Carvalho Chehab static int hi3670_pcie_phy_power_off(struct phy *generic_phy) 716*73075011SMauro Carvalho Chehab { 717*73075011SMauro Carvalho Chehab struct hi3670_pcie_phy *phy = phy_get_drvdata(generic_phy); 718*73075011SMauro Carvalho Chehab 719*73075011SMauro Carvalho Chehab hi3670_pcie_phy_oe_enable(phy, false); 720*73075011SMauro Carvalho Chehab 721*73075011SMauro Carvalho Chehab hi3670_pcie_allclk_ctrl(phy, false); 722*73075011SMauro Carvalho Chehab 723*73075011SMauro Carvalho Chehab /* Drop power supply for Host */ 724*73075011SMauro Carvalho Chehab regmap_write(phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, 0); 725*73075011SMauro Carvalho Chehab 726*73075011SMauro Carvalho Chehab /* 727*73075011SMauro Carvalho Chehab * FIXME: The enabled clocks should be disabled here by calling 728*73075011SMauro Carvalho Chehab * kirin_pcie_clk_ctrl(phy, false); 729*73075011SMauro Carvalho Chehab * However, some clocks used at Kirin 970 should be marked as 730*73075011SMauro Carvalho Chehab * CLK_IS_CRITICAL at clk-hi3670 driver, as powering such clocks off 731*73075011SMauro Carvalho Chehab * cause an Asynchronous SError interrupt, which produces panic(). 732*73075011SMauro Carvalho Chehab * While clk-hi3670 is not fixed, we cannot risk disabling clocks here. 733*73075011SMauro Carvalho Chehab */ 734*73075011SMauro Carvalho Chehab 735*73075011SMauro Carvalho Chehab return 0; 736*73075011SMauro Carvalho Chehab } 737*73075011SMauro Carvalho Chehab 738*73075011SMauro Carvalho Chehab static const struct phy_ops hi3670_phy_ops = { 739*73075011SMauro Carvalho Chehab .init = hi3670_pcie_phy_init, 740*73075011SMauro Carvalho Chehab .power_on = hi3670_pcie_phy_power_on, 741*73075011SMauro Carvalho Chehab .power_off = hi3670_pcie_phy_power_off, 742*73075011SMauro Carvalho Chehab .owner = THIS_MODULE, 743*73075011SMauro Carvalho Chehab }; 744*73075011SMauro Carvalho Chehab 745*73075011SMauro Carvalho Chehab static int hi3670_pcie_phy_get_resources(struct hi3670_pcie_phy *phy, 746*73075011SMauro Carvalho Chehab struct platform_device *pdev) 747*73075011SMauro Carvalho Chehab { 748*73075011SMauro Carvalho Chehab struct device *dev = &pdev->dev; 749*73075011SMauro Carvalho Chehab 750*73075011SMauro Carvalho Chehab /* syscon */ 751*73075011SMauro Carvalho Chehab phy->crgctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-crgctrl"); 752*73075011SMauro Carvalho Chehab if (IS_ERR(phy->crgctrl)) 753*73075011SMauro Carvalho Chehab return PTR_ERR(phy->crgctrl); 754*73075011SMauro Carvalho Chehab 755*73075011SMauro Carvalho Chehab phy->sysctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-sctrl"); 756*73075011SMauro Carvalho Chehab if (IS_ERR(phy->sysctrl)) 757*73075011SMauro Carvalho Chehab return PTR_ERR(phy->sysctrl); 758*73075011SMauro Carvalho Chehab 759*73075011SMauro Carvalho Chehab phy->pmctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-pmctrl"); 760*73075011SMauro Carvalho Chehab if (IS_ERR(phy->sysctrl)) 761*73075011SMauro Carvalho Chehab return PTR_ERR(phy->sysctrl); 762*73075011SMauro Carvalho Chehab 763*73075011SMauro Carvalho Chehab /* clocks */ 764*73075011SMauro Carvalho Chehab phy->phy_ref_clk = devm_clk_get(dev, "phy_ref"); 765*73075011SMauro Carvalho Chehab if (IS_ERR(phy->phy_ref_clk)) 766*73075011SMauro Carvalho Chehab return PTR_ERR(phy->phy_ref_clk); 767*73075011SMauro Carvalho Chehab 768*73075011SMauro Carvalho Chehab phy->aux_clk = devm_clk_get(dev, "aux"); 769*73075011SMauro Carvalho Chehab if (IS_ERR(phy->aux_clk)) 770*73075011SMauro Carvalho Chehab return PTR_ERR(phy->aux_clk); 771*73075011SMauro Carvalho Chehab 772*73075011SMauro Carvalho Chehab phy->apb_phy_clk = devm_clk_get(dev, "apb_phy"); 773*73075011SMauro Carvalho Chehab if (IS_ERR(phy->apb_phy_clk)) 774*73075011SMauro Carvalho Chehab return PTR_ERR(phy->apb_phy_clk); 775*73075011SMauro Carvalho Chehab 776*73075011SMauro Carvalho Chehab phy->apb_sys_clk = devm_clk_get(dev, "apb_sys"); 777*73075011SMauro Carvalho Chehab if (IS_ERR(phy->apb_sys_clk)) 778*73075011SMauro Carvalho Chehab return PTR_ERR(phy->apb_sys_clk); 779*73075011SMauro Carvalho Chehab 780*73075011SMauro Carvalho Chehab phy->aclk = devm_clk_get(dev, "aclk"); 781*73075011SMauro Carvalho Chehab if (IS_ERR(phy->aclk)) 782*73075011SMauro Carvalho Chehab return PTR_ERR(phy->aclk); 783*73075011SMauro Carvalho Chehab 784*73075011SMauro Carvalho Chehab /* registers */ 785*73075011SMauro Carvalho Chehab phy->base = devm_platform_ioremap_resource(pdev, 0); 786*73075011SMauro Carvalho Chehab if (IS_ERR(phy->base)) 787*73075011SMauro Carvalho Chehab return PTR_ERR(phy->base); 788*73075011SMauro Carvalho Chehab 789*73075011SMauro Carvalho Chehab hi3670_pcie_get_eyeparam(phy); 790*73075011SMauro Carvalho Chehab 791*73075011SMauro Carvalho Chehab return 0; 792*73075011SMauro Carvalho Chehab } 793*73075011SMauro Carvalho Chehab 794*73075011SMauro Carvalho Chehab static int hi3670_pcie_phy_probe(struct platform_device *pdev) 795*73075011SMauro Carvalho Chehab { 796*73075011SMauro Carvalho Chehab struct phy_provider *phy_provider; 797*73075011SMauro Carvalho Chehab struct device *dev = &pdev->dev; 798*73075011SMauro Carvalho Chehab struct hi3670_pcie_phy *phy; 799*73075011SMauro Carvalho Chehab struct phy *generic_phy; 800*73075011SMauro Carvalho Chehab int ret; 801*73075011SMauro Carvalho Chehab 802*73075011SMauro Carvalho Chehab phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 803*73075011SMauro Carvalho Chehab if (!phy) 804*73075011SMauro Carvalho Chehab return -ENOMEM; 805*73075011SMauro Carvalho Chehab 806*73075011SMauro Carvalho Chehab phy->dev = dev; 807*73075011SMauro Carvalho Chehab 808*73075011SMauro Carvalho Chehab ret = hi3670_pcie_phy_get_resources(phy, pdev); 809*73075011SMauro Carvalho Chehab if (ret) 810*73075011SMauro Carvalho Chehab return ret; 811*73075011SMauro Carvalho Chehab 812*73075011SMauro Carvalho Chehab generic_phy = devm_phy_create(dev, dev->of_node, &hi3670_phy_ops); 813*73075011SMauro Carvalho Chehab if (IS_ERR(generic_phy)) { 814*73075011SMauro Carvalho Chehab dev_err(dev, "failed to create PHY\n"); 815*73075011SMauro Carvalho Chehab return PTR_ERR(generic_phy); 816*73075011SMauro Carvalho Chehab } 817*73075011SMauro Carvalho Chehab 818*73075011SMauro Carvalho Chehab phy_set_drvdata(generic_phy, phy); 819*73075011SMauro Carvalho Chehab phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 820*73075011SMauro Carvalho Chehab 821*73075011SMauro Carvalho Chehab return PTR_ERR_OR_ZERO(phy_provider); 822*73075011SMauro Carvalho Chehab } 823*73075011SMauro Carvalho Chehab 824*73075011SMauro Carvalho Chehab static const struct of_device_id hi3670_pcie_phy_match[] = { 825*73075011SMauro Carvalho Chehab { 826*73075011SMauro Carvalho Chehab .compatible = "hisilicon,hi970-pcie-phy", 827*73075011SMauro Carvalho Chehab }, 828*73075011SMauro Carvalho Chehab {}, 829*73075011SMauro Carvalho Chehab }; 830*73075011SMauro Carvalho Chehab 831*73075011SMauro Carvalho Chehab static struct platform_driver hi3670_pcie_phy_driver = { 832*73075011SMauro Carvalho Chehab .probe = hi3670_pcie_phy_probe, 833*73075011SMauro Carvalho Chehab .driver = { 834*73075011SMauro Carvalho Chehab .of_match_table = hi3670_pcie_phy_match, 835*73075011SMauro Carvalho Chehab .name = "hi3670_pcie_phy", 836*73075011SMauro Carvalho Chehab .suppress_bind_attrs = true, 837*73075011SMauro Carvalho Chehab } 838*73075011SMauro Carvalho Chehab }; 839*73075011SMauro Carvalho Chehab builtin_platform_driver(hi3670_pcie_phy_driver); 840*73075011SMauro Carvalho Chehab 841*73075011SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, hi3670_pcie_phy_match); 842*73075011SMauro Carvalho Chehab MODULE_DESCRIPTION("PCIe phy driver for Kirin 970"); 843*73075011SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); 844*73075011SMauro Carvalho Chehab MODULE_AUTHOR("Manivannan Sadhasivam <mani@kernel.org>"); 845*73075011SMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 846