phy: for 5.1

*) Add a new driver to support Armada 3700 COMPHY IP (supports SATA, USB3,
      PCIe)
   *) Add a new driver to support Armada UTMI PHY
   *) Add a new driver to support Cadence D-PHY
   *) Extend omap-usb2 PHY driver to be used for AM654 USB2 PHY
   *) Extend qcom-qmp PHY driver to be used for UFS PHY and USB3 PHY in Qualcomm
      MSM8998
   *) Extend qcom-qusb2 PHY driver to support QUSB2 PHY in Qualcomm MSM8998
   *) Remove module specific code that is present for drivers that can be only
      built-in
   *) Allow Freescale IMX8MQ USB to be used for multiple SoCs and not just
      i.MX8MQ
   *) Cleanups such as switch to SPDX identifier, use readl_poll_timeout macro,
      remove unused headers etc.,
 
 Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCgAsFiEEUXMr/TfP2p4suIY5Dlx4XIBNgtkFAlxiwzIOHGtpc2hvbkB0
 aS5jb20ACgkQDlx4XIBNgtnxAQ/+Lb12tqZImrTm5A+KIvk3Kaq47TC0dwsNbfg4
 Y8VWEAXP3Qicrc8uRxJDQdN2Jztf681kBOmTpa+RopwiaWTPQ/62MGTWOWIJHAoz
 LLXUo4FYF/bWDpszAh9CrVQVzZ6K6kq33fnLnJaYtYt0zyZS3pHnClApUgT+Ahz3
 2HW1M/XPKHJYyNH5N1lCqiGdOQM4aKYn9sy+AlxWN9XCWLKA1W9hxzF+wcIH7RAB
 VCixtug8PJ4D2XMyN6SzF99N4OWEmsoES3PC/28/kMs6JfwPUcFTCFYOhE1i+g0l
 rF1b7nvhxXpw6PYG4Ub/O/ltIyU+0ll2sFT3nm6gEbNPbl3FeDlDNXGQupMwHvB7
 N0DPVDZ9w0Xru6FzWQFcmW2PHbauCtTTYv6t+RxmdwtN4ituXwwxoO/xz4Ah1bTL
 Aqvt162uEWdCgqeW/nbq3b9MDITLnBbQ5pevsboaRj/GHXcF9K6D0oFsuWLb56KQ
 PzxulrPToBTWxbOyThA8CV1QI79re9Sd+05Niptg33vTAAw4Oh9+wKeqO8ZYPrvK
 gb2n5SEZIiZgcevA6M3Iy7GiWJ1Zg3p+uQxhBp39cKQsZbl6BtqXtOeG11wm2xOu
 g7D6vntoNMz+wj08/qemHgttrcJ5P8RA5k4PFZIMyCaJgK9Z5vTQH8zOfja4qefG
 LWC+U6Q=
 =wNhh
 -----END PGP SIGNATURE-----

Merge tag 'phy-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next

Kishon writes:

phy: for 5.1

  *) Add a new driver to support Armada 3700 COMPHY IP (supports SATA, USB3,
     PCIe)
  *) Add a new driver to support Armada UTMI PHY
  *) Add a new driver to support Cadence D-PHY
  *) Extend omap-usb2 PHY driver to be used for AM654 USB2 PHY
  *) Extend qcom-qmp PHY driver to be used for UFS PHY and USB3 PHY in Qualcomm
     MSM8998
  *) Extend qcom-qusb2 PHY driver to support QUSB2 PHY in Qualcomm MSM8998
  *) Remove module specific code that is present for drivers that can be only
     built-in
  *) Allow Freescale IMX8MQ USB to be used for multiple SoCs and not just
     i.MX8MQ
  *) Cleanups such as switch to SPDX identifier, use readl_poll_timeout macro,
     remove unused headers etc.,

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

* tag 'phy-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy: (32 commits)
  phy: qcom-qmp: Add QMP UFS PHY support for msm8998
  dt-bindings: phy-qcom-qmp: Add qcom,msm8998-qmp-ufs-phy
  phy: bcm-sr-pcie: Change operation when PIPEMUX=1
  phy: Add Cadence D-PHY support
  dt-bindings: phy: Move the Cadence D-PHY bindings
  phy: dphy: Clarify lanes parameter documentation
  phy: dphy: Change units of wakeup and init parameters
  phy: dphy: Remove unused header
  MAINTAINERS: phy: fill Armada 3700 PHY drivers entry
  dt-bindings: phy: mvebu-utmi: add UTMI PHY bindings
  phy: add A3700 UTMI PHY driver
  MAINTAINERS: phy: add entry for Armada 3700 COMPHY driver
  dt-bindings: phy: mvebu-comphy: extend the file to describe a3700 bindings
  phy: add A3700 COMPHY support
  phy: mvebu-cp110-comphy: fix port check in ->xlate()
  phy: armada375-usb2: switch to SPDX license identifier
  phy: make phy-armada375-usb2 explicitly non-modular
  phy: make phy-mvebu-sata explicitly non-modular
  phy: make phy-core explicitly non-modular
  phy: qcom-qusb2: Add QUSB2 PHY support for msm8998
  ...
This commit is contained in:
Greg Kroah-Hartman 2019-02-12 14:59:43 +01:00
commit 0220dcd113
32 changed files with 1451 additions and 172 deletions

View File

@ -31,28 +31,7 @@ Required subnodes:
- one subnode per DSI device connected on the DSI bus. Each DSI device should
contain a reg property encoding its virtual channel.
Cadence DPHY
============
Cadence DPHY block.
Required properties:
- compatible: should be set to "cdns,dphy".
- reg: physical base address and length of the DPHY registers.
- clocks: DPHY reference clocks.
- clock-names: must contain "psm" and "pll_ref".
- #phy-cells: must be set to 0.
Example:
dphy0: dphy@fd0e0000{
compatible = "cdns,dphy";
reg = <0x0 0xfd0e0000 0x0 0x1000>;
clocks = <&psm_clk>, <&pll_ref_clk>;
clock-names = "psm", "pll_ref";
#phy-cells = <0>;
};
dsi0: dsi@fd0c0000 {
compatible = "cdns,dsi";
reg = <0x0 0xfd0c0000 0x0 0x1000>;

View File

@ -0,0 +1,20 @@
Cadence DPHY
============
Cadence DPHY block.
Required properties:
- compatible: should be set to "cdns,dphy".
- reg: physical base address and length of the DPHY registers.
- clocks: DPHY reference clocks.
- clock-names: must contain "psm" and "pll_ref".
- #phy-cells: must be set to 0.
Example:
dphy0: dphy@fd0e0000{
compatible = "cdns,dphy";
reg = <0x0 0xfd0e0000 0x0 0x1000>;
clocks = <&psm_clk>, <&pll_ref_clk>;
clock-names = "psm", "pll_ref";
#phy-cells = <0>;
};

View File

@ -1,16 +1,27 @@
mvebu comphy driver
-------------------
MVEBU comphy drivers
--------------------
A comphy controller can be found on Marvell Armada 7k/8k on the CP110. It
provides a number of shared PHYs used by various interfaces (network, sata,
usb, PCIe...).
COMPHY controllers can be found on the following Marvell MVEBU SoCs:
* Armada 7k/8k (on the CP110)
* Armada 3700
It provides a number of shared PHYs used by various interfaces (network, SATA,
USB, PCIe...).
Required properties:
- compatible: should be "marvell,comphy-cp110"
- reg: should contain the comphy register location and length.
- marvell,system-controller: should contain a phandle to the
system controller node.
- compatible: should be one of:
* "marvell,comphy-cp110" for Armada 7k/8k
* "marvell,comphy-a3700" for Armada 3700
- reg: should contain the COMPHY register(s) location(s) and length(s).
* 1 entry for Armada 7k/8k
* 4 entries for Armada 3700 along with the corresponding reg-names
properties, memory areas are:
* Generic COMPHY registers
* Lane 1 (PCIe/GbE)
* Lane 0 (USB3/GbE)
* Lane 2 (SATA/USB3)
- marvell,system-controller: should contain a phandle to the system
controller node (only for Armada 7k/8k)
- #address-cells: should be 1.
- #size-cells: should be 0.
@ -18,11 +29,11 @@ A sub-node is required for each comphy lane provided by the comphy.
Required properties (child nodes):
- reg: comphy lane number.
- #phy-cells : from the generic phy bindings, must be 1. Defines the
- reg: COMPHY lane number.
- #phy-cells : from the generic PHY bindings, must be 1. Defines the
input port to use for a given comphy lane.
Example:
Examples:
cpm_comphy: phy@120000 {
compatible = "marvell,comphy-cp110";
@ -41,3 +52,33 @@ Example:
#phy-cells = <1>;
};
};
comphy: phy@18300 {
compatible = "marvell,comphy-a3700";
reg = <0x18300 0x300>,
<0x1F000 0x400>,
<0x5C000 0x400>,
<0xe0178 0x8>;
reg-names = "comphy",
"lane1_pcie_gbe",
"lane0_usb3_gbe",
"lane2_sata_usb3";
#address-cells = <1>;
#size-cells = <0>;
comphy0: phy@0 {
reg = <0>;
#phy-cells = <1>;
};
comphy1: phy@1 {
reg = <1>;
#phy-cells = <1>;
};
comphy2: phy@2 {
reg = <2>;
#phy-cells = <1>;
};
};

View File

@ -0,0 +1,38 @@
MVEBU A3700 UTMI PHY
--------------------
USB2 UTMI+ PHY controllers can be found on the following Marvell MVEBU SoCs:
* Armada 3700
On Armada 3700, there are two USB controllers, one is compatible with the USB2
and USB3 specifications and supports OTG. The other one is USB2 compliant and
only supports host mode. Both of these controllers come with a slightly
different UTMI PHY.
Required Properties:
- compatible: Should be one of:
* "marvell,a3700-utmi-host-phy" for the PHY connected to
the USB2 host-only controller.
* "marvell,a3700-utmi-otg-phy" for the PHY connected to
the USB3 and USB2 OTG capable controller.
- reg: PHY IP register range.
- marvell,usb-misc-reg: handle on the "USB miscellaneous registers" shared
region covering registers related to both the host
controller and the PHY.
- #phy-cells: Standard property (Documentation: phy-bindings.txt) Should be 0.
Example:
usb2_utmi_host_phy: phy@5f000 {
compatible = "marvell,armada-3700-utmi-host-phy";
reg = <0x5f000 0x800>;
marvell,usb-misc-reg = <&usb2_syscon>;
#phy-cells = <0>;
};
usb2_syscon: system-controller@5f800 {
compatible = "marvell,armada-3700-usb2-host-misc", "syscon";
reg = <0x5f800 0x800>;
};

View File

@ -23,6 +23,8 @@ Optional properties:
register files". When set driver will request its
phandle as one companion-grf for some special SoCs
(e.g RV1108).
- extcon : phandle to the extcon device providing the cable state for
the otg phy.
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,

View File

@ -9,6 +9,8 @@ Required properties:
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
"qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998,
"qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998,
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845,
"qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845.
@ -42,6 +44,10 @@ Required properties:
"aux", "cfg_ahb", "ref".
For "qcom,msm8996-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8998-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8998-qmp-ufs-phy" must contain:
"ref", "ref_aux".
For "qcom,sdm845-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref", "com_aux".
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
@ -61,6 +67,9 @@ Required properties:
"phy", "common", "cfg".
For "qcom,msm8996-qmp-usb3-phy" must contain
"phy", "common".
For "qcom,msm8998-qmp-usb3-phy" must contain
"phy", "common".
For "qcom,msm8998-qmp-ufs-phy": no resets are listed.
For "qcom,sdm845-qmp-usb3-phy" must contain:
"phy", "common".
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:

View File

@ -6,6 +6,7 @@ QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
Required properties:
- compatible: compatible list, contains
"qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
"qcom,msm8998-qusb2-phy" for 10nm PHY on msm8998,
"qcom,sdm845-qusb2-phy" for 10nm PHY on sdm845.
- reg: offset and length of the PHY register set.

View File

@ -5,6 +5,8 @@ This file provides information on what the device node for the R-Car generation
Required properties:
- compatible: "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
SoC.
"renesas,usb2-phy-r8a774c0" if the device is a part of an R8A774C0
SoC.
"renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
SoC.

View File

@ -35,6 +35,7 @@ Required properties:
DRA7x
Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY
in DRA7x
Should be "ti,am654-usb2" for the USB2 PHYs on AM654.
- reg : Address and length of the register set for the device.
- #phy-cells: determine the number of cells that should be given in the
phandle while referencing this phy.

View File

@ -9089,6 +9089,14 @@ F: drivers/gpu/drm/armada/
F: include/uapi/drm/armada_drm.h
F: Documentation/devicetree/bindings/display/armada/
MARVELL ARMADA 3700 PHY DRIVERS
M: Miquel Raynal <miquel.raynal@bootlin.com>
S: Maintained
F: drivers/phy/marvell/phy-mvebu-a3700-comphy.c
F: drivers/phy/marvell/phy-mvebu-a3700-utmi.c
F: Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt
F: Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt
MARVELL CRYPTO DRIVER
M: Boris Brezillon <bbrezillon@kernel.org>
M: Arnaud Ebalard <arno@natisbad.org>

View File

