Commit fdef2f9f authored by Roger Quadros's avatar Roger Quadros Committed by Kishon Vijay Abraham I
Browse files

phy: ti-pipe3: improve DPLL stability for SATA & USB

For increased DPLL stability use the settings recommended in
the TRM [1] for PHY_RX registers for SATA and USB.

For SATA we need to use spread spectrum settings even
though we don't have spread spectrum enabled. The
suggested non-spread spectrum settings don't work.

[1] DRA75x, DRA74x TRM - http://www.ti.com/lit/ug/sprui30f/sprui30f.pdf



Signed-off-by: default avatarRoger Quadros <rogerq@ti.com>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 22940823
Loading
Loading
Loading
Loading
+173 −42
Original line number Diff line number Diff line
@@ -68,39 +68,61 @@
#define PCIE_PCS_MASK			0xFF0000
#define PCIE_PCS_DELAY_COUNT_SHIFT	0x10

#define PCIEPHYRX_ANA_PROGRAMMABILITY	0x0000000C
#define PIPE3_PHY_RX_ANA_PROGRAMMABILITY	0x0000000C
#define INTERFACE_MASK			GENMASK(31, 27)
#define INTERFACE_SHIFT			27
#define INTERFACE_MODE_USBSS		BIT(4)
#define INTERFACE_MODE_SATA_1P5		BIT(3)
#define INTERFACE_MODE_SATA_3P0		BIT(2)
#define INTERFACE_MODE_PCIE		BIT(0)

#define LOSD_MASK			GENMASK(17, 14)
#define LOSD_SHIFT			14
#define MEM_PLLDIV			GENMASK(6, 5)

#define PCIEPHYRX_TRIM			0x0000001C
#define MEM_DLL_TRIM_SEL		GENMASK(31, 30)
#define PIPE3_PHY_RX_TRIM		0x0000001C
#define MEM_DLL_TRIM_SEL_MASK		GENMASK(31, 30)
#define MEM_DLL_TRIM_SHIFT		30

#define PCIEPHYRX_DLL			0x00000024
#define MEM_DLL_PHINT_RATE		GENMASK(31, 30)
#define PIPE3_PHY_RX_DLL		0x00000024
#define MEM_DLL_PHINT_RATE_MASK		GENMASK(31, 30)
#define MEM_DLL_PHINT_RATE_SHIFT	30

#define PCIEPHYRX_DIGITAL_MODES		0x00000028
#define PIPE3_PHY_RX_DIGITAL_MODES		0x00000028
#define MEM_HS_RATE_MASK		GENMASK(28, 27)
#define MEM_HS_RATE_SHIFT		27
#define MEM_OVRD_HS_RATE		BIT(26)
#define MEM_OVRD_HS_RATE_SHIFT		26
#define MEM_CDR_FASTLOCK		BIT(23)
#define MEM_CDR_LBW			GENMASK(22, 21)
#define MEM_CDR_STEPCNT			GENMASK(20, 19)
#define MEM_CDR_FASTLOCK_SHIFT		23
#define MEM_CDR_LBW_MASK		GENMASK(22, 21)
#define MEM_CDR_LBW_SHIFT		21
#define MEM_CDR_STEPCNT_MASK		GENMASK(20, 19)
#define MEM_CDR_STEPCNT_SHIFT		19
#define MEM_CDR_STL_MASK		GENMASK(18, 16)
#define MEM_CDR_STL_SHIFT		16
#define MEM_CDR_THR_MASK		GENMASK(15, 13)
#define MEM_CDR_THR_SHIFT		13
#define MEM_CDR_THR_MODE		BIT(12)
#define MEM_CDR_CDR_2NDO_SDM_MODE	BIT(11)
#define MEM_OVRD_HS_RATE		BIT(26)

#define PCIEPHYRX_EQUALIZER		0x00000038
#define MEM_EQLEV			GENMASK(31, 16)
#define MEM_EQFTC			GENMASK(15, 11)
#define MEM_EQCTL			GENMASK(10, 7)
#define MEM_CDR_THR_MODE_SHIFT		12
#define MEM_CDR_2NDO_SDM_MODE		BIT(11)
#define MEM_CDR_2NDO_SDM_MODE_SHIFT	11

#define PIPE3_PHY_RX_EQUALIZER		0x00000038
#define MEM_EQLEV_MASK			GENMASK(31, 16)
#define MEM_EQLEV_SHIFT			16
#define MEM_EQFTC_MASK			GENMASK(15, 11)
#define MEM_EQFTC_SHIFT			11
#define MEM_EQCTL_MASK			GENMASK(10, 7)
#define MEM_EQCTL_SHIFT			7
#define MEM_OVRD_EQLEV			BIT(2)
#define MEM_OVRD_EQLEV_SHIFT		2
#define MEM_OVRD_EQFTC			BIT(1)
#define MEM_OVRD_EQFTC_SHIFT		1

#define SATA_PHY_RX_IO_AND_A2D_OVERRIDES	0x44
#define MEM_CDR_LOS_SOURCE_MASK		GENMASK(10, 9)
#define MEM_CDR_LOS_SOURCE_SHIFT	9

/*
 * This is an Empirical value that works, need to confirm the actual
@@ -127,6 +149,27 @@ struct pipe3_dpll_map {
	struct pipe3_dpll_params params;
};

struct pipe3_settings {
	u8 ana_interface;
	u8 ana_losd;
	u8 dig_fastlock;
	u8 dig_lbw;
	u8 dig_stepcnt;
	u8 dig_stl;
	u8 dig_thr;
	u8 dig_thr_mode;
	u8 dig_2ndo_sdm_mode;
	u8 dig_hs_rate;
	u8 dig_ovrd_hs_rate;
	u8 dll_trim_sel;
	u8 dll_phint_rate;
	u8 eq_lev;
	u8 eq_ftc;
	u8 eq_ctl;
	u8 eq_ovrd_lev;
	u8 eq_ovrd_ftc;
};

struct ti_pipe3 {
	void __iomem		*pll_ctrl_base;
	void __iomem		*phy_rx;
@@ -146,6 +189,7 @@ struct ti_pipe3 {
	unsigned int		pcie_pcs_reg; /* pcs reg. index in syscon */
	bool			sata_refclk_enabled;
	enum pipe3_mode		mode;
	struct pipe3_settings	settings;
};

