diff options
25 files changed, 1200 insertions, 253 deletions
diff --git a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt b/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt index 0acc5a99fb79..faf18084a33a 100644 --- a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt +++ b/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt @@ -1,13 +1,18 @@ -mt65xx USB3.0 PHY binding +MediaTek T-PHY binding -------------------------- -This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC. +T-phy controller supports physical layer functionality for a number of +controllers on MediaTek SoCs, such as, USB2.0, USB3.0, PCIe, and SATA. Required properties (controller (parent) node): - compatible : should be one of - "mediatek,mt2701-u3phy" - "mediatek,mt2712-u3phy" - "mediatek,mt8173-u3phy" + "mediatek,generic-tphy-v1" + "mediatek,generic-tphy-v2" + "mediatek,mt2701-u3phy" (deprecated) + "mediatek,mt2712-u3phy" (deprecated) + "mediatek,mt8173-u3phy"; + make use of "mediatek,generic-tphy-v1" on mt2701 instead and + "mediatek,generic-tphy-v2" on mt2712 instead. - clocks : (deprecated, use port's clocks instead) a list of phandle + clock-specifier pairs, one for each entry in clock-names - clock-names : (deprecated, use port's one instead) must contain @@ -35,6 +40,8 @@ Required properties (port (child) node): cell after port phandle is phy type from: - PHY_TYPE_USB2 - PHY_TYPE_USB3 + - PHY_TYPE_PCIE + - PHY_TYPE_SATA Example: diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt index 84d59b0db8df..a67ef2a3874f 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt @@ -6,6 +6,7 @@ Required properties (phy (parent) node): * "rockchip,rk3328-usb2phy" * "rockchip,rk3366-usb2phy" * "rockchip,rk3399-usb2phy" + * "rockchip,rv1108-usb2phy" - reg : the address offset of grf for usb-phy configuration. - #clock-cells : should be 0. - clock-output-names : specify the 480m output clock name. @@ -18,6 +19,10 @@ Optional properties: usb-phy output 480m and xin24m. Refer to clk/clock-bindings.txt for generic clock consumer properties. + - rockchip,usbgrf : phandle to the syscon managing the "usb general + register files". When set driver will request its + phandle as one companion-grf for some special SoCs + (e.g RV1108). Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify host or otg port, @@ -28,10 +33,14 @@ Required nodes : a sub-node is required for each port the phy provides. Required properties (port (child) node): - #phy-cells : must be 0. See ./phy-bindings.txt for details. - interrupts : specify an interrupt for each entry in interrupt-names. - - interrupt-names : a list which shall be the following entries: + - interrupt-names : a list which should be one of the following cases: + Regular case: * "otg-id" : for the otg id interrupt. * "otg-bvalid" : for the otg vbus interrupt. * "linestate" : for the host/otg linestate interrupt. + Some SoCs use one interrupt with the above muxed together, so for these + * "otg-mux" : otg-port interrupt, which mux otg-id/otg-bvalid/linestate + to one. Optional properties: - phy-supply : phandle to a regulator that provides power to VBUS. diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt index e11c563a65ec..b6a9f2b92bab 100644 --- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt @@ -6,6 +6,7 @@ controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. Required properties: - compatible: compatible list, contains: + "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074 "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996, "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996. @@ -38,6 +39,8 @@ Required properties: "phy", "common", "cfg". For "qcom,msm8996-qmp-usb3-phy" must contain "phy", "common". + For "qcom,ipq8074-qmp-pcie-phy" must contain: + "phy", "common". - vdda-phy-supply: Phandle to a regulator supply to PHY core block. - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block. @@ -60,6 +63,13 @@ Required properties for child node: one for each entry in clock-names. - clock-names: Must contain following for pcie and usb qmp phys: "pipe<lane-number>" for pipe clock specific to each lane. + - clock-output-names: Name of the PHY clock that will be the parent for + the above pipe clock. + + For "qcom,ipq8074-qmp-pcie-phy": + - "pcie20_phy0_pipe_clk" Pipe Clock parent + (or) + "pcie20_phy1_pipe_clk" - resets: a list of phandles and reset controller specifier pairs, one for each entry in reset-names. @@ -96,6 +106,7 @@ Example: clocks = <&gcc GCC_PCIE_0_PIPE_CLK>; clock-names = "pipe0"; + clock-output-names = "pcie_0_pipe_clk_src"; resets = <&gcc GCC_PCIE_0_PHY_BCR>; reset-names = "lane0"; }; diff --git a/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt b/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt new file mode 100644 index 000000000000..9d2868a437ab --- /dev/null +++ b/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt @@ -0,0 +1,23 @@ +Mediatek/Ralink USB PHY + +Required properties: + - compatible: "ralink,rt3352-usbphy" + "mediatek,mt7620-usbphy" + "mediatek,mt7628-usbphy" + - reg: required for "mediatek,mt7628-usbphy", unused otherwise + - #phy-cells: should be 0 + - ralink,sysctl: a phandle to a ralink syscon register region + - resets: the two reset controllers for host and device + - reset-names: the names of the 2 reset controllers + +Example: + +usbphy: phy { + compatible = "mediatek,mt7628-usbphy"; + reg = <0x10120000 0x1000>; + #phy-cells = <0>; + + ralink,sysctl = <&sysc>; + resets = <&rstctrl 22 &rstctrl 25>; + reset-names = "host", "device"; +}; diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 005bc22938ff..cbc7847dbf6c 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -9,6 +9,7 @@ Required properties: * allwinner,sun7i-a20-usb-phy * allwinner,sun8i-a23-usb-phy * allwinner,sun8i-a33-usb-phy + * allwinner,sun8i-a83t-usb-phy * allwinner,sun8i-h3-usb-phy * allwinner,sun8i-v3s-usb-phy * allwinner,sun50i-a64-usb-phy @@ -17,18 +18,22 @@ Required properties: * "phy_ctrl" * "pmu0" for H3, V3s and A64 * "pmu1" - * "pmu2" for sun4i, sun6i or sun7i + * "pmu2" for sun4i, sun6i, sun7i, sun8i-a83t or sun8i-h3 + * "pmu3" for sun8i-h3 - #phy-cells : from the generic phy bindings, must be 1 - clocks : phandle + clock specifier for the phy clocks - clock-names : * "usb_phy" for sun4i, sun5i or sun7i * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i * "usb0_phy", "usb1_phy" for sun8i + * "usb0_phy", "usb1_phy", "usb2_phy" and "usb2_hsic_12M" for sun8i-a83t + * "usb0_phy", "usb1_phy", "usb2_phy" and "usb3_phy" for sun8i-h3 - resets : a list of phandle + reset specifier pairs - reset-names : * "usb0_reset" * "usb1_reset" - * "usb2_reset" for sun4i, sun6i or sun7i + * "usb2_reset" for sun4i, sun6i, sun7i, sun8i-a83t or sun8i-h3 + * "usb3_reset" for sun8i-h3 Optional properties: - usb0_id_det-gpios : gpio phandle for reading the otg id pin value @@ -37,6 +42,7 @@ Optional properties: - usb0_vbus-supply : regulator phandle for controller usb0 vbus - usb1_vbus-supply : regulator phandle for controller usb1 vbus - usb2_vbus-supply : regulator phandle for controller usb2 vbus +- usb3_vbus-supply : regulator phandle for controller usb3 vbus Example: usbphy: phy@0x01c13400 { diff --git a/MAINTAINERS b/MAINTAINERS index fedbff3d15fa..761a363982d4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1570,7 +1570,7 @@ M: Chunfeng Yun <chunfeng.yun@mediatek.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: drivers/phy/phy-mt65xx-usb3.c +F: drivers/phy/mediatek/phy-mtk-tphy.c ARM/MICREL KS8695 ARCHITECTURE M: Greg Ungerer <gerg@uclinux.org> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c1807d4a0079..441912c10b82 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -26,14 +26,6 @@ config PHY_LPC18XX_USB_OTG This driver is need for USB0 support on LPC18xx/43xx and takes care of enabling and clock setup. -config PHY_MT65XX_USB3 - tristate "Mediatek USB3.0 PHY Driver" - depends on ARCH_MEDIATEK && OF - select GENERIC_PHY - help - Say 'Y' here to add support for Mediatek USB3.0 PHY driver, - it supports multiple usb2.0 and usb3.0 ports. - config PHY_PISTACHIO_USB tristate "IMG Pistachio USB2.0 PHY driver" depends on MACH_PISTACHIO @@ -53,8 +45,10 @@ source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig" source "drivers/phy/hisilicon/Kconfig" source "drivers/phy/marvell/Kconfig" +source "drivers/phy/mediatek/Kconfig" source "drivers/phy/motorola/Kconfig" source "drivers/phy/qualcomm/Kconfig" +source "drivers/phy/ralink/Kconfig" source "drivers/phy/renesas/Kconfig" source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f252201e0ec9..06f3c500030d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -4,12 +4,12 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o -obj-$(CONFIG_PHY_MT65XX_USB3) += phy-mt65xx-usb3.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_ARCH_SUNXI) += allwinner/ obj-$(CONFIG_ARCH_MESON) += amlogic/ +obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_RENESAS) += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ @@ -18,6 +18,7 @@ obj-y += broadcom/ \ marvell/ \ motorola/ \ qualcomm/ \ + ralink/ \ samsung/ \ st/ \ ti/ diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index bbf06cfe5898..1161e11fb3cf 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -87,6 +87,16 @@ #define PHY_DISCON_TH_SEL 0x2a #define PHY_SQUELCH_DETECT 0x3c +/* A83T specific control bits for PHY0 */ +#define PHY_CTL_VBUSVLDEXT BIT(5) +#define PHY_CTL_SIDDQ BIT(3) + +/* A83T specific control bits for PHY2 HSIC */ +#define SUNXI_EHCI_HS_FORCE BIT(20) +#define SUNXI_HSIC_CONNECT_DET BIT(17) +#define SUNXI_HSIC_CONNECT_INT BIT(16) +#define SUNXI_HSIC BIT(1) + #define MAX_PHYS 4 /* @@ -100,6 +110,7 @@ enum sun4i_usb_phy_type { sun4i_a10_phy, sun6i_a31_phy, sun8i_a33_phy, + sun8i_a83t_phy, sun8i_h3_phy, sun8i_v3s_phy, sun50i_a64_phy, @@ -107,6 +118,7 @@ enum sun4i_usb_phy_type { struct sun4i_usb_phy_cfg { int num_phys; + int hsic_index; enum sun4i_usb_phy_type type; u32 disc_thresh; u8 phyctl_offset; @@ -126,6 +138,7 @@ struct sun4i_usb_phy_data { struct regulator *vbus; struct reset_control *reset; struct clk *clk; + struct clk *clk2; bool regulator_on; int index; } phys[MAX_PHYS]; @@ -232,6 +245,7 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable) { + struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); u32 bits, reg_value; if (!phy->pmu) @@ -240,6 +254,11 @@ static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable) bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN; + /* A83T USB2 is HSIC */ + if (phy_data->cfg->type == sun8i_a83t_phy && phy->index == 2) + bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT | + SUNXI_HSIC; + reg_value = readl(phy->pmu); if (enable) @@ -261,27 +280,43 @@ static int sun4i_usb_phy_init(struct phy *_phy) if (ret) return ret; - ret = reset_control_deassert(phy->reset); + ret = clk_prepare_enable(phy->clk2); if (ret) { clk_disable_unprepare(phy->clk); return ret; } - if (phy->pmu && data->cfg->enable_pmu_unk1) { - val = readl(phy->pmu + REG_PMU_UNK1); - writel(val & ~2, phy->pmu + REG_PMU_UNK1); + ret = reset_control_deassert(phy->reset); + if (ret) { + clk_disable_unprepare(phy->clk2); + clk_disable_unprepare(phy->clk); + return ret; } - /* Enable USB 45 Ohm resistor calibration */ - if (phy->index == 0) - sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1); + if (data->cfg->type == sun8i_a83t_phy) { + if (phy->index == 0) { + val = readl(data->base + data->cfg->phyctl_offset); + val |= PHY_CTL_VBUSVLDEXT; + val &= ~PHY_CTL_SIDDQ; + writel(val, data->base + data->cfg->phyctl_offset); + } + } else { + if (phy->pmu && data->cfg->enable_pmu_unk1) { + val = readl(phy->pmu + REG_PMU_UNK1); + writel(val & ~2, phy->pmu + REG_PMU_UNK1); + } - /* Adjust PHY's magnitude and rate */ - sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); + /* Enable USB 45 Ohm resistor calibration */ + if (phy->index == 0) + sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1); - /* Disconnect threshold adjustment */ - sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, - data->cfg->disc_thresh, 2); + /* Adjust PHY's magnitude and rate */ + sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); + + /* Disconnect threshold adjustment */ + sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, + data->cfg->disc_thresh, 2); + } sun4i_usb_phy_passby(phy, 1); @@ -307,6 +342,13 @@ static int sun4i_usb_phy_exit(struct phy *_phy) struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); if (phy->index == 0) { + if (data->cfg->type == sun8i_a83t_phy) { + void __iomem *phyctl = data->base + + data->cfg->phyctl_offset; + + writel(readl(phyctl) | PHY_CTL_SIDDQ, phyctl); + } + /* Disable pull-ups */ sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0); sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0); @@ -315,6 +357,7 @@ static int sun4i_usb_phy_exit(struct phy *_phy) sun4i_usb_phy_passby(phy, 0); reset_control_assert(phy->reset); + clk_disable_unprepare(phy->clk2); clk_disable_unprepare(phy->clk); return 0; @@ -653,19 +696,25 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det", GPIOD_IN); - if (IS_ERR(data->id_det_gpio)) + if (IS_ERR(data->id_det_gpio)) { + dev_err(dev, "Couldn't request ID GPIO\n"); return PTR_ERR(data->id_det_gpio); + } data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det", GPIOD_IN); - if (IS_ERR(data->vbus_det_gpio)) + if (IS_ERR(data->vbus_det_gpio)) { + dev_err(dev, "Couldn't request VBUS detect GPIO\n"); return PTR_ERR(data->vbus_det_gpio); + } if (of_find_property(np, "usb0_vbus_power-supply", NULL)) { data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, "usb0_vbus_power-supply"); - if (IS_ERR(data->vbus_power_supply)) + if (IS_ERR(data->vbus_power_supply)) { + dev_err(dev, "Couldn't get the VBUS power supply\n"); return PTR_ERR(data->vbus_power_supply); + } if (!data->vbus_power_supply) return -EPROBE_DEFER; @@ -674,8 +723,10 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0); data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable); - if (IS_ERR(data->extcon)) + if (IS_ERR(data->extcon)) { + dev_err(dev, "Couldn't allocate our extcon device\n"); return PTR_ERR(data->extcon); + } ret = devm_extcon_dev_register(dev, data->extcon); if (ret) { @@ -690,8 +741,13 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "usb%d_vbus", i); phy->vbus = devm_regulator_get_optional(dev, name); if (IS_ERR(phy->vbus)) { - if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) + if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) { + dev_err(dev, + "Couldn't get regulator %s... Deferring probe\n", + name); return -EPROBE_DEFER; + } + phy->vbus = NULL; } @@ -706,6 +762,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(phy->clk); } + /* The first PHY is always tied to OTG, and never HSIC */ + if (data->cfg->hsic_index && i == data->cfg->hsic_index) { + /* HSIC needs secondary clock */ + snprintf(name, sizeof(name), "usb%d_hsic_12M", i); + phy->clk2 = devm_clk_get(dev, name); + if (IS_ERR(phy->clk2)) { + dev_err(dev, "failed to get clock %s\n", name); + return PTR_ERR(phy->clk2); + } + } + snprintf(name, sizeof(name), "usb%d_reset", i); phy->reset = devm_reset_control_get(dev, name); if (IS_ERR(phy->reset)) { @@ -775,6 +842,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(phy_provider); } + dev_dbg(dev, "successfully loaded\n"); + return 0; } @@ -832,6 +901,14 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { .enable_pmu_unk1 = false, }; +static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { + .num_phys = 3, + .hsic_index = 2, + .type = sun8i_a83t_phy, + .phyctl_offset = REG_PHYCTL_A33, + .dedicated_clocks = true, +}; + static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { .num_phys = 4, .type = sun8i_h3_phy, @@ -868,6 +945,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg }, { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg }, { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg }, + { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg }, { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg }, { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg }, { .compatible = "allwinner,sun50i-a64-usb-phy", diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index e6544c8b1ace..9d7f74fe3d7c 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -335,7 +335,7 @@ static int brcm_nsp_sata_init(struct brcm_sata_port *port) /* Wait for pll_seq_done bit */ try = 50; - while (try--) { + while (--try) { val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK, BLOCK0_XGXSSTATUS); if (val & BLOCK0_XGXSSTATUS_PLL_LOCK) diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig new file mode 100644 index 000000000000..88ab4e25e34f --- /dev/null +++ b/drivers/phy/mediatek/Kconfig @@ -0,0 +1,14 @@ +# +# Phy drivers for Mediatek devices +# +config PHY_MTK_TPHY + tristate "MediaTek T-PHY Driver" + depends on ARCH_MEDIATEK && OF + select GENERIC_PHY + help + Say 'Y' here to add support for MediaTek T-PHY driver, + it supports multiple usb2.0, usb3.0 ports, PCIe and + SATA, and meanwhile supports two version T-PHY which have + different banks layout, the T-PHY with shared banks between + multi-ports is first version, otherwise is second veriosn, + so you can easily distinguish them by banks layout. diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile new file mode 100644 index 000000000000..763a92eefa00 --- /dev/null +++ b/drivers/phy/mediatek/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the phy drivers. +# + +obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 59b110f795c3..e3baad78521f 100644 --- a/drivers/phy/phy-mt65xx-usb3.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -29,7 +29,7 @@ #define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */ /* u2 phy bank */ #define SSUSB_SIFSLV_V1_U2PHY_COM 0x000 -/* u3 phy banks */ +/* u3/pcie/sata phy banks */ #define SSUSB_SIFSLV_V1_U3PHYD 0x000 #define SSUSB_SIFSLV_V1_U3PHYA 0x200 @@ -38,7 +38,7 @@ #define SSUSB_SIFSLV_V2_MISC 0x000 #define SSUSB_SIFSLV_V2_U2FREQ 0x100 #define SSUSB_SIFSLV_V2_U2PHY_COM 0x300 -/* u3 phy banks */ +/* u3/pcie/sata phy banks */ #define SSUSB_SIFSLV_V2_SPLLC 0x000 #define SSUSB_SIFSLV_V2_CHIP 0x100 #define SSUSB_SIFSLV_V2_U3PHYD 0x200 @@ -99,6 +99,23 @@ #define P2C_RG_SESSEND BIT(4) #define P2C_RG_AVALID BIT(2) +#define U3P_U3_CHIP_GPIO_CTLD 0x0c +#define P3C_REG_IP_SW_RST BIT(31) +#define P3C_MCU_BUS_CK_GATE_EN BIT(30) +#define P3C_FORCE_IP_SW_RST BIT(29) + +#define U3P_U3_CHIP_GPIO_CTLE 0x10 +#define P3C_RG_SWRST_U3_PHYD BIT(25) +#define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24) + +#define U3P_U3_PHYA_REG0 0x000 +#define P3A_RG_CLKDRV_OFF GENMASK(3, 2) +#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2) + +#define U3P_U3_PHYA_REG1 0x004 +#define P3A_RG_CLKDRV_AMP GENMASK(31, 29) +#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29) + #define U3P_U3_PHYA_REG6 0x018 #define P3A_RG_TX_EIDLE_CM GENMASK(31, 28) #define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28) @@ -108,9 +125,40 @@ #define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1) #define U3P_U3_PHYA_DA_REG0 0x100 +#define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16) +#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16) +#define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12) +#define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12) #define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10) #define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10) +#define U3P_U3_PHYA_DA_REG4 0x108 +#define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19) +#define P3A_RG_PLL_BC_PE2H GENMASK(7, 6) +#define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6) + +#define U3P_U3_PHYA_DA_REG5 0x10c +#define P3A_RG_PLL_BR_PE2H GENMASK(29, 28) +#define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28) +#define P3A_RG_PLL_IC_PE2H GENMASK(15, 12) +#define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12) + +#define U3P_U3_PHYA_DA_REG6 0x110 +#define P3A_RG_PLL_IR_PE2H GENMASK(19, 16) +#define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16) + +#define U3P_U3_PHYA_DA_REG7 0x114 +#define P3A_RG_PLL_BP_PE2H GENMASK(19, 16) +#define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16) + +#define U3P_U3_PHYA_DA_REG20 0x13c +#define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16) +#define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16) + +#define U3P_U3_PHYA_DA_REG25 0x148 +#define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0) +#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x)) + #define U3P_U3_PHYD_LFPS1 0x00c #define P3D_RG_FWAKE_TH GENMASK(21, 16) #define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16) @@ -151,15 +199,74 @@ #define U3P_SR_COEF_DIVISOR 1000 #define U3P_FM_DET_CYCLE_CNT 1024 -enum mt_phy_version { - MT_PHY_V1 = 1, - MT_PHY_V2, +/* SATA register setting */ +#define PHYD_CTRL_SIGNAL_MODE4 0x1c +/* CDR Charge Pump P-path current adjustment */ +#define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20) +#define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20) +#define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8) +#define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8) + +#define PHYD_DESIGN_OPTION2 0x24 +/* Symbol lock count selection */ +#define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4) +#define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4) + +#define PHYD_DESIGN_OPTION9 0x40 +/* COMWAK GAP width window */ +#define RG_TG_MAX_MSK GENMASK(20, 16) +#define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16) +/* COMINIT GAP width window */ +#define RG_T2_MAX_MSK GENMASK(13, 8) +#define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8) +/* COMWAK GAP width window */ +#define RG_TG_MIN_MSK GENMASK(7, 5) +#define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5) +/* COMINIT GAP width window */ +#define RG_T2_MIN_MSK GENMASK(4, 0) +#define RG_T2_MIN_VAL(x) (0x1f & (x)) + +#define ANA_RG_CTRL_SIGNAL1 0x4c +/* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */ +#define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8) +#define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8) + +#define ANA_RG_CTRL_SIGNAL4 0x58 +#define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20) +#define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20) +/* Loop filter R1 resistance adjustment for Gen1 speed */ +#define RG_CDR_BR_GEN2_MSK GENMASK(10, 8) +#define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8) + +#define ANA_RG_CTRL_SIGNAL6 0x60 +/* I-path capacitance adjustment for Gen1 */ +#define RG_CDR_BC_GEN1_MSK GENMASK(28, 24) +#define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24) +#define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0) +#define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x)) + +#define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c +/* RX Gen1 LEQ tuning step */ +#define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8) +#define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8) + +#define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8 +#define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16) +#define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16) + +#define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc +#define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) +#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) + +enum mtk_phy_version { + MTK_PHY_V1 = 1, + MTK_PHY_V2, }; -struct mt65xx_phy_pdata { +struct mtk_phy_pdata { /* avoid RX sensitivity level degradation only for mt8173 */ bool avoid_rx_sen_degradation; - enum mt_phy_version version; + enum mtk_phy_version version; }; struct u2phy_banks { @@ -175,7 +282,7 @@ struct u3phy_banks { void __iomem *phya; /* include u3phya_da */ }; -struct mt65xx_phy_instance { +struct mtk_phy_instance { struct phy *phy; void __iomem *port_base; union { @@ -187,18 +294,18 @@ struct mt65xx_phy_instance { u8 type; }; -struct mt65xx_u3phy { +struct mtk_tphy { struct device *dev; void __iomem *sif_base; /* only shared sif */ /* deprecated, use @ref_clk instead in phy instance */ struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */ - const struct mt65xx_phy_pdata *pdata; - struct mt65xx_phy_instance **phys; + const struct mtk_phy_pdata *pdata; + struct mtk_phy_instance **phys; int nphys; }; -static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, - struct mt65xx_phy_instance *instance) +static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) { struct u2phy_banks *u2_banks = &instance->u2_banks; void __iomem *fmreg = u2_banks->fmreg; @@ -222,7 +329,7 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, tmp = readl(fmreg + U3P_U2FREQ_FMCR0); tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL); tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT); - if (u3phy->pdata->version == MT_PHY_V1) + if (tphy->pdata->version == MTK_PHY_V1) tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1); writel(tmp, fmreg + U3P_U2FREQ_FMCR0); @@ -257,7 +364,7 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, /* if FM detection fail, set default value */ calibration_val = 4; } - dev_dbg(u3phy->dev, "phy:%d, fm_out:%d, calib:%d\n", + dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d\n", instance->index, fm_out, calibration_val); /* set HS slew rate */ @@ -272,8 +379,8 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, writel(tmp, com + U3P_USBPHYACR5); } -static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy, - struct mt65xx_phy_instance *instance) +static void u3_phy_instance_init(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) { struct u3phy_banks *u3_banks = &instance->u3_banks; u32 tmp; @@ -319,11 +426,11 @@ static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy, tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10); writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2); - dev_dbg(u3phy->dev, "%s(%d)\n", __func__, instance->index); + dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); } -static void phy_instance_init(struct mt65xx_u3phy *u3phy, - struct mt65xx_phy_instance *instance) +static void u2_phy_instance_init(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) { struct u2phy_banks *u2_banks = &instance->u2_banks; void __iomem *com = u2_banks->com; @@ -355,7 +462,7 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy, writel(tmp, com + U3P_U2PHYACR4); } - if (u3phy->pdata->avoid_rx_sen_degradation) { + if (tphy->pdata->avoid_rx_sen_degradation) { if (!index) { tmp = readl(com + U3P_USBPHYACR2); tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; @@ -381,11 +488,11 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy, tmp |= PA6_RG_U2_SQTH_VAL(2); writel(tmp, com + U3P_USBPHYACR6); - dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index); + dev_dbg(tphy->dev, "%s(%d)\n", __func__, index); } -static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, - struct mt65xx_phy_instance *instance) +static void u2_phy_instance_power_on(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) { struct u2phy_banks *u2_banks = &instance->u2_banks; void __iomem *com = u2_banks->com; @@ -408,7 +515,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, tmp &= ~P2C_RG_SESSEND; writel(tmp, com + U3P_U2PHYDTM1); - if (u3phy->pdata->avoid_rx_sen_degradation && index) { + if (tphy->pdata->avoid_rx_sen_degradation && index) { tmp = readl(com + |