Commit 50f737ab authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-5.6_v2' of...

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

Kishon writes:

phy: for 5.6

*) Add support in PHY core to create link between PHY consumer and PHY
   provider
*) Add DisplayPort PHY configuration set to be used for negotiating the
   configurations to be used between DisplayPort controller and
   DisplayPort PHY
*) Add PHY wrapper driver (configure inputs to Cadence Sierra PHY) for
   TI's J721E SoC and adapt Cadence Sierra PHY driver to be used for
   J721E SoC (Supports USB and PCIe)
*) Add PHY driver for eMMC PHY in Intel LGM SoC
*) Add PHY support for 7216 and 7211 Broadcom SoCs which uses the new
   Synopsys USB Controller
*) Add support for 16nm SATA PHY present in Broadcom 7216 SoC
*) Fix lost packet issue, fix MDIO from getting inaccessible, fix
   occasional transaction failures, fix USB driver from crashing in
   Broadcom USB PHY driver
*) Fix missing PCS SW reset in UFS PHY of Qualcomm SM8150
*) Use "struct phy_configure_opts_mipi_dphy" to pass parameters from
   display controller to rockchip-inno-dsidphy
*) Other cleanups including compile testing for some of the PHY drivers,
   fixing Kconfig indentation, duplicate writes in drivers etc.,
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>

* tag 'phy-for-5.6_v2' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy: (54 commits)
  dt-bindings: phy: Add PHY_TYPE_DP definition
  phy: ti: j721e-wiz: Fix return value check in wiz_probe()
  dt-bindings: usb: Convert Allwinner A80 USB PHY controller to a schema
  phy: intel-lgm-emmc: Fix warning by adding missing MODULE_LICENSE
  phy: ti: j721e-wiz: Manage typec-gpio-dir
  dt-bindings: phy: ti,phy-j721e-wiz: Add Type-C dir GPIO
  phy: cadence: Sierra: add phy_reset hook
  phy: cadence: Sierra: remove redundant initialization of pointer regmap
  phy: Add DisplayPort configuration options
  phy: Enable compile testing for some of drivers
  phy: mediatek: Fix Kconfig indentation
  phy: intel-lgm-emmc: Add support for eMMC PHY
  dt-bindings: phy: intel-emmc-phy: Add YAML schema for LGM eMMC PHY
  phy: ti: j721e-wiz: Add support for WIZ module present in TI J721E SoC
  dt-bindings: phy: Document WIZ (SERDES wrapper) bindings
  phy: cadence: Sierra: Use correct dev pointer in cdns_sierra_phy_remove()
  phy: cadence: Sierra: Set cmn_refclk_dig_div/cmn_refclk1_dig_div frequency to 25MHz
  phy: cadence: Sierra: Change MAX_LANES of Sierra to 16
  phy: cadence: Sierra: Check for PLL lock during PHY power on
  phy: cadence: Sierra: Get reset control "array" for each link
  ...
parents 4baa550e 8a79db5e
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/allwinner,sun9i-a80-usb-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A80 USB PHY Device Tree Bindings
maintainers:
- Chen-Yu Tsai <wens@csie.org>
- Maxime Ripard <mripard@kernel.org>
properties:
"#phy-cells":
const: 0
compatible:
const: allwinner,sun9i-a80-usb-phy
reg:
maxItems: 1
clocks:
anyOf:
- description: Main PHY Clock
- items:
- description: Main PHY clock
- description: HSIC 12MHz clock
- description: HSIC 480MHz clock
clock-names:
oneOf:
- const: phy
- items:
- const: phy
- const: hsic_12M
- const: hsic_480M
resets:
anyOf:
- description: Normal USB PHY reset
- items:
- description: Normal USB PHY reset
- description: HSIC Reset
reset-names:
oneOf:
- const: phy
- items:
- const: phy
- const: hsic
phy_type:
const: hsic
description:
When absent, the PHY type will be assumed to be normal USB.
phy-supply:
description:
Regulator that powers VBUS
required:
- "#phy-cells"
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
additionalProperties: false
if:
properties:
phy_type:
const: hsic
required:
- phy_type
then:
properties:
clocks:
maxItems: 3
clock-names:
maxItems: 3
resets:
maxItems: 2
reset-names:
maxItems: 2
examples:
- |
#include <dt-bindings/clock/sun9i-a80-usb.h>
#include <dt-bindings/reset/sun9i-a80-usb.h>
usbphy1: phy@a00800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a00800 0x4>;
clocks = <&usb_clocks CLK_USB0_PHY>;
clock-names = "phy";
resets = <&usb_clocks RST_USB0_PHY>;
reset-names = "phy";
phy-supply = <&reg_usb1_vbus>;
#phy-cells = <0>;
};
- |
#include <dt-bindings/clock/sun9i-a80-usb.h>
#include <dt-bindings/reset/sun9i-a80-usb.h>
usbphy3: phy@a02800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a02800 0x4>;
clocks = <&usb_clocks CLK_USB2_PHY>,
<&usb_clocks CLK_USB_HSIC>,
<&usb_clocks CLK_USB2_HSIC>;
clock-names = "phy",
"hsic_12M",
"hsic_480M";
resets = <&usb_clocks RST_USB2_PHY>,
<&usb_clocks RST_USB2_HSIC>;
reset-names = "phy",
"hsic";
phy_type = "hsic";
phy-supply = <&reg_usb3_vbus>;
#phy-cells = <0>;
};
Broadcom STB USB PHY Broadcom STB USB PHY
Required properties: Required properties:
- compatible: brcm,brcmstb-usb-phy - compatible: should be one of
- reg: two offset and length pairs. "brcm,brcmstb-usb-phy"
The first pair specifies a manditory set of memory mapped "brcm,bcm7216-usb-phy"
registers used for general control of the PHY. "brcm,bcm7211-usb-phy"
The second pair specifies optional registers used by some of
the SoCs that support USB 3.x - reg and reg-names properties requirements are specific to the
- #phy-cells: Shall be 1 as it expects one argument for setting compatible string.
"brcm,brcmstb-usb-phy":
- reg: 1 or 2 offset and length pairs. One for the base CTRL registers
and an optional pair for systems with USB 3.x support
- reg-names: not specified
"brcm,bcm7216-usb-phy":
- reg: 3 offset and length pairs for CTRL, XHCI_EC and XHCI_GBL
registers
- reg-names: "ctrl", "xhci_ec", "xhci_gbl"
"brcm,bcm7211-usb-phy":
- reg: 5 offset and length pairs for CTRL, XHCI_EC, XHCI_GBL,
USB_PHY and USB_MDIO registers and an optional pair
for the BDC registers
- reg-names: "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
- #phy-cells: Shall be 1 as it expects one argument for setting
the type of the PHY. Possible values are: the type of the PHY. Possible values are:
- PHY_TYPE_USB2 for USB1.1/2.0 PHY - PHY_TYPE_USB2 for USB1.1/2.0 PHY
- PHY_TYPE_USB3 for USB3.x PHY - PHY_TYPE_USB3 for USB3.x PHY
...@@ -15,16 +30,20 @@ Required properties: ...@@ -15,16 +30,20 @@ Required properties:
Optional Properties: Optional Properties:
- clocks : clock phandles. - clocks : clock phandles.
- clock-names: String, clock name. - clock-names: String, clock name.
- interrupts: wakeup interrupt
- interrupt-names: "wakeup"
- brcm,ipp: Boolean, Invert Port Power. - brcm,ipp: Boolean, Invert Port Power.
Possible values are: 0 (Don't invert), 1 (Invert) Possible values are: 0 (Don't invert), 1 (Invert)
- brcm,ioc: Boolean, Invert Over Current detection. - brcm,ioc: Boolean, Invert Over Current detection.
Possible values are: 0 (Don't invert), 1 (Invert) Possible values are: 0 (Don't invert), 1 (Invert)
NOTE: one or both of the following two properties must be set
- brcm,has-xhci: Boolean indicating the phy has an XHCI phy.
- brcm,has-eohci: Boolean indicating the phy has an EHCI/OHCI phy.
- dr_mode: String, PHY Device mode. - dr_mode: String, PHY Device mode.
Possible values are: "host", "peripheral ", "drd" or "typec-pd" Possible values are: "host", "peripheral ", "drd" or "typec-pd"
If this property is not defined, the phy will default to "host" mode. If this property is not defined, the phy will default to "host" mode.
- brcm,syscon-piarbctl: phandle to syscon for handling config registers
NOTE: one or both of the following two properties must be set
- brcm,has-xhci: Boolean indicating the phy has an XHCI phy.
- brcm,has-eohci: Boolean indicating the phy has an EHCI/OHCI phy.
Example: Example:
...@@ -41,3 +60,27 @@ usbphy_0: usb-phy@f0470200 { ...@@ -41,3 +60,27 @@ usbphy_0: usb-phy@f0470200 {
clocks = <&usb20>, <&usb30>; clocks = <&usb20>, <&usb30>;
clock-names = "sw_usb", "sw_usb3"; clock-names = "sw_usb", "sw_usb3";
}; };
usb-phy@29f0200 {
reg = <0x29f0200 0x200>,
<0x29c0880 0x30>,
<0x29cc100 0x534>,
<0x2808000 0x24>,
<0x2980080 0x8>;
reg-names = "ctrl",
"xhci_ec",
"xhci_gbl",
"usb_phy",
"usb_mdio";
brcm,ioc = <0x0>;
brcm,ipp = <0x0>;
compatible = "brcm,bcm7211-usb-phy";
interrupts = <0x30>;
interrupt-parent = <&vpu_intr1_nosec_intc>;
interrupt-names = "wake";
#phy-cells = <0x1>;
brcm,has-xhci;
syscon-piarbctl = <&syscon_piarbctl>;
clocks = <&scmi_clk 256>;
clock-names = "sw_usb";
};
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Required properties: Required properties:
- compatible: should be one or more of - compatible: should be one or more of
"brcm,bcm7216-sata-phy"
"brcm,bcm7425-sata-phy" "brcm,bcm7425-sata-phy"
"brcm,bcm7445-sata-phy" "brcm,bcm7445-sata-phy"
"brcm,iproc-ns2-sata-phy" "brcm,iproc-ns2-sata-phy"
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/intel,lgm-emmc-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel Lightning Mountain(LGM) eMMC PHY Device Tree Bindings
maintainers:
- Ramuthevar Vadivel Murugan <vadivel.muruganx.ramuthevar@linux.intel.com>
description: |+
Bindings for eMMC PHY on Intel's Lightning Mountain SoC, syscon
node is used to reference the base address of eMMC phy registers.
The eMMC PHY node should be the child of a syscon node with the
required property:
- compatible: Should be one of the following:
"intel,lgm-syscon", "syscon"
- reg:
maxItems: 1
properties:
compatible:
const: intel,lgm-emmc-phy
"#phy-cells":
const: 0
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- "#phy-cells"
- compatible
- reg
- clocks
examples:
- |
sysconf: chiptop@e0200000 {
compatible = "intel,lgm-syscon", "syscon";
reg = <0xe0200000 0x100>;
emmc-phy: emmc-phy@a8 {
compatible = "intel,lgm-emmc-phy";
reg = <0x00a8 0x10>;
clocks = <&emmc>;
#phy-cells = <0>;
};
};
...
...@@ -2,21 +2,24 @@ Cadence Sierra PHY ...@@ -2,21 +2,24 @@ Cadence Sierra PHY
----------------------- -----------------------
Required properties: Required properties:
- compatible: cdns,sierra-phy-t0 - compatible: Must be "cdns,sierra-phy-t0" for Sierra in Cadence platform
- clocks: Must contain an entry in clock-names. Must be "ti,sierra-phy-t0" for Sierra in TI's J721E SoC.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must be "phy_clk"
- resets: Must contain an entry for each in reset-names. - resets: Must contain an entry for each in reset-names.
See ../reset/reset.txt for details. See ../reset/reset.txt for details.
- reset-names: Must include "sierra_reset" and "sierra_apb". - reset-names: Must include "sierra_reset" and "sierra_apb".
"sierra_reset" must control the reset line to the PHY. "sierra_reset" must control the reset line to the PHY.
"sierra_apb" must control the reset line to the APB PHY "sierra_apb" must control the reset line to the APB PHY
interface. interface ("sierra_apb" is optional).
- reg: register range for the PHY. - reg: register range for the PHY.
- #address-cells: Must be 1 - #address-cells: Must be 1
- #size-cells: Must be 0 - #size-cells: Must be 0
Optional properties: Optional properties:
- clocks: Must contain an entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must contain "cmn_refclk_dig_div" and
"cmn_refclk1_dig_div" for configuring the frequency of
the clock to the lanes. "phy_clk" is deprecated.
- cdns,autoconf: A boolean property whose presence indicates that the - cdns,autoconf: A boolean property whose presence indicates that the
PHY registers will be configured by hardware. If not PHY registers will be configured by hardware. If not
present, all sub-node optional properties must be present, all sub-node optional properties must be
......
...@@ -13,9 +13,6 @@ properties: ...@@ -13,9 +13,6 @@ properties:
"#phy-cells": "#phy-cells":
const: 0 const: 0
"#clock-cells":
const: 0
compatible: compatible:
enum: enum:
- rockchip,px30-dsi-dphy - rockchip,px30-dsi-dphy
...@@ -49,7 +46,6 @@ properties: ...@@ -49,7 +46,6 @@ properties:
required: required:
- "#phy-cells" - "#phy-cells"
- "#clock-cells"
- compatible - compatible
- reg - reg
- clocks - clocks
...@@ -66,7 +62,6 @@ examples: ...@@ -66,7 +62,6 @@ examples:
reg = <0x0 0xff2e0000 0x0 0x10000>; reg = <0x0 0xff2e0000 0x0 0x10000>;
clocks = <&pmucru 13>, <&cru 12>; clocks = <&pmucru 13>, <&cru 12>;
clock-names = "ref", "pclk"; clock-names = "ref", "pclk";
#clock-cells = <0>;
resets = <&cru 12>; resets = <&cru 12>;
reset-names = "apb"; reset-names = "apb";
#phy-cells = <0>; #phy-cells = <0>;
......
Allwinner sun9i USB PHY
-----------------------
Required properties:
- compatible : should be one of
* allwinner,sun9i-a80-usb-phy
- reg : a list of offset + length pairs
- #phy-cells : from the generic phy bindings, must be 0
- phy_type : "hsic" for HSIC usage;
other values or absence of this property indicates normal USB
- clocks : phandle + clock specifier for the phy clocks
- clock-names : depending on the "phy_type" property,
* "phy" for normal USB
* "hsic_480M", "hsic_12M" for HSIC
- resets : a list of phandle + reset specifier pairs
- reset-names : depending on the "phy_type" property,
* "phy" for normal USB
* "hsic" for HSIC
Optional Properties:
- phy-supply : from the generic phy bindings, a phandle to a regulator that
provides power to VBUS.
It is recommended to list all clocks and resets available.
The driver will only use those matching the phy_type.
Example:
usbphy1: phy@a01800 {
compatible = "allwinner,sun9i-a80-usb-phy";
reg = <0x00a01800 0x4>;
clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>,
<&usb_phy_clk 3>;
clock-names = "hsic_480M", "hsic_12M", "phy";
resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>;
reset-names = "hsic", "phy";
#phy-cells = <0>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/ti,phy-j721e-wiz.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: TI J721E WIZ (SERDES Wrapper)
maintainers:
- Kishon Vijay Abraham I <kishon@ti.com>
properties:
compatible:
enum:
- ti,j721e-wiz-16g
- ti,j721e-wiz-10g
power-domains:
maxItems: 1
clocks:
maxItems: 3
description: clock-specifier to represent input to the WIZ
clock-names:
items:
- const: fck
- const: core_ref_clk
- const: ext_ref_clk
num-lanes:
minimum: 1
maximum: 4
"#address-cells":
const: 1
"#size-cells":
const: 1
"#reset-cells":
const: 1
ranges: true
assigned-clocks:
maxItems: 2
assigned-clock-parents:
maxItems: 2
typec-dir-gpios:
maxItems: 1
description:
GPIO to signal Type-C cable orientation for lane swap.
If GPIO is active, lane 0 and lane 1 of SERDES will be swapped to
achieve the funtionality of an external type-C plug flip mux.
typec-dir-debounce-ms:
minimum: 100
maximum: 1000
default: 100
description:
Number of milliseconds to wait before sampling typec-dir-gpio.
If not specified, the default debounce of 100ms will be used.
Type-C spec states minimum CC pin debounce of 100 ms and maximum
of 200 ms. However, some solutions might need more than 200 ms.
patternProperties:
"^pll[0|1]-refclk$":
type: object
description: |
WIZ node should have subnodes for each of the PLLs present in
the SERDES.
properties:
clocks:
maxItems: 2
description: Phandle to clock nodes representing the two inputs to PLL.
"#clock-cells":
const: 0
assigned-clocks:
maxItems: 1
assigned-clock-parents:
maxItems: 1
required:
- clocks
- "#clock-cells"
- assigned-clocks
- assigned-clock-parents
"^cmn-refclk1?-dig-div$":
type: object
description:
WIZ node should have subnodes for each of the PMA common refclock
provided by the SERDES.
properties:
clocks:
maxItems: 1
description: Phandle to the clock node representing the input to the
divider clock.
"#clock-cells":
const: 0
required:
- clocks
- "#clock-cells"
"^refclk-dig$":
type: object
description: |
WIZ node should have subnode for refclk_dig to select the reference
clock source for the reference clock used in the PHY and PMA digital
logic.
properties:
clocks:
maxItems: 4
description: Phandle to four clock nodes representing the inputs to
refclk_dig
"#clock-cells":
const: 0
assigned-clocks:
maxItems: 1
assigned-clock-parents:
maxItems: 1
required:
- clocks
- "#clock-cells"
- assigned-clocks
- assigned-clock-parents
"^serdes@[0-9a-f]+$":
type: object
description: |
WIZ node should have '1' subnode for the SERDES. It could be either
Sierra SERDES or Torrent SERDES. Sierra SERDES should follow the
bindings specified in
Documentation/devicetree/bindings/phy/phy-cadence-sierra.txt
Torrent SERDES should follow the bindings specified in
Documentation/devicetree/bindings/phy/phy-cadence-dp.txt
required:
- compatible
- power-domains
- clocks
- clock-names
- num-lanes
- "#address-cells"
- "#size-cells"
- "#reset-cells"
- ranges
examples:
- |
#include <dt-bindings/soc/ti,sci_pm_domain.h>
wiz@5000000 {
compatible = "ti,j721e-wiz-16g";
#address-cells = <1>;
#size-cells = <1>;
power-domains = <&k3_pds 292 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 292 5>, <&k3_clks 292 11>, <&dummy_cmn_refclk>;
clock-names = "fck", "core_ref_clk", "ext_ref_clk";
assigned-clocks = <&k3_clks 292 11>, <&k3_clks 292 0>;
assigned-clock-parents = <&k3_clks 292 15>, <&k3_clks 292 4>;
num-lanes = <2>;
#reset-cells = <1>;
ranges = <0x5000000 0x5000000 0x10000>;
pll0-refclk {
clocks = <&k3_clks 293 13>, <&dummy_cmn_refclk>;
#clock-cells = <0>;
assigned-clocks = <&wiz1_pll0_refclk>;
assigned-clock-parents = <&k3_clks 293 13>;
};
pll1-refclk {
clocks = <&k3_clks 293 0>, <&dummy_cmn_refclk1>;
#clock-cells = <0>;
assigned-clocks = <&wiz1_pll1_refclk>;
assigned-clock-parents = <&k3_clks 293 0>;
};
cmn-refclk-dig-div {
clocks = <&wiz1_refclk_dig>;
#clock-cells = <0>;
};
cmn-refclk1-dig-div {
clocks = <&wiz1_pll1_refclk>;
#clock-cells = <0>;
};
refclk-dig {
clocks = <&k3_clks 292 11>, <&k3_clks 292 0>, <&dummy_cmn_refclk>, <&dummy_cmn_refclk1>;
#clock-cells = <0>;
assigned-clocks = <&wiz0_refclk_dig>;
assigned-clock-parents = <&k3_clks 292 11>;
};
serdes@5000000 {
compatible = "cdns,ti,sierra-phy-t0";
reg-names = "serdes";
reg = <0x5000000 0x10000>;
#address-cells = <1>;
#size-cells = <0>;
resets = <&serdes_wiz0 0>;
reset-names = "sierra_reset";
clocks = <&wiz0_cmn_refclk_dig_div>, <&wiz0_cmn_refclk1_dig_div>;
clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div";
};
};
...@@ -69,5 +69,6 @@ source "drivers/phy/socionext/Kconfig" ...@@ -69,5 +69,6 @@ source "drivers/phy/socionext/Kconfig"
source "drivers/phy/st/Kconfig" source "drivers/phy/st/Kconfig"
source "drivers/phy/tegra/Kconfig" source "drivers/phy/tegra/Kconfig"
source "drivers/phy/ti/Kconfig" source "drivers/phy/ti/Kconfig"
source "drivers/phy/intel/Kconfig"
endmenu endmenu
...@@ -18,6 +18,7 @@ obj-y += broadcom/ \ ...@@ -18,6 +18,7 @@ obj-y += broadcom/ \
cadence/ \ cadence/ \
freescale/ \ freescale/ \
hisilicon/ \ hisilicon/ \
intel/ \
lantiq/ \ lantiq/ \
marvell/ \ marvell/ \
motorola/ \ motorola/ \
......
...@@ -8,7 +8,7 @@ obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o ...@@ -8,7 +8,7 @@ obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.o obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.o
phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o phy-brcm-usb-init-synopsys.o
obj-$(CONFIG_PHY_BCM_SR_PCIE) += phy-bcm-sr-pcie.o obj-$(CONFIG_PHY_BCM_SR_PCIE) += phy-bcm-sr-pcie.o
obj-$(CONFIG_PHY_BCM_SR_USB) += phy-bcm-sr-usb.o obj-$(CONFIG_PHY_BCM_SR_USB) += phy-bcm-sr-usb.o
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8 #define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8
enum brcm_sata_phy_version { enum brcm_sata_phy_version {
BRCM_SATA_PHY_STB_16NM,
BRCM_SATA_PHY_STB_28NM, BRCM_SATA_PHY_STB_28NM,
BRCM_SATA_PHY_STB_40NM, BRCM_SATA_PHY_STB_40NM,
BRCM_SATA_PHY_IPROC_NS2, BRCM_SATA_PHY_IPROC_NS2,
...@@ -104,10 +105,13 @@ enum sata_phy_regs { ...@@ -104,10 +105,13 @@ enum sata_phy_regs {
PLL1_ACTRL5 = 0x85, PLL1_ACTRL5 = 0x85,
PLL1_ACTRL6 = 0x86, PLL1_ACTRL6 = 0x86,
PLL1_ACTRL7 = 0x87, PLL1_ACTRL7 = 0x87,
PLL1_ACTRL8 = 0x88,
TX_REG_BANK = 0x070, TX_REG_BANK = 0x070,
TX_ACTRL0 = 0x80, TX_ACTRL0 = 0x80,
TX_ACTRL0_TXPOL_FLIP = BIT(6), TX_ACTRL0_TXPOL_FLIP = BIT(6),
TX_ACTRL5 = 0x85,
TX_ACTRL5_SSC_EN = BIT(11),
AEQRX_REG_BANK_0 = 0xd0, AEQRX_REG_BANK_0 = 0xd0,
AEQ_CONTROL1 = 0x81, AEQ_CONTROL1 = 0x81,
...@@ -116,6 +120,7 @@ enum sata_phy_regs { ...@@ -116,6 +120,7 @@ enum sata_phy_regs {
AEQ_FRC_EQ = 0x83, AEQ_FRC_EQ = 0x83,
AEQ_FRC_EQ_FORCE = BIT(0), AEQ_FRC_EQ_FORCE = BIT(0),
AEQ_FRC_EQ_FORCE_VAL = BIT(1), AEQ_FRC_EQ_FORCE_VAL = BIT(1),
AEQ_RFZ_FRC_VAL = BIT(8),
AEQRX_REG_BANK_1 = 0xe0, AEQRX_REG_BANK_1 = 0xe0,
AEQRX_SLCAL0_CTRL0 = 0x82, AEQRX_SLCAL0_CTRL0 = 0x82,
AEQRX_SLCAL1_CTRL0 = 0x86, AEQRX_SLCAL1_CTRL0 = 0x86,
...@@ -152,7 +157,28 @@ enum sata_phy_regs { ...@@ -152,7 +157,28 @@ enum sata_phy_regs {
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
RXPMD_REG_BANK = 0x1c0, RXPMD_REG_BANK = 0x1c0,
RXPMD_RX_CDR_CONTROL1 = 0x81,
RXPMD_RX_PPM_VAL_MASK = 0x1ff,
RXPMD_RXPMD_EN_FRC = BIT(12),
RXPMD_RXPMD_EN_FRC_VAL = BIT(13),
RXPMD_RX_CDR_CDR_PROP_BW = 0x82,
RXPMD_G_CDR_PROP_BW_MASK = 0x7,
RXPMD_G1_CDR_PROP_BW_SHIFT = 0,
RXPMD_G2_CDR_PROP_BW_SHIFT = 3,
RXPMD_G3_CDR_PROB_BW_SHIFT = 6,
RXPMD_RX_CDR_CDR_ACQ_INTEG_BW = 0x83,
RXPMD_G_CDR_ACQ_INT_BW_MASK = 0x7,
RXPMD_G1_CDR_ACQ_INT_BW_SHIFT = 0,
RXPMD_G2_CDR_ACQ_INT_BW_SHIFT = 3,
RXPMD_G3_CDR_ACQ_INT_BW_SHIFT = 6,
RXPMD_RX_CDR_CDR_LOCK_INTEG_BW = 0x84,
RXPMD_G_CDR_LOCK_INT_BW_MASK = 0x7,
RXPMD_G1_CDR_LOCK_INT_BW_SHIFT = 0,
RXPMD_G2_CDR_LOCK_INT_BW_SHIFT = 3,
RXPMD_G3_CDR_LOCK_INT_BW_SHIFT = 6,
RXPMD_RX_FREQ_MON_CONTROL1 = 0x87, RXPMD_RX_FREQ_MON_CONTROL1 = 0x87,
RXPMD_MON_CORRECT_EN = BIT(8),
RXPMD_MON_MARGIN_VAL_MASK = 0xff,
}; };
enum sata_phy_ctrl_regs { enum sata_phy_ctrl_regs {
...@@ -166,6 +192,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port) ...@@ -166,6 +192,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
u32 size = 0; u32 size = 0;
switch (priv->version) { switch (priv->version) {
case BRCM_SATA_PHY_STB_16NM:
case BRCM_SATA_PHY_STB_28NM: case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_IPROC_NS2: case BRCM_SATA_PHY_IPROC_NS2:
case BRCM_SATA_PHY_DSL_28NM: case BRCM_SATA_PHY_DSL_28NM:
...@@ -287,6 +314,94 @@ static int brcm_stb_sata_init(struct brcm_sata_port *port) ...@@ -287,6 +314,94 @@ static int brcm_stb_sata_init(struct brcm_sata_port *port)
return brcm_stb_sata_rxaeq_init(port); return brcm_stb_sata_rxaeq_init(port);
} }
static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
{
void __iomem *base = brcm_sata_pcb_base(port);
u32 tmp, value;
/* Reduce CP tail current to 1/16th of its default value */
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0x141);
/* Turn off CP tail current boost */
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL8, 0, 0xc006);
/* Set a specific AEQ equalizer value */
tmp = AEQ_FRC_EQ_FORCE_VAL | AEQ_FRC_EQ_FORCE;
brcm_sata_phy_wr(base, AEQRX_REG_BANK_0, AEQ_FRC_EQ,
~(tmp | AEQ_RFZ_FRC_VAL |
AEQ_FRC_EQ_VAL_MASK << AEQ_FRC_EQ_VAL_SHIFT),
tmp | 32 << AEQ_FRC_EQ_VAL_SHIFT);
/* Set RX PPM val center frequency */
if (port->ssc_en)
value = 0x52;
else
value = 0;
brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CONTROL1,
~RXPMD_RX_PPM_VAL_MASK, value);
/* Set proportional loop bandwith Gen1/2/3 */
tmp = RXPMD_G_CDR_PROP_BW_MASK << RXPMD_G1_CDR_PROP_BW_SHIFT |
RXPMD_G_CDR_PROP_BW_MASK << RXPMD_G2_CDR_PROP_BW_SHIFT |
RXPMD_G_CDR_PROP_BW_MASK << RXPMD_G3_CDR_PROB_BW_SHIFT;
if (port->ssc_en)
value = 2 << RXPMD_G1_CDR_PROP_BW_SHIFT |
2 << RXPMD_G2_CDR_PROP_BW_SHIFT |
2 << RXPMD_G3_CDR_PROB_BW_SHIFT;
else
value = 1 << RXPMD_G1_CDR_PROP_BW_SHIFT |
1 << RXPMD_G2_CDR_PROP_BW_SHIFT |
1 << RXPMD_G3_CDR_PROB_BW_SHIFT;
brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_PROP_BW, ~tmp,
value);
/* Set CDR integral loop acquisition bandwidth for Gen1/2/3 */
tmp = RXPMD_G_CDR_ACQ_INT_BW_MASK << RXPMD_G1_CDR_ACQ_INT_BW_SHIFT |
RXPMD_G_CDR_ACQ_INT_BW_MASK << RXPMD_G2_CDR_ACQ_INT_BW_SHIFT |
RXPMD_G_CDR_ACQ_INT_BW_MASK << RXPMD_G3_CDR_ACQ_INT_BW_SHIFT;
if (port->ssc_en)
value = 1 << RXPMD_G1_CDR_ACQ_INT_BW_SHIFT |
1 << RXPMD_G2_CDR_ACQ_INT_BW_SHIFT |
1 << RXPMD_G3_CDR_ACQ_INT_BW_SHIFT;
else
value = 0;
brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_ACQ_INTEG_BW,
~tmp, value);
/* Set CDR integral loop locking bandwidth to 1 for Gen 1/2/3 */
tmp = RXPMD_G_CDR_LOCK_INT_BW_MASK << RXPMD_G1_CDR_LOCK_INT_BW_SHIFT |
RXPMD_G_CDR_LOCK_INT_BW_MASK << RXPMD_G2_CDR_LOCK_INT_BW_SHIFT |
RXPMD_G_CDR_LOCK_INT_BW_MASK << RXPMD_G3_CDR_LOCK_INT_BW_SHIFT;
if (port->ssc_en)
value = 1 << RXPMD_G1_CDR_LOCK_INT_BW_SHIFT |
1 << RXPMD_G2_CDR_LOCK_INT_BW_SHIFT |
1 << RXPMD_G3_CDR_LOCK_INT_BW_SHIFT;
else
value = 0;
brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_LOCK_INTEG_BW,
~tmp, value);
/* Set no guard band and clamp CDR */
tmp = RXPMD_MON_CORRECT_EN | RXPMD_MON_MARGIN_VAL_MASK;
if (port->ssc_en)
value = 0x51;
else
value = 0;
brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
~tmp, RXPMD_MON_CORRECT_EN | value);
/* Turn on/off SSC */
brcm_sata_phy_wr(base, TX_REG_BANK, TX_ACTRL5, ~TX_ACTRL5_SSC_EN,
port->ssc_en ? TX_ACTRL5_SSC_EN : 0);
return 0;
}
static int brcm_stb_sata_16nm_init(struct brcm_sata_port *port)
{
return brcm_stb_sata_16nm_ssc_init(port);
}
/* NS2 SATA PLL1 defaults were characterized by H/W group */ /* NS2 SATA PLL1 defaults were characterized by H/W group */
#define NS2_PLL1_ACTRL2_MAGIC 0x1df8 #define NS2_PLL1_ACTRL2_MAGIC 0x1df8
#define NS2_PLL1_ACTRL3_MAGIC 0x2b00 #define NS2_PLL1_ACTRL3_MAGIC 0x2b00
...@@ -544,6 +659,9 @@ static int brcm_sata_phy_init(struct phy *phy) ...@@ -544,6 +659,9 @@ static int brcm_sata_phy_init(struct phy *phy)
struct brcm_sata_port *port = phy_get_drvdata(phy); struct brcm_sata_port *port = phy_get_drvdata(phy);
switch (port->phy_priv->version) { switch (port->phy_priv->version) {
case BRCM_SATA_PHY_STB_16NM:
rc = brcm_stb_sata_16nm_init(port);
break;
case BRCM_SATA_PHY_STB_28NM: case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_STB_40NM: case BRCM_SATA_PHY_STB_40NM:
rc = brcm_stb_sata_init(port); rc = brcm_stb_sata_init(port);
...@@ -601,6 +719,8 @@ static const struct phy_ops phy_ops = { ...@@ -601,6 +719,8 @@ static const struct phy_ops phy_ops = {
}; };
static const struct of_device_id brcm_sata_phy_of_match[] = { static const struct of_device_id brcm_sata_phy_of_match[] = {
{ .compatible = "brcm,bcm7216-sata-phy",
.data = (void *)BRCM_SATA_PHY_STB_16NM },
{ .compatible = "brcm,bcm7445-sata-phy", { .compatible = "brcm,bcm7445-sata-phy",
.data = (void *)BRCM_SATA_PHY_STB_28NM }, .data = (void *)BRCM_SATA_PHY_STB_28NM },
{ .compatible = "brcm,bcm7425-sata-phy", { .compatible = "brcm,bcm7425-sata-phy",
......
This diff is collapsed.
This diff is collapsed.
...@@ -6,16 +6,50 @@ ...@@ -6,16 +6,50 @@
#ifndef _USB_BRCM_COMMON_INIT_H #ifndef _USB_BRCM_COMMON_INIT_H
#define _USB_BRCM_COMMON_INIT_H #define _USB_BRCM_COMMON_INIT_H
#include <linux/regmap.h>
#define USB_CTLR_MODE_HOST 0 #define USB_CTLR_MODE_HOST 0
#define USB_CTLR_MODE_DEVICE 1 #define USB_CTLR_MODE_DEVICE 1
#define USB_CTLR_MODE_DRD 2 #define USB_CTLR_MODE_DRD 2
#define USB_CTLR_MODE_TYPEC_PD 3 #define USB_CTLR_MODE_TYPEC_PD 3
enum brcmusb_reg_sel {
BRCM_REGS_CTRL = 0,
BRCM_REGS_XHCI_EC,
BRCM_REGS_XHCI_GBL,
BRCM_REGS_USB_PHY,
BRCM_REGS_USB_MDIO,
BRCM_REGS_BDC_EC,
BRCM_REGS_MAX
};
#define USB_CTRL_REG(base, reg) ((void __iomem *)base + USB_CTRL_##reg)
#define USB_XHCI_EC_REG(base, reg) ((void __iomem *)base + USB_XHCI_EC_##reg)
#define USB_CTRL_MASK(reg, field) \
USB_CTRL_##reg##_##field##_MASK
#define USB_CTRL_SET(base, reg, field) \
brcm_usb_ctrl_set(USB_CTRL_REG(base, reg), \
USB_CTRL_##reg##_##field##_MASK)
#define USB_CTRL_UNSET(base, reg, field) \
brcm_usb_ctrl_unset(USB_CTRL_REG(base, reg), \
USB_CTRL_##reg##_##field##_MASK)
struct brcm_usb_init_params; struct brcm_usb_init_params;
struct brcm_usb_init_ops {
void (*init_ipp)(struct brcm_usb_init_params *params);
void (*init_common)(struct brcm_usb_init_params *params);
void (*init_eohci)(struct brcm_usb_init_params *params);
void (*init_xhci)(struct brcm_usb_init_params *params);
void (*uninit_common)(struct brcm_usb_init_params *params);
void (*uninit_eohci)(struct brcm_usb_init_params *params);
void (*uninit_xhci)(struct brcm_usb_init_params *params);
int (*get_dual_select)(struct brcm_usb_init_params *params);
void (*set_dual_select)(struct brcm_usb_init_params *params, int mode);
};
struct brcm_usb_init_params { struct brcm_usb_init_params {
void __iomem *ctrl_regs; void __iomem *regs[BRCM_REGS_MAX];
void __iomem *xhci_ec_regs;
int ioc; int ioc;
int ipp; int ipp;
int mode; int mode;
...@@ -24,19 +58,105 @@ struct brcm_usb_init_params { ...@@ -24,19 +58,105 @@ struct brcm_usb_init_params {
int selected_family; int selected_family;
const char *family_name; const char *family_name;
const u32 *usb_reg_bits_map; const u32 *usb_reg_bits_map;
const struct brcm_usb_init_ops *ops;
struct regmap *syscon_piarbctl;
bool wake_enabled;
bool suspend_with_clocks;
};
void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params);
static inline u32 brcm_usb_readl(void __iomem *addr)
{
/*
* MIPS endianness is configured by boot strap, which also reverses all
* bus endianness (i.e., big-endian CPU + big endian bus ==> native
* endian I/O).
*
* Other architectures (e.g., ARM) either do not support big endian, or
* else leave I/O in little endian mode.
*/
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
return __raw_readl(addr);
else
return readl_relaxed(addr);
}
static inline void brcm_usb_writel(u32 val, void __iomem *addr)
{
/* See brcmnand_readl() comments */
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
__raw_writel(val, addr);
else
writel_relaxed(val, addr);
}
static inline void brcm_usb_ctrl_unset(void __iomem *reg, u32 mask)
{
brcm_usb_writel(brcm_usb_readl(reg) & ~(mask), reg);
};
static inline void brcm_usb_ctrl_set(void __iomem *reg, u32 mask)
{
brcm_usb_writel(brcm_usb_readl(reg) | (mask), reg);
}; };
void brcm_usb_set_family_map(struct brcm_usb_init_params *params); static inline void brcm_usb_init_ipp(struct brcm_usb_init_params *ini)
int brcm_usb_init_get_dual_select(struct brcm_usb_init_params *params); {
void brcm_usb_init_set_dual_select(struct brcm_usb_init_params *params, if (ini->ops->init_ipp)
int mode); ini->ops->init_ipp(ini);
}
void brcm_usb_init_ipp(struct brcm_usb_init_params *ini);
void brcm_usb_init_common(struct brcm_usb_init_params *ini); static inline void brcm_usb_init_common(struct brcm_usb_init_params *ini)
void brcm_usb_init_eohci(struct brcm_usb_init_params *ini); {
void brcm_usb_init_xhci(struct brcm_usb_init_params *ini); if (ini->ops->init_common)
void brcm_usb_uninit_common(struct brcm_usb_init_params *ini); ini->ops->init_common(ini);
void brcm_usb_uninit_eohci(struct brcm_usb_init_params *ini); }
void brcm_usb_uninit_xhci(struct brcm_usb_init_params *ini);
static inline void brcm_usb_init_eohci(struct brcm_usb_init_params *ini)
{
if (ini->ops->init_eohci)
ini->ops->init_eohci(ini);
}
static inline void brcm_usb_init_xhci(struct brcm_usb_init_params *ini)
{
if (ini->ops->init_xhci)
ini->ops->init_xhci(ini);
}
static inline void brcm_usb_uninit_common(struct brcm_usb_init_params *ini)
{
if (ini->ops->uninit_common)
ini->ops->uninit_common(ini);
}
static inline void brcm_usb_uninit_eohci(struct brcm_usb_init_params *ini)
{
if (ini->ops->uninit_eohci)
ini->ops->uninit_eohci(ini);
}
static inline void brcm_usb_uninit_xhci(struct brcm_usb_init_params *ini)
{
if (ini->ops->uninit_xhci)
ini->ops->uninit_xhci(ini);
}
static inline int brcm_usb_get_dual_select(struct brcm_usb_init_params *ini)
{
if (ini->ops->get_dual_select)
return ini->ops->get_dual_select(ini);
return 0;
}
static inline void brcm_usb_set_dual_select(struct brcm_usb_init_params *ini,
int mode)
{
if (ini->ops->set_dual_select)
ini->ops->set_dual_select(ini, mode);
}
#endif /* _USB_BRCM_COMMON_INIT_H */ #endif /* _USB_BRCM_COMMON_INIT_H */
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
#
# Phy drivers for Intel Lightning Mountain(LGM) platform
#
config PHY_INTEL_EMMC
tristate "Intel EMMC PHY driver"
select GENERIC_PHY
help
Enable this to support the Intel EMMC PHY
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_INTEL_EMMC) += phy-intel-emmc.o
// SPDX-License-Identifier: GPL-2.0
/*
* Intel eMMC PHY driver
* Copyright (C) 2019 Intel, Corp.
*/
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* eMMC phy register definitions */
#define EMMC_PHYCTRL0_REG 0xa8
#define DR_TY_MASK GENMASK(30, 28)
#define DR_TY_SHIFT(x) (((x) << 28) & DR_TY_MASK)
#define OTAPDLYENA BIT(14)
#define OTAPDLYSEL_MASK GENMASK(13, 10)
#define OTAPDLYSEL_SHIFT(x) (((x) << 10) & OTAPDLYSEL_MASK)
#define EMMC_PHYCTRL1_REG 0xac
#define PDB_MASK BIT(0)
#define PDB_SHIFT(x) (((x) << 0) & PDB_MASK)
#define ENDLL_MASK BIT(7)
#define ENDLL_SHIFT(x) (((x) << 7) & ENDLL_MASK)
#define EMMC_PHYCTRL2_REG 0xb0
#define FRQSEL_25M 0
#define FRQSEL_50M 1
#define FRQSEL_100M 2
#define FRQSEL_150M 3
#define FRQSEL_MASK GENMASK(24, 22)
#define FRQSEL_SHIFT(x) (((x) << 22) & FRQSEL_MASK)
#define EMMC_PHYSTAT_REG 0xbc
#define CALDONE_MASK BIT(9)
#define DLLRDY_MASK BIT(8)
#define IS_CALDONE(x) ((x) & CALDONE_MASK)
#define IS_DLLRDY(x) ((x) & DLLRDY_MASK)
struct intel_emmc_phy {
struct regmap *syscfg;
struct clk *emmcclk;
};
static int intel_emmc_phy_power(struct phy *phy, bool on_off)
{
struct intel_emmc_phy *priv = phy_get_drvdata(phy);
unsigned int caldone;
unsigned int dllrdy;
unsigned int freqsel;
unsigned long rate;
int ret, quot;
/*
* Keep phyctrl_pdb and phyctrl_endll low to allow
* initialization of CALIO state M/C DFFs
*/
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL1_REG, PDB_MASK,
PDB_SHIFT(0));
if (ret) {
dev_err(&phy->dev, "CALIO power down bar failed: %d\n", ret);
return ret;
}
/* Already finish power_off above */
if (!on_off)
return 0;
rate = clk_get_rate(priv->emmcclk);
quot = DIV_ROUND_CLOSEST(rate, 50000000);
if (quot > FRQSEL_150M)
dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
freqsel = clamp_t(int, quot, FRQSEL_25M, FRQSEL_150M);
/*
* According to the user manual, calpad calibration
* cycle takes more than 2us without the minimal recommended
* value, so we may need a little margin here
*/
udelay(5);
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL1_REG, PDB_MASK,
PDB_SHIFT(1));
if (ret) {
dev_err(&phy->dev, "CALIO power down bar failed: %d\n", ret);
return ret;
}
/*
* According to the user manual, it asks driver to wait 5us for
* calpad busy trimming. However it is documented that this value is
* PVT(A.K.A process,voltage and temperature) relevant, so some
* failure cases are found which indicates we should be more tolerant
* to calpad busy trimming.
*/
ret = regmap_read_poll_timeout(priv->syscfg, EMMC_PHYSTAT_REG,
caldone, IS_CALDONE(caldone),
0, 50);
if (ret) {
dev_err(&phy->dev, "caldone failed, ret=%d\n", ret);
return ret;
}
/* Set the frequency of the DLL operation */
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL2_REG, FRQSEL_MASK,
FRQSEL_SHIFT(freqsel));
if (ret) {
dev_err(&phy->dev, "set the frequency of dll failed:%d\n", ret);
return ret;
}
/* Turn on the DLL */
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL1_REG, ENDLL_MASK,
ENDLL_SHIFT(1));
if (ret) {
dev_err(&phy->dev, "turn on the dll failed: %d\n", ret);
return ret;
}
/*
* After enabling analog DLL circuits docs say that we need 10.2 us if
* our source clock is at 50 MHz and that lock time scales linearly
* with clock speed. If we are powering on the PHY and the card clock
* is super slow (like 100 kHZ) this could take as long as 5.1 ms as
* per the math: 10.2 us * (50000000 Hz / 100000 Hz) => 5.1 ms
* Hopefully we won't be running at 100 kHz, but we should still make
* sure we wait long enough.
*
* NOTE: There appear to be corner cases where the DLL seems to take
* extra long to lock for reasons that aren't understood. In some
* extreme cases we've seen it take up to over 10ms (!). We'll be
* generous and give it 50ms.
*/
ret = regmap_read_poll_timeout(priv->syscfg,
EMMC_PHYSTAT_REG,
dllrdy, IS_DLLRDY(dllrdy),
0, 50 * USEC_PER_MSEC);
if (ret) {
dev_err(&phy->dev, "dllrdy failed. ret=%d\n", ret);
return ret;
}
return 0;
}
static int intel_emmc_phy_init(struct phy *phy)
{
struct intel_emmc_phy *priv = phy_get_drvdata(phy);
/*
* We purposely get the clock here and not in probe to avoid the
* circular dependency problem. We expect:
* - PHY driver to probe
* - SDHCI driver to start probe
* - SDHCI driver to register it's clock
* - SDHCI driver to get the PHY
* - SDHCI driver to init the PHY
*
* The clock is optional, so upon any error just return it like
* any other error to user.
*
*/
priv->emmcclk = clk_get_optional(&phy->dev, "emmcclk");
if (IS_ERR(priv->emmcclk)) {
dev_err(&phy->dev, "ERROR: getting emmcclk\n");
return PTR_ERR(priv->emmcclk);
}
return 0;
}
static int intel_emmc_phy_exit(struct phy *phy)
{
struct intel_emmc_phy *priv = phy_get_drvdata(phy);
clk_put(priv->emmcclk);
return 0;
}
static int intel_emmc_phy_power_on(struct phy *phy)
{
struct intel_emmc_phy *priv = phy_get_drvdata(phy);
int ret;
/* Drive impedance: 50 Ohm */
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL0_REG, DR_TY_MASK,
DR_TY_SHIFT(6));
if (ret) {
dev_err(&phy->dev, "ERROR set drive-impednce-50ohm: %d\n", ret);
return ret;
}
/* Output tap delay: disable */
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL0_REG, OTAPDLYENA,
0);
if (ret) {
dev_err(&phy->dev, "ERROR Set output tap delay : %d\n", ret);
return ret;
}
/* Output tap delay */
ret = regmap_update_bits(priv->syscfg, EMMC_PHYCTRL0_REG,
OTAPDLYSEL_MASK, OTAPDLYSEL_SHIFT(4));
if (ret) {
dev_err(&phy->dev, "ERROR: output tap dly select: %d\n", ret);
return ret;
}
/* Power up eMMC phy analog blocks */
return intel_emmc_phy_power(phy, true);
}
static int intel_emmc_phy_power_off(struct phy *phy)
{
/* Power down eMMC phy analog blocks */
return intel_emmc_phy_power(phy, false);
}
static const struct phy_ops ops = {
.init = intel_emmc_phy_init,
.exit = intel_emmc_phy_exit,
.power_on = intel_emmc_phy_power_on,
.power_off = intel_emmc_phy_power_off,
.owner = THIS_MODULE,
};
static int intel_emmc_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct intel_emmc_phy *priv;
struct phy *generic_phy;
struct phy_provider *phy_provider;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* Get eMMC phy (accessed via chiptop) regmap */
priv->syscfg = syscon_regmap_lookup_by_phandle(np, "intel,syscon");
if (IS_ERR(priv->syscfg)) {
dev_err(dev, "failed to find syscon\n");
return PTR_ERR(priv->syscfg);
}
generic_phy = devm_phy_create(dev, np, &ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(generic_phy);
}
phy_set_drvdata(generic_phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id intel_emmc_phy_dt_ids[] = {
{ .compatible = "intel,lgm-emmc-phy" },
{}
};
MODULE_DEVICE_TABLE(of, intel_emmc_phy_dt_ids);
static struct platform_driver intel_emmc_driver = {
.probe = intel_emmc_phy_probe,
.driver = {
.name = "intel-emmc-phy",
.of_match_table = intel_emmc_phy_dt_ids,
},
};
module_platform_driver(intel_emmc_driver);
MODULE_AUTHOR("Peter Harliman Liem <peter.harliman.liem@intel.com>");
MODULE_DESCRIPTION("Intel eMMC PHY driver");
MODULE_LICENSE("GPL v2");
...@@ -386,7 +386,7 @@ static struct phy *ltq_vrx200_pcie_phy_xlate(struct device *dev, ...@@ -386,7 +386,7 @@ static struct phy *ltq_vrx200_pcie_phy_xlate(struct device *dev,
default: default:
dev_err(dev, "invalid PHY mode %u\n", mode); dev_err(dev, "invalid PHY mode %u\n", mode);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
}; }
return priv->phy; return priv->phy;
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
# #
config PHY_MTK_TPHY config PHY_MTK_TPHY
tristate "MediaTek T-PHY Driver" tristate "MediaTek T-PHY Driver"
depends on ARCH_MEDIATEK && OF
depends on ARCH_MEDIATEK || COMPILE_TEST depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF depends on OF
select GENERIC_PHY select GENERIC_PHY
......
...@@ -29,7 +29,7 @@ static void devm_phy_release(struct device *dev, void *res) ...@@ -29,7 +29,7 @@ static void devm_phy_release(struct device *dev, void *res)
{ {
struct phy *phy = *(struct phy **)res; struct phy *phy = *(struct phy **)res;
phy_put(phy); phy_put(dev, phy);
} }
static void devm_phy_provider_release(struct device *dev, void *res) static void devm_phy_provider_release(struct device *dev, void *res)
...@@ -566,12 +566,12 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id) ...@@ -566,12 +566,12 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id)
EXPORT_SYMBOL_GPL(of_phy_get); EXPORT_SYMBOL_GPL(of_phy_get);
/** /**
* phy_put() - release the PHY * of_phy_put() - release the PHY
* @phy: the phy returned by phy_get() * @phy: the phy returned by of_phy_get()
* *
* Releases a refcount the caller received from phy_get(). * Releases a refcount the caller received from of_phy_get().
*/ */
void phy_put(struct phy *phy) void of_phy_put(struct phy *phy)
{ {
if (!phy || IS_ERR(phy)) if (!phy || IS_ERR(phy))
return; return;
...@@ -584,6 +584,20 @@ void phy_put(struct phy *phy) ...@@ -584,6 +584,20 @@ void phy_put(struct phy *phy)
module_put(phy->ops->owner); module_put(phy->ops->owner);
put_device(&phy->dev); put_device(&phy->dev);
} }
EXPORT_SYMBOL_GPL(of_phy_put);
/**
* phy_put() - release the PHY
* @dev: device that wants to release this phy
* @phy: the phy returned by phy_get()
*
* Releases a refcount the caller received from phy_get().
*/
void phy_put(struct device *dev, struct phy *phy)
{
device_link_remove(dev, &phy->dev);
of_phy_put(phy);
}
EXPORT_SYMBOL_GPL(phy_put); EXPORT_SYMBOL_GPL(phy_put);
/** /**
...@@ -651,6 +665,7 @@ struct phy *phy_get(struct device *dev, const char *string) ...@@ -651,6 +665,7 @@ struct phy *phy_get(struct device *dev, const char *string)
{ {
int index = 0; int index = 0;
struct phy *phy; struct phy *phy;
struct device_link *link;
if (string == NULL) { if (string == NULL) {
dev_WARN(dev, "missing string\n"); dev_WARN(dev, "missing string\n");
...@@ -672,6 +687,13 @@ struct phy *phy_get(struct device *dev, const char *string) ...@@ -672,6 +687,13 @@ struct phy *phy_get(struct device *dev, const char *string)
get_device(&phy->dev); get_device(&phy->dev);
link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
if (!link) {
dev_err(dev, "failed to create device link to %s\n",
dev_name(phy->dev.parent));
return ERR_PTR(-EINVAL);
}
return phy; return phy;
} }
EXPORT_SYMBOL_GPL(phy_get); EXPORT_SYMBOL_GPL(phy_get);
...@@ -765,6 +787,7 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, ...@@ -765,6 +787,7 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
const char *con_id) const char *con_id)
{ {
struct phy **ptr, *phy; struct phy **ptr, *phy;
struct device_link *link;
ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr) if (!ptr)
...@@ -776,6 +799,14 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, ...@@ -776,6 +799,14 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
devres_add(dev, ptr); devres_add(dev, ptr);
} else { } else {
devres_free(ptr); devres_free(ptr);
return phy;
}
link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
if (!link) {
dev_err(dev, "failed to create device link to %s\n",
dev_name(phy->dev.parent));
return ERR_PTR(-EINVAL);
} }
return phy; return phy;
...@@ -798,6 +829,7 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, ...@@ -798,6 +829,7 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
int index) int index)
{ {
struct phy **ptr, *phy; struct phy **ptr, *phy;
struct device_link *link;
ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr) if (!ptr)
...@@ -819,6 +851,13 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, ...@@ -819,6 +851,13 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
*ptr = phy; *ptr = phy;
devres_add(dev, ptr); devres_add(dev, ptr);
link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
if (!link) {
dev_err(dev, "failed to create device link to %s\n",
dev_name(phy->dev.parent));
return ERR_PTR(-EINVAL);
}
return phy; return phy;
} }
EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index); EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
......
...@@ -166,8 +166,9 @@ static const unsigned int sdm845_ufsphy_regs_layout[] = { ...@@ -166,8 +166,9 @@ static const unsigned int sdm845_ufsphy_regs_layout[] = {
}; };
static const unsigned int sm8150_ufsphy_regs_layout[] = { static const unsigned int sm8150_ufsphy_regs_layout[] = {
[QPHY_START_CTRL] = 0x00, [QPHY_START_CTRL] = QPHY_V4_PHY_START,
[QPHY_PCS_READY_STATUS] = 0x180, [QPHY_PCS_READY_STATUS] = QPHY_V4_PCS_READY_STATUS,
[QPHY_SW_RESET] = QPHY_V4_SW_RESET,
}; };
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = { static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
...@@ -885,7 +886,6 @@ static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { ...@@ -885,7 +886,6 @@ static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = {
}; };
static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes_tbl[] = { static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_POWER_DOWN_CONTROL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11), QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00), QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00),
...@@ -1390,7 +1390,6 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { ...@@ -1390,7 +1390,6 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.pwrdn_ctrl = SW_PWRDN, .pwrdn_ctrl = SW_PWRDN,
.is_dual_lane_phy = true, .is_dual_lane_phy = true,
.no_pcs_sw_reset = true,
}; };
static void qcom_qmp_phy_configure(void __iomem *base, static void qcom_qmp_phy_configure(void __iomem *base,
......
// SPDX-License-Identifier: GPL-2.0 /* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2017, The Linux Foundation. All rights reserved. * Copyright (c) 2017, The Linux Foundation. All rights reserved.
*/ */
......
...@@ -39,6 +39,7 @@ config PHY_ROCKCHIP_INNO_DSIDPHY ...@@ -39,6 +39,7 @@ config PHY_ROCKCHIP_INNO_DSIDPHY
tristate "Rockchip Innosilicon MIPI/LVDS/TTL PHY driver" tristate "Rockchip Innosilicon MIPI/LVDS/TTL PHY driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
select GENERIC_PHY select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
help help
Enable this to support the Rockchip MIPI/LVDS/TTL PHY with Enable this to support the Rockchip MIPI/LVDS/TTL PHY with
Innosilicon IP block. Innosilicon IP block.
......
...@@ -33,6 +33,21 @@ config PHY_AM654_SERDES ...@@ -33,6 +33,21 @@ config PHY_AM654_SERDES
This option enables support for TI AM654 SerDes PHY used for This option enables support for TI AM654 SerDes PHY used for
PCIe. PCIe.
config PHY_J721E_WIZ
tristate "TI J721E WIZ (SERDES Wrapper) support"
depends on OF && ARCH_K3 || COMPILE_TEST
depends on COMMON_CLK
select GENERIC_PHY
select MULTIPLEXER
select REGMAP_MMIO
select MUX_MMIO
help
This option enables support for WIZ module present in TI's J721E
SoC. WIZ is a serdes wrapper used to configure some of the input
signals to the SERDES (Sierra/Torrent). This driver configures
three clock selects (pll0, pll1, dig) and resets for each of the
lanes.
config OMAP_CONTROL_PHY config OMAP_CONTROL_PHY
tristate "OMAP CONTROL PHY Driver" tristate "OMAP CONTROL PHY Driver"
depends on ARCH_OMAP2PLUS || COMPILE_TEST depends on ARCH_OMAP2PLUS || COMPILE_TEST
......
...@@ -8,3 +8,4 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o ...@@ -8,3 +8,4 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o
obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o
obj-$(CONFIG_PHY_J721E_WIZ) += phy-j721e-wiz.o
This diff is collapsed.
...@@ -850,6 +850,12 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -850,6 +850,12 @@ static int ti_pipe3_probe(struct platform_device *pdev)
static int ti_pipe3_remove(struct platform_device *pdev) static int ti_pipe3_remove(struct platform_device *pdev)
{ {
struct ti_pipe3 *phy = platform_get_drvdata(pdev);
if (phy->mode == PIPE3_MODE_SATA) {
clk_disable_unprepare(phy->refclk);
phy->sata_refclk_enabled = false;
}
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0; return 0;
...@@ -900,18 +906,8 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) ...@@ -900,18 +906,8 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
{ {
if (!IS_ERR(phy->wkupclk)) if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk); clk_disable_unprepare(phy->wkupclk);
if (!IS_ERR(phy->refclk)) { if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk);
/*
* SATA refclk needs an additional disable as we left it
* on in probe to avoid Errata i783
*/
if (phy->sata_refclk_enabled) {
clk_disable_unprepare(phy->refclk); clk_disable_unprepare(phy->refclk);
phy->sata_refclk_enabled = false;
}
}
if (!IS_ERR(phy->div_clk)) if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk); clk_disable_unprepare(phy->div_clk);
} }
......
...@@ -32,7 +32,7 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) ...@@ -32,7 +32,7 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev)
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
if (priv->phy) { if (priv->phy) {
phy_put(priv->phy); phy_put(&pdev->dev, priv->phy);
priv->phy = NULL; priv->phy = NULL;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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