@ -78,8 +78,8 @@ struct sr_pcie_phy_core {
static const u8 pipemux_table[] = {
/* PIPEMUX = 0, EP 1x16 */
0x00,
/* PIPEMUX = 1, EP 2x8 */
0x00,
/* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
0x80,
/* PIPEMUX = 2, EP 4x4 */
0x00,
/* PIPEMUX = 3, RC 2x8, cores 0, 7 */

View File

@ -1,6 +1,7 @@
#
# Phy drivers for Cadence PHYs
#
config PHY_CADENCE_DP
tristate "Cadence MHDP DisplayPort PHY driver"
depends on OF
@ -9,9 +10,19 @@ config PHY_CADENCE_DP
help
Support for Cadence MHDP DisplayPort PHY.
config PHY_CADENCE_DPHY
tristate "Cadence D-PHY Support"
depends on HAS_IOMEM && OF
select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
help
Choose this option if you have a Cadence D-PHY in your
system. If M is selected, the module will be called
cdns-dphy.
config PHY_CADENCE_SIERRA
tristate "Cadence Sierra PHY Driver"
depends on OF && HAS_IOMEM && RESET_CONTROLLER
select GENERIC_PHY
help
Enable this to support the Cadence Sierra PHY driver
Enable this to support the Cadence Sierra PHY driver

View File

@ -1,2 +1,3 @@
obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o
obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o

View File

@ -0,0 +1,391 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright: 2017-2018 Cadence Design Systems, Inc.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
#define REG_WAKEUP_TIME_NS 800
#define DPHY_PLL_RATE_HZ 108000000
/* DPHY registers */
#define DPHY_PMA_CMN(reg) (reg)
#define DPHY_PMA_LCLK(reg) (0x100 + (reg))
#define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg))
#define DPHY_PMA_RCLK(reg) (0x600 + (reg))
#define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg))
#define DPHY_PCS(reg) (0xb00 + (reg))
#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20)
#define DPHY_CMN_SSM_EN BIT(0)
#define DPHY_CMN_TX_MODE_EN BIT(9)
#define DPHY_CMN_PWM DPHY_PMA_CMN(0x40)
#define DPHY_CMN_PWM_DIV(x) ((x) << 20)
#define DPHY_CMN_PWM_LOW(x) ((x) << 10)
#define DPHY_CMN_PWM_HIGH(x) (x)
#define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c)
#define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22))
#define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21))
#define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50)
#define DPHY_CMN_IPDIV_FROM_REG BIT(0)
#define DPHY_CMN_IPDIV(x) ((x) << 1)
#define DPHY_CMN_OPDIV_FROM_REG BIT(6)
#define DPHY_CMN_OPDIV(x) ((x) << 7)
#define DPHY_PSM_CFG DPHY_PCS(0x4)
#define DPHY_PSM_CFG_FROM_REG BIT(0)
#define DPHY_PSM_CLK_DIV(x) ((x) << 1)
#define DSI_HBP_FRAME_OVERHEAD 12
#define DSI_HSA_FRAME_OVERHEAD 14
#define DSI_HFP_FRAME_OVERHEAD 6
#define DSI_HSS_VSS_VSE_FRAME_OVERHEAD 4
#define DSI_BLANKING_FRAME_OVERHEAD 6
#define DSI_NULL_FRAME_OVERHEAD 6
#define DSI_EOT_PKT_SIZE 4
struct cdns_dphy_cfg {
u8 pll_ipdiv;
u8 pll_opdiv;
u16 pll_fbdiv;
unsigned int nlanes;
};
enum cdns_dphy_clk_lane_cfg {
DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0,
DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1,
DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2,
DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3,
};
struct cdns_dphy;
struct cdns_dphy_ops {
int (*probe)(struct cdns_dphy *dphy);
void (*remove)(struct cdns_dphy *dphy);
void (*set_psm_div)(struct cdns_dphy *dphy, u8 div);
void (*set_clk_lane_cfg)(struct cdns_dphy *dphy,
enum cdns_dphy_clk_lane_cfg cfg);
void (*set_pll_cfg)(struct cdns_dphy *dphy,
const struct cdns_dphy_cfg *cfg);
unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy);
};
struct cdns_dphy {
struct cdns_dphy_cfg cfg;
void __iomem *regs;
struct clk *psm_clk;
struct clk *pll_ref_clk;
const struct cdns_dphy_ops *ops;
struct phy *phy;
};
static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy,
struct cdns_dphy_cfg *cfg,
struct phy_configure_opts_mipi_dphy *opts,
unsigned int *dsi_hfp_ext)
{
unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk);
u64 dlane_bps;
memset(cfg, 0, sizeof(*cfg));
if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000)
return -EINVAL;
else if (pll_ref_hz < 19200000)
cfg->pll_ipdiv = 1;
else if (pll_ref_hz < 38400000)
cfg->pll_ipdiv = 2;
else if (pll_ref_hz < 76800000)
cfg->pll_ipdiv = 4;
else
cfg->pll_ipdiv = 8;
dlane_bps = opts->hs_clk_rate;
if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL)
return -EINVAL;
else if (dlane_bps >= 1250000000)
cfg->pll_opdiv = 1;
else if (dlane_bps >= 630000000)
cfg->pll_opdiv = 2;
else if (dlane_bps >= 320000000)
cfg->pll_opdiv = 4;
else if (dlane_bps >= 160000000)
cfg->pll_opdiv = 8;
cfg->pll_fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv *
cfg->pll_ipdiv,
pll_ref_hz);
return 0;
}
static int cdns_dphy_setup_psm(struct cdns_dphy *dphy)
{
unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk);
unsigned long psm_div;
if (!psm_clk_hz || psm_clk_hz > 100000000)
return -EINVAL;
psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000);
if (dphy->ops->set_psm_div)
dphy->ops->set_psm_div(dphy, psm_div);
return 0;
}
static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy,
enum cdns_dphy_clk_lane_cfg cfg)
{
if (dphy->ops->set_clk_lane_cfg)
dphy->ops->set_clk_lane_cfg(dphy, cfg);
}
static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy,
const struct cdns_dphy_cfg *cfg)
{
if (dphy->ops->set_pll_cfg)
dphy->ops->set_pll_cfg(dphy, cfg);
}
static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy)
{
return dphy->ops->get_wakeup_time_ns(dphy);
}
static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy)
{
/* Default wakeup time is 800 ns (in a simulated environment). */
return 800;
}
static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy,
const struct cdns_dphy_cfg *cfg)
{
u32 fbdiv_low, fbdiv_high;
fbdiv_low = (cfg->pll_fbdiv / 4) - 2;
fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2;
writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG |
DPHY_CMN_IPDIV(cfg->pll_ipdiv) |
DPHY_CMN_OPDIV(cfg->pll_opdiv),
dphy->regs + DPHY_CMN_OPIPDIV);
writel(DPHY_CMN_FBDIV_FROM_REG |
DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high),
dphy->regs + DPHY_CMN_FBDIV);
writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) |
DPHY_CMN_PWM_DIV(0x8),
dphy->regs + DPHY_CMN_PWM);
}
static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div)
{
writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div),
dphy->regs + DPHY_PSM_CFG);
}
/*
* This is the reference implementation of DPHY hooks. Specific integration of
* this IP may have to re-implement some of them depending on how they decided
* to wire things in the SoC.
*/
static const struct cdns_dphy_ops ref_dphy_ops = {
.get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns,
.set_pll_cfg = cdns_dphy_ref_set_pll_cfg,
.set_psm_div = cdns_dphy_ref_set_psm_div,
};
static int cdns_dphy_config_from_opts(struct phy *phy,
struct phy_configure_opts_mipi_dphy *opts,
struct cdns_dphy_cfg *cfg)
{
struct cdns_dphy *dphy = phy_get_drvdata(phy);
unsigned int dsi_hfp_ext = 0;
int ret;
ret = phy_mipi_dphy_config_validate(opts);
if (ret)
return ret;
ret = cdns_dsi_get_dphy_pll_cfg(dphy, cfg,
opts, &dsi_hfp_ext);
if (ret)
return ret;
opts->wakeup = cdns_dphy_get_wakeup_time_ns(dphy) / 1000;
return 0;
}
static int cdns_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts)
{
struct cdns_dphy_cfg cfg = { 0 };
if (mode != PHY_MODE_MIPI_DPHY)
return -EINVAL;
return cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
}
static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
{
struct cdns_dphy *dphy = phy_get_drvdata(phy);
struct cdns_dphy_cfg cfg = { 0 };
int ret;
ret = cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
if (ret)
return ret;
/*
* Configure the internal PSM clk divider so that the DPHY has a
* 1MHz clk (or something close).
*/
ret = cdns_dphy_setup_psm(dphy);
if (ret)
return ret;
/*
* Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes
* and 8 data lanes, each clk lane can be attache different set of
* data lanes. The 2 groups are named 'left' and 'right', so here we
* just say that we want the 'left' clk lane to drive the 'left' data
* lanes.
*/
cdns_dphy_set_clk_lane_cfg(dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT);
/*
* Configure the DPHY PLL that will be used to generate the TX byte
* clk.
*/
cdns_dphy_set_pll_cfg(dphy, &cfg);
return 0;
}
static int cdns_dphy_power_on(struct phy *phy)
{
struct cdns_dphy *dphy = phy_get_drvdata(phy);
clk_prepare_enable(dphy->psm_clk);
clk_prepare_enable(dphy->pll_ref_clk);
/* Start TX state machine. */
writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN,
dphy->regs + DPHY_CMN_SSM);
return 0;
}
static int cdns_dphy_power_off(struct phy *phy)
{
struct cdns_dphy *dphy = phy_get_drvdata(phy);
clk_disable_unprepare(dphy->pll_ref_clk);
clk_disable_unprepare(dphy->psm_clk);
return 0;
}
static const struct phy_ops cdns_dphy_ops = {
.configure = cdns_dphy_configure,
.validate = cdns_dphy_validate,
.power_on = cdns_dphy_power_on,
.power_off = cdns_dphy_power_off,
};
static int cdns_dphy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
struct cdns_dphy *dphy;
struct resource *res;
int ret;
dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
if (!dphy)
return -ENOMEM;
dev_set_drvdata(&pdev->dev, dphy);
dphy->ops = of_device_get_match_data(&pdev->dev);
if (!dphy->ops)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dphy->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dphy->regs))
return PTR_ERR(dphy->regs);
dphy->psm_clk = devm_clk_get(&pdev->dev, "psm");
if (IS_ERR(dphy->psm_clk))
return PTR_ERR(dphy->psm_clk);
dphy->pll_ref_clk = devm_clk_get(&pdev->dev, "pll_ref");
if (IS_ERR(dphy->pll_ref_clk))
return PTR_ERR(dphy->pll_ref_clk);
if (dphy->ops->probe) {
ret = dphy->ops->probe(dphy);
if (ret)
return ret;
}
dphy->phy = devm_phy_create(&pdev->dev, NULL, &cdns_dphy_ops);
if (IS_ERR(dphy->phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
if (dphy->ops->remove)
dphy->ops->remove(dphy);
return PTR_ERR(dphy->phy);
}
phy_set_drvdata(dphy->phy, dphy);
phy_provider = devm_of_phy_provider_register(&pdev->dev,
of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static int cdns_dphy_remove(struct platform_device *pdev)
{
struct cdns_dphy *dphy = dev_get_drvdata(&pdev->dev);
if (dphy->ops->remove)
dphy->ops->remove(dphy);
return 0;
}
static const struct of_device_id cdns_dphy_of_match[] = {
{ .compatible = "cdns,dphy", .data = &ref_dphy_ops },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, cdns_dphy_of_match);
static struct platform_driver cdns_dphy_platform_driver = {
.probe = cdns_dphy_probe,
.remove = cdns_dphy_remove,
.driver = {
.name = "cdns-mipi-dphy",
.of_match_table = cdns_dphy_of_match,
},
};
module_platform_driver(cdns_dphy_platform_driver);
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
MODULE_DESCRIPTION("Cadence MIPI D-PHY Driver");
MODULE_LICENSE("GPL");

View File

@ -2,4 +2,4 @@ config PHY_FSL_IMX8MQ_USB
tristate "Freescale i.MX8M USB3 PHY"
depends on OF && HAS_IOMEM
select GENERIC_PHY
default SOC_IMX8MQ
default ARCH_MXC && ARM64

View File

@ -21,6 +21,27 @@ config PHY_BERLIN_USB
help
Enable this to support the USB PHY on Marvell Berlin SoCs.
config PHY_MVEBU_A3700_COMPHY
tristate "Marvell A3700 comphy driver"
depends on ARCH_MVEBU || COMPILE_TEST
depends on OF
depends on HAVE_ARM_SMCCC
default y
select GENERIC_PHY
help
This driver allows to control the comphy, a hardware block providing
shared serdes PHYs on Marvell Armada 3700. Its serdes lanes can be
used by various controllers: Ethernet, SATA, USB3, PCIe.
config PHY_MVEBU_A3700_UTMI
tristate "Marvell A3700 UTMI driver"
depends on ARCH_MVEBU || COMPILE_TEST
depends on OF
default y
select GENERIC_PHY
help
Enable this to support Marvell A3700 UTMI PHY driver.
config PHY_MVEBU_CP110_COMPHY
tristate "Marvell CP110 comphy driver"
depends on ARCH_MVEBU || COMPILE_TEST

View File

@ -2,6 +2,8 @@
obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o
obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o
obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* USB cluster support for Armada 375 platform.
*
@ -5,10 +6,6 @@
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is"
* without any warranty of any kind, whether express or implied.
*
* Armada 375 comes with an USB2 host and device controller and an
* USB3 controller. The USB cluster control register allows to manage
* common features of both USB controllers.
@ -18,7 +15,6 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@ -142,7 +138,6 @@ static const struct of_device_id of_usb_cluster_table[] = {
{ .compatible = "marvell,armada-375-usb-cluster", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_usb_cluster_table);
static struct platform_driver armada375_usb_phy_driver = {
.probe = armada375_usb_phy_probe,
@ -151,8 +146,4 @@ static struct platform_driver armada375_usb_phy_driver = {
.name = "armada-375-usb-cluster",
}
};
module_platform_driver(armada375_usb_phy_driver);
MODULE_DESCRIPTION("Armada 375 USB cluster driver");
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
MODULE_LICENSE("GPL");
builtin_platform_driver(armada375_usb_phy_driver);

View File

@ -0,0 +1,318 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Marvell
*
* Authors:
* Evan Wang <xswang@marvell.com>
* Miquèl Raynal <miquel.raynal@bootlin.com>
*
* Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart.
* SMC call initial support done by Grzegorz Jaszczyk.
*/
#include <linux/arm-smccc.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#define MVEBU_A3700_COMPHY_LANES 3
#define MVEBU_A3700_COMPHY_PORTS 2
/* COMPHY Fast SMC function identifiers */
#define COMPHY_SIP_POWER_ON 0x82000001
#define COMPHY_SIP_POWER_OFF 0x82000002
#define COMPHY_SIP_PLL_LOCK 0x82000003
#define COMPHY_FW_MODE_SATA 0x1
#define COMPHY_FW_MODE_SGMII 0x2
#define COMPHY_FW_MODE_HS_SGMII 0x3
#define COMPHY_FW_MODE_USB3H 0x4
#define COMPHY_FW_MODE_USB3D 0x5
#define COMPHY_FW_MODE_PCIE 0x6
#define COMPHY_FW_MODE_RXAUI 0x7
#define COMPHY_FW_MODE_XFI 0x8
#define COMPHY_FW_MODE_SFI 0x9
#define COMPHY_FW_MODE_USB3 0xa
#define COMPHY_FW_SPEED_1_25G 0 /* SGMII 1G */
#define COMPHY_FW_SPEED_2_5G 1
#define COMPHY_FW_SPEED_3_125G 2 /* SGMII 2.5G */
#define COMPHY_FW_SPEED_5G 3
#define COMPHY_FW_SPEED_5_15625G 4 /* XFI 5G */
#define COMPHY_FW_SPEED_6G 5
#define COMPHY_FW_SPEED_10_3125G 6 /* XFI 10G */
#define COMPHY_FW_SPEED_MAX 0x3F
#define COMPHY_FW_MODE(mode) ((mode) << 12)
#define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \
((idx) << 8) | \
((speed) << 2))
#define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \
((width) << 18))
struct mvebu_a3700_comphy_conf {
unsigned int lane;
enum phy_mode mode;
int submode;
unsigned int port;
u32 fw_mode;
};
#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \
{ \
.lane = _lane, \
.mode = _mode, \
.submode = _smode, \
.port = _port, \
.fw_mode = _fw, \
}
#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \
MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw)
#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \
MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw)
static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = {
/* lane 0 */
MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0,
COMPHY_FW_MODE_USB3H),
MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1,
COMPHY_FW_MODE_SGMII),
MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1,
COMPHY_FW_MODE_HS_SGMII),
/* lane 1 */
MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0,
COMPHY_FW_MODE_PCIE),
MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0,
COMPHY_FW_MODE_SGMII),
MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0,
COMPHY_FW_MODE_HS_SGMII),
/* lane 2 */
MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0,
COMPHY_FW_MODE_SATA),
MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0,
COMPHY_FW_MODE_USB3H),
};
struct mvebu_a3700_comphy_lane {
struct device *dev;
unsigned int id;
enum phy_mode mode;
int submode;
int port;
};
static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
unsigned long mode)
{
struct arm_smccc_res res;
arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res);
return res.a0;
}
static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
enum phy_mode mode,
int submode)
{
int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes);
/* Unused PHY mux value is 0x0 */
if (mode == PHY_MODE_INVALID)
return -EINVAL;
for (i = 0; i < n; i++) {
if (mvebu_a3700_comphy_modes[i].lane == lane &&
mvebu_a3700_comphy_modes[i].port == port &&
mvebu_a3700_comphy_modes[i].mode == mode &&
mvebu_a3700_comphy_modes[i].submode == submode)
break;
}
if (i == n)
return -EINVAL;
return mvebu_a3700_comphy_modes[i].fw_mode;
}
static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
int fw_mode;
if (submode == PHY_INTERFACE_MODE_1000BASEX)
submode = PHY_INTERFACE_MODE_SGMII;
fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode,
submode);
if (fw_mode < 0) {
dev_err(lane->dev, "invalid COMPHY mode\n");
return fw_mode;
}
/* Just remember the mode, ->power_on() will do the real setup */
lane->mode = mode;
lane->submode = submode;
return 0;
}
static int mvebu_a3700_comphy_power_on(struct phy *phy)
{
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
u32 fw_param;
int fw_mode;
fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port,
lane->mode, lane->submode);
if (fw_mode < 0) {
dev_err(lane->dev, "invalid COMPHY mode\n");
return fw_mode;
}
switch (lane->mode) {
case PHY_MODE_USB_HOST_SS:
dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id);
fw_param = COMPHY_FW_MODE(fw_mode);
break;
case PHY_MODE_SATA:
dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id);
fw_param = COMPHY_FW_MODE(fw_mode);
break;
case PHY_MODE_ETHERNET:
switch (lane->submode) {
case PHY_INTERFACE_MODE_SGMII:
dev_dbg(lane->dev, "set lane %d to SGMII mode\n",
lane->id);
fw_param = COMPHY_FW_NET(fw_mode, lane->port,
COMPHY_FW_SPEED_1_25G);
break;
case PHY_INTERFACE_MODE_2500BASEX:
dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n",
lane->id);
fw_param = COMPHY_FW_NET(fw_mode, lane->port,
COMPHY_FW_SPEED_3_125G);
break;
default:
dev_err(lane->dev, "unsupported PHY submode (%d)\n",
lane->submode);
return -ENOTSUPP;
}
break;
case PHY_MODE_PCIE:
dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id);
fw_param = COMPHY_FW_PCIE(fw_mode, lane->port,
COMPHY_FW_SPEED_5G,
phy->attrs.bus_width);
break;
default:
dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode);
return -ENOTSUPP;
}
return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
}
static int mvebu_a3700_comphy_power_off(struct phy *phy)
{
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0);
}
static const struct phy_ops mvebu_a3700_comphy_ops = {
.power_on = mvebu_a3700_comphy_power_on,
.power_off = mvebu_a3700_comphy_power_off,
.set_mode = mvebu_a3700_comphy_set_mode,
.owner = THIS_MODULE,
};
static struct phy *mvebu_a3700_comphy_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct mvebu_a3700_comphy_lane *lane;
struct phy *phy;
if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS))
return ERR_PTR(-EINVAL);
phy = of_phy_simple_xlate(dev, args);
if (IS_ERR(phy))
return phy;
lane = phy_get_drvdata(phy);
lane->port = args->args[0];
return phy;
}
static int mvebu_a3700_comphy_probe(struct platform_device *pdev)
{
struct phy_provider *provider;
struct device_node *child;
for_each_available_child_of_node(pdev->dev.of_node, child) {
struct mvebu_a3700_comphy_lane *lane;
struct phy *phy;
int ret;
u32 lane_id;
ret = of_property_read_u32(child, "reg", &lane_id);
if (ret < 0) {
dev_err(&pdev->dev, "missing 'reg' property (%d)\n",
ret);
continue;
}
if (lane_id >= MVEBU_A3700_COMPHY_LANES) {
dev_err(&pdev->dev, "invalid 'reg' property\n");
continue;
}
lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);
if (!lane)
return -ENOMEM;
phy = devm_phy_create(&pdev->dev, child,
&mvebu_a3700_comphy_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
lane->dev = &pdev->dev;
lane->mode = PHY_MODE_INVALID;
lane->submode = PHY_INTERFACE_MODE_NA;
lane->id = lane_id;
lane->port = -1;
phy_set_drvdata(phy, lane);
}
provider = devm_of_phy_provider_register(&pdev->dev,
mvebu_a3700_comphy_xlate);
return PTR_ERR_OR_ZERO(provider);
}
static const struct of_device_id mvebu_a3700_comphy_of_match_table[] = {
{ .compatible = "marvell,comphy-a3700" },
{ },
};
MODULE_DEVICE_TABLE(of, mvebu_a3700_comphy_of_match_table);
static struct platform_driver mvebu_a3700_comphy_driver = {
.probe = mvebu_a3700_comphy_probe,
.driver = {
.name = "mvebu-a3700-comphy",
.of_match_table = mvebu_a3700_comphy_of_match_table,
},
};
module_platform_driver(mvebu_a3700_comphy_driver);
MODULE_AUTHOR("Miquèl Raynal <miquel.raynal@bootlin.com>");
MODULE_DESCRIPTION("Common PHY driver for A3700");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,278 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Marvell
*
* Authors:
* Igal Liberman <igall@marvell.com>
* Miquèl Raynal <miquel.raynal@bootlin.com>
*
* Marvell A3700 UTMI PHY driver
*/
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* Armada 3700 UTMI PHY registers */
#define USB2_PHY_PLL_CTRL_REG0 0x0
#define PLL_REF_DIV_OFF 0
#define PLL_REF_DIV_MASK GENMASK(6, 0)
#define PLL_REF_DIV_5 5
#define PLL_FB_DIV_OFF 16
#define PLL_FB_DIV_MASK GENMASK(24, 16)
#define PLL_FB_DIV_96 96
#define PLL_SEL_LPFR_OFF 28
#define PLL_SEL_LPFR_MASK GENMASK(29, 28)
#define PLL_READY BIT(31)
#define USB2_PHY_CAL_CTRL 0x8
#define PHY_PLLCAL_DONE BIT(31)
#define PHY_IMPCAL_DONE BIT(23)
#define USB2_RX_CHAN_CTRL1 0x18
#define USB2PHY_SQCAL_DONE BIT(31)
#define USB2_PHY_OTG_CTRL 0x34
#define PHY_PU_OTG BIT(4)
#define USB2_PHY_CHRGR_DETECT 0x38
#define PHY_CDP_EN BIT(2)
#define PHY_DCP_EN BIT(3)
#define PHY_PD_EN BIT(4)
#define PHY_PU_CHRG_DTC BIT(5)
#define PHY_CDP_DM_AUTO BIT(7)
#define PHY_ENSWITCH_DP BIT(12)
#define PHY_ENSWITCH_DM BIT(13)
/* Armada 3700 USB miscellaneous registers */
#define USB2_PHY_CTRL(usb32) (usb32 ? 0x20 : 0x4)
#define RB_USB2PHY_PU BIT(0)
#define USB2_DP_PULLDN_DEV_MODE BIT(5)
#define USB2_DM_PULLDN_DEV_MODE BIT(6)
#define RB_USB2PHY_SUSPM(usb32) (usb32 ? BIT(14) : BIT(7))
#define PLL_LOCK_DELAY_US 10000
#define PLL_LOCK_TIMEOUT_US 1000000
/**
* struct mvebu_a3700_utmi_caps - PHY capabilities
*
* @usb32: Flag indicating which PHY is in use (impacts the register map):
* - The UTMI PHY wired to the USB3/USB2 controller (otg)
* - The UTMI PHY wired to the USB2 controller (host only)
* @ops: PHY operations
*/
struct mvebu_a3700_utmi_caps {
int usb32;
const struct phy_ops *ops;
};
/**
* struct mvebu_a3700_utmi - PHY driver data
*
* @regs: PHY registers
* @usb_mis: Regmap with USB miscellaneous registers including PHY ones
* @caps: PHY capabilities
* @phy: PHY handle
*/
struct mvebu_a3700_utmi {
void __iomem *regs;
struct regmap *usb_misc;
const struct mvebu_a3700_utmi_caps *caps;
struct phy *phy;
};
static int mvebu_a3700_utmi_phy_power_on(struct phy *phy)
{
struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
struct device *dev = &phy->dev;
int usb32 = utmi->caps->usb32;
int ret = 0;
u32 reg;
/*
* Setup PLL. 40MHz clock used to be the default, being 25MHz now.
* See "PLL Settings for Typical REFCLK" table.
*/
reg = readl(utmi->regs + USB2_PHY_PLL_CTRL_REG0);
reg &= ~(PLL_REF_DIV_MASK | PLL_FB_DIV_MASK | PLL_SEL_LPFR_MASK);
reg |= (PLL_REF_DIV_5 << PLL_REF_DIV_OFF) |
(PLL_FB_DIV_96 << PLL_FB_DIV_OFF);
writel(reg, utmi->regs + USB2_PHY_PLL_CTRL_REG0);
/* Enable PHY pull up and disable USB2 suspend */
regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU,
RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU);
if (usb32) {
/* Power up OTG module */
reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
reg |= PHY_PU_OTG;
writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);
/* Disable PHY charger detection */
reg = readl(utmi->regs + USB2_PHY_CHRGR_DETECT);
reg &= ~(PHY_CDP_EN | PHY_DCP_EN | PHY_PD_EN | PHY_PU_CHRG_DTC |
PHY_CDP_DM_AUTO | PHY_ENSWITCH_DP | PHY_ENSWITCH_DM);
writel(reg, utmi->regs + USB2_PHY_CHRGR_DETECT);
/* Disable PHY DP/DM pull-down (used for device mode) */
regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
USB2_DP_PULLDN_DEV_MODE |
USB2_DM_PULLDN_DEV_MODE, 0);
}
/* Wait for PLL calibration */
ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
reg & PHY_PLLCAL_DONE,
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
if (ret) {
dev_err(dev, "Failed to end USB2 PLL calibration\n");
return ret;
}
/* Wait for impedance calibration */
ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
reg & PHY_IMPCAL_DONE,
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
if (ret) {
dev_err(dev, "Failed to end USB2 impedance calibration\n");
return ret;
}
/* Wait for squelch calibration */
ret = readl_poll_timeout(utmi->regs + USB2_RX_CHAN_CTRL1, reg,
reg & USB2PHY_SQCAL_DONE,
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
if (ret) {
dev_err(dev, "Failed to end USB2 unknown calibration\n");
return ret;
}
/* Wait for PLL to be locked */
ret = readl_poll_timeout(utmi->regs + USB2_PHY_PLL_CTRL_REG0, reg,
reg & PLL_READY,
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
if (ret)
dev_err(dev, "Failed to lock USB2 PLL\n");
return ret;
}
static int mvebu_a3700_utmi_phy_power_off(struct phy *phy)
{
struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
int usb32 = utmi->caps->usb32;
u32 reg;
/* Disable PHY pull-up and enable USB2 suspend */
reg = readl(utmi->regs + USB2_PHY_CTRL(usb32));
reg &= ~(RB_USB2PHY_PU | RB_USB2PHY_SUSPM(usb32));
writel(reg, utmi->regs + USB2_PHY_CTRL(usb32));
/* Power down OTG module */
if (usb32) {
reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
reg &= ~PHY_PU_OTG;
writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);
}
return 0;
}
static const struct phy_ops mvebu_a3700_utmi_phy_ops = {
.power_on = mvebu_a3700_utmi_phy_power_on,
.power_off = mvebu_a3700_utmi_phy_power_off,
.owner = THIS_MODULE,
};
static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_otg_phy_caps = {
.usb32 = true,
.ops = &mvebu_a3700_utmi_phy_ops,
};
static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_host_phy_caps = {
.usb32 = false,
.ops = &mvebu_a3700_utmi_phy_ops,
};
static const struct of_device_id mvebu_a3700_utmi_of_match[] = {
{
.compatible = "marvell,a3700-utmi-otg-phy",
.data = &mvebu_a3700_utmi_otg_phy_caps,
},
{
.compatible = "marvell,a3700-utmi-host-phy",
.data = &mvebu_a3700_utmi_host_phy_caps,
},
{},
};
MODULE_DEVICE_TABLE(of, mvebu_a3700_utmi_of_match);
static int mvebu_a3700_utmi_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mvebu_a3700_utmi *utmi;
struct phy_provider *provider;
struct resource *res;
utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL);
if (!utmi)
return -ENOMEM;
/* Get UTMI memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "Missing UTMI PHY memory resource\n");
return -ENODEV;
}
utmi->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(utmi->regs))
return PTR_ERR(utmi->regs);
/* Get miscellaneous Host/PHY region */
utmi->usb_misc = syscon_regmap_lookup_by_phandle(dev->of_node,
"marvell,usb-misc-reg");
if (IS_ERR(utmi->usb_misc)) {
dev_err(dev,
"Missing USB misc purpose system controller\n");
return PTR_ERR(utmi->usb_misc);
}
/* Retrieve PHY capabilities */
utmi->caps = of_device_get_match_data(dev);
/* Instantiate the PHY */
utmi->phy = devm_phy_create(dev, NULL, utmi->caps->ops);
if (IS_ERR(utmi->phy)) {
dev_err(dev, "Failed to create the UTMI PHY\n");
return PTR_ERR(utmi->phy);
}
phy_set_drvdata(utmi->phy, utmi);
/* Ensure the PHY is powered off */
utmi->caps->ops->power_off(utmi->phy);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(provider);
}
static struct platform_driver mvebu_a3700_utmi_driver = {
.probe = mvebu_a3700_utmi_phy_probe,
.driver = {
.name = "mvebu-a3700-utmi-phy",
.owner = THIS_MODULE,
.of_match_table = mvebu_a3700_utmi_of_match,
},
};
module_platform_driver(mvebu_a3700_utmi_driver);
MODULE_AUTHOR("Igal Liberman <igall@marvell.com>");
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
MODULE_DESCRIPTION("Marvell EBU A3700 UTMI PHY driver");
MODULE_LICENSE("GPL v2");

