diff --git a/Documentation/devicetree/bindings/phy/canaan,k230-usb-phy.yaml b/Documentation/devicetree/bindings/phy/canaan,k230-usb-phy.yaml new file mode 100644 index 000000000000..b959b381c44c --- /dev/null +++ b/Documentation/devicetree/bindings/phy/canaan,k230-usb-phy.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/canaan,k230-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Canaan K230 USB2.0 PHY + +maintainers: + - Jiayu Du + +properties: + compatible: + const: canaan,k230-usb-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 1 + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + usbphy: usb-phy@91585000 { + compatible = "canaan,k230-usb-phy"; + reg = <0x91585000 0x400>; + #phy-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/phy/eswin,eic7700-sata-phy.yaml b/Documentation/devicetree/bindings/phy/eswin,eic7700-sata-phy.yaml new file mode 100644 index 000000000000..fc7dbac77acf --- /dev/null +++ b/Documentation/devicetree/bindings/phy/eswin,eic7700-sata-phy.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/eswin,eic7700-sata-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Eswin EIC7700 SoC SATA PHY + +maintainers: + - Yulin Lu + - Huan He + +properties: + compatible: + const: eswin,eic7700-sata-phy + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: phy + + resets: + maxItems: 2 + + reset-names: + items: + - const: port + - const: phy + + eswin,tx-amplitude-tuning: + description: This adjusts the transmitter amplitude signal, and its value + is derived from eye diagram tuning. The three values correspond to Gen1, + Gen2, and Gen3 parameters respectively. + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - description: Gen1 parameter. + minimum: 0 + maximum: 0x7f + - description: Gen2 parameter. + minimum: 0 + maximum: 0x7f + - description: Gen3 parameter. + minimum: 0 + maximum: 0x7f + default: [0, 0, 0] + + eswin,tx-preemph-tuning: + description: This adjusts the transmitter de-emphasis signal, and its value + is derived from eye diagram tuning. The three values correspond to Gen1, + Gen2, and Gen3 parameters respectively. + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - description: Gen1 parameter. + minimum: 0 + maximum: 0x3f + - description: Gen2 parameter. + minimum: 0 + maximum: 0x3f + - description: Gen3 parameter. + minimum: 0 + maximum: 0x3f + default: [0, 0, 0] + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + sata-phy@50440300 { + compatible = "eswin,eic7700-sata-phy"; + reg = <0x50440300 0x40>; + clocks = <&hspcrg 17>; + clock-names = "phy"; + resets = <&hspcrg 0>, <&hspcrg 1>; + reset-names = "port", "phy"; + #phy-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index a1731b08c9d1..9616c736b6d4 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -16,6 +16,10 @@ description: properties: compatible: oneOf: + - items: + - enum: + - qcom,qcs8300-qmp-ufs-phy + - const: qcom,sa8775p-qmp-ufs-phy - items: - enum: - qcom,qcs615-qmp-ufs-phy @@ -26,8 +30,8 @@ properties: - const: qcom,sm8550-qmp-ufs-phy - items: - enum: - - qcom,qcs8300-qmp-ufs-phy - - const: qcom,sa8775p-qmp-ufs-phy + - qcom,eliza-qmp-ufs-phy + - const: qcom,sm8650-qmp-ufs-phy - items: - enum: - qcom,kaanapali-qmp-ufs-phy diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 1875d5b784f6..227b9a4c612e 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -46,6 +46,26 @@ config GENERIC_PHY_MIPI_DPHY Provides a number of helpers a core functions for MIPI D-PHY drivers to us. +config PHY_AIROHA_PCIE + tristate "Airoha PCIe-PHY Driver" + depends on ARCH_AIROHA || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Say Y here to add support for Airoha PCIe PHY driver. + This driver create the basic PHY instance and provides initialize + callback for PCIe GEN3 port. + +config PHY_CAN_TRANSCEIVER + tristate "CAN transceiver PHY" + select GENERIC_PHY + select MULTIPLEXER + help + This option enables support for CAN transceivers as a PHY. This + driver provides function for putting the transceivers in various + functional modes using gpios and sets the attribute max link + rate, for CAN drivers. + config PHY_GOOGLE_USB tristate "Google Tensor SoC USB PHY driver" select GENERIC_PHY @@ -57,6 +77,18 @@ config PHY_GOOGLE_USB both of which are integrated with the DWC3 USB DRD controller. This driver currently supports USB high-speed. +config USB_LGM_PHY + tristate "INTEL Lightning Mountain USB PHY Driver" + depends on USB_SUPPORT + depends on X86 || COMPILE_TEST + select USB_PHY + select REGULATOR + select REGULATOR_FIXED_VOLTAGE + help + Enable this to support Intel DWC3 PHY USB phy. This driver provides + interface to interact with USB GEN-II and USB 3.x PHY that is part + of the Intel network SOC. + config PHY_LPC18XX_USB_OTG tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver" depends on OF && (ARCH_LPC18XX || COMPILE_TEST) @@ -68,6 +100,17 @@ config PHY_LPC18XX_USB_OTG This driver is need for USB0 support on LPC18xx/43xx and takes care of enabling and clock setup. +config PHY_NXP_PTN3222 + tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" + depends on I2C + depends on OF + select GENERIC_PHY + help + Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. + This redriver performs translation between eUSB2 and USB2 signalling + schemes. It supports all three USB 2.0 data rates: Low Speed, Full + Speed and High Speed. + config PHY_PISTACHIO_USB tristate "IMG Pistachio USB2.0 PHY driver" depends on MIPS || COMPILE_TEST @@ -90,69 +133,17 @@ config PHY_XGENE help This option enables support for APM X-Gene SoC multi-purpose PHY. -config USB_LGM_PHY - tristate "INTEL Lightning Mountain USB PHY Driver" - depends on USB_SUPPORT - depends on X86 || COMPILE_TEST - select USB_PHY - select REGULATOR - select REGULATOR_FIXED_VOLTAGE - help - Enable this to support Intel DWC3 PHY USB phy. This driver provides - interface to interact with USB GEN-II and USB 3.x PHY that is part - of the Intel network SOC. - -config PHY_CAN_TRANSCEIVER - tristate "CAN transceiver PHY" - select GENERIC_PHY - select MULTIPLEXER - help - This option enables support for CAN transceivers as a PHY. This - driver provides function for putting the transceivers in various - functional modes using gpios and sets the attribute max link - rate, for CAN drivers. - -config PHY_AIROHA_PCIE - tristate "Airoha PCIe-PHY Driver" - depends on ARCH_AIROHA || COMPILE_TEST - depends on OF - select GENERIC_PHY - help - Say Y here to add support for Airoha PCIe PHY driver. - This driver create the basic PHY instance and provides initialize - callback for PCIe GEN3 port. - -config PHY_NXP_PTN3222 - tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" - depends on I2C - depends on OF - select GENERIC_PHY - help - Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. - This redriver performs translation between eUSB2 and USB2 signalling - schemes. It supports all three USB 2.0 data rates: Low Speed, Full - Speed and High Speed. - -config PHY_SPACEMIT_K1_PCIE - tristate "PCIe and combo PHY driver for the SpacemiT K1 SoC" - depends on ARCH_SPACEMIT || COMPILE_TEST - depends on COMMON_CLK - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - default ARCH_SPACEMIT - help - Enable support for the PCIe and USB 3 combo PHY and two - PCIe-only PHYs used in the SpacemiT K1 SoC. - source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/apple/Kconfig" source "drivers/phy/broadcom/Kconfig" source "drivers/phy/cadence/Kconfig" +source "drivers/phy/canaan/Kconfig" +source "drivers/phy/eswin/Kconfig" source "drivers/phy/freescale/Kconfig" source "drivers/phy/hisilicon/Kconfig" source "drivers/phy/ingenic/Kconfig" +source "drivers/phy/intel/Kconfig" source "drivers/phy/lantiq/Kconfig" source "drivers/phy/marvell/Kconfig" source "drivers/phy/mediatek/Kconfig" @@ -174,7 +165,6 @@ source "drivers/phy/starfive/Kconfig" source "drivers/phy/sunplus/Kconfig" source "drivers/phy/tegra/Kconfig" source "drivers/phy/ti/Kconfig" -source "drivers/phy/intel/Kconfig" source "drivers/phy/xilinx/Kconfig" endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index a648c2e02a83..f49d83f00a3d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -7,21 +7,23 @@ obj-$(CONFIG_PHY_COMMON_PROPS) += phy-common-props.o obj-$(CONFIG_PHY_COMMON_PROPS_TEST) += phy-common-props-test.o obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o +obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o +obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o -obj-$(CONFIG_PHY_XGENE) += phy-xgene.o +obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o -obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o -obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o -obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o -obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-spacemit-k1-pcie.o +obj-$(CONFIG_PHY_XGENE) += phy-xgene.o + obj-$(CONFIG_GENERIC_PHY) += allwinner/ \ amlogic/ \ apple/ \ broadcom/ \ cadence/ \ + canaan/ \ + eswin/ \ freescale/ \ hisilicon/ \ ingenic/ \ diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c index dc867f368b68..e9d106f135c5 100644 --- a/drivers/phy/apple/atc.c +++ b/drivers/phy/apple/atc.c @@ -2023,7 +2023,7 @@ static int atcphy_dwc3_reset_deassert(struct reset_controller_dev *rcdev, unsign return 0; } -const struct reset_control_ops atcphy_dwc3_reset_ops = { +static const struct reset_control_ops atcphy_dwc3_reset_ops = { .assert = atcphy_dwc3_reset_assert, .deassert = atcphy_dwc3_reset_deassert, }; @@ -2202,14 +2202,16 @@ static int atcphy_map_resources(struct platform_device *pdev, struct apple_atcph { "pipehandler", &atcphy->regs.pipehandler, NULL }, }; struct resource *res; + void __iomem *addr; for (int i = 0; i < ARRAY_SIZE(resources); i++) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resources[i].name); - *resources[i].addr = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(resources[i].addr)) - return dev_err_probe(atcphy->dev, PTR_ERR(resources[i].addr), + addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(addr)) + return dev_err_probe(atcphy->dev, PTR_ERR(addr), "Unable to map %s regs", resources[i].name); + *resources[i].addr = addr; if (resources[i].res) *resources[i].res = res; } diff --git a/drivers/phy/canaan/Kconfig b/drivers/phy/canaan/Kconfig new file mode 100644 index 000000000000..1ff8831846d5 --- /dev/null +++ b/drivers/phy/canaan/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Phy drivers for Canaan platforms +# +config PHY_CANAAN_USB + tristate "Canaan USB2 PHY Driver" + depends on (ARCH_CANAAN || COMPILE_TEST) && OF + select GENERIC_PHY + help + Enable this driver to support the USB 2.0 PHY controller + on Canaan K230 RISC-V SoCs. This PHY controller + provides physical layer functionality for USB 2.0 devices. + If you have a Canaan K230 board and need USB 2.0 support, + say Y or M here. diff --git a/drivers/phy/canaan/Makefile b/drivers/phy/canaan/Makefile new file mode 100644 index 000000000000..d73857ba284e --- /dev/null +++ b/drivers/phy/canaan/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_CANAAN_USB) += phy-k230-usb.o diff --git a/drivers/phy/canaan/phy-k230-usb.c b/drivers/phy/canaan/phy-k230-usb.c new file mode 100644 index 000000000000..52dad35fc6cf --- /dev/null +++ b/drivers/phy/canaan/phy-k230-usb.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Canaan usb PHY driver + * + * Copyright (C) 2026 Jiayu Du + */ + +#include +#include +#include +#include +#include + +#define MAX_PHYS 2 + +/* Register offsets within the HiSysConfig system controller */ +#define K230_USB0_TEST_REG_BASE 0x70 +#define K230_USB0_CTL_REG_BASE 0xb0 +#define K230_USB1_TEST_REG_BASE 0x90 +#define K230_USB1_CTL_REG_BASE 0xb8 + +/* Relative offsets within each PHY's control/test block */ +#define CTL0_OFFSET 0x00 +#define CTL1_OFFSET 0x04 +#define TEST_CTL3_OFFSET 0x0c + +/* Bit definitions for TEST_CTL3 */ +#define USB_IDPULLUP0 BIT(4) +#define USB_DMPULLDOWN0 BIT(8) +#define USB_DPPULLDOWN0 BIT(9) + +/* USB control register 0 in HiSysConfig system controller */ +/* PLL Integral Path Tune */ +#define USB_CTL0_PLLITUNE_MASK GENMASK(23, 22) + +/* PLL Proportional Path Tune */ +#define USB_CTL0_PLLPTUNE_MASK GENMASK(21, 18) + +/* PLL Bandwidth Adjustment */ +#define USB_CTL0_PLLBTUNE_MASK GENMASK(17, 17) + +/* VReg18 Bypass Control */ +#define USB_CTL0_VREGBYPASS_MASK GENMASK(16, 16) + +/* Retention Mode Enable */ +#define USB_CTL0_RETENABLEN_MASK GENMASK(15, 15) + +/* Reserved Request Input */ +#define USB_CTL0_RESREQIN_MASK GENMASK(14, 14) + +/* External VBUS Valid Select */ +#define USB_CTL0_VBUSVLDEXTSEL0_MASK GENMASK(13, 13) + +/* OTG Block Disable Control */ +#define USB_CTL0_OTGDISABLE0_MASK GENMASK(12, 12) + +/* Drive VBUS Enable */ +#define USB_CTL0_DRVVBUS0_MASK GENMASK(11, 11) + +/* Autoresume Mode Enable */ +#define USB_CTL0_AUTORSMENB0_MASK GENMASK(10, 10) + +/* HS Transceiver Asynchronous Control */ +#define USB_CTL0_HSXCVREXTCTL0_MASK GENMASK(9, 9) + +/* USB 1.1 Transmit Data */ +#define USB_CTL0_FSDATAEXT0_MASK GENMASK(8, 8) + +/* USB 1.1 SE0 Generation */ +#define USB_CTL0_FSSE0EXT0_MASK GENMASK(7, 7) + +/* USB 1.1 Data Enable */ +#define USB_CTL0_TXENABLEN0_MASK GENMASK(6, 6) + +/* Disconnect Threshold */ +#define USB_CTL0_COMPDISTUNE0_MASK GENMASK(5, 3) + +/* Squelch Threshold */ +#define USB_CTL0_SQRXTUNE0_MASK GENMASK(2, 0) + +/* USB control register 1 in HiSysConfig system controller */ +/* Data Detect Voltage */ +#define USB_CTL1_VDATREFTUNE0_MASK GENMASK(23, 22) + +/* VBUS Valid Threshold */ +#define USB_CTL1_OTGTUNE0_MASK GENMASK(21, 19) + +/* Transmitter High-Speed Crossover */ +#define USB_CTL1_TXHSXVTUNE0_MASK GENMASK(18, 17) + +/* FS/LS Source Impedance */ +#define USB_CTL1_TXFSLSTUNE0_MASK GENMASK(16, 13) + +/* HS DC Voltage Level */ +#define USB_CTL1_TXVREFTUNE0_MASK GENMASK(12, 9) + +/* HS Transmitter Rise/Fall Time */ +#define USB_CTL1_TXRISETUNE0_MASK GENMASK(8, 7) + +/* USB Source Impedance */ +#define USB_CTL1_TXRESTUNE0_MASK GENMASK(6, 5) + +/* HS Transmitter Pre-Emphasis Current Control */ +#define USB_CTL1_TXPREEMPAMPTUNE0_MASK GENMASK(4, 3) + +/* HS Transmitter Pre-Emphasis Duration Control */ +#define USB_CTL1_TXPREEMPPULSETUNE0_MASK GENMASK(2, 2) + +/* charging detection */ +#define USB_CTL1_CHRGSRCPUENB0_MASK GENMASK(1, 0) + +#define K230_PHY_CTL0_VAL \ +( \ + FIELD_PREP(USB_CTL0_PLLITUNE_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_PLLPTUNE_MASK, 0xc) | \ + FIELD_PREP(USB_CTL0_PLLBTUNE_MASK, 0x1) | \ + FIELD_PREP(USB_CTL0_VREGBYPASS_MASK, 0x1) | \ + FIELD_PREP(USB_CTL0_RETENABLEN_MASK, 0x1) | \ + FIELD_PREP(USB_CTL0_RESREQIN_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_VBUSVLDEXTSEL0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_OTGDISABLE0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_DRVVBUS0_MASK, 0x1) | \ + FIELD_PREP(USB_CTL0_AUTORSMENB0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_HSXCVREXTCTL0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_FSDATAEXT0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_FSSE0EXT0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_TXENABLEN0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL0_COMPDISTUNE0_MASK, 0x3) | \ + FIELD_PREP(USB_CTL0_SQRXTUNE0_MASK, 0x3) \ +) + +#define K230_PHY_CTL1_VAL \ +( \ + FIELD_PREP(USB_CTL1_VDATREFTUNE0_MASK, 0x1) | \ + FIELD_PREP(USB_CTL1_OTGTUNE0_MASK, 0x3) | \ + FIELD_PREP(USB_CTL1_TXHSXVTUNE0_MASK, 0x3) | \ + FIELD_PREP(USB_CTL1_TXFSLSTUNE0_MASK, 0x3) | \ + FIELD_PREP(USB_CTL1_TXVREFTUNE0_MASK, 0x3) | \ + FIELD_PREP(USB_CTL1_TXRISETUNE0_MASK, 0x1) | \ + FIELD_PREP(USB_CTL1_TXRESTUNE0_MASK, 0x1) | \ + FIELD_PREP(USB_CTL1_TXPREEMPAMPTUNE0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL1_TXPREEMPPULSETUNE0_MASK, 0x0) | \ + FIELD_PREP(USB_CTL1_CHRGSRCPUENB0_MASK, 0x0) \ +) + +struct k230_usb_phy_instance { + struct k230_usb_phy_global *global; + struct phy *phy; + u32 test_offset; + u32 ctl_offset; + int index; +}; + +struct k230_usb_phy_global { + struct k230_usb_phy_instance phys[MAX_PHYS]; + void __iomem *base; +}; + +static int k230_usb_phy_power_on(struct phy *phy) +{ + struct k230_usb_phy_instance *inst = phy_get_drvdata(phy); + struct k230_usb_phy_global *global = inst->global; + void __iomem *base = global->base; + u32 val; + + /* Apply recommended settings */ + writel(K230_PHY_CTL0_VAL, base + inst->ctl_offset + CTL0_OFFSET); + writel(K230_PHY_CTL1_VAL, base + inst->ctl_offset + CTL1_OFFSET); + + /* Configure test register (pull-ups/pull-downs) */ + val = readl(base + inst->test_offset + TEST_CTL3_OFFSET); + val |= USB_IDPULLUP0; + + if (inst->index == 1) + val |= (USB_DMPULLDOWN0 | USB_DPPULLDOWN0); + else + val &= ~(USB_DMPULLDOWN0 | USB_DPPULLDOWN0); + + writel(val, base + inst->test_offset + TEST_CTL3_OFFSET); + + return 0; +} + +static int k230_usb_phy_power_off(struct phy *phy) +{ + struct k230_usb_phy_instance *inst = phy_get_drvdata(phy); + struct k230_usb_phy_global *global = inst->global; + void __iomem *base = global->base; + u32 val; + + val = readl(base + inst->test_offset + TEST_CTL3_OFFSET); + val &= ~(USB_DMPULLDOWN0 | USB_DPPULLDOWN0); + writel(val, base + inst->test_offset + TEST_CTL3_OFFSET); + + return 0; +} + +static const struct phy_ops k230_usb_phy_ops = { + .power_on = k230_usb_phy_power_on, + .power_off = k230_usb_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct phy *k230_usb_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct k230_usb_phy_global *global = dev_get_drvdata(dev); + unsigned int idx = args->args[0]; + + if (idx >= MAX_PHYS) + return ERR_PTR(-EINVAL); + + return global->phys[idx].phy; +} + +static int k230_usb_phy_probe(struct platform_device *pdev) +{ + struct k230_usb_phy_global *global; + struct device *dev = &pdev->dev; + struct phy_provider *provider; + int i; + + global = devm_kzalloc(dev, sizeof(*global), GFP_KERNEL); + if (!global) + return -ENOMEM; + dev_set_drvdata(dev, global); + + global->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(global->base)) + return dev_err_probe(dev, PTR_ERR(global->base), + "failed to map registers\n"); + + static const struct { + u32 test_offset; + u32 ctl_offset; + } phy_reg_info[MAX_PHYS] = { + [0] = { K230_USB0_TEST_REG_BASE, K230_USB0_CTL_REG_BASE }, + [1] = { K230_USB1_TEST_REG_BASE, K230_USB1_CTL_REG_BASE }, + }; + + for (i = 0; i < MAX_PHYS; i++) { + struct k230_usb_phy_instance *inst = &global->phys[i]; + struct phy *phy; + + inst->global = global; + inst->index = i; + inst->test_offset = phy_reg_info[i].test_offset; + inst->ctl_offset = phy_reg_info[i].ctl_offset; + + phy = devm_phy_create(dev, NULL, &k230_usb_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy%d\n", i); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, inst); + inst->phy = phy; + } + + provider = devm_of_phy_provider_register(dev, k230_usb_phy_xlate); + if (IS_ERR(provider)) + return PTR_ERR(provider); + + return 0; +} + +static const struct of_device_id k230_usb_phy_of_match[] = { + { .compatible = "canaan,k230-usb-phy" }, + {} +}; +MODULE_DEVICE_TABLE(of, k230_usb_phy_of_match); + +static struct platform_driver k230_usb_phy_driver = { + .probe = k230_usb_phy_probe, + .driver = { + .name = "k230-usb-phy", + .of_match_table = k230_usb_phy_of_match, + }, +}; +module_platform_driver(k230_usb_phy_driver); + +MODULE_DESCRIPTION("Canaan Kendryte K230 USB 2.0 PHY driver"); +MODULE_AUTHOR("Jiayu Du "); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/eswin/Kconfig b/drivers/phy/eswin/Kconfig new file mode 100644 index 000000000000..cf2bf2efc32f --- /dev/null +++ b/drivers/phy/eswin/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Phy drivers for ESWIN platforms +# +config PHY_EIC7700_SATA + tristate "eic7700 Sata SerDes/PHY driver" + depends on ARCH_ESWIN || COMPILE_TEST + depends on HAS_IOMEM + select GENERIC_PHY + help + Enable this to support SerDes/Phy found on ESWIN's + EIC7700 SoC. This Phy supports SATA 1.5 Gb/s, + SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. + It supports one SATA host port to accept one SATA device. diff --git a/drivers/phy/eswin/Makefile b/drivers/phy/eswin/Makefile new file mode 100644 index 000000000000..db08c66be812 --- /dev/null +++ b/drivers/phy/eswin/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_EIC7700_SATA) += phy-eic7700-sata.o diff --git a/drivers/phy/eswin/phy-eic7700-sata.c b/drivers/phy/eswin/phy-eic7700-sata.c new file mode 100644 index 000000000000..c33653d48daa --- /dev/null +++ b/drivers/phy/eswin/phy-eic7700-sata.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN SATA PHY driver + * + * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd.. + * All rights reserved. + * + * Authors: Yulin Lu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SATA_AXI_LP_CTRL 0x08 +#define SATA_MPLL_CTRL 0x20 +#define SATA_P0_PHY_STAT 0x24 +#define SATA_PHY_CTRL0 0x28 +#define SATA_PHY_CTRL1 0x2c +#define SATA_REF_CTRL 0x34 +#define SATA_REF_CTRL1 0x38 +#define SATA_LOS_IDEN 0x3c + +#define SATA_CLK_RST_SOURCE_PHY BIT(0) +#define SATA_P0_PHY_TX_AMPLITUDE_GEN1_MASK GENMASK(6, 0) +#define SATA_P0_PHY_TX_AMPLITUDE_GEN1_DEFAULT 0x42 +#define SATA_P0_PHY_TX_AMPLITUDE_GEN2_MASK GENMASK(14, 8) +#define SATA_P0_PHY_TX_AMPLITUDE_GEN2_DEFAULT 0x46 +#define SATA_P0_PHY_TX_AMPLITUDE_GEN3_MASK GENMASK(22, 16) +#define SATA_P0_PHY_TX_AMPLITUDE_GEN3_DEFAULT 0x73 +#define SATA_P0_PHY_TX_PREEMPH_GEN1_MASK GENMASK(5, 0) +#define SATA_P0_PHY_TX_PREEMPH_GEN1_DEFAULT 0x5 +#define SATA_P0_PHY_TX_PREEMPH_GEN2_MASK GENMASK(13, 8) +#define SATA_P0_PHY_TX_PREEMPH_GEN2_DEFAULT 0x5 +#define SATA_P0_PHY_TX_PREEMPH_GEN3_MASK GENMASK(21, 16) +#define SATA_P0_PHY_TX_PREEMPH_GEN3_DEFAULT 0x23 +#define SATA_LOS_LEVEL_MASK GENMASK(4, 0) +#define SATA_LOS_BIAS_MASK GENMASK(18, 16) +#define SATA_M_CSYSREQ BIT(0) +#define SATA_S_CSYSREQ BIT(16) +#define SATA_REF_REPEATCLK_EN BIT(0) +#define SATA_REF_USE_PAD BIT(20) +#define SATA_MPLL_MULTIPLIER_MASK GENMASK(22, 16) +#define SATA_P0_PHY_READY BIT(0) + +#define PLL_LOCK_SLEEP_US 10 +#define PLL_LOCK_TIMEOUT_US 1000 + +struct eic7700_sata_phy { + u32 tx_amplitude_tuning_val[3]; + u32 tx_preemph_tuning_val[3]; + struct reset_control *rst; + struct regmap *regmap; + struct clk *clk; + struct phy *phy; +}; + +static const struct regmap_config eic7700_sata_phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = SATA_LOS_IDEN, +}; + +static int wait_for_phy_ready(struct regmap *regmap, u32 reg, u32 checkbit, + u32 status) +{ + u32 val; + int ret; + + ret = regmap_read_poll_timeout(regmap, reg, val, + (val & checkbit) == status, + PLL_LOCK_SLEEP_US, PLL_LOCK_TIMEOUT_US); + + return ret; +} + +static int eic7700_sata_phy_init(struct phy *phy) +{ + struct eic7700_sata_phy *sata_phy = phy_get_drvdata(phy); + u32 val; + int ret; + + ret = clk_prepare_enable(sata_phy->clk); + if (ret) + return ret; + + regmap_write(sata_phy->regmap, SATA_REF_CTRL1, SATA_CLK_RST_SOURCE_PHY); + + val = FIELD_PREP(SATA_P0_PHY_TX_AMPLITUDE_GEN1_MASK, + sata_phy->tx_amplitude_tuning_val[0]) | + FIELD_PREP(SATA_P0_PHY_TX_AMPLITUDE_GEN2_MASK, + sata_phy->tx_amplitude_tuning_val[1]) | + FIELD_PREP(SATA_P0_PHY_TX_AMPLITUDE_GEN3_MASK, + sata_phy->tx_amplitude_tuning_val[2]); + regmap_write(sata_phy->regmap, SATA_PHY_CTRL0, val); + + val = FIELD_PREP(SATA_P0_PHY_TX_PREEMPH_GEN1_MASK, + sata_phy->tx_preemph_tuning_val[0]) | + FIELD_PREP(SATA_P0_PHY_TX_PREEMPH_GEN2_MASK, + sata_phy->tx_preemph_tuning_val[1]) | + FIELD_PREP(SATA_P0_PHY_TX_PREEMPH_GEN3_MASK, + sata_phy->tx_preemph_tuning_val[2]); + regmap_write(sata_phy->regmap, SATA_PHY_CTRL1, val); + + val = FIELD_PREP(SATA_LOS_LEVEL_MASK, 0x9) | + FIELD_PREP(SATA_LOS_BIAS_MASK, 0x2); + regmap_write(sata_phy->regmap, SATA_LOS_IDEN, val); + + val = SATA_M_CSYSREQ | SATA_S_CSYSREQ; + regmap_write(sata_phy->regmap, SATA_AXI_LP_CTRL, val); + + val = SATA_REF_REPEATCLK_EN | SATA_REF_USE_PAD; + regmap_write(sata_phy->regmap, SATA_REF_CTRL, val); + + val = FIELD_PREP(SATA_MPLL_MULTIPLIER_MASK, 0x3c); + regmap_write(sata_phy->regmap, SATA_MPLL_CTRL, val); + + usleep_range(15, 20); + + ret = reset_control_deassert(sata_phy->rst); + if (ret) + goto disable_clk; + + ret = wait_for_phy_ready(sata_phy->regmap, SATA_P0_PHY_STAT, + SATA_P0_PHY_READY, 1); + if (ret < 0) { + dev_err(&sata_phy->phy->dev, "PHY READY check failed\n"); + goto disable_clk; + } + + return 0; + +disable_clk: + clk_disable_unprepare(sata_phy->clk); + return ret; +} + +static int eic7700_sata_phy_exit(struct phy *phy) +{ + struct eic7700_sata_phy *sata_phy = phy_get_drvdata(phy); + int ret; + + ret = reset_control_assert(sata_phy->rst); + if (ret) + return ret; + + clk_disable_unprepare(sata_phy->clk); + + return 0; +} + +static const struct phy_ops eic7700_sata_phy_ops = { + .init = eic7700_sata_phy_init, + .exit = eic7700_sata_phy_exit, + .owner = THIS_MODULE, +}; + +static void eic7700_get_tuning_param(struct device_node *np, + struct eic7700_sata_phy *sata_phy) +{ + if (of_property_read_u32_array + (np, "eswin,tx-amplitude-tuning", + sata_phy->tx_amplitude_tuning_val, + ARRAY_SIZE(sata_phy->tx_amplitude_tuning_val))) { + sata_phy->tx_amplitude_tuning_val[0] = + SATA_P0_PHY_TX_AMPLITUDE_GEN1_DEFAULT; + sata_phy->tx_amplitude_tuning_val[1] = + SATA_P0_PHY_TX_AMPLITUDE_GEN2_DEFAULT; + sata_phy->tx_amplitude_tuning_val[2] = + SATA_P0_PHY_TX_AMPLITUDE_GEN3_DEFAULT; + } + + if (of_property_read_u32_array + (np, "eswin,tx-preemph-tuning", + sata_phy->tx_preemph_tuning_val, + ARRAY_SIZE(sata_phy->tx_preemph_tuning_val))) { + sata_phy->tx_preemph_tuning_val[0] = + SATA_P0_PHY_TX_PREEMPH_GEN1_DEFAULT; + sata_phy->tx_preemph_tuning_val[1] = + SATA_P0_PHY_TX_PREEMPH_GEN2_DEFAULT; + sata_phy->tx_preemph_tuning_val[2] = + SATA_P0_PHY_TX_PREEMPH_GEN3_DEFAULT; + } +} + +static int eic7700_sata_phy_probe(struct platform_device *pdev) +{ + struct eic7700_sata_phy *sata_phy; + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + void __iomem *regs; + + sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL); + if (!sata_phy) + return -ENOMEM; + + /* + * Map the I/O resource with platform_get_resource and devm_ioremap + * instead of the devm_platform_ioremap_resource API, because the + * address region of the SATA-PHY falls into the region of the HSP + * clock & reset that has already been obtained by the HSP + * clock-and-reset driver. + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + regs = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + sata_phy->regmap = devm_regmap_init_mmio + (dev, regs, &eic7700_sata_phy_regmap_config); + if (IS_ERR(sata_phy->regmap)) + return dev_err_probe(dev, PTR_ERR(sata_phy->regmap), + "failed to init regmap\n"); + + dev_set_drvdata(dev, sata_phy); + + eic7700_get_tuning_param(np, sata_phy); + + sata_phy->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(sata_phy->clk)) + return PTR_ERR(sata_phy->clk); + + sata_phy->rst = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(sata_phy->rst)) + return dev_err_probe(dev, PTR_ERR(sata_phy->rst), + "failed to get reset control\n"); + + sata_phy->phy = devm_phy_create(dev, NULL, &eic7700_sata_phy_ops); + if (IS_ERR(sata_phy->phy)) + return dev_err_probe(dev, PTR_ERR(sata_phy->phy), + "failed to create PHY\n"); + + phy_set_drvdata(sata_phy->phy, sata_phy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return dev_err_probe(dev, PTR_ERR(phy_provider), + "failed to register PHY provider\n"); + + return 0; +} + +static const struct of_device_id eic7700_sata_phy_of_match[] = { + { .compatible = "eswin,eic7700-sata-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, eic7700_sata_phy_of_match); + +static struct platform_driver eic7700_sata_phy_driver = { + .probe = eic7700_sata_phy_probe, + .driver = { + .of_match_table = eic7700_sata_phy_of_match, + .name = "eic7700-sata-phy", + } +}; +module_platform_driver(eic7700_sata_phy_driver); + +MODULE_DESCRIPTION("SATA PHY driver for the ESWIN EIC7700 SoC"); +MODULE_AUTHOR("Yulin Lu "); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/marvell/phy-mmp3-hsic.c b/drivers/phy/marvell/phy-mmp3-hsic.c index 271f1a2258ef..72ab6da0ebc3 100644 --- a/drivers/phy/marvell/phy-mmp3-hsic.c +++ b/drivers/phy/marvell/phy-mmp3-hsic.c @@ -14,15 +14,19 @@ #define HSIC_ENABLE BIT(7) #define PLL_BYPASS BIT(4) +struct mmp3_hsic_data { + void __iomem *base; +}; + static int mmp3_hsic_phy_init(struct phy *phy) { - void __iomem *base = (void __iomem *)phy_get_drvdata(phy); + struct mmp3_hsic_data *mmp3 = phy_get_drvdata(phy); u32 hsic_ctrl; - hsic_ctrl = readl_relaxed(base + HSIC_CTRL); + hsic_ctrl = readl_relaxed(mmp3->base + HSIC_CTRL); hsic_ctrl |= HSIC_ENABLE; hsic_ctrl |= PLL_BYPASS; - writel_relaxed(hsic_ctrl, base + HSIC_CTRL); + writel_relaxed(hsic_ctrl, mmp3->base + HSIC_CTRL); return 0; } @@ -41,13 +45,17 @@ MODULE_DEVICE_TABLE(of, mmp3_hsic_phy_of_match); static int mmp3_hsic_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct mmp3_hsic_data *mmp3; struct phy_provider *provider; - void __iomem *base; struct phy *phy; - base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(base)) - return PTR_ERR(base); + mmp3 = devm_kzalloc(dev, sizeof(*mmp3), GFP_KERNEL); + if (!mmp3) + return -ENOMEM; + + mmp3->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(mmp3->base)) + return PTR_ERR(mmp3->base); phy = devm_phy_create(dev, NULL, &mmp3_hsic_phy_ops); if (IS_ERR(phy)) { @@ -55,7 +63,7 @@ static int mmp3_hsic_phy_probe(struct platform_device *pdev) return PTR_ERR(phy); } - phy_set_drvdata(phy, (void *)base); + phy_set_drvdata(phy, mmp3); provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (IS_ERR(provider)) { dev_err(dev, "failed to register PHY provider\n"); diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index f6504e0ecd1a..acf506529507 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -276,14 +276,14 @@ enum mtk_phy_version { }; /** - * mtk_phy_pdata - SoC specific platform data + * struct mtk_phy_pdata - SoC specific platform data * @avoid_rx_sen_degradation: Avoid TX Sensitivity level degradation (MT6795/8173 only) * @sw_pll_48m_to_26m: Workaround for V3 IP (MT8195) - switch the 48MHz PLL from * fractional mode to integer to output 26MHz for U2PHY * @sw_efuse_supported: Switches off eFuse auto-load from PHY and applies values * read from different nvmem (usually different eFuse array) * that is pointed at in the device tree node for this PHY - * @slew_ref_clk_mhz: Default reference clock (in MHz) for slew rate calibration + * @slew_ref_clock_mhz: Default reference clock (in MHz) for slew rate calibration * @slew_rate_coefficient: Coefficient for slew rate calibration * @version: PHY IP Version */ diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c index 95cd3175926d..68f1ba8fec4a 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -83,7 +83,7 @@ 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_CFG1, PLL_EN, 0), M31_EUSB_PHY_INIT_CFG(USB_PHY_FSEL_SEL, FSEL_SEL, 1), }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c index 14feb77789b3..c342479a3798 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -1679,7 +1679,7 @@ static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_node *np if (ret) return ret; - if (qmp->dp_serdes != 0) { + if (qmp->dp_serdes) { ret = phy_dp_clks_register(qmp, np); if (ret) return ret; @@ -1833,7 +1833,7 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) if (IS_ERR(base)) return PTR_ERR(base); - if (offs->dp_serdes != 0) { + if (offs->dp_serdes) { qmp->dp_serdes = base + offs->dp_serdes; qmp->dp_tx = base + offs->dp_txa; qmp->dp_tx2 = base + offs->dp_txb; @@ -1982,7 +1982,7 @@ static int qmp_usbc_probe(struct platform_device *pdev) phy_set_drvdata(qmp->usb_phy, qmp); - if (qmp->dp_serdes != 0) { + if (qmp->dp_serdes) { qmp->dp_phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops); if (IS_ERR(qmp->dp_phy)) { ret = PTR_ERR(qmp->dp_phy); diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig index 0136aee2e8a2..50b0005acf66 100644 --- a/drivers/phy/spacemit/Kconfig +++ b/drivers/phy/spacemit/Kconfig @@ -2,6 +2,18 @@ # # Phy drivers for SpacemiT platforms # +config PHY_SPACEMIT_K1_PCIE + tristate "PCIe and combo PHY driver for the SpacemiT K1 SoC" + depends on ARCH_SPACEMIT || COMPILE_TEST + depends on COMMON_CLK + depends on HAS_IOMEM + depends on OF + select GENERIC_PHY + default ARCH_SPACEMIT + help + Enable support for the PCIe and USB 3 combo PHY and two + PCIe-only PHYs used in the SpacemiT K1 SoC. + config PHY_SPACEMIT_K1_USB2 tristate "SpacemiT K1 USB 2.0 PHY support" depends on (ARCH_SPACEMIT || COMPILE_TEST) && OF diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile index fec0b425a948..a821a21d6142 100644 --- a/drivers/phy/spacemit/Makefile +++ b/drivers/phy/spacemit/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-k1-pcie.o obj-$(CONFIG_PHY_SPACEMIT_K1_USB2) += phy-k1-usb2.o diff --git a/drivers/phy/phy-spacemit-k1-pcie.c b/drivers/phy/spacemit/phy-k1-pcie.c similarity index 100% rename from drivers/phy/phy-spacemit-k1-pcie.c rename to drivers/phy/spacemit/phy-k1-pcie.c