1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20b56e9a7SVivek Gautam /* 30b56e9a7SVivek Gautam * phy-ti-pipe3 - PIPE3 PHY driver. 40b56e9a7SVivek Gautam * 50b56e9a7SVivek Gautam * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com 60b56e9a7SVivek Gautam * Author: Kishon Vijay Abraham I <kishon@ti.com> 70b56e9a7SVivek Gautam */ 80b56e9a7SVivek Gautam 90b56e9a7SVivek Gautam #include <linux/module.h> 100b56e9a7SVivek Gautam #include <linux/platform_device.h> 110b56e9a7SVivek Gautam #include <linux/slab.h> 120b56e9a7SVivek Gautam #include <linux/phy/phy.h> 130b56e9a7SVivek Gautam #include <linux/of.h> 140b56e9a7SVivek Gautam #include <linux/clk.h> 150b56e9a7SVivek Gautam #include <linux/err.h> 160b56e9a7SVivek Gautam #include <linux/io.h> 170b56e9a7SVivek Gautam #include <linux/pm_runtime.h> 180b56e9a7SVivek Gautam #include <linux/delay.h> 190b56e9a7SVivek Gautam #include <linux/phy/omap_control_phy.h> 200b56e9a7SVivek Gautam #include <linux/of_platform.h> 210b56e9a7SVivek Gautam #include <linux/mfd/syscon.h> 220b56e9a7SVivek Gautam #include <linux/regmap.h> 230b56e9a7SVivek Gautam 240b56e9a7SVivek Gautam #define PLL_STATUS 0x00000004 250b56e9a7SVivek Gautam #define PLL_GO 0x00000008 260b56e9a7SVivek Gautam #define PLL_CONFIGURATION1 0x0000000C 270b56e9a7SVivek Gautam #define PLL_CONFIGURATION2 0x00000010 280b56e9a7SVivek Gautam #define PLL_CONFIGURATION3 0x00000014 290b56e9a7SVivek Gautam #define PLL_CONFIGURATION4 0x00000020 300b56e9a7SVivek Gautam 310b56e9a7SVivek Gautam #define PLL_REGM_MASK 0x001FFE00 320b56e9a7SVivek Gautam #define PLL_REGM_SHIFT 0x9 330b56e9a7SVivek Gautam #define PLL_REGM_F_MASK 0x0003FFFF 340b56e9a7SVivek Gautam #define PLL_REGM_F_SHIFT 0x0 350b56e9a7SVivek Gautam #define PLL_REGN_MASK 0x000001FE 360b56e9a7SVivek Gautam #define PLL_REGN_SHIFT 0x1 370b56e9a7SVivek Gautam #define PLL_SELFREQDCO_MASK 0x0000000E 380b56e9a7SVivek Gautam #define PLL_SELFREQDCO_SHIFT 0x1 390b56e9a7SVivek Gautam #define PLL_SD_MASK 0x0003FC00 400b56e9a7SVivek Gautam #define PLL_SD_SHIFT 10 410b56e9a7SVivek Gautam #define SET_PLL_GO 0x1 420b56e9a7SVivek Gautam #define PLL_LDOPWDN BIT(15) 430b56e9a7SVivek Gautam #define PLL_TICOPWDN BIT(16) 440b56e9a7SVivek Gautam #define PLL_LOCK 0x2 450b56e9a7SVivek Gautam #define PLL_IDLE 0x1 460b56e9a7SVivek Gautam 470b56e9a7SVivek Gautam #define SATA_PLL_SOFT_RESET BIT(18) 480b56e9a7SVivek Gautam 499d009d9cSRoger Quadros #define PIPE3_PHY_PWRCTL_CLK_CMD_MASK GENMASK(21, 14) 500b56e9a7SVivek Gautam #define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14 510b56e9a7SVivek Gautam 529d009d9cSRoger Quadros #define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK GENMASK(31, 22) 530b56e9a7SVivek Gautam #define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22 540b56e9a7SVivek Gautam 559d009d9cSRoger Quadros #define PIPE3_PHY_RX_POWERON (0x1 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT) 569d009d9cSRoger Quadros #define PIPE3_PHY_TX_POWERON (0x2 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT) 570b56e9a7SVivek Gautam 580b56e9a7SVivek Gautam #define PCIE_PCS_MASK 0xFF0000 590b56e9a7SVivek Gautam #define PCIE_PCS_DELAY_COUNT_SHIFT 0x10 600b56e9a7SVivek Gautam 61fdef2f9fSRoger Quadros #define PIPE3_PHY_RX_ANA_PROGRAMMABILITY 0x0000000C 622796ceb0SKishon Vijay Abraham I #define INTERFACE_MASK GENMASK(31, 27) 632796ceb0SKishon Vijay Abraham I #define INTERFACE_SHIFT 27 64fdef2f9fSRoger Quadros #define INTERFACE_MODE_USBSS BIT(4) 65fdef2f9fSRoger Quadros #define INTERFACE_MODE_SATA_1P5 BIT(3) 66fdef2f9fSRoger Quadros #define INTERFACE_MODE_SATA_3P0 BIT(2) 67fdef2f9fSRoger Quadros #define INTERFACE_MODE_PCIE BIT(0) 68fdef2f9fSRoger Quadros 692796ceb0SKishon Vijay Abraham I #define LOSD_MASK GENMASK(17, 14) 702796ceb0SKishon Vijay Abraham I #define LOSD_SHIFT 14 712796ceb0SKishon Vijay Abraham I #define MEM_PLLDIV GENMASK(6, 5) 722796ceb0SKishon Vijay Abraham I 73fdef2f9fSRoger Quadros #define PIPE3_PHY_RX_TRIM 0x0000001C 74fdef2f9fSRoger Quadros #define MEM_DLL_TRIM_SEL_MASK GENMASK(31, 30) 752796ceb0SKishon Vijay Abraham I #define MEM_DLL_TRIM_SHIFT 30 762796ceb0SKishon Vijay Abraham I 77fdef2f9fSRoger Quadros #define PIPE3_PHY_RX_DLL 0x00000024 78fdef2f9fSRoger Quadros #define MEM_DLL_PHINT_RATE_MASK GENMASK(31, 30) 79fdef2f9fSRoger Quadros #define MEM_DLL_PHINT_RATE_SHIFT 30 802796ceb0SKishon Vijay Abraham I 81fdef2f9fSRoger Quadros #define PIPE3_PHY_RX_DIGITAL_MODES 0x00000028 82fdef2f9fSRoger Quadros #define MEM_HS_RATE_MASK GENMASK(28, 27) 83fdef2f9fSRoger Quadros #define MEM_HS_RATE_SHIFT 27 84fdef2f9fSRoger Quadros #define MEM_OVRD_HS_RATE BIT(26) 85fdef2f9fSRoger Quadros #define MEM_OVRD_HS_RATE_SHIFT 26 862796ceb0SKishon Vijay Abraham I #define MEM_CDR_FASTLOCK BIT(23) 87fdef2f9fSRoger Quadros #define MEM_CDR_FASTLOCK_SHIFT 23 88fdef2f9fSRoger Quadros #define MEM_CDR_LBW_MASK GENMASK(22, 21) 89fdef2f9fSRoger Quadros #define MEM_CDR_LBW_SHIFT 21 90fdef2f9fSRoger Quadros #define MEM_CDR_STEPCNT_MASK GENMASK(20, 19) 91fdef2f9fSRoger Quadros #define MEM_CDR_STEPCNT_SHIFT 19 922796ceb0SKishon Vijay Abraham I #define MEM_CDR_STL_MASK GENMASK(18, 16) 932796ceb0SKishon Vijay Abraham I #define MEM_CDR_STL_SHIFT 16 942796ceb0SKishon Vijay Abraham I #define MEM_CDR_THR_MASK GENMASK(15, 13) 952796ceb0SKishon Vijay Abraham I #define MEM_CDR_THR_SHIFT 13 962796ceb0SKishon Vijay Abraham I #define MEM_CDR_THR_MODE BIT(12) 97fdef2f9fSRoger Quadros #define MEM_CDR_THR_MODE_SHIFT 12 98fdef2f9fSRoger Quadros #define MEM_CDR_2NDO_SDM_MODE BIT(11) 99fdef2f9fSRoger Quadros #define MEM_CDR_2NDO_SDM_MODE_SHIFT 11 1002796ceb0SKishon Vijay Abraham I 101fdef2f9fSRoger Quadros #define PIPE3_PHY_RX_EQUALIZER 0x00000038 102fdef2f9fSRoger Quadros #define MEM_EQLEV_MASK GENMASK(31, 16) 103fdef2f9fSRoger Quadros #define MEM_EQLEV_SHIFT 16 104fdef2f9fSRoger Quadros #define MEM_EQFTC_MASK GENMASK(15, 11) 105fdef2f9fSRoger Quadros #define MEM_EQFTC_SHIFT 11 106fdef2f9fSRoger Quadros #define MEM_EQCTL_MASK GENMASK(10, 7) 1072796ceb0SKishon Vijay Abraham I #define MEM_EQCTL_SHIFT 7 1082796ceb0SKishon Vijay Abraham I #define MEM_OVRD_EQLEV BIT(2) 109fdef2f9fSRoger Quadros #define MEM_OVRD_EQLEV_SHIFT 2 1102796ceb0SKishon Vijay Abraham I #define MEM_OVRD_EQFTC BIT(1) 111fdef2f9fSRoger Quadros #define MEM_OVRD_EQFTC_SHIFT 1 112fdef2f9fSRoger Quadros 113fdef2f9fSRoger Quadros #define SATA_PHY_RX_IO_AND_A2D_OVERRIDES 0x44 114fdef2f9fSRoger Quadros #define MEM_CDR_LOS_SOURCE_MASK GENMASK(10, 9) 115fdef2f9fSRoger Quadros #define MEM_CDR_LOS_SOURCE_SHIFT 9 1162796ceb0SKishon Vijay Abraham I 1170b56e9a7SVivek Gautam /* 1180b56e9a7SVivek Gautam * This is an Empirical value that works, need to confirm the actual 1190b56e9a7SVivek Gautam * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status 1200b56e9a7SVivek Gautam * to be correctly reflected in the PIPE3PHY_PLL_STATUS register. 1210b56e9a7SVivek Gautam */ 1220b56e9a7SVivek Gautam #define PLL_IDLE_TIME 100 /* in milliseconds */ 1230b56e9a7SVivek Gautam #define PLL_LOCK_TIME 100 /* in milliseconds */ 1240b56e9a7SVivek Gautam 12522940823SRoger Quadros enum pipe3_mode { PIPE3_MODE_PCIE = 1, 12622940823SRoger Quadros PIPE3_MODE_SATA, 12722940823SRoger Quadros PIPE3_MODE_USBSS }; 12822940823SRoger Quadros 1290b56e9a7SVivek Gautam struct pipe3_dpll_params { 1300b56e9a7SVivek Gautam u16 m; 1310b56e9a7SVivek Gautam u8 n; 1320b56e9a7SVivek Gautam u8 freq:3; 1330b56e9a7SVivek Gautam u8 sd; 1340b56e9a7SVivek Gautam u32 mf; 1350b56e9a7SVivek Gautam }; 1360b56e9a7SVivek Gautam 1370b56e9a7SVivek Gautam struct pipe3_dpll_map { 1380b56e9a7SVivek Gautam unsigned long rate; 1390b56e9a7SVivek Gautam struct pipe3_dpll_params params; 1400b56e9a7SVivek Gautam }; 1410b56e9a7SVivek Gautam 142fdef2f9fSRoger Quadros struct pipe3_settings { 143fdef2f9fSRoger Quadros u8 ana_interface; 144fdef2f9fSRoger Quadros u8 ana_losd; 145fdef2f9fSRoger Quadros u8 dig_fastlock; 146fdef2f9fSRoger Quadros u8 dig_lbw; 147fdef2f9fSRoger Quadros u8 dig_stepcnt; 148fdef2f9fSRoger Quadros u8 dig_stl; 149fdef2f9fSRoger Quadros u8 dig_thr; 150fdef2f9fSRoger Quadros u8 dig_thr_mode; 151fdef2f9fSRoger Quadros u8 dig_2ndo_sdm_mode; 152fdef2f9fSRoger Quadros u8 dig_hs_rate; 153fdef2f9fSRoger Quadros u8 dig_ovrd_hs_rate; 154fdef2f9fSRoger Quadros u8 dll_trim_sel; 155fdef2f9fSRoger Quadros u8 dll_phint_rate; 156fdef2f9fSRoger Quadros u8 eq_lev; 157fdef2f9fSRoger Quadros u8 eq_ftc; 158fdef2f9fSRoger Quadros u8 eq_ctl; 159fdef2f9fSRoger Quadros u8 eq_ovrd_lev; 160fdef2f9fSRoger Quadros u8 eq_ovrd_ftc; 161fdef2f9fSRoger Quadros }; 162fdef2f9fSRoger Quadros 1630b56e9a7SVivek Gautam struct ti_pipe3 { 1640b56e9a7SVivek Gautam void __iomem *pll_ctrl_base; 1652796ceb0SKishon Vijay Abraham I void __iomem *phy_rx; 1662796ceb0SKishon Vijay Abraham I void __iomem *phy_tx; 1670b56e9a7SVivek Gautam struct device *dev; 1680b56e9a7SVivek Gautam struct device *control_dev; 1690b56e9a7SVivek Gautam struct clk *wkupclk; 1700b56e9a7SVivek Gautam struct clk *sys_clk; 1710b56e9a7SVivek Gautam struct clk *refclk; 1720b56e9a7SVivek Gautam struct clk *div_clk; 1730b56e9a7SVivek Gautam struct pipe3_dpll_map *dpll_map; 1740b56e9a7SVivek Gautam struct regmap *phy_power_syscon; /* ctrl. reg. acces */ 1750b56e9a7SVivek Gautam struct regmap *pcs_syscon; /* ctrl. reg. acces */ 1760b56e9a7SVivek Gautam struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */ 1770b56e9a7SVivek Gautam unsigned int dpll_reset_reg; /* reg. index within syscon */ 1780b56e9a7SVivek Gautam unsigned int power_reg; /* power reg. index within syscon */ 1790b56e9a7SVivek Gautam unsigned int pcie_pcs_reg; /* pcs reg. index in syscon */ 1800b56e9a7SVivek Gautam bool sata_refclk_enabled; 18122940823SRoger Quadros enum pipe3_mode mode; 182fdef2f9fSRoger Quadros struct pipe3_settings settings; 1830b56e9a7SVivek Gautam }; 1840b56e9a7SVivek Gautam 1850b56e9a7SVivek Gautam static struct pipe3_dpll_map dpll_map_usb[] = { 1860b56e9a7SVivek Gautam {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ 1870b56e9a7SVivek Gautam {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ 1880b56e9a7SVivek Gautam {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ 1890b56e9a7SVivek Gautam {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ 1900b56e9a7SVivek Gautam {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ 1910b56e9a7SVivek Gautam {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ 1920b56e9a7SVivek Gautam { }, /* Terminator */ 1930b56e9a7SVivek Gautam }; 1940b56e9a7SVivek Gautam 1950b56e9a7SVivek Gautam static struct pipe3_dpll_map dpll_map_sata[] = { 196325ce0feSRoger Quadros {12000000, {625, 4, 4, 6, 0} }, /* 12 MHz */ 197325ce0feSRoger Quadros {16800000, {625, 6, 4, 7, 0} }, /* 16.8 MHz */ 1980b56e9a7SVivek Gautam {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */ 199325ce0feSRoger Quadros {20000000, {750, 9, 4, 6, 0} }, /* 20 MHz */ 200325ce0feSRoger Quadros {26000000, {750, 12, 4, 6, 0} }, /* 26 MHz */ 201325ce0feSRoger Quadros {38400000, {625, 15, 4, 6, 0} }, /* 38.4 MHz */ 2020b56e9a7SVivek Gautam { }, /* Terminator */ 2030b56e9a7SVivek Gautam }; 2040b56e9a7SVivek Gautam 20522940823SRoger Quadros struct pipe3_data { 20622940823SRoger Quadros enum pipe3_mode mode; 20722940823SRoger Quadros struct pipe3_dpll_map *dpll_map; 208fdef2f9fSRoger Quadros struct pipe3_settings settings; 20922940823SRoger Quadros }; 21022940823SRoger Quadros 21122940823SRoger Quadros static struct pipe3_data data_usb = { 21222940823SRoger Quadros .mode = PIPE3_MODE_USBSS, 21322940823SRoger Quadros .dpll_map = dpll_map_usb, 214fdef2f9fSRoger Quadros .settings = { 215fdef2f9fSRoger Quadros /* DRA75x TRM Table 26-17 Preferred USB3_PHY_RX SCP Register Settings */ 216fdef2f9fSRoger Quadros .ana_interface = INTERFACE_MODE_USBSS, 217fdef2f9fSRoger Quadros .ana_losd = 0xa, 218fdef2f9fSRoger Quadros .dig_fastlock = 1, 219fdef2f9fSRoger Quadros .dig_lbw = 3, 220fdef2f9fSRoger Quadros .dig_stepcnt = 0, 221fdef2f9fSRoger Quadros .dig_stl = 0x3, 222fdef2f9fSRoger Quadros .dig_thr = 1, 223fdef2f9fSRoger Quadros .dig_thr_mode = 1, 224fdef2f9fSRoger Quadros .dig_2ndo_sdm_mode = 0, 225fdef2f9fSRoger Quadros .dig_hs_rate = 0, 226fdef2f9fSRoger Quadros .dig_ovrd_hs_rate = 1, 227fdef2f9fSRoger Quadros .dll_trim_sel = 0x2, 228fdef2f9fSRoger Quadros .dll_phint_rate = 0x3, 229fdef2f9fSRoger Quadros .eq_lev = 0, 230fdef2f9fSRoger Quadros .eq_ftc = 0, 231fdef2f9fSRoger Quadros .eq_ctl = 0x9, 232fdef2f9fSRoger Quadros .eq_ovrd_lev = 0, 233fdef2f9fSRoger Quadros .eq_ovrd_ftc = 0, 234fdef2f9fSRoger Quadros }, 23522940823SRoger Quadros }; 23622940823SRoger Quadros 23722940823SRoger Quadros static struct pipe3_data data_sata = { 23822940823SRoger Quadros .mode = PIPE3_MODE_SATA, 23922940823SRoger Quadros .dpll_map = dpll_map_sata, 240fdef2f9fSRoger Quadros .settings = { 241fdef2f9fSRoger Quadros /* DRA75x TRM Table 26-9 Preferred SATA_PHY_RX SCP Register Settings */ 242fdef2f9fSRoger Quadros .ana_interface = INTERFACE_MODE_SATA_3P0, 243fdef2f9fSRoger Quadros .ana_losd = 0x5, 244fdef2f9fSRoger Quadros .dig_fastlock = 1, 245fdef2f9fSRoger Quadros .dig_lbw = 3, 246fdef2f9fSRoger Quadros .dig_stepcnt = 0, 247fdef2f9fSRoger Quadros .dig_stl = 0x3, 248fdef2f9fSRoger Quadros .dig_thr = 1, 249fdef2f9fSRoger Quadros .dig_thr_mode = 1, 250fdef2f9fSRoger Quadros .dig_2ndo_sdm_mode = 0, 251fdef2f9fSRoger Quadros .dig_hs_rate = 0, /* Not in TRM preferred settings */ 252fdef2f9fSRoger Quadros .dig_ovrd_hs_rate = 0, /* Not in TRM preferred settings */ 253fdef2f9fSRoger Quadros .dll_trim_sel = 0x1, 254fdef2f9fSRoger Quadros .dll_phint_rate = 0x2, /* for 1.5 GHz DPLL clock */ 255fdef2f9fSRoger Quadros .eq_lev = 0, 256fdef2f9fSRoger Quadros .eq_ftc = 0x1f, 257fdef2f9fSRoger Quadros .eq_ctl = 0, 258fdef2f9fSRoger Quadros .eq_ovrd_lev = 1, 259fdef2f9fSRoger Quadros .eq_ovrd_ftc = 1, 260fdef2f9fSRoger Quadros }, 26122940823SRoger Quadros }; 26222940823SRoger Quadros 26322940823SRoger Quadros static struct pipe3_data data_pcie = { 26422940823SRoger Quadros .mode = PIPE3_MODE_PCIE, 265fdef2f9fSRoger Quadros .settings = { 266fdef2f9fSRoger Quadros /* DRA75x TRM Table 26-62 Preferred PCIe_PHY_RX SCP Register Settings */ 267fdef2f9fSRoger Quadros .ana_interface = INTERFACE_MODE_PCIE, 268fdef2f9fSRoger Quadros .ana_losd = 0xa, 269fdef2f9fSRoger Quadros .dig_fastlock = 1, 270fdef2f9fSRoger Quadros .dig_lbw = 3, 271fdef2f9fSRoger Quadros .dig_stepcnt = 0, 272fdef2f9fSRoger Quadros .dig_stl = 0x3, 273fdef2f9fSRoger Quadros .dig_thr = 1, 274fdef2f9fSRoger Quadros .dig_thr_mode = 1, 275fdef2f9fSRoger Quadros .dig_2ndo_sdm_mode = 0, 276fdef2f9fSRoger Quadros .dig_hs_rate = 0, 277fdef2f9fSRoger Quadros .dig_ovrd_hs_rate = 0, 278fdef2f9fSRoger Quadros .dll_trim_sel = 0x2, 279fdef2f9fSRoger Quadros .dll_phint_rate = 0x3, 280fdef2f9fSRoger Quadros .eq_lev = 0, 281fdef2f9fSRoger Quadros .eq_ftc = 0x1f, 282fdef2f9fSRoger Quadros .eq_ctl = 1, 283fdef2f9fSRoger Quadros .eq_ovrd_lev = 0, 284fdef2f9fSRoger Quadros .eq_ovrd_ftc = 0, 285fdef2f9fSRoger Quadros }, 28622940823SRoger Quadros }; 28722940823SRoger Quadros 2880b56e9a7SVivek Gautam static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset) 2890b56e9a7SVivek Gautam { 2900b56e9a7SVivek Gautam return __raw_readl(addr + offset); 2910b56e9a7SVivek Gautam } 2920b56e9a7SVivek Gautam 2930b56e9a7SVivek Gautam static inline void ti_pipe3_writel(void __iomem *addr, unsigned offset, 2940b56e9a7SVivek Gautam u32 data) 2950b56e9a7SVivek Gautam { 2960b56e9a7SVivek Gautam __raw_writel(data, addr + offset); 2970b56e9a7SVivek Gautam } 2980b56e9a7SVivek Gautam 2990b56e9a7SVivek Gautam static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy) 3000b56e9a7SVivek Gautam { 3010b56e9a7SVivek Gautam unsigned long rate; 3020b56e9a7SVivek Gautam struct pipe3_dpll_map *dpll_map = phy->dpll_map; 3030b56e9a7SVivek Gautam 3040b56e9a7SVivek Gautam rate = clk_get_rate(phy->sys_clk); 3050b56e9a7SVivek Gautam 3060b56e9a7SVivek Gautam for (; dpll_map->rate; dpll_map++) { 3070b56e9a7SVivek Gautam if (rate == dpll_map->rate) 3080b56e9a7SVivek Gautam return &dpll_map->params; 3090b56e9a7SVivek Gautam } 3100b56e9a7SVivek Gautam 3110b56e9a7SVivek Gautam dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate); 3120b56e9a7SVivek Gautam 3130b56e9a7SVivek Gautam return NULL; 3140b56e9a7SVivek Gautam } 3150b56e9a7SVivek Gautam 3160b56e9a7SVivek Gautam static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy); 3170b56e9a7SVivek Gautam static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy); 3180b56e9a7SVivek Gautam 3190b56e9a7SVivek Gautam static int ti_pipe3_power_off(struct phy *x) 3200b56e9a7SVivek Gautam { 3210b56e9a7SVivek Gautam int ret; 3220b56e9a7SVivek Gautam struct ti_pipe3 *phy = phy_get_drvdata(x); 3230b56e9a7SVivek Gautam 3240b56e9a7SVivek Gautam if (!phy->phy_power_syscon) { 3250b56e9a7SVivek Gautam omap_control_phy_power(phy->control_dev, 0); 3260b56e9a7SVivek Gautam return 0; 3270b56e9a7SVivek Gautam } 3280b56e9a7SVivek Gautam 3290b56e9a7SVivek Gautam ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 3309d009d9cSRoger Quadros PIPE3_PHY_PWRCTL_CLK_CMD_MASK, 0); 3310b56e9a7SVivek Gautam return ret; 3320b56e9a7SVivek Gautam } 3330b56e9a7SVivek Gautam 3341d1bae72SRoger Quadros static void ti_pipe3_calibrate(struct ti_pipe3 *phy); 3351d1bae72SRoger Quadros 3360b56e9a7SVivek Gautam static int ti_pipe3_power_on(struct phy *x) 3370b56e9a7SVivek Gautam { 3380b56e9a7SVivek Gautam u32 val; 3390b56e9a7SVivek Gautam u32 mask; 3400b56e9a7SVivek Gautam unsigned long rate; 3410b56e9a7SVivek Gautam struct ti_pipe3 *phy = phy_get_drvdata(x); 3429d009d9cSRoger Quadros bool rx_pending = false; 3430b56e9a7SVivek Gautam 3440b56e9a7SVivek Gautam if (!phy->phy_power_syscon) { 3450b56e9a7SVivek Gautam omap_control_phy_power(phy->control_dev, 1); 3460b56e9a7SVivek Gautam return 0; 3470b56e9a7SVivek Gautam } 3480b56e9a7SVivek Gautam 3490b56e9a7SVivek Gautam rate = clk_get_rate(phy->sys_clk); 3500b56e9a7SVivek Gautam if (!rate) { 3510b56e9a7SVivek Gautam dev_err(phy->dev, "Invalid clock rate\n"); 3520b56e9a7SVivek Gautam return -EINVAL; 3530b56e9a7SVivek Gautam } 3540b56e9a7SVivek Gautam rate = rate / 1000000; 3559d009d9cSRoger Quadros mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK; 3569d009d9cSRoger Quadros val = rate << OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT; 3573cc4502cSVinod Koul regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 3580b56e9a7SVivek Gautam mask, val); 3599d009d9cSRoger Quadros /* 3609d009d9cSRoger Quadros * For PCIe, TX and RX must be powered on simultaneously. 3619d009d9cSRoger Quadros * For USB and SATA, TX must be powered on before RX 3629d009d9cSRoger Quadros */ 3639d009d9cSRoger Quadros mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK; 3649d009d9cSRoger Quadros if (phy->mode == PIPE3_MODE_SATA || phy->mode == PIPE3_MODE_USBSS) { 3659d009d9cSRoger Quadros val = PIPE3_PHY_TX_POWERON; 3669d009d9cSRoger Quadros rx_pending = true; 3679d009d9cSRoger Quadros } else { 3689d009d9cSRoger Quadros val = PIPE3_PHY_TX_POWERON | PIPE3_PHY_RX_POWERON; 3699d009d9cSRoger Quadros } 3709d009d9cSRoger Quadros 3719d009d9cSRoger Quadros regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 3729d009d9cSRoger Quadros mask, val); 3739d009d9cSRoger Quadros 3749d009d9cSRoger Quadros if (rx_pending) { 3759d009d9cSRoger Quadros val = PIPE3_PHY_TX_POWERON | PIPE3_PHY_RX_POWERON; 3769d009d9cSRoger Quadros regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 3779d009d9cSRoger Quadros mask, val); 3789d009d9cSRoger Quadros } 3799d009d9cSRoger Quadros 3801d1bae72SRoger Quadros if (phy->mode == PIPE3_MODE_PCIE) 3811d1bae72SRoger Quadros ti_pipe3_calibrate(phy); 3821d1bae72SRoger Quadros 3839d009d9cSRoger Quadros return 0; 3840b56e9a7SVivek Gautam } 3850b56e9a7SVivek Gautam 3860b56e9a7SVivek Gautam static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy) 3870b56e9a7SVivek Gautam { 3880b56e9a7SVivek Gautam u32 val; 3890b56e9a7SVivek Gautam unsigned long timeout; 3900b56e9a7SVivek Gautam 3910b56e9a7SVivek Gautam timeout = jiffies + msecs_to_jiffies(PLL_LOCK_TIME); 3920b56e9a7SVivek Gautam do { 3930b56e9a7SVivek Gautam cpu_relax(); 3940b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); 3950b56e9a7SVivek Gautam if (val & PLL_LOCK) 3960b56e9a7SVivek Gautam return 0; 3970b56e9a7SVivek Gautam } while (!time_after(jiffies, timeout)); 3980b56e9a7SVivek Gautam 3990b56e9a7SVivek Gautam dev_err(phy->dev, "DPLL failed to lock\n"); 4000b56e9a7SVivek Gautam return -EBUSY; 4010b56e9a7SVivek Gautam } 4020b56e9a7SVivek Gautam 4030b56e9a7SVivek Gautam static int ti_pipe3_dpll_program(struct ti_pipe3 *phy) 4040b56e9a7SVivek Gautam { 4050b56e9a7SVivek Gautam u32 val; 4060b56e9a7SVivek Gautam struct pipe3_dpll_params *dpll_params; 4070b56e9a7SVivek Gautam 4080b56e9a7SVivek Gautam dpll_params = ti_pipe3_get_dpll_params(phy); 4090b56e9a7SVivek Gautam if (!dpll_params) 4100b56e9a7SVivek Gautam return -EINVAL; 4110b56e9a7SVivek Gautam 4120b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); 4130b56e9a7SVivek Gautam val &= ~PLL_REGN_MASK; 4140b56e9a7SVivek Gautam val |= dpll_params->n << PLL_REGN_SHIFT; 4150b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); 4160b56e9a7SVivek Gautam 4170b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 4180b56e9a7SVivek Gautam val &= ~PLL_SELFREQDCO_MASK; 4190b56e9a7SVivek Gautam val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; 4200b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 4210b56e9a7SVivek Gautam 4220b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); 4230b56e9a7SVivek Gautam val &= ~PLL_REGM_MASK; 4240b56e9a7SVivek Gautam val |= dpll_params->m << PLL_REGM_SHIFT; 4250b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); 4260b56e9a7SVivek Gautam 4270b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); 4280b56e9a7SVivek Gautam val &= ~PLL_REGM_F_MASK; 4290b56e9a7SVivek Gautam val |= dpll_params->mf << PLL_REGM_F_SHIFT; 4300b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); 4310b56e9a7SVivek Gautam 4320b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); 4330b56e9a7SVivek Gautam val &= ~PLL_SD_MASK; 4340b56e9a7SVivek Gautam val |= dpll_params->sd << PLL_SD_SHIFT; 4350b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); 4360b56e9a7SVivek Gautam 4370b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO); 4380b56e9a7SVivek Gautam 4390b56e9a7SVivek Gautam return ti_pipe3_dpll_wait_lock(phy); 4400b56e9a7SVivek Gautam } 4410b56e9a7SVivek Gautam 4422796ceb0SKishon Vijay Abraham I static void ti_pipe3_calibrate(struct ti_pipe3 *phy) 4432796ceb0SKishon Vijay Abraham I { 4442796ceb0SKishon Vijay Abraham I u32 val; 445fdef2f9fSRoger Quadros struct pipe3_settings *s = &phy->settings; 4462796ceb0SKishon Vijay Abraham I 447fdef2f9fSRoger Quadros val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY); 4482796ceb0SKishon Vijay Abraham I val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV); 449fdef2f9fSRoger Quadros val |= (s->ana_interface << INTERFACE_SHIFT | s->ana_losd << LOSD_SHIFT); 450fdef2f9fSRoger Quadros ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY, val); 4512796ceb0SKishon Vijay Abraham I 452fdef2f9fSRoger Quadros val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES); 453fdef2f9fSRoger Quadros val &= ~(MEM_HS_RATE_MASK | MEM_OVRD_HS_RATE | MEM_CDR_FASTLOCK | 454fdef2f9fSRoger Quadros MEM_CDR_LBW_MASK | MEM_CDR_STEPCNT_MASK | MEM_CDR_STL_MASK | 455fdef2f9fSRoger Quadros MEM_CDR_THR_MASK | MEM_CDR_THR_MODE | MEM_CDR_2NDO_SDM_MODE); 456fdef2f9fSRoger Quadros val |= s->dig_hs_rate << MEM_HS_RATE_SHIFT | 457fdef2f9fSRoger Quadros s->dig_ovrd_hs_rate << MEM_OVRD_HS_RATE_SHIFT | 458fdef2f9fSRoger Quadros s->dig_fastlock << MEM_CDR_FASTLOCK_SHIFT | 459fdef2f9fSRoger Quadros s->dig_lbw << MEM_CDR_LBW_SHIFT | 460fdef2f9fSRoger Quadros s->dig_stepcnt << MEM_CDR_STEPCNT_SHIFT | 461fdef2f9fSRoger Quadros s->dig_stl << MEM_CDR_STL_SHIFT | 462fdef2f9fSRoger Quadros s->dig_thr << MEM_CDR_THR_SHIFT | 463fdef2f9fSRoger Quadros s->dig_thr_mode << MEM_CDR_THR_MODE_SHIFT | 464fdef2f9fSRoger Quadros s->dig_2ndo_sdm_mode << MEM_CDR_2NDO_SDM_MODE_SHIFT; 465fdef2f9fSRoger Quadros ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES, val); 4662796ceb0SKishon Vijay Abraham I 467fdef2f9fSRoger Quadros val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM); 468fdef2f9fSRoger Quadros val &= ~MEM_DLL_TRIM_SEL_MASK; 469fdef2f9fSRoger Quadros val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT; 470fdef2f9fSRoger Quadros ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val); 4712796ceb0SKishon Vijay Abraham I 472fdef2f9fSRoger Quadros val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL); 473fdef2f9fSRoger Quadros val &= ~MEM_DLL_PHINT_RATE_MASK; 474fdef2f9fSRoger Quadros val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT; 475fdef2f9fSRoger Quadros ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val); 4762796ceb0SKishon Vijay Abraham I 477fdef2f9fSRoger Quadros val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER); 478fdef2f9fSRoger Quadros val &= ~(MEM_EQLEV_MASK | MEM_EQFTC_MASK | MEM_EQCTL_MASK | 479fdef2f9fSRoger Quadros MEM_OVRD_EQLEV | MEM_OVRD_EQFTC); 480fdef2f9fSRoger Quadros val |= s->eq_lev << MEM_EQLEV_SHIFT | 481fdef2f9fSRoger Quadros s->eq_ftc << MEM_EQFTC_SHIFT | 482fdef2f9fSRoger Quadros s->eq_ctl << MEM_EQCTL_SHIFT | 483fdef2f9fSRoger Quadros s->eq_ovrd_lev << MEM_OVRD_EQLEV_SHIFT | 484fdef2f9fSRoger Quadros s->eq_ovrd_ftc << MEM_OVRD_EQFTC_SHIFT; 485fdef2f9fSRoger Quadros ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER, val); 486fdef2f9fSRoger Quadros 487fdef2f9fSRoger Quadros if (phy->mode == PIPE3_MODE_SATA) { 488fdef2f9fSRoger Quadros val = ti_pipe3_readl(phy->phy_rx, 489fdef2f9fSRoger Quadros SATA_PHY_RX_IO_AND_A2D_OVERRIDES); 490fdef2f9fSRoger Quadros val &= ~MEM_CDR_LOS_SOURCE_MASK; 491fdef2f9fSRoger Quadros ti_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES, 492fdef2f9fSRoger Quadros val); 493fdef2f9fSRoger Quadros } 4942796ceb0SKishon Vijay Abraham I } 4952796ceb0SKishon Vijay Abraham I 4960b56e9a7SVivek Gautam static int ti_pipe3_init(struct phy *x) 4970b56e9a7SVivek Gautam { 4980b56e9a7SVivek Gautam struct ti_pipe3 *phy = phy_get_drvdata(x); 4990b56e9a7SVivek Gautam u32 val; 5000b56e9a7SVivek Gautam int ret = 0; 5010b56e9a7SVivek Gautam 5020b56e9a7SVivek Gautam ti_pipe3_enable_clocks(phy); 5030b56e9a7SVivek Gautam /* 5040b56e9a7SVivek Gautam * Set pcie_pcs register to 0x96 for proper functioning of phy 5050b56e9a7SVivek Gautam * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table 5060b56e9a7SVivek Gautam * 18-1804. 5070b56e9a7SVivek Gautam */ 50822940823SRoger Quadros if (phy->mode == PIPE3_MODE_PCIE) { 5090b56e9a7SVivek Gautam if (!phy->pcs_syscon) { 5100b56e9a7SVivek Gautam omap_control_pcie_pcs(phy->control_dev, 0x96); 5110b56e9a7SVivek Gautam return 0; 5120b56e9a7SVivek Gautam } 5130b56e9a7SVivek Gautam 5140b56e9a7SVivek Gautam val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT; 5150b56e9a7SVivek Gautam ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg, 5160b56e9a7SVivek Gautam PCIE_PCS_MASK, val); 5170b56e9a7SVivek Gautam return ret; 5180b56e9a7SVivek Gautam } 5190b56e9a7SVivek Gautam 5200b56e9a7SVivek Gautam /* Bring it out of IDLE if it is IDLE */ 5210b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 5220b56e9a7SVivek Gautam if (val & PLL_IDLE) { 5230b56e9a7SVivek Gautam val &= ~PLL_IDLE; 5240b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 5250b56e9a7SVivek Gautam ret = ti_pipe3_dpll_wait_lock(phy); 5260b56e9a7SVivek Gautam } 5270b56e9a7SVivek Gautam 5280b56e9a7SVivek Gautam /* SATA has issues if re-programmed when locked */ 5290b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); 53022940823SRoger Quadros if ((val & PLL_LOCK) && phy->mode == PIPE3_MODE_SATA) 5310b56e9a7SVivek Gautam return ret; 5320b56e9a7SVivek Gautam 5330b56e9a7SVivek Gautam /* Program the DPLL */ 5340b56e9a7SVivek Gautam ret = ti_pipe3_dpll_program(phy); 5350b56e9a7SVivek Gautam if (ret) { 5360b56e9a7SVivek Gautam ti_pipe3_disable_clocks(phy); 5370b56e9a7SVivek Gautam return -EINVAL; 5380b56e9a7SVivek Gautam } 5390b56e9a7SVivek Gautam 540fdef2f9fSRoger Quadros ti_pipe3_calibrate(phy); 541fdef2f9fSRoger Quadros 5420b56e9a7SVivek Gautam return ret; 5430b56e9a7SVivek Gautam } 5440b56e9a7SVivek Gautam 5450b56e9a7SVivek Gautam static int ti_pipe3_exit(struct phy *x) 5460b56e9a7SVivek Gautam { 5470b56e9a7SVivek Gautam struct ti_pipe3 *phy = phy_get_drvdata(x); 5480b56e9a7SVivek Gautam u32 val; 5490b56e9a7SVivek Gautam unsigned long timeout; 5500b56e9a7SVivek Gautam 5510b56e9a7SVivek Gautam /* If dpll_reset_syscon is not present we wont power down SATA DPLL 5520b56e9a7SVivek Gautam * due to Errata i783 5530b56e9a7SVivek Gautam */ 55422940823SRoger Quadros if (phy->mode == PIPE3_MODE_SATA && !phy->dpll_reset_syscon) 5550b56e9a7SVivek Gautam return 0; 5560b56e9a7SVivek Gautam 5570b56e9a7SVivek Gautam /* PCIe doesn't have internal DPLL */ 55822940823SRoger Quadros if (phy->mode != PIPE3_MODE_PCIE) { 5590b56e9a7SVivek Gautam /* Put DPLL in IDLE mode */ 5600b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 5610b56e9a7SVivek Gautam val |= PLL_IDLE; 5620b56e9a7SVivek Gautam ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 5630b56e9a7SVivek Gautam 5640b56e9a7SVivek Gautam /* wait for LDO and Oscillator to power down */ 5650b56e9a7SVivek Gautam timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME); 5660b56e9a7SVivek Gautam do { 5670b56e9a7SVivek Gautam cpu_relax(); 5680b56e9a7SVivek Gautam val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); 5690b56e9a7SVivek Gautam if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN)) 5700b56e9a7SVivek Gautam break; 5710b56e9a7SVivek Gautam } while (!time_after(jiffies, timeout)); 5720b56e9a7SVivek Gautam 5730b56e9a7SVivek Gautam if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) { 5740b56e9a7SVivek Gautam dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n", 5750b56e9a7SVivek Gautam val); 5760b56e9a7SVivek Gautam return -EBUSY; 5770b56e9a7SVivek Gautam } 5780b56e9a7SVivek Gautam } 5790b56e9a7SVivek Gautam 5800b56e9a7SVivek Gautam /* i783: SATA needs control bit toggle after PLL unlock */ 58122940823SRoger Quadros if (phy->mode == PIPE3_MODE_SATA) { 5820b56e9a7SVivek Gautam regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, 5830b56e9a7SVivek Gautam SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET); 5840b56e9a7SVivek Gautam regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, 5850b56e9a7SVivek Gautam SATA_PLL_SOFT_RESET, 0); 5860b56e9a7SVivek Gautam } 5870b56e9a7SVivek Gautam 5880b56e9a7SVivek Gautam ti_pipe3_disable_clocks(phy); 5890b56e9a7SVivek Gautam 5900b56e9a7SVivek Gautam return 0; 5910b56e9a7SVivek Gautam } 5920b56e9a7SVivek Gautam static const struct phy_ops ops = { 5930b56e9a7SVivek Gautam .init = ti_pipe3_init, 5940b56e9a7SVivek Gautam .exit = ti_pipe3_exit, 5950b56e9a7SVivek Gautam .power_on = ti_pipe3_power_on, 5960b56e9a7SVivek Gautam .power_off = ti_pipe3_power_off, 5970b56e9a7SVivek Gautam .owner = THIS_MODULE, 5980b56e9a7SVivek Gautam }; 5990b56e9a7SVivek Gautam 6000b56e9a7SVivek Gautam static const struct of_device_id ti_pipe3_id_table[]; 6010b56e9a7SVivek Gautam 6020b56e9a7SVivek Gautam static int ti_pipe3_get_clk(struct ti_pipe3 *phy) 6030b56e9a7SVivek Gautam { 6040b56e9a7SVivek Gautam struct clk *clk; 6050b56e9a7SVivek Gautam struct device *dev = phy->dev; 6060b56e9a7SVivek Gautam 6070b56e9a7SVivek Gautam phy->refclk = devm_clk_get(dev, "refclk"); 6080b56e9a7SVivek Gautam if (IS_ERR(phy->refclk)) { 6090b56e9a7SVivek Gautam dev_err(dev, "unable to get refclk\n"); 6100b56e9a7SVivek Gautam /* older DTBs have missing refclk in SATA PHY 6110b56e9a7SVivek Gautam * so don't bail out in case of SATA PHY. 6120b56e9a7SVivek Gautam */ 61322940823SRoger Quadros if (phy->mode != PIPE3_MODE_SATA) 6140b56e9a7SVivek Gautam return PTR_ERR(phy->refclk); 6150b56e9a7SVivek Gautam } 6160b56e9a7SVivek Gautam 61722940823SRoger Quadros if (phy->mode != PIPE3_MODE_SATA) { 6180b56e9a7SVivek Gautam phy->wkupclk = devm_clk_get(dev, "wkupclk"); 6190b56e9a7SVivek Gautam if (IS_ERR(phy->wkupclk)) { 6200b56e9a7SVivek Gautam dev_err(dev, "unable to get wkupclk\n"); 6210b56e9a7SVivek Gautam return PTR_ERR(phy->wkupclk); 6220b56e9a7SVivek Gautam } 6230b56e9a7SVivek Gautam } else { 6240b56e9a7SVivek Gautam phy->wkupclk = ERR_PTR(-ENODEV); 6250b56e9a7SVivek Gautam } 6260b56e9a7SVivek Gautam 62722940823SRoger Quadros if (phy->mode != PIPE3_MODE_PCIE || phy->phy_power_syscon) { 6280b56e9a7SVivek Gautam phy->sys_clk = devm_clk_get(dev, "sysclk"); 6290b56e9a7SVivek Gautam if (IS_ERR(phy->sys_clk)) { 6300b56e9a7SVivek Gautam dev_err(dev, "unable to get sysclk\n"); 6310b56e9a7SVivek Gautam return -EINVAL; 6320b56e9a7SVivek Gautam } 6330b56e9a7SVivek Gautam } 6340b56e9a7SVivek Gautam 63522940823SRoger Quadros if (phy->mode == PIPE3_MODE_PCIE) { 6360b56e9a7SVivek Gautam clk = devm_clk_get(dev, "dpll_ref"); 6370b56e9a7SVivek Gautam if (IS_ERR(clk)) { 6380b56e9a7SVivek Gautam dev_err(dev, "unable to get dpll ref clk\n"); 6390b56e9a7SVivek Gautam return PTR_ERR(clk); 6400b56e9a7SVivek Gautam } 6410b56e9a7SVivek Gautam clk_set_rate(clk, 1500000000); 6420b56e9a7SVivek Gautam 6430b56e9a7SVivek Gautam clk = devm_clk_get(dev, "dpll_ref_m2"); 6440b56e9a7SVivek Gautam if (IS_ERR(clk)) { 6450b56e9a7SVivek Gautam dev_err(dev, "unable to get dpll ref m2 clk\n"); 6460b56e9a7SVivek Gautam return PTR_ERR(clk); 6470b56e9a7SVivek Gautam } 6480b56e9a7SVivek Gautam clk_set_rate(clk, 100000000); 6490b56e9a7SVivek Gautam 6500b56e9a7SVivek Gautam clk = devm_clk_get(dev, "phy-div"); 6510b56e9a7SVivek Gautam if (IS_ERR(clk)) { 6520b56e9a7SVivek Gautam dev_err(dev, "unable to get phy-div clk\n"); 6530b56e9a7SVivek Gautam return PTR_ERR(clk); 6540b56e9a7SVivek Gautam } 6550b56e9a7SVivek Gautam clk_set_rate(clk, 100000000); 6560b56e9a7SVivek Gautam 6570b56e9a7SVivek Gautam phy->div_clk = devm_clk_get(dev, "div-clk"); 6580b56e9a7SVivek Gautam if (IS_ERR(phy->div_clk)) { 6590b56e9a7SVivek Gautam dev_err(dev, "unable to get div-clk\n"); 6600b56e9a7SVivek Gautam return PTR_ERR(phy->div_clk); 6610b56e9a7SVivek Gautam } 6620b56e9a7SVivek Gautam } else { 6630b56e9a7SVivek Gautam phy->div_clk = ERR_PTR(-ENODEV); 6640b56e9a7SVivek Gautam } 6650b56e9a7SVivek Gautam 6660b56e9a7SVivek Gautam return 0; 6670b56e9a7SVivek Gautam } 6680b56e9a7SVivek Gautam 6690b56e9a7SVivek Gautam static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy) 6700b56e9a7SVivek Gautam { 6710b56e9a7SVivek Gautam struct device *dev = phy->dev; 6720b56e9a7SVivek Gautam struct device_node *node = dev->of_node; 6730b56e9a7SVivek Gautam struct device_node *control_node; 6740b56e9a7SVivek Gautam struct platform_device *control_pdev; 6750b56e9a7SVivek Gautam 6760b56e9a7SVivek Gautam phy->phy_power_syscon = syscon_regmap_lookup_by_phandle(node, 6770b56e9a7SVivek Gautam "syscon-phy-power"); 6780b56e9a7SVivek Gautam if (IS_ERR(phy->phy_power_syscon)) { 6790b56e9a7SVivek Gautam dev_dbg(dev, 6800b56e9a7SVivek Gautam "can't get syscon-phy-power, using control device\n"); 6810b56e9a7SVivek Gautam phy->phy_power_syscon = NULL; 6820b56e9a7SVivek Gautam } else { 6830b56e9a7SVivek Gautam if (of_property_read_u32_index(node, 6840b56e9a7SVivek Gautam "syscon-phy-power", 1, 6850b56e9a7SVivek Gautam &phy->power_reg)) { 6860b56e9a7SVivek Gautam dev_err(dev, "couldn't get power reg. offset\n"); 6870b56e9a7SVivek Gautam return -EINVAL; 6880b56e9a7SVivek Gautam } 6890b56e9a7SVivek Gautam } 6900b56e9a7SVivek Gautam 6910b56e9a7SVivek Gautam if (!phy->phy_power_syscon) { 6920b56e9a7SVivek Gautam control_node = of_parse_phandle(node, "ctrl-module", 0); 6930b56e9a7SVivek Gautam if (!control_node) { 6940b56e9a7SVivek Gautam dev_err(dev, "Failed to get control device phandle\n"); 6950b56e9a7SVivek Gautam return -EINVAL; 6960b56e9a7SVivek Gautam } 6970b56e9a7SVivek Gautam 6980b56e9a7SVivek Gautam control_pdev = of_find_device_by_node(control_node); 6990b56e9a7SVivek Gautam if (!control_pdev) { 7000b56e9a7SVivek Gautam dev_err(dev, "Failed to get control device\n"); 7010b56e9a7SVivek Gautam return -EINVAL; 7020b56e9a7SVivek Gautam } 7030b56e9a7SVivek Gautam 7040b56e9a7SVivek Gautam phy->control_dev = &control_pdev->dev; 7050b56e9a7SVivek Gautam } 7060b56e9a7SVivek Gautam 70722940823SRoger Quadros if (phy->mode == PIPE3_MODE_PCIE) { 7080b56e9a7SVivek Gautam phy->pcs_syscon = syscon_regmap_lookup_by_phandle(node, 7090b56e9a7SVivek Gautam "syscon-pcs"); 7100b56e9a7SVivek Gautam if (IS_ERR(phy->pcs_syscon)) { 7110b56e9a7SVivek Gautam dev_dbg(dev, 7120b56e9a7SVivek Gautam "can't get syscon-pcs, using omap control\n"); 7130b56e9a7SVivek Gautam phy->pcs_syscon = NULL; 7140b56e9a7SVivek Gautam } else { 7150b56e9a7SVivek Gautam if (of_property_read_u32_index(node, 7160b56e9a7SVivek Gautam "syscon-pcs", 1, 7170b56e9a7SVivek Gautam &phy->pcie_pcs_reg)) { 7180b56e9a7SVivek Gautam dev_err(dev, 7190b56e9a7SVivek Gautam "couldn't get pcie pcs reg. offset\n"); 7200b56e9a7SVivek Gautam return -EINVAL; 7210b56e9a7SVivek Gautam } 7220b56e9a7SVivek Gautam } 7230b56e9a7SVivek Gautam } 7240b56e9a7SVivek Gautam 72522940823SRoger Quadros if (phy->mode == PIPE3_MODE_SATA) { 7260b56e9a7SVivek Gautam phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, 7270b56e9a7SVivek Gautam "syscon-pllreset"); 7280b56e9a7SVivek Gautam if (IS_ERR(phy->dpll_reset_syscon)) { 7290b56e9a7SVivek Gautam dev_info(dev, 7300b56e9a7SVivek Gautam "can't get syscon-pllreset, sata dpll won't idle\n"); 7310b56e9a7SVivek Gautam phy->dpll_reset_syscon = NULL; 7320b56e9a7SVivek Gautam } else { 7330b56e9a7SVivek Gautam if (of_property_read_u32_index(node, 7340b56e9a7SVivek Gautam "syscon-pllreset", 1, 7350b56e9a7SVivek Gautam &phy->dpll_reset_reg)) { 7360b56e9a7SVivek Gautam dev_err(dev, 7370b56e9a7SVivek Gautam "couldn't get pllreset reg. offset\n"); 7380b56e9a7SVivek Gautam return -EINVAL; 7390b56e9a7SVivek Gautam } 7400b56e9a7SVivek Gautam } 7410b56e9a7SVivek Gautam } 7420b56e9a7SVivek Gautam 7430b56e9a7SVivek Gautam return 0; 7440b56e9a7SVivek Gautam } 7450b56e9a7SVivek Gautam 7462796ceb0SKishon Vijay Abraham I static int ti_pipe3_get_tx_rx_base(struct ti_pipe3 *phy) 7472796ceb0SKishon Vijay Abraham I { 7482796ceb0SKishon Vijay Abraham I struct device *dev = phy->dev; 7492796ceb0SKishon Vijay Abraham I struct platform_device *pdev = to_platform_device(dev); 7502796ceb0SKishon Vijay Abraham I 751*79caf207SChunfeng Yun phy->phy_rx = devm_platform_ioremap_resource_byname(pdev, "phy_rx"); 7522796ceb0SKishon Vijay Abraham I if (IS_ERR(phy->phy_rx)) 7532796ceb0SKishon Vijay Abraham I return PTR_ERR(phy->phy_rx); 7542796ceb0SKishon Vijay Abraham I 755*79caf207SChunfeng Yun phy->phy_tx = devm_platform_ioremap_resource_byname(pdev, "phy_tx"); 7562796ceb0SKishon Vijay Abraham I 7572796ceb0SKishon Vijay Abraham I return PTR_ERR_OR_ZERO(phy->phy_tx); 7582796ceb0SKishon Vijay Abraham I } 7592796ceb0SKishon Vijay Abraham I 7600b56e9a7SVivek Gautam static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy) 7610b56e9a7SVivek Gautam { 7620b56e9a7SVivek Gautam struct device *dev = phy->dev; 7630b56e9a7SVivek Gautam struct platform_device *pdev = to_platform_device(dev); 7640b56e9a7SVivek Gautam 76522940823SRoger Quadros if (phy->mode == PIPE3_MODE_PCIE) 7660b56e9a7SVivek Gautam return 0; 7670b56e9a7SVivek Gautam 768*79caf207SChunfeng Yun phy->pll_ctrl_base = 769*79caf207SChunfeng Yun devm_platform_ioremap_resource_byname(pdev, "pll_ctrl"); 7700b56e9a7SVivek Gautam return PTR_ERR_OR_ZERO(phy->pll_ctrl_base); 7710b56e9a7SVivek Gautam } 7720b56e9a7SVivek Gautam 7730b56e9a7SVivek Gautam static int ti_pipe3_probe(struct platform_device *pdev) 7740b56e9a7SVivek Gautam { 7750b56e9a7SVivek Gautam struct ti_pipe3 *phy; 7760b56e9a7SVivek Gautam struct phy *generic_phy; 7770b56e9a7SVivek Gautam struct phy_provider *phy_provider; 7780b56e9a7SVivek Gautam struct device *dev = &pdev->dev; 7790b56e9a7SVivek Gautam int ret; 78022940823SRoger Quadros const struct of_device_id *match; 78122940823SRoger Quadros struct pipe3_data *data; 7820b56e9a7SVivek Gautam 7830b56e9a7SVivek Gautam phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 7840b56e9a7SVivek Gautam if (!phy) 7850b56e9a7SVivek Gautam return -ENOMEM; 7860b56e9a7SVivek Gautam 78722940823SRoger Quadros match = of_match_device(ti_pipe3_id_table, dev); 78822940823SRoger Quadros if (!match) 78922940823SRoger Quadros return -EINVAL; 79022940823SRoger Quadros 79122940823SRoger Quadros data = (struct pipe3_data *)match->data; 79222940823SRoger Quadros if (!data) { 79322940823SRoger Quadros dev_err(dev, "no driver data\n"); 79422940823SRoger Quadros return -EINVAL; 79522940823SRoger Quadros } 79622940823SRoger Quadros 7970b56e9a7SVivek Gautam phy->dev = dev; 79822940823SRoger Quadros phy->mode = data->mode; 79922940823SRoger Quadros phy->dpll_map = data->dpll_map; 800fdef2f9fSRoger Quadros phy->settings = data->settings; 8010b56e9a7SVivek Gautam 8020b56e9a7SVivek Gautam ret = ti_pipe3_get_pll_base(phy); 8030b56e9a7SVivek Gautam if (ret) 8040b56e9a7SVivek Gautam return ret; 8050b56e9a7SVivek Gautam 8062796ceb0SKishon Vijay Abraham I ret = ti_pipe3_get_tx_rx_base(phy); 8072796ceb0SKishon Vijay Abraham I if (ret) 8082796ceb0SKishon Vijay Abraham I return ret; 8092796ceb0SKishon Vijay Abraham I 8100b56e9a7SVivek Gautam ret = ti_pipe3_get_sysctrl(phy); 8110b56e9a7SVivek Gautam if (ret) 8120b56e9a7SVivek Gautam return ret; 8130b56e9a7SVivek Gautam 8140b56e9a7SVivek Gautam ret = ti_pipe3_get_clk(phy); 8150b56e9a7SVivek Gautam if (ret) 8160b56e9a7SVivek Gautam return ret; 8170b56e9a7SVivek Gautam 8180b56e9a7SVivek Gautam platform_set_drvdata(pdev, phy); 8190b56e9a7SVivek Gautam pm_runtime_enable(dev); 8200b56e9a7SVivek Gautam 8210b56e9a7SVivek Gautam /* 8220b56e9a7SVivek Gautam * Prevent auto-disable of refclk for SATA PHY due to Errata i783 8230b56e9a7SVivek Gautam */ 82422940823SRoger Quadros if (phy->mode == PIPE3_MODE_SATA) { 8250b56e9a7SVivek Gautam if (!IS_ERR(phy->refclk)) { 8260b56e9a7SVivek Gautam clk_prepare_enable(phy->refclk); 8270b56e9a7SVivek Gautam phy->sata_refclk_enabled = true; 8280b56e9a7SVivek Gautam } 8290b56e9a7SVivek Gautam } 8300b56e9a7SVivek Gautam 8310b56e9a7SVivek Gautam generic_phy = devm_phy_create(dev, NULL, &ops); 8320b56e9a7SVivek Gautam if (IS_ERR(generic_phy)) 8330b56e9a7SVivek Gautam return PTR_ERR(generic_phy); 8340b56e9a7SVivek Gautam 8350b56e9a7SVivek Gautam phy_set_drvdata(generic_phy, phy); 8360b56e9a7SVivek Gautam 8370b56e9a7SVivek Gautam ti_pipe3_power_off(generic_phy); 8380b56e9a7SVivek Gautam 8390b56e9a7SVivek Gautam phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 8400b56e9a7SVivek Gautam return PTR_ERR_OR_ZERO(phy_provider); 8410b56e9a7SVivek Gautam } 8420b56e9a7SVivek Gautam 8430b56e9a7SVivek Gautam static int ti_pipe3_remove(struct platform_device *pdev) 8440b56e9a7SVivek Gautam { 84524dbe0aaSChuhong Yuan struct ti_pipe3 *phy = platform_get_drvdata(pdev); 84624dbe0aaSChuhong Yuan 84724dbe0aaSChuhong Yuan if (phy->mode == PIPE3_MODE_SATA) { 84824dbe0aaSChuhong Yuan clk_disable_unprepare(phy->refclk); 84924dbe0aaSChuhong Yuan phy->sata_refclk_enabled = false; 85024dbe0aaSChuhong Yuan } 8510b56e9a7SVivek Gautam pm_runtime_disable(&pdev->dev); 8520b56e9a7SVivek Gautam 8530b56e9a7SVivek Gautam return 0; 8540b56e9a7SVivek Gautam } 8550b56e9a7SVivek Gautam 8560b56e9a7SVivek Gautam static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) 8570b56e9a7SVivek Gautam { 8580b56e9a7SVivek Gautam int ret = 0; 8590b56e9a7SVivek Gautam 8600b56e9a7SVivek Gautam if (!IS_ERR(phy->refclk)) { 8610b56e9a7SVivek Gautam ret = clk_prepare_enable(phy->refclk); 8620b56e9a7SVivek Gautam if (ret) { 8630b56e9a7SVivek Gautam dev_err(phy->dev, "Failed to enable refclk %d\n", ret); 8640b56e9a7SVivek Gautam return ret; 8650b56e9a7SVivek Gautam } 8660b56e9a7SVivek Gautam } 8670b56e9a7SVivek Gautam 8680b56e9a7SVivek Gautam if (!IS_ERR(phy->wkupclk)) { 8690b56e9a7SVivek Gautam ret = clk_prepare_enable(phy->wkupclk); 8700b56e9a7SVivek Gautam if (ret) { 8710b56e9a7SVivek Gautam dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); 8720b56e9a7SVivek Gautam goto disable_refclk; 8730b56e9a7SVivek Gautam } 8740b56e9a7SVivek Gautam } 8750b56e9a7SVivek Gautam 8760b56e9a7SVivek Gautam if (!IS_ERR(phy->div_clk)) { 8770b56e9a7SVivek Gautam ret = clk_prepare_enable(phy->div_clk); 8780b56e9a7SVivek Gautam if (ret) { 8790b56e9a7SVivek Gautam dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); 8800b56e9a7SVivek Gautam goto disable_wkupclk; 8810b56e9a7SVivek Gautam } 8820b56e9a7SVivek Gautam } 8830b56e9a7SVivek Gautam 8840b56e9a7SVivek Gautam return 0; 8850b56e9a7SVivek Gautam 8860b56e9a7SVivek Gautam disable_wkupclk: 8870b56e9a7SVivek Gautam if (!IS_ERR(phy->wkupclk)) 8880b56e9a7SVivek Gautam clk_disable_unprepare(phy->wkupclk); 8890b56e9a7SVivek Gautam 8900b56e9a7SVivek Gautam disable_refclk: 8910b56e9a7SVivek Gautam if (!IS_ERR(phy->refclk)) 8920b56e9a7SVivek Gautam clk_disable_unprepare(phy->refclk); 8930b56e9a7SVivek Gautam 8940b56e9a7SVivek Gautam return ret; 8950b56e9a7SVivek Gautam } 8960b56e9a7SVivek Gautam 8970b56e9a7SVivek Gautam static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) 8980b56e9a7SVivek Gautam { 8990b56e9a7SVivek Gautam if (!IS_ERR(phy->wkupclk)) 9000b56e9a7SVivek Gautam clk_disable_unprepare(phy->wkupclk); 90124dbe0aaSChuhong Yuan if (!IS_ERR(phy->refclk)) 9020b56e9a7SVivek Gautam clk_disable_unprepare(phy->refclk); 9030b56e9a7SVivek Gautam if (!IS_ERR(phy->div_clk)) 9040b56e9a7SVivek Gautam clk_disable_unprepare(phy->div_clk); 9050b56e9a7SVivek Gautam } 9060b56e9a7SVivek Gautam 9070b56e9a7SVivek Gautam static const struct of_device_id ti_pipe3_id_table[] = { 9080b56e9a7SVivek Gautam { 9090b56e9a7SVivek Gautam .compatible = "ti,phy-usb3", 91022940823SRoger Quadros .data = &data_usb, 9110b56e9a7SVivek Gautam }, 9120b56e9a7SVivek Gautam { 9130b56e9a7SVivek Gautam .compatible = "ti,omap-usb3", 91422940823SRoger Quadros .data = &data_usb, 9150b56e9a7SVivek Gautam }, 9160b56e9a7SVivek Gautam { 9170b56e9a7SVivek Gautam .compatible = "ti,phy-pipe3-sata", 91822940823SRoger Quadros .data = &data_sata, 9190b56e9a7SVivek Gautam }, 9200b56e9a7SVivek Gautam { 9210b56e9a7SVivek Gautam .compatible = "ti,phy-pipe3-pcie", 92222940823SRoger Quadros .data = &data_pcie, 9230b56e9a7SVivek Gautam }, 9240b56e9a7SVivek Gautam {} 9250b56e9a7SVivek Gautam }; 9260b56e9a7SVivek Gautam MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); 9270b56e9a7SVivek Gautam 9280b56e9a7SVivek Gautam static struct platform_driver ti_pipe3_driver = { 9290b56e9a7SVivek Gautam .probe = ti_pipe3_probe, 9300b56e9a7SVivek Gautam .remove = ti_pipe3_remove, 9310b56e9a7SVivek Gautam .driver = { 9320b56e9a7SVivek Gautam .name = "ti-pipe3", 9330b56e9a7SVivek Gautam .of_match_table = ti_pipe3_id_table, 9340b56e9a7SVivek Gautam }, 9350b56e9a7SVivek Gautam }; 9360b56e9a7SVivek Gautam 9370b56e9a7SVivek Gautam module_platform_driver(ti_pipe3_driver); 9380b56e9a7SVivek Gautam 9390b56e9a7SVivek Gautam MODULE_ALIAS("platform:ti_pipe3"); 9400b56e9a7SVivek Gautam MODULE_AUTHOR("Texas Instruments Inc."); 9410b56e9a7SVivek Gautam MODULE_DESCRIPTION("TI PIPE3 phy driver"); 9420b56e9a7SVivek Gautam MODULE_LICENSE("GPL v2"); 943