forked from luck/tmp_suning_uos_patched
phy: for 4.15
*) Add support in phy core to perform phy calibration *) Return NULL for optional PHY's even if CONFIG_GENERIC_PHY is not selected *) Add USB Phy driver for Broadcom STB SoCs *) Add support to force mediatek PHY with USB OTG function to enter a specific mode *) Calibrate rockchip-typec PHY according to docs *) Enable dual route feature for sun4i-usb in V3s SoC *) Use dr_mode dt property to enable otg capability in rcar-gen3-usb2 *) Add driver data to specify dedicated otg pins in rcar-gen3-usb2 driver *) Configure the RX equalizer of brcm-sata PHY *) Update pcie phy settings for ti-pipe3 phy *) Add set_mode callback in qcom-ufs-qmp-14nm phy *) Use PHY callbacks in phy-qcom-ufs instead of export APIs Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJZ8HRDAAoJEA5ceFyATYLZyFAP/R8kN02DtuvPTzXxgGYli1kC CNpFYBGwL4rq39C/zT7+8xBXamwCOpPWqQJ6M0HgkD3XX1Vg6htH0VdvND9nZsPk oSDenxPkDELyM6k5OqjGdWQCBEZdvoZqGHtuIsk4ZrZKVajvqBPAG2WI8tVBpiPL 27mwm/5QpXzXfNm1k8onXDqTpSBGmY1EcNvIgmon2Zl/qkWoKuNTpOv3w6JE/ktt YOxg9ScQCyw1LYx82hKF86aq0M9nQ5F+pN5o6c7oNFrotK5cE/Us3XTgKCVH+3sb wtbgHhDCCYeYShBr+msgPj8u8Jy596W6IcGFt2nuIm+ATL/qBZQyhSUtfzqPEf6k ShtJ05jTUHrM16jVDf+nDIkv9ENeSsUOoDJ7FKo4ht0miBE5fD3tmLcXP5NfOla6 PMJN4g+TF/5Ym6eB0mtlq41V5aBInbBr07wD+WFp4uNgdtBHVSRz0yRA2CNIZpww dhjoiAPjOeJlIeWMDJni7cvU6eAEV1hXRHB0+hPa0lQU3B7t4hZaROypzIwJd7Fu ZUetYfcKCmViRinr8O6Ym4DhMatlxPSLgD2R6VQhGYtThUEO57oLBPv5XMzAthwi PkigsXaO9fDCodECcNDO/PD0Zc6tUugRmiiD/UhVpSCQ+X1EsdYSrYBYtSwwMauC DqNvwPo3MExkMjFs68ZU =VvPn -----END PGP SIGNATURE----- Merge tag 'phy-for-4.15_v1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next Kishon writes: phy: for 4.15 *) Add support in phy core to perform phy calibration *) Return NULL for optional PHY's even if CONFIG_GENERIC_PHY is not selected *) Add USB Phy driver for Broadcom STB SoCs *) Add support to force mediatek PHY with USB OTG function to enter a specific mode *) Calibrate rockchip-typec PHY according to docs *) Enable dual route feature for sun4i-usb in V3s SoC *) Use dr_mode dt property to enable otg capability in rcar-gen3-usb2 *) Add driver data to specify dedicated otg pins in rcar-gen3-usb2 driver *) Configure the RX equalizer of brcm-sata PHY *) Update pcie phy settings for ti-pipe3 phy *) Add set_mode callback in qcom-ufs-qmp-14nm phy *) Use PHY callbacks in phy-qcom-ufs instead of export APIs Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
commit
6bd5bb1ede
|
@ -0,0 +1,43 @@
|
||||||
|
Broadcom STB USB PHY
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: brcm,brcmstb-usb-phy
|
||||||
|
- reg: two offset and length pairs.
|
||||||
|
The first pair specifies a manditory set of memory mapped
|
||||||
|
registers used for general control of the PHY.
|
||||||
|
The second pair specifies optional registers used by some of
|
||||||
|
the SoCs that support USB 3.x
|
||||||
|
- #phy-cells: Shall be 1 as it expects one argument for setting
|
||||||
|
the type of the PHY. Possible values are:
|
||||||
|
- PHY_TYPE_USB2 for USB1.1/2.0 PHY
|
||||||
|
- PHY_TYPE_USB3 for USB3.x PHY
|
||||||
|
|
||||||
|
Optional Properties:
|
||||||
|
- clocks : clock phandles.
|
||||||
|
- clock-names: String, clock name.
|
||||||
|
- brcm,ipp: Boolean, Invert Port Power.
|
||||||
|
Possible values are: 0 (Don't invert), 1 (Invert)
|
||||||
|
- brcm,ioc: Boolean, Invert Over Current detection.
|
||||||
|
Possible values are: 0 (Don't invert), 1 (Invert)
|
||||||
|
NOTE: one or both of the following two properties must be set
|
||||||
|
- brcm,has-xhci: Boolean indicating the phy has an XHCI phy.
|
||||||
|
- brcm,has-eohci: Boolean indicating the phy has an EHCI/OHCI phy.
|
||||||
|
- dr_mode: String, PHY Device mode.
|
||||||
|
Possible values are: "host", "peripheral ", "drd" or "typec-pd"
|
||||||
|
If this property is not defined, the phy will default to "host" mode.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
usbphy_0: usb-phy@f0470200 {
|
||||||
|
reg = <0xf0470200 0xb8>,
|
||||||
|
<0xf0471940 0x6c0>;
|
||||||
|
compatible = "brcm,brcmstb-usb-phy";
|
||||||
|
#phy-cells = <1>;
|
||||||
|
dr_mode = "host"
|
||||||
|
brcm,ioc = <1>;
|
||||||
|
brcm,ipp = <1>;
|
||||||
|
brcm,has-xhci;
|
||||||
|
brcm,has-eohci;
|
||||||
|
clocks = <&usb20>, <&usb30>;
|
||||||
|
clock-names = "sw_usb", "sw_usb3";
|
||||||
|
};
|
|
@ -27,7 +27,16 @@ Sub-nodes optional properties:
|
||||||
This property is not applicable for "brcm,iproc-ns2-sata-phy",
|
This property is not applicable for "brcm,iproc-ns2-sata-phy",
|
||||||
"brcm,iproc-nsp-sata-phy" and "brcm,iproc-sr-sata-phy".
|
"brcm,iproc-nsp-sata-phy" and "brcm,iproc-sr-sata-phy".
|
||||||
|
|
||||||
Example:
|
- brcm,rxaeq-mode: string that indicates the desired RX equalizer
|
||||||
|
mode, possible values are:
|
||||||
|
"off" (equivalent to not specifying the property)
|
||||||
|
"auto"
|
||||||
|
"manual" (brcm,rxaeq-value is used in that case)
|
||||||
|
|
||||||
|
- brcm,rxaeq-value: when 'rxaeq-mode' is set to "manual", provides the RX
|
||||||
|
equalizer value that should be used. Allowed range is 0..63.
|
||||||
|
|
||||||
|
Example
|
||||||
sata-phy@f0458100 {
|
sata-phy@f0458100 {
|
||||||
compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
|
compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
|
||||||
reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
|
reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
|
||||||
|
|
|
@ -4,10 +4,13 @@ This file provides information on what the device node for the R-Car generation
|
||||||
2 USB PHY contains.
|
2 USB PHY contains.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
|
- compatible: "renesas,usb-phy-r8a7743" if the device is a part of R8A7743 SoC.
|
||||||
|
"renesas,usb-phy-r8a7745" if the device is a part of R8A7745 SoC.
|
||||||
|
"renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
|
||||||
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
|
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
|
||||||
"renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
|
"renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
|
||||||
"renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 compatible device.
|
"renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 or
|
||||||
|
RZ/G1 compatible device.
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
SoC-specific version corresponding to the platform first
|
SoC-specific version corresponding to the platform first
|
||||||
|
|
|
@ -8,6 +8,8 @@ Required properties:
|
||||||
SoC.
|
SoC.
|
||||||
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
|
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
|
||||||
SoC.
|
SoC.
|
||||||
|
"renesas,usb2-phy-r8a77995" if the device is a part of an
|
||||||
|
R8A77995 SoC.
|
||||||
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
|
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
|
|
|
@ -2896,6 +2896,13 @@ S: Supported
|
||||||
F: drivers/gpio/gpio-brcmstb.c
|
F: drivers/gpio/gpio-brcmstb.c
|
||||||
F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
|
F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
|
||||||
|
|
||||||
|
BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
|
||||||
|
M: Al Cooper <alcooperx@gmail.com>
|
||||||
|
L: linux-kernel@vger.kernel.org
|
||||||
|
L: bcm-kernel-feedback-list@broadcom.com
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/phy/broadcom/phy-brcm-usb*
|
||||||
|
|
||||||
BROADCOM GENET ETHERNET DRIVER
|
BROADCOM GENET ETHERNET DRIVER
|
||||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/device.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
@ -594,6 +595,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||||
int i;
|
int i;
|
||||||
int phy_count;
|
int phy_count;
|
||||||
struct phy **phy;
|
struct phy **phy;
|
||||||
|
struct device_link **link;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct dw_pcie *pci;
|
struct dw_pcie *pci;
|
||||||
|
@ -649,11 +651,21 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||||
if (!phy)
|
if (!phy)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL);
|
||||||
|
if (!link)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < phy_count; i++) {
|
for (i = 0; i < phy_count; i++) {
|
||||||
snprintf(name, sizeof(name), "pcie-phy%d", i);
|
snprintf(name, sizeof(name), "pcie-phy%d", i);
|
||||||
phy[i] = devm_phy_get(dev, name);
|
phy[i] = devm_phy_get(dev, name);
|
||||||
if (IS_ERR(phy[i]))
|
if (IS_ERR(phy[i]))
|
||||||
return PTR_ERR(phy[i]);
|
return PTR_ERR(phy[i]);
|
||||||
|
|
||||||
|
link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
|
||||||
|
if (!link[i]) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err_link;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dra7xx->base = base;
|
dra7xx->base = base;
|
||||||
|
@ -732,6 +744,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
dra7xx_pcie_disable_phy(dra7xx);
|
dra7xx_pcie_disable_phy(dra7xx);
|
||||||
|
|
||||||
|
err_link:
|
||||||
|
while (--i >= 0)
|
||||||
|
device_link_del(link[i]);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -926,6 +926,7 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
|
||||||
.phyctl_offset = REG_PHYCTL_A33,
|
.phyctl_offset = REG_PHYCTL_A33,
|
||||||
.dedicated_clocks = true,
|
.dedicated_clocks = true,
|
||||||
.enable_pmu_unk1 = true,
|
.enable_pmu_unk1 = true,
|
||||||
|
.phy0_dual_route = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
|
static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
|
||||||
|
|
|
@ -67,3 +67,16 @@ config PHY_BRCM_SATA
|
||||||
help
|
help
|
||||||
Enable this to support the Broadcom SATA PHY.
|
Enable this to support the Broadcom SATA PHY.
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config PHY_BRCM_USB
|
||||||
|
tristate "Broadcom STB USB PHY driver"
|
||||||
|
depends on ARCH_BRCMSTB
|
||||||
|
depends on OF
|
||||||
|
select GENERIC_PHY
|
||||||
|
select SOC_BRCMSTB
|
||||||
|
default ARCH_BRCMSTB
|
||||||
|
help
|
||||||
|
Enable this to support the Broadcom STB USB PHY.
|
||||||
|
This driver is required by the USB XHCI, EHCI and OHCI
|
||||||
|
drivers.
|
||||||
|
If unsure, say N.
|
||||||
|
|
|
@ -5,3 +5,6 @@ obj-$(CONFIG_PHY_BCM_NS_USB3) += phy-bcm-ns-usb3.o
|
||||||
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
|
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
|
||||||
obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o
|
obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o
|
||||||
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
|
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
|
||||||
|
obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.o
|
||||||
|
|
||||||
|
phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o
|
||||||
|
|
|
@ -49,11 +49,29 @@ enum brcm_sata_phy_version {
|
||||||
BRCM_SATA_PHY_IPROC_SR,
|
BRCM_SATA_PHY_IPROC_SR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum brcm_sata_phy_rxaeq_mode {
|
||||||
|
RXAEQ_MODE_OFF = 0,
|
||||||
|
RXAEQ_MODE_AUTO,
|
||||||
|
RXAEQ_MODE_MANUAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum brcm_sata_phy_rxaeq_mode rxaeq_to_val(const char *m)
|
||||||
|
{
|
||||||
|
if (!strcmp(m, "auto"))
|
||||||
|
return RXAEQ_MODE_AUTO;
|
||||||
|
else if (!strcmp(m, "manual"))
|
||||||
|
return RXAEQ_MODE_MANUAL;
|
||||||
|
else
|
||||||
|
return RXAEQ_MODE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
struct brcm_sata_port {
|
struct brcm_sata_port {
|
||||||
int portnum;
|
int portnum;
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
struct brcm_sata_phy *phy_priv;
|
struct brcm_sata_phy *phy_priv;
|
||||||
bool ssc_en;
|
bool ssc_en;
|
||||||
|
enum brcm_sata_phy_rxaeq_mode rxaeq_mode;
|
||||||
|
u32 rxaeq_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct brcm_sata_phy {
|
struct brcm_sata_phy {
|
||||||
|
@ -93,6 +111,15 @@ enum sata_phy_regs {
|
||||||
TX_ACTRL0 = 0x80,
|
TX_ACTRL0 = 0x80,
|
||||||
TX_ACTRL0_TXPOL_FLIP = BIT(6),
|
TX_ACTRL0_TXPOL_FLIP = BIT(6),
|
||||||
|
|
||||||
|
AEQRX_REG_BANK_0 = 0xd0,
|
||||||
|
AEQ_CONTROL1 = 0x81,
|
||||||
|
AEQ_CONTROL1_ENABLE = BIT(2),
|
||||||
|
AEQ_CONTROL1_FREEZE = BIT(3),
|
||||||
|
AEQ_FRC_EQ = 0x83,
|
||||||
|
AEQ_FRC_EQ_FORCE = BIT(0),
|
||||||
|
AEQ_FRC_EQ_FORCE_VAL = BIT(1),
|
||||||
|
AEQRX_REG_BANK_1 = 0xe0,
|
||||||
|
|
||||||
OOB_REG_BANK = 0x150,
|
OOB_REG_BANK = 0x150,
|
||||||
OOB1_REG_BANK = 0x160,
|
OOB1_REG_BANK = 0x160,
|
||||||
OOB_CTRL1 = 0x80,
|
OOB_CTRL1 = 0x80,
|
||||||
|
@ -190,7 +217,7 @@ static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs)
|
||||||
#define STB_FMAX_VAL_DEFAULT 0x3df
|
#define STB_FMAX_VAL_DEFAULT 0x3df
|
||||||
#define STB_FMAX_VAL_SSC 0x83
|
#define STB_FMAX_VAL_SSC 0x83
|
||||||
|
|
||||||
static int brcm_stb_sata_init(struct brcm_sata_port *port)
|
static void brcm_stb_sata_ssc_init(struct brcm_sata_port *port)
|
||||||
{
|
{
|
||||||
void __iomem *base = brcm_sata_pcb_base(port);
|
void __iomem *base = brcm_sata_pcb_base(port);
|
||||||
struct brcm_sata_phy *priv = port->phy_priv;
|
struct brcm_sata_phy *priv = port->phy_priv;
|
||||||
|
@ -215,10 +242,47 @@ static int brcm_stb_sata_init(struct brcm_sata_port *port)
|
||||||
|
|
||||||
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
|
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
|
||||||
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
|
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AEQ_FRC_EQ_VAL_SHIFT 2
|
||||||
|
#define AEQ_FRC_EQ_VAL_MASK 0x3f
|
||||||
|
|
||||||
|
static int brcm_stb_sata_rxaeq_init(struct brcm_sata_port *port)
|
||||||
|
{
|
||||||
|
void __iomem *base = brcm_sata_pcb_base(port);
|
||||||
|
u32 tmp = 0, reg = 0;
|
||||||
|
|
||||||
|
switch (port->rxaeq_mode) {
|
||||||
|
case RXAEQ_MODE_OFF:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case RXAEQ_MODE_AUTO:
|
||||||
|
reg = AEQ_CONTROL1;
|
||||||
|
tmp = AEQ_CONTROL1_ENABLE | AEQ_CONTROL1_FREEZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RXAEQ_MODE_MANUAL:
|
||||||
|
reg = AEQ_FRC_EQ;
|
||||||
|
tmp = AEQ_FRC_EQ_FORCE | AEQ_FRC_EQ_FORCE_VAL;
|
||||||
|
if (port->rxaeq_val > AEQ_FRC_EQ_VAL_MASK)
|
||||||
|
return -EINVAL;
|
||||||
|
tmp |= port->rxaeq_val << AEQ_FRC_EQ_VAL_SHIFT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, AEQRX_REG_BANK_0, reg, ~tmp, tmp);
|
||||||
|
brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, reg, ~tmp, tmp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int brcm_stb_sata_init(struct brcm_sata_port *port)
|
||||||
|
{
|
||||||
|
brcm_stb_sata_ssc_init(port);
|
||||||
|
|
||||||
|
return brcm_stb_sata_rxaeq_init(port);
|
||||||
|
}
|
||||||
|
|
||||||
/* NS2 SATA PLL1 defaults were characterized by H/W group */
|
/* NS2 SATA PLL1 defaults were characterized by H/W group */
|
||||||
#define NS2_PLL1_ACTRL2_MAGIC 0x1df8
|
#define NS2_PLL1_ACTRL2_MAGIC 0x1df8
|
||||||
#define NS2_PLL1_ACTRL3_MAGIC 0x2b00
|
#define NS2_PLL1_ACTRL3_MAGIC 0x2b00
|
||||||
|
@ -463,6 +527,7 @@ MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
|
||||||
|
|
||||||
static int brcm_sata_phy_probe(struct platform_device *pdev)
|
static int brcm_sata_phy_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
const char *rxaeq_mode;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct device_node *dn = dev->of_node, *child;
|
struct device_node *dn = dev->of_node, *child;
|
||||||
const struct of_device_id *of_id;
|
const struct of_device_id *of_id;
|
||||||
|
@ -525,6 +590,13 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
|
||||||
port->portnum = id;
|
port->portnum = id;
|
||||||
port->phy_priv = priv;
|
port->phy_priv = priv;
|
||||||
port->phy = devm_phy_create(dev, child, &phy_ops);
|
port->phy = devm_phy_create(dev, child, &phy_ops);
|
||||||
|
port->rxaeq_mode = RXAEQ_MODE_OFF;
|
||||||
|
if (!of_property_read_string(child, "brcm,rxaeq-mode",
|
||||||
|
&rxaeq_mode))
|
||||||
|
port->rxaeq_mode = rxaeq_to_val(rxaeq_mode);
|
||||||
|
if (port->rxaeq_mode == RXAEQ_MODE_MANUAL)
|
||||||
|
of_property_read_u32(child, "brcm,rxaeq-value",
|
||||||
|
&port->rxaeq_val);
|
||||||
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
|
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
|
||||||
if (IS_ERR(port->phy)) {
|
if (IS_ERR(port->phy)) {
|
||||||
dev_err(dev, "failed to create PHY\n");
|
dev_err(dev, "failed to create PHY\n");
|
||||||
|
|
1017
drivers/phy/broadcom/phy-brcm-usb-init.c
Normal file
1017
drivers/phy/broadcom/phy-brcm-usb-init.c
Normal file
File diff suppressed because it is too large
Load Diff
50
drivers/phy/broadcom/phy-brcm-usb-init.h
Normal file
50
drivers/phy/broadcom/phy-brcm-usb-init.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2017 Broadcom
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _USB_BRCM_COMMON_INIT_H
|
||||||
|
#define _USB_BRCM_COMMON_INIT_H
|
||||||
|
|
||||||
|
#define USB_CTLR_MODE_HOST 0
|
||||||
|
#define USB_CTLR_MODE_DEVICE 1
|
||||||
|
#define USB_CTLR_MODE_DRD 2
|
||||||
|
#define USB_CTLR_MODE_TYPEC_PD 3
|
||||||
|
|
||||||
|
struct brcm_usb_init_params;
|
||||||
|
|
||||||
|
struct brcm_usb_init_params {
|
||||||
|
void __iomem *ctrl_regs;
|
||||||
|
void __iomem *xhci_ec_regs;
|
||||||
|
int ioc;
|
||||||
|
int ipp;
|
||||||
|
int mode;
|
||||||
|
u32 family_id;
|
||||||
|
u32 product_id;
|
||||||
|
int selected_family;
|
||||||
|
const char *family_name;
|
||||||
|
const u32 *usb_reg_bits_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
void brcm_usb_set_family_map(struct brcm_usb_init_params *params);
|
||||||
|
int brcm_usb_init_get_dual_select(struct brcm_usb_init_params *params);
|
||||||
|
void brcm_usb_init_set_dual_select(struct brcm_usb_init_params *params,
|
||||||
|
int mode);
|
||||||
|
|
||||||
|
void brcm_usb_init_ipp(struct brcm_usb_init_params *ini);
|
||||||
|
void brcm_usb_init_common(struct brcm_usb_init_params *ini);
|
||||||
|
void brcm_usb_init_eohci(struct brcm_usb_init_params *ini);
|
||||||
|
void brcm_usb_init_xhci(struct brcm_usb_init_params *ini);
|
||||||
|
void brcm_usb_uninit_common(struct brcm_usb_init_params *ini);
|
||||||
|
void brcm_usb_uninit_eohci(struct brcm_usb_init_params *ini);
|
||||||
|
void brcm_usb_uninit_xhci(struct brcm_usb_init_params *ini);
|
||||||
|
|
||||||
|
#endif /* _USB_BRCM_COMMON_INIT_H */
|
459
drivers/phy/broadcom/phy-brcm-usb.c
Normal file
459
drivers/phy/broadcom/phy-brcm-usb.c
Normal file
|
@ -0,0 +1,459 @@
|
||||||
|
/*
|
||||||
|
* phy-brcm-usb.c - Broadcom USB Phy Driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2017 Broadcom
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/soc/brcmstb/brcmstb.h>
|
||||||
|
#include <dt-bindings/phy/phy.h>
|
||||||
|
|
||||||
|
#include "phy-brcm-usb-init.h"
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(sysfs_lock);
|
||||||
|
|
||||||
|
enum brcm_usb_phy_id {
|
||||||
|
BRCM_USB_PHY_2_0 = 0,
|
||||||
|
BRCM_USB_PHY_3_0,
|
||||||
|
BRCM_USB_PHY_ID_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct value_to_name_map {
|
||||||
|
int value;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct value_to_name_map brcm_dr_mode_to_name[] = {
|
||||||
|
{ USB_CTLR_MODE_HOST, "host" },
|
||||||
|
{ USB_CTLR_MODE_DEVICE, "peripheral" },
|
||||||
|
{ USB_CTLR_MODE_DRD, "drd" },
|
||||||
|
{ USB_CTLR_MODE_TYPEC_PD, "typec-pd" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct value_to_name_map brcm_dual_mode_to_name[] = {
|
||||||
|
{ 0, "host" },
|
||||||
|
{ 1, "device" },
|
||||||
|
{ 2, "auto" },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct brcm_usb_phy {
|
||||||
|
struct phy *phy;
|
||||||
|
unsigned int id;
|
||||||
|
bool inited;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct brcm_usb_phy_data {
|
||||||
|
struct brcm_usb_init_params ini;
|
||||||
|
bool has_eohci;
|
||||||
|
bool has_xhci;
|
||||||
|
struct clk *usb_20_clk;
|
||||||
|
struct clk *usb_30_clk;
|
||||||
|
struct mutex mutex; /* serialize phy init */
|
||||||
|
int init_count;
|
||||||
|
struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
static int brcm_usb_phy_init(struct phy *gphy)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
|
||||||
|
struct brcm_usb_phy_data *priv =
|
||||||
|
container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use a lock to make sure a second caller waits until
|
||||||
|
* the base phy is inited before using it.
|
||||||
|
*/
|
||||||
|
mutex_lock(&priv->mutex);
|
||||||
|
if (priv->init_count++ == 0) {
|
||||||
|
clk_enable(priv->usb_20_clk);
|
||||||
|
clk_enable(priv->usb_30_clk);
|
||||||
|
brcm_usb_init_common(&priv->ini);
|
||||||
|
}
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
if (phy->id == BRCM_USB_PHY_2_0)
|
||||||
|
brcm_usb_init_eohci(&priv->ini);
|
||||||
|
else if (phy->id == BRCM_USB_PHY_3_0)
|
||||||
|
brcm_usb_init_xhci(&priv->ini);
|
||||||
|
phy->inited = true;
|
||||||
|
dev_dbg(&gphy->dev, "INIT, id: %d, total: %d\n", phy->id,
|
||||||
|
priv->init_count);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcm_usb_phy_exit(struct phy *gphy)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
|
||||||
|
struct brcm_usb_phy_data *priv =
|
||||||
|
container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
|
||||||
|
|
||||||
|
dev_dbg(&gphy->dev, "EXIT\n");
|
||||||
|
if (phy->id == BRCM_USB_PHY_2_0)
|
||||||
|
brcm_usb_uninit_eohci(&priv->ini);
|
||||||
|
if (phy->id == BRCM_USB_PHY_3_0)
|
||||||
|
brcm_usb_uninit_xhci(&priv->ini);
|
||||||
|
|
||||||
|
/* If both xhci and eohci are gone, reset everything else */
|
||||||
|
mutex_lock(&priv->mutex);
|
||||||
|
if (--priv->init_count == 0) {
|
||||||
|
brcm_usb_uninit_common(&priv->ini);
|
||||||
|
clk_disable(priv->usb_20_clk);
|
||||||
|
clk_disable(priv->usb_30_clk);
|
||||||
|
}
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
phy->inited = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct phy_ops brcm_usb_phy_ops = {
|
||||||
|
.init = brcm_usb_phy_init,
|
||||||
|
.exit = brcm_usb_phy_exit,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct phy *brcm_usb_phy_xlate(struct device *dev,
|
||||||
|
struct of_phandle_args *args)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* values 0 and 1 are for backward compatibility with
|
||||||
|
* device tree nodes from older bootloaders.
|
||||||
|
*/
|
||||||
|
switch (args->args[0]) {
|
||||||
|
case 0:
|
||||||
|
case PHY_TYPE_USB2:
|
||||||
|
if (data->phys[BRCM_USB_PHY_2_0].phy)
|
||||||
|
return data->phys[BRCM_USB_PHY_2_0].phy;
|
||||||
|
dev_warn(dev, "Error, 2.0 Phy not found\n");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case PHY_TYPE_USB3:
|
||||||
|
if (data->phys[BRCM_USB_PHY_3_0].phy)
|
||||||
|
return data->phys[BRCM_USB_PHY_3_0].phy;
|
||||||
|
dev_warn(dev, "Error, 3.0 Phy not found\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int name_to_value(struct value_to_name_map *table, int count,
|
||||||
|
const char *name, int *value)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
*value = 0;
|
||||||
|
for (x = 0; x < count; x++) {
|
||||||
|
if (sysfs_streq(name, table[x].name)) {
|
||||||
|
*value = x;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *value_to_name(struct value_to_name_map *table, int count,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
if (value >= count)
|
||||||
|
return "unknown";
|
||||||
|
return table[value].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t dr_mode_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n",
|
||||||
|
value_to_name(&brcm_dr_mode_to_name[0],
|
||||||
|
ARRAY_SIZE(brcm_dr_mode_to_name),
|
||||||
|
priv->ini.mode));
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(dr_mode);
|
||||||
|
|
||||||
|
static ssize_t dual_select_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
|
||||||
|
int value;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
mutex_lock(&sysfs_lock);
|
||||||
|
res = name_to_value(&brcm_dual_mode_to_name[0],
|
||||||
|
ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value);
|
||||||
|
if (!res) {
|
||||||
|
brcm_usb_init_set_dual_select(&priv->ini, value);
|
||||||
|
res = len;
|
||||||
|
}
|
||||||
|
mutex_unlock(&sysfs_lock);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t dual_select_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
|
||||||
|
int value;
|
||||||
|
|
||||||
|
mutex_lock(&sysfs_lock);
|
||||||
|
value = brcm_usb_init_get_dual_select(&priv->ini);
|
||||||
|
mutex_unlock(&sysfs_lock);
|
||||||
|
return sprintf(buf, "%s\n",
|
||||||
|
value_to_name(&brcm_dual_mode_to_name[0],
|
||||||
|
ARRAY_SIZE(brcm_dual_mode_to_name),
|
||||||
|
value));
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RW(dual_select);
|
||||||
|
|
||||||
|
static struct attribute *brcm_usb_phy_attrs[] = {
|
||||||
|
&dev_attr_dr_mode.attr,
|
||||||
|
&dev_attr_dual_select.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group brcm_usb_phy_group = {
|
||||||
|
.attrs = brcm_usb_phy_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int brcm_usb_phy_dvr_init(struct device *dev,
|
||||||
|
struct brcm_usb_phy_data *priv,
|
||||||
|
struct device_node *dn)
|
||||||
|
{
|
||||||
|
struct phy *gphy;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb");
|
||||||
|
if (IS_ERR(priv->usb_20_clk)) {
|
||||||
|
dev_info(dev, "Clock not found in Device Tree\n");
|
||||||
|
priv->usb_20_clk = NULL;
|
||||||
|
}
|
||||||
|
err = clk_prepare_enable(priv->usb_20_clk);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (priv->has_eohci) {
|
||||||
|
gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
|
||||||
|
if (IS_ERR(gphy)) {
|
||||||
|
dev_err(dev, "failed to create EHCI/OHCI PHY\n");
|
||||||
|
return PTR_ERR(gphy);
|
||||||
|
}
|
||||||
|
priv->phys[BRCM_USB_PHY_2_0].phy = gphy;
|
||||||
|
priv->phys[BRCM_USB_PHY_2_0].id = BRCM_USB_PHY_2_0;
|
||||||
|
phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_2_0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->has_xhci) {
|
||||||
|
gphy = devm_phy_create(dev, NULL, &brcm_usb_phy_ops);
|
||||||
|
if (IS_ERR(gphy)) {
|
||||||
|
dev_err(dev, "failed to create XHCI PHY\n");
|
||||||
|
return PTR_ERR(gphy);
|
||||||
|
}
|
||||||
|
priv->phys[BRCM_USB_PHY_3_0].phy = gphy;
|
||||||
|
priv->phys[BRCM_USB_PHY_3_0].id = BRCM_USB_PHY_3_0;
|
||||||
|
phy_set_drvdata(gphy, &priv->phys[BRCM_USB_PHY_3_0]);
|
||||||
|
|
||||||
|
priv->usb_30_clk = of_clk_get_by_name(dn, "sw_usb3");
|
||||||
|
if (IS_ERR(priv->usb_30_clk)) {
|
||||||
|
dev_info(dev,
|
||||||
|
"USB3.0 clock not found in Device Tree\n");
|
||||||
|
priv->usb_30_clk = NULL;
|
||||||
|
}
|
||||||
|
err = clk_prepare_enable(priv->usb_30_clk);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcm_usb_phy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct brcm_usb_phy_data *priv;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct device_node *dn = pdev->dev.of_node;
|
||||||
|
int err;
|
||||||
|
const char *mode;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
priv->ini.family_id = brcmstb_get_family_id();
|
||||||
|
priv->ini.product_id = brcmstb_get_product_id();
|
||||||
|
brcm_usb_set_family_map(&priv->ini);
|
||||||
|
dev_dbg(dev, "Best mapping table is for %s\n",
|
||||||
|
priv->ini.family_name);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res) {
|
||||||
|
dev_err(dev, "can't get USB_CTRL base address\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
priv->ini.ctrl_regs = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(priv->ini.ctrl_regs)) {
|
||||||
|
dev_err(dev, "can't map CTRL register space\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The XHCI EC registers are optional */
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||||
|
if (res) {
|
||||||
|
priv->ini.xhci_ec_regs =
|
||||||
|
devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(priv->ini.xhci_ec_regs)) {
|
||||||
|
dev_err(dev, "can't map XHCI EC register space\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp);
|
||||||
|
of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc);
|
||||||
|
|
||||||
|
priv->ini.mode = USB_CTLR_MODE_HOST;
|
||||||
|
err = of_property_read_string(dn, "dr_mode", &mode);
|
||||||
|
if (err == 0) {
|
||||||
|
name_to_value(&brcm_dr_mode_to_name[0],
|
||||||
|
ARRAY_SIZE(brcm_dr_mode_to_name),
|
||||||
|
mode, &priv->ini.mode);
|
||||||
|
}
|
||||||
|
if (of_property_read_bool(dn, "brcm,has_xhci"))
|
||||||
|
priv->has_xhci = true;
|
||||||
|
if (of_property_read_bool(dn, "brcm,has_eohci"))
|
||||||
|
priv->has_eohci = true;
|
||||||
|
|
||||||
|
err = brcm_usb_phy_dvr_init(dev, priv, dn);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
mutex_init(&priv->mutex);
|
||||||
|
|
||||||
|
/* make sure invert settings are correct */
|
||||||
|
brcm_usb_init_ipp(&priv->ini);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create sysfs entries for mode.
|
||||||
|
* Remove "dual_select" attribute if not in dual mode
|
||||||
|
*/
|
||||||
|
if (priv->ini.mode != USB_CTLR_MODE_DRD)
|
||||||
|
brcm_usb_phy_attrs[1] = NULL;
|
||||||
|
err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group);
|
||||||
|
if (err)
|
||||||
|
dev_warn(dev, "Error creating sysfs attributes\n");
|
||||||
|
|
||||||
|
/* start with everything off */
|
||||||
|
if (priv->has_xhci)
|
||||||
|
brcm_usb_uninit_xhci(&priv->ini);
|
||||||
|
if (priv->has_eohci)
|
||||||
|
brcm_usb_uninit_eohci(&priv->ini);
|
||||||
|
brcm_usb_uninit_common(&priv->ini);
|
||||||
|
clk_disable(priv->usb_20_clk);
|
||||||
|
clk_disable(priv->usb_30_clk);
|
||||||
|
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
|
||||||
|
if (IS_ERR(phy_provider))
|
||||||
|
return PTR_ERR(phy_provider);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int brcm_usb_phy_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (priv->init_count) {
|
||||||
|
clk_disable(priv->usb_20_clk);
|
||||||
|
clk_disable(priv->usb_30_clk);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcm_usb_phy_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
clk_enable(priv->usb_20_clk);
|
||||||
|
clk_enable(priv->usb_30_clk);
|
||||||
|
brcm_usb_init_ipp(&priv->ini);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize anything that was previously initialized.
|
||||||
|
* Uninitialize anything that wasn't previously initialized.
|
||||||
|
*/
|
||||||
|
if (priv->init_count) {
|
||||||
|
brcm_usb_init_common(&priv->ini);
|
||||||
|
if (priv->phys[BRCM_USB_PHY_2_0].inited) {
|
||||||
|
brcm_usb_init_eohci(&priv->ini);
|
||||||
|
} else if (priv->has_eohci) {
|
||||||
|
brcm_usb_uninit_eohci(&priv->ini);
|
||||||
|
clk_disable(priv->usb_20_clk);
|
||||||
|
}
|
||||||
|
if (priv->phys[BRCM_USB_PHY_3_0].inited) {
|
||||||
|
brcm_usb_init_xhci(&priv->ini);
|
||||||
|
} else if (priv->has_xhci) {
|
||||||
|
brcm_usb_uninit_xhci(&priv->ini);
|
||||||
|
clk_disable(priv->usb_30_clk);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (priv->has_xhci)
|
||||||
|
brcm_usb_uninit_xhci(&priv->ini);
|
||||||
|
if (priv->has_eohci)
|
||||||
|
brcm_usb_uninit_eohci(&priv->ini);
|
||||||
|
brcm_usb_uninit_common(&priv->ini);
|
||||||
|
clk_disable(priv->usb_20_clk);
|
||||||
|
clk_disable(priv->usb_30_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
|
static const struct dev_pm_ops brcm_usb_phy_pm_ops = {
|
||||||
|
SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id brcm_usb_dt_ids[] = {
|
||||||
|
{ .compatible = "brcm,brcmstb-usb-phy" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
|
||||||
|
|
||||||
|
static struct platform_driver brcm_usb_driver = {
|
||||||
|
.probe = brcm_usb_phy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "brcmstb-usb-phy",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.pm = &brcm_usb_phy_pm_ops,
|
||||||
|
.of_match_table = brcm_usb_dt_ids,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(brcm_usb_driver);
|
||||||
|
|
||||||
|
MODULE_ALIAS("platform:brcmstb-usb-phy");
|
||||||
|
MODULE_AUTHOR("Al Cooper <acooper@broadcom.com>");
|
||||||
|
MODULE_DESCRIPTION("BRCM USB PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -154,7 +154,6 @@ struct mvebu_comphy_priv {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
int modes[MVEBU_COMPHY_LANES];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mvebu_comphy_lane {
|
struct mvebu_comphy_lane {
|
||||||
|
|
|
@ -96,9 +96,11 @@
|
||||||
|
|
||||||
#define U3P_U2PHYDTM1 0x06C
|
#define U3P_U2PHYDTM1 0x06C
|
||||||
#define P2C_RG_UART_EN BIT(16)
|
#define P2C_RG_UART_EN BIT(16)
|
||||||
|
#define P2C_FORCE_IDDIG BIT(9)
|
||||||
#define P2C_RG_VBUSVALID BIT(5)
|
#define P2C_RG_VBUSVALID BIT(5)
|
||||||
#define P2C_RG_SESSEND BIT(4)
|
#define P2C_RG_SESSEND BIT(4)
|
||||||
#define P2C_RG_AVALID BIT(2)
|
#define P2C_RG_AVALID BIT(2)
|
||||||
|
#define P2C_RG_IDDIG BIT(1)
|
||||||
|
|
||||||
#define U3P_U3_CHIP_GPIO_CTLD 0x0c
|
#define U3P_U3_CHIP_GPIO_CTLD 0x0c
|
||||||
#define P3C_REG_IP_SW_RST BIT(31)
|
#define P3C_REG_IP_SW_RST BIT(31)
|
||||||
|
@ -585,6 +587,31 @@ static void u2_phy_instance_exit(struct mtk_tphy *tphy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void u2_phy_instance_set_mode(struct mtk_tphy *tphy,
|
||||||
|
struct mtk_phy_instance *instance,
|
||||||
|
enum phy_mode mode)
|
||||||
|
{
|
||||||
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
tmp = readl(u2_banks->com + U3P_U2PHYDTM1);
|
||||||
|
switch (mode) {
|
||||||
|
case PHY_MODE_USB_DEVICE:
|
||||||
|
tmp |= P2C_FORCE_IDDIG | P2C_RG_IDDIG;
|
||||||
|
break;
|
||||||
|
case PHY_MODE_USB_HOST:
|
||||||
|
tmp |= P2C_FORCE_IDDIG;
|
||||||
|
tmp &= ~P2C_RG_IDDIG;
|
||||||
|
break;
|
||||||
|
case PHY_MODE_USB_OTG:
|
||||||
|
tmp &= ~(P2C_FORCE_IDDIG | P2C_RG_IDDIG);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writel(tmp, u2_banks->com + U3P_U2PHYDTM1);
|
||||||
|
}
|
||||||
|
|
||||||
static void pcie_phy_instance_init(struct mtk_tphy *tphy,
|
static void pcie_phy_instance_init(struct mtk_tphy *tphy,
|
||||||
struct mtk_phy_instance *instance)
|
struct mtk_phy_instance *instance)
|
||||||
{
|
{
|
||||||
|
@ -881,6 +908,17 @@ static int mtk_phy_exit(struct phy *phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||||
|
{
|
||||||
|
struct mtk_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
|
struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
|
||||||
|
if (instance->type == PHY_TYPE_USB2)
|
||||||
|
u2_phy_instance_set_mode(tphy, instance, mode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct phy *mtk_phy_xlate(struct device *dev,
|
static struct phy *mtk_phy_xlate(struct device *dev,
|
||||||
struct of_phandle_args *args)
|
struct of_phandle_args *args)
|
||||||
{
|
{
|
||||||
|
@ -931,6 +969,7 @@ static const struct phy_ops mtk_tphy_ops = {
|
||||||
.exit = mtk_phy_exit,
|
.exit = mtk_phy_exit,
|
||||||
.power_on = mtk_phy_power_on,
|
.power_on = mtk_phy_power_on,
|
||||||
.power_off = mtk_phy_power_off,
|
.power_off = mtk_phy_power_off,
|
||||||
|
.set_mode = mtk_phy_set_mode,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -372,6 +372,21 @@ int phy_reset(struct phy *phy)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(phy_reset);
|
EXPORT_SYMBOL_GPL(phy_reset);
|
||||||
|
|
||||||
|
int phy_calibrate(struct phy *phy)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!phy || !phy->ops->calibrate)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mutex_lock(&phy->mutex);
|
||||||
|
ret = phy->ops->calibrate(phy);
|
||||||
|
mutex_unlock(&phy->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(phy_calibrate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _of_phy_get() - lookup and obtain a reference to a phy by phandle
|
* _of_phy_get() - lookup and obtain a reference to a phy by phandle
|
||||||
* @np: device_node for which to get the phy
|
* @np: device_node for which to get the phy
|
||||||
|
|
|
@ -114,14 +114,16 @@ struct ufs_qcom_phy {
|
||||||
struct ufs_qcom_phy_calibration *cached_regs;
|
struct ufs_qcom_phy_calibration *cached_regs;
|
||||||
int cached_regs_table_size;
|
int cached_regs_table_size;
|
||||||
bool is_powered_on;
|
bool is_powered_on;
|
||||||
|
bool is_started;
|
||||||
struct ufs_qcom_phy_specific_ops *phy_spec_ops;
|
struct ufs_qcom_phy_specific_ops *phy_spec_ops;
|
||||||
|
|
||||||
|
enum phy_mode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a
|
* struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a
|
||||||
* specific implementation per phy. Each UFS phy, should implement
|
* specific implementation per phy. Each UFS phy, should implement
|
||||||
* those functions according to its spec and requirements
|
* those functions according to its spec and requirements
|
||||||
* @calibrate_phy: pointer to a function that calibrate the phy
|
|
||||||
* @start_serdes: pointer to a function that starts the serdes
|
* @start_serdes: pointer to a function that starts the serdes
|
||||||
* @is_physical_coding_sublayer_ready: pointer to a function that
|
* @is_physical_coding_sublayer_ready: pointer to a function that
|
||||||
* checks pcs readiness. returns 0 for success and non-zero for error.
|
* checks pcs readiness. returns 0 for success and non-zero for error.
|
||||||
|
@ -130,7 +132,6 @@ struct ufs_qcom_phy {
|
||||||
* and writes to QSERDES_RX_SIGDET_CNTRL attribute
|
* and writes to QSERDES_RX_SIGDET_CNTRL attribute
|
||||||
*/
|
*/
|
||||||
struct ufs_qcom_phy_specific_ops {
|
struct ufs_qcom_phy_specific_ops {
|
||||||
int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
|
|
||||||
void (*start_serdes)(struct ufs_qcom_phy *phy);
|
void (*start_serdes)(struct ufs_qcom_phy *phy);
|
||||||
int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
|
int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
|
||||||
void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
|
void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
|
||||||
|
|
|
@ -44,7 +44,19 @@ void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
|
||||||
|
|
||||||
static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
|
static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
|
||||||
{
|
{
|
||||||
return 0;
|
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
|
||||||
|
bool is_rate_B = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (phy_common->mode == PHY_MODE_UFS_HS_B)
|
||||||
|
is_rate_B = true;
|
||||||
|
|
||||||
|
ret = ufs_qcom_phy_qmp_14nm_phy_calibrate(phy_common, is_rate_B);
|
||||||
|
if (!ret)
|
||||||
|
/* phy calibrated, but yet to be started */
|
||||||
|
phy_common->is_started = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
|
static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
|
||||||
|
@ -52,6 +64,19 @@ static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy, enum phy_mode mode)
|
||||||
|
{
|
||||||
|
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
|
||||||
|
|
||||||
|
phy_common->mode = PHY_MODE_INVALID;
|
||||||
|
|
||||||
|
if (mode > 0)
|
||||||
|
phy_common->mode = mode;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, bool val)
|
void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, bool val)
|
||||||
{
|
{
|
||||||
|
@ -102,11 +127,11 @@ static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
|
||||||
.exit = ufs_qcom_phy_qmp_14nm_exit,
|
.exit = ufs_qcom_phy_qmp_14nm_exit,
|
||||||
.power_on = ufs_qcom_phy_power_on,
|
.power_on = ufs_qcom_phy_power_on,
|
||||||
.power_off = ufs_qcom_phy_power_off,
|
.power_off = ufs_qcom_phy_power_off,
|
||||||
|
.set_mode = ufs_qcom_phy_qmp_14nm_set_mode,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
|
static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
|
||||||
.calibrate_phy = ufs_qcom_phy_qmp_14nm_phy_calibrate,
|
|
||||||
.start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes,
|
.start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes,
|
||||||
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
|
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
|
||||||
.set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
|
.set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
|
||||||
|
|
|
@ -63,7 +63,19 @@ void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
|
||||||
|
|
||||||
static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy)
|
static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy)
|
||||||
{
|
{
|
||||||
return 0;
|
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
|
||||||
|
bool is_rate_B = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (phy_common->mode == PHY_MODE_UFS_HS_B)
|
||||||
|
is_rate_B = true;
|
||||||
|
|
||||||
|
ret = ufs_qcom_phy_qmp_20nm_phy_calibrate(phy_common, is_rate_B);
|
||||||
|
if (!ret)
|
||||||
|
/* phy calibrated, but yet to be started */
|
||||||
|
phy_common->is_started = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
|
static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
|
||||||
|
@ -71,6 +83,19 @@ static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy, enum phy_mode mode)
|
||||||
|
{
|
||||||
|
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
|
||||||
|
|
||||||
|
phy_common->mode = PHY_MODE_INVALID;
|
||||||
|
|
||||||
|
if (mode > 0)
|
||||||
|
phy_common->mode = mode;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, bool val)
|
void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, bool val)
|
||||||
{
|
{
|
||||||
|
@ -160,11 +185,11 @@ static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
|
||||||
.exit = ufs_qcom_phy_qmp_20nm_exit,
|
.exit = ufs_qcom_phy_qmp_20nm_exit,
|
||||||
.power_on = ufs_qcom_phy_power_on,
|
.power_on = ufs_qcom_phy_power_on,
|
||||||
.power_off = ufs_qcom_phy_power_off,
|
.power_off = ufs_qcom_phy_power_off,
|
||||||
|
.set_mode = ufs_qcom_phy_qmp_20nm_set_mode,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
|
static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
|
||||||
.calibrate_phy = ufs_qcom_phy_qmp_20nm_phy_calibrate,
|
|
||||||
.start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes,
|
.start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes,
|
||||||
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,
|
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,
|
||||||
.set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
|
.set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
|
||||||
|
|
|
@ -518,9 +518,8 @@ void ufs_qcom_phy_disable_iface_clk(struct ufs_qcom_phy *phy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
|
static int ufs_qcom_phy_start_serdes(struct ufs_qcom_phy *ufs_qcom_phy)
|
||||||
{
|
{
|
||||||
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!ufs_qcom_phy->phy_spec_ops->start_serdes) {
|
if (!ufs_qcom_phy->phy_spec_ops->start_serdes) {
|
||||||
|
@ -533,7 +532,6 @@ int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_start_serdes);
|
|
||||||
|
|
||||||
int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
|
int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
|
||||||
{
|
{
|
||||||
|
@ -564,31 +562,8 @@ void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_save_controller_version);
|
EXPORT_SYMBOL_GPL(ufs_qcom_phy_save_controller_version);
|
||||||
|
|
||||||
int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B)
|
static int ufs_qcom_phy_is_pcs_ready(struct ufs_qcom_phy *ufs_qcom_phy)
|
||||||
{
|
{
|
||||||
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!ufs_qcom_phy->phy_spec_ops->calibrate_phy) {
|
|
||||||
dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() callback is not supported\n",
|
|
||||||
__func__);
|
|
||||||
ret = -ENOTSUPP;
|
|
||||||
} else {
|
|
||||||
ret = ufs_qcom_phy->phy_spec_ops->
|
|
||||||
calibrate_phy(ufs_qcom_phy, is_rate_B);
|
|
||||||
if (ret)
|
|
||||||
dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() failed %d\n",
|
|
||||||
__func__, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate_phy);
|
|
||||||
|
|
||||||
int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
|
|
||||||
{
|
|
||||||
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
|
|
||||||
|
|
||||||
if (!ufs_qcom_phy->phy_spec_ops->is_physical_coding_sublayer_ready) {
|
if (!ufs_qcom_phy->phy_spec_ops->is_physical_coding_sublayer_ready) {
|
||||||
dev_err(ufs_qcom_phy->dev, "%s: is_physical_coding_sublayer_ready() callback is not supported\n",
|
dev_err(ufs_qcom_phy->dev, "%s: is_physical_coding_sublayer_ready() callback is not supported\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
@ -598,7 +573,6 @@ int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
|
||||||
return ufs_qcom_phy->phy_spec_ops->
|
return ufs_qcom_phy->phy_spec_ops->
|
||||||
is_physical_coding_sublayer_ready(ufs_qcom_phy);
|
is_physical_coding_sublayer_ready(ufs_qcom_phy);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_is_pcs_ready);
|
|
||||||
|
|
||||||
int ufs_qcom_phy_power_on(struct phy *generic_phy)
|
int ufs_qcom_phy_power_on(struct phy *generic_phy)
|
||||||
{
|
{
|
||||||
|
@ -609,6 +583,18 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
|
||||||
if (phy_common->is_powered_on)
|
if (phy_common->is_powered_on)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!phy_common->is_started) {
|
||||||
|
err = ufs_qcom_phy_start_serdes(phy_common);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = ufs_qcom_phy_is_pcs_ready(phy_common);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
phy_common->is_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy);
|
err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
|
dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Renesas R-Car Gen3 for USB2.0 PHY driver
|
* Renesas R-Car Gen3 for USB2.0 PHY driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Renesas Electronics Corporation
|
* Copyright (C) 2015-2017 Renesas Electronics Corporation
|
||||||
*
|
*
|
||||||
* This is based on the phy-rcar-gen2 driver:
|
* This is based on the phy-rcar-gen2 driver:
|
||||||
* Copyright (C) 2014 Renesas Solutions Corp.
|
* Copyright (C) 2014 Renesas Solutions Corp.
|
||||||
|
@ -18,10 +18,12 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/usb/of.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
/******* USB2.0 Host registers (original offset is +0x200) *******/
|
/******* USB2.0 Host registers (original offset is +0x200) *******/
|
||||||
|
@ -79,6 +81,8 @@
|
||||||
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
|
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
|
||||||
#define USB2_ADPCTRL_DRVVBUS BIT(4)
|
#define USB2_ADPCTRL_DRVVBUS BIT(4)
|
||||||
|
|
||||||
|
#define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1
|
||||||
|
|
||||||
struct rcar_gen3_chan {
|
struct rcar_gen3_chan {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct extcon_dev *extcon;
|
struct extcon_dev *extcon;
|
||||||
|
@ -86,7 +90,7 @@ struct rcar_gen3_chan {
|
||||||
struct regulator *vbus;
|
struct regulator *vbus;
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
bool extcon_host;
|
bool extcon_host;
|
||||||
bool has_otg;
|
bool has_otg_pins;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
|
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
|
||||||
|
@ -218,33 +222,40 @@ static bool rcar_gen3_is_host(struct rcar_gen3_chan *ch)
|
||||||
return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI);
|
return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum phy_mode rcar_gen3_get_phy_mode(struct rcar_gen3_chan *ch)
|
||||||
|
{
|
||||||
|
if (rcar_gen3_is_host(ch))
|
||||||
|
return PHY_MODE_USB_HOST;
|
||||||
|
|
||||||
|
return PHY_MODE_USB_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
||||||
bool is_b_device, is_host, new_mode_is_host;
|
bool is_b_device;
|
||||||
|
enum phy_mode cur_mode, new_mode;
|
||||||
|
|
||||||
if (!ch->has_otg || !ch->phy->init_count)
|
if (!ch->has_otg_pins || !ch->phy->init_count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
/*
|
|
||||||
* is_b_device: true is B-Device. false is A-Device.
|
|
||||||
* If {new_mode_}is_host: true is Host mode. false is Peripheral mode.
|
|
||||||
*/
|
|
||||||
is_b_device = rcar_gen3_check_id(ch);
|
|
||||||
is_host = rcar_gen3_is_host(ch);
|
|
||||||
if (!strncmp(buf, "host", strlen("host")))
|
if (!strncmp(buf, "host", strlen("host")))
|
||||||
new_mode_is_host = true;
|
new_mode = PHY_MODE_USB_HOST;
|
||||||
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
|
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
|
||||||
new_mode_is_host = false;
|
new_mode = PHY_MODE_USB_DEVICE;
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* is_b_device: true is B-Device. false is A-Device. */
|
||||||
|
is_b_device = rcar_gen3_check_id(ch);
|
||||||
|
cur_mode = rcar_gen3_get_phy_mode(ch);
|
||||||
|
|
||||||
/* If current and new mode is the same, this returns the error */
|
/* If current and new mode is the same, this returns the error */
|
||||||
if (is_host == new_mode_is_host)
|
if (cur_mode == new_mode)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (new_mode_is_host) { /* And is_host must be false */
|
if (new_mode == PHY_MODE_USB_HOST) { /* And is_host must be false */
|
||||||
if (!is_b_device) /* A-Peripheral */
|
if (!is_b_device) /* A-Peripheral */
|
||||||
rcar_gen3_init_from_a_peri_to_a_host(ch);
|
rcar_gen3_init_from_a_peri_to_a_host(ch);
|
||||||
else /* B-Peripheral */
|
else /* B-Peripheral */
|
||||||
|
@ -264,7 +275,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (!ch->has_otg || !ch->phy->init_count)
|
if (!ch->has_otg_pins || !ch->phy->init_count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
|
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
|
||||||
|
@ -303,7 +314,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
|
||||||
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
|
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
|
||||||
|
|
||||||
/* Initialize otg part */
|
/* Initialize otg part */
|
||||||
if (channel->has_otg)
|
if (channel->has_otg_pins)
|
||||||
rcar_gen3_init_otg(channel);
|
rcar_gen3_init_otg(channel);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -377,9 +388,17 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
|
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
|
||||||
{ .compatible = "renesas,usb2-phy-r8a7795" },
|
{
|
||||||
{ .compatible = "renesas,usb2-phy-r8a7796" },
|
.compatible = "renesas,usb2-phy-r8a7795",
|
||||||
{ .compatible = "renesas,rcar-gen3-usb2-phy" },
|
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "renesas,usb2-phy-r8a7796",
|
||||||
|
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "renesas,rcar-gen3-usb2-phy",
|
||||||
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
|
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
|
||||||
|
@ -415,14 +434,17 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||||
/* call request_irq for OTG */
|
/* call request_irq for OTG */
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
if (irq >= 0) {
|
if (irq >= 0) {
|
||||||
int ret;
|
|
||||||
|
|
||||||
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
|
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
|
||||||
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
|
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
|
||||||
IRQF_SHARED, dev_name(dev), channel);
|
IRQF_SHARED, dev_name(dev), channel);
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
dev_err(dev, "No irq handler (%d)\n", irq);
|
dev_err(dev, "No irq handler (%d)\n", irq);
|
||||||
channel->has_otg = true;
|
}
|
||||||
|
|
||||||
|
if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev);
|
||||||
channel->extcon = devm_extcon_dev_allocate(dev,
|
channel->extcon = devm_extcon_dev_allocate(dev,
|
||||||
rcar_gen3_phy_cable);
|
rcar_gen3_phy_cable);
|
||||||
if (IS_ERR(channel->extcon))
|
if (IS_ERR(channel->extcon))
|
||||||
|
@ -464,7 +486,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||||
dev_err(dev, "Failed to register PHY provider\n");
|
dev_err(dev, "Failed to register PHY provider\n");
|
||||||
ret = PTR_ERR(provider);
|
ret = PTR_ERR(provider);
|
||||||
goto error;
|
goto error;
|
||||||
} else if (channel->has_otg) {
|
} else if (channel->has_otg_pins) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = device_create_file(dev, &dev_attr_role);
|
ret = device_create_file(dev, &dev_attr_role);
|
||||||
|
@ -484,7 +506,7 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
|
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
if (channel->has_otg)
|
if (channel->has_otg_pins)
|
||||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
|
@ -102,9 +102,40 @@
|
||||||
#define CMN_PLL1_SS_CTRL1 (0xb8 << 2)
|
#define CMN_PLL1_SS_CTRL1 (0xb8 << 2)
|
||||||
#define CMN_PLL1_SS_CTRL2 (0xb9 << 2)
|
#define CMN_PLL1_SS_CTRL2 (0xb9 << 2)
|
||||||
#define CMN_RXCAL_OVRD (0xd1 << 2)
|
#define CMN_RXCAL_OVRD (0xd1 << 2)
|
||||||
|
|
||||||
#define CMN_TXPUCAL_CTRL (0xe0 << 2)
|
#define CMN_TXPUCAL_CTRL (0xe0 << 2)
|
||||||
#define CMN_TXPUCAL_OVRD (0xe1 << 2)
|
#define CMN_TXPUCAL_OVRD (0xe1 << 2)
|
||||||
|
#define CMN_TXPDCAL_CTRL (0xf0 << 2)
|
||||||
#define CMN_TXPDCAL_OVRD (0xf1 << 2)
|
#define CMN_TXPDCAL_OVRD (0xf1 << 2)
|
||||||
|
|
||||||
|
/* For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL */
|
||||||
|
#define CMN_TXPXCAL_START BIT(15)
|
||||||
|
#define CMN_TXPXCAL_DONE BIT(14)
|
||||||
|
#define CMN_TXPXCAL_NO_RESPONSE BIT(13)
|
||||||
|
#define CMN_TXPXCAL_CURRENT_RESPONSE BIT(12)
|
||||||
|
|
||||||
|
#define CMN_TXPU_ADJ_CTRL (0x108 << 2)
|
||||||
|
#define CMN_TXPD_ADJ_CTRL (0x10c << 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL,
|
||||||
|
* CMN_TXPU_ADJ_CTRL, CMN_TXPDCAL_CTRL
|
||||||
|
*
|
||||||
|
* NOTE: some of these registers are documented to be 2's complement
|
||||||
|
* signed numbers, but then documented to be always positive. Weird.
|
||||||
|
* In such a case, using CMN_CALIB_CODE_POS() avoids the unnecessary
|
||||||
|
* sign extension.
|
||||||
|
*/
|
||||||
|
#define CMN_CALIB_CODE_WIDTH 7
|
||||||
|
#define CMN_CALIB_CODE_OFFSET 0
|
||||||
|
#define CMN_CALIB_CODE_MASK GENMASK(CMN_CALIB_CODE_WIDTH, 0)
|
||||||
|
#define CMN_CALIB_CODE(x) \
|
||||||
|
sign_extend32((x) >> CMN_CALIB_CODE_OFFSET, CMN_CALIB_CODE_WIDTH)
|
||||||
|
|
||||||
|
#define CMN_CALIB_CODE_POS_MASK GENMASK(CMN_CALIB_CODE_WIDTH - 1, 0)
|
||||||
|
#define CMN_CALIB_CODE_POS(x) \
|
||||||
|
(((x) >> CMN_CALIB_CODE_OFFSET) & CMN_CALIB_CODE_POS_MASK)
|
||||||
|
|
||||||
#define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2)
|
#define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2)
|
||||||
#define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2)
|
#define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2)
|
||||||
#define CMN_DIAG_PLL0_OVRD (0x1c2 << 2)
|
#define CMN_DIAG_PLL0_OVRD (0x1c2 << 2)
|
||||||
|
@ -138,6 +169,15 @@
|
||||||
#define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2)
|
#define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2)
|
||||||
#define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2)
|
#define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2)
|
||||||
#define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2)
|
#define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_000(n) ((0x4058 | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_001(n) ((0x4059 | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_010(n) ((0x405a | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_011(n) ((0x405b | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_100(n) ((0x405c | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_101(n) ((0x405d | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_110(n) ((0x405e | ((n) << 9)) << 2)
|
||||||
|
#define TX_TXCC_MGNLS_MULT_111(n) ((0x405f | ((n) << 9)) << 2)
|
||||||
|
|
||||||
#define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2)
|
#define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2)
|
||||||
#define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2)
|
#define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2)
|
||||||
#define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2)
|
#define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2)
|
||||||
|
@ -150,10 +190,63 @@
|
||||||
#define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2)
|
#define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2)
|
||||||
#define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2)
|
#define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2)
|
||||||
#define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2)
|
#define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2)
|
||||||
|
|
||||||
|
/* Use this for "n" in macros like "_MULT_XXX" to target the aux channel */
|
||||||
|
#define AUX_CH_LANE 8
|
||||||
|
|
||||||
#define TX_ANA_CTRL_REG_1 (0x5020 << 2)
|
#define TX_ANA_CTRL_REG_1 (0x5020 << 2)
|
||||||
|
|
||||||
|
#define TXDA_DP_AUX_EN BIT(15)
|
||||||
|
#define AUXDA_SE_EN BIT(14)
|
||||||
|
#define TXDA_CAL_LATCH_EN BIT(13)
|
||||||
|
#define AUXDA_POLARITY BIT(12)
|
||||||
|
#define TXDA_DRV_POWER_ISOLATION_EN BIT(11)
|
||||||
|
#define TXDA_DRV_POWER_EN_PH_2_N BIT(10)
|
||||||
|
#define TXDA_DRV_POWER_EN_PH_1_N BIT(9)
|
||||||
|
#define TXDA_BGREF_EN BIT(8)
|
||||||
|
#define TXDA_DRV_LDO_EN BIT(7)
|
||||||
|
#define TXDA_DECAP_EN_DEL BIT(6)
|
||||||
|
#define TXDA_DECAP_EN BIT(5)
|
||||||
|
#define TXDA_UPHY_SUPPLY_EN_DEL BIT(4)
|
||||||
|
#define TXDA_UPHY_SUPPLY_EN BIT(3)
|
||||||
|
#define TXDA_LOW_LEAKAGE_EN BIT(2)
|
||||||
|
#define TXDA_DRV_IDLE_LOWI_EN BIT(1)
|
||||||
|
#define TXDA_DRV_CMN_MODE_EN BIT(0)
|
||||||
|
|
||||||
#define TX_ANA_CTRL_REG_2 (0x5021 << 2)
|
#define TX_ANA_CTRL_REG_2 (0x5021 << 2)
|
||||||
|
|
||||||
|
#define AUXDA_DEBOUNCING_CLK BIT(15)
|
||||||
|
#define TXDA_LPBK_RECOVERED_CLK_EN BIT(14)
|
||||||
|
#define TXDA_LPBK_ISI_GEN_EN BIT(13)
|
||||||
|
#define TXDA_LPBK_SERIAL_EN BIT(12)
|
||||||
|
#define TXDA_LPBK_LINE_EN BIT(11)
|
||||||
|
#define TXDA_DRV_LDO_REDC_SINKIQ BIT(10)
|
||||||
|
#define XCVR_DECAP_EN_DEL BIT(9)
|
||||||
|
#define XCVR_DECAP_EN BIT(8)
|
||||||
|
#define TXDA_MPHY_ENABLE_HS_NT BIT(7)
|
||||||
|
#define TXDA_MPHY_SA_MODE BIT(6)
|
||||||
|
#define TXDA_DRV_LDO_RBYR_FB_EN BIT(5)
|
||||||
|
#define TXDA_DRV_RST_PULL_DOWN BIT(4)
|
||||||
|
#define TXDA_DRV_LDO_BG_FB_EN BIT(3)
|
||||||
|
#define TXDA_DRV_LDO_BG_REF_EN BIT(2)
|
||||||
|
#define TXDA_DRV_PREDRV_EN_DEL BIT(1)
|
||||||
|
#define TXDA_DRV_PREDRV_EN BIT(0)
|
||||||
|
|
||||||
#define TXDA_COEFF_CALC_CTRL (0x5022 << 2)
|
#define TXDA_COEFF_CALC_CTRL (0x5022 << 2)
|
||||||
|
|
||||||
|
#define TX_HIGH_Z BIT(6)
|
||||||
|
#define TX_VMARGIN_OFFSET 3
|
||||||
|
#define TX_VMARGIN_MASK 0x7
|
||||||
|
#define LOW_POWER_SWING_EN BIT(2)
|
||||||
|
#define TX_FCM_DRV_MAIN_EN BIT(1)
|
||||||
|
#define TX_FCM_FULL_MARGIN BIT(0)
|
||||||
|
|
||||||
#define TX_DIG_CTRL_REG_2 (0x5024 << 2)
|
#define TX_DIG_CTRL_REG_2 (0x5024 << 2)
|
||||||
|
|
||||||
|
#define TX_HIGH_Z_TM_EN BIT(15)
|
||||||
|
#define TX_RESCAL_CODE_OFFSET 0
|
||||||
|
#define TX_RESCAL_CODE_MASK 0x3f
|
||||||
|
|
||||||
#define TXDA_CYA_AUXDA_CYA (0x5025 << 2)
|
#define TXDA_CYA_AUXDA_CYA (0x5025 << 2)
|
||||||
#define TX_ANA_CTRL_REG_3 (0x5026 << 2)
|
#define TX_ANA_CTRL_REG_3 (0x5026 << 2)
|
||||||
#define TX_ANA_CTRL_REG_4 (0x5027 << 2)
|
#define TX_ANA_CTRL_REG_4 (0x5027 << 2)
|
||||||
|
@ -456,54 +549,72 @@ static void tcphy_dp_aux_set_flip(struct rockchip_typec_phy *tcphy)
|
||||||
*/
|
*/
|
||||||
tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1);
|
tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
if (!tcphy->flip)
|
if (!tcphy->flip)
|
||||||
tx_ana_ctrl_reg_1 |= BIT(12);
|
tx_ana_ctrl_reg_1 |= AUXDA_POLARITY;
|
||||||
else
|
else
|
||||||
tx_ana_ctrl_reg_1 &= ~BIT(12);
|
tx_ana_ctrl_reg_1 &= ~AUXDA_POLARITY;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
|
static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
|
||||||
{
|
{
|
||||||
|
u16 val;
|
||||||
u16 tx_ana_ctrl_reg_1;
|
u16 tx_ana_ctrl_reg_1;
|
||||||
u16 rdata, rdata2, val;
|
u16 tx_ana_ctrl_reg_2;
|
||||||
|
s32 pu_calib_code, pd_calib_code;
|
||||||
|
s32 pu_adj, pd_adj;
|
||||||
|
u16 calib;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate calibration code as per docs: use an average of the
|
||||||
|
* pull down and pull up. Then add in adjustments.
|
||||||
|
*/
|
||||||
|
val = readl(tcphy->base + CMN_TXPUCAL_CTRL);
|
||||||
|
pu_calib_code = CMN_CALIB_CODE_POS(val);
|
||||||
|
val = readl(tcphy->base + CMN_TXPDCAL_CTRL);
|
||||||
|
pd_calib_code = CMN_CALIB_CODE_POS(val);
|
||||||
|
val = readl(tcphy->base + CMN_TXPU_ADJ_CTRL);
|
||||||
|
pu_adj = CMN_CALIB_CODE(val);
|
||||||
|
val = readl(tcphy->base + CMN_TXPD_ADJ_CTRL);
|
||||||
|
pd_adj = CMN_CALIB_CODE(val);
|
||||||
|
calib = (pu_calib_code + pd_calib_code) / 2 + pu_adj + pd_adj;
|
||||||
|
|
||||||
/* disable txda_cal_latch_en for rewrite the calibration values */
|
/* disable txda_cal_latch_en for rewrite the calibration values */
|
||||||
tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1);
|
tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
tx_ana_ctrl_reg_1 &= ~BIT(13);
|
tx_ana_ctrl_reg_1 &= ~TXDA_CAL_LATCH_EN;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
|
|
||||||
/*
|
/* write the calibration, then delay 10 ms as sample in docs */
|
||||||
* read a resistor calibration code from CMN_TXPUCAL_CTRL[6:0] and
|
val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
|
||||||
* write it to TX_DIG_CTRL_REG_2[6:0], and delay 1ms to make sure it
|
val &= ~(TX_RESCAL_CODE_MASK << TX_RESCAL_CODE_OFFSET);
|
||||||
* works.
|
val |= calib << TX_RESCAL_CODE_OFFSET;
|
||||||
*/
|
|
||||||
rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
|
|
||||||
rdata = rdata & 0xffc0;
|
|
||||||
|
|
||||||
rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
|
|
||||||
rdata2 = rdata2 & 0x3f;
|
|
||||||
|
|
||||||
val = rdata | rdata2;
|
|
||||||
writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
|
writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
|
||||||
usleep_range(1000, 1050);
|
usleep_range(10000, 10050);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable signal for latch that sample and holds calibration values.
|
* Enable signal for latch that sample and holds calibration values.
|
||||||
* Activate this signal for 1 clock cycle to sample new calibration
|
* Activate this signal for 1 clock cycle to sample new calibration
|
||||||
* values.
|
* values.
|
||||||
*/
|
*/
|
||||||
tx_ana_ctrl_reg_1 |= BIT(13);
|
tx_ana_ctrl_reg_1 |= TXDA_CAL_LATCH_EN;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
usleep_range(150, 200);
|
usleep_range(150, 200);
|
||||||
|
|
||||||
/* set TX Voltage Level and TX Deemphasis to 0 */
|
/* set TX Voltage Level and TX Deemphasis to 0 */
|
||||||
writel(0, tcphy->base + PHY_DP_TX_CTL);
|
writel(0, tcphy->base + PHY_DP_TX_CTL);
|
||||||
|
|
||||||
/* re-enable decap */
|
/* re-enable decap */
|
||||||
writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
|
tx_ana_ctrl_reg_2 = XCVR_DECAP_EN;
|
||||||
writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
|
writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2);
|
||||||
tx_ana_ctrl_reg_1 |= BIT(3);
|
udelay(1);
|
||||||
|
tx_ana_ctrl_reg_2 |= XCVR_DECAP_EN_DEL;
|
||||||
|
writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2);
|
||||||
|
|
||||||
|
writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
|
||||||
|
|
||||||
|
tx_ana_ctrl_reg_1 |= TXDA_UPHY_SUPPLY_EN;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
tx_ana_ctrl_reg_1 |= BIT(4);
|
udelay(1);
|
||||||
|
tx_ana_ctrl_reg_1 |= TXDA_UPHY_SUPPLY_EN_DEL;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
|
|
||||||
writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
|
writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
|
||||||
|
@ -515,44 +626,66 @@ static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
|
||||||
writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
|
writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
|
||||||
|
|
||||||
/* re-enables Bandgap reference for LDO */
|
/* re-enables Bandgap reference for LDO */
|
||||||
tx_ana_ctrl_reg_1 |= BIT(7);
|
tx_ana_ctrl_reg_1 |= TXDA_DRV_LDO_EN;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
tx_ana_ctrl_reg_1 |= BIT(8);
|
udelay(5);
|
||||||
|
tx_ana_ctrl_reg_1 |= TXDA_BGREF_EN;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* re-enables the transmitter pre-driver, driver data selection MUX,
|
* re-enables the transmitter pre-driver, driver data selection MUX,
|
||||||
* and receiver detect circuits.
|
* and receiver detect circuits.
|
||||||
*/
|
*/
|
||||||
writel(0x301, tcphy->base + TX_ANA_CTRL_REG_2);
|
tx_ana_ctrl_reg_2 |= TXDA_DRV_PREDRV_EN;
|
||||||
writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
|
writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2);
|
||||||
|
udelay(1);
|
||||||
|
tx_ana_ctrl_reg_2 |= TXDA_DRV_PREDRV_EN_DEL;
|
||||||
|
writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do some magic undocumented stuff, some of which appears to
|
* Do all the undocumented magic:
|
||||||
* undo the "re-enables Bandgap reference for LDO" above.
|
* - Turn on TXDA_DP_AUX_EN, whatever that is, even though sample
|
||||||
|
* never shows this going on.
|
||||||
|
* - Turn on TXDA_DECAP_EN (and TXDA_DECAP_EN_DEL) even though
|
||||||
|
* docs say for aux it's always 0.
|
||||||
|
* - Turn off the LDO and BGREF, which we just spent time turning
|
||||||
|
* on above (???).
|
||||||
|
*
|
||||||
|
* Without this magic, things seem worse.
|
||||||
*/
|
*/
|
||||||
tx_ana_ctrl_reg_1 |= BIT(15);
|
tx_ana_ctrl_reg_1 |= TXDA_DP_AUX_EN;
|
||||||
tx_ana_ctrl_reg_1 &= ~BIT(8);
|
tx_ana_ctrl_reg_1 |= TXDA_DECAP_EN;
|
||||||
tx_ana_ctrl_reg_1 &= ~BIT(7);
|
tx_ana_ctrl_reg_1 &= ~TXDA_DRV_LDO_EN;
|
||||||
tx_ana_ctrl_reg_1 |= BIT(6);
|
tx_ana_ctrl_reg_1 &= ~TXDA_BGREF_EN;
|
||||||
tx_ana_ctrl_reg_1 |= BIT(5);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
|
udelay(1);
|
||||||
|
tx_ana_ctrl_reg_1 |= TXDA_DECAP_EN_DEL;
|
||||||
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
|
||||||
|
|
||||||
writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
|
|
||||||
writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
|
|
||||||
writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Controls low_power_swing_en, don't set the voltage swing of the
|
* Undo the work we did to set the LDO voltage.
|
||||||
* driver to 400mv. The values below are peak to peak (differential)
|
* This doesn't seem to help nor hurt, but it kinda goes with the
|
||||||
* values.
|
* undocumented magic above.
|
||||||
*/
|
*/
|
||||||
|
writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
|
||||||
|
|
||||||
|
/* Don't set voltage swing to 400 mV peak to peak (differential) */
|
||||||
writel(0, tcphy->base + TXDA_COEFF_CALC_CTRL);
|
writel(0, tcphy->base + TXDA_COEFF_CALC_CTRL);
|
||||||
|
|
||||||
|
/* Init TXDA_CYA_AUXDA_CYA for unknown magic reasons */
|
||||||
writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
|
writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
|
||||||
|
|
||||||
/* Controls tx_high_z_tm_en */
|
/*
|
||||||
|
* More undocumented magic, presumably the goal of which is to
|
||||||
|
* make the "auxda_source_aux_oen" be ignored and instead to decide
|
||||||
|
* about "high impedance state" based on what software puts in the
|
||||||
|
* register TXDA_COEFF_CALC_CTRL (see TX_HIGH_Z). Since we only
|
||||||
|
* program that register once and we don't set the bit TX_HIGH_Z,
|
||||||
|
* presumably the goal here is that we should never put the analog
|
||||||
|
* driver in high impedance state.
|
||||||
|
*/
|
||||||
val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
|
val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
|
||||||
val |= BIT(15);
|
val |= TX_HIGH_Z_TM_EN;
|
||||||
writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
|
writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,40 @@
|
||||||
#define PCIE_PCS_MASK 0xFF0000
|
#define PCIE_PCS_MASK 0xFF0000
|
||||||
#define PCIE_PCS_DELAY_COUNT_SHIFT 0x10
|
#define PCIE_PCS_DELAY_COUNT_SHIFT 0x10
|
||||||
|
|
||||||
|
#define PCIEPHYRX_ANA_PROGRAMMABILITY 0x0000000C
|
||||||
|
#define INTERFACE_MASK GENMASK(31, 27)
|
||||||
|
#define INTERFACE_SHIFT 27
|
||||||
|
#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 MEM_DLL_TRIM_SHIFT 30
|
||||||
|
|
||||||
|
#define PCIEPHYRX_DLL 0x00000024
|
||||||
|
#define MEM_DLL_PHINT_RATE GENMASK(31, 30)
|
||||||
|
|
||||||
|
#define PCIEPHYRX_DIGITAL_MODES 0x00000028
|
||||||
|
#define MEM_CDR_FASTLOCK BIT(23)
|
||||||
|
#define MEM_CDR_LBW GENMASK(22, 21)
|
||||||
|
#define MEM_CDR_STEPCNT GENMASK(20, 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_EQCTL_SHIFT 7
|
||||||
|
#define MEM_OVRD_EQLEV BIT(2)
|
||||||
|
#define MEM_OVRD_EQFTC BIT(1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is an Empirical value that works, need to confirm the actual
|
* This is an Empirical value that works, need to confirm the actual
|
||||||
* value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
|
* value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
|
||||||
|
@ -91,6 +125,8 @@ struct pipe3_dpll_map {
|
||||||
|
|
||||||
struct ti_pipe3 {
|
struct ti_pipe3 {
|
||||||
void __iomem *pll_ctrl_base;
|
void __iomem *pll_ctrl_base;
|
||||||
|
void __iomem *phy_rx;
|
||||||
|
void __iomem *phy_tx;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct device *control_dev;
|
struct device *control_dev;
|
||||||
struct clk *wkupclk;
|
struct clk *wkupclk;
|
||||||
|
@ -261,6 +297,37 @@ static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
|
||||||
return ti_pipe3_dpll_wait_lock(phy);
|
return ti_pipe3_dpll_wait_lock(phy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ti_pipe3_calibrate(struct ti_pipe3 *phy)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_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 = 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);
|
||||||
|
}
|
||||||
|
|
||||||
static int ti_pipe3_init(struct phy *x)
|
static int ti_pipe3_init(struct phy *x)
|
||||||
{
|
{
|
||||||
struct ti_pipe3 *phy = phy_get_drvdata(x);
|
struct ti_pipe3 *phy = phy_get_drvdata(x);
|
||||||
|
@ -282,7 +349,12 @@ static int ti_pipe3_init(struct phy *x)
|
||||||
val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT;
|
val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT;
|
||||||
ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg,
|
ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg,
|
||||||
PCIE_PCS_MASK, val);
|
PCIE_PCS_MASK, val);
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ti_pipe3_calibrate(phy);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bring it out of IDLE if it is IDLE */
|
/* Bring it out of IDLE if it is IDLE */
|
||||||
|
@ -513,6 +585,29 @@ static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ti_pipe3_get_tx_rx_base(struct ti_pipe3 *phy)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
struct device *dev = phy->dev;
|
||||||
|
struct device_node *node = dev->of_node;
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
|
||||||
|
if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||||
|
"phy_rx");
|
||||||
|
phy->phy_rx = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(phy->phy_rx))
|
||||||
|
return PTR_ERR(phy->phy_rx);
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||||
|
"phy_tx");
|
||||||
|
phy->phy_tx = devm_ioremap_resource(dev, res);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(phy->phy_tx);
|
||||||
|
}
|
||||||
|
|
||||||
static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy)
|
static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
@ -559,6 +654,10 @@ static int ti_pipe3_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = ti_pipe3_get_tx_rx_base(phy);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = ti_pipe3_get_sysctrl(phy);
|
ret = ti_pipe3_get_sysctrl(phy);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -273,15 +273,18 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
|
||||||
bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
|
bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
|
||||||
? true : false;
|
? true : false;
|
||||||
|
|
||||||
|
if (is_rate_B)
|
||||||
|
phy_set_mode(phy, PHY_MODE_UFS_HS_B);
|
||||||
|
|
||||||
/* Assert PHY reset and apply PHY calibration values */
|
/* Assert PHY reset and apply PHY calibration values */
|
||||||
ufs_qcom_assert_reset(hba);
|
ufs_qcom_assert_reset(hba);
|
||||||
/* provide 1ms delay to let the reset pulse propagate */
|
/* provide 1ms delay to let the reset pulse propagate */
|
||||||
usleep_range(1000, 1100);
|
usleep_range(1000, 1100);
|
||||||
|
|
||||||
ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
|
/* phy initialization - calibrate the phy */
|
||||||
|
ret = phy_init(phy);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
|
dev_err(hba->dev, "%s: phy init failed, ret = %d\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -294,21 +297,22 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
|
||||||
* voltage, current to settle down before starting serdes.
|
* voltage, current to settle down before starting serdes.
|
||||||
*/
|
*/
|
||||||
usleep_range(1000, 1100);
|
usleep_range(1000, 1100);
|
||||||
ret = ufs_qcom_phy_start_serdes(phy);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(hba->dev, "%s: ufs_qcom_phy_start_serdes() failed, ret = %d\n",
|
|
||||||
__func__, ret);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ufs_qcom_phy_is_pcs_ready(phy);
|
/* power on phy - start serdes and phy's power and clocks */
|
||||||
if (ret)
|
ret = phy_power_on(phy);
|
||||||
dev_err(hba->dev,
|
if (ret) {
|
||||||
"%s: is_physical_coding_sublayer_ready() failed, ret = %d\n",
|
dev_err(hba->dev, "%s: phy power on failed, ret = %d\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
|
goto out_disable_phy;
|
||||||
|
}
|
||||||
|
|
||||||
ufs_qcom_select_unipro_mode(host);
|
ufs_qcom_select_unipro_mode(host);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_disable_phy:
|
||||||
|
ufs_qcom_assert_reset(hba);
|
||||||
|
phy_exit(phy);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1273,14 +1277,9 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
ufs_qcom_phy_save_controller_version(host->generic_phy,
|
ufs_qcom_phy_save_controller_version(host->generic_phy,
|
||||||
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
|
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
|
||||||
|
|
||||||
phy_init(host->generic_phy);
|
|
||||||
err = phy_power_on(host->generic_phy);
|
|
||||||
if (err)
|
|
||||||
goto out_unregister_bus;
|
|
||||||
|
|
||||||
err = ufs_qcom_init_lane_clks(host);
|
err = ufs_qcom_init_lane_clks(host);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_disable_phy;
|
goto out_variant_clear;
|
||||||
|
|
||||||
ufs_qcom_set_caps(hba);
|
ufs_qcom_set_caps(hba);
|
||||||
ufs_qcom_advertise_quirks(hba);
|
ufs_qcom_advertise_quirks(hba);
|
||||||
|
@ -1301,10 +1300,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out_disable_phy:
|
|
||||||
phy_power_off(host->generic_phy);
|
|
||||||
out_unregister_bus:
|
|
||||||
phy_exit(host->generic_phy);
|
|
||||||
out_variant_clear:
|
out_variant_clear:
|
||||||
ufshcd_set_variant(hba, NULL);
|
ufshcd_set_variant(hba, NULL);
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -40,6 +40,18 @@ bool soc_is_brcmstb(void)
|
||||||
return of_match_node(brcmstb_machine_match, root) != NULL;
|
return of_match_node(brcmstb_machine_match, root) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 brcmstb_get_family_id(void)
|
||||||
|
{
|
||||||
|
return family_id;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(brcmstb_get_family_id);
|
||||||
|
|
||||||
|
u32 brcmstb_get_product_id(void)
|
||||||
|
{
|
||||||
|
return product_id;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(brcmstb_get_product_id);
|
||||||
|
|
||||||
static const struct of_device_id sun_top_ctrl_match[] = {
|
static const struct of_device_id sun_top_ctrl_match[] = {
|
||||||
{ .compatible = "brcm,bcm7125-sun-top-ctrl", },
|
{ .compatible = "brcm,bcm7125-sun-top-ctrl", },
|
||||||
{ .compatible = "brcm,bcm7346-sun-top-ctrl", },
|
{ .compatible = "brcm,bcm7346-sun-top-ctrl", },
|
||||||
|
|
|
@ -15,5 +15,6 @@
|
||||||
#define PHY_TYPE_PCIE 2
|
#define PHY_TYPE_PCIE 2
|
||||||
#define PHY_TYPE_USB2 3
|
#define PHY_TYPE_USB2 3
|
||||||
#define PHY_TYPE_USB3 4
|
#define PHY_TYPE_USB3 4
|
||||||
|
#define PHY_TYPE_UFS 5
|
||||||
|
|
||||||
#endif /* _DT_BINDINGS_PHY */
|
#endif /* _DT_BINDINGS_PHY */
|
||||||
|
|
|
@ -31,10 +31,7 @@ void ufs_qcom_phy_enable_dev_ref_clk(struct phy *phy);
|
||||||
*/
|
*/
|
||||||
void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy);
|
void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy);
|
||||||
|
|
||||||
int ufs_qcom_phy_start_serdes(struct phy *phy);
|
|
||||||
int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes);
|
int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes);
|
||||||
int ufs_qcom_phy_calibrate_phy(struct phy *phy, bool is_rate_B);
|
|
||||||
int ufs_qcom_phy_is_pcs_ready(struct phy *phy);
|
|
||||||
void ufs_qcom_phy_save_controller_version(struct phy *phy,
|
void ufs_qcom_phy_save_controller_version(struct phy *phy,
|
||||||
u8 major, u16 minor, u16 step);
|
u8 major, u16 minor, u16 step);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ enum phy_mode {
|
||||||
PHY_MODE_USB_OTG,
|
PHY_MODE_USB_OTG,
|
||||||
PHY_MODE_SGMII,
|
PHY_MODE_SGMII,
|
||||||
PHY_MODE_10GKR,
|
PHY_MODE_10GKR,
|
||||||
|
PHY_MODE_UFS_HS_A,
|
||||||
|
PHY_MODE_UFS_HS_B,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +41,7 @@ enum phy_mode {
|
||||||
* @power_off: powering off the phy
|
* @power_off: powering off the phy
|
||||||
* @set_mode: set the mode of the phy
|
* @set_mode: set the mode of the phy
|
||||||
* @reset: resetting the phy
|
* @reset: resetting the phy
|
||||||
|
* @calibrate: calibrate the phy
|
||||||
* @owner: the module owner containing the ops
|
* @owner: the module owner containing the ops
|
||||||
*/
|
*/
|
||||||
struct phy_ops {
|
struct phy_ops {
|
||||||
|
@ -48,6 +51,7 @@ struct phy_ops {
|
||||||
int (*power_off)(struct phy *phy);
|
int (*power_off)(struct phy *phy);
|
||||||
int (*set_mode)(struct phy *phy, enum phy_mode mode);
|
int (*set_mode)(struct phy *phy, enum phy_mode mode);
|
||||||
int (*reset)(struct phy *phy);
|
int (*reset)(struct phy *phy);
|
||||||
|
int (*calibrate)(struct phy *phy);
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,6 +145,7 @@ int phy_power_on(struct phy *phy);
|
||||||
int phy_power_off(struct phy *phy);
|
int phy_power_off(struct phy *phy);
|
||||||
int phy_set_mode(struct phy *phy, enum phy_mode mode);
|
int phy_set_mode(struct phy *phy, enum phy_mode mode);
|
||||||
int phy_reset(struct phy *phy);
|
int phy_reset(struct phy *phy);
|
||||||
|
int phy_calibrate(struct phy *phy);
|
||||||
static inline int phy_get_bus_width(struct phy *phy)
|
static inline int phy_get_bus_width(struct phy *phy)
|
||||||
{
|
{
|
||||||
return phy->attrs.bus_width;
|
return phy->attrs.bus_width;
|
||||||
|
@ -262,6 +267,13 @@ static inline int phy_reset(struct phy *phy)
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int phy_calibrate(struct phy *phy)
|
||||||
|
{
|
||||||
|
if (!phy)
|
||||||
|
return 0;
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int phy_get_bus_width(struct phy *phy)
|
static inline int phy_get_bus_width(struct phy *phy)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
@ -291,7 +303,7 @@ static inline struct phy *devm_phy_get(struct device *dev, const char *string)
|
||||||
static inline struct phy *devm_phy_optional_get(struct device *dev,
|
static inline struct phy *devm_phy_optional_get(struct device *dev,
|
||||||
const char *string)
|
const char *string)
|
||||||
{
|
{
|
||||||
return ERR_PTR(-ENOSYS);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct phy *devm_of_phy_get(struct device *dev,
|
static inline struct phy *devm_of_phy_get(struct device *dev,
|
||||||
|
|
|
@ -1,10 +1,27 @@
|
||||||
#ifndef __BRCMSTB_SOC_H
|
#ifndef __BRCMSTB_SOC_H
|
||||||
#define __BRCMSTB_SOC_H
|
#define __BRCMSTB_SOC_H
|
||||||
|
|
||||||
|
static inline u32 BRCM_ID(u32 reg)
|
||||||
|
{
|
||||||
|
return reg >> 28 ? reg >> 16 : reg >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 BRCM_REV(u32 reg)
|
||||||
|
{
|
||||||
|
return reg & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bus Interface Unit control register setup, must happen early during boot,
|
* Bus Interface Unit control register setup, must happen early during boot,
|
||||||
* before SMP is brought up, called by machine entry point.
|
* before SMP is brought up, called by machine entry point.
|
||||||
*/
|
*/
|
||||||
void brcmstb_biuctrl_init(void);
|
void brcmstb_biuctrl_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper functions for getting family or product id from the
|
||||||
|
* SoC driver.
|
||||||
|
*/
|
||||||
|
u32 brcmstb_get_family_id(void);
|
||||||
|
u32 brcmstb_get_product_id(void);
|
||||||
|
|
||||||
#endif /* __BRCMSTB_SOC_H */
|
#endif /* __BRCMSTB_SOC_H */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user