static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -171,20 +215,84 @@ static struct pipe3_dpll_map dpll_map_sata[] = {
struct pipe3_data {
	enum pipe3_mode mode;
	struct pipe3_dpll_map *dpll_map;
	struct pipe3_settings settings;
};

static struct pipe3_data data_usb = {
	.mode = PIPE3_MODE_USBSS,
	.dpll_map = dpll_map_usb,
	.settings = {
	/* DRA75x TRM Table 26-17 Preferred USB3_PHY_RX SCP Register Settings */
		.ana_interface = INTERFACE_MODE_USBSS,
		.ana_losd = 0xa,
		.dig_fastlock = 1,
		.dig_lbw = 3,
		.dig_stepcnt = 0,
		.dig_stl = 0x3,
		.dig_thr = 1,
		.dig_thr_mode = 1,
		.dig_2ndo_sdm_mode = 0,
		.dig_hs_rate = 0,
		.dig_ovrd_hs_rate = 1,
		.dll_trim_sel = 0x2,
		.dll_phint_rate = 0x3,
		.eq_lev = 0,
		.eq_ftc = 0,
		.eq_ctl = 0x9,
		.eq_ovrd_lev = 0,
		.eq_ovrd_ftc = 0,
	},
};

static struct pipe3_data data_sata = {
	.mode = PIPE3_MODE_SATA,
	.dpll_map = dpll_map_sata,
	.settings = {
	/* DRA75x TRM Table 26-9 Preferred SATA_PHY_RX SCP Register Settings */
		.ana_interface = INTERFACE_MODE_SATA_3P0,
		.ana_losd = 0x5,
		.dig_fastlock = 1,
		.dig_lbw = 3,
		.dig_stepcnt = 0,
		.dig_stl = 0x3,
		.dig_thr = 1,
		.dig_thr_mode = 1,
		.dig_2ndo_sdm_mode = 0,
		.dig_hs_rate = 0,	/* Not in TRM preferred settings */
		.dig_ovrd_hs_rate = 0,	/* Not in TRM preferred settings */
		.dll_trim_sel = 0x1,
		.dll_phint_rate = 0x2,	/* for 1.5 GHz DPLL clock */
		.eq_lev = 0,
		.eq_ftc = 0x1f,
		.eq_ctl = 0,
		.eq_ovrd_lev = 1,
		.eq_ovrd_ftc = 1,
	},
};

static struct pipe3_data data_pcie = {
	.mode = PIPE3_MODE_PCIE,
	.settings = {
	/* DRA75x TRM Table 26-62 Preferred PCIe_PHY_RX SCP Register Settings */
		.ana_interface = INTERFACE_MODE_PCIE,
		.ana_losd = 0xa,
		.dig_fastlock = 1,
		.dig_lbw = 3,
		.dig_stepcnt = 0,
		.dig_stl = 0x3,
		.dig_thr = 1,
		.dig_thr_mode = 1,
		.dig_2ndo_sdm_mode = 0,
		.dig_hs_rate = 0,
		.dig_ovrd_hs_rate = 0,
		.dll_trim_sel = 0x2,
		.dll_phint_rate = 0x3,
		.eq_lev = 0,
		.eq_ftc = 0x1f,
		.eq_ctl = 1,
		.eq_ovrd_lev = 0,
		.eq_ovrd_ftc = 0,
	},
};

static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset)
@@ -324,32 +432,55 @@ static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
static void ti_pipe3_calibrate(struct ti_pipe3 *phy)
{
	u32 val;
	struct pipe3_settings *s = &phy->settings;

	val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_ANA_PROGRAMMABILITY);
	val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY);
	val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV);
	val |= (0x1 << INTERFACE_SHIFT | 0xA << LOSD_SHIFT);
	ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_ANA_PROGRAMMABILITY, val);
	val |= (s->ana_interface << INTERFACE_SHIFT | s->ana_losd << LOSD_SHIFT);
	ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY, val);

	val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES);
	val &= ~(MEM_HS_RATE_MASK | MEM_OVRD_HS_RATE | MEM_CDR_FASTLOCK |
		 MEM_CDR_LBW_MASK | MEM_CDR_STEPCNT_MASK | MEM_CDR_STL_MASK |
		 MEM_CDR_THR_MASK | MEM_CDR_THR_MODE | MEM_CDR_2NDO_SDM_MODE);
	val |= s->dig_hs_rate << MEM_HS_RATE_SHIFT |
		s->dig_ovrd_hs_rate << MEM_OVRD_HS_RATE_SHIFT |
		s->dig_fastlock << MEM_CDR_FASTLOCK_SHIFT |
		s->dig_lbw << MEM_CDR_LBW_SHIFT |
		s->dig_stepcnt << MEM_CDR_STEPCNT_SHIFT |
		s->dig_stl << MEM_CDR_STL_SHIFT |
		s->dig_thr << MEM_CDR_THR_SHIFT |
		s->dig_thr_mode << MEM_CDR_THR_MODE_SHIFT |
		s->dig_2ndo_sdm_mode << MEM_CDR_2NDO_SDM_MODE_SHIFT;
	ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES, val);

	val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM);
	val &= ~MEM_DLL_TRIM_SEL_MASK;
	val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT;
	ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val);

	val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL);
	val &= ~MEM_DLL_PHINT_RATE_MASK;
	val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT;
	ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val);

	val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER);
	val &= ~(MEM_EQLEV_MASK | MEM_EQFTC_MASK | MEM_EQCTL_MASK |
		 MEM_OVRD_EQLEV | MEM_OVRD_EQFTC);
	val |= s->eq_lev << MEM_EQLEV_SHIFT |
		s->eq_ftc << MEM_EQFTC_SHIFT |
		s->eq_ctl << MEM_EQCTL_SHIFT |
		s->eq_ovrd_lev << MEM_OVRD_EQLEV_SHIFT |
		s->eq_ovrd_ftc << MEM_OVRD_EQFTC_SHIFT;
	ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER, val);

	val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_DIGITAL_MODES);
	val &= ~(MEM_CDR_STEPCNT | MEM_CDR_STL_MASK | MEM_CDR_THR_MASK |
		 MEM_CDR_CDR_2NDO_SDM_MODE | MEM_OVRD_HS_RATE);
	val |= (MEM_CDR_FASTLOCK | MEM_CDR_LBW | 0x3 << MEM_CDR_STL_SHIFT |
		0x1 << MEM_CDR_THR_SHIFT | MEM_CDR_THR_MODE);
	ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_DIGITAL_MODES, val);

	val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_TRIM);
	val &= ~MEM_DLL_TRIM_SEL;
	val |= 0x2 << MEM_DLL_TRIM_SHIFT;
	ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_TRIM, val);

	val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_DLL);
	val |= MEM_DLL_PHINT_RATE;
	ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_DLL, val);

	val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_EQUALIZER);
	val &= ~(MEM_EQLEV | MEM_EQCTL | MEM_OVRD_EQLEV | MEM_OVRD_EQFTC);
	val |= MEM_EQFTC | 0x1 << MEM_EQCTL_SHIFT;
	ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_EQUALIZER, val);
	if (phy->mode == PIPE3_MODE_SATA) {
		val = ti_pipe3_readl(phy->phy_rx,
				     SATA_PHY_RX_IO_AND_A2D_OVERRIDES);
		val &= ~MEM_CDR_LOS_SOURCE_MASK;
		ti_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES,
				val);
	}
}

static int ti_pipe3_init(struct phy *x)
@@ -401,6 +532,8 @@ static int ti_pipe3_init(struct phy *x)
		return -EINVAL;
	}

	ti_pipe3_calibrate(phy);

	return ret;
}

@@ -611,9 +744,6 @@ static int ti_pipe3_get_tx_rx_base(struct ti_pipe3 *phy)
	struct device *dev = phy->dev;
	struct platform_device *pdev = to_platform_device(dev);

	if (phy->mode != PIPE3_MODE_PCIE)
		return 0;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
					   "phy_rx");
	phy->phy_rx = devm_ioremap_resource(dev, res);
@@ -669,6 +799,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
	phy->dev = dev;
	phy->mode = data->mode;
	phy->dpll_map = data->dpll_map;
	phy->settings = data->settings;

	ret = ti_pipe3_get_pll_base(phy);
	if (ret)