Commit a6308d70 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-4.12' of...

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: default avatarKishon Vijay Abraham I <kishon@ti.com>
parents 37e47d5c 6239879b
...@@ -6,12 +6,11 @@ This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC. ...@@ -6,12 +6,11 @@ This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
Required properties (controller (parent) node): Required properties (controller (parent) node):
- compatible : should be one of - compatible : should be one of
"mediatek,mt2701-u3phy" "mediatek,mt2701-u3phy"
"mediatek,mt2712-u3phy"
"mediatek,mt8173-u3phy" "mediatek,mt8173-u3phy"
- reg : offset and length of register for phy, exclude port's - clocks : (deprecated, use port's clocks instead) a list of phandle +
register. clock-specifier pairs, one for each entry in clock-names
- clocks : a list of phandle + clock-specifier pairs, one for each - clock-names : (deprecated, use port's one instead) must contain
entry in clock-names
- clock-names : must contain
"u3phya_ref": for reference clock of usb3.0 analog phy. "u3phya_ref": for reference clock of usb3.0 analog phy.
Required nodes : a sub-node is required for each port the controller 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 ...@@ -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 'reg' property is used inside these nodes to describe
the controller's topology. 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): Required properties (port (child) node):
- reg : address and length of the register set for the port. - 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) - #phy-cells : should be 1 (See second example)
cell after port phandle is phy type from: cell after port phandle is phy type from:
- PHY_TYPE_USB2 - PHY_TYPE_USB2
...@@ -31,21 +41,31 @@ Example: ...@@ -31,21 +41,31 @@ Example:
u3phy: usb-phy@11290000 { u3phy: usb-phy@11290000 {
compatible = "mediatek,mt8173-u3phy"; compatible = "mediatek,mt8173-u3phy";
reg = <0 0x11290000 0 0x800>; reg = <0 0x11290000 0 0x800>;
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
clock-names = "u3phya_ref";
#address-cells = <2>; #address-cells = <2>;
#size-cells = <2>; #size-cells = <2>;
ranges; ranges;
status = "okay"; status = "okay";
phy_port0: port@11290800 { u2port0: usb-phy@11290800 {
reg = <0 0x11290800 0 0x800>; reg = <0 0x11290800 0 0x100>;
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
clock-names = "ref";
#phy-cells = <1>; #phy-cells = <1>;
status = "okay"; status = "okay";
}; };
phy_port1: port@11291000 { u3port0: usb-phy@11290900 {
reg = <0 0x11291000 0 0x800>; 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>; #phy-cells = <1>;
status = "okay"; status = "okay";
}; };
...@@ -64,7 +84,54 @@ Example: ...@@ -64,7 +84,54 @@ Example:
usb30: usb@11270000 { usb30: usb@11270000 {
... ...
phys = <&phy_port0 PHY_TYPE_USB3>; phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
phy-names = "usb3-0"; 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 ...@@ -2,6 +2,7 @@ ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
Required properties (phy (parent) node): Required properties (phy (parent) node):
- compatible : should be one of the listed compatibles: - compatible : should be one of the listed compatibles:
* "rockchip,rk3328-usb2phy"
* "rockchip,rk3366-usb2phy" * "rockchip,rk3366-usb2phy"
* "rockchip,rk3399-usb2phy" * "rockchip,rk3399-usb2phy"
- reg : the address offset of grf for usb-phy configuration. - reg : the address offset of grf for usb-phy configuration.
...@@ -11,6 +12,11 @@ Required properties (phy (parent) node): ...@@ -11,6 +12,11 @@ Required properties (phy (parent) node):
Optional properties: Optional properties:
- clocks : phandle + phy specifier pair, for the input clock of phy. - clocks : phandle + phy specifier pair, for the input clock of phy.
- clock-names : input clock name of phy, must be "phyclk". - 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. 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, The sub-node name is used to identify host or otg port,
......
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 {
...
...
};
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: ...@@ -30,6 +30,7 @@ Optional Properties:
- reset-names: Only allow the following entries: - reset-names: Only allow the following entries:
- phy-reset - phy-reset
- resets: Must contain an entry for each entry in reset-names. - resets: Must contain an entry for each entry in reset-names.
- vbus-supply: power-supply phandle for vbus power source
Example: Example:
......
...@@ -15,6 +15,7 @@ Required properties: ...@@ -15,6 +15,7 @@ Required properties:
- reg : a list of offset + length pairs - reg : a list of offset + length pairs
- reg-names : - reg-names :
* "phy_ctrl" * "phy_ctrl"
* "pmu0" for H3, V3s and A64
* "pmu1" * "pmu1"
* "pmu2" for sun4i, sun6i or sun7i * "pmu2" for sun4i, sun6i or sun7i
- #phy-cells : from the generic phy bindings, must be 1 - #phy-cells : from the generic phy bindings, must be 1
......
...@@ -8,6 +8,8 @@ From RK3368 SoCs, the GRF is divided into two sections, ...@@ -8,6 +8,8 @@ From RK3368 SoCs, the GRF is divided into two sections,
- SGRF, used for general secure system, - SGRF, used for general secure system,
- PMUGRF, used for always on system - PMUGRF, used for always on system
On RK3328 SoCs, the GRF adds a section for USB2PHYGRF,
Required Properties: Required Properties:
- compatible: GRF should be one of the following: - compatible: GRF should be one of the following:
...@@ -23,6 +25,8 @@ Required Properties: ...@@ -23,6 +25,8 @@ Required Properties:
- "rockchip,rk3399-pmugrf", "syscon": for rk3399 - "rockchip,rk3399-pmugrf", "syscon": for rk3399
- compatible: SGRF should be one of the following - compatible: SGRF should be one of the following
- "rockchip,rk3288-sgrf", "syscon": for rk3288 - "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 - reg: physical base address of the controller and length of memory mapped
region. region.
......
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/exynos5-pmu.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/types.h> #include <linux/types.h>
/* LPASS Top register definitions */ /* LPASS Top register definitions */
...@@ -83,7 +83,7 @@ static void exynos_lpass_enable(struct exynos_lpass *lpass) ...@@ -83,7 +83,7 @@ static void exynos_lpass_enable(struct exynos_lpass *lpass)
/* Activate related PADs from retention state */ /* Activate related PADs from retention state */
regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION, 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_I2S_SW_RESET);
exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET); exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
......
...@@ -439,6 +439,25 @@ config PHY_STIH407_USB ...@@ -439,6 +439,25 @@ config PHY_STIH407_USB
Enable this support to enable the picoPHY device used by USB2 Enable this support to enable the picoPHY device used by USB2
and USB3 controllers on STMicroelectronics STiH407 SoC families. 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 config PHY_QCOM_UFS
tristate "Qualcomm UFS PHY driver" tristate "Qualcomm UFS PHY driver"
depends on OF && ARCH_QCOM depends on OF && ARCH_QCOM
......
...@@ -50,6 +50,8 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o ...@@ -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_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.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.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Broadcom Northstar USB 3.0 PHY Driver * Broadcom Northstar USB 3.0 PHY Driver
* *
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl> * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
* Copyright (C) 2016 Broadcom
* *
* All magic values used for initialization (and related comments) were obtained * All magic values used for initialization (and related comments) were obtained
* from Broadcom's SDK: * from Broadcom's SDK:
...@@ -23,6 +24,23 @@ ...@@ -23,6 +24,23 @@
#define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */ #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 { enum bcm_ns_family {
BCM_NS_UNKNOWN, BCM_NS_UNKNOWN,
BCM_NS_AX, BCM_NS_AX,
...@@ -76,8 +94,10 @@ static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3) ...@@ -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)); 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; int err;
err = bcm_ns_usb3_mii_mng_wait_idle(usb3); 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) ...@@ -86,7 +106,11 @@ static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
return err; 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; return 0;
} }
...@@ -102,21 +126,22 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) ...@@ -102,21 +126,22 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
udelay(2); udelay(2);
/* USB3 PLL Block */ /* 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) if (err < 0)
return err; return err;
/* Assert Ana_Pllseq start */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* Waiting MII Mgt interface idle */
bcm_ns_usb3_mii_mng_wait_idle(usb3); 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) ...@@ -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); writel(0, usb3->dmp + BCMA_RESET_CTL);
/* PLL frequency monitor enable */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* Waiting MII Mgt interface idle */
bcm_ns_usb3_mii_mng_wait_idle(usb3); 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) ...@@ -159,22 +186,24 @@ static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3)
udelay(2); udelay(2);
/* PLL30 block */ /* 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) if (err < 0)
return err; 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 */ /* 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 */ /* Waiting MII Mgt interface idle */
bcm_ns_usb3_mii_mng_wait_idle(usb3); bcm_ns_usb3_mii_mng_wait_idle(usb3);
......
...@@ -14,12 +14,12 @@ ...@@ -14,12 +14,12 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/exynos5-pmu.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
struct exynos_dp_video_phy_drvdata { struct exynos_dp_video_phy_drvdata {
u32 phy_ctrl_offset; u32 phy_ctrl_offset;
...@@ -36,7 +36,7 @@ static int exynos_dp_video_phy_power_on(struct phy *phy) ...@@ -36,7 +36,7 @@ static int exynos_dp_video_phy_power_on(struct phy *phy)
/* Disable power isolation on DP-PHY */ /* Disable power isolation on DP-PHY */
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset, 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) 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) ...@@ -45,7 +45,7 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
/* Enable power isolation on DP-PHY */ /* Enable power isolation on DP-PHY */
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset, 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 = { static const struct phy_ops exynos_dp_video_phy_ops = {
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.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/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -21,6 +19,7 @@ ...@@ -21,6 +19,7 @@
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
enum exynos_mipi_phy_id { enum exynos_mipi_phy_id {
...@@ -64,7 +63,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = { ...@@ -64,7 +63,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
{ {
/* EXYNOS_MIPI_PHY_ID_CSIS0 */ /* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, .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_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN, .resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
...@@ -73,7 +72,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = { ...@@ -73,7 +72,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */ /* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, .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_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN, .resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
...@@ -82,7 +81,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = { ...@@ -82,7 +81,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */ /* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1, .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_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN, .resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
...@@ -91,7 +90,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = { ...@@ -91,7 +90,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */ /* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1, .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_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN, .resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
...@@ -109,47 +108,47 @@ static const struct mipi_phy_device_desc exynos5420_mipi_phy = { ...@@ -109,47 +108,47 @@ static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
{ {
/* EXYNOS_MIPI_PHY_ID_CSIS0 */ /* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL, .enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, .resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL, .resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU, .resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, { }, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */ /* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL, .enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN, .resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL, .resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU, .resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, { }, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */ /* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL, .enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, .resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL, .resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU, .resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, { }, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */ /* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL, .enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN, .resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL, .resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU, .resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, { }, {
/* EXYNOS_MIPI_PHY_ID_CSIS2 */ /* EXYNOS_MIPI_PHY_ID_CSIS2 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL, .enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, .resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL, .resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU, .resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, },
}, },
...@@ -172,8 +171,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = { ...@@ -172,8 +171,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
{ {
/* EXYNOS_MIPI_PHY_ID_CSIS0 */ /* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL, .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0), .resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON, .resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
...@@ -181,8 +180,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = { ...@@ -181,8 +180,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */ /* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL, .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0), .resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY, .resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
...@@ -190,8 +189,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = { ...@@ -190,8 +189,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */ /* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL, .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(1), .resetn_val = BIT(1),
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON, .resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
...@@ -199,8 +198,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = { ...@@ -199,8 +198,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */ /* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL, .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(1), .resetn_val = BIT(1),
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY, .resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
...@@ -208,8 +207,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = { ...@@ -208,8 +207,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
}, { }, {
/* EXYNOS_MIPI_PHY_ID_CSIS2 */ /* EXYNOS_MIPI_PHY_ID_CSIS2 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE, .enable_val = EXYNOS4_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL, .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(2),
.enable_map = EXYNOS_MIPI_REGMAP_PMU, .enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0), .resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON, .resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/init.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
...@@ -228,7 +228,6 @@ static const struct of_device_id exynos_pcie_phy_match[] = { ...@@ -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) static int exynos_pcie_phy_probe(struct platform_device *pdev)
{ {
...@@ -278,8 +277,5 @@ static struct platform_driver exynos_pcie_phy_driver = { ...@@ -278,8 +277,5 @@ static struct platform_driver exynos_pcie_phy_driver = {
.name = "exynos_pcie_phy", .name = "exynos_pcie_phy",
} }
}; };
module_platform_driver(exynos_pcie_phy_driver);
MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC PCIe PHY driver"); builtin_platform_driver(exynos_pcie_phy_driver);
MODULE_AUTHOR("Jaehoon Chung <jh80.chung@samsung.com>");
MODULE_LICENSE("GPL v2");
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/exynos5-pmu.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
/* Exynos USB PHY registers */ /* Exynos USB PHY registers */
#define EXYNOS5_FSEL_9MHZ6 0x0 #define EXYNOS5_FSEL_9MHZ6 0x0
...@@ -235,10 +235,10 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst, ...@@ -235,10 +235,10 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
if (!inst->reg_pmu) if (!inst->reg_pmu)
return; return;
val = on ? 0 : EXYNOS5_PHY_ENABLE; val = on ? 0 : EXYNOS4_PHY_ENABLE;
regmap_update_bits(inst->reg_pmu, inst->pmu_offset, regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
EXYNOS5_PHY_ENABLE, val); EXYNOS4_PHY_ENABLE, val);
} }
/* /*
......
...@@ -81,9 +81,9 @@ ...@@ -81,9 +81,9 @@
#define REG_ADP_BC_ACA_PIN_GND BIT(25) #define REG_ADP_BC_ACA_PIN_GND BIT(25)
#define REG_ADP_BC_ACA_PIN_FLOAT BIT(26) #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_DATA_IN_MASK GENMASK(3, 0)
#define REG_TEST_EN_MASK GENMASK(7, 4) #define REG_TEST_EN_MASK GENMASK(7, 4)
#define REG_TEST_ADDR_MASK GENMASK(11, 8) #define REG_TEST_ADDR_MASK GENMASK(11, 8)
...@@ -93,7 +93,7 @@ ...@@ -93,7 +93,7 @@
#define REG_TEST_DATA_OUT_MASK GENMASK(19, 16) #define REG_TEST_DATA_OUT_MASK GENMASK(19, 16)
#define REG_TEST_DISABLE_ID_PULLUP BIT(20) #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_RES_TUNE_MASK GENMASK(1, 0)
#define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2) #define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2)
#define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4) #define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4)
......
...@@ -23,47 +23,55 @@ ...@@ -23,47 +23,55 @@
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
/* /* version V1 sub-banks offset base address */
* for sifslv2 register, but exclude port's; /* banks shared by multiple phys */
* relative to USB3_SIF2_BASE base address #define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
*/ #define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
#define SSUSB_SIFSLV_SPLLC 0x0000 /* u2 phy bank */
#define SSUSB_SIFSLV_U2FREQ 0x0100 #define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
/* u3 phy banks */
/* offsets of sub-segment in each port registers */ #define SSUSB_SIFSLV_V1_U3PHYD 0x000
#define SSUSB_SIFSLV_U2PHY_COM_BASE 0x0000 #define SSUSB_SIFSLV_V1_U3PHYA 0x200
#define SSUSB_SIFSLV_U3PHYD_BASE 0x0100
#define SSUSB_USB30_PHYA_SIV_B_BASE 0x0300 /* version V2 sub-banks offset base address */
#define SSUSB_SIFSLV_U3PHYA_DA_BASE 0x0400 /* u2 phy banks */
#define SSUSB_SIFSLV_V2_MISC 0x000
#define U3P_USBPHYACR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0000) #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 0x000
#define PA0_RG_U2PLL_FORCE_ON BIT(15) #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 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_SRCAL_EN BIT(15)
#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12) #define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) #define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
#define PA5_RG_U2_HS_100U_U3_EN BIT(11) #define PA5_RG_U2_HS_100U_U3_EN BIT(11)
#define U3P_USBPHYACR6 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0018) #define U3P_USBPHYACR6 0x018
#define PA6_RG_U2_ISO_EN BIT(31)
#define PA6_RG_U2_BC11_SW_EN BIT(23) #define PA6_RG_U2_BC11_SW_EN BIT(23)
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20) #define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
#define PA6_RG_U2_SQTH GENMASK(3, 0) #define PA6_RG_U2_SQTH GENMASK(3, 0)
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x)) #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_RG_USB20_GPIO_CTL BIT(9)
#define P2C_USB20_GPIO_MODE BIT(8) #define P2C_USB20_GPIO_MODE BIT(8)
#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE) #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 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_UART_EN BIT(26)
#define P2C_FORCE_DATAIN BIT(23) #define P2C_FORCE_DATAIN BIT(23)
#define P2C_FORCE_DM_PULLDOWN BIT(21) #define P2C_FORCE_DM_PULLDOWN BIT(21)
...@@ -85,47 +93,56 @@ ...@@ -85,47 +93,56 @@
P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \ P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL) 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_UART_EN BIT(16)
#define P2C_RG_VBUSVALID BIT(5) #define P2C_RG_VBUSVALID BIT(5)
#define P2C_RG_SESSEND BIT(4) #define P2C_RG_SESSEND BIT(4)
#define P2C_RG_AVALID BIT(2) #define P2C_RG_AVALID BIT(2)
#define U3P_U3_PHYA_REG0 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0000) #define U3P_U3_PHYA_REG6 0x018
#define P3A_RG_U3_VUSB10_ON BIT(5)
#define U3P_U3_PHYA_REG6 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0018)
#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28) #define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 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 GENMASK(5, 1)
#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 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 GENMASK(11, 10)
#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 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 GENMASK(28, 24)
#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 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 GENMASK(12, 8)
#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 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_XTAL_RX_PWD BIT(9)
#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8) #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 GENMASK(27, 26)
#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26) #define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
#define P2F_RG_FREQDET_EN BIT(24) #define P2F_RG_FREQDET_EN BIT(24)
#define P2F_RG_CYCLECNT GENMASK(23, 0) #define P2F_RG_CYCLECNT GENMASK(23, 0)
#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x)) #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_USB_FM_VALID BIT(0)
#define P2F_RG_FRCK_EN BIT(8) #define P2F_RG_FRCK_EN BIT(8)
...@@ -134,21 +151,46 @@ ...@@ -134,21 +151,46 @@
#define U3P_SR_COEF_DIVISOR 1000 #define U3P_SR_COEF_DIVISOR 1000
#define U3P_FM_DET_CYCLE_CNT 1024 #define U3P_FM_DET_CYCLE_CNT 1024
enum mt_phy_version {
MT_PHY_V1 = 1,
MT_PHY_V2,
};
struct mt65xx_phy_pdata { struct mt65xx_phy_pdata {
/* avoid RX sensitivity level degradation only for mt8173 */ /* avoid RX sensitivity level degradation only for mt8173 */
bool avoid_rx_sen_degradation; 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 mt65xx_phy_instance {
struct phy *phy; struct phy *phy;
void __iomem *port_base; 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; u32 index;
u8 type; u8 type;
}; };
struct mt65xx_u3phy { struct mt65xx_u3phy {
struct device *dev; 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 */ struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
const struct mt65xx_phy_pdata *pdata; const struct mt65xx_phy_pdata *pdata;
struct mt65xx_phy_instance **phys; struct mt65xx_phy_instance **phys;
...@@ -158,49 +200,53 @@ struct mt65xx_u3phy { ...@@ -158,49 +200,53 @@ struct mt65xx_u3phy {
static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
struct mt65xx_phy_instance *instance) 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 calibration_val;
int fm_out; int fm_out;
u32 tmp; u32 tmp;
/* enable USB ring oscillator */ /* enable USB ring oscillator */
tmp = readl(instance->port_base + U3P_USBPHYACR5); tmp = readl(com + U3P_USBPHYACR5);
tmp |= PA5_RG_U2_HSTX_SRCAL_EN; tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
writel(tmp, instance->port_base + U3P_USBPHYACR5); writel(tmp, com + U3P_USBPHYACR5);
udelay(1); udelay(1);
/*enable free run clock */ /*enable free run clock */
tmp = readl(sif_base + U3P_U2FREQ_FMMONR1); tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
tmp |= P2F_RG_FRCK_EN; 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 */ /* 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 | P2F_RG_MONCLK_SEL);
tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT); tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index); if (u3phy->pdata->version == MT_PHY_V1)
writel(tmp, sif_base + U3P_U2FREQ_FMCR0); tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
/* enable frequency meter */ /* enable frequency meter */
tmp = readl(sif_base + U3P_U2FREQ_FMCR0); tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
tmp |= P2F_RG_FREQDET_EN; tmp |= P2F_RG_FREQDET_EN;
writel(tmp, sif_base + U3P_U2FREQ_FMCR0); writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
/* ignore return value */ /* ignore return value */
readl_poll_timeout(sif_base + U3P_U2FREQ_FMMONR1, tmp, readl_poll_timeout(fmreg + U3P_U2FREQ_FMMONR1, tmp,
(tmp & P2F_USB_FM_VALID), 10, 200); (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 */ /* disable frequency meter */
tmp = readl(sif_base + U3P_U2FREQ_FMCR0); tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
tmp &= ~P2F_RG_FREQDET_EN; tmp &= ~P2F_RG_FREQDET_EN;
writel(tmp, sif_base + U3P_U2FREQ_FMCR0); writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
/*disable free run clock */ /*disable free run clock */
tmp = readl(sif_base + U3P_U2FREQ_FMMONR1); tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
tmp &= ~P2F_RG_FRCK_EN; tmp &= ~P2F_RG_FRCK_EN;
writel(tmp, sif_base + U3P_U2FREQ_FMMONR1); writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
if (fm_out) { if (fm_out) {
/* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */ /* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
...@@ -215,85 +261,125 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, ...@@ -215,85 +261,125 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
instance->index, fm_out, calibration_val); instance->index, fm_out, calibration_val);
/* set HS slew rate */ /* 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;
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val); 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 */ /* disable USB ring oscillator */
tmp = readl(instance->port_base + U3P_USBPHYACR5); tmp = readl(com + U3P_USBPHYACR5);
tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN; 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, static void phy_instance_init(struct mt65xx_u3phy *u3phy,
struct mt65xx_phy_instance *instance) 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 index = instance->index;
u32 tmp; u32 tmp;
/* switch to USB function. (system register, force ip into usb mode) */ /* 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_FORCE_UART_EN;
tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0); 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; 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) { if (!index) {
tmp = readl(port_base + U3P_U2PHYACR4); tmp = readl(com + U3P_U2PHYACR4);
tmp &= ~P2C_U2_GPIO_CTR_MSK; 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 (u3phy->pdata->avoid_rx_sen_degradation) {
if (!index) { if (!index) {
tmp = readl(port_base + U3P_USBPHYACR2); tmp = readl(com + U3P_USBPHYACR2);
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; 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; tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0); writel(tmp, com + U3D_U2PHYDCR0);
} else { } else {
tmp = readl(port_base + U3D_U2PHYDCR0); tmp = readl(com + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; 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; 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_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
tmp &= ~PA6_RG_U2_SQTH; tmp &= ~PA6_RG_U2_SQTH;
tmp |= PA6_RG_U2_SQTH_VAL(2); tmp |= PA6_RG_U2_SQTH_VAL(2);
writel(tmp, port_base + U3P_USBPHYACR6); writel(tmp, com + 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);
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index); dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
} }
...@@ -301,58 +387,35 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy, ...@@ -301,58 +387,35 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
struct mt65xx_phy_instance *instance) 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 index = instance->index;
u32 tmp; 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) */ /* (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_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK); tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
writel(tmp, port_base + U3P_U2PHYDTM0); writel(tmp, com + U3P_U2PHYDTM0);
/* OTG Enable */ /* OTG Enable */
tmp = readl(port_base + U3P_USBPHYACR6); tmp = readl(com + U3P_USBPHYACR6);
tmp |= PA6_RG_U2_OTG_VBUSCMP_EN; tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
writel(tmp, port_base + U3P_USBPHYACR6); writel(tmp, com + U3P_USBPHYACR6);
if (!index) { tmp = readl(com + U3P_U2PHYDTM1);
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 |= P2C_RG_VBUSVALID | P2C_RG_AVALID; tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
tmp &= ~P2C_RG_SESSEND; tmp &= ~P2C_RG_SESSEND;
writel(tmp, port_base + U3P_U2PHYDTM1); writel(tmp, com + 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);
if (u3phy->pdata->avoid_rx_sen_degradation && index) { 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; 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; 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); dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
} }
...@@ -360,48 +423,36 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, ...@@ -360,48 +423,36 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
static void phy_instance_power_off(struct mt65xx_u3phy *u3phy, static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
struct mt65xx_phy_instance *instance) 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 index = instance->index;
u32 tmp; u32 tmp;
tmp = readl(port_base + U3P_U2PHYDTM0); tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN); tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
tmp |= P2C_FORCE_SUSPENDM; tmp |= P2C_FORCE_SUSPENDM;
writel(tmp, port_base + U3P_U2PHYDTM0); writel(tmp, com + U3P_U2PHYDTM0);
/* OTG Disable */ /* OTG Disable */
tmp = readl(port_base + U3P_USBPHYACR6); tmp = readl(com + U3P_USBPHYACR6);
tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN; tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
writel(tmp, port_base + U3P_USBPHYACR6); writel(tmp, com + 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);
}
/* let suspendm=0, set utmi into analog power down */ /* let suspendm=0, set utmi into analog power down */
tmp = readl(port_base + U3P_U2PHYDTM0); tmp = readl(com + U3P_U2PHYDTM0);
tmp &= ~P2C_RG_SUSPENDM; tmp &= ~P2C_RG_SUSPENDM;
writel(tmp, port_base + U3P_U2PHYDTM0); writel(tmp, com + U3P_U2PHYDTM0);
udelay(1); udelay(1);
tmp = readl(port_base + U3P_U2PHYDTM1); tmp = readl(com + U3P_U2PHYDTM1);
tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID); tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
tmp |= P2C_RG_SESSEND; tmp |= P2C_RG_SESSEND;
writel(tmp, port_base + U3P_U2PHYDTM1); writel(tmp, com + 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);
}
if (u3phy->pdata->avoid_rx_sen_degradation && index) { 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; 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); dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
...@@ -410,18 +461,55 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy, ...@@ -410,18 +461,55 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
static void phy_instance_exit(struct mt65xx_u3phy *u3phy, static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
struct mt65xx_phy_instance *instance) 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 index = instance->index;
u32 tmp; u32 tmp;
if (u3phy->pdata->avoid_rx_sen_degradation && index) { 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; 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; 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) ...@@ -437,7 +525,17 @@ static int mt65xx_phy_init(struct phy *phy)
return ret; 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; return 0;
} }
...@@ -446,8 +544,10 @@ static int mt65xx_phy_power_on(struct phy *phy) ...@@ -446,8 +544,10 @@ static int mt65xx_phy_power_on(struct phy *phy)
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
phy_instance_power_on(u3phy, instance); if (instance->type == PHY_TYPE_USB2) {
hs_slew_rate_calibrate(u3phy, instance); phy_instance_power_on(u3phy, instance);
hs_slew_rate_calibrate(u3phy, instance);
}
return 0; return 0;
} }
...@@ -456,7 +556,9 @@ static int mt65xx_phy_power_off(struct phy *phy) ...@@ -456,7 +556,9 @@ static int mt65xx_phy_power_off(struct phy *phy)
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); 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; return 0;
} }
...@@ -465,7 +567,10 @@ static int mt65xx_phy_exit(struct phy *phy) ...@@ -465,7 +567,10 @@ static int mt65xx_phy_exit(struct phy *phy)
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); 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); clk_disable_unprepare(u3phy->u3phya_ref);
return 0; return 0;
} }
...@@ -478,7 +583,6 @@ static struct phy *mt65xx_phy_xlate(struct device *dev, ...@@ -478,7 +583,6 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
struct device_node *phy_np = args->np; struct device_node *phy_np = args->np;
int index; int index;
if (args->args_count != 1) { if (args->args_count != 1) {
dev_err(dev, "invalid number of cells in 'phy' property\n"); dev_err(dev, "invalid number of cells in 'phy' property\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -496,13 +600,21 @@ static struct phy *mt65xx_phy_xlate(struct device *dev, ...@@ -496,13 +600,21 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
} }
instance->type = args->args[0]; instance->type = args->args[0];
if (!(instance->type == PHY_TYPE_USB2 || if (!(instance->type == PHY_TYPE_USB2 ||
instance->type == PHY_TYPE_USB3)) { instance->type == PHY_TYPE_USB3)) {
dev_err(dev, "unsupported device type: %d\n", instance->type); dev_err(dev, "unsupported device type: %d\n", instance->type);
return ERR_PTR(-EINVAL); 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; return instance->phy;
} }
...@@ -516,14 +628,22 @@ static const struct phy_ops mt65xx_u3phy_ops = { ...@@ -516,14 +628,22 @@ static const struct phy_ops mt65xx_u3phy_ops = {
static const struct mt65xx_phy_pdata mt2701_pdata = { static const struct mt65xx_phy_pdata mt2701_pdata = {
.avoid_rx_sen_degradation = false, .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 = { static const struct mt65xx_phy_pdata mt8173_pdata = {
.avoid_rx_sen_degradation = true, .avoid_rx_sen_degradation = true,
.version = MT_PHY_V1,
}; };
static const struct of_device_id mt65xx_u3phy_id_table[] = { static const struct of_device_id mt65xx_u3phy_id_table[] = {
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata }, { .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
{ .compatible = "mediatek,mt2712-u3phy", .data = &mt2712_pdata },
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata }, { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
{ }, { },
}; };
...@@ -559,17 +679,23 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev) ...@@ -559,17 +679,23 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
u3phy->dev = dev; u3phy->dev = dev;
platform_set_drvdata(pdev, u3phy); platform_set_drvdata(pdev, u3phy);
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (u3phy->pdata->version == MT_PHY_V1) {
u3phy->sif_base = devm_ioremap_resource(dev, sif_res); /* get banks shared by multiple phys */
if (IS_ERR(u3phy->sif_base)) { sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev_err(dev, "failed to remap sif regs\n"); u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
return PTR_ERR(u3phy->sif_base); 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"); u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
if (IS_ERR(u3phy->u3phya_ref)) { if (IS_ERR(u3phy->u3phya_ref)) {
dev_err(dev, "error to get u3phya_ref\n"); if (PTR_ERR(u3phy->u3phya_ref) == -EPROBE_DEFER)
return PTR_ERR(u3phy->u3phya_ref); return -EPROBE_DEFER;
u3phy->u3phya_ref = NULL;
} }
port = 0; port = 0;
...@@ -610,6 +736,17 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev) ...@@ -610,6 +736,17 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
instance->index = port; instance->index = port;
phy_set_drvdata(phy, instance); phy_set_drvdata(phy, instance);
port++; 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); provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
......
/*
* 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/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <dt-bindings/phy/phy.h>
/* QMP PHY QSERDES COM registers */
#define QSERDES_COM_BG_TIMER 0x00c
#define QSERDES_COM_SSC_EN_CENTER 0x010
#define QSERDES_COM_SSC_ADJ_PER1 0x014
#define QSERDES_COM_SSC_ADJ_PER2 0x018
#define QSERDES_COM_SSC_PER1 0x01c
#define QSERDES_COM_SSC_PER2 0x020
#define QSERDES_COM_SSC_STEP_SIZE1 0x024
#define QSERDES_COM_SSC_STEP_SIZE2 0x028
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x034
#define QSERDES_COM_CLK_ENABLE1 0x038
#define QSERDES_COM_SYS_CLK_CTRL 0x03c
#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x040
#define QSERDES_COM_PLL_IVCO 0x048
#define QSERDES_COM_LOCK_CMP1_MODE0 0x04c
#define QSERDES_COM_LOCK_CMP2_MODE0 0x050
#define QSERDES_COM_LOCK_CMP3_MODE0 0x054
#define QSERDES_COM_LOCK_CMP1_MODE1 0x058
#define QSERDES_COM_LOCK_CMP2_MODE1 0x05c
#define QSERDES_COM_LOCK_CMP3_MODE1 0x060
#define QSERDES_COM_BG_TRIM 0x070
#define QSERDES_COM_CLK_EP_DIV 0x074
#define QSERDES_COM_CP_CTRL_MODE0 0x078
#define QSERDES_COM_CP_CTRL_MODE1 0x07c
#define QSERDES_COM_PLL_RCTRL_MODE0 0x084
#define QSERDES_COM_PLL_RCTRL_MODE1 0x088
#define QSERDES_COM_PLL_CCTRL_MODE0 0x090
#define QSERDES_COM_PLL_CCTRL_MODE1 0x094
#define QSERDES_COM_SYSCLK_EN_SEL 0x0ac
#define QSERDES_COM_RESETSM_CNTRL 0x0b4
#define QSERDES_COM_RESTRIM_CTRL 0x0bc
#define QSERDES_COM_RESCODE_DIV_NUM 0x0c4
#define QSERDES_COM_LOCK_CMP_EN 0x0c8
#define QSERDES_COM_LOCK_CMP_CFG 0x0cc
#define QSERDES_COM_DEC_START_MODE0 0x0d0
#define QSERDES_COM_DEC_START_MODE1 0x0d4
#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x0dc
#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x0e0
#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x0e4
#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x0e8
#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x0ec
#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x0f0
#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x108
#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10c
#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x110
#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x114
#define QSERDES_COM_VCO_TUNE_CTRL 0x124
#define QSERDES_COM_VCO_TUNE_MAP 0x128
#define QSERDES_COM_VCO_TUNE1_MODE0 0x12c
#define QSERDES_COM_VCO_TUNE2_MODE0 0x130
#define QSERDES_COM_VCO_TUNE1_MODE1 0x134
#define QSERDES_COM_VCO_TUNE2_MODE1 0x138
#define QSERDES_COM_VCO_TUNE_TIMER1 0x144
#define QSERDES_COM_VCO_TUNE_TIMER2 0x148
#define QSERDES_COM_BG_CTRL 0x170
#define QSERDES_COM_CLK_SELECT 0x174
#define QSERDES_COM_HSCLK_SEL 0x178
#define QSERDES_COM_CORECLK_DIV 0x184
#define QSERDES_COM_CORE_CLK_EN 0x18c
#define QSERDES_COM_C_READY_STATUS 0x190
#define QSERDES_COM_CMN_CONFIG 0x194
#define QSERDES_COM_SVS_MODE_CLK_SEL 0x19c
#define QSERDES_COM_DEBUG_BUS0 0x1a0
#define QSERDES_COM_DEBUG_BUS1 0x1a4
#define QSERDES_COM_DEBUG_BUS2 0x1a8
#define QSERDES_COM_DEBUG_BUS3 0x1ac
#define QSERDES_COM_DEBUG_BUS_SEL 0x1b0
#define QSERDES_COM_CORECLK_DIV_MODE1 0x1bc
/* QMP PHY TX registers */
#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x054
#define QSERDES_TX_DEBUG_BUS_SEL 0x064
#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x068
#define QSERDES_TX_LANE_MODE 0x094
#define QSERDES_TX_RCV_DETECT_LVL_2 0x0ac
/* QMP PHY RX registers */
#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010
#define QSERDES_RX_UCDR_SO_GAIN 0x01c
#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040
#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048
#define QSERDES_RX_RX_TERM_BW 0x090
#define QSERDES_RX_RX_EQ_GAIN1_LSB 0x0c4
#define QSERDES_RX_RX_EQ_GAIN1_MSB 0x0c8
#define QSERDES_RX_RX_EQ_GAIN2_LSB 0x0cc
#define QSERDES_RX_RX_EQ_GAIN2_MSB 0x0d0
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d8
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x0dc
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x0e0
#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x108
#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x10c
#define QSERDES_RX_SIGDET_ENABLES 0x110
#define QSERDES_RX_SIGDET_CNTRL 0x114
#define QSERDES_RX_SIGDET_LVL 0x118
#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x11c
#define QSERDES_RX_RX_BAND 0x120
#define QSERDES_RX_RX_INTERFACE_MODE 0x12c
/* QMP PHY PCS registers */
#define QPHY_POWER_DOWN_CONTROL 0x04
#define QPHY_TXDEEMPH_M6DB_V0 0x24
#define QPHY_TXDEEMPH_M3P5DB_V0 0x28
#define QPHY_ENDPOINT_REFCLK_DRIVE 0x54
#define QPHY_RX_IDLE_DTCT_CNTRL 0x58
#define QPHY_POWER_STATE_CONFIG1 0x60
#define QPHY_POWER_STATE_CONFIG2 0x64
#define QPHY_POWER_STATE_CONFIG4 0x6c
#define QPHY_LOCK_DETECT_CONFIG1 0x80
#define QPHY_LOCK_DETECT_CONFIG2 0x84
#define QPHY_LOCK_DETECT_CONFIG3 0x88
#define QPHY_PWRUP_RESET_DLY_TIME_AUXCLK 0xa0
#define QPHY_LP_WAKEUP_DLY_TIME_AUXCLK 0xa4
/* QPHY_SW_RESET bit */
#define SW_RESET BIT(0)
/* QPHY_POWER_DOWN_CONTROL */
#define SW_PWRDN BIT(0)
#define REFCLK_DRV_DSBL BIT(1)
/* QPHY_START_CONTROL bits */
#define SERDES_START BIT(0)
#define PCS_START BIT(1)
#define PLL_READY_GATE_EN BIT(3)
/* QPHY_PCS_STATUS bit */
#define PHYSTATUS BIT(6)
/* QPHY_COM_PCS_READY_STATUS bit */
#define PCS_READY BIT(0)
#define PHY_INIT_COMPLETE_TIMEOUT 1000
#define POWER_DOWN_DELAY_US_MIN 10
#define POWER_DOWN_DELAY_US_MAX 11
#define MAX_PROP_NAME 32
struct qmp_phy_init_tbl {
unsigned int offset;
unsigned int val;
/*
* register part of layout ?
* if yes, then offset gives index in the reg-layout
*/
int in_layout;
};
#define QMP_PHY_INIT_CFG(o, v) \
{ \
.offset = o, \
.val = v, \
}
#define QMP_PHY_INIT_CFG_L(o, v) \
{ \
.offset = o, \
.val = v, \
.in_layout = 1, \
}
/* set of registers with offsets different per-PHY */
enum qphy_reg_layout {
/* Common block control registers */
QPHY_COM_SW_RESET,
QPHY_COM_POWER_DOWN_CONTROL,
QPHY_COM_START_CONTROL,
QPHY_COM_PCS_READY_STATUS,
/* PCS registers */
QPHY_PLL_LOCK_CHK_DLY_TIME,
QPHY_FLL_CNTRL1,
QPHY_FLL_CNTRL2,
QPHY_FLL_CNT_VAL_L,
QPHY_FLL_CNT_VAL_H_TOL,
QPHY_FLL_MAN_CODE,
QPHY_SW_RESET,
QPHY_START_CTRL,
QPHY_PCS_READY_STATUS,
};
static const unsigned int pciephy_regs_layout[] = {
[QPHY_COM_SW_RESET] = 0x400,
[QPHY_COM_POWER_DOWN_CONTROL] = 0x404,
[QPHY_COM_START_CONTROL] = 0x408,
[QPHY_COM_PCS_READY_STATUS] = 0x448,
[QPHY_PLL_LOCK_CHK_DLY_TIME] = 0xa8,
[QPHY_FLL_CNTRL1] = 0xc4,
[QPHY_FLL_CNTRL2] = 0xc8,
[QPHY_FLL_CNT_VAL_L] = 0xcc,
[QPHY_FLL_CNT_VAL_H_TOL] = 0xd0,
[QPHY_FLL_MAN_CODE] = 0xd4,
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x08,
[QPHY_PCS_READY_STATUS] = 0x174,
};
static const unsigned int usb3phy_regs_layout[] = {
[QPHY_FLL_CNTRL1] = 0xc0,
[QPHY_FLL_CNTRL2] = 0xc4,
[QPHY_FLL_CNT_VAL_L] = 0xc8,
[QPHY_FLL_CNT_VAL_H_TOL] = 0xcc,
[QPHY_FLL_MAN_CODE] = 0xd0,
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x08,
[QPHY_PCS_READY_STATUS] = 0x17c,
};
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x33),
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x42),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x1f),
QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x09),
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x1a),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x33),
QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1f),
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x04),
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x02),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19),
QMP_PHY_INIT_CFG(QSERDES_COM_RESCODE_DIV_NUM, 0x15),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_RESCODE_DIV_NUM, 0x40),
};
static const struct qmp_phy_init_tbl msm8996_pcie_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06),
};
static const struct qmp_phy_init_tbl msm8996_pcie_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x00),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_BAND, 0x18),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN_HALF, 0x04),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x19),
};
static const struct qmp_phy_init_tbl msm8996_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_RX_IDLE_DTCT_CNTRL, 0x4c),
QMP_PHY_INIT_CFG(QPHY_PWRUP_RESET_DLY_TIME_AUXCLK, 0x00),
QMP_PHY_INIT_CFG(QPHY_LP_WAKEUP_DLY_TIME_AUXCLK, 0x01),
QMP_PHY_INIT_CFG_L(QPHY_PLL_LOCK_CHK_DLY_TIME, 0x05),
QMP_PHY_INIT_CFG(QPHY_ENDPOINT_REFCLK_DRIVE, 0x05),
QMP_PHY_INIT_CFG(QPHY_POWER_DOWN_CONTROL, 0x02),
QMP_PHY_INIT_CFG(QPHY_POWER_STATE_CONFIG4, 0x00),
QMP_PHY_INIT_CFG(QPHY_POWER_STATE_CONFIG1, 0xa3),
QMP_PHY_INIT_CFG(QPHY_TXDEEMPH_M3P5DB_V0, 0x0e),
};
static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06),
QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x04),
/* PLL and Loop filter settings */
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03),
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),
/* SSC settings */
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07),
};
static const struct qmp_phy_init_tbl msm8996_usb3_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12),
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06),
};
static const struct qmp_phy_init_tbl msm8996_usb3_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xbb),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x03),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x18),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x16),
};
static const struct qmp_phy_init_tbl msm8996_usb3_pcs_tbl[] = {
/* FLL settings */
QMP_PHY_INIT_CFG_L(QPHY_FLL_CNTRL2, 0x03),
QMP_PHY_INIT_CFG_L(QPHY_FLL_CNTRL1, 0x02),
QMP_PHY_INIT_CFG_L(QPHY_FLL_CNT_VAL_L, 0x09),
QMP_PHY_INIT_CFG_L(QPHY_FLL_CNT_VAL_H_TOL, 0x42),
QMP_PHY_INIT_CFG_L(QPHY_FLL_MAN_CODE, 0x85),
/* Lock Det settings */
QMP_PHY_INIT_CFG(QPHY_LOCK_DETECT_CONFIG1, 0xd1),
QMP_PHY_INIT_CFG(QPHY_LOCK_DETECT_CONFIG2, 0x1f),
QMP_PHY_INIT_CFG(QPHY_LOCK_DETECT_CONFIG3, 0x47),
QMP_PHY_INIT_CFG(QPHY_POWER_STATE_CONFIG2, 0x08),
};
/* struct qmp_phy_cfg - per-PHY initialization config */
struct qmp_phy_cfg {
/* phy-type - PCIE/UFS/USB */
unsigned int type;
/* number of lanes provided by phy */
int nlanes;
/* Init sequence for PHY blocks - serdes, tx, rx, pcs */
const struct qmp_phy_init_tbl *serdes_tbl;
int serdes_tbl_num;
const struct qmp_phy_init_tbl *tx_tbl;
int tx_tbl_num;
const struct qmp_phy_init_tbl *rx_tbl;
int rx_tbl_num;
const struct qmp_phy_init_tbl *pcs_tbl;
int pcs_tbl_num;
/* clock ids to be requested */
const char * const *clk_list;
int num_clks;
/* resets to be requested */
const char * const *reset_list;
int num_resets;
/* regulators to be requested */
const char * const *vreg_list;
int num_vregs;
/* array of registers with different offsets */
const unsigned int *regs;
unsigned int start_ctrl;
unsigned int pwrdn_ctrl;
unsigned int mask_pcs_ready;
unsigned int mask_com_pcs_ready;
/* true, if PHY has a separate PHY_COM control block */
bool has_phy_com_ctrl;
/* true, if PHY has a reset for individual lanes */
bool has_lane_rst;
/* true, if PHY needs delay after POWER_DOWN */
bool has_pwrdn_delay;
/* power_down delay in usec */
int pwrdn_delay_min;
int pwrdn_delay_max;
};
/**
* struct qmp_phy - per-lane phy descriptor
*
* @phy: generic phy
* @tx: iomapped memory space for lane's tx
* @rx: iomapped memory space for lane's rx
* @pcs: iomapped memory space for lane's pcs
* @pipe_clk: pipe lock
* @index: lane index
* @qmp: QMP phy to which this lane belongs
* @lane_rst: lane's reset controller
*/
struct qmp_phy {
struct phy *phy;
void __iomem *tx;
void __iomem *rx;
void __iomem *pcs;
struct clk *pipe_clk;
unsigned int index;
struct qcom_qmp *qmp;
struct reset_control *lane_rst;
};
/**
* struct qcom_qmp - structure holding QMP phy block attributes
*
* @dev: device
* @serdes: iomapped memory space for phy's serdes
*
* @clks: array of clocks required by phy
* @resets: array of resets required by phy
* @vregs: regulator supplies bulk data
*
* @cfg: phy specific configuration
* @phys: array of per-lane phy descriptors
* @phy_mutex: mutex lock for PHY common block initialization
* @init_count: phy common block initialization count
*/
struct qcom_qmp {
struct device *dev;
void __iomem *serdes;
struct clk **clks;
struct reset_control **resets;
struct regulator_bulk_data *vregs;
const struct qmp_phy_cfg *cfg;
struct qmp_phy **phys;
struct mutex phy_mutex;
int init_count;
};
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
{
u32 reg;
reg = readl(base + offset);
reg |= val;
writel(reg, base + offset);
/* ensure that above write is through */
readl(base + offset);
}
static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val)
{
u32 reg;
reg = readl(base + offset);
reg &= ~val;
writel(reg, base + offset);
/* ensure that above write is through */
readl(base + offset);
}
/* list of clocks required by phy */
static const char * const msm8996_phy_clk_l[] = {
"aux", "cfg_ahb", "ref",
};
/* list of resets */
static const char * const msm8996_pciephy_reset_l[] = {
"phy", "common", "cfg",
};
static const char * const msm8996_usb3phy_reset_l[] = {
"phy", "common",
};
/* list of regulators */
static const char * const msm8996_phy_vreg_l[] = {
"vdda-phy", "vdda-pll",
};
static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
.type = PHY_TYPE_PCIE,
.nlanes = 3,
.serdes_tbl = msm8996_pcie_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(msm8996_pcie_serdes_tbl),
.tx_tbl = msm8996_pcie_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(msm8996_pcie_tx_tbl),
.rx_tbl = msm8996_pcie_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(msm8996_pcie_rx_tbl),
.pcs_tbl = msm8996_pcie_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(msm8996_pcie_pcs_tbl),
.clk_list = msm8996_phy_clk_l,
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
.reset_list = msm8996_pciephy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l),
.vreg_list = msm8996_phy_vreg_l,
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
.regs = pciephy_regs_layout,
.start_ctrl = PCS_START | PLL_READY_GATE_EN,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.mask_com_pcs_ready = PCS_READY,
.has_phy_com_ctrl = true,
.has_lane_rst = true,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
};
static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
.type = PHY_TYPE_USB3,
.nlanes = 1,
.serdes_tbl = msm8996_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(msm8996_usb3_serdes_tbl),
.tx_tbl = msm8996_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(msm8996_usb3_tx_tbl),
.rx_tbl = msm8996_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(msm8996_usb3_rx_tbl),
.pcs_tbl = msm8996_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(msm8996_usb3_pcs_tbl),
.clk_list = msm8996_phy_clk_l,
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = msm8996_phy_vreg_l,
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
.regs = usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
.mask_pcs_ready = PHYSTATUS,
};
static void qcom_qmp_phy_configure(void __iomem *base,
const unsigned int *regs,
const struct qmp_phy_init_tbl tbl[],
int num)
{
int i;
const struct qmp_phy_init_tbl *t = tbl;
if (!t)
return;
for (i = 0; i < num; i++, t++) {
if (t->in_layout)
writel(t->val, base + regs[t->offset]);
else
writel(t->val, base + t->offset);
}
}
static int qcom_qmp_phy_poweron(struct phy *phy)
{
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
int num = qmp->cfg->num_vregs;
int ret;
dev_vdbg(&phy->dev, "Powering on QMP phy\n");
/* turn on regulator supplies */
ret = regulator_bulk_enable(num, qmp->vregs);
if (ret) {
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
return ret;
}
ret = clk_prepare_enable(qphy->pipe_clk);
if (ret) {
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
regulator_bulk_disable(num, qmp->vregs);
return ret;
}
return 0;
}
static int qcom_qmp_phy_poweroff(struct phy *phy)
{
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
clk_disable_unprepare(qphy->pipe_clk);
regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
return 0;
}
static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *serdes = qmp->serdes;
int ret, i;
mutex_lock(&qmp->phy_mutex);
if (qmp->init_count++) {
mutex_unlock(&qmp->phy_mutex);
return 0;
}
for (i = 0; i < cfg->num_resets; i++) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
dev_err(qmp->dev, "%s reset deassert failed\n",
qmp->cfg->reset_list[i]);
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
goto err_rst;
}
}
if (cfg->has_phy_com_ctrl)
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
SW_PWRDN);
/* Serdes configuration */
qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl,
cfg->serdes_tbl_num);
if (cfg->has_phy_com_ctrl) {
void __iomem *status;
unsigned int mask, val;
qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET);
qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL],
SERDES_START | PCS_START);
status = serdes + cfg->regs[QPHY_COM_PCS_READY_STATUS];
mask = cfg->mask_com_pcs_ready;
ret = readl_poll_timeout(status, val, (val & mask), 10,
PHY_INIT_COMPLETE_TIMEOUT);
if (ret) {
dev_err(qmp->dev,
"phy common block init timed-out\n");
goto err_com_init;
}
}
mutex_unlock(&qmp->phy_mutex);
return 0;
err_com_init:
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
err_rst:
mutex_unlock(&qmp->phy_mutex);
return ret;
}
static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *serdes = qmp->serdes;
int i = cfg->num_resets;
mutex_lock(&qmp->phy_mutex);
if (--qmp->init_count) {
mutex_unlock(&qmp->phy_mutex);
return 0;
}
if (cfg->has_phy_com_ctrl) {
qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL],
SERDES_START | PCS_START);
qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET],
SW_RESET);
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
SW_PWRDN);
}
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
mutex_unlock(&qmp->phy_mutex);
return 0;
}
/* PHY Initialization */
static int qcom_qmp_phy_init(struct phy *phy)
{
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *tx = qphy->tx;
void __iomem *rx = qphy->rx;
void __iomem *pcs = qphy->pcs;
void __iomem *status;
unsigned int mask, val;
int ret, i;
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
for (i = 0; i < qmp->cfg->num_clks; i++) {
ret = clk_prepare_enable(qmp->clks[i]);
if (ret) {
dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
qmp->cfg->clk_list[i], ret);
while (--i >= 0)
clk_disable_unprepare(qmp->clks[i]);
}
}
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
goto err_com_init;
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
if (ret) {
dev_err(qmp->dev, "lane%d reset deassert failed\n",
qphy->index);
goto err_lane_rst;
}
}
/* Tx, Rx, and PCS configurations */
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num);
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
/*
* Pull out PHY from POWER DOWN state.
* This is active low enable signal to power-down PHY.
*/
qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
if (cfg->has_pwrdn_delay)
usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
/* start SerDes and Phy-Coding-Sublayer */
qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
/* Pull PHY out of reset state */
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
ret = readl_poll_timeout(status, val, !(val & mask), 1,
PHY_INIT_COMPLETE_TIMEOUT);
if (ret) {
dev_err(qmp->dev, "phy initialization timed-out\n");
goto err_pcs_ready;
}
return ret;
err_pcs_ready:
if (cfg->has_lane_rst)
reset_control_assert(qphy->lane_rst);
err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
err_com_init:
while (--i >= 0)
clk_disable_unprepare(qmp->clks[i]);
return ret;
}
static int qcom_qmp_phy_exit(struct phy *phy)
{
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
int i = cfg->num_clks;
/* PHY reset */
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
/* stop SerDes and Phy-Coding-Sublayer */
qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
/* Put PHY into POWER DOWN state: active low */
qphy_clrbits(qphy->pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
if (cfg->has_lane_rst)
reset_control_assert(qphy->lane_rst);
qcom_qmp_phy_com_exit(qmp);
while (--i >= 0)
clk_disable_unprepare(qmp->clks[i]);
return 0;
}
static int qcom_qmp_phy_vreg_init(struct device *dev)
{
struct qcom_qmp *qmp = dev_get_drvdata(dev);
int num = qmp->cfg->num_vregs;
int i;
qmp->vregs = devm_kcalloc(dev, num, sizeof(qmp->vregs), GFP_KERNEL);
if (!qmp->vregs)
return -ENOMEM;
for (i = 0; i < num; i++)
qmp->vregs[i].supply = qmp->cfg->vreg_list[i];
return devm_regulator_bulk_get(dev, num, qmp->vregs);
}
static int qcom_qmp_phy_reset_init(struct device *dev)
{
struct qcom_qmp *qmp = dev_get_drvdata(dev);
int i;
qmp->resets = devm_kcalloc(dev, qmp->cfg->num_resets,
sizeof(*qmp->resets), GFP_KERNEL);
if (!qmp->resets)
return -ENOMEM;
for (i = 0; i < qmp->cfg->num_resets; i++) {
struct reset_control *rst;
const char *name = qmp->cfg->reset_list[i];
rst = devm_reset_control_get(dev, name);
if (IS_ERR(rst)) {
dev_err(dev, "failed to get %s reset\n", name);
return PTR_ERR(rst);
}
qmp->resets[i] = rst;
}
return 0;
}
static int qcom_qmp_phy_clk_init(struct device *dev)
{
struct qcom_qmp *qmp = dev_get_drvdata(dev);
int ret, i;
qmp->clks = devm_kcalloc(dev, qmp->cfg->num_clks,
sizeof(*qmp->clks), GFP_KERNEL);
if (!qmp->clks)
return -ENOMEM;
for (i = 0; i < qmp->cfg->num_clks; i++) {
struct clk *_clk;
const char *name = qmp->cfg->clk_list[i];
_clk = devm_clk_get(dev, name);
if (IS_ERR(_clk)) {
ret = PTR_ERR(_clk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get %s clk, %d\n",
name, ret);
return ret;
}
qmp->clks[i] = _clk;
}
return 0;
}
/*
* Register a fixed rate pipe clock.
*
* The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
* controls it. The <s>_pipe_clk coming out of the GCC is requested
* by the PHY driver for its operations.
* We register the <s>_pipe_clksrc here. The gcc driver takes care
* of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
* Below picture shows this relationship.
*
* +---------------+
* | PHY block |<<---------------------------------------+
* | | |
* | +-------+ | +-----+ |
* I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
* clk | +-------+ | +-----+
* +---------------+
*/
static int phy_pipe_clk_register(struct qcom_qmp *qmp, int id)
{
char name[24];
struct clk_fixed_rate *fixed;
struct clk_init_data init = { };
switch (qmp->cfg->type) {
case PHY_TYPE_USB3:
snprintf(name, sizeof(name), "usb3_phy_pipe_clk_src");
break;
case PHY_TYPE_PCIE:
snprintf(name, sizeof(name), "pcie_%d_pipe_clk_src", id);
break;
default:
/* not all phys register pipe clocks, so return success */
return 0;
}
fixed = devm_kzalloc(qmp->dev, sizeof(*fixed), GFP_KERNEL);
if (!fixed)
return -ENOMEM;
init.name = name;
init.ops = &clk_fixed_rate_ops;
/* controllers using QMP phys use 125MHz pipe clock interface */
fixed->fixed_rate = 125000000;
fixed->hw.init = &init;
return devm_clk_hw_register(qmp->dev, &fixed->hw);
}
static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init = qcom_qmp_phy_init,
.exit = qcom_qmp_phy_exit,
.power_on = qcom_qmp_phy_poweron,
.power_off = qcom_qmp_phy_poweroff,
.owner = THIS_MODULE,
};
static
int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id)
{
struct qcom_qmp *qmp = dev_get_drvdata(dev);
struct phy *generic_phy;
struct qmp_phy *qphy;
char prop_name[MAX_PROP_NAME];
int ret;
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
if (!qphy)
return -ENOMEM;
/*
* Get memory resources for each phy lane:
* Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
*/
qphy->tx = of_iomap(np, 0);
if (IS_ERR(qphy->tx))
return PTR_ERR(qphy->tx);
qphy->rx = of_iomap(np, 1);
if (IS_ERR(qphy->rx))
return PTR_ERR(qphy->rx);
qphy->pcs = of_iomap(np, 2);
if (IS_ERR(qphy->pcs))
return PTR_ERR(qphy->pcs);
/*
* Get PHY's Pipe clock, if any. USB3 and PCIe are PIPE3
* based phys, so they essentially have pipe clock. So,
* we return error in case phy is USB3 or PIPE type.
* Otherwise, we initialize pipe clock to NULL for
* all phys that don't need this.
*/
snprintf(prop_name, sizeof(prop_name), "pipe%d", id);
qphy->pipe_clk = of_clk_get_by_name(np, prop_name);
if (IS_ERR(qphy->pipe_clk)) {
if (qmp->cfg->type == PHY_TYPE_PCIE ||
qmp->cfg->type == PHY_TYPE_USB3) {
ret = PTR_ERR(qphy->pipe_clk);
if (ret != -EPROBE_DEFER)
dev_err(dev,
"failed to get lane%d pipe_clk, %d\n",
id, ret);
return ret;
}
qphy->pipe_clk = NULL;
}
/* Get lane reset, if any */
if (qmp->cfg->has_lane_rst) {
snprintf(prop_name, sizeof(prop_name), "lane%d", id);
qphy->lane_rst = of_reset_control_get(np, prop_name);
if (IS_ERR(qphy->lane_rst)) {
dev_err(dev, "failed to get lane%d reset\n", id);
return PTR_ERR(qphy->lane_rst);
}
}
generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_gen_ops);
if (IS_ERR(generic_phy)) {
ret = PTR_ERR(generic_phy);
dev_err(dev, "failed to create qphy %d\n", ret);
return ret;
}
qphy->phy = generic_phy;
qphy->index = id;
qphy->qmp = qmp;
qmp->phys[id] = qphy;
phy_set_drvdata(generic_phy, qphy);
return 0;
}
static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
{
.compatible = "qcom,msm8996-qmp-pcie-phy",
.data = &msm8996_pciephy_cfg,
}, {
.compatible = "qcom,msm8996-qmp-usb3-phy",
.data = &msm8996_usb3phy_cfg,
},
{ },
};
MODULE_DEVICE_TABLE(of, qcom_qmp_phy_of_match_table);
static int qcom_qmp_phy_probe(struct platform_device *pdev)
{
struct qcom_qmp *qmp;
struct device *dev = &pdev->dev;
struct resource *res;
struct device_node *child;
struct phy_provider *phy_provider;
void __iomem *base;
int num, id;
int ret;
qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
if (!qmp)
return -ENOMEM;
qmp->dev = dev;
dev_set_drvdata(dev, qmp);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
/* per PHY serdes; usually located at base address */
qmp->serdes = base;
mutex_init(&qmp->phy_mutex);
/* Get the specific init parameters of QMP phy */
qmp->cfg = of_device_get_match_data(dev);
ret = qcom_qmp_phy_clk_init(dev);
if (ret)
return ret;
ret = qcom_qmp_phy_reset_init(dev);
if (ret)
return ret;
ret = qcom_qmp_phy_vreg_init(dev);
if (ret) {
dev_err(dev, "failed to get regulator supplies\n");
return ret;
}
num = of_get_available_child_count(dev->of_node);
/* do we have a rogue child node ? */
if (num > qmp->cfg->nlanes)
return -EINVAL;
qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL);
if (!qmp->phys)
return -ENOMEM;
id = 0;
for_each_available_child_of_node(dev->of_node, child) {
/* Create per-lane phy */
ret = qcom_qmp_phy_create(dev, child, id);
if (ret) {
dev_err(dev, "failed to create lane%d phy, %d\n",
id, ret);
return ret;
}
/*
* Register the pipe clock provided by phy.
* See function description to see details of this pipe clock.
*/
ret = phy_pipe_clk_register(qmp, id);
if (ret) {
dev_err(qmp->dev,
"failed to register pipe clock source\n");
return ret;
}
id++;
}
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider))
dev_info(dev, "Registered Qcom-QMP phy\n");
return PTR_ERR_OR_ZERO(phy_provider);
}
static struct platform_driver qcom_qmp_phy_driver = {
.probe = qcom_qmp_phy_probe,
.driver = {
.name = "qcom-qmp-phy",
.of_match_table = qcom_qmp_phy_of_match_table,
},
};
module_platform_driver(qcom_qmp_phy_driver);
MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm QMP PHY driver");
MODULE_LICENSE("GPL v2");
/*
* 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 @@ ...@@ -20,6 +20,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -395,7 +396,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -395,7 +396,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct rcar_gen3_chan *channel; struct rcar_gen3_chan *channel;
struct phy_provider *provider; struct phy_provider *provider;
struct resource *res; struct resource *res;
int irq; int irq, ret = 0;
if (!dev->of_node) { if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n"); dev_err(dev, "This driver needs device tree\n");
...@@ -434,17 +435,24 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -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); channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
if (IS_ERR(channel->phy)) { if (IS_ERR(channel->phy)) {
dev_err(dev, "Failed to create USB2 PHY\n"); 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"); channel->vbus = devm_regulator_get_optional(dev, "vbus");
if (IS_ERR(channel->vbus)) { if (IS_ERR(channel->vbus)) {
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) {
return PTR_ERR(channel->vbus); ret = PTR_ERR(channel->vbus);
goto error;
}
channel->vbus = NULL; channel->vbus = NULL;
} }
...@@ -454,15 +462,22 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -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); provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider)) { if (IS_ERR(provider)) {
dev_err(dev, "Failed to register PHY provider\n"); dev_err(dev, "Failed to register PHY provider\n");
ret = PTR_ERR(provider);
goto error;
} else if (channel->has_otg) { } else if (channel->has_otg) {
int ret; int ret;
ret = device_create_file(dev, &dev_attr_role); ret = device_create_file(dev, &dev_attr_role);
if (ret < 0) 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) 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) ...@@ -472,6 +487,8 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
if (channel->has_otg) if (channel->has_otg)
device_remove_file(&pdev->dev, &dev_attr_role); device_remove_file(&pdev->dev, &dev_attr_role);
pm_runtime_disable(&pdev->dev);
return 0; return 0;
}; };
......
...@@ -554,8 +554,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) ...@@ -554,8 +554,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
case USB_CHG_STATE_DETECTED: case USB_CHG_STATE_DETECTED:
switch (rphy->chg_type) { switch (rphy->chg_type) {
case POWER_SUPPLY_TYPE_USB: case POWER_SUPPLY_TYPE_USB:
dev_dbg(&rport->phy->dev, dev_dbg(&rport->phy->dev, "sdp cable is connected\n");
"sdp cable is connecetd\n");
rockchip_usb2phy_power_on(rport->phy); rockchip_usb2phy_power_on(rport->phy);
rport->state = OTG_STATE_B_PERIPHERAL; rport->state = OTG_STATE_B_PERIPHERAL;
notify_charger = true; notify_charger = true;
...@@ -563,16 +562,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) ...@@ -563,16 +562,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
cable = EXTCON_CHG_USB_SDP; cable = EXTCON_CHG_USB_SDP;
break; break;
case POWER_SUPPLY_TYPE_USB_DCP: case POWER_SUPPLY_TYPE_USB_DCP:
dev_dbg(&rport->phy->dev, dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
"dcp cable is connecetd\n");
rockchip_usb2phy_power_off(rport->phy); rockchip_usb2phy_power_off(rport->phy);
notify_charger = true; notify_charger = true;
sch_work = true; sch_work = true;
cable = EXTCON_CHG_USB_DCP; cable = EXTCON_CHG_USB_DCP;
break; break;
case POWER_SUPPLY_TYPE_USB_CDP: case POWER_SUPPLY_TYPE_USB_CDP:
dev_dbg(&rport->phy->dev, dev_dbg(&rport->phy->dev, "cdp cable is connected\n");
"cdp cable is connecetd\n");
rockchip_usb2phy_power_on(rport->phy); rockchip_usb2phy_power_on(rport->phy);
rport->state = OTG_STATE_B_PERIPHERAL; rport->state = OTG_STATE_B_PERIPHERAL;
notify_charger = true; notify_charger = true;
...@@ -1141,6 +1138,49 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) ...@@ -1141,6 +1138,49 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
return ret; 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[] = { static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
{ {
.reg = 0x700, .reg = 0x700,
...@@ -1223,6 +1263,7 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { ...@@ -1223,6 +1263,7 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
}; };
static const struct of_device_id rockchip_usb2phy_dt_match[] = { 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,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
{} {}
......
...@@ -66,6 +66,7 @@ struct rockchip_usb_phy { ...@@ -66,6 +66,7 @@ struct rockchip_usb_phy {
struct phy *phy; struct phy *phy;
bool uart_enabled; bool uart_enabled;
struct reset_control *reset; struct reset_control *reset;
struct regulator *vbus;
}; };
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, 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) ...@@ -88,6 +89,9 @@ static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
struct rockchip_usb_phy, struct rockchip_usb_phy,
clk480m_hw); clk480m_hw);
if (phy->vbus)
regulator_disable(phy->vbus);
/* Power down usb phy analog blocks by set siddq 1 */ /* Power down usb phy analog blocks by set siddq 1 */
rockchip_usb_phy_power(phy, 1); rockchip_usb_phy_power(phy, 1);
} }
...@@ -143,6 +147,14 @@ static int rockchip_usb_phy_power_on(struct phy *_phy) ...@@ -143,6 +147,14 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
if (phy->uart_enabled) if (phy->uart_enabled)
return -EBUSY; return -EBUSY;
if (phy->vbus) {
int ret;
ret = regulator_enable(phy->vbus);
if (ret)
return ret;
}
return clk_prepare_enable(phy->clk480m); return clk_prepare_enable(phy->clk480m);
} }
...@@ -268,6 +280,13 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, ...@@ -268,6 +280,13 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
} }
phy_set_drvdata(rk_phy->phy, rk_phy); 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 * When acting as uart-pipe, just keep clock on otherwise
* only power up usb phy when it use, so disable it when init * only power up usb phy when it use, so disable it when init
......
...@@ -49,12 +49,14 @@ ...@@ -49,12 +49,14 @@
#define REG_PHYBIST 0x08 #define REG_PHYBIST 0x08
#define REG_PHYTUNE 0x0c #define REG_PHYTUNE 0x0c
#define REG_PHYCTL_A33 0x10 #define REG_PHYCTL_A33 0x10
#define REG_PHY_UNK_H3 0x20 #define REG_PHY_OTGCTL 0x20
#define REG_PMU_UNK1 0x10 #define REG_PMU_UNK1 0x10
#define PHYCTL_DATA BIT(7) #define PHYCTL_DATA BIT(7)
#define OTGCTL_ROUTE_MUSB BIT(0)
#define SUNXI_AHB_ICHR8_EN BIT(10) #define SUNXI_AHB_ICHR8_EN BIT(10)
#define SUNXI_AHB_INCR4_BURST_EN BIT(9) #define SUNXI_AHB_INCR4_BURST_EN BIT(9)
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) #define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
...@@ -110,6 +112,7 @@ struct sun4i_usb_phy_cfg { ...@@ -110,6 +112,7 @@ struct sun4i_usb_phy_cfg {
u8 phyctl_offset; u8 phyctl_offset;
bool dedicated_clocks; bool dedicated_clocks;
bool enable_pmu_unk1; bool enable_pmu_unk1;
bool phy0_dual_route;
}; };
struct sun4i_usb_phy_data { struct sun4i_usb_phy_data {
...@@ -188,10 +191,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 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); spin_lock_irqsave(&phy_data->reg_lock, flags);
if (phy_data->cfg->type == sun8i_a33_phy || if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
phy_data->cfg->type == sun50i_a64_phy || /* SoCs newer than A33 need us to set phyctl to 0 explicitly */
phy_data->cfg->type == sun8i_v3s_phy) {
/* A33 or A64 needs us to set phyctl to 0 explicitly */
writel(0, phyctl); writel(0, phyctl);
} }
...@@ -271,23 +272,16 @@ static int sun4i_usb_phy_init(struct phy *_phy) ...@@ -271,23 +272,16 @@ static int sun4i_usb_phy_init(struct phy *_phy)
writel(val & ~2, phy->pmu + REG_PMU_UNK1); writel(val & ~2, phy->pmu + REG_PMU_UNK1);
} }
if (data->cfg->type == sun8i_h3_phy) { /* Enable USB 45 Ohm resistor calibration */
if (phy->index == 0) { if (phy->index == 0)
val = readl(data->base + REG_PHY_UNK_H3); sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
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);
/* Adjust PHY's magnitude and rate */ /* Adjust PHY's magnitude and rate */
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
/* Disconnect threshold adjustment */ /* Disconnect threshold adjustment */
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
data->cfg->disc_thresh, 2); data->cfg->disc_thresh, 2);
}
sun4i_usb_phy_passby(phy, 1); sun4i_usb_phy_passby(phy, 1);
...@@ -486,6 +480,21 @@ static const struct phy_ops sun4i_usb_phy_ops = { ...@@ -486,6 +480,21 @@ static const struct phy_ops sun4i_usb_phy_ops = {
.owner = THIS_MODULE, .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) static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
{ {
struct sun4i_usb_phy_data *data = struct sun4i_usb_phy_data *data =
...@@ -546,6 +555,10 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) ...@@ -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); sun4i_usb_phy0_set_vbus_detect(phy0, 1);
mutex_unlock(&phy0->mutex); 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) if (vbus_notify)
...@@ -700,7 +713,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) ...@@ -700,7 +713,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->reset); 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); snprintf(name, sizeof(name), "pmu%d", i);
res = platform_get_resource_byname(pdev, res = platform_get_resource_byname(pdev,
IORESOURCE_MEM, name); IORESOURCE_MEM, name);
...@@ -823,8 +836,10 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { ...@@ -823,8 +836,10 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
.num_phys = 4, .num_phys = 4,
.type = sun8i_h3_phy, .type = sun8i_h3_phy,
.disc_thresh = 3, .disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true, .dedicated_clocks = true,
.enable_pmu_unk1 = true, .enable_pmu_unk1 = true,
.phy0_dual_route = true,
}; };
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
...@@ -843,6 +858,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { ...@@ -843,6 +858,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
.phyctl_offset = REG_PHYCTL_A33, .phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true, .dedicated_clocks = true,
.enable_pmu_unk1 = true, .enable_pmu_unk1 = true,
.phy0_dual_route = true,
}; };
static const struct of_device_id sun4i_usb_phy_of_match[] = { static const struct of_device_id sun4i_usb_phy_of_match[] = {
......
...@@ -12,36 +12,6 @@ ...@@ -12,36 +12,6 @@
#ifndef _LINUX_MFD_SYSCON_PMU_EXYNOS5_H_ #ifndef _LINUX_MFD_SYSCON_PMU_EXYNOS5_H_
#define _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_PHY_ENABLE BIT(0)
#define EXYNOS5_MIPI_PHY_S_RESETN BIT(1) #define EXYNOS5_MIPI_PHY_S_RESETN BIT(1)
#define EXYNOS5_MIPI_PHY_M_RESETN BIT(2) #define EXYNOS5_MIPI_PHY_M_RESETN BIT(2)
......
/* /*
* Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. * Copyright (c) 2010-2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com * http://www.samsung.com
* *
* EXYNOS - Power management unit definition * EXYNOS - Power management unit definition
...@@ -50,6 +50,14 @@ ...@@ -50,6 +50,14 @@
#define S5P_WAKEUP_MASK 0x0608 #define S5P_WAKEUP_MASK 0x0608
#define S5P_WAKEUP_MASK2 0x0614 #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_INFORM0 0x0800
#define S5P_INFORM1 0x0804 #define S5P_INFORM1 0x0804
#define S5P_INFORM5 0x0814 #define S5P_INFORM5 0x0814
...@@ -342,6 +350,8 @@ ...@@ -342,6 +350,8 @@
#define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408
#define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C #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_USE_RETENTION BIT(4)
#define EXYNOS5_SYS_WDTRESET (1 << 20) #define EXYNOS5_SYS_WDTRESET (1 << 20)
...@@ -495,6 +505,9 @@ ...@@ -495,6 +505,9 @@
#define EXYNOS5420_KFC_CORE_RESET(_nr) \ #define EXYNOS5420_KFC_CORE_RESET(_nr) \
((EXYNOS5420_KFC_CORE_RESET0 | EXYNOS5420_KFC_ETM_RESET0) << (_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_ARM_CORE2_SYS_PWR_REG 0x1020
#define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024 #define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024
#define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028 #define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028
...@@ -632,6 +645,7 @@ ...@@ -632,6 +645,7 @@
| EXYNOS5420_KFC_USE_STANDBY_WFI3) | EXYNOS5420_KFC_USE_STANDBY_WFI3)
/* For EXYNOS5433 */ /* For EXYNOS5433 */
#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x0728)
#define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028) #define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028)
#define EXYNOS5433_PAD_RETENTION_MMC2_OPTION (0x30C8) #define EXYNOS5433_PAD_RETENTION_MMC2_OPTION (0x30C8)
#define EXYNOS5433_PAD_RETENTION_TOP_OPTION (0x3108) #define EXYNOS5433_PAD_RETENTION_TOP_OPTION (0x3108)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment