From: Daniil Gnusarev <gnusarevda@basealt.ru> To: devel-kernel@lists.altlinux.org Subject: [d-kernel] [PATCH 03/39] USB: Add support for Baikal USB PHY Date: Mon, 14 Oct 2024 18:01:44 +0400 Message-ID: <20241014140221.535985-4-gnusarevda@basealt.ru> (raw) In-Reply-To: <20241014140221.535985-1-gnusarevda@basealt.ru> Add support for USB PHY for Baikal BE-M1000 with firmware from SDK-ARM64-2403-6.6 Signed-off-by: Daniil Gnusarev <gnusarevda@basealt.ru> Co-developed-by: Baikal Electronics <info@baikalelectronics.ru> --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/baikal/Kconfig | 10 + drivers/phy/baikal/Makefile | 3 + drivers/phy/baikal/baikal-usb-phy.c | 305 ++++++++++++++++++++++++++++ 5 files changed, 320 insertions(+) create mode 100644 drivers/phy/baikal/Kconfig create mode 100644 drivers/phy/baikal/Makefile create mode 100644 drivers/phy/baikal/baikal-usb-phy.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e4502958fd62d..b590354e7f66c 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -74,6 +74,7 @@ config PHY_CAN_TRANSCEIVER source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" +source "drivers/phy/baikal/Kconfig" source "drivers/phy/broadcom/Kconfig" source "drivers/phy/cadence/Kconfig" source "drivers/phy/freescale/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index fb3dc9de61115..624f6689d9f92 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-y += allwinner/ \ amlogic/ \ + baikal/ \ broadcom/ \ cadence/ \ freescale/ \ diff --git a/drivers/phy/baikal/Kconfig b/drivers/phy/baikal/Kconfig new file mode 100644 index 0000000000000..b8b598d6019e1 --- /dev/null +++ b/drivers/phy/baikal/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config USB_PHY_BAIKAL + tristate "Baikal USB PHY driver" + depends on USB_SUPPORT + select GENERIC_PHY + select USB_PHY + help + Enable this to support the USB PHY on Baikal SoCs. + This driver controls both the USB2 PHY and the USB3 PHY. \ No newline at end of file diff --git a/drivers/phy/baikal/Makefile b/drivers/phy/baikal/Makefile new file mode 100644 index 0000000000000..54fcd11988681 --- /dev/null +++ b/drivers/phy/baikal/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_USB_PHY_BAIKAL) += baikal-usb-phy.o diff --git a/drivers/phy/baikal/baikal-usb-phy.c b/drivers/phy/baikal/baikal-usb-phy.c new file mode 100644 index 0000000000000..72e7b747914d3 --- /dev/null +++ b/drivers/phy/baikal/baikal-usb-phy.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Baikal USB PHY driver + * + * Copyright (C) 2022-2023 Baikal Electronics, JSC + */ + +#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <dt-bindings/phy/phy.h> + +struct phy_baikal_desc { + struct phy *phy; + int index; + bool enable; +}; + +struct phy_baikal_priv { + struct phy_baikal_desc **phys; + int nphys; + struct clk_bulk_data *clocks; + unsigned int nclocks; +}; + +#ifdef CONFIG_ACPI +static int phy_baikal_acpi_get_info(struct fwnode_handle *fwnode, + bool *is_usb3, const char **ref_name) +{ + struct acpi_device *adev = to_acpi_device_node(fwnode); + struct acpi_device *ref_adev; + struct device *ref_dev; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int ret = 0; + + *is_usb3 = fwnode_property_read_bool(fwnode, "usb3"); + status = acpi_evaluate_object_typed(adev->handle, "CTRL", NULL, + &buffer, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + dev_err(&adev->dev, "failed to get CTRL data\n"); + return -ENODEV; + } + + obj = buffer.pointer; + if (obj->package.count != 1) { + dev_err(&adev->dev, "invalid CTRL data\n"); + ret = -EINVAL; + goto err; + } + + obj = &obj->package.elements[0]; + if (obj->type != ACPI_TYPE_LOCAL_REFERENCE || !obj->reference.handle) { + dev_err(&adev->dev, "invalid CTRL reference\n"); + ret = -EINVAL; + goto err; + } + + ref_adev = acpi_fetch_acpi_dev(obj->reference.handle); + if (!ref_adev) { + dev_err(&adev->dev, "failed to process CTRL reference\n"); + ret = -ENODEV; + goto err; + } + + ref_dev = bus_find_device_by_fwnode(&platform_bus_type, + acpi_fwnode_handle(ref_adev)); + if (!ref_dev) { + dev_err(&adev->dev, "failed to get referenced device\n"); + ret = -ENODEV; + goto err; + } + *ref_name = dev_name(ref_dev); + +err: + acpi_os_free(buffer.pointer); + return ret; +} + +static int phy_baikal_acpi_add(struct device *dev) +{ + struct phy_baikal_priv *priv = dev_get_drvdata(dev); + struct fwnode_handle *child; + const char **ref_name; + bool *is_usb3; + int count = 0, i, ret; + + ref_name = kcalloc(priv->nphys, sizeof(*ref_name), GFP_KERNEL); + if (!ref_name) + return -ENOMEM; + + is_usb3 = kcalloc(priv->nphys, sizeof(*is_usb3), GFP_KERNEL); + if (!is_usb3) { + kfree(ref_name); + return -ENOMEM; + } + + device_for_each_child_node(dev, child) { + ret = phy_baikal_acpi_get_info(child, &is_usb3[count], + &ref_name[count]); + if (ret) + goto err; + + ret = phy_create_lookup(priv->phys[count]->phy, + is_usb3[count] ? "usb3-phy" : "usb2-phy", + ref_name[count]); + if (ret) + goto err; + + ++count; + } + +err: + if (ret) { + for (i = 0; i < count; ++i) + phy_remove_lookup(priv->phys[i]->phy, + is_usb3[i] ? "usb3-phy" : "usb2-phy", + ref_name[i]); + } + + kfree(ref_name); + kfree(is_usb3); + return ret; +} + +static void phy_baikal_acpi_remove(struct device *dev) +{ + struct phy_baikal_priv *priv = dev_get_drvdata(dev); + struct fwnode_handle *child; + const char *ref_name; + bool is_usb3; + int i, ret; + + device_for_each_child_node(dev, child) { + ret = phy_baikal_acpi_get_info(child, &is_usb3, &ref_name); + if (ret) { + ++i; + continue; + } + + phy_remove_lookup(priv->phys[i++]->phy, + is_usb3 ? "usb3-phy" : "usb2-phy", + ref_name); + } +} + +static void phy_baikal_acpi_init_clk(struct phy_baikal_desc *desc) +{ + struct device *dev = desc->phy->dev.parent; + struct phy_baikal_priv *priv = dev_get_drvdata(dev); + struct fwnode_handle *child; + int i = 0; + + device_for_each_child_node(dev, child) { + if (i++ == desc->index) { + priv->clocks[2 * desc->index].clk = + devm_clk_get_optional(&to_acpi_device_node(child)->dev, "phy0_clk"); + priv->clocks[2 * desc->index + 1].clk = + devm_clk_get_optional(&to_acpi_device_node(child)->dev, "phy1_clk"); + break; + } + } +} +#else /* CONFIG_ACPI */ +static inline int phy_baikal_acpi_add(struct device *dev) +{ + return 0; +} + +static inline void phy_baikal_acpi_remove(struct device *dev) +{ +} + +static inline void phy_baikal_acpi_init_clk(struct phy_baikal_desc *desc) +{ +} +#endif + +static int phy_baikal_init(struct phy *phy) +{ + struct phy_baikal_priv *priv = dev_get_drvdata(phy->dev.parent); + struct phy_baikal_desc *desc = phy_get_drvdata(phy); + int n = 2 * desc->index; + + if (!acpi_disabled) + phy_baikal_acpi_init_clk(desc); + + if (desc->enable) { + clk_prepare_enable(priv->clocks[n + 0].clk); + clk_prepare_enable(priv->clocks[n + 1].clk); + return 0; + } else { + clk_disable_unprepare(priv->clocks[n + 0].clk); + clk_disable_unprepare(priv->clocks[n + 1].clk); + return -1; + } +} + +static const struct phy_ops phy_baikal_ops = { + .init = phy_baikal_init, + .owner = THIS_MODULE, +}; + +static struct phy *phy_baikal_xlate(struct device *dev, struct of_phandle_args *args) +{ + int i; + struct phy_baikal_priv *priv = dev_get_drvdata(dev); + + for (i = 0; i < priv->nphys; i++) { + if (priv->phys[i]->index == args->args[0]) + break; + } + + return priv->phys[i]->phy; +} + +static int phy_baikal_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fwnode_handle *child; + struct phy *phy; + struct phy_baikal_priv *priv; + struct phy_baikal_desc *phy_desc; + int index; + int i = 0; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->nphys = device_get_child_node_count(dev); + priv->phys = devm_kcalloc(dev, priv->nphys, sizeof(*priv->phys), GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + + if (acpi_disabled) { + priv->nclocks = devm_clk_bulk_get_all(dev, &priv->clocks); + } else { + priv->nclocks = 2 * priv->nphys; + priv->clocks = devm_kcalloc(dev, priv->nclocks, + sizeof(*priv->clocks), GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; + } + + dev_set_drvdata(dev, priv); + device_for_each_child_node(dev, child) { + fwnode_property_read_u32(child, "reg", &index); + phy = devm_phy_create(dev, NULL, &phy_baikal_ops); + if (!phy) + return -ENOMEM; + + phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL); + if (!phy_desc) + return -ENOMEM; + + phy_desc->phy = phy; + phy_desc->index = index; + phy_desc->enable = fwnode_property_read_bool(child, "enable"); + priv->phys[i++] = phy_desc; + phy_set_drvdata(phy, phy_desc); + } + + if (acpi_disabled) + return PTR_ERR_OR_ZERO(devm_of_phy_provider_register(dev, phy_baikal_xlate)); + else + return phy_baikal_acpi_add(dev); +} + +static int phy_baikal_remove(struct platform_device *pdev) +{ + if (!acpi_disabled) + phy_baikal_acpi_remove(&pdev->dev); + + return 0; +} + +static const struct of_device_id phy_baikal_table[] = { + { .compatible = "baikal,bm1000-usb-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, phy_baikal_table); + +static struct platform_driver phy_baikal_driver = { + .probe = phy_baikal_probe, + .remove = phy_baikal_remove, + .driver = { + .name = "baikal,bm1000-usb-phy", + .of_match_table = phy_baikal_table, + }, +}; +module_platform_driver(phy_baikal_driver); + +MODULE_DESCRIPTION("Baikal USB PHY driver"); +MODULE_LICENSE("GPL v2"); -- 2.42.2
next prev parent reply other threads:[~2024-10-14 14:01 UTC|newest] Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-10-14 14:01 [d-kernel] [PATCH 00/39] Support Baikal-M in un-def in p11 Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 01/39] Baikal Electronics SoC family Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 02/39] Clk: Add clock drivers for Baikal BE-M1000 with new firmware Daniil Gnusarev 2024-10-14 14:01 ` Daniil Gnusarev [this message] 2024-10-14 14:01 ` [d-kernel] [PATCH 04/39] PCI: Add support for PCIe controller for Baikal BE-M1000 Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 05/39] AHCI SATA: Add support " Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 06/39] UART: Add support for UART " Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 07/39] cpufreq-dt: don't load on Baikal-M SoC Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 08/39] Sound: add support for Baikal BE-M1000 I2S Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 09/39] sound: baikal-i2s: paper over RX overrun warnings on Baikal-M Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 10/39] net: stmmac: support of Baikal-BE1000 SoCs GMAC Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 11/39] net: fwnode_get_phy_id: consider all compatible strings Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 12/39] hwmon: bt1-pvt: access registers via pvt_{readl, writel} helpers Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 13/39] hwmon: bt1-pvt: define pvt_readl/pvt_writel for Baikal-M SoC Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 14/39] hwmon: bt1-pvt: adjusted probing " Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 15/39] hwmon: bt1-pvt: added compatible baikal, pvt Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 16/39] PVT: support register addressing with new firmware Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 17/39] drm: add Baikal-M SoC video display unit driver Daniil Gnusarev 2024-10-14 14:01 ` [d-kernel] [PATCH 18/39] drm/bridge: dw-hdmi: support ahb audio hw revision 0x2a Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 19/39] dt-bindings: dw-hdmi: added ahb-audio-regshift Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 20/39] drm/bridge: dw-hdmi: force ahb audio register offset for Baikal-M Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 21/39] drm/panfrost: forcibly set dma-coherent on Baikal-M Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 22/39] drm/panfrost: disable devfreq " Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 23/39] bmc: add board management controller driver Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 24/39] pm: disable all sleep states on Baikal-M based boards Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 25/39] sound: dwc-i2s: paper over RX overrun warnings on Baikal-M Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 26/39] sound: dwc-i2s: request all IRQs specified in device tree Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 27/39] usb: dwc3: of-simple: added compatible string for Baikal-M SoC Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 28/39] serial: 8250_dw: verify clock rate in dw8250_set_termios Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 29/39] clk: use "cmu-id" if there is no "reg" in devicetree Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 30/39] pci: baikal-pcie: driver compatibility with SDK earlier than 5.7 Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 31/39] pci: baikal-pcie: driver compatibility with SDK versions 5.4 Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 32/39] dw-pcie: refuse to load on Baikal-M with recent firmware Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 33/39] drm: baikal-vdu: driver compatibility with SDK earlier than 5.9 Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 34/39] input: new driver - serdev-serio Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 35/39] input: added TF307 serio PS/2 emulator driver Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 36/39] input: tp_serio: catch up API changes Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 37/39] drm: baikal-m: add vblank events, fix mode switching Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 38/39] drm: baikal-vdu: disable backlight driver loading Daniil Gnusarev 2024-10-14 14:02 ` [d-kernel] [PATCH 39/39] config-aarch64: enable more configs for baikal-m support Daniil Gnusarev 2024-10-14 14:28 ` [d-kernel] [PATCH 00/39] Support Baikal-M in un-def in p11 Vitaly Chikunov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20241014140221.535985-4-gnusarevda@basealt.ru \ --to=gnusarevda@basealt.ru \ --cc=devel-kernel@lists.altlinux.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
ALT Linux kernel packages development This inbox may be cloned and mirrored by anyone: git clone --mirror http://lore.altlinux.org/devel-kernel/0 devel-kernel/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 devel-kernel devel-kernel/ http://lore.altlinux.org/devel-kernel \ devel-kernel@altlinux.org devel-kernel@altlinux.ru devel-kernel@altlinux.com public-inbox-index devel-kernel Example config snippet for mirrors. Newsgroup available over NNTP: nntp://lore.altlinux.org/org.altlinux.lists.devel-kernel AGPL code for this site: git clone https://public-inbox.org/public-inbox.git