View File

@ -580,8 +580,6 @@ static struct phy *mvebu_comphy_xlate(struct device *dev,
return phy;
lane = phy_get_drvdata(phy);
if (lane->port >= 0)
return ERR_PTR(-EBUSY);
lane->port = args->args[0];
return phy;

View File

@ -10,7 +10,7 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/phy/phy.h>
#include <linux/io.h>
@ -122,7 +122,6 @@ static const struct of_device_id phy_mvebu_sata_of_match[] = {
{ .compatible = "marvell,mvebu-sata-phy" },
{ },
};
MODULE_DEVICE_TABLE(of, phy_mvebu_sata_of_match);
static struct platform_driver phy_mvebu_sata_driver = {
.probe = phy_mvebu_sata_probe,
@ -131,8 +130,4 @@ static struct platform_driver phy_mvebu_sata_driver = {
.of_match_table = phy_mvebu_sata_of_match,
}
};
module_platform_driver(phy_mvebu_sata_driver);
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
MODULE_DESCRIPTION("Marvell MVEBU SATA PHY driver");
MODULE_LICENSE("GPL v2");
builtin_platform_driver(phy_mvebu_sata_driver);

View File

@ -65,12 +65,12 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
*/
cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui);
cfg->init = 100000000;
cfg->init = 100;
cfg->lpx = 60000;
cfg->ta_get = 5 * cfg->lpx;
cfg->ta_go = 4 * cfg->lpx;
cfg->ta_sure = 2 * cfg->lpx;
cfg->wakeup = 1000000000;
cfg->wakeup = 1000;
cfg->hs_clk_rate = hs_clk_rate;
cfg->lanes = lanes;
@ -143,7 +143,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg)
if (cfg->hs_trail < max(8 * ui, 60000 + 4 * ui))
return -EINVAL;
if (cfg->init < 100000000)
if (cfg->init < 100)
return -EINVAL;
if (cfg->lpx < 50000)
@ -158,7 +158,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg)
if (cfg->ta_sure < cfg->lpx || cfg->ta_sure > (2 * cfg->lpx))
return -EINVAL;
if (cfg->wakeup < 1000000000)
if (cfg->wakeup < 1000)
return -EINVAL;
return 0;

