phy-for-6.19
- Core
- Drop Kishon as maintainer, thanks to him for helping, move to credits and
add Neil to help with reviews.
- Add new phy_notify_stat to notify phy from controllers during the
runtime transitions and usage in samsung phy
- New Support
- Renesas RZ/G3E USB3.0 driver
- NXP Support TJA1048/TJA1051 CAN phy
- Rockchip support for rk3506 dsi dphy
- Qualcomm Glymur QMP PCIe PHY support
- Updates
- PM support for rcar-gen3-usb2 driver
- Samsung HDMI/eDP Transmitter Combo PHY updates
- Freescale imx8mq support for alternate reference clock
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmk2fUUACgkQfBQHDyUj
g0dBWA/9G7FZahHvVj40hS721fYJ8RYVWkRwaPaUg+DBd8rRgU0lE+rYXC60Y+Hp
lILhtwb9NvzjR9+i9fuVmrMWRdYCb7aLzwOjRSzxApnB1s3S7Nl7M33/xrtZ6n6K
KL978REzaJgQzRICZfjrky65OfUA942eqmgtTmMpfdnJCHI8QOzIwQApQt1Zubjt
Gu+R4D1iujarDM0J+J6UudixTdnYk5UnY+UqpsR/e6g9E5ERk5g7xC/NG49Q7oim
L2TXB755ZXAJdlMP6KQGFAS8bq44qvudrOaiy2PHVy1yxmhmcAeh1GmR51WJKOmM
lVypGbKgsce2eFWwCDe3fVtA2aJD9urdWtn5MAXQRdC8Cwz7Q7P8ne7Q9FXhHGr8
GgGSXd1iQho7zOwm3LGRJ4ItSb2dK3sypldjskD2lMXGrm53y7DMfwsDsK3ZzCrZ
YV3+klzeeQrA0jVTRD4CS2eZ62GdsGRx/8XrvKe4eMd4EBsgDTLG/894PQU/VOte
V/rSv6d4CW/UfRVychlEW9+4f9gqpgsfgdl39u/cVS5c/VPTV7XtMOd/9bFM+k1Q
qOVPLwBcz24hO8e+3jbYouiISbrvxGpLVK4PomyesOm/5AWNM+30vGFWjR5cXngi
DekaYa4nD2m1Dk0h+wD5gvgdfzhUuhNOnWggPRmUSywGirrnj+I=
=mvDM
-----END PGP SIGNATURE-----
Merge tag 'phy-for-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
Pull phy updates from Vinod Koul:
"Core:
- Drop Kishon as maintainer, thanks to him for helping, move to
credits and add Neil to help with reviews.
- Add new phy_notify_stat to notify phy from controllers during the
runtime transitions and usage in samsung phy
New hardware support:
- Renesas RZ/G3E USB3.0 driver
- NXP Support TJA1048/TJA1051 CAN phy
- Rockchip support for rk3506 dsi dphy
- Qualcomm Glymur QMP PCIe PHY support
Updates:
- PM support for rcar-gen3-usb2 driver
- Samsung HDMI/eDP Transmitter Combo PHY updates
- Freescale imx8mq support for alternate reference clock"
* tag 'phy-for-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (40 commits)
MAINTAINERS: phy: Add Neil Armstrong as reviewers for phy subsystem
MAINTAINERS: phy: Move Kishon Vijay Abraham I to credits
phy: fsl-imx8mq-usb: support alternate reference clock
dt-bindings: phy: imx8mq-usb: add alternate reference clock
phy: rockchip: samsung-hdptx: Prevent Inter-Pair Skew from exceeding the limits
phy: rockchip: samsung-hdptx: Reduce ROPLL loop bandwidth
phy: rockchip: samsung-hdptx: Fix reported clock rate in high bpc mode
phy: ti: gmii-sel: Add a sanity check on the phy_id
phy: qcom: qmp-pcie: Add support for Glymur PCIe Gen5x4 PHY
phy: qcom-qmp: pcs: Add v8.50 register offsets
dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the Glymur QMP PCIe PHY
dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Restrict resets per each device
phy: freescale: Initialize priv->lock
phy: renesas: Remove unneeded semicolons
phy: qcom: m31-eusb2: Update init sequence to set PHY_ENABLE
phy: qcom: qmp-combo: get the USB3 & DisplayPort lanes mapping from DT
dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: Document lanes mapping when not using in USB-C complex
phy: rockchip: naneng-combphy: Fix PCIe L1ss support RK3562
phy: rockchip: naneng-combphy: Fix PCIe L1ss support RK3528
phy: renesas: rcar-gen3-usb2: Add suspend/resume support
...
master
commit
0623fdf30b
4
CREDITS
4
CREDITS
|
|
@ -16,6 +16,10 @@ D: One of assisting postmasters for vger.kernel.org's lists
|
|||
S: (ask for current address)
|
||||
S: Finland
|
||||
|
||||
N: Kishon Vijay Abraham I
|
||||
E: kishon@kernel.org
|
||||
D: Generic Phy Framework
|
||||
|
||||
N: Thomas Abraham
|
||||
E: thomas.ab@samsung.com
|
||||
D: Samsung pin controller driver
|
||||
|
|
|
|||
|
|
@ -27,11 +27,16 @@ properties:
|
|||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
items:
|
||||
- description: PHY configuration clock
|
||||
- description: Alternate PHY reference clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: phy
|
||||
- const: alt
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ properties:
|
|||
- mediatek,mt2712-tphy
|
||||
- mediatek,mt6893-tphy
|
||||
- mediatek,mt7629-tphy
|
||||
- mediatek,mt7981-tphy
|
||||
- mediatek,mt7986-tphy
|
||||
- mediatek,mt8183-tphy
|
||||
- mediatek,mt8186-tphy
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,glymur-qmp-gen5x4-pcie-phy
|
||||
- qcom,qcs615-qmp-gen3x1-pcie-phy
|
||||
- qcom,qcs8300-qmp-gen4x2-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x2-pcie-phy
|
||||
|
|
@ -178,6 +179,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,glymur-qmp-gen5x4-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x2-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x4-pcie-phy
|
||||
- qcom,sc8280xp-qmp-gen3x1-pcie-phy
|
||||
|
|
@ -213,17 +215,26 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,glymur-qmp-gen5x4-pcie-phy
|
||||
- qcom,sm8550-qmp-gen4x2-pcie-phy
|
||||
- qcom,sm8650-qmp-gen4x2-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen3x2-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x2-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x4-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x8-pcie-phy
|
||||
- qcom,x1p42100-qmp-gen4x4-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 2
|
||||
reset-names:
|
||||
minItems: 2
|
||||
else:
|
||||
properties:
|
||||
resets:
|
||||
maxItems: 1
|
||||
reset-names:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
|
|
|||
|
|
@ -78,10 +78,77 @@ properties:
|
|||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
description: Output endpoint of the PHY
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/graph.yaml#/$defs/endpoint-base
|
||||
unevaluatedProperties: false
|
||||
|
||||
endpoint@0:
|
||||
$ref: /schemas/graph.yaml#/$defs/endpoint-base
|
||||
description: Display Port Output lanes of the PHY when used with static mapping,
|
||||
The entry index is the DP lanes index, and the number is the PHY
|
||||
signal in the order RX0, TX0, TX1, RX1.
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
# Static lane mappings are mutually exclusive with typec-mux/orientation-mux
|
||||
data-lanes:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
oneOf:
|
||||
- items: # DisplayPort 1 lane, normal orientation
|
||||
- const: 3
|
||||
- items: # DisplayPort 1 lane, flipped orientation
|
||||
- const: 0
|
||||
- items: # DisplayPort 2 lanes, normal orientation
|
||||
- const: 3
|
||||
- const: 2
|
||||
- items: # DisplayPort 2 lanes, flipped orientation
|
||||
- const: 0
|
||||
- const: 1
|
||||
- items: # DisplayPort 4 lanes, normal orientation
|
||||
- const: 3
|
||||
- const: 2
|
||||
- const: 1
|
||||
- const: 0
|
||||
- items: # DisplayPort 4 lanes, flipped orientation
|
||||
- const: 0
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
endpoint@1:
|
||||
$ref: /schemas/graph.yaml#/$defs/endpoint-base
|
||||
description: USB Output lanes of the PHY when used with static mapping.
|
||||
The entry index is the USB3 lane in the order TX then RX, and the
|
||||
number is the PHY signal in the order RX0, TX0, TX1, RX1.
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
# Static lane mappings are mutually exclusive with typec-mux/orientation-mux
|
||||
data-lanes:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
oneOf:
|
||||
- items: # USB3, normal orientation
|
||||
- const: 1
|
||||
- const: 0
|
||||
- items: # USB3, flipped orientation
|
||||
- const: 2
|
||||
- const: 3
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/renesas,rzg3e-usb3-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/G3E USB 3.0 PHY
|
||||
|
||||
maintainers:
|
||||
- Biju Das <biju.das.jz@bp.renesas.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,r9a09g047-usb3-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: APB bus clock
|
||||
- description: USB 2.0 PHY reference clock
|
||||
- description: USB 3.0 PHY reference clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
- const: core
|
||||
- const: ref_alt_clk_p
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- '#phy-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/renesas,r9a09g047-cpg.h>
|
||||
|
||||
usb-phy@15870000 {
|
||||
compatible = "renesas,r9a09g047-usb3-phy";
|
||||
reg = <0x15870000 0x10000>;
|
||||
clocks = <&cpg CPG_MOD 0xb0>, <&cpg CPG_CORE 13>, <&cpg CPG_CORE 12>;
|
||||
clock-names = "pclk", "core", "ref_alt_clk_p";
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg 0xaa>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
|
@ -118,6 +118,7 @@ allOf:
|
|||
contains:
|
||||
enum:
|
||||
- renesas,usb2-phy-r9a09g057
|
||||
- renesas,usb2-phy-r9a08g045
|
||||
- renesas,rzg2l-usb2-phy
|
||||
then:
|
||||
properties:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ properties:
|
|||
- rockchip,px30-dsi-dphy
|
||||
- rockchip,rk3128-dsi-dphy
|
||||
- rockchip,rk3368-dsi-dphy
|
||||
- rockchip,rk3506-dsi-dphy
|
||||
- rockchip,rk3568-dsi-dphy
|
||||
- rockchip,rv1126-dsi-dphy
|
||||
|
||||
|
|
|
|||
|
|
@ -23,15 +23,25 @@ properties:
|
|||
- enum:
|
||||
- ti,tcan1042
|
||||
- ti,tcan1043
|
||||
- nxp,tja1048
|
||||
- nxp,tja1051
|
||||
- nxp,tja1057
|
||||
- nxp,tjr1443
|
||||
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
enum: [0, 1]
|
||||
|
||||
silent-gpios:
|
||||
description:
|
||||
gpio node to toggle silent signal on transceiver
|
||||
maxItems: 1
|
||||
|
||||
standby-gpios:
|
||||
description:
|
||||
gpio node to toggle standby signal on transceiver
|
||||
maxItems: 1
|
||||
gpio node to toggle standby signal on transceiver. For two Items, item 1
|
||||
is for stbn1, item 2 is for stbn2.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
enable-gpios:
|
||||
description:
|
||||
|
|
@ -54,6 +64,59 @@ required:
|
|||
- compatible
|
||||
- '#phy-cells'
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,tjr1443
|
||||
- ti,tcan1042
|
||||
- ti,tcan1043
|
||||
then:
|
||||
properties:
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
silent-gpios: false
|
||||
standby-gpios:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: nxp,tja1048
|
||||
then:
|
||||
properties:
|
||||
'#phy-cells':
|
||||
const: 1
|
||||
enable-gpios: false
|
||||
silent-gpios: false
|
||||
standby-gpios:
|
||||
minItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: nxp,tja1051
|
||||
then:
|
||||
properties:
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
standby-gpios: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: nxp,tja1057
|
||||
then:
|
||||
properties:
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
enable-gpios: false
|
||||
standby-gpios: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -10547,7 +10547,7 @@ F: include/uapi/asm-generic/
|
|||
|
||||
GENERIC PHY FRAMEWORK
|
||||
M: Vinod Koul <vkoul@kernel.org>
|
||||
M: Kishon Vijay Abraham I <kishon@kernel.org>
|
||||
R: Neil Armstrong <neil.armstrong@linaro.org>
|
||||
L: linux-phy@lists.infradead.org
|
||||
S: Supported
|
||||
Q: https://patchwork.kernel.org/project/linux-phy/list/
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ static struct phy *bcm63xx_usbh_phy_xlate(struct device *dev,
|
|||
return of_phy_simple_xlate(dev, args);
|
||||
}
|
||||
|
||||
static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev)
|
||||
static int bcm63xx_usbh_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm63xx_usbh_phy *usbh;
|
||||
|
|
@ -432,7 +432,7 @@ static int __init bcm63xx_usbh_phy_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = {
|
||||
static const struct of_device_id bcm63xx_usbh_phy_ids[] = {
|
||||
{ .compatible = "brcm,bcm6318-usbh-phy", .data = &usbh_bcm6318 },
|
||||
{ .compatible = "brcm,bcm6328-usbh-phy", .data = &usbh_bcm6328 },
|
||||
{ .compatible = "brcm,bcm6358-usbh-phy", .data = &usbh_bcm6358 },
|
||||
|
|
@ -443,7 +443,7 @@ static const struct of_device_id bcm63xx_usbh_phy_ids[] __initconst = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm63xx_usbh_phy_ids);
|
||||
|
||||
static struct platform_driver bcm63xx_usbh_phy_driver __refdata = {
|
||||
static struct platform_driver bcm63xx_usbh_phy_driver = {
|
||||
.driver = {
|
||||
.name = "bcm63xx-usbh-phy",
|
||||
.of_match_table = bcm63xx_usbh_phy_ids,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#define PHY_CTRL0_REF_SSP_EN BIT(2)
|
||||
#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
|
||||
#define PHY_CTRL0_FSEL_24M 0x2a
|
||||
#define PHY_CTRL0_FSEL_100M 0x27
|
||||
|
||||
#define PHY_CTRL1 0x4
|
||||
#define PHY_CTRL1_RESET BIT(0)
|
||||
|
|
@ -108,6 +109,7 @@ struct tca_blk {
|
|||
struct imx8mq_usb_phy {
|
||||
struct phy *phy;
|
||||
struct clk *clk;
|
||||
struct clk *alt_clk;
|
||||
void __iomem *base;
|
||||
struct regulator *vbus;
|
||||
struct tca_blk *tca;
|
||||
|
|
@ -582,7 +584,8 @@ static int imx8mp_usb_phy_init(struct phy *phy)
|
|||
/* USB3.0 PHY signal fsel for 24M ref */
|
||||
value = readl(imx_phy->base + PHY_CTRL0);
|
||||
value &= ~PHY_CTRL0_FSEL_MASK;
|
||||
value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M);
|
||||
value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, imx_phy->alt_clk ?
|
||||
PHY_CTRL0_FSEL_100M : PHY_CTRL0_FSEL_24M);
|
||||
writel(value, imx_phy->base + PHY_CTRL0);
|
||||
|
||||
/* Disable alt_clk_en and use internal MPLL clocks */
|
||||
|
|
@ -626,13 +629,24 @@ static int imx8mq_phy_power_on(struct phy *phy)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return clk_prepare_enable(imx_phy->clk);
|
||||
ret = clk_prepare_enable(imx_phy->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(imx_phy->alt_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(imx_phy->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8mq_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
|
||||
|
||||
clk_disable_unprepare(imx_phy->alt_clk);
|
||||
clk_disable_unprepare(imx_phy->clk);
|
||||
regulator_disable(imx_phy->vbus);
|
||||
|
||||
|
|
@ -681,6 +695,11 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(imx_phy->clk);
|
||||
}
|
||||
|
||||
imx_phy->alt_clk = devm_clk_get_optional(dev, "alt");
|
||||
if (IS_ERR(imx_phy->alt_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(imx_phy->alt_clk),
|
||||
"Failed to get alt clk\n");
|
||||
|
||||
imx_phy->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(imx_phy->base))
|
||||
return PTR_ERR(imx_phy->base);
|
||||
|
|
|
|||
|
|
@ -533,7 +533,7 @@ static struct phy *imx_hsio_xlate(struct device *dev,
|
|||
|
||||
static int imx_hsio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
int i, ret;
|
||||
void __iomem *off;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
|
@ -545,6 +545,9 @@ static int imx_hsio_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
priv->dev = &pdev->dev;
|
||||
priv->drvdata = of_device_get_match_data(dev);
|
||||
ret = devm_mutex_init(dev, &priv->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get HSIO configuration mode */
|
||||
if (of_property_read_string(np, "fsl,hsio-cfg", &priv->hsio_cfg))
|
||||
|
|
|
|||
|
|
@ -17,31 +17,40 @@ struct can_transceiver_data {
|
|||
u32 flags;
|
||||
#define CAN_TRANSCEIVER_STB_PRESENT BIT(0)
|
||||
#define CAN_TRANSCEIVER_EN_PRESENT BIT(1)
|
||||
#define CAN_TRANSCEIVER_DUAL_CH BIT(2)
|
||||
#define CAN_TRANSCEIVER_SILENT_PRESENT BIT(3)
|
||||
};
|
||||
|
||||
struct can_transceiver_phy {
|
||||
struct phy *generic_phy;
|
||||
struct gpio_desc *silent_gpio;
|
||||
struct gpio_desc *standby_gpio;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct can_transceiver_priv *priv;
|
||||
};
|
||||
|
||||
struct can_transceiver_priv {
|
||||
struct mux_state *mux_state;
|
||||
int num_ch;
|
||||
struct can_transceiver_phy can_transceiver_phy[] __counted_by(num_ch);
|
||||
};
|
||||
|
||||
/* Power on function */
|
||||
static int can_transceiver_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy);
|
||||
struct can_transceiver_priv *priv = can_transceiver_phy->priv;
|
||||
int ret;
|
||||
|
||||
if (can_transceiver_phy->mux_state) {
|
||||
ret = mux_state_select(can_transceiver_phy->mux_state);
|
||||
if (priv->mux_state) {
|
||||
ret = mux_state_select(priv->mux_state);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "Failed to select CAN mux: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (can_transceiver_phy->standby_gpio)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->silent_gpio, 0);
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0);
|
||||
if (can_transceiver_phy->enable_gpio)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1);
|
||||
|
||||
return 0;
|
||||
|
|
@ -51,13 +60,13 @@ static int can_transceiver_phy_power_on(struct phy *phy)
|
|||
static int can_transceiver_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy);
|
||||
struct can_transceiver_priv *priv = can_transceiver_phy->priv;
|
||||
|
||||
if (can_transceiver_phy->standby_gpio)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->silent_gpio, 1);
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1);
|
||||
if (can_transceiver_phy->enable_gpio)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0);
|
||||
if (can_transceiver_phy->mux_state)
|
||||
mux_state_deselect(can_transceiver_phy->mux_state);
|
||||
if (priv->mux_state)
|
||||
mux_state_deselect(priv->mux_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -76,6 +85,18 @@ static const struct can_transceiver_data tcan1043_drvdata = {
|
|||
.flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_EN_PRESENT,
|
||||
};
|
||||
|
||||
static const struct can_transceiver_data tja1048_drvdata = {
|
||||
.flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_DUAL_CH,
|
||||
};
|
||||
|
||||
static const struct can_transceiver_data tja1051_drvdata = {
|
||||
.flags = CAN_TRANSCEIVER_SILENT_PRESENT | CAN_TRANSCEIVER_EN_PRESENT,
|
||||
};
|
||||
|
||||
static const struct can_transceiver_data tja1057_drvdata = {
|
||||
.flags = CAN_TRANSCEIVER_SILENT_PRESENT,
|
||||
};
|
||||
|
||||
static const struct of_device_id can_transceiver_phy_ids[] = {
|
||||
{
|
||||
.compatible = "ti,tcan1042",
|
||||
|
|
@ -85,6 +106,18 @@ static const struct of_device_id can_transceiver_phy_ids[] = {
|
|||
.compatible = "ti,tcan1043",
|
||||
.data = &tcan1043_drvdata
|
||||
},
|
||||
{
|
||||
.compatible = "nxp,tja1048",
|
||||
.data = &tja1048_drvdata
|
||||
},
|
||||
{
|
||||
.compatible = "nxp,tja1051",
|
||||
.data = &tja1051_drvdata
|
||||
},
|
||||
{
|
||||
.compatible = "nxp,tja1057",
|
||||
.data = &tja1057_drvdata
|
||||
},
|
||||
{
|
||||
.compatible = "nxp,tjr1443",
|
||||
.data = &tcan1043_drvdata
|
||||
|
|
@ -103,64 +136,107 @@ devm_mux_state_get_optional(struct device *dev, const char *mux_name)
|
|||
return devm_mux_state_get(dev, mux_name);
|
||||
}
|
||||
|
||||
static struct phy *can_transceiver_phy_xlate(struct device *dev,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
struct can_transceiver_priv *priv = dev_get_drvdata(dev);
|
||||
u32 idx;
|
||||
|
||||
if (priv->num_ch == 1)
|
||||
return priv->can_transceiver_phy[0].generic_phy;
|
||||
|
||||
if (args->args_count != 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
idx = args->args[0];
|
||||
if (idx >= priv->num_ch)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return priv->can_transceiver_phy[idx].generic_phy;
|
||||
}
|
||||
|
||||
static int can_transceiver_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct can_transceiver_phy *can_transceiver_phy;
|
||||
struct can_transceiver_priv *priv;
|
||||
const struct can_transceiver_data *drvdata;
|
||||
const struct of_device_id *match;
|
||||
struct phy *phy;
|
||||
struct gpio_desc *silent_gpio;
|
||||
struct gpio_desc *standby_gpio;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct mux_state *mux_state;
|
||||
u32 max_bitrate = 0;
|
||||
int err;
|
||||
|
||||
can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL);
|
||||
if (!can_transceiver_phy)
|
||||
return -ENOMEM;
|
||||
int err, i, num_ch = 1;
|
||||
|
||||
match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
|
||||
drvdata = match->data;
|
||||
if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
|
||||
num_ch = 2;
|
||||
|
||||
priv = devm_kzalloc(dev, struct_size(priv, can_transceiver_phy, num_ch), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->num_ch = num_ch;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
mux_state = devm_mux_state_get_optional(dev, NULL);
|
||||
if (IS_ERR(mux_state))
|
||||
return PTR_ERR(mux_state);
|
||||
|
||||
can_transceiver_phy->mux_state = mux_state;
|
||||
priv->mux_state = mux_state;
|
||||
|
||||
phy = devm_phy_create(dev, dev->of_node,
|
||||
&can_transceiver_phy_ops);
|
||||
err = device_property_read_u32(dev, "max-bitrate", &max_bitrate);
|
||||
if ((err != -EINVAL) && !max_bitrate)
|
||||
dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n");
|
||||
|
||||
for (i = 0; i < num_ch; i++) {
|
||||
can_transceiver_phy = &priv->can_transceiver_phy[i];
|
||||
can_transceiver_phy->priv = priv;
|
||||
|
||||
phy = devm_phy_create(dev, dev->of_node, &can_transceiver_phy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "failed to create can transceiver phy\n");
|
||||
return PTR_ERR(phy);
|
||||
}
|
||||
|
||||
err = device_property_read_u32(dev, "max-bitrate", &max_bitrate);
|
||||
if ((err != -EINVAL) && !max_bitrate)
|
||||
dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n");
|
||||
phy->attrs.max_link_rate = max_bitrate;
|
||||
|
||||
can_transceiver_phy->generic_phy = phy;
|
||||
can_transceiver_phy->priv = priv;
|
||||
|
||||
if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) {
|
||||
standby_gpio = devm_gpiod_get_optional(dev, "standby", GPIOD_OUT_HIGH);
|
||||
standby_gpio = devm_gpiod_get_index_optional(dev, "standby", i,
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(standby_gpio))
|
||||
return PTR_ERR(standby_gpio);
|
||||
can_transceiver_phy->standby_gpio = standby_gpio;
|
||||
}
|
||||
|
||||
if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) {
|
||||
enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
|
||||
enable_gpio = devm_gpiod_get_index_optional(dev, "enable", i,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(enable_gpio))
|
||||
return PTR_ERR(enable_gpio);
|
||||
can_transceiver_phy->enable_gpio = enable_gpio;
|
||||
}
|
||||
|
||||
if (drvdata->flags & CAN_TRANSCEIVER_SILENT_PRESENT) {
|
||||
silent_gpio = devm_gpiod_get_index_optional(dev, "silent", i,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(silent_gpio))
|
||||
return PTR_ERR(silent_gpio);
|
||||
can_transceiver_phy->silent_gpio = silent_gpio;
|
||||
}
|
||||
|
||||
phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
}
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, can_transceiver_phy_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -520,6 +520,31 @@ int phy_notify_disconnect(struct phy *phy, int port)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(phy_notify_disconnect);
|
||||
|
||||
/**
|
||||
* phy_notify_state() - phy state notification
|
||||
* @phy: the PHY returned by phy_get()
|
||||
* @state: the PHY state
|
||||
*
|
||||
* Notify the PHY of a state transition. Used to notify and
|
||||
* configure the PHY accordingly.
|
||||
*
|
||||
* Returns: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_notify_state(struct phy *phy, union phy_notify state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!phy || !phy->ops->notify_phystate)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
ret = phy->ops->notify_phystate(phy, state);
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_notify_state);
|
||||
|
||||
/**
|
||||
* phy_configure() - Changes the phy parameters
|
||||
* @phy: the phy returned by phy_get()
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#define POR BIT(1)
|
||||
|
||||
#define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
|
||||
#define PHY_ENABLE BIT(0)
|
||||
#define SIDDQ_SEL BIT(1)
|
||||
#define SIDDQ BIT(2)
|
||||
#define FSEL GENMASK(6, 4)
|
||||
|
|
@ -81,6 +82,7 @@ struct m31_eusb2_priv_data {
|
|||
static const struct m31_phy_tbl_entry m31_eusb2_setup_tbl[] = {
|
||||
M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG0, UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 1),
|
||||
M31_EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL5, POR, 1),
|
||||
M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL_COMMON0, PHY_ENABLE, 1),
|
||||
M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG1, PLL_EN, 1),
|
||||
M31_EUSB_PHY_INIT_CFG(USB_PHY_FSEL_SEL, FSEL_SEL, 1),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
@ -1643,14 +1644,9 @@ static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_usb_tbl[] = {
|
|||
};
|
||||
|
||||
/* list of regulators */
|
||||
struct qmp_regulator_data {
|
||||
const char *name;
|
||||
unsigned int enable_load;
|
||||
};
|
||||
|
||||
static struct qmp_regulator_data qmp_phy_vreg_l[] = {
|
||||
{ .name = "vdda-phy", .enable_load = 21800 },
|
||||
{ .name = "vdda-pll", .enable_load = 36000 },
|
||||
static struct regulator_bulk_data qmp_phy_vreg_l[] = {
|
||||
{ .supply = "vdda-phy", .init_load_uA = 21800, },
|
||||
{ .supply = "vdda-pll", .init_load_uA = 36000, },
|
||||
};
|
||||
|
||||
static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = {
|
||||
|
|
@ -1744,6 +1740,26 @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = {
|
|||
{ 0x22, 0xff, 0xff, 0xff }
|
||||
};
|
||||
|
||||
struct qmp_combo_lane_mapping {
|
||||
unsigned int lanes_count;
|
||||
enum typec_orientation orientation;
|
||||
u32 lanes[4];
|
||||
};
|
||||
|
||||
static const struct qmp_combo_lane_mapping usb3_data_lanes[] = {
|
||||
{ 2, TYPEC_ORIENTATION_NORMAL, { 1, 0 }},
|
||||
{ 2, TYPEC_ORIENTATION_REVERSE, { 2, 3 }},
|
||||
};
|
||||
|
||||
static const struct qmp_combo_lane_mapping dp_data_lanes[] = {
|
||||
{ 1, TYPEC_ORIENTATION_NORMAL, { 3 }},
|
||||
{ 1, TYPEC_ORIENTATION_REVERSE, { 0 }},
|
||||
{ 2, TYPEC_ORIENTATION_NORMAL, { 3, 2 }},
|
||||
{ 2, TYPEC_ORIENTATION_REVERSE, { 0, 1 }},
|
||||
{ 4, TYPEC_ORIENTATION_NORMAL, { 3, 2, 1, 0 }},
|
||||
{ 4, TYPEC_ORIENTATION_REVERSE, { 0, 1, 2, 3 }},
|
||||
};
|
||||
|
||||
struct qmp_combo;
|
||||
|
||||
struct qmp_combo_offsets {
|
||||
|
|
@ -1808,7 +1824,7 @@ struct qmp_phy_cfg {
|
|||
const char * const *reset_list;
|
||||
int num_resets;
|
||||
/* regulators to be requested */
|
||||
const struct qmp_regulator_data *vreg_list;
|
||||
const struct regulator_bulk_data *vreg_list;
|
||||
int num_vregs;
|
||||
|
||||
/* array of registers with different offsets */
|
||||
|
|
@ -3439,39 +3455,6 @@ static const struct dev_pm_ops qmp_combo_pm_ops = {
|
|||
qmp_combo_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static int qmp_combo_vreg_init(struct qmp_combo *qmp)
|
||||
{
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
struct device *dev = qmp->dev;
|
||||
int num = cfg->num_vregs;
|
||||
int ret, i;
|
||||
|
||||
qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
|
||||
if (!qmp->vregs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
qmp->vregs[i].supply = cfg->vreg_list[i].name;
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, num, qmp->vregs);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed at devm_regulator_bulk_get\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = regulator_set_load(qmp->vregs[i].consumer,
|
||||
cfg->vreg_list[i].enable_load);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to set load at %s\n",
|
||||
qmp->vregs[i].supply);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qmp_combo_reset_init(struct qmp_combo *qmp)
|
||||
{
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
|
|
@ -4117,6 +4100,84 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phand
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static void qmp_combo_find_lanes_orientation(const struct qmp_combo_lane_mapping *mapping,
|
||||
unsigned int mapping_count,
|
||||
u32 *lanes, unsigned int lanes_count,
|
||||
enum typec_orientation *orientation)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mapping_count; i++) {
|
||||
if (mapping[i].lanes_count != lanes_count)
|
||||
continue;
|
||||
if (!memcmp(mapping[i].lanes, lanes, sizeof(u32) * lanes_count)) {
|
||||
*orientation = mapping[i].orientation;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int qmp_combo_get_dt_lanes_mapping(struct device *dev, unsigned int endpoint,
|
||||
u32 *data_lanes, unsigned int max,
|
||||
unsigned int *count)
|
||||
{
|
||||
struct device_node *ep __free(device_node) = NULL;
|
||||
int ret;
|
||||
|
||||
ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, endpoint);
|
||||
if (!ep)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_property_count_u32_elems(ep, "data-lanes");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*count = ret;
|
||||
if (*count > max)
|
||||
return -EINVAL;
|
||||
|
||||
return of_property_read_u32_array(ep, "data-lanes", data_lanes,
|
||||
min_t(unsigned int, *count, max));
|
||||
}
|
||||
|
||||
static int qmp_combo_get_dt_dp_orientation(struct device *dev,
|
||||
enum typec_orientation *orientation)
|
||||
{
|
||||
unsigned int count;
|
||||
u32 data_lanes[4];
|
||||
int ret;
|
||||
|
||||
/* DP is described on the first endpoint of the first port */
|
||||
ret = qmp_combo_get_dt_lanes_mapping(dev, 0, data_lanes, 4, &count);
|
||||
if (ret < 0)
|
||||
return ret == -EINVAL ? 0 : ret;
|
||||
|
||||
/* Search for a match and only update orientation if found */
|
||||
qmp_combo_find_lanes_orientation(dp_data_lanes, ARRAY_SIZE(dp_data_lanes),
|
||||
data_lanes, count, orientation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qmp_combo_get_dt_usb3_orientation(struct device *dev,
|
||||
enum typec_orientation *orientation)
|
||||
{
|
||||
unsigned int count;
|
||||
u32 data_lanes[2];
|
||||
int ret;
|
||||
|
||||
/* USB3 is described on the second endpoint of the first port */
|
||||
ret = qmp_combo_get_dt_lanes_mapping(dev, 1, data_lanes, 2, &count);
|
||||
if (ret < 0)
|
||||
return ret == -EINVAL ? 0 : ret;
|
||||
|
||||
/* Search for a match and only update orientation if found */
|
||||
qmp_combo_find_lanes_orientation(usb3_data_lanes, ARRAY_SIZE(usb3_data_lanes),
|
||||
data_lanes, count, orientation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qmp_combo_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct qmp_combo *qmp;
|
||||
|
|
@ -4144,7 +4205,8 @@ static int qmp_combo_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = qmp_combo_vreg_init(qmp);
|
||||
ret = devm_regulator_bulk_get_const(dev, qmp->cfg->num_vregs,
|
||||
qmp->cfg->vreg_list, &qmp->vregs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -4167,9 +4229,41 @@ static int qmp_combo_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_node_put;
|
||||
|
||||
qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
|
||||
|
||||
if (of_property_present(dev->of_node, "mode-switch") ||
|
||||
of_property_present(dev->of_node, "orientation-switch")) {
|
||||
ret = qmp_combo_typec_register(qmp);
|
||||
if (ret)
|
||||
goto err_node_put;
|
||||
} else {
|
||||
enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE;
|
||||
enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE;
|
||||
|
||||
ret = qmp_combo_get_dt_dp_orientation(dev, &dp_orientation);
|
||||
if (ret)
|
||||
goto err_node_put;
|
||||
|
||||
ret = qmp_combo_get_dt_usb3_orientation(dev, &usb3_orientation);
|
||||
if (ret)
|
||||
goto err_node_put;
|
||||
|
||||
if (dp_orientation == TYPEC_ORIENTATION_NONE &&
|
||||
usb3_orientation != TYPEC_ORIENTATION_NONE) {
|
||||
qmp->qmpphy_mode = QMPPHY_MODE_USB3_ONLY;
|
||||
qmp->orientation = usb3_orientation;
|
||||
} else if (usb3_orientation == TYPEC_ORIENTATION_NONE &&
|
||||
dp_orientation != TYPEC_ORIENTATION_NONE) {
|
||||
qmp->qmpphy_mode = QMPPHY_MODE_DP_ONLY;
|
||||
qmp->orientation = dp_orientation;
|
||||
} else if (dp_orientation != TYPEC_ORIENTATION_NONE &&
|
||||
dp_orientation == usb3_orientation) {
|
||||
qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
|
||||
qmp->orientation = dp_orientation;
|
||||
} else {
|
||||
dev_warn(dev, "unable to determine orientation & mode from data-lanes");
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_aux_bridge_register(dev);
|
||||
if (ret)
|
||||
|
|
@ -4189,11 +4283,6 @@ static int qmp_combo_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_node_put;
|
||||
|
||||
/*
|
||||
* The hw default is USB3_ONLY, but USB3+DP mode lets us more easily
|
||||
* check both sub-blocks' init tables for blunders at probe time.
|
||||
*/
|
||||
qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
|
||||
|
||||
qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops);
|
||||
if (IS_ERR(qmp->usb_phy)) {
|
||||
|
|
|
|||
|
|
@ -100,6 +100,12 @@ static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = {
|
|||
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL,
|
||||
};
|
||||
|
||||
static const unsigned int pciephy_v8_50_regs_layout[QPHY_LAYOUT_SIZE] = {
|
||||
[QPHY_START_CTRL] = QPHY_V8_50_PCS_START_CONTROL,
|
||||
[QPHY_PCS_STATUS] = QPHY_V8_50_PCS_STATUS1,
|
||||
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V8_50_PCS_POWER_DOWN_CONTROL,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
|
||||
|
|
@ -3072,6 +3078,7 @@ struct qmp_pcie_offsets {
|
|||
u16 rx2;
|
||||
u16 txz;
|
||||
u16 rxz;
|
||||
u16 txrxz;
|
||||
u16 ln_shrd;
|
||||
};
|
||||
|
||||
|
|
@ -3356,6 +3363,12 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = {
|
|||
.ln_shrd = 0x8000,
|
||||
};
|
||||
|
||||
static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_50 = {
|
||||
.serdes = 0x8000,
|
||||
.pcs = 0x9000,
|
||||
.txrxz = 0xd000,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
|
||||
.lanes = 1,
|
||||
|
||||
|
|
@ -4412,6 +4425,22 @@ static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = {
|
|||
.phy_status = PHYSTATUS_4_20,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = {
|
||||
.lanes = 4,
|
||||
|
||||
.offsets = &qmp_pcie_offsets_v8_50,
|
||||
|
||||
.reset_list = sdm845_pciephy_reset_l,
|
||||
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
|
||||
.regs = pciephy_v8_50_regs_layout,
|
||||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
};
|
||||
|
||||
static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls)
|
||||
{
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
|
|
@ -5163,6 +5192,9 @@ err_node_put:
|
|||
|
||||
static const struct of_device_id qmp_pcie_of_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,glymur-qmp-gen5x4-pcie-phy",
|
||||
.data = &glymur_qmp_gen5x4_pciephy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,ipq6018-qmp-pcie-phy",
|
||||
.data = &ipq6018_pciephy_cfg,
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef QCOM_PHY_QMP_PCS_V8_50_H_
|
||||
#define QCOM_PHY_QMP_PCS_V8_50_H_
|
||||
|
||||
#define QPHY_V8_50_PCS_STATUS1 0x010
|
||||
#define QPHY_V8_50_PCS_START_CONTROL 0x05c
|
||||
#define QPHY_V8_50_PCS_POWER_DOWN_CONTROL 0x64
|
||||
|
||||
#endif
|
||||
|
|
@ -58,6 +58,8 @@
|
|||
|
||||
#include "phy-qcom-qmp-pcs-v8.h"
|
||||
|
||||
#include "phy-qcom-qmp-pcs-v8_50.h"
|
||||
|
||||
/* QPHY_SW_RESET bit */
|
||||
#define SW_RESET BIT(0)
|
||||
/* QPHY_POWER_DOWN_CONTROL */
|
||||
|
|
|
|||
|
|
@ -40,3 +40,10 @@ config PHY_RCAR_GEN3_USB3
|
|||
select GENERIC_PHY
|
||||
help
|
||||
Support for USB 3.0 PHY found on Renesas R-Car generation 3 SoCs.
|
||||
|
||||
config PHY_RZ_G3E_USB3
|
||||
tristate "Renesas RZ/G3E USB 3.0 PHY driver"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Support for USB 3.0 PHY found on Renesas RZ/G3E SoCs.
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
|
|||
obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o
|
||||
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
|
||||
obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o
|
||||
obj-$(CONFIG_PHY_RZ_G3E_USB3) += phy-rzg3e-usb3.o
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ error:
|
|||
static void rcar_gen3_phy_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
};
|
||||
}
|
||||
|
||||
static struct platform_driver rcar_gen3_phy_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -132,9 +132,9 @@ struct rcar_gen3_chan {
|
|||
struct device *dev; /* platform_device's device */
|
||||
const struct rcar_gen3_phy_drv_data *phy_data;
|
||||
struct extcon_dev *extcon;
|
||||
struct reset_control *rstc;
|
||||
struct rcar_gen3_phy rphys[NUM_OF_PHYS];
|
||||
struct regulator *vbus;
|
||||
struct reset_control *rstc;
|
||||
struct work_struct work;
|
||||
spinlock_t lock; /* protects access to hardware and driver data structure. */
|
||||
enum usb_dr_mode dr_mode;
|
||||
|
|
@ -771,33 +771,32 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np)
|
|||
return candidate;
|
||||
}
|
||||
|
||||
static void rcar_gen3_reset_assert(void *data)
|
||||
{
|
||||
reset_control_assert(data);
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel)
|
||||
{
|
||||
struct device *dev = channel->dev;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
channel->rstc = devm_reset_control_array_get_shared(dev);
|
||||
if (IS_ERR(channel->rstc))
|
||||
return PTR_ERR(channel->rstc);
|
||||
if (!channel->phy_data->init_bus)
|
||||
return 0;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_deassert(channel->rstc);
|
||||
if (ret)
|
||||
goto rpm_put;
|
||||
|
||||
val = readl(channel->base + USB2_AHB_BUS_CTR);
|
||||
val &= ~USB2_AHB_BUS_CTR_MBL_MASK;
|
||||
val |= USB2_AHB_BUS_CTR_MBL_INCR4;
|
||||
writel(val, channel->base + USB2_AHB_BUS_CTR);
|
||||
|
||||
rpm_put:
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
|
|
@ -837,6 +836,18 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
channel->rstc = devm_reset_control_array_get_optional_shared(dev);
|
||||
if (IS_ERR(channel->rstc))
|
||||
return PTR_ERR(channel->rstc);
|
||||
|
||||
ret = reset_control_deassert(channel->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, rcar_gen3_reset_assert, channel->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* devm_phy_create() will call pm_runtime_enable(&phy->dev);
|
||||
* And then, phy-core will manage runtime pm for this device.
|
||||
|
|
@ -852,11 +863,9 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, channel);
|
||||
channel->dev = dev;
|
||||
|
||||
if (channel->phy_data->init_bus) {
|
||||
ret = rcar_gen3_phy_usb2_init_bus(channel);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
spin_lock_init(&channel->lock);
|
||||
for (i = 0; i < NUM_OF_PHYS; i++) {
|
||||
|
|
@ -924,14 +933,41 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
|||
if (channel->is_otg_channel)
|
||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||
|
||||
reset_control_assert(channel->rstc);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
};
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_suspend(struct device *dev)
|
||||
{
|
||||
struct rcar_gen3_chan *channel = dev_get_drvdata(dev);
|
||||
|
||||
return reset_control_assert(channel->rstc);
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_resume(struct device *dev)
|
||||
{
|
||||
struct rcar_gen3_chan *channel = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = reset_control_deassert(channel->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rcar_gen3_phy_usb2_init_bus(channel);
|
||||
if (ret)
|
||||
reset_control_assert(channel->rstc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(rcar_gen3_phy_usb2_pm_ops,
|
||||
rcar_gen3_phy_usb2_suspend,
|
||||
rcar_gen3_phy_usb2_resume);
|
||||
|
||||
static struct platform_driver rcar_gen3_phy_usb2_driver = {
|
||||
.driver = {
|
||||
.name = "phy_rcar_gen3_usb2",
|
||||
.of_match_table = rcar_gen3_phy_usb2_match_table,
|
||||
.pm = pm_ptr(&rcar_gen3_phy_usb2_pm_ops),
|
||||
},
|
||||
.probe = rcar_gen3_phy_usb2_probe,
|
||||
.remove = rcar_gen3_phy_usb2_remove,
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ error:
|
|||
static void rcar_gen3_phy_usb3_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
};
|
||||
}
|
||||
|
||||
static struct platform_driver rcar_gen3_phy_usb3_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,259 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Renesas RZ/G3E USB3.0 PHY driver
|
||||
*
|
||||
* Copyright (C) 2025 Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define USB3_TEST_RESET 0x0000
|
||||
#define USB3_TEST_UTMICTRL2 0x0b04
|
||||
#define USB3_TEST_PRMCTRL5_R 0x0c10
|
||||
#define USB3_TEST_PRMCTRL6_R 0x0c14
|
||||
|
||||
#define USB3_TEST_RSTCTRL 0x1000
|
||||
#define USB3_TEST_CLKCTRL 0x1004
|
||||
#define USB3_TEST_RAMCTRL 0x100c
|
||||
#define USB3_TEST_CREGCTRL 0x1010
|
||||
#define USB3_TEST_LANECONFIG0 0x1030
|
||||
|
||||
#define USB3_TEST_RESET_PORTRESET0_CTRL BIT(9)
|
||||
#define USB3_TEST_RESET_SIDDQ BIT(3)
|
||||
#define USB3_TEST_RESET_PHY_RESET BIT(2)
|
||||
#define USB3_TEST_RESET_PORTRESET0 BIT(1)
|
||||
#define USB3_TEST_RESET_RELEASE_OVERRIDE (0)
|
||||
|
||||
#define USB3_TEST_UTMICTRL2_CTRL_MASK GENMASK(9, 8)
|
||||
#define USB3_TEST_UTMICTRL2_MODE_MASK GENMASK(1, 0)
|
||||
|
||||
#define USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK GENMASK(2, 1)
|
||||
|
||||
#define USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK GENMASK(2, 0)
|
||||
|
||||
#define USB3_TEST_RSTCTRL_HARDRESET_ODEN BIT(9)
|
||||
#define USB3_TEST_RSTCTRL_PIPERESET_ODEN BIT(8)
|
||||
#define USB3_TEST_RSTCTRL_HARDRESET BIT(1)
|
||||
#define USB3_TEST_RSTCTRL_PIPERESET BIT(0)
|
||||
#define USB3_TEST_RSTCTRL_ASSERT \
|
||||
(USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN | \
|
||||
USB3_TEST_RSTCTRL_HARDRESET | USB3_TEST_RSTCTRL_PIPERESET)
|
||||
#define USB3_TEST_RSTCTRL_RELEASE_HARDRESET \
|
||||
(USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN | \
|
||||
USB3_TEST_RSTCTRL_PIPERESET)
|
||||
#define USB3_TEST_RSTCTRL_DEASSERT \
|
||||
(USB3_TEST_RSTCTRL_HARDRESET_ODEN | USB3_TEST_RSTCTRL_PIPERESET_ODEN)
|
||||
#define USB3_TEST_RSTCTRL_RELEASE_OVERRIDE (0)
|
||||
|
||||
#define USB3_TEST_CLKCTRL_MPLLA_SSC_EN BIT(2)
|
||||
|
||||
#define USB3_TEST_RAMCTRL_SRAM_INIT_DONE BIT(2)
|
||||
#define USB3_TEST_RAMCTRL_SRAM_EXT_LD_DONE BIT(0)
|
||||
|
||||
#define USB3_TEST_CREGCTRL_PARA_SEL BIT(8)
|
||||
|
||||
#define USB3_TEST_LANECONFIG0_DEFAULT (0xd)
|
||||
|
||||
struct rz_usb3 {
|
||||
void __iomem *base;
|
||||
struct reset_control *rstc;
|
||||
bool skip_reinit;
|
||||
};
|
||||
|
||||
static void rzg3e_phy_usb2test_phy_init(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(base + USB3_TEST_UTMICTRL2);
|
||||
val |= USB3_TEST_UTMICTRL2_CTRL_MASK | USB3_TEST_UTMICTRL2_MODE_MASK;
|
||||
writel(val, base + USB3_TEST_UTMICTRL2);
|
||||
|
||||
val = readl(base + USB3_TEST_PRMCTRL5_R);
|
||||
val &= ~USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK;
|
||||
val |= FIELD_PREP(USB3_TEST_PRMCTRL5_R_TXPREEMPAMPTUNE0_MASK, 2);
|
||||
writel(val, base + USB3_TEST_PRMCTRL5_R);
|
||||
|
||||
val = readl(base + USB3_TEST_PRMCTRL6_R);
|
||||
val &= ~USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK;
|
||||
val |= FIELD_PREP(USB3_TEST_PRMCTRL6_R_OTGTUNE0_MASK, 7);
|
||||
writel(val, base + USB3_TEST_PRMCTRL6_R);
|
||||
|
||||
val = readl(base + USB3_TEST_RESET);
|
||||
val &= ~USB3_TEST_RESET_SIDDQ;
|
||||
val |= USB3_TEST_RESET_PORTRESET0_CTRL | USB3_TEST_RESET_PHY_RESET |
|
||||
USB3_TEST_RESET_PORTRESET0;
|
||||
writel(val, base + USB3_TEST_RESET);
|
||||
fsleep(10);
|
||||
|
||||
val &= ~(USB3_TEST_RESET_PHY_RESET | USB3_TEST_RESET_PORTRESET0);
|
||||
writel(val, base + USB3_TEST_RESET);
|
||||
fsleep(10);
|
||||
|
||||
val = readl(base + USB3_TEST_UTMICTRL2);
|
||||
val &= ~USB3_TEST_UTMICTRL2_CTRL_MASK;
|
||||
writel(val, base + USB3_TEST_UTMICTRL2);
|
||||
|
||||
writel(USB3_TEST_RESET_RELEASE_OVERRIDE, base + USB3_TEST_RESET);
|
||||
}
|
||||
|
||||
static int rzg3e_phy_usb3test_phy_init(void __iomem *base)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
writel(USB3_TEST_CREGCTRL_PARA_SEL, base + USB3_TEST_CREGCTRL);
|
||||
writel(USB3_TEST_RSTCTRL_ASSERT, base + USB3_TEST_RSTCTRL);
|
||||
fsleep(20);
|
||||
|
||||
writel(USB3_TEST_CLKCTRL_MPLLA_SSC_EN, base + USB3_TEST_CLKCTRL);
|
||||
writel(USB3_TEST_LANECONFIG0_DEFAULT, base + USB3_TEST_LANECONFIG0);
|
||||
writel(USB3_TEST_RSTCTRL_RELEASE_HARDRESET, base + USB3_TEST_RSTCTRL);
|
||||
|
||||
ret = readl_poll_timeout_atomic(base + USB3_TEST_RAMCTRL, val,
|
||||
val & USB3_TEST_RAMCTRL_SRAM_INIT_DONE, 1, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(USB3_TEST_RSTCTRL_DEASSERT, base + USB3_TEST_RSTCTRL);
|
||||
writel(USB3_TEST_RAMCTRL_SRAM_EXT_LD_DONE, base + USB3_TEST_RAMCTRL);
|
||||
writel(USB3_TEST_RSTCTRL_RELEASE_OVERRIDE, base + USB3_TEST_RSTCTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg3e_phy_usb3_init_helper(void __iomem *base)
|
||||
{
|
||||
rzg3e_phy_usb2test_phy_init(base);
|
||||
|
||||
return rzg3e_phy_usb3test_phy_init(base);
|
||||
}
|
||||
|
||||
static int rzg3e_phy_usb3_init(struct phy *p)
|
||||
{
|
||||
struct rz_usb3 *r = phy_get_drvdata(p);
|
||||
int ret = 0;
|
||||
|
||||
if (!r->skip_reinit)
|
||||
ret = rzg3e_phy_usb3_init_helper(r->base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct phy_ops rzg3e_phy_usb3_ops = {
|
||||
.init = rzg3e_phy_usb3_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int rzg3e_phy_usb3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy_provider *provider;
|
||||
struct rz_usb3 *r;
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
|
||||
r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL);
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
|
||||
r->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(r->base))
|
||||
return PTR_ERR(r->base);
|
||||
|
||||
r->rstc = devm_reset_control_get_shared_deasserted(dev, NULL);
|
||||
if (IS_ERR(r->rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(r->rstc), "failed to get deasserted reset\n");
|
||||
|
||||
/*
|
||||
* devm_phy_create() will call pm_runtime_enable(&phy->dev);
|
||||
* And then, phy-core will manage runtime pm for this device.
|
||||
*/
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &rzg3e_phy_usb3_ops);
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy), "failed to create USB3 PHY\n");
|
||||
|
||||
platform_set_drvdata(pdev, r);
|
||||
phy_set_drvdata(phy, r);
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(provider))
|
||||
return dev_err_probe(dev, PTR_ERR(provider), "failed to register PHY provider\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg3e_phy_usb3_suspend(struct device *dev)
|
||||
{
|
||||
struct rz_usb3 *r = dev_get_drvdata(dev);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
reset_control_assert(r->rstc);
|
||||
r->skip_reinit = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg3e_phy_usb3_resume(struct device *dev)
|
||||
{
|
||||
struct rz_usb3 *r = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = reset_control_deassert(r->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
goto reset_assert;
|
||||
|
||||
ret = rzg3e_phy_usb3_init_helper(r->base);
|
||||
if (ret)
|
||||
goto pm_put;
|
||||
|
||||
r->skip_reinit = true;
|
||||
|
||||
return 0;
|
||||
|
||||
pm_put:
|
||||
pm_runtime_put(dev);
|
||||
reset_assert:
|
||||
reset_control_assert(r->rstc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rzg3e_phy_usb3_pm = {
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(rzg3e_phy_usb3_suspend, rzg3e_phy_usb3_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id rzg3e_phy_usb3_match_table[] = {
|
||||
{ .compatible = "renesas,r9a09g047-usb3-phy" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, rzg3e_phy_usb3_match_table);
|
||||
static struct platform_driver rzg3e_phy_usb3_driver = {
|
||||
.driver = {
|
||||
.name = "phy_rzg3e_usb3",
|
||||
.of_match_table = rzg3e_phy_usb3_match_table,
|
||||
.pm = pm_sleep_ptr(&rzg3e_phy_usb3_pm),
|
||||
},
|
||||
.probe = rzg3e_phy_usb3_probe,
|
||||
};
|
||||
module_platform_driver(rzg3e_phy_usb3_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Renesas RZ/G3E USB3.0 PHY Driver");
|
||||
MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");
|
||||
|
|
@ -99,10 +99,30 @@
|
|||
#define VOD_MID_RANGE 0x3
|
||||
#define VOD_BIG_RANGE 0x7
|
||||
#define VOD_MAX_RANGE 0xf
|
||||
/* Analog Register Part: reg18 */
|
||||
#define LANE0_PRE_EMPHASIS_ENABLE_MASK BIT(6)
|
||||
#define LANE0_PRE_EMPHASIS_ENABLE BIT(6)
|
||||
#define LANE0_PRE_EMPHASIS_DISABLE 0
|
||||
#define LANE1_PRE_EMPHASIS_ENABLE_MASK BIT(5)
|
||||
#define LANE1_PRE_EMPHASIS_ENABLE BIT(5)
|
||||
#define LANE1_PRE_EMPHASIS_DISABLE 0
|
||||
/* Analog Register Part: reg19 */
|
||||
#define PRE_EMPHASIS_RANGE_SET_MASK GENMASK(7, 6)
|
||||
#define PRE_EMPHASIS_RANGE_SET(x) UPDATE(x, 7, 6)
|
||||
/* Analog Register Part: reg1E */
|
||||
#define PLL_MODE_SEL_MASK GENMASK(6, 5)
|
||||
#define PLL_MODE_SEL_LVDS_MODE 0
|
||||
#define PLL_MODE_SEL_MIPI_MODE BIT(5)
|
||||
/* Analog Register Part: reg20 */
|
||||
#define LANE0_PRE_EMPHASIS_RANGE_SET_MASK GENMASK(7, 6)
|
||||
#define LANE0_PRE_EMPHASIS_RANGE_SET(x) UPDATE(x, 7, 6)
|
||||
/* Analog Register Part: reg21 */
|
||||
#define LANE1_PRE_EMPHASIS_RANGE_SET_MASK GENMASK(7, 6)
|
||||
#define LANE1_PRE_EMPHASIS_RANGE_SET(x) UPDATE(x, 7, 6)
|
||||
#define PRE_EMPHASIS_MIN_RANGE 0x0
|
||||
#define PRE_EMPHASIS_MID_RANGE 0x1
|
||||
#define PRE_EMPHASIS_MAX_RANGE 0x2
|
||||
#define PRE_EMPHASIS_RESERVED_RANGE 0x3
|
||||
/* Digital Register Part: reg00 */
|
||||
#define REG_DIG_RSTN_MASK BIT(0)
|
||||
#define REG_DIG_RSTN_NORMAL BIT(0)
|
||||
|
|
@ -193,6 +213,7 @@
|
|||
|
||||
enum phy_max_rate {
|
||||
MAX_1GHZ,
|
||||
MAX_1_5GHZ,
|
||||
MAX_2_5GHZ,
|
||||
};
|
||||
|
||||
|
|
@ -200,6 +221,7 @@ struct inno_video_phy_plat_data {
|
|||
const struct inno_mipi_dphy_timing *inno_mipi_dphy_timing_table;
|
||||
const unsigned int num_timings;
|
||||
enum phy_max_rate max_rate;
|
||||
unsigned int max_lanes;
|
||||
};
|
||||
|
||||
struct inno_dsidphy {
|
||||
|
|
@ -258,6 +280,24 @@ struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_1ghz[] = {
|
|||
{1000000000, 0x0, 0x09, 0x20, 0x09, 0x27},
|
||||
};
|
||||
|
||||
static const
|
||||
struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_1_5ghz[] = {
|
||||
{ 110, 0x02, 0x7f, 0x16, 0x02, 0x02},
|
||||
{ 150, 0x02, 0x7f, 0x16, 0x03, 0x02},
|
||||
{ 200, 0x02, 0x7f, 0x17, 0x04, 0x02},
|
||||
{ 250, 0x02, 0x7f, 0x17, 0x05, 0x04},
|
||||
{ 300, 0x02, 0x7f, 0x18, 0x06, 0x04},
|
||||
{ 400, 0x03, 0x7e, 0x19, 0x07, 0x04},
|
||||
{ 500, 0x03, 0x7c, 0x1b, 0x07, 0x08},
|
||||
{ 600, 0x03, 0x70, 0x1d, 0x08, 0x10},
|
||||
{ 700, 0x05, 0x40, 0x1e, 0x08, 0x30},
|
||||
{ 800, 0x05, 0x02, 0x1f, 0x09, 0x30},
|
||||
{1000, 0x05, 0x08, 0x20, 0x09, 0x30},
|
||||
{1200, 0x06, 0x03, 0x32, 0x14, 0x0f},
|
||||
{1400, 0x09, 0x03, 0x32, 0x14, 0x0f},
|
||||
{1500, 0x0d, 0x42, 0x36, 0x0e, 0x0f},
|
||||
};
|
||||
|
||||
static const
|
||||
struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_2_5ghz[] = {
|
||||
{ 110000000, 0x02, 0x7f, 0x16, 0x02, 0x02},
|
||||
|
|
@ -372,6 +412,7 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno)
|
|||
u32 hs_exit, clk_post, clk_pre, wakeup, lpx, ta_go, ta_sure, ta_wait;
|
||||
u32 hs_prepare, hs_trail, hs_zero, clk_lane_hs_zero, data_lane_hs_zero;
|
||||
unsigned int i;
|
||||
u32 val;
|
||||
|
||||
timings = inno->pdata->inno_mipi_dphy_timing_table;
|
||||
|
||||
|
|
@ -393,6 +434,23 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno)
|
|||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x0b,
|
||||
CLOCK_LANE_VOD_RANGE_SET_MASK,
|
||||
CLOCK_LANE_VOD_RANGE_SET(VOD_MAX_RANGE));
|
||||
} else if (inno->pdata->max_rate == MAX_1_5GHZ) {
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x18,
|
||||
LANE0_PRE_EMPHASIS_ENABLE_MASK, LANE0_PRE_EMPHASIS_ENABLE);
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x18,
|
||||
LANE1_PRE_EMPHASIS_ENABLE_MASK, LANE1_PRE_EMPHASIS_ENABLE);
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x19,
|
||||
PRE_EMPHASIS_RANGE_SET_MASK,
|
||||
PRE_EMPHASIS_RANGE_SET(PRE_EMPHASIS_MID_RANGE));
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x1a,
|
||||
LANE0_PRE_EMPHASIS_RANGE_SET_MASK,
|
||||
LANE0_PRE_EMPHASIS_RANGE_SET(PRE_EMPHASIS_MID_RANGE));
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x1b,
|
||||
LANE1_PRE_EMPHASIS_RANGE_SET_MASK,
|
||||
LANE1_PRE_EMPHASIS_RANGE_SET(PRE_EMPHASIS_MID_RANGE));
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x0b,
|
||||
CLOCK_LANE_VOD_RANGE_SET_MASK,
|
||||
CLOCK_LANE_VOD_RANGE_SET(VOD_MAX_RANGE));
|
||||
}
|
||||
/* Enable PLL and LDO */
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01,
|
||||
|
|
@ -518,10 +576,25 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno)
|
|||
T_TA_WAIT_CNT(ta_wait));
|
||||
}
|
||||
|
||||
/* Enable all lanes on analog part */
|
||||
/* Enable lanes on analog part */
|
||||
switch (inno->pdata->max_lanes) {
|
||||
case 1:
|
||||
val = LANE_EN_0;
|
||||
break;
|
||||
case 2:
|
||||
val = LANE_EN_0 | LANE_EN_1;
|
||||
break;
|
||||
case 3:
|
||||
val = LANE_EN_0 | LANE_EN_1 | LANE_EN_2;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
val = LANE_EN_0 | LANE_EN_1 | LANE_EN_2 | LANE_EN_3;
|
||||
break;
|
||||
}
|
||||
|
||||
phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00,
|
||||
LANE_EN_MASK, LANE_EN_CK | LANE_EN_3 | LANE_EN_2 |
|
||||
LANE_EN_1 | LANE_EN_0);
|
||||
LANE_EN_MASK, LANE_EN_CK | val);
|
||||
}
|
||||
|
||||
static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno)
|
||||
|
|
@ -680,12 +753,21 @@ static const struct inno_video_phy_plat_data max_1ghz_video_phy_plat_data = {
|
|||
.inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_1ghz,
|
||||
.num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_1ghz),
|
||||
.max_rate = MAX_1GHZ,
|
||||
.max_lanes = 4,
|
||||
};
|
||||
|
||||
static const struct inno_video_phy_plat_data max_1_5ghz_video_phy_plat_data = {
|
||||
.inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_1_5ghz,
|
||||
.num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_1_5ghz),
|
||||
.max_rate = MAX_1_5GHZ,
|
||||
.max_lanes = 2,
|
||||
};
|
||||
|
||||
static const struct inno_video_phy_plat_data max_2_5ghz_video_phy_plat_data = {
|
||||
.inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_2_5ghz,
|
||||
.num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_2_5ghz),
|
||||
.max_rate = MAX_2_5GHZ,
|
||||
.max_lanes = 4,
|
||||
};
|
||||
|
||||
static int inno_dsidphy_probe(struct platform_device *pdev)
|
||||
|
|
@ -767,6 +849,9 @@ static const struct of_device_id inno_dsidphy_of_match[] = {
|
|||
}, {
|
||||
.compatible = "rockchip,rk3368-dsi-dphy",
|
||||
.data = &max_1ghz_video_phy_plat_data,
|
||||
}, {
|
||||
.compatible = "rockchip,rk3506-dsi-dphy",
|
||||
.data = &max_1_5ghz_video_phy_plat_data,
|
||||
}, {
|
||||
.compatible = "rockchip,rk3568-dsi-dphy",
|
||||
.data = &max_2_5ghz_video_phy_plat_data,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@
|
|||
#define REF_CLOCK_100MHz (100 * HZ_PER_MHZ)
|
||||
|
||||
/* RK3528 COMBO PHY REG */
|
||||
#define RK3528_PHYREG5 0x14
|
||||
#define RK3528_PHYREG5_GATE_TX_PCK_SEL BIT(3)
|
||||
#define RK3528_PHYREG5_GATE_TX_PCK_DLY_PLL_OFF BIT(3)
|
||||
#define RK3528_PHYREG6 0x18
|
||||
#define RK3528_PHYREG6_PLL_KVCO GENMASK(12, 10)
|
||||
#define RK3528_PHYREG6_PLL_KVCO_VALUE 0x2
|
||||
|
|
@ -103,6 +106,10 @@
|
|||
#define RK3568_PHYREG18 0x44
|
||||
#define RK3568_PHYREG18_PLL_LOOP 0x32
|
||||
|
||||
#define RK3568_PHYREG30 0x74
|
||||
#define RK3568_PHYREG30_GATE_TX_PCK_SEL BIT(7)
|
||||
#define RK3568_PHYREG30_GATE_TX_PCK_DLY_PLL_OFF BIT(7)
|
||||
|
||||
#define RK3568_PHYREG32 0x7C
|
||||
#define RK3568_PHYREG32_SSC_MASK GENMASK(7, 4)
|
||||
#define RK3568_PHYREG32_SSC_DIR_MASK GENMASK(5, 4)
|
||||
|
|
@ -504,6 +511,10 @@ static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv)
|
|||
case REF_CLOCK_100MHz:
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
|
||||
if (priv->type == PHY_TYPE_PCIE) {
|
||||
/* Gate_tx_pck_sel length select for L1ss support */
|
||||
rockchip_combphy_updatel(priv, RK3528_PHYREG5_GATE_TX_PCK_SEL,
|
||||
RK3528_PHYREG5_GATE_TX_PCK_DLY_PLL_OFF, RK3528_PHYREG5);
|
||||
|
||||
/* PLL KVCO tuning fine */
|
||||
val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE);
|
||||
rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val,
|
||||
|
|
@ -657,6 +668,10 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv)
|
|||
case REF_CLOCK_100MHz:
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
|
||||
if (priv->type == PHY_TYPE_PCIE) {
|
||||
/* Gate_tx_pck_sel length select for L1ss support */
|
||||
rockchip_combphy_updatel(priv, RK3568_PHYREG30_GATE_TX_PCK_SEL,
|
||||
RK3568_PHYREG30_GATE_TX_PCK_DLY_PLL_OFF,
|
||||
RK3568_PHYREG30);
|
||||
/* PLL KVCO tuning fine */
|
||||
val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK,
|
||||
RK3568_PHYREG33_PLL_KVCO_VALUE);
|
||||
|
|
|
|||
|
|
@ -500,9 +500,7 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
|
|||
REG_SEQ0(CMN_REG(0043), 0x00),
|
||||
REG_SEQ0(CMN_REG(0044), 0x46),
|
||||
REG_SEQ0(CMN_REG(0045), 0x24),
|
||||
REG_SEQ0(CMN_REG(0046), 0xff),
|
||||
REG_SEQ0(CMN_REG(0047), 0x00),
|
||||
REG_SEQ0(CMN_REG(0048), 0x44),
|
||||
REG_SEQ0(CMN_REG(0049), 0xfa),
|
||||
REG_SEQ0(CMN_REG(004a), 0x08),
|
||||
REG_SEQ0(CMN_REG(004b), 0x00),
|
||||
|
|
@ -575,6 +573,8 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = {
|
|||
REG_SEQ0(CMN_REG(0034), 0x00),
|
||||
REG_SEQ0(CMN_REG(003d), 0x40),
|
||||
REG_SEQ0(CMN_REG(0042), 0x78),
|
||||
REG_SEQ0(CMN_REG(0046), 0xdd),
|
||||
REG_SEQ0(CMN_REG(0048), 0x11),
|
||||
REG_SEQ0(CMN_REG(004e), 0x34),
|
||||
REG_SEQ0(CMN_REG(005c), 0x25),
|
||||
REG_SEQ0(CMN_REG(005e), 0x4f),
|
||||
|
|
@ -668,13 +668,9 @@ static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = {
|
|||
|
||||
static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = {
|
||||
REG_SEQ0(LANE_REG(0312), 0x00),
|
||||
REG_SEQ0(LANE_REG(031e), 0x00),
|
||||
REG_SEQ0(LANE_REG(0412), 0x00),
|
||||
REG_SEQ0(LANE_REG(041e), 0x00),
|
||||
REG_SEQ0(LANE_REG(0512), 0x00),
|
||||
REG_SEQ0(LANE_REG(051e), 0x00),
|
||||
REG_SEQ0(LANE_REG(0612), 0x00),
|
||||
REG_SEQ0(LANE_REG(061e), 0x08),
|
||||
REG_SEQ0(LANE_REG(0303), 0x2f),
|
||||
REG_SEQ0(LANE_REG(0403), 0x2f),
|
||||
REG_SEQ0(LANE_REG(0503), 0x2f),
|
||||
|
|
@ -687,6 +683,11 @@ static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = {
|
|||
REG_SEQ0(LANE_REG(0406), 0x1c),
|
||||
REG_SEQ0(LANE_REG(0506), 0x1c),
|
||||
REG_SEQ0(LANE_REG(0606), 0x1c),
|
||||
/* Keep Inter-Pair Skew in the limits */
|
||||
REG_SEQ0(LANE_REG(031e), 0x02),
|
||||
REG_SEQ0(LANE_REG(041e), 0x02),
|
||||
REG_SEQ0(LANE_REG(051e), 0x02),
|
||||
REG_SEQ0(LANE_REG(061e), 0x0a),
|
||||
};
|
||||
|
||||
static struct tx_drv_ctrl tx_drv_ctrl_rbr[4][4] = {
|
||||
|
|
@ -1037,7 +1038,8 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
|
|||
|
||||
ret = rk_hdptx_post_enable_pll(hdptx);
|
||||
if (!ret)
|
||||
hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate;
|
||||
hdptx->hw_rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8,
|
||||
hdptx->hdmi_cfg.bpc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1895,19 +1897,20 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
* hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
|
||||
* a different rate argument.
|
||||
*/
|
||||
return hdptx->hdmi_cfg.tmds_char_rate;
|
||||
return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, hdptx->hdmi_cfg.bpc);
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8);
|
||||
|
||||
/* Revert any unlikely TMDS char rate change since round_rate() */
|
||||
if (hdptx->hdmi_cfg.tmds_char_rate != rate) {
|
||||
dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n",
|
||||
rate, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
hdptx->hdmi_cfg.tmds_char_rate = rate;
|
||||
if (hdptx->hdmi_cfg.tmds_char_rate != tmds_rate) {
|
||||
dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n",
|
||||
tmds_rate, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
hdptx->hdmi_cfg.tmds_char_rate = tmds_rate;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1823,7 +1823,7 @@ static int exynos5_usbdrd_orien_sw_set(struct typec_switch_dev *sw,
|
|||
phy_drd->orientation = orientation;
|
||||
}
|
||||
|
||||
clk_bulk_disable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,12 +108,39 @@ static const struct samsung_ufs_phy_cfg tensor_gs101_post_pwr_hs_config[] = {
|
|||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
static const struct samsung_ufs_phy_cfg tensor_gs101_post_h8_enter[] = {
|
||||
PHY_TRSV_REG_CFG_GS101(0x262, 0x08, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x265, 0x0A, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x1, 0x8, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x0, 0x86, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x8, 0x60, PWR_MODE_HS_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x222, 0x08, PWR_MODE_HS_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x246, 0x01, PWR_MODE_HS_ANY),
|
||||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
static const struct samsung_ufs_phy_cfg tensor_gs101_pre_h8_exit[] = {
|
||||
PHY_COMN_REG_CFG(0x0, 0xC6, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x1, 0x0C, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x262, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x265, 0x00, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x8, 0xE0, PWR_MODE_HS_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x246, 0x03, PWR_MODE_HS_ANY),
|
||||
PHY_TRSV_REG_CFG_GS101(0x222, 0x18, PWR_MODE_HS_ANY),
|
||||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
static const struct samsung_ufs_phy_cfg *tensor_gs101_ufs_phy_cfgs[CFG_TAG_MAX] = {
|
||||
[CFG_PRE_INIT] = tensor_gs101_pre_init_cfg,
|
||||
[CFG_PRE_PWR_HS] = tensor_gs101_pre_pwr_hs_config,
|
||||
[CFG_POST_PWR_HS] = tensor_gs101_post_pwr_hs_config,
|
||||
};
|
||||
|
||||
static const struct samsung_ufs_phy_cfg *tensor_gs101_hibern8_cfgs[] = {
|
||||
[CFG_POST_HIBERN8_ENTER] = tensor_gs101_post_h8_enter,
|
||||
[CFG_PRE_HIBERN8_EXIT] = tensor_gs101_pre_h8_exit,
|
||||
};
|
||||
|
||||
static const char * const tensor_gs101_ufs_phy_clks[] = {
|
||||
"ref_clk",
|
||||
};
|
||||
|
|
@ -170,6 +197,7 @@ static int gs101_phy_wait_for_cdr_lock(struct phy *phy, u8 lane)
|
|||
|
||||
const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy = {
|
||||
.cfgs = tensor_gs101_ufs_phy_cfgs,
|
||||
.cfgs_hibern8 = tensor_gs101_hibern8_cfgs,
|
||||
.isol = {
|
||||
.offset = TENSOR_GS101_PHY_CTRL,
|
||||
.mask = TENSOR_GS101_PHY_CTRL_MASK,
|
||||
|
|
|
|||
|
|
@ -217,6 +217,44 @@ static int samsung_ufs_phy_set_mode(struct phy *generic_phy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_ufs_phy_notify_state(struct phy *phy,
|
||||
union phy_notify state)
|
||||
{
|
||||
struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
|
||||
const struct samsung_ufs_phy_cfg *cfg;
|
||||
int i, err = -EINVAL;
|
||||
|
||||
if (!ufs_phy->cfgs_hibern8)
|
||||
return 0;
|
||||
|
||||
if (state.ufs_state == PHY_UFS_HIBERN8_ENTER)
|
||||
cfg = ufs_phy->cfgs_hibern8[CFG_POST_HIBERN8_ENTER];
|
||||
else if (state.ufs_state == PHY_UFS_HIBERN8_EXIT)
|
||||
cfg = ufs_phy->cfgs_hibern8[CFG_PRE_HIBERN8_EXIT];
|
||||
else
|
||||
goto err_out;
|
||||
|
||||
for_each_phy_cfg(cfg) {
|
||||
for_each_phy_lane(ufs_phy, i) {
|
||||
samsung_ufs_phy_config(ufs_phy, cfg, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.ufs_state == PHY_UFS_HIBERN8_EXIT) {
|
||||
for_each_phy_lane(ufs_phy, i) {
|
||||
if (ufs_phy->drvdata->wait_for_cdr) {
|
||||
err = ufs_phy->drvdata->wait_for_cdr(phy, i);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int samsung_ufs_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy);
|
||||
|
|
@ -233,6 +271,7 @@ static const struct phy_ops samsung_ufs_phy_ops = {
|
|||
.power_off = samsung_ufs_phy_power_off,
|
||||
.calibrate = samsung_ufs_phy_calibrate,
|
||||
.set_mode = samsung_ufs_phy_set_mode,
|
||||
.notify_phystate = samsung_ufs_phy_notify_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
@ -287,6 +326,7 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev)
|
|||
phy->dev = dev;
|
||||
phy->drvdata = drvdata;
|
||||
phy->cfgs = drvdata->cfgs;
|
||||
phy->cfgs_hibern8 = drvdata->cfgs_hibern8;
|
||||
memcpy(&phy->isol, &drvdata->isol, sizeof(phy->isol));
|
||||
|
||||
if (!of_property_read_u32_index(dev->of_node, "samsung,pmu-syscon", 1,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ enum {
|
|||
CFG_TAG_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
CFG_POST_HIBERN8_ENTER,
|
||||
CFG_PRE_HIBERN8_EXIT,
|
||||
};
|
||||
|
||||
struct samsung_ufs_phy_cfg {
|
||||
u32 off_0;
|
||||
u32 off_1;
|
||||
|
|
@ -108,6 +113,7 @@ struct samsung_ufs_phy_pmu_isol {
|
|||
|
||||
struct samsung_ufs_phy_drvdata {
|
||||
const struct samsung_ufs_phy_cfg **cfgs;
|
||||
const struct samsung_ufs_phy_cfg **cfgs_hibern8;
|
||||
struct samsung_ufs_phy_pmu_isol isol;
|
||||
const char * const *clk_list;
|
||||
int num_clks;
|
||||
|
|
@ -124,6 +130,7 @@ struct samsung_ufs_phy {
|
|||
struct clk_bulk_data *clks;
|
||||
const struct samsung_ufs_phy_drvdata *drvdata;
|
||||
const struct samsung_ufs_phy_cfg * const *cfgs;
|
||||
const struct samsung_ufs_phy_cfg * const *cfgs_hibern8;
|
||||
struct samsung_ufs_phy_pmu_isol isol;
|
||||
u8 lane_cnt;
|
||||
int ufs_phy_state;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
|
|||
if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
|
||||
args->args_count < 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (phy_id > priv->num_ports)
|
||||
if (phy_id < 1 || phy_id > priv->num_ports)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (phy_id != priv->if_phys[phy_id - 1].id)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,15 @@ enum phy_media {
|
|||
PHY_MEDIA_DAC,
|
||||
};
|
||||
|
||||
enum phy_ufs_state {
|
||||
PHY_UFS_HIBERN8_ENTER,
|
||||
PHY_UFS_HIBERN8_EXIT,
|
||||
};
|
||||
|
||||
union phy_notify {
|
||||
enum phy_ufs_state ufs_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* union phy_configure_opts - Opaque generic phy configuration
|
||||
*
|
||||
|
|
@ -83,6 +92,7 @@ union phy_configure_opts {
|
|||
* @set_speed: set the speed of the phy (optional)
|
||||
* @reset: resetting the phy
|
||||
* @calibrate: calibrate the phy
|
||||
* @notify_phystate: notify and configure the phy for a particular state
|
||||
* @release: ops to be performed while the consumer relinquishes the PHY
|
||||
* @owner: the module owner containing the ops
|
||||
*/
|
||||
|
|
@ -132,6 +142,7 @@ struct phy_ops {
|
|||
int (*connect)(struct phy *phy, int port);
|
||||
int (*disconnect)(struct phy *phy, int port);
|
||||
|
||||
int (*notify_phystate)(struct phy *phy, union phy_notify state);
|
||||
void (*release)(struct phy *phy);
|
||||
struct module *owner;
|
||||
};
|
||||
|
|
@ -255,6 +266,7 @@ int phy_reset(struct phy *phy);
|
|||
int phy_calibrate(struct phy *phy);
|
||||
int phy_notify_connect(struct phy *phy, int port);
|
||||
int phy_notify_disconnect(struct phy *phy, int port);
|
||||
int phy_notify_state(struct phy *phy, union phy_notify state);
|
||||
static inline int phy_get_bus_width(struct phy *phy)
|
||||
{
|
||||
return phy->attrs.bus_width;
|
||||
|
|
@ -412,6 +424,13 @@ static inline int phy_notify_disconnect(struct phy *phy, int index)
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int phy_notify_state(struct phy *phy, union phy_notify state)
|
||||
{
|
||||
if (!phy)
|
||||
return 0;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int phy_configure(struct phy *phy,
|
||||
union phy_configure_opts *opts)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue