162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * phy-ti-pipe3 - PIPE3 PHY driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com 662306a36Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/phy/phy.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/clk.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/phy/omap_control_phy.h> 2062306a36Sopenharmony_ci#include <linux/of_platform.h> 2162306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2262306a36Sopenharmony_ci#include <linux/regmap.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define PLL_STATUS 0x00000004 2562306a36Sopenharmony_ci#define PLL_GO 0x00000008 2662306a36Sopenharmony_ci#define PLL_CONFIGURATION1 0x0000000C 2762306a36Sopenharmony_ci#define PLL_CONFIGURATION2 0x00000010 2862306a36Sopenharmony_ci#define PLL_CONFIGURATION3 0x00000014 2962306a36Sopenharmony_ci#define PLL_CONFIGURATION4 0x00000020 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define PLL_REGM_MASK 0x001FFE00 3262306a36Sopenharmony_ci#define PLL_REGM_SHIFT 0x9 3362306a36Sopenharmony_ci#define PLL_REGM_F_MASK 0x0003FFFF 3462306a36Sopenharmony_ci#define PLL_REGM_F_SHIFT 0x0 3562306a36Sopenharmony_ci#define PLL_REGN_MASK 0x000001FE 3662306a36Sopenharmony_ci#define PLL_REGN_SHIFT 0x1 3762306a36Sopenharmony_ci#define PLL_SELFREQDCO_MASK 0x0000000E 3862306a36Sopenharmony_ci#define PLL_SELFREQDCO_SHIFT 0x1 3962306a36Sopenharmony_ci#define PLL_SD_MASK 0x0003FC00 4062306a36Sopenharmony_ci#define PLL_SD_SHIFT 10 4162306a36Sopenharmony_ci#define SET_PLL_GO 0x1 4262306a36Sopenharmony_ci#define PLL_LDOPWDN BIT(15) 4362306a36Sopenharmony_ci#define PLL_TICOPWDN BIT(16) 4462306a36Sopenharmony_ci#define PLL_LOCK 0x2 4562306a36Sopenharmony_ci#define PLL_IDLE 0x1 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SATA_PLL_SOFT_RESET BIT(18) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define PIPE3_PHY_PWRCTL_CLK_CMD_MASK GENMASK(21, 14) 5062306a36Sopenharmony_ci#define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK GENMASK(31, 22) 5362306a36Sopenharmony_ci#define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define PIPE3_PHY_RX_POWERON (0x1 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT) 5662306a36Sopenharmony_ci#define PIPE3_PHY_TX_POWERON (0x2 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define PCIE_PCS_MASK 0xFF0000 5962306a36Sopenharmony_ci#define PCIE_PCS_DELAY_COUNT_SHIFT 0x10 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define PIPE3_PHY_RX_ANA_PROGRAMMABILITY 0x0000000C 6262306a36Sopenharmony_ci#define INTERFACE_MASK GENMASK(31, 27) 6362306a36Sopenharmony_ci#define INTERFACE_SHIFT 27 6462306a36Sopenharmony_ci#define INTERFACE_MODE_USBSS BIT(4) 6562306a36Sopenharmony_ci#define INTERFACE_MODE_SATA_1P5 BIT(3) 6662306a36Sopenharmony_ci#define INTERFACE_MODE_SATA_3P0 BIT(2) 6762306a36Sopenharmony_ci#define INTERFACE_MODE_PCIE BIT(0) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define LOSD_MASK GENMASK(17, 14) 7062306a36Sopenharmony_ci#define LOSD_SHIFT 14 7162306a36Sopenharmony_ci#define MEM_PLLDIV GENMASK(6, 5) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define PIPE3_PHY_RX_TRIM 0x0000001C 7462306a36Sopenharmony_ci#define MEM_DLL_TRIM_SEL_MASK GENMASK(31, 30) 7562306a36Sopenharmony_ci#define MEM_DLL_TRIM_SHIFT 30 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define PIPE3_PHY_RX_DLL 0x00000024 7862306a36Sopenharmony_ci#define MEM_DLL_PHINT_RATE_MASK GENMASK(31, 30) 7962306a36Sopenharmony_ci#define MEM_DLL_PHINT_RATE_SHIFT 30 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define PIPE3_PHY_RX_DIGITAL_MODES 0x00000028 8262306a36Sopenharmony_ci#define MEM_HS_RATE_MASK GENMASK(28, 27) 8362306a36Sopenharmony_ci#define MEM_HS_RATE_SHIFT 27 8462306a36Sopenharmony_ci#define MEM_OVRD_HS_RATE BIT(26) 8562306a36Sopenharmony_ci#define MEM_OVRD_HS_RATE_SHIFT 26 8662306a36Sopenharmony_ci#define MEM_CDR_FASTLOCK BIT(23) 8762306a36Sopenharmony_ci#define MEM_CDR_FASTLOCK_SHIFT 23 8862306a36Sopenharmony_ci#define MEM_CDR_LBW_MASK GENMASK(22, 21) 8962306a36Sopenharmony_ci#define MEM_CDR_LBW_SHIFT 21 9062306a36Sopenharmony_ci#define MEM_CDR_STEPCNT_MASK GENMASK(20, 19) 9162306a36Sopenharmony_ci#define MEM_CDR_STEPCNT_SHIFT 19 9262306a36Sopenharmony_ci#define MEM_CDR_STL_MASK GENMASK(18, 16) 9362306a36Sopenharmony_ci#define MEM_CDR_STL_SHIFT 16 9462306a36Sopenharmony_ci#define MEM_CDR_THR_MASK GENMASK(15, 13) 9562306a36Sopenharmony_ci#define MEM_CDR_THR_SHIFT 13 9662306a36Sopenharmony_ci#define MEM_CDR_THR_MODE BIT(12) 9762306a36Sopenharmony_ci#define MEM_CDR_THR_MODE_SHIFT 12 9862306a36Sopenharmony_ci#define MEM_CDR_2NDO_SDM_MODE BIT(11) 9962306a36Sopenharmony_ci#define MEM_CDR_2NDO_SDM_MODE_SHIFT 11 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define PIPE3_PHY_RX_EQUALIZER 0x00000038 10262306a36Sopenharmony_ci#define MEM_EQLEV_MASK GENMASK(31, 16) 10362306a36Sopenharmony_ci#define MEM_EQLEV_SHIFT 16 10462306a36Sopenharmony_ci#define MEM_EQFTC_MASK GENMASK(15, 11) 10562306a36Sopenharmony_ci#define MEM_EQFTC_SHIFT 11 10662306a36Sopenharmony_ci#define MEM_EQCTL_MASK GENMASK(10, 7) 10762306a36Sopenharmony_ci#define MEM_EQCTL_SHIFT 7 10862306a36Sopenharmony_ci#define MEM_OVRD_EQLEV BIT(2) 10962306a36Sopenharmony_ci#define MEM_OVRD_EQLEV_SHIFT 2 11062306a36Sopenharmony_ci#define MEM_OVRD_EQFTC BIT(1) 11162306a36Sopenharmony_ci#define MEM_OVRD_EQFTC_SHIFT 1 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define SATA_PHY_RX_IO_AND_A2D_OVERRIDES 0x44 11462306a36Sopenharmony_ci#define MEM_CDR_LOS_SOURCE_MASK GENMASK(10, 9) 11562306a36Sopenharmony_ci#define MEM_CDR_LOS_SOURCE_SHIFT 9 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * This is an Empirical value that works, need to confirm the actual 11962306a36Sopenharmony_ci * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status 12062306a36Sopenharmony_ci * to be correctly reflected in the PIPE3PHY_PLL_STATUS register. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci#define PLL_IDLE_TIME 100 /* in milliseconds */ 12362306a36Sopenharmony_ci#define PLL_LOCK_TIME 100 /* in milliseconds */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cienum pipe3_mode { PIPE3_MODE_PCIE = 1, 12662306a36Sopenharmony_ci PIPE3_MODE_SATA, 12762306a36Sopenharmony_ci PIPE3_MODE_USBSS }; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistruct pipe3_dpll_params { 13062306a36Sopenharmony_ci u16 m; 13162306a36Sopenharmony_ci u8 n; 13262306a36Sopenharmony_ci u8 freq:3; 13362306a36Sopenharmony_ci u8 sd; 13462306a36Sopenharmony_ci u32 mf; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct pipe3_dpll_map { 13862306a36Sopenharmony_ci unsigned long rate; 13962306a36Sopenharmony_ci struct pipe3_dpll_params params; 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistruct pipe3_settings { 14362306a36Sopenharmony_ci u8 ana_interface; 14462306a36Sopenharmony_ci u8 ana_losd; 14562306a36Sopenharmony_ci u8 dig_fastlock; 14662306a36Sopenharmony_ci u8 dig_lbw; 14762306a36Sopenharmony_ci u8 dig_stepcnt; 14862306a36Sopenharmony_ci u8 dig_stl; 14962306a36Sopenharmony_ci u8 dig_thr; 15062306a36Sopenharmony_ci u8 dig_thr_mode; 15162306a36Sopenharmony_ci u8 dig_2ndo_sdm_mode; 15262306a36Sopenharmony_ci u8 dig_hs_rate; 15362306a36Sopenharmony_ci u8 dig_ovrd_hs_rate; 15462306a36Sopenharmony_ci u8 dll_trim_sel; 15562306a36Sopenharmony_ci u8 dll_phint_rate; 15662306a36Sopenharmony_ci u8 eq_lev; 15762306a36Sopenharmony_ci u8 eq_ftc; 15862306a36Sopenharmony_ci u8 eq_ctl; 15962306a36Sopenharmony_ci u8 eq_ovrd_lev; 16062306a36Sopenharmony_ci u8 eq_ovrd_ftc; 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct ti_pipe3 { 16462306a36Sopenharmony_ci void __iomem *pll_ctrl_base; 16562306a36Sopenharmony_ci void __iomem *phy_rx; 16662306a36Sopenharmony_ci void __iomem *phy_tx; 16762306a36Sopenharmony_ci struct device *dev; 16862306a36Sopenharmony_ci struct device *control_dev; 16962306a36Sopenharmony_ci struct clk *wkupclk; 17062306a36Sopenharmony_ci struct clk *sys_clk; 17162306a36Sopenharmony_ci struct clk *refclk; 17262306a36Sopenharmony_ci struct clk *div_clk; 17362306a36Sopenharmony_ci struct pipe3_dpll_map *dpll_map; 17462306a36Sopenharmony_ci struct regmap *phy_power_syscon; /* ctrl. reg. acces */ 17562306a36Sopenharmony_ci struct regmap *pcs_syscon; /* ctrl. reg. acces */ 17662306a36Sopenharmony_ci struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */ 17762306a36Sopenharmony_ci unsigned int dpll_reset_reg; /* reg. index within syscon */ 17862306a36Sopenharmony_ci unsigned int power_reg; /* power reg. index within syscon */ 17962306a36Sopenharmony_ci unsigned int pcie_pcs_reg; /* pcs reg. index in syscon */ 18062306a36Sopenharmony_ci bool sata_refclk_enabled; 18162306a36Sopenharmony_ci enum pipe3_mode mode; 18262306a36Sopenharmony_ci struct pipe3_settings settings; 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic struct pipe3_dpll_map dpll_map_usb[] = { 18662306a36Sopenharmony_ci {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ 18762306a36Sopenharmony_ci {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ 18862306a36Sopenharmony_ci {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ 18962306a36Sopenharmony_ci {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ 19062306a36Sopenharmony_ci {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ 19162306a36Sopenharmony_ci {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ 19262306a36Sopenharmony_ci { }, /* Terminator */ 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic struct pipe3_dpll_map dpll_map_sata[] = { 19662306a36Sopenharmony_ci {12000000, {625, 4, 4, 6, 0} }, /* 12 MHz */ 19762306a36Sopenharmony_ci {16800000, {625, 6, 4, 7, 0} }, /* 16.8 MHz */ 19862306a36Sopenharmony_ci {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */ 19962306a36Sopenharmony_ci {20000000, {750, 9, 4, 6, 0} }, /* 20 MHz */ 20062306a36Sopenharmony_ci {26000000, {750, 12, 4, 6, 0} }, /* 26 MHz */ 20162306a36Sopenharmony_ci {38400000, {625, 15, 4, 6, 0} }, /* 38.4 MHz */ 20262306a36Sopenharmony_ci { }, /* Terminator */ 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistruct pipe3_data { 20662306a36Sopenharmony_ci enum pipe3_mode mode; 20762306a36Sopenharmony_ci struct pipe3_dpll_map *dpll_map; 20862306a36Sopenharmony_ci struct pipe3_settings settings; 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic struct pipe3_data data_usb = { 21262306a36Sopenharmony_ci .mode = PIPE3_MODE_USBSS, 21362306a36Sopenharmony_ci .dpll_map = dpll_map_usb, 21462306a36Sopenharmony_ci .settings = { 21562306a36Sopenharmony_ci /* DRA75x TRM Table 26-17 Preferred USB3_PHY_RX SCP Register Settings */ 21662306a36Sopenharmony_ci .ana_interface = INTERFACE_MODE_USBSS, 21762306a36Sopenharmony_ci .ana_losd = 0xa, 21862306a36Sopenharmony_ci .dig_fastlock = 1, 21962306a36Sopenharmony_ci .dig_lbw = 3, 22062306a36Sopenharmony_ci .dig_stepcnt = 0, 22162306a36Sopenharmony_ci .dig_stl = 0x3, 22262306a36Sopenharmony_ci .dig_thr = 1, 22362306a36Sopenharmony_ci .dig_thr_mode = 1, 22462306a36Sopenharmony_ci .dig_2ndo_sdm_mode = 0, 22562306a36Sopenharmony_ci .dig_hs_rate = 0, 22662306a36Sopenharmony_ci .dig_ovrd_hs_rate = 1, 22762306a36Sopenharmony_ci .dll_trim_sel = 0x2, 22862306a36Sopenharmony_ci .dll_phint_rate = 0x3, 22962306a36Sopenharmony_ci .eq_lev = 0, 23062306a36Sopenharmony_ci .eq_ftc = 0, 23162306a36Sopenharmony_ci .eq_ctl = 0x9, 23262306a36Sopenharmony_ci .eq_ovrd_lev = 0, 23362306a36Sopenharmony_ci .eq_ovrd_ftc = 0, 23462306a36Sopenharmony_ci }, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic struct pipe3_data data_sata = { 23862306a36Sopenharmony_ci .mode = PIPE3_MODE_SATA, 23962306a36Sopenharmony_ci .dpll_map = dpll_map_sata, 24062306a36Sopenharmony_ci .settings = { 24162306a36Sopenharmony_ci /* DRA75x TRM Table 26-9 Preferred SATA_PHY_RX SCP Register Settings */ 24262306a36Sopenharmony_ci .ana_interface = INTERFACE_MODE_SATA_3P0, 24362306a36Sopenharmony_ci .ana_losd = 0x5, 24462306a36Sopenharmony_ci .dig_fastlock = 1, 24562306a36Sopenharmony_ci .dig_lbw = 3, 24662306a36Sopenharmony_ci .dig_stepcnt = 0, 24762306a36Sopenharmony_ci .dig_stl = 0x3, 24862306a36Sopenharmony_ci .dig_thr = 1, 24962306a36Sopenharmony_ci .dig_thr_mode = 1, 25062306a36Sopenharmony_ci .dig_2ndo_sdm_mode = 0, 25162306a36Sopenharmony_ci .dig_hs_rate = 0, /* Not in TRM preferred settings */ 25262306a36Sopenharmony_ci .dig_ovrd_hs_rate = 0, /* Not in TRM preferred settings */ 25362306a36Sopenharmony_ci .dll_trim_sel = 0x1, 25462306a36Sopenharmony_ci .dll_phint_rate = 0x2, /* for 1.5 GHz DPLL clock */ 25562306a36Sopenharmony_ci .eq_lev = 0, 25662306a36Sopenharmony_ci .eq_ftc = 0x1f, 25762306a36Sopenharmony_ci .eq_ctl = 0, 25862306a36Sopenharmony_ci .eq_ovrd_lev = 1, 25962306a36Sopenharmony_ci .eq_ovrd_ftc = 1, 26062306a36Sopenharmony_ci }, 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic struct pipe3_data data_pcie = { 26462306a36Sopenharmony_ci .mode = PIPE3_MODE_PCIE, 26562306a36Sopenharmony_ci .settings = { 26662306a36Sopenharmony_ci /* DRA75x TRM Table 26-62 Preferred PCIe_PHY_RX SCP Register Settings */ 26762306a36Sopenharmony_ci .ana_interface = INTERFACE_MODE_PCIE, 26862306a36Sopenharmony_ci .ana_losd = 0xa, 26962306a36Sopenharmony_ci .dig_fastlock = 1, 27062306a36Sopenharmony_ci .dig_lbw = 3, 27162306a36Sopenharmony_ci .dig_stepcnt = 0, 27262306a36Sopenharmony_ci .dig_stl = 0x3, 27362306a36Sopenharmony_ci .dig_thr = 1, 27462306a36Sopenharmony_ci .dig_thr_mode = 1, 27562306a36Sopenharmony_ci .dig_2ndo_sdm_mode = 0, 27662306a36Sopenharmony_ci .dig_hs_rate = 0, 27762306a36Sopenharmony_ci .dig_ovrd_hs_rate = 0, 27862306a36Sopenharmony_ci .dll_trim_sel = 0x2, 27962306a36Sopenharmony_ci .dll_phint_rate = 0x3, 28062306a36Sopenharmony_ci .eq_lev = 0, 28162306a36Sopenharmony_ci .eq_ftc = 0x1f, 28262306a36Sopenharmony_ci .eq_ctl = 1, 28362306a36Sopenharmony_ci .eq_ovrd_lev = 0, 28462306a36Sopenharmony_ci .eq_ovrd_ftc = 0, 28562306a36Sopenharmony_ci }, 28662306a36Sopenharmony_ci}; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci return __raw_readl(addr + offset); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic inline void ti_pipe3_writel(void __iomem *addr, unsigned offset, 29462306a36Sopenharmony_ci u32 data) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci __raw_writel(data, addr + offset); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci unsigned long rate; 30262306a36Sopenharmony_ci struct pipe3_dpll_map *dpll_map = phy->dpll_map; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci rate = clk_get_rate(phy->sys_clk); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci for (; dpll_map->rate; dpll_map++) { 30762306a36Sopenharmony_ci if (rate == dpll_map->rate) 30862306a36Sopenharmony_ci return &dpll_map->params; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return NULL; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int ti_pipe3_enable_clocks(struct ti_pipe3 *phy); 31762306a36Sopenharmony_cistatic void ti_pipe3_disable_clocks(struct ti_pipe3 *phy); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int ti_pipe3_power_off(struct phy *x) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci int ret; 32262306a36Sopenharmony_ci struct ti_pipe3 *phy = phy_get_drvdata(x); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!phy->phy_power_syscon) { 32562306a36Sopenharmony_ci omap_control_phy_power(phy->control_dev, 0); 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 33062306a36Sopenharmony_ci PIPE3_PHY_PWRCTL_CLK_CMD_MASK, 0); 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void ti_pipe3_calibrate(struct ti_pipe3 *phy); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int ti_pipe3_power_on(struct phy *x) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci u32 val; 33962306a36Sopenharmony_ci u32 mask; 34062306a36Sopenharmony_ci unsigned long rate; 34162306a36Sopenharmony_ci struct ti_pipe3 *phy = phy_get_drvdata(x); 34262306a36Sopenharmony_ci bool rx_pending = false; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!phy->phy_power_syscon) { 34562306a36Sopenharmony_ci omap_control_phy_power(phy->control_dev, 1); 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci rate = clk_get_rate(phy->sys_clk); 35062306a36Sopenharmony_ci if (!rate) { 35162306a36Sopenharmony_ci dev_err(phy->dev, "Invalid clock rate\n"); 35262306a36Sopenharmony_ci return -EINVAL; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci rate = rate / 1000000; 35562306a36Sopenharmony_ci mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK; 35662306a36Sopenharmony_ci val = rate << OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT; 35762306a36Sopenharmony_ci regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 35862306a36Sopenharmony_ci mask, val); 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * For PCIe, TX and RX must be powered on simultaneously. 36162306a36Sopenharmony_ci * For USB and SATA, TX must be powered on before RX 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK; 36462306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA || phy->mode == PIPE3_MODE_USBSS) { 36562306a36Sopenharmony_ci val = PIPE3_PHY_TX_POWERON; 36662306a36Sopenharmony_ci rx_pending = true; 36762306a36Sopenharmony_ci } else { 36862306a36Sopenharmony_ci val = PIPE3_PHY_TX_POWERON | PIPE3_PHY_RX_POWERON; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 37262306a36Sopenharmony_ci mask, val); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (rx_pending) { 37562306a36Sopenharmony_ci val = PIPE3_PHY_TX_POWERON | PIPE3_PHY_RX_POWERON; 37662306a36Sopenharmony_ci regmap_update_bits(phy->phy_power_syscon, phy->power_reg, 37762306a36Sopenharmony_ci mask, val); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_PCIE) 38162306a36Sopenharmony_ci ti_pipe3_calibrate(phy); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci u32 val; 38962306a36Sopenharmony_ci unsigned long timeout; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(PLL_LOCK_TIME); 39262306a36Sopenharmony_ci do { 39362306a36Sopenharmony_ci cpu_relax(); 39462306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); 39562306a36Sopenharmony_ci if (val & PLL_LOCK) 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci } while (!time_after(jiffies, timeout)); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci dev_err(phy->dev, "DPLL failed to lock\n"); 40062306a36Sopenharmony_ci return -EBUSY; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int ti_pipe3_dpll_program(struct ti_pipe3 *phy) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci u32 val; 40662306a36Sopenharmony_ci struct pipe3_dpll_params *dpll_params; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci dpll_params = ti_pipe3_get_dpll_params(phy); 40962306a36Sopenharmony_ci if (!dpll_params) 41062306a36Sopenharmony_ci return -EINVAL; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); 41362306a36Sopenharmony_ci val &= ~PLL_REGN_MASK; 41462306a36Sopenharmony_ci val |= dpll_params->n << PLL_REGN_SHIFT; 41562306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 41862306a36Sopenharmony_ci val &= ~PLL_SELFREQDCO_MASK; 41962306a36Sopenharmony_ci val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; 42062306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); 42362306a36Sopenharmony_ci val &= ~PLL_REGM_MASK; 42462306a36Sopenharmony_ci val |= dpll_params->m << PLL_REGM_SHIFT; 42562306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); 42862306a36Sopenharmony_ci val &= ~PLL_REGM_F_MASK; 42962306a36Sopenharmony_ci val |= dpll_params->mf << PLL_REGM_F_SHIFT; 43062306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); 43362306a36Sopenharmony_ci val &= ~PLL_SD_MASK; 43462306a36Sopenharmony_ci val |= dpll_params->sd << PLL_SD_SHIFT; 43562306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci return ti_pipe3_dpll_wait_lock(phy); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void ti_pipe3_calibrate(struct ti_pipe3 *phy) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci u32 val; 44562306a36Sopenharmony_ci struct pipe3_settings *s = &phy->settings; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY); 44862306a36Sopenharmony_ci val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV); 44962306a36Sopenharmony_ci val |= (s->ana_interface << INTERFACE_SHIFT | s->ana_losd << LOSD_SHIFT); 45062306a36Sopenharmony_ci ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY, val); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES); 45362306a36Sopenharmony_ci val &= ~(MEM_HS_RATE_MASK | MEM_OVRD_HS_RATE | MEM_CDR_FASTLOCK | 45462306a36Sopenharmony_ci MEM_CDR_LBW_MASK | MEM_CDR_STEPCNT_MASK | MEM_CDR_STL_MASK | 45562306a36Sopenharmony_ci MEM_CDR_THR_MASK | MEM_CDR_THR_MODE | MEM_CDR_2NDO_SDM_MODE); 45662306a36Sopenharmony_ci val |= s->dig_hs_rate << MEM_HS_RATE_SHIFT | 45762306a36Sopenharmony_ci s->dig_ovrd_hs_rate << MEM_OVRD_HS_RATE_SHIFT | 45862306a36Sopenharmony_ci s->dig_fastlock << MEM_CDR_FASTLOCK_SHIFT | 45962306a36Sopenharmony_ci s->dig_lbw << MEM_CDR_LBW_SHIFT | 46062306a36Sopenharmony_ci s->dig_stepcnt << MEM_CDR_STEPCNT_SHIFT | 46162306a36Sopenharmony_ci s->dig_stl << MEM_CDR_STL_SHIFT | 46262306a36Sopenharmony_ci s->dig_thr << MEM_CDR_THR_SHIFT | 46362306a36Sopenharmony_ci s->dig_thr_mode << MEM_CDR_THR_MODE_SHIFT | 46462306a36Sopenharmony_ci s->dig_2ndo_sdm_mode << MEM_CDR_2NDO_SDM_MODE_SHIFT; 46562306a36Sopenharmony_ci ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES, val); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM); 46862306a36Sopenharmony_ci val &= ~MEM_DLL_TRIM_SEL_MASK; 46962306a36Sopenharmony_ci val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT; 47062306a36Sopenharmony_ci ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL); 47362306a36Sopenharmony_ci val &= ~MEM_DLL_PHINT_RATE_MASK; 47462306a36Sopenharmony_ci val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT; 47562306a36Sopenharmony_ci ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER); 47862306a36Sopenharmony_ci val &= ~(MEM_EQLEV_MASK | MEM_EQFTC_MASK | MEM_EQCTL_MASK | 47962306a36Sopenharmony_ci MEM_OVRD_EQLEV | MEM_OVRD_EQFTC); 48062306a36Sopenharmony_ci val |= s->eq_lev << MEM_EQLEV_SHIFT | 48162306a36Sopenharmony_ci s->eq_ftc << MEM_EQFTC_SHIFT | 48262306a36Sopenharmony_ci s->eq_ctl << MEM_EQCTL_SHIFT | 48362306a36Sopenharmony_ci s->eq_ovrd_lev << MEM_OVRD_EQLEV_SHIFT | 48462306a36Sopenharmony_ci s->eq_ovrd_ftc << MEM_OVRD_EQFTC_SHIFT; 48562306a36Sopenharmony_ci ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER, val); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA) { 48862306a36Sopenharmony_ci val = ti_pipe3_readl(phy->phy_rx, 48962306a36Sopenharmony_ci SATA_PHY_RX_IO_AND_A2D_OVERRIDES); 49062306a36Sopenharmony_ci val &= ~MEM_CDR_LOS_SOURCE_MASK; 49162306a36Sopenharmony_ci ti_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES, 49262306a36Sopenharmony_ci val); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int ti_pipe3_init(struct phy *x) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct ti_pipe3 *phy = phy_get_drvdata(x); 49962306a36Sopenharmony_ci u32 val; 50062306a36Sopenharmony_ci int ret = 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ti_pipe3_enable_clocks(phy); 50362306a36Sopenharmony_ci /* 50462306a36Sopenharmony_ci * Set pcie_pcs register to 0x96 for proper functioning of phy 50562306a36Sopenharmony_ci * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table 50662306a36Sopenharmony_ci * 18-1804. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_PCIE) { 50962306a36Sopenharmony_ci if (!phy->pcs_syscon) { 51062306a36Sopenharmony_ci omap_control_pcie_pcs(phy->control_dev, 0x96); 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT; 51562306a36Sopenharmony_ci ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg, 51662306a36Sopenharmony_ci PCIE_PCS_MASK, val); 51762306a36Sopenharmony_ci return ret; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Bring it out of IDLE if it is IDLE */ 52162306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 52262306a36Sopenharmony_ci if (val & PLL_IDLE) { 52362306a36Sopenharmony_ci val &= ~PLL_IDLE; 52462306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 52562306a36Sopenharmony_ci ret = ti_pipe3_dpll_wait_lock(phy); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* SATA has issues if re-programmed when locked */ 52962306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); 53062306a36Sopenharmony_ci if ((val & PLL_LOCK) && phy->mode == PIPE3_MODE_SATA) 53162306a36Sopenharmony_ci return ret; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Program the DPLL */ 53462306a36Sopenharmony_ci ret = ti_pipe3_dpll_program(phy); 53562306a36Sopenharmony_ci if (ret) { 53662306a36Sopenharmony_ci ti_pipe3_disable_clocks(phy); 53762306a36Sopenharmony_ci return -EINVAL; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ti_pipe3_calibrate(phy); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return ret; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int ti_pipe3_exit(struct phy *x) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct ti_pipe3 *phy = phy_get_drvdata(x); 54862306a36Sopenharmony_ci u32 val; 54962306a36Sopenharmony_ci unsigned long timeout; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* If dpll_reset_syscon is not present we wont power down SATA DPLL 55262306a36Sopenharmony_ci * due to Errata i783 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA && !phy->dpll_reset_syscon) 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* PCIe doesn't have internal DPLL */ 55862306a36Sopenharmony_ci if (phy->mode != PIPE3_MODE_PCIE) { 55962306a36Sopenharmony_ci /* Put DPLL in IDLE mode */ 56062306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); 56162306a36Sopenharmony_ci val |= PLL_IDLE; 56262306a36Sopenharmony_ci ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* wait for LDO and Oscillator to power down */ 56562306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME); 56662306a36Sopenharmony_ci do { 56762306a36Sopenharmony_ci cpu_relax(); 56862306a36Sopenharmony_ci val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); 56962306a36Sopenharmony_ci if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN)) 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci } while (!time_after(jiffies, timeout)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) { 57462306a36Sopenharmony_ci dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n", 57562306a36Sopenharmony_ci val); 57662306a36Sopenharmony_ci return -EBUSY; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* i783: SATA needs control bit toggle after PLL unlock */ 58162306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA) { 58262306a36Sopenharmony_ci regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, 58362306a36Sopenharmony_ci SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET); 58462306a36Sopenharmony_ci regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, 58562306a36Sopenharmony_ci SATA_PLL_SOFT_RESET, 0); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci ti_pipe3_disable_clocks(phy); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_cistatic const struct phy_ops ops = { 59362306a36Sopenharmony_ci .init = ti_pipe3_init, 59462306a36Sopenharmony_ci .exit = ti_pipe3_exit, 59562306a36Sopenharmony_ci .power_on = ti_pipe3_power_on, 59662306a36Sopenharmony_ci .power_off = ti_pipe3_power_off, 59762306a36Sopenharmony_ci .owner = THIS_MODULE, 59862306a36Sopenharmony_ci}; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic const struct of_device_id ti_pipe3_id_table[]; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int ti_pipe3_get_clk(struct ti_pipe3 *phy) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct clk *clk; 60562306a36Sopenharmony_ci struct device *dev = phy->dev; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci phy->refclk = devm_clk_get(dev, "refclk"); 60862306a36Sopenharmony_ci if (IS_ERR(phy->refclk)) { 60962306a36Sopenharmony_ci dev_err(dev, "unable to get refclk\n"); 61062306a36Sopenharmony_ci /* older DTBs have missing refclk in SATA PHY 61162306a36Sopenharmony_ci * so don't bail out in case of SATA PHY. 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_ci if (phy->mode != PIPE3_MODE_SATA) 61462306a36Sopenharmony_ci return PTR_ERR(phy->refclk); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (phy->mode != PIPE3_MODE_SATA) { 61862306a36Sopenharmony_ci phy->wkupclk = devm_clk_get(dev, "wkupclk"); 61962306a36Sopenharmony_ci if (IS_ERR(phy->wkupclk)) { 62062306a36Sopenharmony_ci dev_err(dev, "unable to get wkupclk\n"); 62162306a36Sopenharmony_ci return PTR_ERR(phy->wkupclk); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci } else { 62462306a36Sopenharmony_ci phy->wkupclk = ERR_PTR(-ENODEV); 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (phy->mode != PIPE3_MODE_PCIE || phy->phy_power_syscon) { 62862306a36Sopenharmony_ci phy->sys_clk = devm_clk_get(dev, "sysclk"); 62962306a36Sopenharmony_ci if (IS_ERR(phy->sys_clk)) { 63062306a36Sopenharmony_ci dev_err(dev, "unable to get sysclk\n"); 63162306a36Sopenharmony_ci return -EINVAL; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_PCIE) { 63662306a36Sopenharmony_ci clk = devm_clk_get(dev, "dpll_ref"); 63762306a36Sopenharmony_ci if (IS_ERR(clk)) { 63862306a36Sopenharmony_ci dev_err(dev, "unable to get dpll ref clk\n"); 63962306a36Sopenharmony_ci return PTR_ERR(clk); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci clk_set_rate(clk, 1500000000); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci clk = devm_clk_get(dev, "dpll_ref_m2"); 64462306a36Sopenharmony_ci if (IS_ERR(clk)) { 64562306a36Sopenharmony_ci dev_err(dev, "unable to get dpll ref m2 clk\n"); 64662306a36Sopenharmony_ci return PTR_ERR(clk); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci clk_set_rate(clk, 100000000); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci clk = devm_clk_get(dev, "phy-div"); 65162306a36Sopenharmony_ci if (IS_ERR(clk)) { 65262306a36Sopenharmony_ci dev_err(dev, "unable to get phy-div clk\n"); 65362306a36Sopenharmony_ci return PTR_ERR(clk); 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci clk_set_rate(clk, 100000000); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci phy->div_clk = devm_clk_get(dev, "div-clk"); 65862306a36Sopenharmony_ci if (IS_ERR(phy->div_clk)) { 65962306a36Sopenharmony_ci dev_err(dev, "unable to get div-clk\n"); 66062306a36Sopenharmony_ci return PTR_ERR(phy->div_clk); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci } else { 66362306a36Sopenharmony_ci phy->div_clk = ERR_PTR(-ENODEV); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci return 0; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct device *dev = phy->dev; 67262306a36Sopenharmony_ci struct device_node *node = dev->of_node; 67362306a36Sopenharmony_ci struct device_node *control_node; 67462306a36Sopenharmony_ci struct platform_device *control_pdev; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci phy->phy_power_syscon = syscon_regmap_lookup_by_phandle(node, 67762306a36Sopenharmony_ci "syscon-phy-power"); 67862306a36Sopenharmony_ci if (IS_ERR(phy->phy_power_syscon)) { 67962306a36Sopenharmony_ci dev_dbg(dev, 68062306a36Sopenharmony_ci "can't get syscon-phy-power, using control device\n"); 68162306a36Sopenharmony_ci phy->phy_power_syscon = NULL; 68262306a36Sopenharmony_ci } else { 68362306a36Sopenharmony_ci if (of_property_read_u32_index(node, 68462306a36Sopenharmony_ci "syscon-phy-power", 1, 68562306a36Sopenharmony_ci &phy->power_reg)) { 68662306a36Sopenharmony_ci dev_err(dev, "couldn't get power reg. offset\n"); 68762306a36Sopenharmony_ci return -EINVAL; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (!phy->phy_power_syscon) { 69262306a36Sopenharmony_ci control_node = of_parse_phandle(node, "ctrl-module", 0); 69362306a36Sopenharmony_ci if (!control_node) { 69462306a36Sopenharmony_ci dev_err(dev, "Failed to get control device phandle\n"); 69562306a36Sopenharmony_ci return -EINVAL; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci control_pdev = of_find_device_by_node(control_node); 69962306a36Sopenharmony_ci of_node_put(control_node); 70062306a36Sopenharmony_ci if (!control_pdev) { 70162306a36Sopenharmony_ci dev_err(dev, "Failed to get control device\n"); 70262306a36Sopenharmony_ci return -EINVAL; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci phy->control_dev = &control_pdev->dev; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_PCIE) { 70962306a36Sopenharmony_ci phy->pcs_syscon = syscon_regmap_lookup_by_phandle(node, 71062306a36Sopenharmony_ci "syscon-pcs"); 71162306a36Sopenharmony_ci if (IS_ERR(phy->pcs_syscon)) { 71262306a36Sopenharmony_ci dev_dbg(dev, 71362306a36Sopenharmony_ci "can't get syscon-pcs, using omap control\n"); 71462306a36Sopenharmony_ci phy->pcs_syscon = NULL; 71562306a36Sopenharmony_ci } else { 71662306a36Sopenharmony_ci if (of_property_read_u32_index(node, 71762306a36Sopenharmony_ci "syscon-pcs", 1, 71862306a36Sopenharmony_ci &phy->pcie_pcs_reg)) { 71962306a36Sopenharmony_ci dev_err(dev, 72062306a36Sopenharmony_ci "couldn't get pcie pcs reg. offset\n"); 72162306a36Sopenharmony_ci return -EINVAL; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA) { 72762306a36Sopenharmony_ci phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, 72862306a36Sopenharmony_ci "syscon-pllreset"); 72962306a36Sopenharmony_ci if (IS_ERR(phy->dpll_reset_syscon)) { 73062306a36Sopenharmony_ci dev_info(dev, 73162306a36Sopenharmony_ci "can't get syscon-pllreset, sata dpll won't idle\n"); 73262306a36Sopenharmony_ci phy->dpll_reset_syscon = NULL; 73362306a36Sopenharmony_ci } else { 73462306a36Sopenharmony_ci if (of_property_read_u32_index(node, 73562306a36Sopenharmony_ci "syscon-pllreset", 1, 73662306a36Sopenharmony_ci &phy->dpll_reset_reg)) { 73762306a36Sopenharmony_ci dev_err(dev, 73862306a36Sopenharmony_ci "couldn't get pllreset reg. offset\n"); 73962306a36Sopenharmony_ci return -EINVAL; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int ti_pipe3_get_tx_rx_base(struct ti_pipe3 *phy) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct device *dev = phy->dev; 75062306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci phy->phy_rx = devm_platform_ioremap_resource_byname(pdev, "phy_rx"); 75362306a36Sopenharmony_ci if (IS_ERR(phy->phy_rx)) 75462306a36Sopenharmony_ci return PTR_ERR(phy->phy_rx); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci phy->phy_tx = devm_platform_ioremap_resource_byname(pdev, "phy_tx"); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(phy->phy_tx); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic int ti_pipe3_get_pll_base(struct ti_pipe3 *phy) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci struct device *dev = phy->dev; 76462306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_PCIE) 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci phy->pll_ctrl_base = 77062306a36Sopenharmony_ci devm_platform_ioremap_resource_byname(pdev, "pll_ctrl"); 77162306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(phy->pll_ctrl_base); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int ti_pipe3_probe(struct platform_device *pdev) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct ti_pipe3 *phy; 77762306a36Sopenharmony_ci struct phy *generic_phy; 77862306a36Sopenharmony_ci struct phy_provider *phy_provider; 77962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 78062306a36Sopenharmony_ci int ret; 78162306a36Sopenharmony_ci const struct of_device_id *match; 78262306a36Sopenharmony_ci struct pipe3_data *data; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 78562306a36Sopenharmony_ci if (!phy) 78662306a36Sopenharmony_ci return -ENOMEM; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci match = of_match_device(ti_pipe3_id_table, dev); 78962306a36Sopenharmony_ci if (!match) 79062306a36Sopenharmony_ci return -EINVAL; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci data = (struct pipe3_data *)match->data; 79362306a36Sopenharmony_ci if (!data) { 79462306a36Sopenharmony_ci dev_err(dev, "no driver data\n"); 79562306a36Sopenharmony_ci return -EINVAL; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci phy->dev = dev; 79962306a36Sopenharmony_ci phy->mode = data->mode; 80062306a36Sopenharmony_ci phy->dpll_map = data->dpll_map; 80162306a36Sopenharmony_ci phy->settings = data->settings; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci ret = ti_pipe3_get_pll_base(phy); 80462306a36Sopenharmony_ci if (ret) 80562306a36Sopenharmony_ci return ret; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci ret = ti_pipe3_get_tx_rx_base(phy); 80862306a36Sopenharmony_ci if (ret) 80962306a36Sopenharmony_ci return ret; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci ret = ti_pipe3_get_sysctrl(phy); 81262306a36Sopenharmony_ci if (ret) 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci ret = ti_pipe3_get_clk(phy); 81662306a36Sopenharmony_ci if (ret) 81762306a36Sopenharmony_ci return ret; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci platform_set_drvdata(pdev, phy); 82062306a36Sopenharmony_ci pm_runtime_enable(dev); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* 82362306a36Sopenharmony_ci * Prevent auto-disable of refclk for SATA PHY due to Errata i783 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA) { 82662306a36Sopenharmony_ci if (!IS_ERR(phy->refclk)) { 82762306a36Sopenharmony_ci clk_prepare_enable(phy->refclk); 82862306a36Sopenharmony_ci phy->sata_refclk_enabled = true; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci generic_phy = devm_phy_create(dev, NULL, &ops); 83362306a36Sopenharmony_ci if (IS_ERR(generic_phy)) 83462306a36Sopenharmony_ci return PTR_ERR(generic_phy); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci phy_set_drvdata(generic_phy, phy); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci ti_pipe3_power_off(generic_phy); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 84162306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic void ti_pipe3_remove(struct platform_device *pdev) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci struct ti_pipe3 *phy = platform_get_drvdata(pdev); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (phy->mode == PIPE3_MODE_SATA) { 84962306a36Sopenharmony_ci clk_disable_unprepare(phy->refclk); 85062306a36Sopenharmony_ci phy->sata_refclk_enabled = false; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci int ret = 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!IS_ERR(phy->refclk)) { 86062306a36Sopenharmony_ci ret = clk_prepare_enable(phy->refclk); 86162306a36Sopenharmony_ci if (ret) { 86262306a36Sopenharmony_ci dev_err(phy->dev, "Failed to enable refclk %d\n", ret); 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (!IS_ERR(phy->wkupclk)) { 86862306a36Sopenharmony_ci ret = clk_prepare_enable(phy->wkupclk); 86962306a36Sopenharmony_ci if (ret) { 87062306a36Sopenharmony_ci dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); 87162306a36Sopenharmony_ci goto disable_refclk; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (!IS_ERR(phy->div_clk)) { 87662306a36Sopenharmony_ci ret = clk_prepare_enable(phy->div_clk); 87762306a36Sopenharmony_ci if (ret) { 87862306a36Sopenharmony_ci dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); 87962306a36Sopenharmony_ci goto disable_wkupclk; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cidisable_wkupclk: 88662306a36Sopenharmony_ci if (!IS_ERR(phy->wkupclk)) 88762306a36Sopenharmony_ci clk_disable_unprepare(phy->wkupclk); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cidisable_refclk: 89062306a36Sopenharmony_ci if (!IS_ERR(phy->refclk)) 89162306a36Sopenharmony_ci clk_disable_unprepare(phy->refclk); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return ret; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci if (!IS_ERR(phy->wkupclk)) 89962306a36Sopenharmony_ci clk_disable_unprepare(phy->wkupclk); 90062306a36Sopenharmony_ci if (!IS_ERR(phy->refclk)) 90162306a36Sopenharmony_ci clk_disable_unprepare(phy->refclk); 90262306a36Sopenharmony_ci if (!IS_ERR(phy->div_clk)) 90362306a36Sopenharmony_ci clk_disable_unprepare(phy->div_clk); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic const struct of_device_id ti_pipe3_id_table[] = { 90762306a36Sopenharmony_ci { 90862306a36Sopenharmony_ci .compatible = "ti,phy-usb3", 90962306a36Sopenharmony_ci .data = &data_usb, 91062306a36Sopenharmony_ci }, 91162306a36Sopenharmony_ci { 91262306a36Sopenharmony_ci .compatible = "ti,omap-usb3", 91362306a36Sopenharmony_ci .data = &data_usb, 91462306a36Sopenharmony_ci }, 91562306a36Sopenharmony_ci { 91662306a36Sopenharmony_ci .compatible = "ti,phy-pipe3-sata", 91762306a36Sopenharmony_ci .data = &data_sata, 91862306a36Sopenharmony_ci }, 91962306a36Sopenharmony_ci { 92062306a36Sopenharmony_ci .compatible = "ti,phy-pipe3-pcie", 92162306a36Sopenharmony_ci .data = &data_pcie, 92262306a36Sopenharmony_ci }, 92362306a36Sopenharmony_ci {} 92462306a36Sopenharmony_ci}; 92562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_pipe3_id_table); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic struct platform_driver ti_pipe3_driver = { 92862306a36Sopenharmony_ci .probe = ti_pipe3_probe, 92962306a36Sopenharmony_ci .remove_new = ti_pipe3_remove, 93062306a36Sopenharmony_ci .driver = { 93162306a36Sopenharmony_ci .name = "ti-pipe3", 93262306a36Sopenharmony_ci .of_match_table = ti_pipe3_id_table, 93362306a36Sopenharmony_ci }, 93462306a36Sopenharmony_ci}; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cimodule_platform_driver(ti_pipe3_driver); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ciMODULE_ALIAS("platform:ti_pipe3"); 93962306a36Sopenharmony_ciMODULE_AUTHOR("Texas Instruments Inc."); 94062306a36Sopenharmony_ciMODULE_DESCRIPTION("TI PIPE3 phy driver"); 94162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 942