View File

@ -1112,14 +1112,4 @@ static int __init phy_core_init(void)
return 0;
}
module_init(phy_core_init);
static void __exit phy_core_exit(void)
{
class_destroy(phy_class);
}
module_exit(phy_core_exit);
MODULE_DESCRIPTION("Generic PHY Framework");
MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
MODULE_LICENSE("GPL v2");
device_initcall(phy_core_init);

View File

@ -687,6 +687,116 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02),
};
static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
};
static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16),
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00),
};
static const struct qmp_phy_init_tbl msm8998_usb3_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05),
};
static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
};
/* struct qmp_phy_cfg - per-PHY initialization config */
struct qmp_phy_cfg {
/* phy-type - PCIE/UFS/USB */
@ -1036,6 +1146,33 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
.no_pcs_sw_reset = true,
};
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.type = PHY_TYPE_USB3,
.nlanes = 1,
.serdes_tbl = msm8998_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl),
.tx_tbl = msm8998_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl),
.rx_tbl = msm8998_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl),
.pcs_tbl = msm8998_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(msm8998_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 = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
.mask_pcs_ready = PHYSTATUS,
.is_dual_lane_phy = true,
};
static void qcom_qmp_phy_configure(void __iomem *base,
const unsigned int *regs,
const struct qmp_phy_init_tbl tbl[],
@ -1735,6 +1872,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,msm8996-qmp-usb3-phy",
.data = &msm8996_usb3phy_cfg,
}, {
.compatible = "qcom,msm8998-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
}, {
.compatible = "qcom,ipq8074-qmp-pcie-phy",
.data = &ipq8074_pciephy_cfg,
@ -1747,6 +1887,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,sdm845-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
}, {
.compatible = "qcom,msm8998-qmp-usb3-phy",
.data = &msm8998_usb3phy_cfg,
},
{ },
};

