diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 09:40:49 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 09:40:49 -0800 |
commit | e4ee8b85b7657d9c769b727038faabdc2e6a3412 (patch) | |
tree | e6b52a1e866ed77b09b267f60f8f1b5449228325 /drivers/phy | |
parent | 7109a04eae81c41ed529da9f3c48c3655ccea741 (diff) | |
parent | d08dd3f3dd2ae351b793fc5b76abdbf0fd317b12 (diff) | |
download | linux-e4ee8b85b7657d9c769b727038faabdc2e6a3412.tar.bz2 |
Merge tag 'usb-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big USB and PHY driver update for 4.16-rc1.
Along with the normally expected XHCI, MUSB, and Gadget driver
patches, there are some PHY driver fixes, license cleanups, sysfs
attribute cleanups, usbip changes, and a raft of other smaller fixes
and additions.
Full details are in the shortlog.
All of these have been in the linux-next tree for a long time with no
reported issues"
* tag 'usb-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (137 commits)
USB: serial: pl2303: new device id for Chilitag
USB: misc: fix up some remaining DEVICE_ATTR() usages
USB: musb: fix up one odd DEVICE_ATTR() usage
USB: atm: fix up some remaining DEVICE_ATTR() usage
USB: move many drivers to use DEVICE_ATTR_WO
USB: move many drivers to use DEVICE_ATTR_RO
USB: move many drivers to use DEVICE_ATTR_RW
USB: misc: chaoskey: Use true and false for boolean values
USB: storage: remove old wording about how to submit a change
USB: storage: remove invalid URL from drivers
usb: ehci-omap: don't complain on -EPROBE_DEFER when no PHY found
usbip: list: don't list devices attached to vhci_hcd
usbip: prevent bind loops on devices attached to vhci_hcd
USB: serial: remove redundant initializations of 'mos_parport'
usb/gadget: Fix "high bandwidth" check in usb_gadget_ep_match_desc()
usb: gadget: compress return logic into one line
usbip: vhci_hcd: update 'status' file header and format
USB: serial: simple: add Motorola Tetra driver
CDC-ACM: apply quirk for card reader
usb: option: Add support for FS040U modem
...
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/broadcom/phy-brcm-usb-init.c | 22 | ||||
-rw-r--r-- | drivers/phy/broadcom/phy-brcm-usb.c | 4 | ||||
-rw-r--r-- | drivers/phy/mediatek/phy-mtk-tphy.c | 35 | ||||
-rw-r--r-- | drivers/phy/samsung/phy-exynos5-usbdrd.c | 183 |
4 files changed, 210 insertions, 34 deletions
diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.c b/drivers/phy/broadcom/phy-brcm-usb-init.c index 1e7ce0b6f299..1b7febc43da9 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init.c +++ b/drivers/phy/broadcom/phy-brcm-usb-init.c @@ -50,6 +50,8 @@ #define USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK 0x80000000 /* option */ #define USB_CTRL_EBRIDGE 0x0c #define USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK 0x00020000 /* option */ +#define USB_CTRL_OBRIDGE 0x10 +#define USB_CTRL_OBRIDGE_LS_KEEP_ALIVE_MASK 0x08000000 #define USB_CTRL_MDIO 0x14 #define USB_CTRL_MDIO2 0x18 #define USB_CTRL_UTMI_CTL_1 0x2c @@ -71,6 +73,7 @@ #define USB_CTRL_USB30_CTL1_USB3_IPP_MASK 0x20000000 /* option */ #define USB_CTRL_USB30_PCTL 0x70 #define USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_MASK 0x00000002 +#define USB_CTRL_USB30_PCTL_PHY3_IDDQ_OVERRIDE_MASK 0x00008000 #define USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_P1_MASK 0x00020000 #define USB_CTRL_USB_DEVICE_CTL1 0x90 #define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003 /* option */ @@ -116,7 +119,6 @@ enum { USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR, USB_CTRL_SETUP_OC3_DISABLE_SELECTOR, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR, - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_SELECTOR, USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR, USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR, USB_CTRL_USB_PM_USB_PWRDN_SELECTOR, @@ -203,7 +205,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK, 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_USB_PWRDN_MASK, @@ -225,7 +226,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ @@ -247,7 +247,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK, 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_USB_PWRDN_MASK, @@ -269,7 +268,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ @@ -291,7 +289,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ USB_CTRL_SETUP_OC3_DISABLE_MASK, 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, USB_CTRL_USB_PM_USB_PWRDN_MASK, @@ -313,7 +310,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ @@ -335,7 +331,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK, 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK */ USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_USB_PWRDN_MASK, @@ -357,7 +352,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ @@ -379,7 +373,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK, 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_USB_PWRDN_MASK, @@ -401,7 +394,6 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK, 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_USB_PWRDN_MASK, @@ -926,6 +918,7 @@ void brcm_usb_init_common(struct brcm_usb_init_params *params) USB_CTRL_UNSET_FAMILY(params, USB_PM, BDC_SOFT_RESETB); break; default: + USB_CTRL_UNSET_FAMILY(params, USB_PM, BDC_SOFT_RESETB); USB_CTRL_SET_FAMILY(params, USB_PM, BDC_SOFT_RESETB); break; } @@ -952,13 +945,17 @@ void brcm_usb_init_eohci(struct brcm_usb_init_params *params) * Don't enable this so the memory controller doesn't read * into memory holes. NOTE: This bit is low true on 7366C0. */ - USB_CTRL_SET_FAMILY(params, EBRIDGE, ESTOP_SCB_REQ); + USB_CTRL_SET(ctrl, EBRIDGE, ESTOP_SCB_REQ); /* Setup the endian bits */ reg = brcmusb_readl(USB_CTRL_REG(ctrl, SETUP)); reg &= ~USB_CTRL_SETUP_ENDIAN_BITS; reg |= USB_CTRL_MASK_FAMILY(params, SETUP, ENDIAN); brcmusb_writel(reg, USB_CTRL_REG(ctrl, SETUP)); + + if (params->selected_family == BRCM_FAMILY_7271A0) + /* Enable LS keep alive fix for certain keyboards */ + USB_CTRL_SET(ctrl, OBRIDGE, LS_KEEP_ALIVE); } void brcm_usb_init_xhci(struct brcm_usb_init_params *params) @@ -1003,6 +1000,7 @@ void brcm_usb_uninit_eohci(struct brcm_usb_init_params *params) void brcm_usb_uninit_xhci(struct brcm_usb_init_params *params) { brcmusb_xhci_soft_reset(params, 1); + USB_CTRL_SET(params->ctrl_regs, USB30_PCTL, PHY3_IDDQ_OVERRIDE); } void brcm_usb_set_family_map(struct brcm_usb_init_params *params) diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index 195b98139e5f..d1dab36fa5b7 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -338,9 +338,9 @@ static int brcm_usb_phy_probe(struct platform_device *pdev) ARRAY_SIZE(brcm_dr_mode_to_name), mode, &priv->ini.mode); } - if (of_property_read_bool(dn, "brcm,has_xhci")) + if (of_property_read_bool(dn, "brcm,has-xhci")) priv->has_xhci = true; - if (of_property_read_bool(dn, "brcm,has_eohci")) + if (of_property_read_bool(dn, "brcm,has-eohci")) priv->has_eohci = true; err = brcm_usb_phy_dvr_init(dev, priv, dn); diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 402385f2562a..1e96d0740ef5 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -20,6 +20,7 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> @@ -440,9 +441,9 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, u32 index = instance->index; u32 tmp; - /* switch to USB function. (system register, force ip into usb mode) */ + /* switch to USB function, and enable usb pll */ tmp = readl(com + U3P_U2PHYDTM0); - tmp &= ~P2C_FORCE_UART_EN; + tmp &= ~(P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM); tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0); writel(tmp, com + U3P_U2PHYDTM0); @@ -502,10 +503,8 @@ static void u2_phy_instance_power_on(struct mtk_tphy *tphy, u32 index = instance->index; u32 tmp; - /* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */ tmp = readl(com + U3P_U2PHYDTM0); - tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL); - tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK); + tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK); writel(tmp, com + U3P_U2PHYDTM0); /* OTG Enable */ @@ -540,7 +539,6 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy, tmp = readl(com + U3P_U2PHYDTM0); tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN); - tmp |= P2C_FORCE_SUSPENDM; writel(tmp, com + U3P_U2PHYDTM0); /* OTG Disable */ @@ -548,18 +546,16 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy, tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN; writel(tmp, com + U3P_USBPHYACR6); - /* let suspendm=0, set utmi into analog power down */ - tmp = readl(com + U3P_U2PHYDTM0); - tmp &= ~P2C_RG_SUSPENDM; - writel(tmp, com + U3P_U2PHYDTM0); - udelay(1); - tmp = readl(com + U3P_U2PHYDTM1); tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID); tmp |= P2C_RG_SESSEND; writel(tmp, com + U3P_U2PHYDTM1); if (tphy->pdata->avoid_rx_sen_degradation && index) { + tmp = readl(com + U3P_U2PHYDTM0); + tmp &= ~(P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM); + writel(tmp, com + U3P_U2PHYDTM0); + tmp = readl(com + U3D_U2PHYDCR0); tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; writel(tmp, com + U3D_U2PHYDCR0); @@ -1000,7 +996,6 @@ MODULE_DEVICE_TABLE(of, mtk_tphy_id_table); static int mtk_tphy_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct device_node *child_np; @@ -1010,15 +1005,14 @@ static int mtk_tphy_probe(struct platform_device *pdev) struct resource res; int port, retval; - match = of_match_node(mtk_tphy_id_table, pdev->dev.of_node); - if (!match) - return -EINVAL; - tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL); if (!tphy) return -ENOMEM; - tphy->pdata = match->data; + tphy->pdata = of_device_get_match_data(dev); + if (!tphy->pdata) + return -EINVAL; + tphy->nphys = of_get_child_count(np); tphy->phys = devm_kcalloc(dev, tphy->nphys, sizeof(*tphy->phys), GFP_KERNEL); @@ -1028,9 +1022,10 @@ static int mtk_tphy_probe(struct platform_device *pdev) tphy->dev = dev; platform_set_drvdata(pdev, tphy); - if (tphy->pdata->version == MTK_PHY_V1) { + sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* SATA phy of V1 needn't it if not shared with PCIe or USB */ + if (sif_res && tphy->pdata->version == MTK_PHY_V1) { /* get banks shared by multiple phys */ - sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); tphy->sif_base = devm_ioremap_resource(dev, sif_res); if (IS_ERR(tphy->sif_base)) { dev_err(dev, "failed to remap sif regs\n"); diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index 22c68f58b181..b8b226a20014 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -90,7 +90,17 @@ #define PHYCLKRST_COMMONONN BIT(0) #define EXYNOS5_DRD_PHYREG0 0x14 +#define PHYREG0_SSC_REF_CLK_SEL BIT(21) +#define PHYREG0_SSC_RANGE BIT(20) +#define PHYREG0_CR_WRITE BIT(19) +#define PHYREG0_CR_READ BIT(18) +#define PHYREG0_CR_DATA_IN(_x) ((_x) << 2) +#define PHYREG0_CR_CAP_DATA BIT(1) +#define PHYREG0_CR_CAP_ADDR BIT(0) + #define EXYNOS5_DRD_PHYREG1 0x18 +#define PHYREG1_CR_DATA_OUT(_x) ((_x) << 1) +#define PHYREG1_CR_ACK BIT(0) #define EXYNOS5_DRD_PHYPARAM0 0x1c @@ -119,6 +129,25 @@ #define EXYNOS5_DRD_PHYRESUME 0x34 #define EXYNOS5_DRD_LINKPORT 0x44 +/* USB 3.0 DRD PHY SS Function Control Reg; accessed by CR_PORT */ +#define EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN (0x15) +#define LOSLEVEL_OVRD_IN_LOS_BIAS_5420 (0x5 << 13) +#define LOSLEVEL_OVRD_IN_LOS_BIAS_DEFAULT (0x0 << 13) +#define LOSLEVEL_OVRD_IN_EN (0x1 << 10) +#define LOSLEVEL_OVRD_IN_LOS_LEVEL_DEFAULT (0x9 << 0) + +#define EXYNOS5_DRD_PHYSS_TX_VBOOSTLEVEL_OVRD_IN (0x12) +#define TX_VBOOSTLEVEL_OVRD_IN_VBOOST_5420 (0x5 << 13) +#define TX_VBOOSTLEVEL_OVRD_IN_VBOOST_DEFAULT (0x4 << 13) + +#define EXYNOS5_DRD_PHYSS_LANE0_TX_DEBUG (0x1010) +#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_19M2_20M (0x4 << 4) +#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_24M (0x8 << 4) +#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_25M_26M (0x8 << 4) +#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_48M_50M_52M (0x20 << 4) +#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_62M5 (0x20 << 4) +#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_96M_100M (0x40 << 4) + #define KHZ 1000 #define MHZ (KHZ * KHZ) @@ -527,6 +556,151 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy) return 0; } +static int crport_handshake(struct exynos5_usbdrd_phy *phy_drd, + u32 val, u32 cmd) +{ + u32 usec = 100; + unsigned int result; + + writel(val | cmd, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + + do { + result = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1); + if (result & PHYREG1_CR_ACK) + break; + + udelay(1); + } while (usec-- > 0); + + if (!usec) { + dev_err(phy_drd->dev, + "CRPORT handshake timeout1 (0x%08x)\n", val); + return -ETIME; + } + + usec = 100; + + writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + + do { + result = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYREG1); + if (!(result & PHYREG1_CR_ACK)) + break; + + udelay(1); + } while (usec-- > 0); + + if (!usec) { + dev_err(phy_drd->dev, + "CRPORT handshake timeout2 (0x%08x)\n", val); + return -ETIME; + } + + return 0; +} + +static int crport_ctrl_write(struct exynos5_usbdrd_phy *phy_drd, + u32 addr, u32 data) +{ + int ret; + + /* Write Address */ + writel(PHYREG0_CR_DATA_IN(addr), + phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(addr), + PHYREG0_CR_CAP_ADDR); + if (ret) + return ret; + + /* Write Data */ + writel(PHYREG0_CR_DATA_IN(data), + phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data), + PHYREG0_CR_CAP_DATA); + if (ret) + return ret; + + ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data), + PHYREG0_CR_WRITE); + + return ret; +} + +/* + * Calibrate few PHY parameters using CR_PORT register to meet + * SuperSpeed requirements on Exynos5420 and Exynos5800 systems, + * which have 28nm USB 3.0 DRD PHY. + */ +static int exynos5420_usbdrd_phy_calibrate(struct exynos5_usbdrd_phy *phy_drd) +{ + unsigned int temp; + int ret = 0; + + /* + * Change los_bias to (0x5) for 28nm PHY from a + * default value (0x0); los_level is set as default + * (0x9) as also reflected in los_level[30:26] bits + * of PHYPARAM0 register. + */ + temp = LOSLEVEL_OVRD_IN_LOS_BIAS_5420 | + LOSLEVEL_OVRD_IN_EN | + LOSLEVEL_OVRD_IN_LOS_LEVEL_DEFAULT; + ret = crport_ctrl_write(phy_drd, + EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN, + temp); + if (ret) { + dev_err(phy_drd->dev, + "Failed setting Loss-of-Signal level for SuperSpeed\n"); + return ret; + } + + /* + * Set tx_vboost_lvl to (0x5) for 28nm PHY Tuning, + * to raise Tx signal level from its default value of (0x4) + */ + temp = TX_VBOOSTLEVEL_OVRD_IN_VBOOST_5420; + ret = crport_ctrl_write(phy_drd, + EXYNOS5_DRD_PHYSS_TX_VBOOSTLEVEL_OVRD_IN, + temp); + if (ret) { + dev_err(phy_drd->dev, + "Failed setting Tx-Vboost-Level for SuperSpeed\n"); + return ret; + } + + /* + * Set proper time to wait for RxDetect measurement, for + * desired reference clock of PHY, by tuning the CR_PORT + * register LANE0.TX_DEBUG which is internal to PHY. + * This fixes issue with few USB 3.0 devices, which are + * not detected (not even generate interrupts on the bus + * on insertion) without this change. + * e.g. Samsung SUM-TSB16S 3.0 USB drive. + */ + switch (phy_drd->extrefclk) { + case EXYNOS5_FSEL_50MHZ: + temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_48M_50M_52M; + break; + case EXYNOS5_FSEL_20MHZ: + case EXYNOS5_FSEL_19MHZ2: + temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_19M2_20M; + break; + case EXYNOS5_FSEL_24MHZ: + default: + temp = LANE0_TX_DEBUG_RXDET_MEAS_TIME_24M; + break; + } + + ret = crport_ctrl_write(phy_drd, + EXYNOS5_DRD_PHYSS_LANE0_TX_DEBUG, + temp); + if (ret) + dev_err(phy_drd->dev, + "Fail to set RxDet measurement time for SuperSpeed\n"); + + return ret; +} + static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -538,11 +712,20 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, return phy_drd->phys[args->args[0]].phy; } +static int exynos5_usbdrd_phy_calibrate(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + return exynos5420_usbdrd_phy_calibrate(phy_drd); +} + static const struct phy_ops exynos5_usbdrd_phy_ops = { .init = exynos5_usbdrd_phy_init, .exit = exynos5_usbdrd_phy_exit, .power_on = exynos5_usbdrd_phy_power_on, .power_off = exynos5_usbdrd_phy_power_off, + .calibrate = exynos5_usbdrd_phy_calibrate, .owner = THIS_MODULE, }; |