brintos

brintos / linux-shallow public Read only

0
0
Text · 12.3 KiB · f461585 Raw
398 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Salvo PHY is a 28nm PHY, it is a legacy PHY, and only4 * for USB3 and USB2.5 *6 * Copyright (c) 2019-2020 NXP7 */8 9#include <linux/bitfield.h>10#include <linux/clk.h>11#include <linux/io.h>12#include <linux/module.h>13#include <linux/phy/phy.h>14#include <linux/platform_device.h>15#include <linux/delay.h>16#include <linux/of.h>17#include <linux/of_platform.h>18 19#define USB3_PHY_OFFSET			0x020#define USB2_PHY_OFFSET			0x3800021/* USB3 PHY register definition */22#define PHY_PMA_CMN_CTRL1			0xC80023#define TB_ADDR_CMN_DIAG_HSCLK_SEL		0x01e024#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR	0x008425#define TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR	0x008526#define TB_ADDR_CMN_PLL0_INTDIV	                0x009427#define TB_ADDR_CMN_PLL0_FRACDIV		0x009528#define TB_ADDR_CMN_PLL0_HIGH_THR		0x009629#define TB_ADDR_CMN_PLL0_SS_CTRL1		0x009830#define TB_ADDR_CMN_PLL0_SS_CTRL2		0x009931#define TB_ADDR_CMN_PLL0_DSM_DIAG		0x009732#define TB_ADDR_CMN_DIAG_PLL0_OVRD		0x01c233#define TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD		0x01c034#define TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD		0x01c135#define TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE          0x01C536#define TB_ADDR_CMN_DIAG_PLL0_CP_TUNE           0x01C637#define TB_ADDR_CMN_DIAG_PLL0_LF_PROG           0x01C738#define TB_ADDR_CMN_DIAG_PLL0_TEST_MODE		0x01c439#define TB_ADDR_CMN_PSM_CLK_CTRL		0x006140#define TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR	0x40ea41#define TB_ADDR_XCVR_PSM_RCTRL	                0x400142#define TB_ADDR_TX_PSC_A0		        0x410043#define TB_ADDR_TX_PSC_A1		        0x410144#define TB_ADDR_TX_PSC_A2		        0x410245#define TB_ADDR_TX_PSC_A3		        0x410346#define TB_ADDR_TX_DIAG_ECTRL_OVRD		0x41f547#define TB_ADDR_TX_PSC_CAL		        0x410648#define TB_ADDR_TX_PSC_RDY		        0x410749#define TB_ADDR_RX_PSC_A0	                0x800050#define TB_ADDR_RX_PSC_A1	                0x800151#define TB_ADDR_RX_PSC_A2	                0x800252#define TB_ADDR_RX_PSC_A3	                0x800353#define TB_ADDR_RX_PSC_CAL	                0x800654#define TB_ADDR_RX_PSC_RDY	                0x800755#define TB_ADDR_TX_TXCC_MGNLS_MULT_000		0x405856#define TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY	0x41e757#define TB_ADDR_RX_SLC_CU_ITER_TMR		0x80e358#define TB_ADDR_RX_SIGDET_HL_FILT_TMR		0x809059#define TB_ADDR_RX_SAMP_DAC_CTRL		0x805860#define TB_ADDR_RX_DIAG_SIGDET_TUNE		0x81dc61#define TB_ADDR_RX_DIAG_LFPSDET_TUNE2		0x81df62#define TB_ADDR_RX_DIAG_BS_TM	                0x81f563#define TB_ADDR_RX_DIAG_DFE_CTRL1		0x81d364#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM4		0x81c765#define TB_ADDR_RX_DIAG_ILL_E_TRIM0		0x81c266#define TB_ADDR_RX_DIAG_ILL_IQ_TRIM0		0x81c167#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM6		0x81c968#define TB_ADDR_RX_DIAG_RXFE_TM3		0x81f869#define TB_ADDR_RX_DIAG_RXFE_TM4		0x81f970#define TB_ADDR_RX_DIAG_LFPSDET_TUNE		0x81dd71#define TB_ADDR_RX_DIAG_DFE_CTRL3		0x81d572#define TB_ADDR_RX_DIAG_SC2C_DELAY		0x81e173#define TB_ADDR_RX_REE_VGA_GAIN_NODFE		0x81bf74#define TB_ADDR_XCVR_PSM_CAL_TMR		0x400275#define TB_ADDR_XCVR_PSM_A0BYP_TMR		0x400476#define TB_ADDR_XCVR_PSM_A0IN_TMR		0x400377#define TB_ADDR_XCVR_PSM_A1IN_TMR		0x400578#define TB_ADDR_XCVR_PSM_A2IN_TMR		0x400679#define TB_ADDR_XCVR_PSM_A3IN_TMR		0x400780#define TB_ADDR_XCVR_PSM_A4IN_TMR		0x400881#define TB_ADDR_XCVR_PSM_A5IN_TMR		0x400982#define TB_ADDR_XCVR_PSM_A0OUT_TMR		0x400a83#define TB_ADDR_XCVR_PSM_A1OUT_TMR		0x400b84#define TB_ADDR_XCVR_PSM_A2OUT_TMR		0x400c85#define TB_ADDR_XCVR_PSM_A3OUT_TMR		0x400d86#define TB_ADDR_XCVR_PSM_A4OUT_TMR		0x400e87#define TB_ADDR_XCVR_PSM_A5OUT_TMR		0x400f88#define TB_ADDR_TX_RCVDET_EN_TMR	        0x412289#define TB_ADDR_TX_RCVDET_ST_TMR	        0x412390#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR	0x40f291#define TB_ADDR_TX_RCVDETSC_CTRL	        0x412492 93/* USB2 PHY register definition */94#define UTMI_REG15				0xaf95#define UTMI_AFE_RX_REG0			0x0d96#define UTMI_AFE_RX_REG5			0x1297#define UTMI_AFE_BC_REG4			0x2998 99/* Align UTMI_AFE_RX_REG0 bit[7:6] define */100enum usb2_disconn_threshold {101	USB2_DISCONN_THRESHOLD_575 = 0x0,102	USB2_DISCONN_THRESHOLD_610 = 0x1,103	USB2_DISCONN_THRESHOLD_645 = 0x3,104};105 106#define RX_USB2_DISCONN_MASK			GENMASK(7, 6)107 108/* TB_ADDR_TX_RCVDETSC_CTRL */109#define RXDET_IN_P3_32KHZ			BIT(0)110/*111 * UTMI_REG15112 *113 * Gate how many us for the txvalid signal until analog114 * HS/FS transmitters have powered up115 */116#define TXVALID_GATE_THRESHOLD_HS_MASK		(BIT(4) | BIT(5))117/* 0us, txvalid is ready just after HS/FS transmitters have powered up */118#define TXVALID_GATE_THRESHOLD_HS_0US		(BIT(4) | BIT(5))119 120#define SET_B_SESSION_VALID			(BIT(6) | BIT(5))121#define CLR_B_SESSION_VALID			(BIT(6))122 123struct cdns_reg_pairs {124	u16 val;125	u32 off;126};127 128struct cdns_salvo_data {129	u8 reg_offset_shift;130	const struct cdns_reg_pairs *init_sequence_val;131	u8 init_sequence_length;132};133 134struct cdns_salvo_phy {135	struct phy *phy;136	struct clk *clk;137	void __iomem *base;138	struct cdns_salvo_data *data;139	enum usb2_disconn_threshold usb2_disconn;140};141 142static const struct of_device_id cdns_salvo_phy_of_match[];143static const struct cdns_salvo_data cdns_nxp_salvo_data;144 145static bool cdns_is_nxp_phy(struct cdns_salvo_phy *salvo_phy)146{147	return salvo_phy->data == &cdns_nxp_salvo_data;148}149 150static u16 cdns_salvo_read(struct cdns_salvo_phy *salvo_phy, u32 offset, u32 reg)151{152	return (u16)readl(salvo_phy->base + offset +153		reg * (1 << salvo_phy->data->reg_offset_shift));154}155 156static void cdns_salvo_write(struct cdns_salvo_phy *salvo_phy, u32 offset,157			     u32 reg, u16 val)158{159	writel(val, salvo_phy->base + offset +160		reg * (1 << salvo_phy->data->reg_offset_shift));161}162 163/*164 * Below bringup sequence pair are from Cadence PHY's User Guide165 * and NXP platform tuning results.166 */167static const struct cdns_reg_pairs cdns_nxp_sequence_pair[] = {168	{0x0830, PHY_PMA_CMN_CTRL1},169	{0x0010, TB_ADDR_CMN_DIAG_HSCLK_SEL},170	{0x00f0, TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR},171	{0x0018, TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR},172	{0x00d0, TB_ADDR_CMN_PLL0_INTDIV},173	{0x4aaa, TB_ADDR_CMN_PLL0_FRACDIV},174	{0x0034, TB_ADDR_CMN_PLL0_HIGH_THR},175	{0x01ee, TB_ADDR_CMN_PLL0_SS_CTRL1},176	{0x7f03, TB_ADDR_CMN_PLL0_SS_CTRL2},177	{0x0020, TB_ADDR_CMN_PLL0_DSM_DIAG},178	{0x0000, TB_ADDR_CMN_DIAG_PLL0_OVRD},179	{0x0000, TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD},180	{0x0000, TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD},181	{0x0007, TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE},182	{0x0027, TB_ADDR_CMN_DIAG_PLL0_CP_TUNE},183	{0x0008, TB_ADDR_CMN_DIAG_PLL0_LF_PROG},184	{0x0022, TB_ADDR_CMN_DIAG_PLL0_TEST_MODE},185	{0x000a, TB_ADDR_CMN_PSM_CLK_CTRL},186	{0x0139, TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR},187	{0xbefc, TB_ADDR_XCVR_PSM_RCTRL},188 189	{0x7799, TB_ADDR_TX_PSC_A0},190	{0x7798, TB_ADDR_TX_PSC_A1},191	{0x509b, TB_ADDR_TX_PSC_A2},192	{0x0003, TB_ADDR_TX_DIAG_ECTRL_OVRD},193	{0x509b, TB_ADDR_TX_PSC_A3},194	{0x2090, TB_ADDR_TX_PSC_CAL},195	{0x2090, TB_ADDR_TX_PSC_RDY},196 197	{0xA6FD, TB_ADDR_RX_PSC_A0},198	{0xA6FD, TB_ADDR_RX_PSC_A1},199	{0xA410, TB_ADDR_RX_PSC_A2},200	{0x2410, TB_ADDR_RX_PSC_A3},201 202	{0x23FF, TB_ADDR_RX_PSC_CAL},203	{0x2010, TB_ADDR_RX_PSC_RDY},204 205	{0x0020, TB_ADDR_TX_TXCC_MGNLS_MULT_000},206	{0x00ff, TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY},207	{0x0002, TB_ADDR_RX_SLC_CU_ITER_TMR},208	{0x0013, TB_ADDR_RX_SIGDET_HL_FILT_TMR},209	{0x0000, TB_ADDR_RX_SAMP_DAC_CTRL},210	{0x1004, TB_ADDR_RX_DIAG_SIGDET_TUNE},211	{0x4041, TB_ADDR_RX_DIAG_LFPSDET_TUNE2},212	{0x0480, TB_ADDR_RX_DIAG_BS_TM},213	{0x8006, TB_ADDR_RX_DIAG_DFE_CTRL1},214	{0x003f, TB_ADDR_RX_DIAG_ILL_IQE_TRIM4},215	{0x543f, TB_ADDR_RX_DIAG_ILL_E_TRIM0},216	{0x543f, TB_ADDR_RX_DIAG_ILL_IQ_TRIM0},217	{0x0000, TB_ADDR_RX_DIAG_ILL_IQE_TRIM6},218	{0x8000, TB_ADDR_RX_DIAG_RXFE_TM3},219	{0x0003, TB_ADDR_RX_DIAG_RXFE_TM4},220	{0x2408, TB_ADDR_RX_DIAG_LFPSDET_TUNE},221	{0x05ca, TB_ADDR_RX_DIAG_DFE_CTRL3},222	{0x0258, TB_ADDR_RX_DIAG_SC2C_DELAY},223	{0x1fff, TB_ADDR_RX_REE_VGA_GAIN_NODFE},224 225	{0x02c6, TB_ADDR_XCVR_PSM_CAL_TMR},226	{0x0002, TB_ADDR_XCVR_PSM_A0BYP_TMR},227	{0x02c6, TB_ADDR_XCVR_PSM_A0IN_TMR},228	{0x0010, TB_ADDR_XCVR_PSM_A1IN_TMR},229	{0x0010, TB_ADDR_XCVR_PSM_A2IN_TMR},230	{0x0010, TB_ADDR_XCVR_PSM_A3IN_TMR},231	{0x0010, TB_ADDR_XCVR_PSM_A4IN_TMR},232	{0x0010, TB_ADDR_XCVR_PSM_A5IN_TMR},233 234	{0x0002, TB_ADDR_XCVR_PSM_A0OUT_TMR},235	{0x0002, TB_ADDR_XCVR_PSM_A1OUT_TMR},236	{0x0002, TB_ADDR_XCVR_PSM_A2OUT_TMR},237	{0x0002, TB_ADDR_XCVR_PSM_A3OUT_TMR},238	{0x0002, TB_ADDR_XCVR_PSM_A4OUT_TMR},239	{0x0002, TB_ADDR_XCVR_PSM_A5OUT_TMR},240	/* Change rx detect parameter */241	{0x0960, TB_ADDR_TX_RCVDET_EN_TMR},242	{0x01e0, TB_ADDR_TX_RCVDET_ST_TMR},243	{0x0090, TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR},244};245 246static int cdns_salvo_phy_init(struct phy *phy)247{248	struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);249	struct cdns_salvo_data *data = salvo_phy->data;250	int ret, i;251	u16 value;252 253	ret = clk_prepare_enable(salvo_phy->clk);254	if (ret)255		return ret;256 257	for (i = 0; i < data->init_sequence_length; i++) {258		const struct cdns_reg_pairs *reg_pair = data->init_sequence_val + i;259 260		cdns_salvo_write(salvo_phy, USB3_PHY_OFFSET, reg_pair->off, reg_pair->val);261	}262 263	/* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */264	value = cdns_salvo_read(salvo_phy, USB3_PHY_OFFSET, TB_ADDR_TX_RCVDETSC_CTRL);265	value |= RXDET_IN_P3_32KHZ;266	cdns_salvo_write(salvo_phy, USB3_PHY_OFFSET, TB_ADDR_TX_RCVDETSC_CTRL,267			 RXDET_IN_P3_32KHZ);268 269	value = cdns_salvo_read(salvo_phy, USB2_PHY_OFFSET, UTMI_REG15);270	value &= ~TXVALID_GATE_THRESHOLD_HS_MASK;271	cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_REG15,272			 value | TXVALID_GATE_THRESHOLD_HS_0US);273 274	cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_RX_REG5, 0x5);275 276	value = cdns_salvo_read(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_RX_REG0);277	value &= ~RX_USB2_DISCONN_MASK;278	value = FIELD_PREP(RX_USB2_DISCONN_MASK, salvo_phy->usb2_disconn);279	cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_RX_REG0, value);280 281	udelay(10);282 283	clk_disable_unprepare(salvo_phy->clk);284 285	return ret;286}287 288static int cdns_salvo_phy_power_on(struct phy *phy)289{290	struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);291 292	return clk_prepare_enable(salvo_phy->clk);293}294 295static int cdns_salvo_phy_power_off(struct phy *phy)296{297	struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);298 299	clk_disable_unprepare(salvo_phy->clk);300 301	return 0;302}303 304static int cdns_salvo_set_mode(struct phy *phy, enum phy_mode mode, int submode)305{306	struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);307 308	if (!cdns_is_nxp_phy(salvo_phy))309		return 0;310 311	if (mode == PHY_MODE_USB_DEVICE)312		cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_BC_REG4,313			 SET_B_SESSION_VALID);314	else315		cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_BC_REG4,316			 CLR_B_SESSION_VALID);317 318	return 0;319}320 321static const struct phy_ops cdns_salvo_phy_ops = {322	.init		= cdns_salvo_phy_init,323	.power_on	= cdns_salvo_phy_power_on,324	.power_off	= cdns_salvo_phy_power_off,325	.owner		= THIS_MODULE,326	.set_mode	= cdns_salvo_set_mode,327};328 329static int cdns_salvo_phy_probe(struct platform_device *pdev)330{331	struct phy_provider *phy_provider;332	struct device *dev = &pdev->dev;333	struct cdns_salvo_phy *salvo_phy;334	struct cdns_salvo_data *data;335	u32 val;336 337	data = (struct cdns_salvo_data *)of_device_get_match_data(dev);338	salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL);339	if (!salvo_phy)340		return -ENOMEM;341 342	salvo_phy->data = data;343	salvo_phy->clk = devm_clk_get_optional(dev, "salvo_phy_clk");344	if (IS_ERR(salvo_phy->clk))345		return PTR_ERR(salvo_phy->clk);346 347	if (of_property_read_u32(dev->of_node, "cdns,usb2-disconnect-threshold-microvolt", &val))348		val = 575;349 350	if (val < 610)351		salvo_phy->usb2_disconn = USB2_DISCONN_THRESHOLD_575;352	else if (val < 645)353		salvo_phy->usb2_disconn = USB2_DISCONN_THRESHOLD_610;354	else355		salvo_phy->usb2_disconn = USB2_DISCONN_THRESHOLD_645;356 357	salvo_phy->base = devm_platform_ioremap_resource(pdev, 0);358	if (IS_ERR(salvo_phy->base))359		return PTR_ERR(salvo_phy->base);360 361	salvo_phy->phy = devm_phy_create(dev, NULL, &cdns_salvo_phy_ops);362	if (IS_ERR(salvo_phy->phy))363		return PTR_ERR(salvo_phy->phy);364 365	phy_set_drvdata(salvo_phy->phy, salvo_phy);366 367	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);368	return PTR_ERR_OR_ZERO(phy_provider);369}370 371static const struct cdns_salvo_data cdns_nxp_salvo_data = {372	2,373	cdns_nxp_sequence_pair,374	ARRAY_SIZE(cdns_nxp_sequence_pair),375};376 377static const struct of_device_id cdns_salvo_phy_of_match[] = {378	{379		.compatible = "nxp,salvo-phy",380		.data = &cdns_nxp_salvo_data,381	},382	{}383};384MODULE_DEVICE_TABLE(of, cdns_salvo_phy_of_match);385 386static struct platform_driver cdns_salvo_phy_driver = {387	.probe	= cdns_salvo_phy_probe,388	.driver = {389		.name	= "cdns-salvo-phy",390		.of_match_table	= cdns_salvo_phy_of_match,391	}392};393module_platform_driver(cdns_salvo_phy_driver);394 395MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");396MODULE_LICENSE("GPL v2");397MODULE_DESCRIPTION("Cadence SALVO PHY Driver");398