View File

@ -174,6 +174,7 @@
#define QSERDES_V3_COM_DIV_FRAC_START1_MODE1 0x0c4
#define QSERDES_V3_COM_DIV_FRAC_START2_MODE1 0x0c8
#define QSERDES_V3_COM_DIV_FRAC_START3_MODE1 0x0cc
#define QSERDES_V3_COM_INTEGLOOP_INITVAL 0x0d0
#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0 0x0d8
#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0 0x0dc
#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1 0x0e0
@ -201,6 +202,7 @@
#define QSERDES_V3_COM_DEBUG_BUS2 0x170
#define QSERDES_V3_COM_DEBUG_BUS3 0x174
#define QSERDES_V3_COM_DEBUG_BUS_SEL 0x178
#define QSERDES_V3_COM_CMN_MODE 0x184
/* Only for QMP V3 PHY - TX registers */
#define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX 0x044
@ -211,6 +213,7 @@
#define QSERDES_V3_TX_RCV_DETECT_LVL_2 0x0a4
/* Only for QMP V3 PHY - RX registers */
#define QSERDES_V3_RX_UCDR_FO_GAIN 0x008
#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024
@ -219,6 +222,7 @@
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040
#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc

View File

@ -152,6 +152,31 @@ static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
};
static const unsigned int msm8998_regs_layout[] = {
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
[QUSB2PHY_PLL_STATUS] = 0x1a0,
[QUSB2PHY_PORT_TUNE1] = 0x23c,
[QUSB2PHY_PORT_TUNE2] = 0x240,
[QUSB2PHY_PORT_TUNE3] = 0x244,
[QUSB2PHY_PORT_TUNE4] = 0x248,
[QUSB2PHY_PORT_TEST1] = 0x24c,
[QUSB2PHY_PORT_TEST2] = 0x250,
[QUSB2PHY_PORT_POWERDOWN] = 0x210,
[QUSB2PHY_INTR_CTRL] = 0x22c,
};
static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x13),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xa5),
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x09),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
};
static const unsigned int sdm845_regs_layout[] = {
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
[QUSB2PHY_PLL_STATUS] = 0x1a0,
@ -221,6 +246,18 @@ static const struct qusb2_phy_cfg msm8996_phy_cfg = {
.autoresume_en = BIT(3),
};
static const struct qusb2_phy_cfg msm8998_phy_cfg = {
.tbl = msm8998_init_tbl,
.tbl_num = ARRAY_SIZE(msm8998_init_tbl),
.regs = msm8998_regs_layout,
.disable_ctrl = POWER_DOWN,
.mask_core_ready = CORE_READY_STATUS,
.has_pll_override = true,
.autoresume_en = BIT(0),
.update_tune1_with_efuse = true,
};
static const struct qusb2_phy_cfg sdm845_phy_cfg = {
.tbl = sdm845_init_tbl,
.tbl_num = ARRAY_SIZE(sdm845_init_tbl),
@ -733,6 +770,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
{
.compatible = "qcom,msm8996-qusb2-phy",
.data = &msm8996_phy_cfg,
}, {
.compatible = "qcom,msm8998-qusb2-phy",
.data = &msm8998_phy_cfg,
}, {
.compatible = "qcom,sdm845-qusb2-phy",
.data = &sdm845_phy_cfg,

View File

@ -23,24 +23,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
({ \
ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
might_sleep_if(timeout_us); \
for (;;) { \
(val) = readl(addr); \
if (cond) \
break; \
if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
(val) = readl(addr); \
break; \
} \
if (sleep_us) \
usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
} \
(cond) ? 0 : -ETIMEDOUT; \
})
#include <linux/iopoll.h>
#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \
{ \

View File

@ -55,16 +55,16 @@ enum rockchip_usb2phy_host_state {
};
/**
* Different states involved in USB charger detection.
* USB_CHG_STATE_UNDEFINED USB charger is not connected or detection
* enum usb_chg_state - Different states involved in USB charger detection.
* @USB_CHG_STATE_UNDEFINED: USB charger is not connected or detection
* process is not yet started.
* USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact.
* USB_CHG_STATE_DCD_DONE Data pin contact is detected.
* USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects
* @USB_CHG_STATE_WAIT_FOR_DCD: Waiting for Data pins contact.
* @USB_CHG_STATE_DCD_DONE: Data pin contact is detected.
* @USB_CHG_STATE_PRIMARY_DONE: Primary detection is completed (Detects
* between SDP and DCP/CDP).
* USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects
* between DCP and CDP).
* USB_CHG_STATE_DETECTED USB charger type is determined.
* @USB_CHG_STATE_SECONDARY_DONE: Secondary detection is completed (Detects
* between DCP and CDP).
* @USB_CHG_STATE_DETECTED: USB charger type is determined.
*/
enum usb_chg_state {
USB_CHG_STATE_UNDEFINED = 0,
@ -94,7 +94,7 @@ struct usb2phy_reg {
};
/**
* struct rockchip_chg_det_reg: usb charger detect registers
* struct rockchip_chg_det_reg - usb charger detect registers
* @cp_det: charging port detected successfully.
* @dcp_det: dedicated charging port detected successfully.
* @dp_det: assert data pin connect successfully.
@ -120,7 +120,7 @@ struct rockchip_chg_det_reg {
};
/**
* struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
* struct rockchip_usb2phy_port_cfg - usb-phy port configuration.
* @phy_sus: phy suspend register.
* @bvalid_det_en: vbus valid rise detection enable register.
* @bvalid_det_st: vbus valid rise detection status register.
@ -148,10 +148,11 @@ struct rockchip_usb2phy_port_cfg {
};
/**
* struct rockchip_usb2phy_cfg: usb-phy configuration.
* struct rockchip_usb2phy_cfg - usb-phy configuration.
* @reg: the address offset of grf for usb-phy config.
* @num_ports: specify how many ports that the phy has.
* @clkout_ctl: keep on/turn off output clk of phy.
* @port_cfgs: usb-phy port configurations.
* @chg_det: charger detection registers.
*/
struct rockchip_usb2phy_cfg {
@ -163,12 +164,10 @@ struct rockchip_usb2phy_cfg {
};
/**
* struct rockchip_usb2phy_port: usb-phy port data.
* struct rockchip_usb2phy_port - usb-phy port data.
* @phy: generic phy.
* @port_id: flag for otg port or host port.
* @suspended: phy suspended flag.
* @utmi_avalid: utmi avalid status usage flag.
* true - use avalid to get vbus status
* flase - use bvalid to get vbus status
* @vbus_attached: otg device vbus status.
* @bvalid_irq: IRQ number assigned for vbus valid rise detection.
* @ls_irq: IRQ number assigned for linestate detection.
@ -178,7 +177,7 @@ struct rockchip_usb2phy_cfg {
* @chg_work: charge detect work.
* @otg_sm_work: OTG state machine work.
* @sm_work: HOST state machine work.
* @phy_cfg: port register configuration, assigned by driver data.
* @port_cfg: port register configuration, assigned by driver data.
* @event_nb: hold event notification callback.
* @state: define OTG enumeration states before device reset.
* @mode: the dr_mode of the controller.
@ -187,7 +186,6 @@ struct rockchip_usb2phy_port {
struct phy *phy;
unsigned int port_id;
bool suspended;
bool utmi_avalid;
bool vbus_attached;
int bvalid_irq;
int ls_irq;
@ -203,12 +201,13 @@ struct rockchip_usb2phy_port {
};
/**
* struct rockchip_usb2phy: usb2.0 phy driver data.
* struct rockchip_usb2phy - usb2.0 phy driver data.
* @dev: pointer to device.
* @grf: General Register Files regmap.
* @usbgrf: USB General Register Files regmap.
* @clk: clock struct of phy input clk.
* @clk480m: clock struct of phy output clk.
* @clk_hw: clock struct of phy output clk management.
* @clk480m_hw: clock struct of phy output clk management.
* @chg_state: states involved in USB charger detection.
* @chg_type: USB charger types.
* @dcd_retries: The retry count used to track Data contact
@ -542,12 +541,8 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
unsigned long delay;
bool vbus_attach, sch_work, notify_charger;
if (rport->utmi_avalid)
vbus_attach = property_enabled(rphy->grf,
&rport->port_cfg->utmi_avalid);
else
vbus_attach = property_enabled(rphy->grf,
&rport->port_cfg->utmi_bvalid);
vbus_attach = property_enabled(rphy->grf,
&rport->port_cfg->utmi_bvalid);
sch_work = false;
notify_charger = false;
@ -1021,9 +1016,6 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
rport->utmi_avalid =
of_property_read_bool(child_np, "rockchip,utmi-avalid");
/*
* Some SoCs use one interrupt with otg-id/otg-bvalid/linestate
* interrupts muxed together, so probe the otg-mux interrupt first,

View File

@ -33,12 +33,11 @@ config OMAP_CONTROL_PHY
config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
depends on ARCH_OMAP2PLUS || ARCH_K3
depends on USB_SUPPORT
select GENERIC_PHY
select USB_PHY
select OMAP_CONTROL_PHY
depends on OMAP_OCP2SCP
select OMAP_CONTROL_PHY if ARCH_OMAP2PLUS
help
Enable this to support the transceiver that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
@ -50,7 +49,6 @@ config TI_PIPE3
depends on ARCH_OMAP2PLUS || COMPILE_TEST
select GENERIC_PHY
select OMAP_CONTROL_PHY
depends on OMAP_OCP2SCP
help
Enable this to support the PIPE3 PHY that is part of TI SOCs. This
driver takes care of all the PHY functionality apart from comparator.

View File

@ -36,6 +36,10 @@
#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
#define USB2PHY_ANA_CONFIG1 0x4c
#define AM654_USB2_OTG_PD BIT(8)
#define AM654_USB2_VBUS_DET_EN BIT(5)
#define AM654_USB2_VBUSVALID_DET_EN BIT(4)
/**
* omap_usb2_set_comparator - links the comparator present in the sytem with
* this phy
@ -135,9 +139,9 @@ static int omap_usb_power_on(struct phy *x)
static int omap_usb2_disable_clocks(struct omap_usb *phy)
{
clk_disable(phy->wkupclk);
clk_disable_unprepare(phy->wkupclk);
if (!IS_ERR(phy->optclk))
clk_disable(phy->optclk);
clk_disable_unprepare(phy->optclk);
return 0;
}
@ -146,14 +150,14 @@ static int omap_usb2_enable_clocks(struct omap_usb *phy)
{
int ret;
ret = clk_enable(phy->wkupclk);
ret = clk_prepare_enable(phy->wkupclk);
if (ret < 0) {
dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
goto err0;
}
if (!IS_ERR(phy->optclk)) {
ret = clk_enable(phy->optclk);
ret = clk_prepare_enable(phy->optclk);
if (ret < 0) {
dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
goto err1;
@ -245,6 +249,15 @@ static const struct usb_phy_data am437x_usb2_data = {
.power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
};
static const struct usb_phy_data am654_usb2_data = {
.label = "am654_usb2",
.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
.mask = AM654_USB2_OTG_PD | AM654_USB2_VBUS_DET_EN |
AM654_USB2_VBUSVALID_DET_EN,
.power_on = AM654_USB2_VBUS_DET_EN | AM654_USB2_VBUSVALID_DET_EN,
.power_off = AM654_USB2_OTG_PD,
};
static const struct of_device_id omap_usb2_id_table[] = {
{
.compatible = "ti,omap-usb2",
@ -266,6 +279,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
.compatible = "ti,am437x-usb2",
.data = &am437x_usb2_data,
},
{
.compatible = "ti,am654-usb2",
.data = &am654_usb2_data,
},
{},
};
MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
@ -346,13 +363,52 @@ static int omap_usb2_probe(struct platform_device *pdev)
}
}
otg->set_host = omap_usb_set_host;
otg->set_peripheral = omap_usb_set_peripheral;
phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
if (IS_ERR(phy->wkupclk)) {
if (PTR_ERR(phy->wkupclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_warn(&pdev->dev, "unable to get wkupclk %ld, trying old name\n",
PTR_ERR(phy->wkupclk));
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
if (IS_ERR(phy->wkupclk)) {
if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
return PTR_ERR(phy->wkupclk);
} else {
dev_warn(&pdev->dev,
"found usb_phy_cm_clk32k, please fix DTS\n");
}
}
phy->optclk = devm_clk_get(phy->dev, "refclk");
if (IS_ERR(phy->optclk)) {
if (PTR_ERR(phy->optclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
if (IS_ERR(phy->optclk)) {
if (PTR_ERR(phy->optclk) != -EPROBE_DEFER) {
dev_dbg(&pdev->dev,
"unable to get usb_otg_ss_refclk960m\n");
}
} else {
dev_warn(&pdev->dev,
"found usb_otg_ss_refclk960m, please fix DTS\n");
}
}
otg->set_host = omap_usb_set_host;
otg->set_peripheral = omap_usb_set_peripheral;
if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
otg->set_vbus = omap_usb_set_vbus;
otg->set_vbus = omap_usb_set_vbus;
if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
otg->start_srp = omap_usb_start_srp;
otg->usb_phy = &phy->phy;
otg->start_srp = omap_usb_start_srp;
otg->usb_phy = &phy->phy;
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);
@ -367,42 +423,12 @@ static int omap_usb2_probe(struct platform_device *pdev)
omap_usb_power_off(generic_phy);
phy_provider = devm_of_phy_provider_register(phy->dev,
of_phy_simple_xlate);
of_phy_simple_xlate);
if (IS_ERR(phy_provider)) {
pm_runtime_disable(phy->dev);
return PTR_ERR(phy_provider);
}
phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
if (IS_ERR(phy->wkupclk)) {
dev_warn(&pdev->dev, "unable to get wkupclk, trying old name\n");
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
if (IS_ERR(phy->wkupclk)) {
dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
pm_runtime_disable(phy->dev);
return PTR_ERR(phy->wkupclk);
} else {
dev_warn(&pdev->dev,
"found usb_phy_cm_clk32k, please fix DTS\n");
}
}
clk_prepare(phy->wkupclk);
phy->optclk = devm_clk_get(phy->dev, "refclk");
if (IS_ERR(phy->optclk)) {
dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
if (IS_ERR(phy->optclk)) {
dev_dbg(&pdev->dev,
"unable to get usb_otg_ss_refclk960m\n");
} else {
dev_warn(&pdev->dev,
"found usb_otg_ss_refclk960m, please fix DTS\n");
}
}
if (!IS_ERR(phy->optclk))
clk_prepare(phy->optclk);
usb_add_phy_dev(&phy->phy);
@ -413,9 +439,6 @@ static int omap_usb2_remove(struct platform_device *pdev)
{
struct omap_usb *phy = platform_get_drvdata(pdev);
clk_unprepare(phy->wkupclk);
if (!IS_ERR(phy->optclk))
clk_unprepare(phy->optclk);
usb_remove_phy(&phy->phy);
pm_runtime_disable(phy->dev);

View File

@ -6,8 +6,6 @@
#ifndef __PHY_MIPI_DPHY_H_
#define __PHY_MIPI_DPHY_H_
#include <video/videomode.h>
/**
* struct phy_configure_opts_mipi_dphy - MIPI D-PHY configuration set
*
@ -192,10 +190,10 @@ struct phy_configure_opts_mipi_dphy {
/**
* @init:
*
* Time, in picoseconds for the initialization period to
* Time, in microseconds for the initialization period to
* complete.
*
* Minimum value: 100000000 ps
* Minimum value: 100 us
*/
unsigned int init;
@ -246,11 +244,11 @@ struct phy_configure_opts_mipi_dphy {
/**
* @wakeup:
*
* Time, in picoseconds, that a transmitter drives a Mark-1
* Time, in microseconds, that a transmitter drives a Mark-1
* state prior to a Stop state in order to initiate an exit
* from ULPS.
*
* Minimum value: 1000000000 ps
* Minimum value: 1000 us
*/
unsigned int wakeup;
@ -271,7 +269,8 @@ struct phy_configure_opts_mipi_dphy {
/**
* @lanes:
*
* Number of active data lanes used for the transmissions.
* Number of active, consecutive, data lanes, starting from
* lane 0, used for the transmissions.
*/
unsigned char lanes;
};