phy: for 4.12
*) Add new PHY driver for Qualcomm's QMP PHY (used by PCIe, UFS and USB) *) Add new PHY driver for Qualcomm's QUSB2 PHY *) Add support for vbus regulator in rockchip-usb driver *) Add support for usb2-phy in rk3328 to rockchip-inno-usb2 driver *) Add support for a new version of PHY in phy-mt65xx-usb3 driver *) Add support for Allwinner A64 PHY to switch between MUSB and EHCI/OHCI *) Cleanups in Exynos driver and phy-mt65xx-usb3 driver Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJY62nSAAoJEA5ceFyATYLZWkoP/2lImyWp5P61S8cOdvli1SHj J/TIfcyGyvwTQPtUdYGQmgS0JfBtXkSqu5y5E+diIyZMSSLsob7udJ+qeO4WWtOQ wNOm2MTNAyOvbYqdhEiUWRXGLhCkVmhfFoUG5tB2FXnOHMDVc14PFh3U1PmqETWN QIL3oc44L9JGgeGcYvGWJHm1pcLxD7eHPzkeqS4+KJfX4ehFo5kuZId1K7YM5cdZ EgQ8UQy93jDB2t/0x6wrd7MQ+saSiB8gg7U6UOBR7cm57pXBvs1LTvk6qqIGSG3r xmlYyI/N3QaU7Z3yGpCRyMGj7JZslBAzYBX/U0s6sio4IcQT5Vyp3moSnTjCexR0 LIpZJoiTf45hZ6JUIxRrPFM9UG6vKVhobtXHzLwbRiSQxN1IPmT+j9HsDEBHdmvu qNGwkciuaBsS5hRJeIs7gR52wCt8PRKH1riXbeTi5O1t/h98pnf5Dlasvtvl9E20 cMa3o/8YSrwspOXqJ8er4rHc3SEKb+FLBHko/unqK1Sf3xOEaU4lle4F459P7MVN 2btEvSlOKbgYwnlOuKw7xwZX3rmNnPh/IZpqRLlI0vf4OvlabaW1u+toirCaaD2K Jkfw2yvy41qXfD/4ERH9NcWmryhgRHTV1KCpmQGNzJdk8RTZAoRd8EOSuQ4kZBKr NCx4jg4+N8llxItXXXFF =7TO8 -----END PGP SIGNATURE----- Merge tag 'phy-for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next Kishon writes: phy: for 4.12 *) Add new PHY driver for Qualcomm's QMP PHY (used by PCIe, UFS and USB) *) Add new PHY driver for Qualcomm's QUSB2 PHY *) Add support for vbus regulator in rockchip-usb driver *) Add support for usb2-phy in rk3328 to rockchip-inno-usb2 driver *) Add support for a new version of PHY in phy-mt65xx-usb3 driver *) Add support for Allwinner A64 PHY to switch between MUSB and EHCI/OHCI *) Cleanups in Exynos driver and phy-mt65xx-usb3 driver Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
commit
a6308d700b
|
@ -6,12 +6,11 @@ This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
|
|||
Required properties (controller (parent) node):
|
||||
- compatible : should be one of
|
||||
"mediatek,mt2701-u3phy"
|
||||
"mediatek,mt2712-u3phy"
|
||||
"mediatek,mt8173-u3phy"
|
||||
- reg : offset and length of register for phy, exclude port's
|
||||
register.
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain
|
||||
- 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
|
||||
"u3phya_ref": for reference clock of usb3.0 analog phy.
|
||||
|
||||
Required nodes : a sub-node is required for each port the controller
|
||||
|
@ -19,8 +18,19 @@ Required nodes : a sub-node is required for each port the controller
|
|||
'reg' property is used inside these nodes to describe
|
||||
the controller's topology.
|
||||
|
||||
Optional properties (controller (parent) node):
|
||||
- reg : offset and length of register shared by multiple ports,
|
||||
exclude port's private register. It is needed on mt2701
|
||||
and mt8173, but not on mt2712.
|
||||
|
||||
Required properties (port (child) node):
|
||||
- reg : address and length of the register set for the port.
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain
|
||||
"ref": 48M reference clock for HighSpeed analog phy; and 26M
|
||||
reference clock for SuperSpeed analog phy, sometimes is
|
||||
24M, 25M or 27M, depended on platform.
|
||||
- #phy-cells : should be 1 (See second example)
|
||||
cell after port phandle is phy type from:
|
||||
- PHY_TYPE_USB2
|
||||
|
@ -31,21 +41,31 @@ Example:
|
|||
u3phy: usb-phy@11290000 {
|
||||
compatible = "mediatek,mt8173-u3phy";
|
||||
reg = <0 0x11290000 0 0x800>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||
clock-names = "u3phya_ref";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
status = "okay";
|
||||
|
||||
phy_port0: port@11290800 {
|
||||
reg = <0 0x11290800 0 0x800>;
|
||||
u2port0: usb-phy@11290800 {
|
||||
reg = <0 0x11290800 0 0x100>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
phy_port1: port@11291000 {
|
||||
reg = <0 0x11291000 0 0x800>;
|
||||
u3port0: usb-phy@11290900 {
|
||||
reg = <0 0x11290800 0 0x700>;
|
||||
clocks = <&clk26m>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
u2port1: usb-phy@11291000 {
|
||||
reg = <0 0x11291000 0 0x100>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
@ -64,7 +84,54 @@ Example:
|
|||
|
||||
usb30: usb@11270000 {
|
||||
...
|
||||
phys = <&phy_port0 PHY_TYPE_USB3>;
|
||||
phy-names = "usb3-0";
|
||||
phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
|
||||
phy-names = "usb2-0", "usb3-0";
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
Layout differences of banks between mt8173/mt2701 and mt2712
|
||||
-------------------------------------------------------------
|
||||
mt8173 and mt2701:
|
||||
port offset bank
|
||||
shared 0x0000 SPLLC
|
||||
0x0100 FMREG
|
||||
u2 port0 0x0800 U2PHY_COM
|
||||
u3 port0 0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 U2PHY_COM
|
||||
u3 port1 0x1100 U3PHYD
|
||||
0x1200 U3PHYD_BANK2
|
||||
0x1300 U3PHYA
|
||||
0x1400 U3PHYA_DA
|
||||
u2 port2 0x1800 U2PHY_COM
|
||||
...
|
||||
|
||||
mt2712:
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u3 port0 0x0700 SPLLC
|
||||
0x0800 CHIP
|
||||
0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u3 port1 0x1700 SPLLC
|
||||
0x1800 CHIP
|
||||
0x1900 U3PHYD
|
||||
0x1a00 U3PHYD_BANK2
|
||||
0x1b00 U3PHYA
|
||||
0x1c00 U3PHYA_DA
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
|
||||
SPLLC shared by u3 ports and FMREG shared by u2 ports on
|
||||
mt8173/mt2701 are put back into each port; a new bank MISC for
|
||||
u2 ports and CHIP for u3 ports are added on mt2712.
|
||||
|
|
|
@ -2,6 +2,7 @@ ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
|
|||
|
||||
Required properties (phy (parent) node):
|
||||
- compatible : should be one of the listed compatibles:
|
||||
* "rockchip,rk3328-usb2phy"
|
||||
* "rockchip,rk3366-usb2phy"
|
||||
* "rockchip,rk3399-usb2phy"
|
||||
- reg : the address offset of grf for usb-phy configuration.
|
||||
|
@ -11,6 +12,11 @@ Required properties (phy (parent) node):
|
|||
Optional properties:
|
||||
- clocks : phandle + phy specifier pair, for the input clock of phy.
|
||||
- clock-names : input clock name of phy, must be "phyclk".
|
||||
- assigned-clocks : phandle of usb 480m clock.
|
||||
- assigned-clock-parents : parent of usb 480m clock, select between
|
||||
usb-phy output 480m and xin24m.
|
||||
Refer to clk/clock-bindings.txt for generic clock
|
||||
consumer properties.
|
||||
|
||||
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,
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
Qualcomm QMP PHY controller
|
||||
===========================
|
||||
|
||||
QMP phy controller supports physical layer functionality for a number of
|
||||
controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
|
||||
|
||||
Required properties:
|
||||
- compatible: compatible list, contains:
|
||||
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
|
||||
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
|
||||
|
||||
- reg: offset and length of register set for PHY's common serdes block.
|
||||
|
||||
- #clock-cells: must be 1
|
||||
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
|
||||
interface (for pipe based PHYs). These clock are then gate-controlled
|
||||
by gcc.
|
||||
- #address-cells: must be 1
|
||||
- #size-cells: must be 1
|
||||
- ranges: must be present
|
||||
|
||||
- clocks: a list of phandles and clock-specifier pairs,
|
||||
one for each entry in clock-names.
|
||||
- clock-names: "cfg_ahb" for phy config clock,
|
||||
"aux" for phy aux clock,
|
||||
"ref" for 19.2 MHz ref clk,
|
||||
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
||||
"aux", "cfg_ahb", "ref".
|
||||
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
||||
"aux", "cfg_ahb", "ref".
|
||||
|
||||
- resets: a list of phandles and reset controller specifier pairs,
|
||||
one for each entry in reset-names.
|
||||
- reset-names: "phy" for reset of phy block,
|
||||
"common" for phy common block reset,
|
||||
"cfg" for phy's ahb cfg block reset (Optional).
|
||||
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
||||
"phy", "common", "cfg".
|
||||
For "qcom,msm8996-qmp-usb3-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.
|
||||
|
||||
Optional properties:
|
||||
- vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
|
||||
pll block.
|
||||
|
||||
Required nodes:
|
||||
- Each device node of QMP phy is required to have as many child nodes as
|
||||
the number of lanes the PHY has.
|
||||
|
||||
Required properties for child node:
|
||||
- reg: list of offset and length pairs of register sets for PHY blocks -
|
||||
tx, rx and pcs.
|
||||
|
||||
- #phy-cells: must be 0
|
||||
|
||||
- clocks: a list of phandles and clock-specifier pairs,
|
||||
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.
|
||||
|
||||
- resets: a list of phandles and reset controller specifier pairs,
|
||||
one for each entry in reset-names.
|
||||
- reset-names: Must contain following for pcie qmp phys:
|
||||
"lane<lane-number>" for reset specific to each lane.
|
||||
|
||||
Example:
|
||||
phy@34000 {
|
||||
compatible = "qcom,msm8996-qmp-pcie-phy";
|
||||
reg = <0x34000 0x488>;
|
||||
#clock-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
|
||||
<&gcc GCC_PCIE_PHY_CFG_AHB_CLK>,
|
||||
<&gcc GCC_PCIE_CLKREF_CLK>;
|
||||
clock-names = "aux", "cfg_ahb", "ref";
|
||||
|
||||
vdda-phy-supply = <&pm8994_l28>;
|
||||
vdda-pll-supply = <&pm8994_l12>;
|
||||
|
||||
resets = <&gcc GCC_PCIE_PHY_BCR>,
|
||||
<&gcc GCC_PCIE_PHY_COM_BCR>,
|
||||
<&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>;
|
||||
reset-names = "phy", "common", "cfg";
|
||||
|
||||
pciephy_0: lane@35000 {
|
||||
reg = <0x35000 0x130>,
|
||||
<0x35200 0x200>,
|
||||
<0x35400 0x1dc>;
|
||||
#phy-cells = <0>;
|
||||
|
||||
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
|
||||
clock-names = "pipe0";
|
||||
resets = <&gcc GCC_PCIE_0_PHY_BCR>;
|
||||
reset-names = "lane0";
|
||||
};
|
||||
|
||||
pciephy_1: lane@36000 {
|
||||
...
|
||||
...
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
Qualcomm QUSB2 phy controller
|
||||
=============================
|
||||
|
||||
QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
|
||||
|
||||
Required properties:
|
||||
- compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
|
||||
- reg: offset and length of the PHY register set.
|
||||
- #phy-cells: must be 0.
|
||||
|
||||
- clocks: a list of phandles and clock-specifier pairs,
|
||||
one for each entry in clock-names.
|
||||
- clock-names: must be "cfg_ahb" for phy config clock,
|
||||
"ref" for 19.2 MHz ref clk,
|
||||
"iface" for phy interface clock (Optional).
|
||||
|
||||
- vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
|
||||
- vdda-phy-dpdm-supply: Phandle to 3.1V regulator supply to Dp/Dm port signals.
|
||||
|
||||
- resets: Phandle to reset to phy block.
|
||||
|
||||
Optional properties:
|
||||
- nvmem-cells: Phandle to nvmem cell that contains 'HS Tx trim'
|
||||
tuning parameter value for qusb2 phy.
|
||||
|
||||
- qcom,tcsr-syscon: Phandle to TCSR syscon register region.
|
||||
|
||||
Example:
|
||||
hsusb_phy: phy@7411000 {
|
||||
compatible = "qcom,msm8996-qusb2-phy";
|
||||
reg = <0x7411000 0x180>;
|
||||
#phy-cells = <0>;
|
||||
|
||||
clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
|
||||
<&gcc GCC_RX1_USB2_CLKREF_CLK>,
|
||||
clock-names = "cfg_ahb", "ref";
|
||||
|
||||
vdda-pll-supply = <&pm8994_l12>;
|
||||
vdda-phy-dpdm-supply = <&pm8994_l24>;
|
||||
|
||||
resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
|
||||
nvmem-cells = <&qusb2p_hstx_trim>;
|
||||
};
|
|
@ -30,6 +30,7 @@ Optional Properties:
|
|||
- reset-names: Only allow the following entries:
|
||||
- phy-reset
|
||||
- resets: Must contain an entry for each entry in reset-names.
|
||||
- vbus-supply: power-supply phandle for vbus power source
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ Required properties:
|
|||
- reg : a list of offset + length pairs
|
||||
- reg-names :
|
||||
* "phy_ctrl"
|
||||
* "pmu0" for H3, V3s and A64
|
||||
* "pmu1"
|
||||
* "pmu2" for sun4i, sun6i or sun7i
|
||||
- #phy-cells : from the generic phy bindings, must be 1
|
||||
|
|
|
@ -8,6 +8,8 @@ From RK3368 SoCs, the GRF is divided into two sections,
|
|||
- SGRF, used for general secure system,
|
||||
- PMUGRF, used for always on system
|
||||
|
||||
On RK3328 SoCs, the GRF adds a section for USB2PHYGRF,
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: GRF should be one of the following:
|
||||
|
@ -23,6 +25,8 @@ Required Properties:
|
|||
- "rockchip,rk3399-pmugrf", "syscon": for rk3399
|
||||
- compatible: SGRF should be one of the following
|
||||
- "rockchip,rk3288-sgrf", "syscon": for rk3288
|
||||
- compatible: USB2PHYGRF should be one of the followings
|
||||
- "rockchip,rk3328-usb2phy-grf", "syscon": for rk3328
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* LPASS Top register definitions */
|
||||
|
@ -83,7 +83,7 @@ static void exynos_lpass_enable(struct exynos_lpass *lpass)
|
|||
|
||||
/* Activate related PADs from retention state */
|
||||
regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION,
|
||||
EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR);
|
||||
EXYNOS_WAKEUP_FROM_LOWPWR);
|
||||
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
|
||||
|
|
|
@ -439,6 +439,25 @@ config PHY_STIH407_USB
|
|||
Enable this support to enable the picoPHY device used by USB2
|
||||
and USB3 controllers on STMicroelectronics STiH407 SoC families.
|
||||
|
||||
config PHY_QCOM_QMP
|
||||
tristate "Qualcomm QMP PHY Driver"
|
||||
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the QMP PHY transceiver that is used
|
||||
with controllers such as PCIe, UFS, and USB on Qualcomm chips.
|
||||
|
||||
config PHY_QCOM_QUSB2
|
||||
tristate "Qualcomm QUSB2 PHY Driver"
|
||||
depends on OF && (ARCH_QCOM || COMPILE_TEST)
|
||||
depends on NVMEM || !NVMEM
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the HighSpeed QUSB2 PHY transceiver for USB
|
||||
controllers on Qualcomm chips. This driver supports the high-speed
|
||||
PHY which is usually paired with either the ChipIdea or Synopsys DWC3
|
||||
USB IPs on MSM SOCs.
|
||||
|
||||
config PHY_QCOM_UFS
|
||||
tristate "Qualcomm UFS PHY driver"
|
||||
depends on OF && ARCH_QCOM
|
||||
|
|
|
@ -50,6 +50,8 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
|
|||
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
|
||||
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
|
||||
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
|
||||
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
|
||||
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
|
||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
|
||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Broadcom Northstar USB 3.0 PHY Driver
|
||||
*
|
||||
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
|
||||
* Copyright (C) 2016 Broadcom
|
||||
*
|
||||
* All magic values used for initialization (and related comments) were obtained
|
||||
* from Broadcom's SDK:
|
||||
|
@ -23,6 +24,23 @@
|
|||
|
||||
#define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */
|
||||
|
||||
#define BCM_NS_USB3_PHY_BASE_ADDR_REG 0x1f
|
||||
#define BCM_NS_USB3_PHY_PLL30_BLOCK 0x8000
|
||||
#define BCM_NS_USB3_PHY_TX_PMD_BLOCK 0x8040
|
||||
#define BCM_NS_USB3_PHY_PIPE_BLOCK 0x8060
|
||||
|
||||
/* Registers of PLL30 block */
|
||||
#define BCM_NS_USB3_PLL_CONTROL 0x01
|
||||
#define BCM_NS_USB3_PLLA_CONTROL0 0x0a
|
||||
#define BCM_NS_USB3_PLLA_CONTROL1 0x0b
|
||||
|
||||
/* Registers of TX PMD block */
|
||||
#define BCM_NS_USB3_TX_PMD_CONTROL1 0x01
|
||||
|
||||
/* Registers of PIPE block */
|
||||
#define BCM_NS_USB3_LFPS_CMP 0x02
|
||||
#define BCM_NS_USB3_LFPS_DEGLITCH 0x03
|
||||
|
||||
enum bcm_ns_family {
|
||||
BCM_NS_UNKNOWN,
|
||||
BCM_NS_AX,
|
||||
|
@ -76,8 +94,10 @@ static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3)
|
|||
usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US));
|
||||
}
|
||||
|
||||
static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
|
||||
static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg,
|
||||
u16 value)
|
||||
{
|
||||
u32 tmp = 0;
|
||||
int err;
|
||||
|
||||
err = bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||
|
@ -86,7 +106,11 @@ static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
|
|||
return err;
|
||||
}
|
||||
|
||||
writel(value, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA);
|
||||
/* TODO: Use a proper MDIO bus layer */
|
||||
tmp |= 0x58020000; /* Magic value for MDIO PHY write */
|
||||
tmp |= reg << 18;
|
||||
tmp |= value;
|
||||
writel(tmp, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,21 +126,22 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
|
|||
udelay(2);
|
||||
|
||||
/* USB3 PLL Block */
|
||||
err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
|
||||
err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||
BCM_NS_USB3_PHY_PLL30_BLOCK);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Assert Ana_Pllseq start */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061000);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x1000);
|
||||
|
||||
/* Assert CML Divider ratio to 26 */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400);
|
||||
|
||||
/* Asserting PLL Reset */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582ec000);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0xc000);
|
||||
|
||||
/* Deaaserting PLL Reset */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582e8000);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0x8000);
|
||||
|
||||
/* Waiting MII Mgt interface idle */
|
||||
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||
|
@ -125,22 +150,24 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
|
|||
writel(0, usb3->dmp + BCMA_RESET_CTL);
|
||||
|
||||
/* PLL frequency monitor enable */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58069000);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x9000);
|
||||
|
||||
/* PIPE Block */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8060);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||
BCM_NS_USB3_PHY_PIPE_BLOCK);
|
||||
|
||||
/* CMPMAX & CMPMINTH setting */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580af30d);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_CMP, 0xf30d);
|
||||
|
||||
/* DEGLITCH MIN & MAX setting */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580e6302);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_DEGLITCH, 0x6302);
|
||||
|
||||
/* TXPMD block */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||
BCM_NS_USB3_PHY_TX_PMD_BLOCK);
|
||||
|
||||
/* Enabling SSC */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003);
|
||||
|
||||
/* Waiting MII Mgt interface idle */
|
||||
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||
|
@ -159,22 +186,24 @@ static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3)
|
|||
udelay(2);
|
||||
|
||||
/* PLL30 block */
|
||||
err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
|
||||
err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||
BCM_NS_USB3_PHY_PLL30_BLOCK);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400);
|
||||
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e80e0);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 0x80e0);
|
||||
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580a009c);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x009c);
|
||||
|
||||
/* Enable SSC */
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||
BCM_NS_USB3_PHY_TX_PMD_BLOCK);
|
||||
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580a21d3);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x21d3);
|
||||
|
||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
|
||||
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003);
|
||||
|
||||
/* Waiting MII Mgt interface idle */
|
||||
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||
|
||||
struct exynos_dp_video_phy_drvdata {
|
||||
u32 phy_ctrl_offset;
|
||||
|
@ -36,7 +36,7 @@ static int exynos_dp_video_phy_power_on(struct phy *phy)
|
|||
|
||||
/* Disable power isolation on DP-PHY */
|
||||
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
|
||||
EXYNOS5_PHY_ENABLE, EXYNOS5_PHY_ENABLE);
|
||||
EXYNOS4_PHY_ENABLE, EXYNOS4_PHY_ENABLE);
|
||||
}
|
||||
|
||||
static int exynos_dp_video_phy_power_off(struct phy *phy)
|
||||
|
@ -45,7 +45,7 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
|
|||
|
||||
/* Enable power isolation on DP-PHY */
|
||||
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
|
||||
EXYNOS5_PHY_ENABLE, 0);
|
||||
EXYNOS4_PHY_ENABLE, 0);
|
||||
}
|
||||
|
||||
static const struct phy_ops exynos_dp_video_phy_ops = {
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon/exynos4-pmu.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -21,6 +19,7 @@
|
|||
#include <linux/phy/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
enum exynos_mipi_phy_id {
|
||||
|
@ -64,7 +63,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||
{
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
|
@ -73,7 +72,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||
|
@ -82,7 +81,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
|
@ -91,7 +90,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||
|
@ -109,47 +108,47 @@ static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
|
|||
{
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
},
|
||||
},
|
||||
|
@ -172,8 +171,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||
{
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(0),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
||||
|
@ -181,8 +180,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(0),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
||||
|
@ -190,8 +189,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(1),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
||||
|
@ -199,8 +198,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(1),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
||||
|
@ -208,8 +207,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL,
|
||||
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(2),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(0),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
@ -228,7 +228,6 @@ static const struct of_device_id exynos_pcie_phy_match[] = {
|
|||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_pcie_phy_match);
|
||||
|
||||
static int exynos_pcie_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -278,8 +277,5 @@ static struct platform_driver exynos_pcie_phy_driver = {
|
|||
.name = "exynos_pcie_phy",
|
||||
}
|
||||
};
|
||||
module_platform_driver(exynos_pcie_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC PCIe PHY driver");
|
||||
MODULE_AUTHOR("Jaehoon Chung <jh80.chung@samsung.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
builtin_platform_driver(exynos_pcie_phy_driver);
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||
|
||||
/* Exynos USB PHY registers */
|
||||
#define EXYNOS5_FSEL_9MHZ6 0x0
|
||||
|
@ -235,10 +235,10 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
|
|||
if (!inst->reg_pmu)
|
||||
return;
|
||||
|
||||
val = on ? 0 : EXYNOS5_PHY_ENABLE;
|
||||
val = on ? 0 : EXYNOS4_PHY_ENABLE;
|
||||
|
||||
regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
|
||||
EXYNOS5_PHY_ENABLE, val);
|
||||
EXYNOS4_PHY_ENABLE, val);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -81,9 +81,9 @@
|
|||
#define REG_ADP_BC_ACA_PIN_GND BIT(25)
|
||||
#define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
|
||||
|
||||
#define REG_DBG_UART 0x14
|
||||
#define REG_DBG_UART 0x10
|
||||
|
||||
#define REG_TEST 0x18
|
||||
#define REG_TEST 0x14
|
||||
#define REG_TEST_DATA_IN_MASK GENMASK(3, 0)
|
||||
#define REG_TEST_EN_MASK GENMASK(7, 4)
|
||||
#define REG_TEST_ADDR_MASK GENMASK(11, 8)
|
||||
|
@ -93,7 +93,7 @@
|
|||
#define REG_TEST_DATA_OUT_MASK GENMASK(19, 16)
|
||||
#define REG_TEST_DISABLE_ID_PULLUP BIT(20)
|
||||
|
||||
#define REG_TUNE 0x1c
|
||||
#define REG_TUNE 0x18
|
||||
#define REG_TUNE_TX_RES_TUNE_MASK GENMASK(1, 0)
|
||||
#define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2)
|
||||
#define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4)
|
||||
|
|
|
@ -23,47 +23,55 @@
|
|||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* for sifslv2 register, but exclude port's;
|
||||
* relative to USB3_SIF2_BASE base address
|
||||
*/
|
||||
#define SSUSB_SIFSLV_SPLLC 0x0000
|
||||
#define SSUSB_SIFSLV_U2FREQ 0x0100
|
||||
/* version V1 sub-banks offset base address */
|
||||
/* banks shared by multiple phys */
|
||||
#define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
|
||||
#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
|
||||
/* u2 phy bank */
|
||||
#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
|
||||
/* u3 phy banks */
|
||||
#define SSUSB_SIFSLV_V1_U3PHYD 0x000
|
||||
#define SSUSB_SIFSLV_V1_U3PHYA 0x200
|
||||
|
||||
/* offsets of sub-segment in each port registers */
|
||||
#define SSUSB_SIFSLV_U2PHY_COM_BASE 0x0000
|
||||
#define SSUSB_SIFSLV_U3PHYD_BASE 0x0100
|
||||
#define SSUSB_USB30_PHYA_SIV_B_BASE 0x0300
|
||||
#define SSUSB_SIFSLV_U3PHYA_DA_BASE 0x0400
|
||||
/* version V2 sub-banks offset base address */
|
||||
/* u2 phy banks */
|
||||
#define SSUSB_SIFSLV_V2_MISC 0x000
|
||||
#define SSUSB_SIFSLV_V2_U2FREQ 0x100
|
||||
#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
|
||||
/* u3 phy banks */
|
||||
#define SSUSB_SIFSLV_V2_SPLLC 0x000
|
||||
#define SSUSB_SIFSLV_V2_CHIP 0x100
|
||||
#define SSUSB_SIFSLV_V2_U3PHYD 0x200
|
||||
#define SSUSB_SIFSLV_V2_U3PHYA 0x400
|
||||
|
||||
#define U3P_USBPHYACR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0000)
|
||||
#define U3P_USBPHYACR0 0x000
|
||||
#define PA0_RG_U2PLL_FORCE_ON BIT(15)
|
||||
#define PA0_RG_USB20_INTR_EN BIT(5)
|
||||
|
||||
#define U3P_USBPHYACR2 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0008)
|
||||
#define U3P_USBPHYACR2 0x008
|
||||
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
|
||||
|
||||
#define U3P_USBPHYACR5 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0014)
|
||||
#define U3P_USBPHYACR5 0x014
|
||||
#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
|
||||
#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
|
||||
#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
|
||||
#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
|
||||
|
||||
#define U3P_USBPHYACR6 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0018)
|
||||
#define PA6_RG_U2_ISO_EN BIT(31)
|
||||
#define U3P_USBPHYACR6 0x018
|
||||
#define PA6_RG_U2_BC11_SW_EN BIT(23)
|
||||
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
|
||||
#define PA6_RG_U2_SQTH GENMASK(3, 0)
|
||||
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
|
||||
|
||||
#define U3P_U2PHYACR4 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0020)
|
||||
#define U3P_U2PHYACR4 0x020
|
||||
#define P2C_RG_USB20_GPIO_CTL BIT(9)
|
||||
#define P2C_USB20_GPIO_MODE BIT(8)
|
||||
#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
|
||||
|
||||
#define U3D_U2PHYDCR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0060)
|
||||
#define U3D_U2PHYDCR0 0x060
|
||||
#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
|
||||
|
||||
#define U3P_U2PHYDTM0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0068)
|
||||
#define U3P_U2PHYDTM0 0x068
|
||||
#define P2C_FORCE_UART_EN BIT(26)
|
||||
#define P2C_FORCE_DATAIN BIT(23)
|
||||
#define P2C_FORCE_DM_PULLDOWN BIT(21)
|
||||
|
@ -85,47 +93,56 @@
|
|||
P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
|
||||
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
|
||||
|
||||
#define U3P_U2PHYDTM1 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x006C)
|
||||
#define U3P_U2PHYDTM1 0x06C
|
||||
#define P2C_RG_UART_EN BIT(16)
|
||||
#define P2C_RG_VBUSVALID BIT(5)
|
||||
#define P2C_RG_SESSEND BIT(4)
|
||||
#define P2C_RG_AVALID BIT(2)
|
||||
|
||||
#define U3P_U3_PHYA_REG0 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0000)
|
||||
#define P3A_RG_U3_VUSB10_ON BIT(5)
|
||||
|
||||
#define U3P_U3_PHYA_REG6 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0018)
|
||||
#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)
|
||||
|
||||
#define U3P_U3_PHYA_REG9 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0024)
|
||||
#define U3P_U3_PHYA_REG9 0x024
|
||||
#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
|
||||
#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
|
||||
|
||||
#define U3P_U3PHYA_DA_REG0 (SSUSB_SIFSLV_U3PHYA_DA_BASE + 0x0000)
|
||||
#define U3P_U3_PHYA_DA_REG0 0x100
|
||||
#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
|
||||
#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
|
||||
|
||||
#define U3P_PHYD_CDR1 (SSUSB_SIFSLV_U3PHYD_BASE + 0x005c)
|
||||
#define U3P_U3_PHYD_LFPS1 0x00c
|
||||
#define P3D_RG_FWAKE_TH GENMASK(21, 16)
|
||||
#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
|
||||
|
||||
#define U3P_U3_PHYD_CDR1 0x05c
|
||||
#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
|
||||
#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
|
||||
#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
|
||||
#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
|
||||
|
||||
#define U3P_XTALCTL3 (SSUSB_SIFSLV_SPLLC + 0x0018)
|
||||
#define U3P_U3_PHYD_RXDET1 0x128
|
||||
#define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
|
||||
#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
|
||||
|
||||
#define U3P_U3_PHYD_RXDET2 0x12c
|
||||
#define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
|
||||
#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
|
||||
|
||||
#define U3P_SPLLC_XTALCTL3 0x018
|
||||
#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
|
||||
#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
|
||||
|
||||
#define U3P_U2FREQ_FMCR0 (SSUSB_SIFSLV_U2FREQ + 0x00)
|
||||
#define U3P_U2FREQ_FMCR0 0x00
|
||||
#define P2F_RG_MONCLK_SEL GENMASK(27, 26)
|
||||
#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
|
||||
#define P2F_RG_FREQDET_EN BIT(24)
|
||||
#define P2F_RG_CYCLECNT GENMASK(23, 0)
|
||||
#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
|
||||
|
||||
#define U3P_U2FREQ_VALUE (SSUSB_SIFSLV_U2FREQ + 0x0c)
|
||||
#define U3P_U2FREQ_VALUE 0x0c
|
||||
|
||||
#define U3P_U2FREQ_FMMONR1 (SSUSB_SIFSLV_U2FREQ + 0x10)
|
||||
#define U3P_U2FREQ_FMMONR1 0x10
|
||||
#define P2F_USB_FM_VALID BIT(0)
|
||||
#define P2F_RG_FRCK_EN BIT(8)
|
||||
|
||||
|
@ -134,21 +151,46 @@
|
|||
#define U3P_SR_COEF_DIVISOR 1000
|
||||
#define U3P_FM_DET_CYCLE_CNT 1024
|
||||
|
||||
enum mt_phy_version {
|
||||
MT_PHY_V1 = 1,
|
||||
MT_PHY_V2,
|
||||
};
|
||||
|
||||
struct mt65xx_phy_pdata {
|
||||
/* avoid RX sensitivity level degradation only for mt8173 */
|
||||
bool avoid_rx_sen_degradation;
|
||||
enum mt_phy_version version;
|
||||
};
|
||||
|
||||
struct u2phy_banks {
|
||||
void __iomem *misc;
|
||||
void __iomem *fmreg;
|
||||
void __iomem *com;
|
||||
};
|
||||
|
||||
struct u3phy_banks {
|
||||
void __iomem *spllc;
|
||||
void __iomem *chip;
|
||||
void __iomem *phyd; /* include u3phyd_bank2 */
|
||||
void __iomem *phya; /* include u3phya_da */
|
||||
};
|
||||
|
||||
struct mt65xx_phy_instance {
|
||||
struct phy *phy;
|
||||
void __iomem *port_base;
|
||||
union {
|
||||
struct u2phy_banks u2_banks;
|
||||
struct u3phy_banks u3_banks;
|
||||
};
|
||||
struct clk *ref_clk; /* reference clock of anolog phy */
|
||||
u32 index;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
struct mt65xx_u3phy {
|
||||
struct device *dev;
|
||||
void __iomem *sif_base; /* include sif2, but exclude port's */
|
||||
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;
|
||||
|
@ -158,49 +200,53 @@ struct mt65xx_u3phy {
|
|||
static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
void __iomem *sif_base = u3phy->sif_base;
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
void __iomem *fmreg = u2_banks->fmreg;
|
||||
void __iomem *com = u2_banks->com;
|
||||
int calibration_val;
|
||||
int fm_out;
|
||||
u32 tmp;
|
||||
|
||||
/* enable USB ring oscillator */
|
||||
tmp = readl(instance->port_base + U3P_USBPHYACR5);
|
||||
tmp = readl(com + U3P_USBPHYACR5);
|
||||
tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
|
||||
writel(tmp, instance->port_base + U3P_USBPHYACR5);
|
||||
writel(tmp, com + U3P_USBPHYACR5);
|
||||
udelay(1);
|
||||
|
||||
/*enable free run clock */
|
||||
tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
|
||||
tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
|
||||
tmp |= P2F_RG_FRCK_EN;
|
||||
writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
|
||||
writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
|
||||
|
||||
/* set cycle count as 1024, and select u2 channel */
|
||||
tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
|
||||
tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
|
||||
tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
|
||||
tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
|
||||
tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index);
|
||||
writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
|
||||
if (u3phy->pdata->version == MT_PHY_V1)
|
||||
tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
|
||||
|
||||
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
|
||||
|
||||
/* enable frequency meter */
|
||||
tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
|
||||
tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
|
||||
tmp |= P2F_RG_FREQDET_EN;
|
||||
writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
|
||||
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
|
||||
|
||||
/* ignore return value */
|
||||
readl_poll_timeout(sif_base + U3P_U2FREQ_FMMONR1, tmp,
|
||||
(tmp & P2F_USB_FM_VALID), 10, 200);
|
||||
readl_poll_timeout(fmreg + U3P_U2FREQ_FMMONR1, tmp,
|
||||
(tmp & P2F_USB_FM_VALID), 10, 200);
|
||||
|
||||
fm_out = readl(sif_base + U3P_U2FREQ_VALUE);
|
||||
fm_out = readl(fmreg + U3P_U2FREQ_VALUE);
|
||||
|
||||
/* disable frequency meter */
|
||||
tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
|
||||
tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
|
||||
tmp &= ~P2F_RG_FREQDET_EN;
|
||||
writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
|
||||
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
|
||||
|
||||
/*disable free run clock */
|
||||
tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
|
||||
tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
|
||||
tmp &= ~P2F_RG_FRCK_EN;
|
||||
writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
|
||||
writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
|
||||
|
||||
if (fm_out) {
|
||||
/* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
|
||||
|
@ -215,85 +261,125 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
|
|||
instance->index, fm_out, calibration_val);
|
||||
|
||||
/* set HS slew rate */
|
||||
tmp = readl(instance->port_base + U3P_USBPHYACR5);
|
||||
tmp = readl(com + U3P_USBPHYACR5);
|
||||
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
|
||||
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
|
||||
writel(tmp, instance->port_base + U3P_USBPHYACR5);
|
||||
writel(tmp, com + U3P_USBPHYACR5);
|
||||
|
||||
/* disable USB ring oscillator */
|
||||
tmp = readl(instance->port_base + U3P_USBPHYACR5);
|
||||
tmp = readl(com + U3P_USBPHYACR5);
|
||||
tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
|
||||
writel(tmp, instance->port_base + U3P_USBPHYACR5);
|
||||
writel(tmp, com + U3P_USBPHYACR5);
|
||||
}
|
||||
|
||||
static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
u32 tmp;
|
||||
|
||||
/* gating PCIe Analog XTAL clock */
|
||||
tmp = readl(u3_banks->spllc + U3P_SPLLC_XTALCTL3);
|
||||
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
|
||||
writel(tmp, u3_banks->spllc + U3P_SPLLC_XTALCTL3);
|
||||
|
||||
/* gating XSQ */
|
||||
tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
|
||||
tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
|
||||
tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
|
||||
writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
|
||||
|
||||
tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG9);
|
||||
tmp &= ~P3A_RG_RX_DAC_MUX;
|
||||
tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
|
||||
writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG9);
|
||||
|
||||
tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG6);
|
||||
tmp &= ~P3A_RG_TX_EIDLE_CM;
|
||||
tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
|
||||
writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG6);
|
||||
|
||||
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_CDR1);
|
||||
tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
|
||||
tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
|
||||
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_CDR1);
|
||||
|
||||
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_LFPS1);
|
||||
tmp &= ~P3D_RG_FWAKE_TH;
|
||||
tmp |= P3D_RG_FWAKE_TH_VAL(0x34);
|
||||
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_LFPS1);
|
||||
|
||||
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1);
|
||||
tmp &= ~P3D_RG_RXDET_STB2_SET;
|
||||
tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10);
|
||||
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
|
||||
|
||||
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2);
|
||||
tmp &= ~P3D_RG_RXDET_STB2_SET_P3;
|
||||
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);
|
||||
}
|
||||
|
||||
static void phy_instance_init(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
void __iomem *port_base = instance->port_base;
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
void __iomem *com = u2_banks->com;
|
||||
u32 index = instance->index;
|
||||
u32 tmp;
|
||||
|
||||
/* switch to USB function. (system register, force ip into usb mode) */
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp &= ~P2C_FORCE_UART_EN;
|
||||
tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM1);
|
||||
tmp = readl(com + U3P_U2PHYDTM1);
|
||||
tmp &= ~P2C_RG_UART_EN;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM1);
|
||||
writel(tmp, com + U3P_U2PHYDTM1);
|
||||
|
||||
tmp = readl(com + U3P_USBPHYACR0);
|
||||
tmp |= PA0_RG_USB20_INTR_EN;
|
||||
writel(tmp, com + U3P_USBPHYACR0);
|
||||
|
||||
/* disable switch 100uA current to SSUSB */
|
||||
tmp = readl(com + U3P_USBPHYACR5);
|
||||
tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
|
||||
writel(tmp, com + U3P_USBPHYACR5);
|
||||
|
||||
if (!index) {
|
||||
tmp = readl(port_base + U3P_U2PHYACR4);
|
||||
tmp = readl(com + U3P_U2PHYACR4);
|
||||
tmp &= ~P2C_U2_GPIO_CTR_MSK;
|
||||
writel(tmp, port_base + U3P_U2PHYACR4);
|
||||
writel(tmp, com + U3P_U2PHYACR4);
|
||||
}
|
||||
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation) {
|
||||
if (!index) {
|
||||
tmp = readl(port_base + U3P_USBPHYACR2);
|
||||
tmp = readl(com + U3P_USBPHYACR2);
|
||||
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR2);
|
||||
writel(tmp, com + U3P_USBPHYACR2);
|
||||
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp = readl(com + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
writel(tmp, com + U3D_U2PHYDCR0);
|
||||
} else {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp = readl(com + U3D_U2PHYDCR0);
|
||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
writel(tmp, com + U3D_U2PHYDCR0);
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
||||
tmp = readl(com + U3P_USBPHYACR6);
|
||||
tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
|
||||
tmp &= ~PA6_RG_U2_SQTH;
|
||||
tmp |= PA6_RG_U2_SQTH_VAL(2);
|
||||
writel(tmp, port_base + U3P_USBPHYACR6);
|
||||
|
||||
tmp = readl(port_base + U3P_U3PHYA_DA_REG0);
|
||||
tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
|
||||
tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
|
||||
writel(tmp, port_base + U3P_U3PHYA_DA_REG0);
|
||||
|
||||
tmp = readl(port_base + U3P_U3_PHYA_REG9);
|
||||
tmp &= ~P3A_RG_RX_DAC_MUX;
|
||||
tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
|
||||
writel(tmp, port_base + U3P_U3_PHYA_REG9);
|
||||
|
||||
tmp = readl(port_base + U3P_U3_PHYA_REG6);
|
||||
tmp &= ~P3A_RG_TX_EIDLE_CM;
|
||||
tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
|
||||
writel(tmp, port_base + U3P_U3_PHYA_REG6);
|
||||
|
||||
tmp = readl(port_base + U3P_PHYD_CDR1);
|
||||
tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
|
||||
tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
|
||||
writel(tmp, port_base + U3P_PHYD_CDR1);
|
||||
writel(tmp, com + U3P_USBPHYACR6);
|
||||
|
||||
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
||||
}
|
||||
|
@ -301,58 +387,35 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
|
|||
static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
void __iomem *port_base = instance->port_base;
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
void __iomem *com = u2_banks->com;
|
||||
u32 index = instance->index;
|
||||
u32 tmp;
|
||||
|
||||
if (!index) {
|
||||
/* Set RG_SSUSB_VUSB10_ON as 1 after VUSB10 ready */
|
||||
tmp = readl(port_base + U3P_U3_PHYA_REG0);
|
||||
tmp |= P3A_RG_U3_VUSB10_ON;
|
||||
writel(tmp, port_base + U3P_U3_PHYA_REG0);
|
||||
}
|
||||
|
||||
/* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
|
||||
tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
|
||||
/* OTG Enable */
|
||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
||||
tmp = readl(com + U3P_USBPHYACR6);
|
||||
tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR6);
|
||||
writel(tmp, com + U3P_USBPHYACR6);
|
||||
|
||||
if (!index) {
|
||||
tmp = readl(u3phy->sif_base + U3P_XTALCTL3);
|
||||
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
|
||||
writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
|
||||
|
||||
/* switch 100uA current to SSUSB */
|
||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
||||
tmp |= PA5_RG_U2_HS_100U_U3_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
||||
}
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM1);
|
||||
tmp = readl(com + U3P_U2PHYDTM1);
|
||||
tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
|
||||
tmp &= ~P2C_RG_SESSEND;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM1);
|
||||
|
||||
/* USB 2.0 slew rate calibration */
|
||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
||||
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
|
||||
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
|
||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
||||
writel(tmp, com + U3P_U2PHYDTM1);
|
||||
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp = readl(com + U3D_U2PHYDCR0);
|
||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
writel(tmp, com + U3D_U2PHYDCR0);
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
}
|
||||
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
||||
}
|
||||
|
@ -360,48 +423,36 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
|||
static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
void __iomem *port_base = instance->port_base;
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
void __iomem *com = u2_banks->com;
|
||||
u32 index = instance->index;
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
|
||||
tmp |= P2C_FORCE_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
|
||||
/* OTG Disable */
|
||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
||||
tmp = readl(com + U3P_USBPHYACR6);
|
||||
tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR6);
|
||||
|
||||
if (!index) {
|
||||
/* switch 100uA current back to USB2.0 */
|
||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
||||
tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
||||
}
|
||||
writel(tmp, com + U3P_USBPHYACR6);
|
||||
|
||||
/* let suspendm=0, set utmi into analog power down */
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp &= ~P2C_RG_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
udelay(1);
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM1);
|
||||
tmp = readl(com + U3P_U2PHYDTM1);
|
||||
tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
|
||||
tmp |= P2C_RG_SESSEND;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM1);
|
||||
|
||||
if (!index) {
|
||||
tmp = readl(port_base + U3P_U3_PHYA_REG0);
|
||||
tmp &= ~P3A_RG_U3_VUSB10_ON;
|
||||
writel(tmp, port_base + U3P_U3_PHYA_REG0);
|
||||
}
|
||||
writel(tmp, com + U3P_U2PHYDTM1);
|
||||
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp = readl(com + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
writel(tmp, com + U3D_U2PHYDCR0);
|
||||
}
|
||||
|
||||
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
||||
|
@ -410,18 +461,55 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
|
|||
static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
void __iomem *port_base = instance->port_base;
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
void __iomem *com = u2_banks->com;
|
||||
u32 index = instance->index;
|
||||
u32 tmp;
|
||||
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp = readl(com + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
writel(tmp, com + U3D_U2PHYDCR0);
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(com + U3P_U2PHYDTM0);
|
||||
tmp &= ~P2C_FORCE_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
writel(tmp, com + U3P_U2PHYDTM0);
|
||||
}
|
||||
}
|
||||
|
||||
static void phy_v1_banks_init(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
|
||||
if (instance->type == PHY_TYPE_USB2) {
|
||||
u2_banks->misc = NULL;
|
||||
u2_banks->fmreg = u3phy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
|
||||
u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
|
||||
} else if (instance->type == PHY_TYPE_USB3) {
|
||||
u3_banks->spllc = u3phy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
|
||||
u3_banks->chip = NULL;
|
||||
u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
|
||||
u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
|
||||
}
|
||||
}
|
||||
|
||||
static void phy_v2_banks_init(struct mt65xx_u3phy *u3phy,
|
||||
struct mt65xx_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
|
||||
if (instance->type == PHY_TYPE_USB2) {
|
||||
u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
|
||||
u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
|
||||
u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
|
||||
} else if (instance->type == PHY_TYPE_USB3) {
|
||||
u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
|
||||
u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
|
||||
u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
|
||||
u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,7 +525,17 @@ static int mt65xx_phy_init(struct phy *phy)
|
|||
return ret;
|
||||
}
|
||||
|
||||
phy_instance_init(u3phy, instance);
|
||||
ret = clk_prepare_enable(instance->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(u3phy->dev, "failed to enable ref_clk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (instance->type == PHY_TYPE_USB2)
|
||||
phy_instance_init(u3phy, instance);
|
||||
else
|
||||
u3_phy_instance_init(u3phy, instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -446,8 +544,10 @@ static int mt65xx_phy_power_on(struct phy *phy)
|
|||
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
||||
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
||||
|
||||
phy_instance_power_on(u3phy, instance);
|
||||
hs_slew_rate_calibrate(u3phy, instance);
|
||||
if (instance->type == PHY_TYPE_USB2) {
|
||||
phy_instance_power_on(u3phy, instance);
|
||||
hs_slew_rate_calibrate(u3phy, instance);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -456,7 +556,9 @@ static int mt65xx_phy_power_off(struct phy *phy)
|
|||
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
||||
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
||||
|
||||
phy_instance_power_off(u3phy, instance);
|
||||
if (instance->type == PHY_TYPE_USB2)
|
||||
phy_instance_power_off(u3phy, instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -465,7 +567,10 @@ static int mt65xx_phy_exit(struct phy *phy)
|
|||
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
||||
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
||||
|
||||
phy_instance_exit(u3phy, instance);
|
||||
if (instance->type == PHY_TYPE_USB2)
|
||||
phy_instance_exit(u3phy, instance);
|
||||
|
||||
clk_disable_unprepare(instance->ref_clk);
|
||||
clk_disable_unprepare(u3phy->u3phya_ref);
|
||||
return 0;
|
||||
}
|
||||
|
@ -478,7 +583,6 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
|
|||
struct device_node *phy_np = args->np;
|
||||
int index;
|
||||
|
||||
|
||||
if (args->args_count != 1) {
|
||||
dev_err(dev, "invalid number of cells in 'phy' property\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -496,13 +600,21 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
|
|||
}
|
||||
|
||||
instance->type = args->args[0];
|
||||
|
||||
if (!(instance->type == PHY_TYPE_USB2 ||
|
||||
instance->type == PHY_TYPE_USB3)) {
|
||||
dev_err(dev, "unsupported device type: %d\n", instance->type);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (u3phy->pdata->version == MT_PHY_V1) {
|
||||
phy_v1_banks_init(u3phy, instance);
|
||||
} else if (u3phy->pdata->version == MT_PHY_V2) {
|
||||
phy_v2_banks_init(u3phy, instance);
|
||||
} else {
|
||||
dev_err(dev, "phy version is not supported\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return instance->phy;
|
||||
}
|
||||
|
||||
|
@ -516,14 +628,22 @@ static const struct phy_ops mt65xx_u3phy_ops = {
|
|||
|
||||
static const struct mt65xx_phy_pdata mt2701_pdata = {
|
||||
.avoid_rx_sen_degradation = false,
|
||||
.version = MT_PHY_V1,
|
||||
};
|
||||
|
||||
static const struct mt65xx_phy_pdata mt2712_pdata = {
|
||||
.avoid_rx_sen_degradation = false,
|
||||
.version = MT_PHY_V2,
|
||||
};
|
||||
|
||||
static const struct mt65xx_phy_pdata mt8173_pdata = {
|
||||
.avoid_rx_sen_degradation = true,
|
||||
.version = MT_PHY_V1,
|
||||
};
|
||||
|
||||
static const struct of_device_id mt65xx_u3phy_id_table[] = {
|
||||
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
|
||||
{ .compatible = "mediatek,mt2712-u3phy", .data = &mt2712_pdata },
|
||||
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
|
||||
{ },
|
||||
};
|
||||
|
@ -559,17 +679,23 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
|||
u3phy->dev = dev;
|
||||
platform_set_drvdata(pdev, u3phy);
|
||||
|
||||
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
|
||||
if (IS_ERR(u3phy->sif_base)) {
|
||||
dev_err(dev, "failed to remap sif regs\n");
|
||||
return PTR_ERR(u3phy->sif_base);
|
||||
if (u3phy->pdata->version == MT_PHY_V1) {
|
||||
/* get banks shared by multiple phys */
|
||||
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
|
||||
if (IS_ERR(u3phy->sif_base)) {
|
||||
dev_err(dev, "failed to remap sif regs\n");
|
||||
return PTR_ERR(u3phy->sif_base);
|
||||
}
|
||||
}
|
||||
|
||||
/* it's deprecated, make it optional for backward compatibility */
|
||||
u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
|
||||
if (IS_ERR(u3phy->u3phya_ref)) {
|
||||
dev_err(dev, "error to get u3phya_ref\n");
|
||||
return PTR_ERR(u3phy->u3phya_ref);
|
||||
if (PTR_ERR(u3phy->u3phya_ref) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
u3phy->u3phya_ref = NULL;
|
||||
}
|
||||
|
||||
port = 0;
|
||||
|
@ -610,6 +736,17 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
|||
instance->index = port;
|
||||
phy_set_drvdata(phy, instance);
|
||||
port++;
|
||||
|
||||
/* if deprecated clock is provided, ignore instance's one */
|
||||
if (u3phy->u3phya_ref)
|
||||
continue;
|
||||
|
||||
instance->ref_clk = devm_clk_get(&phy->dev, "ref");
|
||||
if (IS_ERR(instance->ref_clk)) {
|
||||
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
|
||||
retval = PTR_ERR(instance->ref_clk);
|
||||
goto put_child;
|
||||
}
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define QUSB2PHY_PLL_TEST 0x04
|
||||
#define CLK_REF_SEL BIT(7)
|
||||
|
||||
#define QUSB2PHY_PLL_TUNE 0x08
|
||||
#define QUSB2PHY_PLL_USER_CTL1 0x0c
|
||||
#define QUSB2PHY_PLL_USER_CTL2 0x10
|
||||
#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1c
|
||||
#define QUSB2PHY_PLL_PWR_CTRL 0x18
|
||||
|
||||
#define QUSB2PHY_PLL_STATUS 0x38
|
||||
#define PLL_LOCKED BIT(5)
|
||||
|
||||
#define QUSB2PHY_PORT_TUNE1 0x80
|
||||
#define QUSB2PHY_PORT_TUNE2 0x84
|
||||
#define QUSB2PHY_PORT_TUNE3 0x88
|
||||
#define QUSB2PHY_PORT_TUNE4 0x8c
|
||||
#define QUSB2PHY_PORT_TUNE5 0x90
|
||||
#define QUSB2PHY_PORT_TEST2 0x9c
|
||||
|
||||
#define QUSB2PHY_PORT_POWERDOWN 0xb4
|
||||
#define CLAMP_N_EN BIT(5)
|
||||
#define FREEZIO_N BIT(1)
|
||||
#define POWER_DOWN BIT(0)
|
||||
|
||||
#define QUSB2PHY_REFCLK_ENABLE BIT(0)
|
||||
|
||||
#define PHY_CLK_SCHEME_SEL BIT(0)
|
||||
|
||||
struct qusb2_phy_init_tbl {
|
||||
unsigned int offset;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
#define QUSB2_PHY_INIT_CFG(o, v) \
|
||||
{ \
|
||||
.offset = o, \
|
||||
.val = v, \
|
||||
}
|
||||
|
||||
static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
|
||||
};
|
||||
|
||||
struct qusb2_phy_cfg {
|
||||
const struct qusb2_phy_init_tbl *tbl;
|
||||
/* number of entries in the table */
|
||||
unsigned int tbl_num;
|
||||
/* offset to PHY_CLK_SCHEME register in TCSR map */
|
||||
unsigned int clk_scheme_offset;
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_cfg msm8996_phy_cfg = {
|
||||
.tbl = msm8996_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(msm8996_init_tbl),
|
||||
};
|
||||
|
||||
static const char * const qusb2_phy_vreg_names[] = {
|
||||
"vdda-pll", "vdda-phy-dpdm",
|
||||
};
|
||||
|
||||
#define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names)
|
||||
|
||||
/**
|
||||
* struct qusb2_phy - structure holding qusb2 phy attributes
|
||||
*
|
||||
* @phy: generic phy
|
||||
* @base: iomapped memory space for qubs2 phy
|
||||
*
|
||||
* @cfg_ahb_clk: AHB2PHY interface clock
|
||||
* @ref_clk: phy reference clock
|
||||
* @iface_clk: phy interface clock
|
||||
* @phy_reset: phy reset control
|
||||
* @vregs: regulator supplies bulk data
|
||||
*
|
||||
* @tcsr: TCSR syscon register map
|
||||
* @cell: nvmem cell containing phy tuning value
|
||||
*
|
||||
* @cfg: phy config data
|
||||
* @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
|
||||
*/
|
||||
struct qusb2_phy {
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
|
||||
struct clk *cfg_ahb_clk;
|
||||
struct clk *ref_clk;
|
||||
struct clk *iface_clk;
|
||||
struct reset_control *phy_reset;
|
||||
struct regulator_bulk_data vregs[QUSB2_NUM_VREGS];
|
||||
|
||||
struct regmap *tcsr;
|
||||
struct nvmem_cell *cell;
|
||||
|
||||
const struct qusb2_phy_cfg *cfg;
|
||||
bool has_se_clk_scheme;
|
||||
};
|
||||
|
||||
static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(base + offset);
|
||||
reg |= val;
|
||||
writel(reg, base + offset);
|
||||
|
||||
/* Ensure above write is completed */
|
||||
readl(base + offset);
|
||||
}
|
||||
|
||||
static inline void qusb2_clrbits(void __iomem *base, u32 offset, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(base + offset);
|
||||
reg &= ~val;
|
||||
writel(reg, base + offset);
|
||||
|
||||
/* Ensure above write is completed */
|
||||
readl(base + offset);
|
||||
}
|
||||
|
||||
static inline
|
||||
void qcom_qusb2_phy_configure(void __iomem *base,
|
||||
const struct qusb2_phy_init_tbl tbl[], int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
writel(tbl[i].val, base + tbl[i].offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetches HS Tx tuning value from nvmem and sets the
|
||||
* QUSB2PHY_PORT_TUNE2 register.
|
||||
* For error case, skip setting the value and use the default value.
|
||||
*/
|
||||
static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
|
||||
{
|
||||
struct device *dev = &qphy->phy->dev;
|
||||
u8 *val;
|
||||
|
||||
/*
|
||||
* Read efuse register having TUNE2 parameter's high nibble.
|
||||
* If efuse register shows value as 0x0, or if we fail to find
|
||||
* a valid efuse register settings, then use default value
|
||||
* as 0xB for high nibble that we have already set while
|
||||
* configuring phy.
|
||||
*/
|
||||
val = nvmem_cell_read(qphy->cell, NULL);
|
||||
if (IS_ERR(val) || !val[0]) {
|
||||
dev_dbg(dev, "failed to read a valid hs-tx trim value\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fused TUNE2 value is the higher nibble only */
|
||||
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
|
||||
}
|
||||
|
||||
static int qusb2_phy_poweron(struct phy *phy)
|
||||
{
|
||||
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||
int num = ARRAY_SIZE(qphy->vregs);
|
||||
int ret;
|
||||
|
||||
dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
|
||||
|
||||
/* turn on regulator supplies */
|
||||
ret = regulator_bulk_enable(num, qphy->vregs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(qphy->iface_clk);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
|
||||
regulator_bulk_disable(num, qphy->vregs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qusb2_phy_poweroff(struct phy *phy)
|
||||
{
|
||||
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||
|
||||
clk_disable_unprepare(qphy->iface_clk);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qusb2_phy_init(struct phy *phy)
|
||||
{
|
||||
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||
unsigned int val;
|
||||
unsigned int clk_scheme;
|
||||
int ret;
|
||||
|
||||
dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
|
||||
|
||||
/* enable ahb interface clock to program phy */
|
||||
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Perform phy reset */
|
||||
ret = reset_control_assert(qphy->phy_reset);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
|
||||
goto disable_ahb_clk;
|
||||
}
|
||||
|
||||
/* 100 us delay to keep PHY in reset mode */
|
||||
usleep_range(100, 150);
|
||||
|
||||
ret = reset_control_deassert(qphy->phy_reset);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
|
||||
goto disable_ahb_clk;
|
||||
}
|
||||
|
||||
/* Disable the PHY */
|
||||
qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
|
||||
CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
|
||||
|
||||
/* save reset value to override reference clock scheme later */
|
||||
val = readl(qphy->base + QUSB2PHY_PLL_TEST);
|
||||
|
||||
qcom_qusb2_phy_configure(qphy->base, qphy->cfg->tbl,
|
||||
qphy->cfg->tbl_num);
|
||||
|
||||
/* Set efuse value for tuning the PHY */
|
||||
qusb2_phy_set_tune2_param(qphy);
|
||||
|
||||
/* Enable the PHY */
|
||||
qusb2_clrbits(qphy->base, QUSB2PHY_PORT_POWERDOWN, POWER_DOWN);
|
||||
|
||||
/* Required to get phy pll lock successfully */
|
||||
usleep_range(150, 160);
|
||||
|
||||
/* Default is single-ended clock on msm8996 */
|
||||
qphy->has_se_clk_scheme = true;
|
||||
/*
|
||||
* read TCSR_PHY_CLK_SCHEME register to check if single-ended
|
||||
* clock scheme is selected. If yes, then disable differential
|
||||
* ref_clk and use single-ended clock, otherwise use differential
|
||||
* ref_clk only.
|
||||
*/
|
||||
if (qphy->tcsr) {
|
||||
ret = regmap_read(qphy->tcsr, qphy->cfg->clk_scheme_offset,
|
||||
&clk_scheme);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "failed to read clk scheme reg\n");
|
||||
goto assert_phy_reset;
|
||||
}
|
||||
|
||||
/* is it a differential clock scheme ? */
|
||||
if (!(clk_scheme & PHY_CLK_SCHEME_SEL)) {
|
||||
dev_vdbg(&phy->dev, "%s(): select differential clk\n",
|
||||
__func__);
|
||||
qphy->has_se_clk_scheme = false;
|
||||
} else {
|
||||
dev_vdbg(&phy->dev, "%s(): select single-ended clk\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
|
||||
if (!qphy->has_se_clk_scheme) {
|
||||
val &= ~CLK_REF_SEL;
|
||||
ret = clk_prepare_enable(qphy->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "failed to enable ref clk, %d\n",
|
||||
ret);
|
||||
goto assert_phy_reset;
|
||||
}
|
||||
} else {
|
||||
val |= CLK_REF_SEL;
|
||||
}
|
||||
|
||||
writel(val, qphy->base + QUSB2PHY_PLL_TEST);
|
||||
|
||||
/* ensure above write is through */
|
||||
readl(qphy->base + QUSB2PHY_PLL_TEST);
|
||||
|
||||
/* Required to get phy pll lock successfully */
|
||||
usleep_range(100, 110);
|
||||
|
||||
val = readb(qphy->base + QUSB2PHY_PLL_STATUS);
|
||||
if (!(val & PLL_LOCKED)) {
|
||||
dev_err(&phy->dev,
|
||||
"QUSB2PHY pll lock failed: status reg = %x\n", val);
|
||||
ret = -EBUSY;
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_ref_clk:
|
||||
if (!qphy->has_se_clk_scheme)
|
||||
clk_disable_unprepare(qphy->ref_clk);
|
||||
assert_phy_reset:
|
||||
reset_control_assert(qphy->phy_reset);
|
||||
disable_ahb_clk:
|
||||
clk_disable_unprepare(qphy->cfg_ahb_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qusb2_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||
|
||||
/* Disable the PHY */
|
||||
qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
|
||||
CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
|
||||
|
||||
if (!qphy->has_se_clk_scheme)
|
||||
clk_disable_unprepare(qphy->ref_clk);
|
||||
|
||||
reset_control_assert(qphy->phy_reset);
|
||||
|
||||
clk_disable_unprepare(qphy->cfg_ahb_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops qusb2_phy_gen_ops = {
|
||||
.init = qusb2_phy_init,
|
||||
.exit = qusb2_phy_exit,
|
||||
.power_on = qusb2_phy_poweron,
|
||||
.power_off = qusb2_phy_poweroff,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id qusb2_phy_of_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,msm8996-qusb2-phy",
|
||||
.data = &msm8996_phy_cfg,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qusb2_phy_of_match_table);
|
||||
|
||||
static int qusb2_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct qusb2_phy *qphy;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *generic_phy;
|
||||
struct resource *res;
|
||||
int ret, i;
|
||||
int num;
|
||||
|
||||
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
|
||||
if (!qphy)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
qphy->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(qphy->base))
|
||||
return PTR_ERR(qphy->base);
|
||||
|
||||
qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb");
|
||||
if (IS_ERR(qphy->cfg_ahb_clk)) {
|
||||
ret = PTR_ERR(qphy->cfg_ahb_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get cfg ahb clk, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qphy->ref_clk = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(qphy->ref_clk)) {
|
||||
ret = PTR_ERR(qphy->ref_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get ref clk, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qphy->iface_clk = devm_clk_get(dev, "iface");
|
||||
if (IS_ERR(qphy->iface_clk)) {
|
||||
ret = PTR_ERR(qphy->iface_clk);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
qphy->iface_clk = NULL;
|
||||
dev_dbg(dev, "failed to get iface clk, %d\n", ret);
|
||||
}
|
||||
|
||||
qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0);
|
||||
if (IS_ERR(qphy->phy_reset)) {
|
||||
dev_err(dev, "failed to get phy core reset\n");
|
||||
return PTR_ERR(qphy->phy_reset);
|
||||
}
|
||||
|
||||
num = ARRAY_SIZE(qphy->vregs);
|
||||
for (i = 0; i < num; i++)
|
||||
qphy->vregs[i].supply = qusb2_phy_vreg_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get regulator supplies\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the specific init parameters of QMP phy */
|
||||
qphy->cfg = of_device_get_match_data(dev);
|
||||
|
||||
qphy->tcsr = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"qcom,tcsr-syscon");
|
||||
if (IS_ERR(qphy->tcsr)) {
|
||||
dev_dbg(dev, "failed to lookup TCSR regmap\n");
|
||||
qphy->tcsr = NULL;
|
||||
}
|
||||
|
||||
qphy->cell = devm_nvmem_cell_get(dev, NULL);
|
||||
if (IS_ERR(qphy->cell)) {
|
||||
if (PTR_ERR(qphy->cell) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
qphy->cell = NULL;
|
||||
dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");
|
||||
}
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
ret = PTR_ERR(generic_phy);
|
||||
dev_err(dev, "failed to create phy, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
qphy->phy = generic_phy;
|
||||
|
||||
dev_set_drvdata(dev, qphy);
|
||||
phy_set_drvdata(generic_phy, qphy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (!IS_ERR(phy_provider))
|
||||
dev_info(dev, "Registered Qcom-QUSB2 phy\n");
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static struct platform_driver qusb2_phy_driver = {
|
||||
.probe = qusb2_phy_probe,
|
||||
.driver = {
|
||||
.name = "qcom-qusb2-phy",
|
||||
.of_match_table = qusb2_phy_of_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(qusb2_phy_driver);
|
||||
|
||||
MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
|
||||
MODULE_DESCRIPTION("Qualcomm QUSB2 PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
@ -395,7 +396,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
struct rcar_gen3_chan *channel;
|
||||
struct phy_provider *provider;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int irq, ret = 0;
|
||||
|
||||
if (!dev->of_node) {
|
||||
dev_err(dev, "This driver needs device tree\n");
|
||||
|
@ -434,17 +435,24 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
/* devm_phy_create() will call pm_runtime_enable(dev); */
|
||||
/*
|
||||
* devm_phy_create() will call pm_runtime_enable(&phy->dev);
|
||||
* And then, phy-core will manage runtime pm for this device.
|
||||
*/
|
||||
pm_runtime_enable(dev);
|
||||
channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
|
||||
if (IS_ERR(channel->phy)) {
|
||||
dev_err(dev, "Failed to create USB2 PHY\n");
|
||||
return PTR_ERR(channel->phy);
|
||||
ret = PTR_ERR(channel->phy);
|
||||
goto error;
|
||||
}
|
||||
|
||||
channel->vbus = devm_regulator_get_optional(dev, "vbus");
|
||||
if (IS_ERR(channel->vbus)) {
|
||||
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
|
||||
return PTR_ERR(channel->vbus);
|
||||
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) {
|
||||
ret = PTR_ERR(channel->vbus);
|
||||
goto error;
|
||||
}
|
||||
channel->vbus = NULL;
|
||||
}
|
||||
|
||||
|
@ -454,15 +462,22 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(dev, "Failed to register PHY provider\n");
|
||||
ret = PTR_ERR(provider);
|
||||
goto error;
|
||||
} else if (channel->has_otg) {
|
||||
int ret;
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_role);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return PTR_ERR_OR_ZERO(provider);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
||||
|
@ -472,6 +487,8 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
|||
if (channel->has_otg)
|
||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -554,8 +554,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
|
|||
case USB_CHG_STATE_DETECTED:
|
||||
switch (rphy->chg_type) {
|
||||
case POWER_SUPPLY_TYPE_USB:
|
||||
dev_dbg(&rport->phy->dev,
|
||||
"sdp cable is connecetd\n");
|
||||
dev_dbg(&rport->phy->dev, "sdp cable is connected\n");
|
||||
rockchip_usb2phy_power_on(rport->phy);
|
||||
rport->state = OTG_STATE_B_PERIPHERAL;
|
||||
notify_charger = true;
|
||||
|
@ -563,16 +562,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
|
|||
cable = EXTCON_CHG_USB_SDP;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_USB_DCP:
|
||||
dev_dbg(&rport->phy->dev,
|
||||
"dcp cable is connecetd\n");
|
||||
dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
|
||||
rockchip_usb2phy_power_off(rport->phy);
|
||||
notify_charger = true;
|
||||
sch_work = true;
|
||||
cable = EXTCON_CHG_USB_DCP;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_USB_CDP:
|
||||
dev_dbg(&rport->phy->dev,
|
||||
"cdp cable is connecetd\n");
|
||||
dev_dbg(&rport->phy->dev, "cdp cable is connected\n");
|
||||
rockchip_usb2phy_power_on(rport->phy);
|
||||
rport->state = OTG_STATE_B_PERIPHERAL;
|
||||
notify_charger = true;
|
||||
|
@ -1141,6 +1138,49 @@ disable_clks:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x100,
|
||||
.num_ports = 2,
|
||||
.clkout_ctl = { 0x108, 4, 4, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x0100, 15, 0, 0, 0x1d1 },
|
||||
.bvalid_det_en = { 0x0110, 2, 2, 0, 1 },
|
||||
.bvalid_det_st = { 0x0114, 2, 2, 0, 1 },
|
||||
.bvalid_det_clr = { 0x0118, 2, 2, 0, 1 },
|
||||
.ls_det_en = { 0x0110, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x0114, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x0118, 0, 0, 0, 1 },
|
||||
.utmi_avalid = { 0x0120, 10, 10, 0, 1 },
|
||||
.utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
|
||||
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0x104, 15, 0, 0, 0x1d1 },
|
||||
.ls_det_en = { 0x110, 1, 1, 0, 1 },
|
||||
.ls_det_st = { 0x114, 1, 1, 0, 1 },
|
||||
.ls_det_clr = { 0x118, 1, 1, 0, 1 },
|
||||
.utmi_ls = { 0x120, 17, 16, 0, 1 },
|
||||
.utmi_hstdet = { 0x120, 19, 19, 0, 1 }
|
||||
}
|
||||
},
|
||||
.chg_det = {
|
||||
.opmode = { 0x0100, 3, 0, 5, 1 },
|
||||
.cp_det = { 0x0120, 24, 24, 0, 1 },
|
||||
.dcp_det = { 0x0120, 23, 23, 0, 1 },
|
||||
.dp_det = { 0x0120, 25, 25, 0, 1 },
|
||||
.idm_sink_en = { 0x0108, 8, 8, 0, 1 },
|
||||
.idp_sink_en = { 0x0108, 7, 7, 0, 1 },
|
||||
.idp_src_en = { 0x0108, 9, 9, 0, 1 },
|
||||
.rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 },
|
||||
.vdm_src_en = { 0x0108, 12, 12, 0, 1 },
|
||||
.vdp_src_en = { 0x0108, 11, 11, 0, 1 },
|
||||
},
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x700,
|
||||
|
@ -1223,6 +1263,7 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
|
|||
};
|
||||
|
||||
static const struct of_device_id rockchip_usb2phy_dt_match[] = {
|
||||
{ .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
|
||||
{}
|
||||
|
|
|
@ -66,6 +66,7 @@ struct rockchip_usb_phy {
|
|||
struct phy *phy;
|
||||
bool uart_enabled;
|
||||
struct reset_control *reset;
|
||||
struct regulator *vbus;
|
||||
};
|
||||
|
||||
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
|
||||
|
@ -88,6 +89,9 @@ static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
|
|||
struct rockchip_usb_phy,
|
||||
clk480m_hw);
|
||||
|
||||
if (phy->vbus)
|
||||
regulator_disable(phy->vbus);
|
||||
|
||||
/* Power down usb phy analog blocks by set siddq 1 */
|
||||
rockchip_usb_phy_power(phy, 1);
|
||||
}
|
||||
|
@ -143,6 +147,14 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
|
|||
if (phy->uart_enabled)
|
||||
return -EBUSY;
|
||||
|
||||
if (phy->vbus) {
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(phy->vbus);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return clk_prepare_enable(phy->clk480m);
|
||||
}
|
||||
|
||||
|
@ -268,6 +280,13 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
|
|||
}
|
||||
phy_set_drvdata(rk_phy->phy, rk_phy);
|
||||
|
||||
rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus");
|
||||
if (IS_ERR(rk_phy->vbus)) {
|
||||
if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER)
|
||||
return PTR_ERR(rk_phy->vbus);
|
||||
rk_phy->vbus = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* When acting as uart-pipe, just keep clock on otherwise
|
||||
* only power up usb phy when it use, so disable it when init
|
||||
|
|
|
@ -49,12 +49,14 @@
|
|||
#define REG_PHYBIST 0x08
|
||||
#define REG_PHYTUNE 0x0c
|
||||
#define REG_PHYCTL_A33 0x10
|
||||
#define REG_PHY_UNK_H3 0x20
|
||||
#define REG_PHY_OTGCTL 0x20
|
||||
|
||||
#define REG_PMU_UNK1 0x10
|
||||
|
||||
#define PHYCTL_DATA BIT(7)
|
||||
|
||||
#define OTGCTL_ROUTE_MUSB BIT(0)
|
||||
|
||||
#define SUNXI_AHB_ICHR8_EN BIT(10)
|
||||
#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
|
||||
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
|
||||
|
@ -110,6 +112,7 @@ struct sun4i_usb_phy_cfg {
|
|||
u8 phyctl_offset;
|
||||
bool dedicated_clocks;
|
||||
bool enable_pmu_unk1;
|
||||
bool phy0_dual_route;
|
||||
};
|
||||
|
||||
struct sun4i_usb_phy_data {
|
||||
|
@ -188,10 +191,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
|
|||
|
||||
spin_lock_irqsave(&phy_data->reg_lock, flags);
|
||||
|
||||
if (phy_data->cfg->type == sun8i_a33_phy ||
|
||||
phy_data->cfg->type == sun50i_a64_phy ||
|
||||
phy_data->cfg->type == sun8i_v3s_phy) {
|
||||
/* A33 or A64 needs us to set phyctl to 0 explicitly */
|
||||
if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
|
||||
/* SoCs newer than A33 need us to set phyctl to 0 explicitly */
|
||||
writel(0, phyctl);
|
||||
}
|
||||
|
||||
|
@ -271,23 +272,16 @@ static int sun4i_usb_phy_init(struct phy *_phy)
|
|||
writel(val & ~2, phy->pmu + REG_PMU_UNK1);
|
||||
}
|
||||
|
||||
if (data->cfg->type == sun8i_h3_phy) {
|
||||
if (phy->index == 0) {
|
||||
val = readl(data->base + REG_PHY_UNK_H3);
|
||||
writel(val & ~1, data->base + REG_PHY_UNK_H3);
|
||||
}
|
||||
} else {
|
||||
/* Enable USB 45 Ohm resistor calibration */
|
||||
if (phy->index == 0)
|
||||
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
|
||||
/* Enable USB 45 Ohm resistor calibration */
|
||||
if (phy->index == 0)
|
||||
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
|
||||
|
||||
/* Adjust PHY's magnitude and rate */
|
||||
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
|
||||
/* 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);
|
||||
}
|
||||
/* Disconnect threshold adjustment */
|
||||
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
|
||||
data->cfg->disc_thresh, 2);
|
||||
|
||||
sun4i_usb_phy_passby(phy, 1);
|
||||
|
||||
|
@ -486,6 +480,21 @@ static const struct phy_ops sun4i_usb_phy_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void sun4i_usb_phy0_reroute(struct sun4i_usb_phy_data *data, int id_det)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = readl(data->base + REG_PHY_OTGCTL);
|
||||
if (id_det == 0) {
|
||||
/* Host mode. Route phy0 to EHCI/OHCI */
|
||||
regval &= ~OTGCTL_ROUTE_MUSB;
|
||||
} else {
|
||||
/* Peripheral mode. Route phy0 to MUSB */
|
||||
regval |= OTGCTL_ROUTE_MUSB;
|
||||
}
|
||||
writel(regval, data->base + REG_PHY_OTGCTL);
|
||||
}
|
||||
|
||||
static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
||||
{
|
||||
struct sun4i_usb_phy_data *data =
|
||||
|
@ -546,6 +555,10 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
|||
sun4i_usb_phy0_set_vbus_detect(phy0, 1);
|
||||
mutex_unlock(&phy0->mutex);
|
||||
}
|
||||
|
||||
/* Re-route PHY0 if necessary */
|
||||
if (data->cfg->phy0_dual_route)
|
||||
sun4i_usb_phy0_reroute(data, id_det);
|
||||
}
|
||||
|
||||
if (vbus_notify)
|
||||
|
@ -700,7 +713,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(phy->reset);
|
||||
}
|
||||
|
||||
if (i) { /* No pmu for usbc0 */
|
||||
if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */
|
||||
snprintf(name, sizeof(name), "pmu%d", i);
|
||||
res = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, name);
|
||||
|
@ -823,8 +836,10 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
|
|||
.num_phys = 4,
|
||||
.type = sun8i_h3_phy,
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
|
||||
|
@ -843,6 +858,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
|
|||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
||||
|
|
|
@ -12,36 +12,6 @@
|
|||
#ifndef _LINUX_MFD_SYSCON_PMU_EXYNOS5_H_
|
||||
#define _LINUX_MFD_SYSCON_PMU_EXYNOS5_H_
|
||||
|
||||
/* Exynos5 PMU register definitions */
|
||||
#define EXYNOS5_HDMI_PHY_CONTROL (0x700)
|
||||
#define EXYNOS5_USBDRD_PHY_CONTROL (0x704)
|
||||
|
||||
/* Exynos5250 specific register definitions */
|
||||
#define EXYNOS5_USBHOST_PHY_CONTROL (0x708)
|
||||
#define EXYNOS5_EFNAND_PHY_CONTROL (0x70c)
|
||||
#define EXYNOS5_MIPI_PHY0_CONTROL (0x710)
|
||||
#define EXYNOS5_MIPI_PHY1_CONTROL (0x714)
|
||||
#define EXYNOS5_ADC_PHY_CONTROL (0x718)
|
||||
#define EXYNOS5_MTCADC_PHY_CONTROL (0x71c)
|
||||
#define EXYNOS5_DPTX_PHY_CONTROL (0x720)
|
||||
#define EXYNOS5_SATA_PHY_CONTROL (0x724)
|
||||
|
||||
/* Exynos5420 specific register definitions */
|
||||
#define EXYNOS5420_USBDRD1_PHY_CONTROL (0x708)
|
||||
#define EXYNOS5420_USBHOST_PHY_CONTROL (0x70c)
|
||||
#define EXYNOS5420_MIPI_PHY0_CONTROL (0x714)
|
||||
#define EXYNOS5420_MIPI_PHY1_CONTROL (0x718)
|
||||
#define EXYNOS5420_MIPI_PHY2_CONTROL (0x71c)
|
||||
#define EXYNOS5420_ADC_PHY_CONTROL (0x720)
|
||||
#define EXYNOS5420_MTCADC_PHY_CONTROL (0x724)
|
||||
#define EXYNOS5420_DPTX_PHY_CONTROL (0x728)
|
||||
|
||||
/* Exynos5433 specific register definitions */
|
||||
#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x728)
|
||||
#define EXYNOS5433_MIPI_PHY0_CONTROL (0x710)
|
||||
#define EXYNOS5433_MIPI_PHY1_CONTROL (0x714)
|
||||
#define EXYNOS5433_MIPI_PHY2_CONTROL (0x718)
|
||||
|
||||
#define EXYNOS5_PHY_ENABLE BIT(0)
|
||||
#define EXYNOS5_MIPI_PHY_S_RESETN BIT(1)
|
||||
#define EXYNOS5_MIPI_PHY_M_RESETN BIT(2)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
|
||||
* Copyright (c) 2010-2015 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* EXYNOS - Power management unit definition
|
||||
|
@ -50,6 +50,14 @@
|
|||
#define S5P_WAKEUP_MASK 0x0608
|
||||
#define S5P_WAKEUP_MASK2 0x0614
|
||||
|
||||
/* MIPI_PHYn_CONTROL, valid for Exynos3250, Exynos4, Exynos5250 and Exynos5433 */
|
||||
#define EXYNOS4_MIPI_PHY_CONTROL(n) (0x0710 + (n) * 4)
|
||||
/* Phy enable bit, common for all phy registers, not only MIPI */
|
||||
#define EXYNOS4_PHY_ENABLE (1 << 0)
|
||||
#define EXYNOS4_MIPI_PHY_SRESETN (1 << 1)
|
||||
#define EXYNOS4_MIPI_PHY_MRESETN (1 << 2)
|
||||
#define EXYNOS4_MIPI_PHY_RESET_MASK (3 << 1)
|
||||
|
||||
#define S5P_INFORM0 0x0800
|
||||
#define S5P_INFORM1 0x0804
|
||||
#define S5P_INFORM5 0x0814
|
||||
|
@ -342,6 +350,8 @@
|
|||
|
||||
#define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408
|
||||
#define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C
|
||||
#define EXYNOS5_USBDRD_PHY_CONTROL 0x0704
|
||||
#define EXYNOS5_DPTX_PHY_CONTROL 0x0720
|
||||
|
||||
#define EXYNOS5_USE_RETENTION BIT(4)
|
||||
#define EXYNOS5_SYS_WDTRESET (1 << 20)
|
||||
|
@ -495,6 +505,9 @@
|
|||
#define EXYNOS5420_KFC_CORE_RESET(_nr) \
|
||||
((EXYNOS5420_KFC_CORE_RESET0 | EXYNOS5420_KFC_ETM_RESET0) << (_nr))
|
||||
|
||||
#define EXYNOS5420_USBDRD1_PHY_CONTROL 0x0708
|
||||
#define EXYNOS5420_MIPI_PHY_CONTROL(n) (0x0714 + (n) * 4)
|
||||
#define EXYNOS5420_DPTX_PHY_CONTROL 0x0728
|
||||
#define EXYNOS5420_ARM_CORE2_SYS_PWR_REG 0x1020
|
||||
#define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024
|
||||
#define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028
|
||||
|
@ -632,6 +645,7 @@
|
|||
| EXYNOS5420_KFC_USE_STANDBY_WFI3)
|
||||
|
||||
/* For EXYNOS5433 */
|
||||
#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x0728)
|
||||
#define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028)
|
||||
#define EXYNOS5433_PAD_RETENTION_MMC2_OPTION (0x30C8)
|
||||
#define EXYNOS5433_PAD_RETENTION_TOP_OPTION (0x3108)
|
||||
|
|
Loading…
Reference in New Issue