diff options
author | Tom Rini <trini@konsulko.com> | 2022-05-10 15:28:02 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-05-10 15:28:02 -0400 |
commit | 21e25992c86306b41caafcf85efc47d66f5efa6e (patch) | |
tree | 3c9f1ccb01f1a83f077064b4e4f4e028760f2e39 /drivers/phy/phy-stm32-usbphyc.c | |
parent | b4eb57766314062e3dd1ee8e439d2cb2d5dc33d8 (diff) | |
parent | e198d4fe7c34cbb97d7d3cbf31d3a78a5ecc43f7 (diff) |
Merge tag 'u-boot-stm32-20220510' of https://source.denx.de/u-boot/custodians/u-boot-stm
Add new STM32 MCU boards and Documentation
STM32 programmer improvements
video: support several LTDC HW versions and fix data enable polarity
board: fix stboard error message, consider USB cable connected when boot device is USB
configs: stm32mp1: set console variable for extlinux.conf
configs: stm32mp1: add support for baudrate higher than 115200 for ST-Link
ARM: stm32mp: Fix Silicon version handling and ft_system_setup()
phy: stm32-usbphyc: Add DT phy tuning support
arm: dts: stm32mp15: alignment with v5.18
ram: Conditionally enable ASR
mach-stm32mp: psci: retain MCUDIVR, PLL3CR, PLL4CR, MSSCKSELR across suspend
configs: Use TFTP_TSIZE on DHSOM and STMicroelectronics boards
ARM: stm32: Use default CONFIG_TFTP_BLOCKSIZE on DHSOM
pinctrl: stm32: rework GPIO holes management
Diffstat (limited to 'drivers/phy/phy-stm32-usbphyc.c')
-rw-r--r-- | drivers/phy/phy-stm32-usbphyc.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 9c1dcfae524..d7f7c37f919 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -17,6 +17,8 @@ #include <usb.h> #include <asm/io.h> #include <dm/device_compat.h> +#include <dm/of_access.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/delay.h> #include <power/regulator.h> @@ -24,6 +26,7 @@ /* USBPHYC registers */ #define STM32_USBPHYC_PLL 0x0 #define STM32_USBPHYC_MISC 0x8 +#define STM32_USBPHYC_TUNE(X) (0x10C + ((X) * 0x100)) /* STM32_USBPHYC_PLL bit fields */ #define PLLNDIV GENMASK(6, 0) @@ -40,6 +43,26 @@ /* STM32_USBPHYC_MISC bit fields */ #define SWITHOST BIT(0) +/* STM32_USBPHYC_TUNE bit fields */ +#define INCURREN BIT(0) +#define INCURRINT BIT(1) +#define LFSCAPEN BIT(2) +#define HSDRVSLEW BIT(3) +#define HSDRVDCCUR BIT(4) +#define HSDRVDCLEV BIT(5) +#define HSDRVCURINCR BIT(6) +#define FSDRVRFADJ BIT(7) +#define HSDRVRFRED BIT(8) +#define HSDRVCHKITRM GENMASK(12, 9) +#define HSDRVCHKZTRM GENMASK(14, 13) +#define OTPCOMP GENMASK(19, 15) +#define SQLCHCTL GENMASK(21, 20) +#define HDRXGNEQEN BIT(22) +#define HSRXOFF GENMASK(24, 23) +#define HSFALLPREEM BIT(25) +#define SHTCCTCTLPROT BIT(26) +#define STAGSEL BIT(27) + #define MAX_PHYS 2 /* max 100 us for PLL lock and 100 us for PHY init */ @@ -49,6 +72,62 @@ #define PLL_INFF_MIN_RATE 19200000 /* in Hz */ #define PLL_INFF_MAX_RATE 38400000 /* in Hz */ +enum boosting_vals { + BOOST_1000_UA = 1000, + BOOST_2000_UA = 2000, +}; + +enum dc_level_vals { + DC_MINUS_5_TO_7_MV, + DC_PLUS_5_TO_7_MV, + DC_PLUS_10_TO_14_MV, + DC_MAX, +}; + +enum current_trim { + CUR_NOMINAL, + CUR_PLUS_1_56_PCT, + CUR_PLUS_3_12_PCT, + CUR_PLUS_4_68_PCT, + CUR_PLUS_6_24_PCT, + CUR_PLUS_7_8_PCT, + CUR_PLUS_9_36_PCT, + CUR_PLUS_10_92_PCT, + CUR_PLUS_12_48_PCT, + CUR_PLUS_14_04_PCT, + CUR_PLUS_15_6_PCT, + CUR_PLUS_17_16_PCT, + CUR_PLUS_19_01_PCT, + CUR_PLUS_20_58_PCT, + CUR_PLUS_22_16_PCT, + CUR_PLUS_23_73_PCT, + CUR_MAX, +}; + +enum impedance_trim { + IMP_NOMINAL, + IMP_MINUS_2_OHMS, + IMP_MINUS_4_OMHS, + IMP_MINUS_6_OHMS, + IMP_MAX, +}; + +enum squelch_level { + SQLCH_NOMINAL, + SQLCH_PLUS_7_MV, + SQLCH_MINUS_5_MV, + SQLCH_PLUS_14_MV, + SQLCH_MAX, +}; + +enum rx_offset { + NO_RX_OFFSET, + RX_OFFSET_PLUS_5_MV, + RX_OFFSET_PLUS_10_MV, + RX_OFFSET_MINUS_5_MV, + RX_OFFSET_MAX, +}; + struct pll_params { u8 ndiv; u16 frac; @@ -327,6 +406,90 @@ static int stm32_usbphyc_of_xlate(struct phy *phy, return 0; } +static void stm32_usbphyc_tuning(struct udevice *dev, ofnode node, u32 index) +{ + struct stm32_usbphyc *usbphyc = dev_get_priv(dev); + u32 reg = STM32_USBPHYC_TUNE(index); + u32 otpcomp, val, tune = 0; + int ret; + + /* Backup OTP compensation code */ + otpcomp = FIELD_GET(OTPCOMP, readl(usbphyc->base + reg)); + + ret = ofnode_read_u32(node, "st,current-boost-microamp", &val); + if (!ret && (val == BOOST_1000_UA || val == BOOST_2000_UA)) { + val = (val == BOOST_2000_UA) ? 1 : 0; + tune |= INCURREN | FIELD_PREP(INCURRINT, val); + } else if (ret != -EINVAL) { + dev_warn(dev, "phy%d: invalid st,current-boost-microamp value\n", index); + } + + if (!ofnode_read_bool(node, "st,no-lsfs-fb-cap")) + tune |= LFSCAPEN; + + if (ofnode_read_bool(node, "st,decrease-hs-slew-rate")) + tune |= HSDRVSLEW; + + ret = ofnode_read_u32(node, "st,tune-hs-dc-level", &val); + if (!ret && val < DC_MAX) { + if (val == DC_MINUS_5_TO_7_MV) { + tune |= HSDRVDCCUR; + } else { + val = (val == DC_PLUS_10_TO_14_MV) ? 1 : 0; + tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); + } + } else if (ret != -EINVAL) { + dev_warn(dev, "phy%d: invalid st,tune-hs-dc-level value\n", index); + } + + if (ofnode_read_bool(node, "st,enable-fs-rftime-tuning")) + tune |= FSDRVRFADJ; + + if (ofnode_read_bool(node, "st,enable-hs-rftime-reduction")) + tune |= HSDRVRFRED; + + ret = ofnode_read_u32(node, "st,trim-hs-current", &val); + if (!ret && val < CUR_MAX) + tune |= FIELD_PREP(HSDRVCHKITRM, val); + else if (ret != -EINVAL) + dev_warn(dev, "phy%d: invalid st,trim-hs-current value\n", index); + + ret = ofnode_read_u32(node, "st,trim-hs-impedance", &val); + if (!ret && val < IMP_MAX) + tune |= FIELD_PREP(HSDRVCHKZTRM, val); + else if (ret != -EINVAL) + dev_warn(dev, "phy%d: invalid trim-hs-impedance value\n", index); + + ret = ofnode_read_u32(node, "st,tune-squelch-level", &val); + if (!ret && val < SQLCH_MAX) + tune |= FIELD_PREP(SQLCHCTL, val); + else if (ret != -EINVAL) + dev_warn(dev, "phy%d: invalid st,tune-squelch-level value\n", index); + + if (ofnode_read_bool(node, "st,enable-hs-rx-gain-eq")) + tune |= HDRXGNEQEN; + + ret = ofnode_read_u32(node, "st,tune-hs-rx-offset", &val); + if (!ret && val < RX_OFFSET_MAX) + tune |= FIELD_PREP(HSRXOFF, val); + else if (ret != -EINVAL) + dev_warn(dev, "phy%d: invalid st,tune-hs-rx-offset value\n", index); + + if (ofnode_read_bool(node, "st,no-hs-ftime-ctrl")) + tune |= HSFALLPREEM; + + if (!ofnode_read_bool(node, "st,no-lsfs-sc")) + tune |= SHTCCTCTLPROT; + + if (ofnode_read_bool(node, "st,enable-hs-tx-staggering")) + tune |= STAGSEL; + + /* Restore OTP compensation code */ + tune |= FIELD_PREP(OTPCOMP, otpcomp); + + writel(tune, usbphyc->base + reg); +} + static const struct phy_ops stm32_usbphyc_phy_ops = { .init = stm32_usbphyc_phy_init, .exit = stm32_usbphyc_phy_exit, @@ -389,6 +552,10 @@ static int stm32_usbphyc_probe(struct udevice *dev) phy_id, ofnode_get_name(node)); return -ENOENT; } + + /* Configure phy tuning */ + stm32_usbphyc_tuning(dev, node, phy_id); + usbphyc_phy = usbphyc->phys + phy_id; usbphyc_phy->init = false; usbphyc_phy->powered = false; |