* [PATCH v3 2/2] usb: cdns3: Add USBSSP platform driver support
From: Peter Chen @ 2026-04-21 2:34 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, arnd, gregkh, pawell, rogerq
Cc: devicetree, linux-kernel, linux-usb, cix-kernel-upstream,
Peter Chen
In-Reply-To: <20260421023459.506145-1-peter.chen@cixtech.com>
Expose Cadence USBSSP through the same platform path as USBSS, trim
Kconfig and Makefile: one core loadable object plus separate glue .ko
files.
Single cdns.ko bundles core, DRD, the generic "cdns,usb3" platform
driver in cdns3-plat.c, optional host.o, and optional gadget objects.
Use CONFIG_USB_CDNS3_GADGET as a bool to compile gadget support into
that module. Remove duplicate MODULE_* declarations from cdns3-plat.c
now that it links into the same module.
Kconfig: the generic platform driver is selected via CONFIG_USB_CDNS3.
Move CONFIG_USB_CDNSP_PCI beside CONFIG_USB_CDNS3_PCI_WRAP under
"Platform glue driver support". SoC glue entries (TI, i.MX, StarFive)
depend only on CONFIG_USB_CDNS3.
Tighten CONFIG_USB_CDNS_SUPPORT dependencies so the umbrella follows
host or gadget when either is built as a module. Match host and gadget
bools to the cdns.ko tristate with USB=USB_CDNS3 and USB_GADGET=USB_CDNS3
instead of comparing against USB_CDNS_SUPPORT.
Link host.o when CONFIG_USB_CDNS3_HOST is enabled and use that symbol in
host-export.h, removing the redundant CONFIG_USB_CDNS_HOST indirection.
Export cdns_core_init_role and reorganize the function cdns_init, and
controller version could be gotten before the gadget init function is
decided per controller.
Keep host_init / gadget_init callbacks in struct cdns, so core.c does
not need direct linkage to host or gadget objects. Refactor cdnsp-pci.c
into a thin PCI-to-platform wrapper.
drivers/usb/Makefile: descend into drivers/usb/cdns3/ only when
CONFIG_USB_CDNS_SUPPORT is enabled.
Assisted-by: Cursor:claude-4.6-opus
Suggested-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Peter Chen <peter.chen@cixtech.com>
---
drivers/usb/Makefile | 2 -
drivers/usb/cdns3/Kconfig | 112 +++++++--------
drivers/usb/cdns3/Makefile | 44 +++---
drivers/usb/cdns3/cdns3-gadget.c | 1 +
drivers/usb/cdns3/cdns3-plat.c | 27 +++-
drivers/usb/cdns3/cdnsp-gadget.c | 1 +
drivers/usb/cdns3/cdnsp-pci.c | 217 +++++++++++++-----------------
drivers/usb/cdns3/core.c | 45 ++-----
drivers/usb/cdns3/core.h | 5 +-
drivers/usb/cdns3/gadget-export.h | 10 +-
drivers/usb/cdns3/host-export.h | 4 +-
11 files changed, 201 insertions(+), 267 deletions(-)
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 6f3c86149887..eecbd631fdab 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -14,8 +14,6 @@ obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns3/
-obj-$(CONFIG_USB_CDNS3) += cdns3/
-obj-$(CONFIG_USB_CDNSP_PCI) += cdns3/
obj-$(CONFIG_USB_FOTG210) += fotg210/
diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
index 0a514b591527..39ad23d1ada8 100644
--- a/drivers/usb/cdns3/Kconfig
+++ b/drivers/usb/cdns3/Kconfig
@@ -1,6 +1,9 @@
config USB_CDNS_SUPPORT
tristate "Cadence USB Support"
- depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA
+ depends on USB_SUPPORT && HAS_DMA
+ depends on USB || USB_GADGET
+ depends on USB if !USB_GADGET
+ depends on USB_GADGET if !USB
select USB_XHCI_PLATFORM if USB_XHCI_HCD
select USB_ROLE_SWITCH
help
@@ -8,44 +11,49 @@ config USB_CDNS_SUPPORT
dual-role controller.
It supports: dual-role switch, Host-only, and Peripheral-only.
-config USB_CDNS_HOST
- bool
-
if USB_CDNS_SUPPORT
config USB_CDNS3
- tristate "Cadence USB3 Dual-Role Controller"
+ tristate "Cadence USB dual-role controller (USBSS and USBSSP)"
depends on USB_CDNS_SUPPORT
help
- Say Y here if your system has a Cadence USB3 dual-role controller.
- It supports: dual-role switch, Host-only, and Peripheral-only.
+ Say Y or M here if your system has an on-chip Cadence USB
+ dual-role controller. This covers both USBSS (USB 3.0) and
+ USBSSP (SuperSpeed Plus) IP; the driver detects the variant at
+ runtime.
- If you choose to build this driver is a dynamically linked
- as module, the module will be called cdns3.ko.
-endif
+ The core driver (core, DRD, generic platform binding for the
+ "cdns,usb3" device tree compatible, optional host and gadget)
+ builds as one module named cdns.ko when built as a loadable
+ module.
+
+ It supports: dual-role switch, Host-only, and Peripheral-only.
if USB_CDNS3
-config USB_CDNS3_GADGET
- bool "Cadence USB3 device controller"
- depends on USB_GADGET=y || USB_GADGET=USB_CDNS3
+config USB_CDNS3_HOST
+ bool "Cadence USB host controller (xHCI)"
+ depends on USB=y || USB=USB_CDNS3
help
- Say Y here to enable device controller functionality of the
- Cadence USBSS-DEV driver.
+ Say Y here to enable host controller functionality for Cadence
+ USBSS and USBSSP dual-role controllers.
- This controller supports FF, HS and SS mode. It doesn't support
- LS and SSP mode.
+ The host controller is xHCI compliant and uses the standard
+ xHCI driver.
-config USB_CDNS3_HOST
- bool "Cadence USB3 host controller"
- depends on USB=y || USB=USB_CDNS3
- select USB_CDNS_HOST
+config USB_CDNS3_GADGET
+ bool "Cadence USB device controller (USBSS and USBSSP)"
+ depends on USB_GADGET=y || USB_GADGET=USB_CDNS3
help
- Say Y here to enable host controller functionality of the
- Cadence driver.
+ Say Y here to include Cadence USB device (gadget) support for
+ both USBSS (USB 3.0) and USBSSP (SuperSpeed Plus) IP in the
+ cdns.ko module. The implementation is selected at runtime from
+ the detected controller version.
- Host controller is compliant with XHCI so it will use
- standard XHCI driver.
+ USBSS gadget supports FF, HS and SS mode (not LS or SSP).
+ USBSSP gadget supports FF, HS, SS and SSP mode (not LS).
+
+comment "Platform glue driver support"
config USB_CDNS3_PCI_WRAP
tristate "Cadence USB3 support on PCIe-based platforms"
@@ -58,6 +66,17 @@ config USB_CDNS3_PCI_WRAP
If you choose to build this driver as module it will
be dynamically linked and module will be called cdns3-pci.ko
+config USB_CDNSP_PCI
+ tristate "Cadence USBSSP support on PCIe-based platforms"
+ depends on USB_PCI && ACPI
+ default USB_CDNS3
+ help
+ If you're using the USBSSP Core IP with a PCIe, please say
+ 'Y' or 'M' here.
+
+ If you choose to build this driver as module it will
+ be dynamically linked and module will be called cdnsp-pci.ko
+
config USB_CDNS3_TI
tristate "Cadence USB3 support on TI platforms"
depends on ARCH_K3 || COMPILE_TEST
@@ -81,6 +100,7 @@ config USB_CDNS3_IMX
config USB_CDNS3_STARFIVE
tristate "Cadence USB3 support on StarFive SoC platforms"
depends on ARCH_STARFIVE || COMPILE_TEST
+ default USB_CDNS3
help
Say 'Y' or 'M' here if you are building for StarFive SoCs
platforms that contain Cadence USB3 controller core.
@@ -89,45 +109,7 @@ config USB_CDNS3_STARFIVE
If you choose to build this driver as module it will
be dynamically linked and module will be called cdns3-starfive.ko
-endif
-
-if USB_CDNS_SUPPORT
-
-config USB_CDNSP_PCI
- tristate "Cadence CDNSP Dual-Role Controller"
- depends on USB_CDNS_SUPPORT && USB_PCI && ACPI
- help
- Say Y here if your system has a Cadence CDNSP dual-role controller.
- It supports: dual-role switch Host-only, and Peripheral-only.
-
- If you choose to build this driver is a dynamically linked
- module, the module will be called cdnsp.ko.
-endif
-
-if USB_CDNSP_PCI
-
-config USB_CDNSP_GADGET
- bool "Cadence CDNSP device controller"
- depends on USB_GADGET=y || USB_GADGET=USB_CDNSP_PCI
- help
- Say Y here to enable device controller functionality of the
- Cadence CDNSP-DEV driver.
-
- Cadence CDNSP Device Controller in device mode is
- very similar to XHCI controller. Therefore some algorithms
- used has been taken from host driver.
- This controller supports FF, HS, SS and SSP mode.
- It doesn't support LS.
-
-config USB_CDNSP_HOST
- bool "Cadence CDNSP host controller"
- depends on USB=y || USB=USB_CDNSP_PCI
- select USB_CDNS_HOST
- help
- Say Y here to enable host controller functionality of the
- Cadence driver.
- Host controller is compliant with XHCI so it uses
- standard XHCI driver.
+endif # USB_CDNS3
-endif
+endif # USB_CDNS_SUPPORT
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
index 48dfae75b5aa..b2e4ba6a49a3 100644
--- a/drivers/usb/cdns3/Makefile
+++ b/drivers/usb/cdns3/Makefile
@@ -3,42 +3,28 @@
CFLAGS_cdns3-trace.o := -I$(src)
CFLAGS_cdnsp-trace.o := -I$(src)
-cdns-usb-common-y := core.o drd.o
-cdns3-y := cdns3-plat.o
+obj-$(CONFIG_USB_CDNS3) += cdns.o
-ifeq ($(CONFIG_USB),m)
-obj-m += cdns-usb-common.o
-obj-m += cdns3.o
-else
-obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns-usb-common.o
-obj-$(CONFIG_USB_CDNS3) += cdns3.o
-endif
+cdns-y := core.o drd.o cdns3-plat.o
+cdns-$(CONFIG_USB_CDNS3_HOST) += host.o
-cdns-usb-common-$(CONFIG_USB_CDNS_HOST) += host.o
-cdns3-$(CONFIG_USB_CDNS3_GADGET) += cdns3-gadget.o cdns3-ep0.o
+ifneq ($(CONFIG_USB_CDNS3_GADGET),)
+cdns-y += cdns3-gadget.o cdns3-ep0.o \
+ cdnsp-ring.o cdnsp-gadget.o \
+ cdnsp-mem.o cdnsp-ep0.o
+endif
+ifneq ($(CONFIG_TRACING),)
ifneq ($(CONFIG_USB_CDNS3_GADGET),)
-cdns3-$(CONFIG_TRACING) += cdns3-trace.o
+cdns-y += cdns3-trace.o cdnsp-trace.o
+endif
endif
+##
+# Platform-specific glue layers (PCI wrappers, SoC integration)
+##
obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o
+obj-$(CONFIG_USB_CDNSP_PCI) += cdnsp-pci.o
obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o
obj-$(CONFIG_USB_CDNS3_IMX) += cdns3-imx.o
obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o
-
-cdnsp-udc-pci-y := cdnsp-pci.o
-
-ifdef CONFIG_USB_CDNSP_PCI
-ifeq ($(CONFIG_USB),m)
-obj-m += cdnsp-udc-pci.o
-else
-obj-$(CONFIG_USB_CDNSP_PCI) += cdnsp-udc-pci.o
-endif
-endif
-
-cdnsp-udc-pci-$(CONFIG_USB_CDNSP_GADGET) += cdnsp-ring.o cdnsp-gadget.o \
- cdnsp-mem.o cdnsp-ep0.o
-
-ifneq ($(CONFIG_USB_CDNSP_GADGET),)
-cdnsp-udc-pci-$(CONFIG_TRACING) += cdnsp-trace.o
-endif
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index d59a60a16ec7..ff422e5204e4 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -3508,3 +3508,4 @@ int cdns3_gadget_init(struct cdns *cdns)
return 0;
}
+EXPORT_SYMBOL_GPL(cdns3_gadget_init);
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index 735df88774e4..3fe3109a3688 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -21,6 +21,7 @@
#include "core.h"
#include "gadget-export.h"
+#include "host-export.h"
#include "drd.h"
static int set_phy_power_on(struct cdns *cdns)
@@ -44,6 +45,19 @@ static void set_phy_power_off(struct cdns *cdns)
phy_power_off(cdns->usb2_phy);
}
+static int cdns3_plat_gadget_init(struct cdns *cdns)
+{
+ if (cdns->version < CDNSP_CONTROLLER_V2)
+ return cdns3_gadget_init(cdns);
+ else
+ return cdnsp_gadget_init(cdns);
+}
+
+static int cdns3_plat_host_init(struct cdns *cdns)
+{
+ return cdns_host_init(cdns);
+}
+
/**
* cdns3_plat_probe - probe for cdns3 core device
* @pdev: Pointer to cdns3 core platform device
@@ -64,6 +78,8 @@ static int cdns3_plat_probe(struct platform_device *pdev)
cdns->dev = dev;
cdns->pdata = dev_get_platdata(dev);
+ if (cdns->pdata && cdns->pdata->override_apb_timeout)
+ cdns->override_apb_timeout = cdns->pdata->override_apb_timeout;
platform_set_drvdata(pdev, cdns);
@@ -143,12 +159,16 @@ static int cdns3_plat_probe(struct platform_device *pdev)
if (ret)
goto err_phy_power_on;
- cdns->gadget_init = cdns3_gadget_init;
-
ret = cdns_init(cdns);
if (ret)
goto err_cdns_init;
+ cdns->gadget_init = cdns3_plat_gadget_init;
+ cdns->host_init = cdns3_plat_host_init;
+ ret = cdns_core_init_role(cdns);
+ if (ret)
+ goto err_cdns_init;
+
device_set_wakeup_capable(dev, true);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@@ -336,6 +356,3 @@ static struct platform_driver cdns3_driver = {
module_platform_driver(cdns3_driver);
MODULE_ALIAS("platform:cdns3");
-MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver");
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index 6b3815f8a6e5..18e872ad29bd 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -2075,3 +2075,4 @@ int cdnsp_gadget_init(struct cdns *cdns)
return 0;
}
+EXPORT_SYMBOL_GPL(cdnsp_gadget_init);
diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
index 566d94e49102..432007cfe695 100644
--- a/drivers/usb/cdns3/cdnsp-pci.c
+++ b/drivers/usb/cdns3/cdnsp-pci.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Cadence PCI Glue driver.
+ * Cadence USBSSP PCI Glue driver.
*
* Copyright (C) 2019 Cadence.
*
@@ -16,7 +16,19 @@
#include <linux/pci.h>
#include "core.h"
-#include "gadget-export.h"
+
+struct cdnsp_wrap {
+ struct platform_device *plat_dev;
+ struct resource dev_res[6];
+ int devfn;
+};
+
+#define RES_IRQ_HOST_ID 0
+#define RES_IRQ_PERIPHERAL_ID 1
+#define RES_IRQ_OTG_ID 2
+#define RES_HOST_ID 3
+#define RES_DEV_ID 4
+#define RES_DRD_ID 5
#define PCI_BAR_HOST 0
#define PCI_BAR_OTG 0
@@ -26,16 +38,16 @@
#define PCI_DEV_FN_OTG 1
#define PCI_DRIVER_NAME "cdns-pci-usbssp"
-#define PLAT_DRIVER_NAME "cdns-usbssp"
+#define PLAT_DRIVER_NAME "cdns-usb3"
-#define CHICKEN_APB_TIMEOUT_VALUE 0x1C20
+#define CHICKEN_APB_TIMEOUT_VALUE 0x1C20
static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
{
/*
* Gets the second function.
- * Platform has two function. The fist keeps resources for
- * Host/Device while the secon keeps resources for DRD/OTG.
+ * Platform has two function. The first keeps resources for
+ * Host/Device while the second keeps resources for DRD/OTG.
*/
if (pdev->device == PCI_DEVICE_ID_CDNS_USBSSP)
return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USBSS, NULL);
@@ -48,11 +60,12 @@ static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
static int cdnsp_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- struct device *dev = &pdev->dev;
- struct pci_dev *func;
+ struct platform_device_info plat_info;
+ static struct cdns3_platform_data pdata;
+ struct cdnsp_wrap *wrap;
struct resource *res;
- struct cdns *cdnsp;
- int ret;
+ struct pci_dev *func;
+ int ret = 0;
/*
* For GADGET/HOST PCI (devfn) function number is 0,
@@ -79,146 +92,105 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
}
pci_set_master(pdev);
+
if (pci_is_enabled(func)) {
- cdnsp = pci_get_drvdata(func);
+ wrap = pci_get_drvdata(func);
} else {
- cdnsp = kzalloc_obj(*cdnsp);
- if (!cdnsp) {
+ wrap = kzalloc_obj(*wrap);
+ if (!wrap) {
ret = -ENOMEM;
goto put_pci;
}
}
- /* For GADGET device function number is 0. */
- if (pdev->devfn == 0) {
- resource_size_t rsrc_start, rsrc_len;
-
- /* Function 0: host(BAR_0) + device(BAR_1).*/
- dev_dbg(dev, "Initialize resources\n");
- rsrc_start = pci_resource_start(pdev, PCI_BAR_DEV);
- rsrc_len = pci_resource_len(pdev, PCI_BAR_DEV);
- res = devm_request_mem_region(dev, rsrc_start, rsrc_len, "dev");
- if (!res) {
- dev_dbg(dev, "controller already in use\n");
- ret = -EBUSY;
- goto free_cdnsp;
- }
-
- cdnsp->dev_regs = devm_ioremap(dev, rsrc_start, rsrc_len);
- if (!cdnsp->dev_regs) {
- dev_dbg(dev, "error mapping memory\n");
- ret = -EFAULT;
- goto free_cdnsp;
- }
-
- cdnsp->dev_irq = pdev->irq;
- dev_dbg(dev, "USBSS-DEV physical base addr: %pa\n",
- &rsrc_start);
-
- res = &cdnsp->xhci_res[0];
- res->start = pci_resource_start(pdev, PCI_BAR_HOST);
- res->end = pci_resource_end(pdev, PCI_BAR_HOST);
- res->name = "xhci";
- res->flags = IORESOURCE_MEM;
- dev_dbg(dev, "USBSS-XHCI physical base addr: %pa\n",
- &res->start);
-
- /* Interrupt for XHCI, */
- res = &cdnsp->xhci_res[1];
- res->start = pdev->irq;
- res->name = "host";
- res->flags = IORESOURCE_IRQ;
+ res = wrap->dev_res;
+
+ if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) {
+ /* Function 0: host(BAR_0) + device(BAR_2). */
+ dev_dbg(&pdev->dev, "Initialize Device resources\n");
+ res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV);
+ res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV);
+ res[RES_DEV_ID].name = "dev";
+ res[RES_DEV_ID].flags = IORESOURCE_MEM;
+ dev_dbg(&pdev->dev, "USBSSP-DEV physical base addr: %pa\n",
+ &res[RES_DEV_ID].start);
+
+ res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST);
+ res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST);
+ res[RES_HOST_ID].name = "xhci";
+ res[RES_HOST_ID].flags = IORESOURCE_MEM;
+ dev_dbg(&pdev->dev, "USBSSP-XHCI physical base addr: %pa\n",
+ &res[RES_HOST_ID].start);
+
+ /* Interrupt for XHCI */
+ wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq;
+ wrap->dev_res[RES_IRQ_HOST_ID].name = "host";
+ wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ;
+
+ /* Interrupt for device. It's the same as for HOST. */
+ wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq;
+ wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name = "peripheral";
+ wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags = IORESOURCE_IRQ;
} else {
- res = &cdnsp->otg_res;
- res->start = pci_resource_start(pdev, PCI_BAR_OTG);
- res->end = pci_resource_end(pdev, PCI_BAR_OTG);
- res->name = "otg";
- res->flags = IORESOURCE_MEM;
- dev_dbg(dev, "CDNSP-DRD physical base addr: %pa\n",
- &res->start);
+ res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG);
+ res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG);
+ res[RES_DRD_ID].name = "otg";
+ res[RES_DRD_ID].flags = IORESOURCE_MEM;
+ dev_dbg(&pdev->dev, "CDNSP-DRD physical base addr: %pa\n",
+ &res[RES_DRD_ID].start);
/* Interrupt for OTG/DRD. */
- cdnsp->otg_irq = pdev->irq;
+ wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq;
+ wrap->dev_res[RES_IRQ_OTG_ID].name = "otg";
+ wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ;
}
- /*
- * Cadence PCI based platform require some longer timeout for APB
- * to fixes domain clock synchronization issue after resuming
- * controller from L1 state.
- */
- cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE;
- pci_set_drvdata(pdev, cdnsp);
-
if (pci_is_enabled(func)) {
- cdnsp->dev = dev;
- cdnsp->gadget_init = cdnsp_gadget_init;
-
- ret = cdns_init(cdnsp);
- if (ret)
- goto free_cdnsp;
+ /* set up platform device info */
+ pdata.override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE;
+ memset(&plat_info, 0, sizeof(plat_info));
+ plat_info.parent = &pdev->dev;
+ plat_info.fwnode = pdev->dev.fwnode;
+ plat_info.name = PLAT_DRIVER_NAME;
+ plat_info.id = pdev->devfn;
+ plat_info.res = wrap->dev_res;
+ plat_info.num_res = ARRAY_SIZE(wrap->dev_res);
+ plat_info.dma_mask = pdev->dma_mask;
+ plat_info.data = &pdata;
+ plat_info.size_data = sizeof(pdata);
+ wrap->devfn = pdev->devfn;
+ /* register platform device */
+ wrap->plat_dev = platform_device_register_full(&plat_info);
+ if (IS_ERR(wrap->plat_dev)) {
+ ret = PTR_ERR(wrap->plat_dev);
+ kfree(wrap);
+ goto put_pci;
+ }
}
- device_wakeup_enable(&pdev->dev);
- if (pci_dev_run_wake(pdev))
- pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
-
-free_cdnsp:
- if (!pci_is_enabled(func))
- kfree(cdnsp);
-
+ pci_set_drvdata(pdev, wrap);
put_pci:
pci_dev_put(func);
-
return ret;
}
static void cdnsp_pci_remove(struct pci_dev *pdev)
{
- struct cdns *cdnsp;
+ struct cdnsp_wrap *wrap;
struct pci_dev *func;
func = cdnsp_get_second_fun(pdev);
- cdnsp = (struct cdns *)pci_get_drvdata(pdev);
+ wrap = pci_get_drvdata(pdev);
- if (pci_dev_run_wake(pdev))
- pm_runtime_get_noresume(&pdev->dev);
+ if (wrap->devfn == pdev->devfn)
+ platform_device_unregister(wrap->plat_dev);
- if (pci_is_enabled(func)) {
- cdns_remove(cdnsp);
- } else {
- kfree(cdnsp);
- }
+ if (!pci_is_enabled(func))
+ kfree(wrap);
pci_dev_put(func);
}
-static int __maybe_unused cdnsp_pci_suspend(struct device *dev)
-{
- struct cdns *cdns = dev_get_drvdata(dev);
-
- return cdns_suspend(cdns);
-}
-
-static int __maybe_unused cdnsp_pci_resume(struct device *dev)
-{
- struct cdns *cdns = dev_get_drvdata(dev);
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&cdns->lock, flags);
- ret = cdns_resume(cdns);
- spin_unlock_irqrestore(&cdns->lock, flags);
- cdns_set_active(cdns, 1);
-
- return ret;
-}
-
-static const struct dev_pm_ops cdnsp_pci_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cdnsp_pci_suspend, cdnsp_pci_resume)
-};
-
static const struct pci_device_id cdnsp_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP),
.class = PCI_CLASS_SERIAL_USB_DEVICE },
@@ -230,13 +202,10 @@ static const struct pci_device_id cdnsp_pci_ids[] = {
};
static struct pci_driver cdnsp_pci_driver = {
- .name = "cdnsp-pci",
+ .name = PCI_DRIVER_NAME,
.id_table = cdnsp_pci_ids,
.probe = cdnsp_pci_probe,
.remove = cdnsp_pci_remove,
- .driver = {
- .pm = &cdnsp_pci_pm_ops,
- }
};
module_pci_driver(cdnsp_pci_driver);
@@ -245,4 +214,4 @@ MODULE_DEVICE_TABLE(pci, cdnsp_pci_ids);
MODULE_ALIAS("pci:cdnsp");
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence CDNSP PCI driver");
+MODULE_DESCRIPTION("Cadence CDNSP PCI wrapper");
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index f0e32227c0b7..6a8d1fefbc0d 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -21,7 +21,6 @@
#include <linux/pm_runtime.h>
#include "core.h"
-#include "host-export.h"
#include "drd.h"
static int cdns_idle_init(struct cdns *cdns);
@@ -80,7 +79,7 @@ static void cdns_exit_roles(struct cdns *cdns)
*
* Returns 0 on success otherwise negative errno
*/
-static int cdns_core_init_role(struct cdns *cdns)
+int cdns_core_init_role(struct cdns *cdns)
{
struct device *dev = cdns->dev;
enum usb_dr_mode best_dr_mode;
@@ -96,23 +95,13 @@ static int cdns_core_init_role(struct cdns *cdns)
* can be restricted later depending on strap pin configuration.
*/
if (dr_mode == USB_DR_MODE_UNKNOWN) {
- if (cdns->version == CDNSP_CONTROLLER_V2) {
- if (IS_ENABLED(CONFIG_USB_CDNSP_HOST) &&
- IS_ENABLED(CONFIG_USB_CDNSP_GADGET))
- dr_mode = USB_DR_MODE_OTG;
- else if (IS_ENABLED(CONFIG_USB_CDNSP_HOST))
- dr_mode = USB_DR_MODE_HOST;
- else if (IS_ENABLED(CONFIG_USB_CDNSP_GADGET))
- dr_mode = USB_DR_MODE_PERIPHERAL;
- } else {
- if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) &&
- IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
- dr_mode = USB_DR_MODE_OTG;
- else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST))
- dr_mode = USB_DR_MODE_HOST;
- else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
- dr_mode = USB_DR_MODE_PERIPHERAL;
- }
+ if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) &&
+ IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
+ dr_mode = USB_DR_MODE_OTG;
+ else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST))
+ dr_mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
+ dr_mode = USB_DR_MODE_PERIPHERAL;
}
/*
@@ -137,11 +126,8 @@ static int cdns_core_init_role(struct cdns *cdns)
dr_mode = best_dr_mode;
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
- if ((cdns->version == CDNSP_CONTROLLER_V2 &&
- IS_ENABLED(CONFIG_USB_CDNSP_HOST)) ||
- (cdns->version < CDNSP_CONTROLLER_V2 &&
- IS_ENABLED(CONFIG_USB_CDNS3_HOST)))
- ret = cdns_host_init(cdns);
+ if (cdns->host_init)
+ ret = cdns->host_init(cdns);
else
ret = -ENXIO;
@@ -197,11 +183,14 @@ static int cdns_core_init_role(struct cdns *cdns)
goto err;
}
+ dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
return 0;
err:
cdns_exit_roles(cdns);
return ret;
}
+EXPORT_SYMBOL_GPL(cdns_core_init_role);
/**
* cdns_hw_role_state_machine - role switch state machine based on hw events.
@@ -469,14 +458,8 @@ int cdns_init(struct cdns *cdns)
if (ret)
goto init_failed;
- ret = cdns_core_init_role(cdns);
- if (ret)
- goto init_failed;
-
spin_lock_init(&cdns->lock);
- dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
-
return 0;
init_failed:
cdns_drd_exit(cdns);
@@ -576,5 +559,5 @@ EXPORT_SYMBOL_GPL(cdns_set_active);
MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
-MODULE_DESCRIPTION("Cadence USBSS and USBSSP DRD Driver");
+MODULE_DESCRIPTION("Cadence USBSS/USBSSP DRD driver (core, DRD, platform, optional host/gadget)");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
index 801be9e61340..bca973b999a4 100644
--- a/drivers/usb/cdns3/core.h
+++ b/drivers/usb/cdns3/core.h
@@ -45,6 +45,7 @@ struct cdns3_platform_data {
unsigned long quirks;
#define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0)
#define CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE BIT(1)
+ u32 override_apb_timeout; /* 0 = use default (e.g. for PCI) */
};
/**
@@ -82,6 +83,7 @@ struct cdns3_platform_data {
* @override_apb_timeout: hold value of APB timeout. For value 0 the default
* value in CHICKEN_BITS_3 will be preserved.
* @gadget_init: pointer to gadget initialization function
+ * @host_init: pointer to host initialization function
*/
struct cdns {
struct device *dev;
@@ -120,13 +122,14 @@ struct cdns {
spinlock_t lock;
struct xhci_plat_priv *xhci_plat_data;
u32 override_apb_timeout;
-
int (*gadget_init)(struct cdns *cdns);
+ int (*host_init)(struct cdns *cdns);
};
int cdns_hw_role_switch(struct cdns *cdns);
int cdns_init(struct cdns *cdns);
int cdns_remove(struct cdns *cdns);
+int cdns_core_init_role(struct cdns *cdns);
#ifdef CONFIG_PM_SLEEP
int cdns_resume(struct cdns *cdns);
diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h
index c37b6269b001..60c3177db62c 100644
--- a/drivers/usb/cdns3/gadget-export.h
+++ b/drivers/usb/cdns3/gadget-export.h
@@ -10,9 +10,10 @@
#ifndef __LINUX_CDNS3_GADGET_EXPORT
#define __LINUX_CDNS3_GADGET_EXPORT
-#if IS_ENABLED(CONFIG_USB_CDNSP_GADGET)
+#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
int cdnsp_gadget_init(struct cdns *cdns);
+int cdns3_gadget_init(struct cdns *cdns);
#else
static inline int cdnsp_gadget_init(struct cdns *cdns)
@@ -20,13 +21,6 @@ static inline int cdnsp_gadget_init(struct cdns *cdns)
return -ENXIO;
}
-#endif /* CONFIG_USB_CDNSP_GADGET */
-
-#if IS_ENABLED(CONFIG_USB_CDNS3_GADGET)
-
-int cdns3_gadget_init(struct cdns *cdns);
-#else
-
static inline int cdns3_gadget_init(struct cdns *cdns)
{
return -ENXIO;
diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h
index cf92173ecf00..34fd1f1ad59d 100644
--- a/drivers/usb/cdns3/host-export.h
+++ b/drivers/usb/cdns3/host-export.h
@@ -9,7 +9,7 @@
#ifndef __LINUX_CDNS3_HOST_EXPORT
#define __LINUX_CDNS3_HOST_EXPORT
-#if IS_ENABLED(CONFIG_USB_CDNS_HOST)
+#if IS_ENABLED(CONFIG_USB_CDNS3_HOST)
int cdns_host_init(struct cdns *cdns);
@@ -22,6 +22,6 @@ static inline int cdns_host_init(struct cdns *cdns)
static inline void cdns_host_exit(struct cdns *cdns) { }
-#endif /* USB_CDNS_HOST */
+#endif /* CONFIG_USB_CDNS3_HOST */
#endif /* __LINUX_CDNS3_HOST_EXPORT */
--
2.50.1
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: usb: cdns,usb3: document USBSSP controller support
From: Peter Chen @ 2026-04-21 2:34 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, arnd, gregkh, pawell, rogerq
Cc: devicetree, linux-kernel, linux-usb, cix-kernel-upstream,
Peter Chen
In-Reply-To: <20260421023459.506145-1-peter.chen@cixtech.com>
Update the Cadence USBSS DRD binding to document that it also covers
the USBSSP (SuperSpeed Plus, USB 3.1 gen2x1) controller. Both USBSS
and USBSSP share the same DRD/OTG register interface, so the driver
auto-detects the controller version at runtime: no additional
compatible string is needed.
Changes to the binding:
- Update title and add description
- maximum-speed: add super-speed-plus
Assisted-by: Cursor:claude-4.6-opus
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Peter Chen <peter.chen@cixtech.com>
---
Documentation/devicetree/bindings/usb/cdns,usb3.yaml | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
index f454ddd9bbaa..ad5acf956edf 100644
--- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
+++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml
@@ -4,11 +4,17 @@
$id: http://devicetree.org/schemas/usb/cdns,usb3.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Cadence USBSS-DRD controller
+title: Cadence USBSS and USBSSP DRD controller
maintainers:
- Pawel Laszczak <pawell@cadence.com>
+description:
+ Cadence USB dual-role controller. Covers USBSS (SuperSpeed, USB 3.0) and
+ USBSSP (SuperSpeed Plus, USB 3.1 gen2x1). Both variants share the same
+ DRD/OTG register interface, so the driver auto-detects the controller
+ version at runtime.
+
properties:
compatible:
const: cdns,usb3
@@ -49,7 +55,7 @@ properties:
cdns3 to type C connector.
maximum-speed:
- enum: [super-speed, high-speed, full-speed]
+ enum: [super-speed-plus, super-speed, high-speed, full-speed]
phys:
minItems: 1
--
2.50.1
^ permalink raw reply related
* [PATCH 0/2] Add cap-aggressive-pm support
From: Shawn Lin @ 2026-04-21 2:46 UTC (permalink / raw)
To: Ulf Hansson
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, devicetree,
linux-kernel, linux-rockchip, Shawn Lin
Aggressive power-management is now all-or-nothing set by host drivers.
This should be board-specific, add a new dt property to support adding
it via firmware;
Shawn Lin (2):
dt-bindings: mmc: Add cap-aggressive-pm property
mmc: core: Parse property for aggressive power management
Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml | 5 +++++
drivers/mmc/core/host.c | 2 ++
2 files changed, 7 insertions(+)
--
2.7.4
^ permalink raw reply
* Re: [PATCH v9 1/7] i3c: master: Expose the APIs to support I3C hub
From: Frank Li @ 2026-04-21 3:03 UTC (permalink / raw)
To: Lakshay Piplani
Cc: linux-kernel, linux-i3c, alexandre.belloni, krzk+dt, robh,
conor+dt, devicetree, broonie, lee, lgirdwood, vikash.bansal,
priyanka.jain, aman.kumarpandey
In-Reply-To: <20260420105222.1562243-2-lakshay.piplani@nxp.com>
On Mon, Apr 20, 2026 at 04:22:16PM +0530, Lakshay Piplani wrote:
> From: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
>
> The following APIs were already declared in i3c_internals.h but were
> missing EXPORT_SYMBOL_GPL() in their implementation, making them
> inaccessible to modular drivers such as the I3C hub driver:
>
> 1) i3c_dev_enable_ibi_locked()
> 2) i3c_dev_disable_ibi_locked()
> 3) i3c_dev_request_ibi_locked()
> 4) i3c_dev_free_ibi_locked()
>
> i3c_master_reattach_i3c_dev() is declared in include/linux/i3c/master.h
> and exported via EXPORT_SYMBOL_GPL() to make it accessible to the I3C
> hub driver.
>
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
> Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
>
> ---
...
> -static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
> - u8 old_dyn_addr)
> +/**
> + * i3c_master_reattach_i3c_dev() - reattach an I3C device with a new address
> + * @dev: I3C device descriptor to reattach
> + * @old_dyn_addr: previous dynamic address of the device
> + *
> + * This function reattaches an existing I3C device to the bus when its dynamic
> + * address has changed. It updates the bus address slot status accordingly:
> + * - Marks the new dynamic address as occupied by an I3C device.
> + * - Frees the old dynamic address slot if applicable.
> + *
> + * This function must be called with the bus lock held in write mode.
If this function required lock, please add new patch before this one to
rename to i3c_master_reattach_i3c_dev_lock() to keep consistent with
others.
Frank
>
^ permalink raw reply
* Re: [PATCH v9 2/7] i3c: master: Add the APIs to support I3C hub
From: Frank Li @ 2026-04-21 3:09 UTC (permalink / raw)
To: Lakshay Piplani
Cc: linux-kernel, linux-i3c, alexandre.belloni, krzk+dt, robh,
conor+dt, devicetree, broonie, lee, lgirdwood, vikash.bansal,
priyanka.jain, aman.kumarpandey
In-Reply-To: <20260420105222.1562243-3-lakshay.piplani@nxp.com>
On Mon, Apr 20, 2026 at 04:22:17PM +0530, Lakshay Piplani wrote:
> From: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
>
> Add simple helpers to direct attach/detach I3C devices and two CCC helpers
> to check CCC support and send CCC commands. These additions prepare the
> master core for I3C hub support.
Nit: This additions prepare for I3C hub support.
>
> 1) i3c_master_direct_attach_i3c_dev()
> 2) i3c_master_direct_detach_i3c_dev()
> 3) i3c_master_send_ccc_cmd()
> 4) i3c_master_supports_ccc_cmd()
>
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
> Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
>
> ---
> Changes in v9:
> - No change
>
> Changes in v8:
> - No change
>
> Changes in v7:
> - Update commit message to clarify purpose (prepare for I3C hub support)
>
> Changes in v6:
> - Split the patch into two parts:
> 1) expose the existing API
> 2) add new APIs.
> ---
> ---
> drivers/i3c/master.c | 103 +++++++++++++++++++++++++++++++++++++
> include/linux/i3c/master.h | 8 +++
> 2 files changed, 111 insertions(+)
>
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index d11fe6937ba8..2b88021d8a23 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -1652,6 +1652,59 @@ static int i3c_master_attach_i3c_dev(struct i3c_master_controller *master,
> return 0;
> }
>
> +/**
> + * i3c_master_direct_attach_i3c_dev() - attach an I3C device to a master
> + * @master: I3C master controller to attach the device to
> + * @dev: I3C device descriptor representing the device
> + *
> + * This function attaches an I3C device to its master controller once the
> + * device has a valid address on the bus. Devices without
> + * an assigned address are ignored. The master device itself is never
Nit: wrap at consistent position. (such as 80 chars), check others.
Frank
^ permalink raw reply
* Re: [PATCH 2/2] drm/bridge: Add LT7911EXC edp to mipi bridge driver
From: 杨孙运 @ 2026-04-21 3:13 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: syyang, robh, krzk+dt, conor+dt, andrzej.hajda, neil.armstrong,
maarten.lankhorst, rfoss, mripard, Laurent.pinchart, jonas,
jernej.skrabec, devicetree, dri-devel, linux-kernel, xmzhu,
tzimmermann, xbpeng, rlyu, xmzhu
In-Reply-To: <CAO9ioeXDfTdETEBQknoLehk2aiabCgse109sDgJoPHuQ_07nKQ@mail.gmail.com>
Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> 于2026年4月20日周一 11:57写道:
>
> On Mon, 20 Apr 2026 at 05:34, <syyang@lontium.com> wrote:
> >
> > From: Sunyun Yang <syyang@lontium.com>
> >
> > LT7911EXC is a high performance eDP1.4 to MIPI chip for
>
> MIPI what?
>
MIPI DSI,
It will be modified in the next version.
> > VR/Display application.
> >
> > -eDP1.4Receiver
> > 1.Support SSC
> > 2.Support 1/2/4 lanes
> > 3.Support up to 4K@60HzRGB/YCbCr4:4:48bpc
> > 4.Support lane swap and PN swap
> >
> > -MIPI Transmitter
> > 1.CompliantwithD-PHY1.2&DSI1.1&CSI-22.0;1 clock lane,
> > and1/2/3/4 configurable data lanes:2.5Gbpsperdatalane
> > 2.CompliantwithC-PHY1.0&DSI-21.0&CSI-22.0;
> > 1/2/3 configurable data trio;2.5Gsps perdatatrio
> > 3.Support1/2configurable ports
> > 4.DSISupport16/20/24-bit YCbCr4:2:2,16/18/24/30-bit RGB
> >
> > Signed-off-by: Sunyun Yang <syyang@lontium.com>
> > ---
> > drivers/gpu/drm/bridge/Kconfig | 18 +
> > drivers/gpu/drm/bridge/Makefile | 1 +
> > drivers/gpu/drm/bridge/lontium-lt7911exc.c | 571 +++++++++++++++++++++
> > 3 files changed, 590 insertions(+)
> > create mode 100644 drivers/gpu/drm/bridge/lontium-lt7911exc.c
> >
> > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> > index c3209b0f4678..bae8cdaea666 100644
> > --- a/drivers/gpu/drm/bridge/Kconfig
> > +++ b/drivers/gpu/drm/bridge/Kconfig
> > @@ -202,6 +202,24 @@ config DRM_LONTIUM_LT8713SX
> > to 3 configurable Type-C/DP1.4/HDMI2.0 outputs
> > Please say Y if you have such hardware.
> >
> > +config DRM_LONTIUM_LT9611C
>
> I thought the patch is for LT7911EXC
>
Yes, it is LT7911EXC, It will be modified in the next version.
> > + tristate "Lontium LT9611C DSI/HDMI bridge"
> > + select SND_SOC_HDMI_CODEC if SND_SOC
> > + depends on OF
> > + select CRC8
> > + select FW_LOADER
> > + select DRM_PANEL_BRIDGE
> > + select DRM_KMS_HELPER
> > + select DRM_MIPI_DSI
> > + select DRM_DISPLAY_HELPER
> > + select DRM_DISPLAY_HDMI_STATE_HELPER
> > + select REGMAP_I2C
> > + help
> > + Driver for Lontium DSI to HDMI bridge
> > + chip driver that converts dual DSI and I2S to
> > + HDMI signals
> > + Please say Y if you have such hardware.
> > +
> > config DRM_ITE_IT66121
> > tristate "ITE IT66121 HDMI bridge"
> > depends on OF
> > diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> > index beab5b695a6e..54b293d1663e 100644
> > --- a/drivers/gpu/drm/bridge/Makefile
> > +++ b/drivers/gpu/drm/bridge/Makefile
> > @@ -18,6 +18,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o
> > obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
> > obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o
> > obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o
> > +obj-$(CONFIG_DRM_LONTIUM_LT7911EXC) += lontium-lt7911exc.o
>
> Keep the list sorted, please.
>
Where can I see the sorting rules? Please guide me.
it is:
obj-$(CONFIG_DRM_LONTIUM_LT7911EXC) += lontium-lt7911exc.o
obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o
?
> > obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
> > obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
> > obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o
> > diff --git a/drivers/gpu/drm/bridge/lontium-lt7911exc.c b/drivers/gpu/drm/bridge/lontium-lt7911exc.c
> > new file mode 100644
> > index 000000000000..d1c1d9e073ef
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/lontium-lt7911exc.c
> > @@ -0,0 +1,571 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2026 Lontium Semiconductor, Inc.
> > + */
> > +
> > +#include <linux/crc32.h>
> > +#include <linux/firmware.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/i2c.h>
> > +#include <linux/regmap.h>
>
> I think you use more than that.
>
It will be modified in the next version.
> > +#include <drm/drm_of.h>
> > +
> > +#define FW_SIZE (64 * 1024)
> > +#define LT_PAGE_SIZE 32
> > +#define FW_FILE "LT7911EXC.bin"
> > +#define LT7911EXC_PAGE_CONTROL 0xff
> > +
> > +struct lt7911exc {
> > + struct device *dev;
> > + struct i2c_client *client;
> > + struct drm_bridge bridge;
> > + struct drm_bridge *panel_bridge;
>
> Use next_bridge from struct drm_bridge instead.
>
It will be modified in the next version.
> > + struct regmap *regmap;
> > + /* Protects all accesses to registers by stopping the on-chip MCU */
> > + struct mutex ocm_lock;
> > + struct regulator_bulk_data supplies[2];
> > +
> > + struct gpio_desc *reset_gpio;
> > + const struct firmware *fw;
>
> Do you need to store it during the runtime? If not, please remove from
> the data struct.
>
Don't need store during the runtime.
Can I use the global variable 'fw'?
Because I need use 'fw' to calculate the CRC32 and burn the firmware.
> > + int fw_version;
> > + u32 fw_crc;
> > +
> > + bool enabled;
>
> What for?
>
(bool enabled;) is used as a flag in the code to reduce the frequency
of power supply switching.
Of course, it can also be removed in the next version.
> > +};
> > +
> > +static const struct regmap_range_cfg lt7911exc_ranges[] = {
> > + {
> > + .name = "register_range",
> > + .range_min = 0,
> > + .range_max = 0xffff,
>
> Is it an actual range?
>
0xe8ff is actual range.
> > + .selector_reg = LT7911EXC_PAGE_CONTROL,
> > + .selector_mask = 0xff,
> > + .selector_shift = 0,
> > + .window_start = 0,
> > + .window_len = 0x100,
> > + },
> > +};
> > +
> > +static const struct regmap_config lt7911exc_regmap_config = {
> > + .reg_bits = 8,
> > + .val_bits = 8,
> > + .max_register = 0xffff,
> > + .ranges = lt7911exc_ranges,
> > + .num_ranges = ARRAY_SIZE(lt7911exc_ranges),
> > +};
> > +
> > +static u32 cal_crc32_custom(const u8 *data, u64 length)
> > +{
> > + u32 crc = 0xffffffff;
> > + u8 buf[4];
> > + u64 i;
> > +
> > + for (i = 0; i < length; i += 4) {
> > + buf[0] = data[i + 3];
> > + buf[1] = data[i + 2];
> > + buf[2] = data[i + 1];
> > + buf[3] = data[i + 0];
> > + crc = crc32_be(crc, buf, 4);
>
> How is it different from crc32_le()?
>
The implementation differs from crc32_le() in both byte ordering and
processing granularity.
This function performs a 32-bit word-wise byte swap (little-endian to
big-endian) before feeding data into crc32_be(), while crc32_le()
processes the input stream directly in little-endian order without
transformation.
Therefore, the result is not equivalent to crc32_le(), and is required
to match the firmware's expected big-endian word-based CRC format.
> > + }
>
> Wrong alignment.
>
it will be fixed in the next version
> > +
> > + return crc;
> > +}
> > +
> > +static inline struct lt7911exc *
> > + bridge_to_lt7911exc(struct drm_bridge *bridge)
>
> One line, please.
>
it will be fixed in the next version
> > +{
> > + return container_of(bridge, struct lt7911exc, bridge);
> > +}
> > +
> > +static int lt7911exc_regulator_enable(struct lt7911exc *lt7911exc)
> > +{
> > + int ret;
> > +
> > + ret = regulator_enable(lt7911exc->supplies[0].consumer);
>
> If you are not using bulk interface here, why did you declare supplies as bulks?
>
it will be fixed in the next version
> > + if (ret < 0)
> > + return ret;
> > +
> > + usleep_range(5000, 10000);
> > +
> > + ret = regulator_enable(lt7911exc->supplies[1].consumer);
> > + if (ret < 0) {
> > + regulator_disable(lt7911exc->supplies[0].consumer);
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_regulator_disable(struct lt7911exc *lt7911exc)
> > +{
> > + int ret;
> > +
> > + ret = regulator_disable(lt7911exc->supplies[1].consumer);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = regulator_disable(lt7911exc->supplies[0].consumer);
> > + if (ret < 0)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > +static void lt7911exc_reset(struct lt7911exc *lt7911exc)
> > +{
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 1);
> > + msleep(20);
> > +
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 0);
> > + msleep(20);
> > +
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 1);
>
> Yep, it's active low. Invert polarities here.
>
gpiod_set_value_cansleep(lt7911exc->reset_gpio, 0);
msleep(20);
gpiod_set_value_cansleep(lt7911exc->reset_gpio, 1);
msleep(20);
gpiod_set_value_cansleep(lt7911exc->reset_gpio, 0);
next version, fixed.
> > + msleep(400);
> > +
> > + dev_dbg(lt7911exc->dev, "lt7911exc reset");
> > +}
> > +
> > +static int lt7911exc_parse_dt(struct lt7911exc *lt7911exc)
> > +{
> > + int ret;
> > +
> > + lt7911exc->supplies[0].supply = "vcc";
> > + lt7911exc->supplies[1].supply = "vdd";
> > +
> > + ret = devm_regulator_bulk_get(lt7911exc->dev, 2, lt7911exc->supplies);
> > + if (ret) {
> > + dev_err(lt7911exc->dev, "failed get regulator\n");
> > + return ret;
>
> return dev_err_probe();
>
it will be fixed in the next version
> > + }
> > +
> > + lt7911exc->reset_gpio = devm_gpiod_get(lt7911exc->dev, "reset", GPIOD_OUT_LOW);
> > + if (IS_ERR(lt7911exc->reset_gpio)) {
> > + dev_err(lt7911exc->dev, "failed to acquire reset gpio\n");
>
> return dev_err_probe();
>
it will be fixed in the next version
> > + return PTR_ERR(lt7911exc->reset_gpio);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_read_version(struct lt7911exc *lt7911exc)
> > +{
> > + u8 buf[2];
> > + int ret;
> > +
> > + ret = regmap_bulk_read(lt7911exc->regmap, 0xe081, buf, 3);
>
> Do you see a buffer overflow here?
>
sorry, it will be fixed in the next version
> > + if (ret)
> > + return ret;
> > +
> > + return (buf[0] << 16) | (buf[1] << 8) | buf[2];
> > +}
> > +
> > +static void lt7911exc_lock(struct lt7911exc *lt7911exc)
> > +{
> > + mutex_lock(<7911exc->ocm_lock);
> > + regmap_write(lt7911exc->regmap, 0xe0ee, 0x01);
> > +}
> > +
> > +static void lt7911exc_unlock(struct lt7911exc *lt7911exc)
> > +{
> > + regmap_write(lt7911exc->regmap, 0xe0ee, 0x00);
> > + mutex_unlock(<7911exc->ocm_lock);
> > +}
> > +
> > +static int lt7911exc_prepare_firmware_data(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + int ret;
> > + u8 *buffer;
> > + size_t total_size = FW_SIZE - 4;
> > +
> > + ret = request_firmware(<7911exc->fw, FW_FILE, dev);
> > + if (ret) {
> > + dev_err(dev, "failed load file '%s', error type %d\n", FW_FILE, ret);
> > + return ret;
> > + }
> > +
> > + if (lt7911exc->fw->size > total_size) {
> > + dev_err(dev, "firmware too large (%zu > %zu)\n", lt7911exc->fw->size, total_size);
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > + return -EINVAL;
> > + }
> > +
> > + dev_dbg(dev, "firmware size: %zu bytes\n", lt7911exc->fw->size);
> > +
> > + buffer = kzalloc(total_size, GFP_KERNEL);
> > + if (!buffer) {
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > + return -ENOMEM;
> > + }
> > +
> > + memset(buffer, 0xff, total_size);
> > + memcpy(buffer, lt7911exc->fw->data, lt7911exc->fw->size);
> > +
> > + lt7911exc->fw_crc = cal_crc32_custom(buffer, total_size);
> > + dev_dbg(dev, "firmware crc: 0x%08x\n", lt7911exc->fw_crc);
> > +
> > + kfree(buffer);
> > + return 0;
> > +}
> > +
> > +static void lt7911exc_block_erase(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + const u32 addr = 0x00;
> > +
> > + const struct reg_sequence seq_write[] = {
> > + REG_SEQ0(0xe0ee, 0x01),
> > + REG_SEQ0(0xe054, 0x01),
> > + REG_SEQ0(0xe055, 0x06),
> > + REG_SEQ0(0xe051, 0x01),
> > + REG_SEQ0(0xe051, 0x00),
> > + REG_SEQ0(0xe054, 0x05),
> > + REG_SEQ0(0xe055, 0xd8),
> > + REG_SEQ0(0xe05a, (addr >> 16) & 0xff),
> > + REG_SEQ0(0xe05b, (addr >> 8) & 0xff),
> > + REG_SEQ0(0xe05c, addr & 0xff),
> > + REG_SEQ0(0xe051, 0x01),
> > + REG_SEQ0(0xe050, 0x00),
> > + };
> > +
> > + regmap_multi_reg_write(lt7911exc->regmap, seq_write, ARRAY_SIZE(seq_write));
> > +
> > + msleep(200);
> > + dev_dbg(dev, "erase flash done.\n");
> > +}
> > +
> > +static void lt7911exc_prog_init(struct lt7911exc *lt7911exc, u64 addr)
> > +{
> > + const struct reg_sequence seq_write[] = {
> > + REG_SEQ0(0xe0ee, 0x01),
> > + REG_SEQ0(0xe05f, 0x01),
> > + REG_SEQ0(0xe05a, (addr >> 16) & 0xff),
> > + REG_SEQ0(0xe05b, (addr >> 8) & 0xff),
> > + REG_SEQ0(0xe05c, addr & 0xff),
> > + };
> > +
> > + regmap_multi_reg_write(lt7911exc->regmap, seq_write, ARRAY_SIZE(seq_write));
> > +}
> > +
> > +static int lt7911exc_write_data(struct lt7911exc *lt7911exc, u64 addr)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + int ret;
> > + int page = 0, num = 0, page_len = 0;
> > + u64 size, offset;
> > + const u8 *data;
> > +
> > + data = lt7911exc->fw->data;
> > + size = lt7911exc->fw->size;
> > + page = (size + LT_PAGE_SIZE - 1) / LT_PAGE_SIZE;
> > + if (page * LT_PAGE_SIZE > FW_SIZE) {
> > + dev_err(dev, "firmware size out of range\n");
> > + return -EINVAL;
> > + }
> > +
> > + dev_dbg(dev, "%u pages, total size %llu byte\n", page, size);
> > +
> > + for (num = 0; num < page; num++) {
> > + offset = num * LT_PAGE_SIZE;
> > + page_len = (offset + LT_PAGE_SIZE <= size) ? LT_PAGE_SIZE : (size - offset);
> > + lt7911exc_prog_init(lt7911exc, addr);
> > +
> > + ret = regmap_raw_write(lt7911exc->regmap, 0xe05d, &data[offset], page_len);
> > + if (ret) {
> > + dev_err(dev, "write error at page %d\n", num);
> > + return ret;
> > + }
> > +
> > + if (page_len < LT_PAGE_SIZE) {
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x05);
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x01);
> > + //hardware requires delay
> > + usleep_range(1000, 2000);
> > + }
> > +
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x00);
> > + addr += LT_PAGE_SIZE;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_write_crc(struct lt7911exc *lt7911exc, u64 addr)
> > +{
> > + u8 crc[4];
> > + int ret;
> > +
> > + crc[0] = lt7911exc->fw_crc & 0xff;
> > + crc[1] = (lt7911exc->fw_crc >> 8) & 0xff;
> > + crc[2] = (lt7911exc->fw_crc >> 16) & 0xff;
> > + crc[3] = (lt7911exc->fw_crc >> 24) & 0xff;
> > +
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x01);
> > + regmap_write(lt7911exc->regmap, 0xe05a, (addr >> 16) & 0xff);
> > + regmap_write(lt7911exc->regmap, 0xe05b, (addr >> 8) & 0xff);
> > + regmap_write(lt7911exc->regmap, 0xe05c, addr & 0xff);
> > +
> > + ret = regmap_raw_write(lt7911exc->regmap, 0xe05d, crc, 4);
> > + if (ret)
> > + return ret;
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x05);
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x01);
> > + usleep_range(1000, 2000);
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x00);
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_firmware_upgrade(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + int ret;
> > +
> > + ret = lt7911exc_prepare_firmware_data(lt7911exc);
> > + if (ret < 0)
> > + return ret;
> > +
> > + dev_dbg(dev, "starting firmware upgrade, size: %zu bytes\n", lt7911exc->fw->size);
> > +
> > + lt7911exc_block_erase(lt7911exc);
> > +
> > + ret = lt7911exc_write_data(lt7911exc, 0);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to write firmware data\n");
> > + return ret;
> > + }
> > +
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > +
> > + ret = lt7911exc_write_crc(lt7911exc, FW_SIZE - 4);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to write firmware crc\n");
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_upgrade_result(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + u32 read_hw_crc = 0;
> > + u8 crc_tmp[4];
> > + int ret;
> > +
> > + regmap_write(lt7911exc->regmap, 0xe0ee, 0x01);
> > + regmap_write(lt7911exc->regmap, 0xe07b, 0x60);
> > + regmap_write(lt7911exc->regmap, 0xe07b, 0x40);
> > + msleep(150);
> > + ret = regmap_bulk_read(lt7911exc->regmap, 0x22, crc_tmp, 4);
> > + if (ret) {
> > + dev_err(lt7911exc->dev, "Failed to read CRC: %d\n", ret);
> > + return ret;
> > + }
> > +
> > + read_hw_crc = crc_tmp[0] << 24 | crc_tmp[1] << 16 |
> > + crc_tmp[2] << 8 | crc_tmp[3];
> > +
> > + if (read_hw_crc != lt7911exc->fw_crc) {
> > + dev_err(dev, "lt7911exc firmware upgrade failed, expected CRC=0x%08x, read CRC=0x%08x\n",
> > + lt7911exc->fw_crc, read_hw_crc);
> > + return -EIO;
> > + }
> > +
> > + dev_dbg(dev, "lt7911exc firmware upgrade success, CRC=0x%08x\n", read_hw_crc);
> > + return 0;
> > +}
> > +
> > +static void lt7911exc_pre_enable(struct drm_bridge *bridge)
> > +{
> > + struct lt7911exc *lt7911exc = bridge_to_lt7911exc(bridge);
> > + int ret;
> > +
> > + if (lt7911exc->enabled)
> > + return;
> > +
> > + ret = lt7911exc_regulator_enable(lt7911exc);
> > + if (ret)
> > + return;
> > +
> > + lt7911exc_reset(lt7911exc);
> > +
> > + lt7911exc->enabled = true;
> > +}
> > +
> > +static void lt7911exc_disable(struct drm_bridge *bridge)
> > +{
> > + /* Delay after panel is disabled */
> > + msleep(20);
> > +}
> > +
> > +static void lt7911exc_post_disable(struct drm_bridge *bridge)
> > +{
> > + struct lt7911exc *lt7911exc = bridge_to_lt7911exc(bridge);
> > + int ret;
> > +
> > + if (!lt7911exc->enabled)
> > + return;
> > +
> > + lt7911exc->enabled = false;
> > +
> > + ret = lt7911exc_regulator_disable(lt7911exc);
> > + if (ret)
> > + return;
> > +
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 0);
> > +}
> > +
> > +static int lt7911exc_attach(struct drm_bridge *bridge,
> > + struct drm_encoder *encoder,
> > + enum drm_bridge_attach_flags flags)
> > +{
> > + struct lt7911exc *lt7911exc = bridge_to_lt7911exc(bridge);
> > +
> > + return drm_bridge_attach(lt7911exc->bridge.encoder, lt7911exc->panel_bridge,
> > + <7911exc->bridge, flags);
> > +}
> > +
> > +static const struct drm_bridge_funcs lt7911exc_bridge_funcs = {
> > + .pre_enable = lt7911exc_pre_enable,
> > + .disable = lt7911exc_disable,
> > + .post_disable = lt7911exc_post_disable,
> > + .attach = lt7911exc_attach,
> > +};
> > +
> > +static int lt7911exc_probe(struct i2c_client *client)
> > +{
> > + struct device *dev = &client->dev;
> > + struct lt7911exc *lt7911exc;
> > + struct drm_bridge *panel_bridge;
> > + bool fw_updated = false;
> > + int ret;
> > +
> > + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> > + dev_err(dev, "device doesn't support I2C\n");
> > + return -ENODEV;
> > + }
> > +
> > + lt7911exc = devm_drm_bridge_alloc(dev, struct lt7911exc, bridge,
> > + <7911exc_bridge_funcs);
> > + if (IS_ERR(lt7911exc))
> > + return PTR_ERR(lt7911exc);
> > +
> > + panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
> > + if (IS_ERR(panel_bridge))
> > + return PTR_ERR(panel_bridge);
> > +
> > + lt7911exc->panel_bridge = panel_bridge;
> > + lt7911exc->client = client;
> > + lt7911exc->dev = dev;
> > + i2c_set_clientdata(client, lt7911exc);
> > + mutex_init(<7911exc->ocm_lock);
>
> devm_mutex_init()
>
it will be fixed in the next version
> > +
> > + lt7911exc->regmap = devm_regmap_init_i2c(client, <7911exc_regmap_config);
> > + if (IS_ERR(lt7911exc->regmap)) {
> > + dev_err(dev, "regmap i2c init failed\n");
> > + return PTR_ERR(lt7911exc->regmap);
> > + }
> > +
> > + ret = lt7911exc_parse_dt(lt7911exc);
> > + if (ret)
> > + return ret;
> > +
> > + ret = lt7911exc_regulator_enable(lt7911exc);
> > + if (ret)
> > + return ret;
> > +
> > + lt7911exc_reset(lt7911exc);
> > + lt7911exc->enabled = true;
> > + lt7911exc_lock(lt7911exc);
> > +
> > +retry:
> > + lt7911exc->fw_version = lt7911exc_read_version(lt7911exc);
> > + if (lt7911exc->fw_version < 0) {
> > + dev_err(dev, "failed to read FW version\n");
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > +
> > + } else if (lt7911exc->fw_version == 0) {
> > + if (!fw_updated) {
> > + fw_updated = true;
> > + ret = lt7911exc_firmware_upgrade(lt7911exc);
> > + if (ret < 0) {
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > + }
> > +
> > + lt7911exc_reset(lt7911exc);
> > +
> > + ret = lt7911exc_upgrade_result(lt7911exc);
> > + if (ret < 0) {
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > + }
> > +
> > + goto retry;
> > +
> > + } else {
> > + dev_err(dev, "fw version 0x%04x, update failed\n", lt7911exc->fw_version);
> > + ret = -EOPNOTSUPP;
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > + }
> > + }
> > +
> > + lt7911exc_unlock(lt7911exc);
> > +
> > + lt7911exc->bridge.type = DRM_MODE_CONNECTOR_DSI;
>
> So, this is the DSI host. Where do you register one? Where do you
> populate the DT entries (if there is a panel attached to this bridge
> it will be a child node).
>
it will be fixed in the next version
> > + lt7911exc->bridge.of_node = dev->of_node;
> > + drm_bridge_add(<7911exc->bridge);
>
> devm_drm_bridge_add().
>
it will be fixed in the next version
> > +
> > + return 0;
> > +
> > +err_disable_regulators:
> > + regulator_bulk_disable(ARRAY_SIZE(lt7911exc->supplies), lt7911exc->supplies);
> > + if (lt7911exc->fw) {
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void lt7911exc_remove(struct i2c_client *client)
> > +{
> > + struct lt7911exc *lt7911exc = i2c_get_clientdata(client);
> > +
> > + drm_bridge_remove(<7911exc->bridge);
> > + mutex_destroy(<7911exc->ocm_lock);
> > +}
> > +
> > +static const struct i2c_device_id lt7911exc_i2c_table[] = {
> > + {"lontium, lt7911exc", 0},
> > + { /* sentinel */ }
> > +};
> > +
> > +MODULE_DEVICE_TABLE(i2c, lt7911exc_i2c_table);
> > +
> > +static const struct of_device_id lt7911exc_devices[] = {
> > + {.compatible = "lontium,lt7911exc",},
> > + {}
> > +};
> > +MODULE_DEVICE_TABLE(of, lt7911exc_devices);
> > +
> > +static struct i2c_driver lt7911exc_driver = {
> > + .id_table = lt7911exc_i2c_table,
> > + .probe = lt7911exc_probe,
> > + .remove = lt7911exc_remove,
> > + .driver = {
> > + .name = "lt7911exc",
> > + .of_match_table = lt7911exc_devices,
> > + },
> > +};
> > +module_i2c_driver(lt7911exc_driver);
> > +
> > +MODULE_AUTHOR("SunYun Yang <syyang@lontium.com>");
> > +MODULE_DESCRIPTION("Lontium lt7911exc edp to mipi dsi bridge driver");
>
> MIPI, DSI. It LT7911EXC or lt7911exc?
>
it will be fixed in the next version:Lontium lLT7911EXC to MIPI DSI
bridge driver
> > +MODULE_LICENSE("GPL v2");
Should GPL be used here? I got an error during testing: GPL v2;
> > --
> > 2.34.1
> >
>
>
> --
> With best wishes
> Dmitry
^ permalink raw reply
* Re: [PATCH v9 4/7] mfd: p3h2x4x: Add driver for NXP P3H2x4x i3c hub and on-die regulator
From: Frank Li @ 2026-04-21 3:14 UTC (permalink / raw)
To: Lakshay Piplani
Cc: linux-kernel, linux-i3c, alexandre.belloni, krzk+dt, robh,
conor+dt, devicetree, broonie, lee, lgirdwood, vikash.bansal,
priyanka.jain, aman.kumarpandey
In-Reply-To: <20260420105222.1562243-5-lakshay.piplani@nxp.com>
On Mon, Apr 20, 2026 at 04:22:19PM +0530, Lakshay Piplani wrote:
> From: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
>
> Add core MFD support for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
> family of multiport I3C hub devices. These devices connect to a host via
> I3C/I2C/SMBus and expose multiple downstream target ports.
>
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
> Signed-off-by: Vikash Bansal <vikash.bansal@nxp.com>
> Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
>
> ---
...
> +static int p3h2x4x_device_probe_i3c(struct i3c_device *i3cdev)
> +{
> + struct p3h2x4x_dev *p3h2x4x;
> + int ret;
> +
> + p3h2x4x = devm_kzalloc(&i3cdev->dev, sizeof(*p3h2x4x), GFP_KERNEL);
> + if (!p3h2x4x)
> + return -ENOMEM;
> +
> + i3cdev_set_drvdata(i3cdev, p3h2x4x);
> +
> + p3h2x4x->regmap = devm_regmap_init_i3c(i3cdev, &p3h2x4x_regmap_config);
> + if (IS_ERR(p3h2x4x->regmap))
> + return dev_err_probe(&i3cdev->dev, PTR_ERR(p3h2x4x->regmap),
> + "Failed to register HUB regmap\n");
> +
> + p3h2x4x->is_p3h2x4x_in_i3c = true;
Needn't this one, you can check p3h2x4x->i3cdev to know if it is i3c dev.
Frank
^ permalink raw reply
* Re: [PATCH 2/2] drm/bridge: Add LT7911EXC edp to mipi bridge driver
From: 杨孙运 @ 2026-04-21 3:26 UTC (permalink / raw)
To: Quentin Freimanis
Cc: syyang, robh, krzk+dt, conor+dt, andrzej.hajda, neil.armstrong,
dmitry.baryshkov, maarten.lankhorst, rfoss, mripard,
Laurent.pinchart, jonas, jernej.skrabec, devicetree, dri-devel,
linux-kernel, xmzhu, tzimmermann, xmzhu, xbpeng, rlyu
In-Reply-To: <f9753cfc-bfe1-4256-af35-0f262a4e8b81@q-lab.dev>
Quentin Freimanis <quentin@q-lab.dev> 于2026年4月20日周一 13:06写道:
>
> On 2026-04-19 7:33 p.m., syyang@lontium.com wrote:
> > From: Sunyun Yang <syyang@lontium.com>
> >
> > LT7911EXC is a high performance eDP1.4 to MIPI chip for
> > VR/Display application.
> >
> > -eDP1.4Receiver
> > 1.Support SSC
>
> s/1.Support/1. Supports/
>
it will be fixed in the next version.
> > 2.Support 1/2/4 lanes
> > 3.Support up to 4K@60HzRGB/YCbCr4:4:48bpc
> > 4.Support lane swap and PN swap
>
> Same for these
>
it will be fixed in the next version.
> >
> > -MIPI Transmitter
> > 1.CompliantwithD-PHY1.2&DSI1.1&CSI-22.0;1 clock lane,
> > and1/2/3/4 configurable data lanes:2.5Gbpsperdatalane
> > 2.CompliantwithC-PHY1.0&DSI-21.0&CSI-22.0;
> > 1/2/3 configurable data trio;2.5Gsps perdatatrio
> > 3.Support1/2configurable ports
> > 4.DSISupport16/20/24-bit YCbCr4:2:2,16/18/24/30-bit RGB
>
> Missing spaces, this is hard to read and needs to be cleaned up
>
it will be fixed in the next version.
> >
> > Signed-off-by: Sunyun Yang <syyang@lontium.com>
> > ---
> > drivers/gpu/drm/bridge/Kconfig | 18 +
> > drivers/gpu/drm/bridge/Makefile | 1 +
> > drivers/gpu/drm/bridge/lontium-lt7911exc.c | 571 +++++++++++++++++++++
> > 3 files changed, 590 insertions(+)
> > create mode 100644 drivers/gpu/drm/bridge/lontium-lt7911exc.c
> >
> > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> > index c3209b0f4678..bae8cdaea666 100644
> > --- a/drivers/gpu/drm/bridge/Kconfig
> > +++ b/drivers/gpu/drm/bridge/Kconfig
> > @@ -202,6 +202,24 @@ config DRM_LONTIUM_LT8713SX
> > to 3 configurable Type-C/DP1.4/HDMI2.0 outputs
> > Please say Y if you have such hardware.
> >
> > +config DRM_LONTIUM_LT9611C
> > + tristate "Lontium LT9611C DSI/HDMI bridge"
> > + select SND_SOC_HDMI_CODEC if SND_SOC
> > + depends on OF
> > + select CRC8
> > + select FW_LOADER
> > + select DRM_PANEL_BRIDGE
> > + select DRM_KMS_HELPER
> > + select DRM_MIPI_DSI
> > + select DRM_DISPLAY_HELPER
> > + select DRM_DISPLAY_HDMI_STATE_HELPER
> > + select REGMAP_I2C
> > + help
> > + Driver for Lontium DSI to HDMI bridge
> > + chip driver that converts dual DSI and I2S to
> > + HDMI signals
> > + Please say Y if you have such hardware.
> > +
> > config DRM_ITE_IT66121
> > tristate "ITE IT66121 HDMI bridge"
> > depends on OF
> > diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> > index beab5b695a6e..54b293d1663e 100644
> > --- a/drivers/gpu/drm/bridge/Makefile
> > +++ b/drivers/gpu/drm/bridge/Makefile
> > @@ -18,6 +18,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o
> > obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
> > obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o
> > obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o
> > +obj-$(CONFIG_DRM_LONTIUM_LT7911EXC) += lontium-lt7911exc.o
> > obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
> > obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
> > obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o
> > diff --git a/drivers/gpu/drm/bridge/lontium-lt7911exc.c b/drivers/gpu/drm/bridge/lontium-lt7911exc.c
> > new file mode 100644
> > index 000000000000..d1c1d9e073ef
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/lontium-lt7911exc.c
> > @@ -0,0 +1,571 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2026 Lontium Semiconductor, Inc.
> > + */
> > +
> > +#include <linux/crc32.h>
> > +#include <linux/firmware.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/i2c.h>
> > +#include <linux/regmap.h>
> > +#include <drm/drm_of.h>
> > +
> > +#define FW_SIZE (64 * 1024)
> > +#define LT_PAGE_SIZE 32
> > +#define FW_FILE "LT7911EXC.bin"
>
> Other lontium bridge chips use lowercase and a _fw.bin suffix, such as
> "lt9611uxc_fw.bin". Rename to be consistent
>
it will be fixed in the next version.
> > +#define LT7911EXC_PAGE_CONTROL 0xff
> > +
> > +struct lt7911exc {
> > + struct device *dev;
> > + struct i2c_client *client;
> > + struct drm_bridge bridge;
> > + struct drm_bridge *panel_bridge;
> > + struct regmap *regmap;
> > + /* Protects all accesses to registers by stopping the on-chip MCU */
> > + struct mutex ocm_lock;
> > + struct regulator_bulk_data supplies[2];
> > +
> > + struct gpio_desc *reset_gpio;
> > + const struct firmware *fw;
> > + int fw_version;
> > + u32 fw_crc;
> > +
> > + bool enabled;
> > +};
> > +
> > +static const struct regmap_range_cfg lt7911exc_ranges[] = {
> > + {
> > + .name = "register_range",
> > + .range_min = 0,
> > + .range_max = 0xffff,
> > + .selector_reg = LT7911EXC_PAGE_CONTROL,
> > + .selector_mask = 0xff,
> > + .selector_shift = 0,
> > + .window_start = 0,
> > + .window_len = 0x100,
> > + },
> > +};
> > +
> > +static const struct regmap_config lt7911exc_regmap_config = {
> > + .reg_bits = 8,
> > + .val_bits = 8,
> > + .max_register = 0xffff,
> > + .ranges = lt7911exc_ranges,
> > + .num_ranges = ARRAY_SIZE(lt7911exc_ranges),
> > +};
> > +
> > +static u32 cal_crc32_custom(const u8 *data, u64 length)
> > +{
> > + u32 crc = 0xffffffff;
> > + u8 buf[4];
> > + u64 i;
> > +
> > + for (i = 0; i < length; i += 4) {
> > + buf[0] = data[i + 3];
> > + buf[1] = data[i + 2];
> > + buf[2] = data[i + 1];
> > + buf[3] = data[i + 0];
> > + crc = crc32_be(crc, buf, 4);
> > + }
> > +
> > + return crc;
> > +}
> > +
> > +static inline struct lt7911exc *
> > + bridge_to_lt7911exc(struct drm_bridge *bridge)
> > +{
> > + return container_of(bridge, struct lt7911exc, bridge);
> > +}
> > +
> > +static int lt7911exc_regulator_enable(struct lt7911exc *lt7911exc)
> > +{
> > + int ret;
> > +
> > + ret = regulator_enable(lt7911exc->supplies[0].consumer);
> > + if (ret < 0)
> > + return ret;
> > +
> > + usleep_range(5000, 10000);
> > +
> > + ret = regulator_enable(lt7911exc->supplies[1].consumer);
> > + if (ret < 0) {
> > + regulator_disable(lt7911exc->supplies[0].consumer);
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_regulator_disable(struct lt7911exc *lt7911exc)
> > +{
> > + int ret;
> > +
> > + ret = regulator_disable(lt7911exc->supplies[1].consumer);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = regulator_disable(lt7911exc->supplies[0].consumer);
> > + if (ret < 0)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > +static void lt7911exc_reset(struct lt7911exc *lt7911exc)
> > +{
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 1);
> > + msleep(20);
> > +
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 0);
> > + msleep(20);
> > +
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 1);
> > + msleep(400);
> > +
> > + dev_dbg(lt7911exc->dev, "lt7911exc reset");
>
> missing newline in dev_dbg(), all other calls have it.
>
it will be fixed in the next version.
dev_dbg(lt7911exc->dev, "lt7911exc reset\n");
> > +}
> > +
> > +static int lt7911exc_parse_dt(struct lt7911exc *lt7911exc)
> > +{
> > + int ret;
> > +
> > + lt7911exc->supplies[0].supply = "vcc";
> > + lt7911exc->supplies[1].supply = "vdd";
> > +
> > + ret = devm_regulator_bulk_get(lt7911exc->dev, 2, lt7911exc->supplies);
> > + if (ret) {
> > + dev_err(lt7911exc->dev, "failed get regulator\n");
> > + return ret;
> > + }
> > +
> > + lt7911exc->reset_gpio = devm_gpiod_get(lt7911exc->dev, "reset", GPIOD_OUT_LOW);
> > + if (IS_ERR(lt7911exc->reset_gpio)) {
> > + dev_err(lt7911exc->dev, "failed to acquire reset gpio\n");
> > + return PTR_ERR(lt7911exc->reset_gpio);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_read_version(struct lt7911exc *lt7911exc)
> > +{
> > + u8 buf[2];
> > + int ret;
> > +
> > + ret = regmap_bulk_read(lt7911exc->regmap, 0xe081, buf, 3);
> > + if (ret)
> > + return ret;
> > +
> > + return (buf[0] << 16) | (buf[1] << 8) | buf[2];
> > +}
> > +
> > +static void lt7911exc_lock(struct lt7911exc *lt7911exc)
> > +{
> > + mutex_lock(<7911exc->ocm_lock);
> > + regmap_write(lt7911exc->regmap, 0xe0ee, 0x01);
> > +}
> > +
> > +static void lt7911exc_unlock(struct lt7911exc *lt7911exc)
> > +{
> > + regmap_write(lt7911exc->regmap, 0xe0ee, 0x00);
> > + mutex_unlock(<7911exc->ocm_lock);
> > +}
> > +
> > +static int lt7911exc_prepare_firmware_data(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + int ret;
> > + u8 *buffer;
> > + size_t total_size = FW_SIZE - 4;
> > +
> > + ret = request_firmware(<7911exc->fw, FW_FILE, dev);
> > + if (ret) {
> > + dev_err(dev, "failed load file '%s', error type %d\n", FW_FILE, ret);
> > + return ret;
> > + }
> > +
> > + if (lt7911exc->fw->size > total_size) {
> > + dev_err(dev, "firmware too large (%zu > %zu)\n", lt7911exc->fw->size, total_size);
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > + return -EINVAL;
> > + }
> > +
> > + dev_dbg(dev, "firmware size: %zu bytes\n", lt7911exc->fw->size);
> > +
> > + buffer = kzalloc(total_size, GFP_KERNEL);
> > + if (!buffer) {
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > + return -ENOMEM;
> > + }
> > +
> > + memset(buffer, 0xff, total_size);
> > + memcpy(buffer, lt7911exc->fw->data, lt7911exc->fw->size);
> > +
> > + lt7911exc->fw_crc = cal_crc32_custom(buffer, total_size);
> > + dev_dbg(dev, "firmware crc: 0x%08x\n", lt7911exc->fw_crc);
> > +
> > + kfree(buffer);
> > + return 0;
> > +}
> > +
> > +static void lt7911exc_block_erase(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + const u32 addr = 0x00;
> > +
> > + const struct reg_sequence seq_write[] = {
> > + REG_SEQ0(0xe0ee, 0x01),
> > + REG_SEQ0(0xe054, 0x01),
> > + REG_SEQ0(0xe055, 0x06),
> > + REG_SEQ0(0xe051, 0x01),
> > + REG_SEQ0(0xe051, 0x00),
> > + REG_SEQ0(0xe054, 0x05),
> > + REG_SEQ0(0xe055, 0xd8),
> > + REG_SEQ0(0xe05a, (addr >> 16) & 0xff),
> > + REG_SEQ0(0xe05b, (addr >> 8) & 0xff),
> > + REG_SEQ0(0xe05c, addr & 0xff),
> > + REG_SEQ0(0xe051, 0x01),
> > + REG_SEQ0(0xe050, 0x00),
> > + };
> > +
> > + regmap_multi_reg_write(lt7911exc->regmap, seq_write, ARRAY_SIZE(seq_write));
> > +
> > + msleep(200);
> > + dev_dbg(dev, "erase flash done.\n");
> > +}
> > +
> > +static void lt7911exc_prog_init(struct lt7911exc *lt7911exc, u64 addr)
> > +{
> > + const struct reg_sequence seq_write[] = {
> > + REG_SEQ0(0xe0ee, 0x01),
> > + REG_SEQ0(0xe05f, 0x01),
> > + REG_SEQ0(0xe05a, (addr >> 16) & 0xff),
> > + REG_SEQ0(0xe05b, (addr >> 8) & 0xff),
> > + REG_SEQ0(0xe05c, addr & 0xff),
> > + };
> > +
> > + regmap_multi_reg_write(lt7911exc->regmap, seq_write, ARRAY_SIZE(seq_write));
> > +}
> > +
> > +static int lt7911exc_write_data(struct lt7911exc *lt7911exc, u64 addr)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + int ret;
> > + int page = 0, num = 0, page_len = 0;
> > + u64 size, offset;
> > + const u8 *data;
> > +
> > + data = lt7911exc->fw->data;
> > + size = lt7911exc->fw->size;
> > + page = (size + LT_PAGE_SIZE - 1) / LT_PAGE_SIZE;
> > + if (page * LT_PAGE_SIZE > FW_SIZE) {
> > + dev_err(dev, "firmware size out of range\n");
> > + return -EINVAL;
> > + }
> > +
> > + dev_dbg(dev, "%u pages, total size %llu byte\n", page, size);
> > +
> > + for (num = 0; num < page; num++) {
> > + offset = num * LT_PAGE_SIZE;
> > + page_len = (offset + LT_PAGE_SIZE <= size) ? LT_PAGE_SIZE : (size - offset);
> > + lt7911exc_prog_init(lt7911exc, addr);
> > +
> > + ret = regmap_raw_write(lt7911exc->regmap, 0xe05d, &data[offset], page_len);
> > + if (ret) {
> > + dev_err(dev, "write error at page %d\n", num);
> > + return ret;
> > + }
> > +
> > + if (page_len < LT_PAGE_SIZE) {
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x05);
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x01);
> > + //hardware requires delay
> > + usleep_range(1000, 2000);
> > + }
> > +
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x00);
> > + addr += LT_PAGE_SIZE;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_write_crc(struct lt7911exc *lt7911exc, u64 addr)
> > +{
> > + u8 crc[4];
> > + int ret;
> > +
> > + crc[0] = lt7911exc->fw_crc & 0xff;
> > + crc[1] = (lt7911exc->fw_crc >> 8) & 0xff;
> > + crc[2] = (lt7911exc->fw_crc >> 16) & 0xff;
> > + crc[3] = (lt7911exc->fw_crc >> 24) & 0xff;
> > +
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x01);
> > + regmap_write(lt7911exc->regmap, 0xe05a, (addr >> 16) & 0xff);
> > + regmap_write(lt7911exc->regmap, 0xe05b, (addr >> 8) & 0xff);
> > + regmap_write(lt7911exc->regmap, 0xe05c, addr & 0xff);
> > +
> > + ret = regmap_raw_write(lt7911exc->regmap, 0xe05d, crc, 4);
> > + if (ret)
> > + return ret;
>
> nit: Newline here makes it more readable
>
it will be fixed in the next version.
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x05);
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x01);
> > + usleep_range(1000, 2000);
> > + regmap_write(lt7911exc->regmap, 0xe05f, 0x00);
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_firmware_upgrade(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + int ret;
> > +
> > + ret = lt7911exc_prepare_firmware_data(lt7911exc);
> > + if (ret < 0)
> > + return ret;
> > +
> > + dev_dbg(dev, "starting firmware upgrade, size: %zu bytes\n", lt7911exc->fw->size);
> > +
> > + lt7911exc_block_erase(lt7911exc);
> > +
> > + ret = lt7911exc_write_data(lt7911exc, 0);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to write firmware data\n");
> > + return ret;
> > + }
> > +
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > +
> > + ret = lt7911exc_write_crc(lt7911exc, FW_SIZE - 4);
> > + if (ret < 0) {
> > + dev_err(dev, "failed to write firmware crc\n");
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int lt7911exc_upgrade_result(struct lt7911exc *lt7911exc)
> > +{
> > + struct device *dev = lt7911exc->dev;
> > + u32 read_hw_crc = 0;
> > + u8 crc_tmp[4];
> > + int ret;
> > +
> > + regmap_write(lt7911exc->regmap, 0xe0ee, 0x01);
> > + regmap_write(lt7911exc->regmap, 0xe07b, 0x60);
> > + regmap_write(lt7911exc->regmap, 0xe07b, 0x40);
> > + msleep(150);
> > + ret = regmap_bulk_read(lt7911exc->regmap, 0x22, crc_tmp, 4);
> > + if (ret) {
> > + dev_err(lt7911exc->dev, "Failed to read CRC: %d\n", ret);
> > + return ret;
> > + }
> > +
> > + read_hw_crc = crc_tmp[0] << 24 | crc_tmp[1] << 16 |
> > + crc_tmp[2] << 8 | crc_tmp[3];
> > +
> > + if (read_hw_crc != lt7911exc->fw_crc) {
> > + dev_err(dev, "lt7911exc firmware upgrade failed, expected CRC=0x%08x, read CRC=0x%08x\n",
> > + lt7911exc->fw_crc, read_hw_crc);
> > + return -EIO;
> > + }
> > +
> > + dev_dbg(dev, "lt7911exc firmware upgrade success, CRC=0x%08x\n", read_hw_crc);
> > + return 0;
> > +}
> > +
> > +static void lt7911exc_pre_enable(struct drm_bridge *bridge)
> > +{
> > + struct lt7911exc *lt7911exc = bridge_to_lt7911exc(bridge);
> > + int ret;
> > +
> > + if (lt7911exc->enabled)
> > + return;
> > +
> > + ret = lt7911exc_regulator_enable(lt7911exc);
> > + if (ret)
> > + return;
> > +
> > + lt7911exc_reset(lt7911exc);
> > +
> > + lt7911exc->enabled = true;
> > +}
> > +
> > +static void lt7911exc_disable(struct drm_bridge *bridge)
> > +{
> > + /* Delay after panel is disabled */
> > + msleep(20);
> > +}
> > +
> > +static void lt7911exc_post_disable(struct drm_bridge *bridge)
> > +{
> > + struct lt7911exc *lt7911exc = bridge_to_lt7911exc(bridge);
> > + int ret;
> > +
> > + if (!lt7911exc->enabled)
> > + return;
> > +
> > + lt7911exc->enabled = false;
> > +
> > + ret = lt7911exc_regulator_disable(lt7911exc);
> > + if (ret)
> > + return;
> > +
> > + gpiod_set_value_cansleep(lt7911exc->reset_gpio, 0);
> > +}
> > +
> > +static int lt7911exc_attach(struct drm_bridge *bridge,
> > + struct drm_encoder *encoder,
> > + enum drm_bridge_attach_flags flags)
> > +{
> > + struct lt7911exc *lt7911exc = bridge_to_lt7911exc(bridge);
> > +
> > + return drm_bridge_attach(lt7911exc->bridge.encoder, lt7911exc->panel_bridge,
> > + <7911exc->bridge, flags);
> > +}
> > +
> > +static const struct drm_bridge_funcs lt7911exc_bridge_funcs = {
> > + .pre_enable = lt7911exc_pre_enable,
> > + .disable = lt7911exc_disable,
> > + .post_disable = lt7911exc_post_disable,
>
> These are all deprecated, is there any reason to use them and not the
> atomic_* callbacks?
>
it will be fixed in the next version.
> > + .attach = lt7911exc_attach,
> > +};
> > +
> > +static int lt7911exc_probe(struct i2c_client *client)
> > +{
> > + struct device *dev = &client->dev;
> > + struct lt7911exc *lt7911exc;
> > + struct drm_bridge *panel_bridge;
> > + bool fw_updated = false;
> > + int ret;
> > +
> > + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> > + dev_err(dev, "device doesn't support I2C\n");
> > + return -ENODEV;
> > + }
> > +
> > + lt7911exc = devm_drm_bridge_alloc(dev, struct lt7911exc, bridge,
> > + <7911exc_bridge_funcs);
> > + if (IS_ERR(lt7911exc))
> > + return PTR_ERR(lt7911exc);
> > +
> > + panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
> > + if (IS_ERR(panel_bridge))
> > + return PTR_ERR(panel_bridge);
> > +
> > + lt7911exc->panel_bridge = panel_bridge;
> > + lt7911exc->client = client;
> > + lt7911exc->dev = dev;
> > + i2c_set_clientdata(client, lt7911exc);
> > + mutex_init(<7911exc->ocm_lock);
> > +
> > + lt7911exc->regmap = devm_regmap_init_i2c(client, <7911exc_regmap_config);
> > + if (IS_ERR(lt7911exc->regmap)) {
> > + dev_err(dev, "regmap i2c init failed\n");
> > + return PTR_ERR(lt7911exc->regmap);
> > + }
> > +
> > + ret = lt7911exc_parse_dt(lt7911exc);
> > + if (ret)
> > + return ret;
> > +
> > + ret = lt7911exc_regulator_enable(lt7911exc);
> > + if (ret)
> > + return ret;
> > +
> > + lt7911exc_reset(lt7911exc);
> > + lt7911exc->enabled = true;
> > + lt7911exc_lock(lt7911exc);
> > +
> > +retry:
> > + lt7911exc->fw_version = lt7911exc_read_version(lt7911exc);
> > + if (lt7911exc->fw_version < 0) {
> > + dev_err(dev, "failed to read FW version\n");
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > +
> > + } else if (lt7911exc->fw_version == 0) {
> > + if (!fw_updated) {
> > + fw_updated = true;
> > + ret = lt7911exc_firmware_upgrade(lt7911exc);
> > + if (ret < 0) {
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > + }
> > +
> > + lt7911exc_reset(lt7911exc);
> > +
> > + ret = lt7911exc_upgrade_result(lt7911exc);
> > + if (ret < 0) {
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > + }
> > +
> > + goto retry;
> > +
> > + } else {
> > + dev_err(dev, "fw version 0x%04x, update failed\n", lt7911exc->fw_version);
> > + ret = -EOPNOTSUPP;
> > + lt7911exc_unlock(lt7911exc);
> > + goto err_disable_regulators;
> > + }
> > + }
> > +
> > + lt7911exc_unlock(lt7911exc);
> > +
> > + lt7911exc->bridge.type = DRM_MODE_CONNECTOR_DSI;
> > + lt7911exc->bridge.of_node = dev->of_node;
> > + drm_bridge_add(<7911exc->bridge);
> > +
> > + return 0;
> > +
> > +err_disable_regulators:
> > + regulator_bulk_disable(ARRAY_SIZE(lt7911exc->supplies), lt7911exc->supplies);
> > + if (lt7911exc->fw) {
> > + release_firmware(lt7911exc->fw);
> > + lt7911exc->fw = NULL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void lt7911exc_remove(struct i2c_client *client)
> > +{
> > + struct lt7911exc *lt7911exc = i2c_get_clientdata(client);
> > +
> > + drm_bridge_remove(<7911exc->bridge);
> > + mutex_destroy(<7911exc->ocm_lock);
> > +}
> > +
> > +static const struct i2c_device_id lt7911exc_i2c_table[] = {
> > + {"lontium, lt7911exc", 0},
>
> Extra space here in the device id
>
it will be fixed in the next version. {"lontium, lt7911exc"},
> > + { /* sentinel */ }
> > +};
> > +
> > +MODULE_DEVICE_TABLE(i2c, lt7911exc_i2c_table);
> > +
> > +static const struct of_device_id lt7911exc_devices[] = {
> > + {.compatible = "lontium,lt7911exc",},
> > + {}
> > +};
> > +MODULE_DEVICE_TABLE(of, lt7911exc_devices);
> > +
> > +static struct i2c_driver lt7911exc_driver = {
> > + .id_table = lt7911exc_i2c_table,
> > + .probe = lt7911exc_probe,
> > + .remove = lt7911exc_remove,
> > + .driver = {
> > + .name = "lt7911exc",
> > + .of_match_table = lt7911exc_devices,
> > + },
> > +};
> > +module_i2c_driver(lt7911exc_driver);
> > +
> > +MODULE_AUTHOR("SunYun Yang <syyang@lontium.com>");
> > +MODULE_DESCRIPTION("Lontium lt7911exc edp to mipi dsi bridge driver");
> > +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply
* Re: [PATCH v9 6/7] i3c: hub: Add support for the I3C interface in the I3C hub
From: Frank Li @ 2026-04-21 3:28 UTC (permalink / raw)
To: Lakshay Piplani
Cc: linux-kernel, linux-i3c, alexandre.belloni, krzk+dt, robh,
conor+dt, devicetree, broonie, lee, lgirdwood, vikash.bansal,
priyanka.jain, aman.kumarpandey
In-Reply-To: <20260420105222.1562243-7-lakshay.piplani@nxp.com>
On Mon, Apr 20, 2026 at 04:22:21PM +0530, Lakshay Piplani wrote:
> Add virtual I3C bus support for the hub and provide interface to enable
> or disable downstream ports.
>
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
> Signed-off-by: Vikash Bansal <vikash.bansal@nxp.com>
> Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
>
> ---
> Changes in v9:
> - No change
>
> Changes in v8:
> - No change
>
> Changes in v7:
> - Convert Kconfig option to tristate
> - Fix signedness issue in return value
> - Fix kernel-doc warnings
>
> Changes in v6:
> - Add support for the generic I3C interface in the I3C Hub
> ---
> ---
> MAINTAINERS | 2 +
> drivers/i3c/Kconfig | 15 ++
> drivers/i3c/Makefile | 1 +
> drivers/i3c/hub.c | 460 ++++++++++++++++++++++++++++++++++++++++
> include/linux/i3c/hub.h | 107 ++++++++++
> 5 files changed, 585 insertions(+)
> create mode 100644 drivers/i3c/hub.c
> create mode 100644 include/linux/i3c/hub.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b2119fadef7b..bb3e8e9674c4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19274,8 +19274,10 @@ L: linux-kernel@vger.kernel.org
> L: linux-i3c-owner@lists.infradead.org
> S: Maintained
> F: Documentation/devicetree/bindings/i3c/nxp,p3h2840.yaml
> +F: drivers/i3c/hub.c
> F: drivers/mfd/p3h2840.c
> F: drivers/regulator/p3h2840_i3c_hub_regulator.c
> +F: include/linux/i3c/hub.h
> F: include/linux/mfd/p3h2840.h
>
> NXP PF5300/PF5301/PF5302 PMIC REGULATOR DEVICE DRIVER
> diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
> index 626c54b386d5..65304b416bb4 100644
> --- a/drivers/i3c/Kconfig
> +++ b/drivers/i3c/Kconfig
> @@ -21,6 +21,21 @@ menuconfig I3C
>
> if I3C
> source "drivers/i3c/master/Kconfig"
> +
> +config I3C_HUB
> + tristate "I3C Hub Support"
> + depends on I3C
> + help
> + Enable support for the I3C interface in hub devices.
> +
> + This option adds virtual I3C bus support for hubs by creating
> + virtual master controllers for downstream ports and forwarding
> + bus operations through the hub device. It also provides an
> + interface used by hub drivers to enable or disable downstream
> + ports during bus transactions.
> +
> + Say Y here if your platform includes an I3C hub device
> +
> endif # I3C
>
> config I3C_OR_I2C
> diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile
> index 11982efbc6d9..9ddee56a6338 100644
> --- a/drivers/i3c/Makefile
> +++ b/drivers/i3c/Makefile
> @@ -2,3 +2,4 @@
> i3c-y := device.o master.o
> obj-$(CONFIG_I3C) += i3c.o
> obj-$(CONFIG_I3C) += master/
> +obj-$(CONFIG_I3C_HUB) += hub.o
> diff --git a/drivers/i3c/hub.c b/drivers/i3c/hub.c
> new file mode 100644
> index 000000000000..67c5d2695a61
> --- /dev/null
> +++ b/drivers/i3c/hub.c
> @@ -0,0 +1,460 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2026 NXP
> + * Generic I3C Hub core implementing virtual controller operations.
> + */
> +#include <linux/i3c/device.h>
> +#include <linux/i3c/hub.h>
> +
> +#include "internals.h"
> +
> +/**
> + * i3c_hub_master_bus_init() - Bind controller to hub device
> + * @controller: Virtual controller for a hub port
> + *
> + * Associates the virtual controller with the hub device descriptor so that
> + * transfers are executed through the hub on the parent bus.
> + */
> +static int i3c_hub_master_bus_init(struct i3c_master_controller *controller)
> +{
> + struct i3c_hub_controller *hub_controller;
> + struct i3c_hub *hub;
> +
> + hub_controller = dev_get_drvdata(&controller->dev);
> + if (!hub_controller || !hub_controller->hub)
> + return -ENODEV;
> +
> + hub = hub_controller->hub;
> +
> + if (!hub->hub_dev)
> + return -ENODEV;
> +
> + controller->this = hub->hub_dev->desc;
> + return 0;
> +}
> +
> +static void i3c_hub_master_bus_cleanup(struct i3c_master_controller *controller)
> +{
> + controller->this = NULL;
> +}
> +
> +static int i3c_hub_attach_i3c_dev(struct i3c_dev_desc *dev)
> +{
> + return 0;
> +}
> +
> +static int i3c_hub_reattach_i3c_dev(struct i3c_dev_desc *dev, u8 old_dyn_addr)
> +{
> + return 0;
> +}
> +
> +static void i3c_hub_detach_i3c_dev(struct i3c_dev_desc *dev)
> +{
> +}
> +
> +/**
> + * i3c_hub_do_daa() - Perform DAA via hub port
> + * @hub: Hub instance
> + * @controller: Virtual controller for a hub port
> + *
> + * Enables the port connection, performs DAA on the parent controller,
> + * then disables the connection.
> + */
> +static int i3c_hub_do_daa(struct i3c_hub *hub,
> + struct i3c_master_controller *controller)
> +{
> + int ret;
> +
> + if (!hub || !hub->parent)
> + return -ENODEV;
> +
> + i3c_hub_enable_port(controller);
> + ret = i3c_master_do_daa(hub->parent);
> + i3c_hub_disable_port(controller);
> +
> + return ret;
> +}
> +
> +static bool i3c_hub_supports_ccc_cmd(struct i3c_hub *hub,
> + const struct i3c_ccc_cmd *cmd)
> +{
> + return i3c_master_supports_ccc_cmd(hub->parent, cmd);
> +}
> +
> +/**
> + * i3c_hub_send_ccc_cmd() - Send CCC through hub port
> + * @hub: Hub instance
> + * @controller: Virtual controller
> + * @cmd: CCC command
> + *
> + * Enables the port connection while issuing CCC on the parent controller.
> + */
> +static int i3c_hub_send_ccc_cmd(struct i3c_hub *hub,
> + struct i3c_master_controller *controller,
> + struct i3c_ccc_cmd *cmd)
> +{
> + int ret;
> +
> + if (!hub || !hub->parent)
> + return -ENODEV;
> +
> + i3c_hub_enable_port(controller);
> + ret = i3c_master_send_ccc_cmd(hub->parent, cmd);
> + i3c_hub_disable_port(controller);
> +
> + return ret;
> +}
> +
> +/**
> + * i3c_hub_master_priv_xfers() - Execute private transfers via hub
> + * @dev: Target device descriptor
> + * @xfers: Transfer array
> + * @nxfers: Number of transfers
> + * @mode: transfer mode (SDR, HDR, etc.)
> + *
> + * Handles address adjustment and forwards private transfers through the hub
> + * device.
> + */
> +static int i3c_hub_master_priv_xfers(struct i3c_dev_desc *dev,
> + struct i3c_xfer *xfers,
> + int nxfers,
> + enum i3c_xfer_mode mode)
> +{
> + struct i3c_master_controller *controller = i3c_dev_get_master(dev);
> + struct i3c_hub_controller *hub_controller;
> + struct i3c_dev_desc *hub_dev;
> + u8 hub_addr, target_addr;
> + struct i3c_hub *hub;
> + int ret;
> +
> + hub_controller = dev_get_drvdata(&controller->dev);
> + if (!hub_controller || !hub_controller->hub)
> + return -ENODEV;
> +
> + hub = hub_controller->hub;
> +
> + if (!hub->hub_dev)
> + return -ENODEV;
> +
> + hub_dev = hub->hub_dev->desc;
> +
> + i3c_hub_enable_port(controller);
> +
> + hub_addr = hub_dev->info.dyn_addr ?
> + hub_dev->info.dyn_addr : hub_dev->info.static_addr;
> +
> + target_addr = dev->info.dyn_addr ?
> + dev->info.dyn_addr : dev->info.static_addr;
> +
> + if (hub_addr != target_addr) {
> + hub_dev->info.dyn_addr = target_addr;
> + ret = i3c_master_reattach_i3c_dev(hub_dev, target_addr);
> + if (ret)
> + goto disable;
> + }
> +
> + ret = i3c_device_do_xfers(hub->hub_dev, xfers, nxfers, mode);
> +
> + if (hub_addr != target_addr) {
> + hub_dev->info.dyn_addr = hub_addr;
> + ret |= i3c_master_reattach_i3c_dev(hub_dev, hub_addr);
> + }
> +
> +disable:
> + i3c_hub_disable_port(controller);
> + return ret;
> +}
> +
> +static int i3c_hub_attach_i2c_dev(struct i2c_dev_desc *dev)
> +{
> + return 0;
> +}
> +
> +static void i3c_hub_detach_i2c_dev(struct i2c_dev_desc *dev)
> +{
> +}
> +
> +static int i3c_hub_i2c_xfers(struct i2c_dev_desc *dev,
> + struct i2c_msg *xfers, int nxfers)
> +{
> + return 0;
> +}
> +
> +static int i3c_hub_master_do_daa(struct i3c_master_controller *controller)
> +{
> + struct i3c_hub_controller *hub_controller;
> + struct i3c_hub *hub;
> +
> + hub_controller = dev_get_drvdata(&controller->dev);
> + if (!hub_controller || !hub_controller->hub)
> + return -ENODEV;
> +
> + hub = hub_controller->hub;
> +
> + return i3c_hub_do_daa(hub, controller);
> +}
> +
> +static int i3c_hub_master_send_ccc_cmd(struct i3c_master_controller *controller,
> + struct i3c_ccc_cmd *cmd)
> +{
> + struct i3c_hub_controller *hub_controller;
> + struct i3c_hub *hub;
> +
> + hub_controller = dev_get_drvdata(&controller->dev);
> + if (!hub_controller || !hub_controller->hub)
> + return -ENODEV;
> +
> + hub = hub_controller->hub;
> +
> + if (!hub->parent)
> + return -ENODEV;
> +
> + if (cmd->id == I3C_CCC_RSTDAA(true))
> + return 0;
> +
> + return i3c_hub_send_ccc_cmd(hub, controller, cmd);
> +}
> +
> +static bool i3c_hub_master_supports_ccc_cmd(struct i3c_master_controller *controller,
> + const struct i3c_ccc_cmd *cmd)
> +{
> + struct i3c_hub_controller *hub_controller;
> + struct i3c_hub *hub;
> +
> + hub_controller = dev_get_drvdata(&controller->dev);
> + if (!hub_controller || !hub_controller->hub)
> + return false;
> +
> + hub = hub_controller->hub;
> +
> + return i3c_hub_supports_ccc_cmd(hub, cmd);
> +}
> +
> +/**
> + * i3c_hub_request_ibi() - Request IBI through parent controller
> + * @desc: Target device descriptor
> + * @req: IBI setup
> + *
> + * Temporarily updates parent controller context to request IBI for a device
> + * connected through the hub.
> + */
> +static int i3c_hub_request_ibi(struct i3c_dev_desc *desc,
> + const struct i3c_ibi_setup *req)
> +{
> + struct i3c_master_controller *controller = i3c_dev_get_master(desc);
> + struct i3c_hub_controller *hub_controller;
> + struct i3c_master_controller *orig_parent;
> + struct i3c_master_controller *parent;
> + struct i3c_hub *hub;
> + int ret;
> +
> + hub_controller = dev_get_drvdata(&controller->dev);
> + if (!hub_controller || !hub_controller->hub)
> + return -ENODEV;
> +
> + hub = hub_controller->hub;
> +
> + if (!hub->parent)
> + return -ENODEV;
> +
> + parent = hub->parent;
> +
> + orig_parent = i3c_hub_update_desc_parent(&desc->common, parent);
> +
> + ret = i3c_master_direct_attach_i3c_dev(parent, desc);
> + if (ret) {
> + i3c_hub_restore_desc_parent(&desc->common, orig_parent);
> + return ret;
> + }
> +
> + mutex_unlock(&desc->ibi_lock);
why need unlock desc->ibi_lock firstly? If have to do that, need comments
because it is uncommon and try to avoid this kinds of situation.
Frank
^ permalink raw reply
* Re: [net-next v2 3/5] dt-bindings: net: starfive,jh7110-dwmac: Add JHB100 sgmii rx clk
From: Minda Chen @ 2026-04-21 3:07 UTC (permalink / raw)
To: Rob Herring
Cc: Alexandre Torgue, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
Emil Renner Berthing, Krzysztof Kozlowski, Conor Dooley,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
devicetree@vger.kernel.org
In-Reply-To: <20260420133930.GA2322456-robh@kernel.org>
>
> On Fri, Apr 17, 2026 at 10:45:21AM +0800, Minda Chen wrote:
> > JHB100 SGMII interface tx/rx mac clock is split and require to set
> > clock rate in 10M/100M/1000M speed. So dts need to add a new rx clock
> > in code, dts and dt binding doc.
> >
> > Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
> > ---
> > .../bindings/net/starfive,jh7110-dwmac.yaml | 42 ++++++++++++++++---
> > 1 file changed, 36 insertions(+), 6 deletions(-)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > index edc246a71ce3..3802cdbf1848 100644
> > --- a/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > +++ b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > @@ -39,20 +39,26 @@ properties:
> > maxItems: 1
> >
> > clocks:
> > + minItems: 5
> > items:
> > - description: GMAC main clock
> > - description: GMAC AHB clock
> > - description: PTP clock
> > - description: TX clock
> > - description: GTX clock
> > + - description: SGMII RX clock
> >
> > clock-names:
> > - items:
> > - - const: stmmaceth
> > - - const: pclk
> > - - const: ptp_ref
> > - - const: tx
> > - - const: gtx
> > + minItems: 5
> > + maxItems: 6
> > + contains:
> > + enum:
> > + - stmmaceth
> > + - pclk
> > + - ptp_ref
> > + - tx
> > + - gtx
> > + - sgmii_rx
>
> No, this allows any of the above strings plus any other random strings.
>
> Rob
Got it. Thanks. In JHB100 I will using "oneOf" 5 clocks or 6 clocks. 7100/7100 are const clock names
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: bridge: This patch adds new content to the lontium,lt9611.yaml binding file
From: 杨孙运 @ 2026-04-21 3:39 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: syyang, robh, krzk+dt, conor+dt, andrzej.hajda, neil.armstrong,
dmitry.baryshkov, maarten.lankhorst, rfoss, mripard,
Laurent.pinchart, jonas, jernej.skrabec, devicetree, dri-devel,
linux-kernel, xmzhu, tzimmermann, xmzhu, xbpeng, rlyu
In-Reply-To: <6f3a890f-3bc3-450e-b3a1-20fa7e84fb8a@kernel.org>
Krzysztof Kozlowski <krzk@kernel.org> 于2026年4月20日周一 22:18写道:
>
> On 20/04/2026 16:15, Krzysztof Kozlowski wrote:
> > On Mon, Apr 20, 2026 at 01:33:46PM +0200, Krzysztof Kozlowski wrote:
> >>> -audio
> >>> 1.sample rates of 32~192 KHz and sample sizes
> >>> of 16~24 bits
> >>> 2.SPDIF interface supports PCM, Dolbydigital, DTS digital audio
> >>> at up to 192KHz frame rate
> >>>
> >>> -Miscellaneous
> >>> 1.CSC:RGB<->YUV444<->YUV422
> >>
> >> Commit msg is not a datasheet introduction chapter. What does this all
> >> mean for compatibility? What is the benefit of listing all this?
> >>
> >> You did not even explain the differences between C, UX and EXD, so all
> >> above is pointless. Explain the differences and why devices are not
> >> compatible.
> >>
First of all, I'm sorry for the trouble I've caused you.
Secondly, when adding a new chip, my intention in writing this was to
let reviewers understand the chip's capabilities.
Then, the C, EX, and UXD are a series of chips within the same product
family, with differences in hardware features:
- LT9611UXD: Supports 2-port MIPI DSI → HDMI 1.4/2.0
- LT9611C: Supports 1-port MIPI DSI → HDMI 1.4
- LT9611EX: Supports 2-port MIPI DSI → HDMI 1.4
Finally, it will be fixed in the next version.
> >
> > Also, you have checkpatch errors.
> >
it will be fixed in the next version.
>
> ... and finally (apologies for making it in three emails, checkpatch
> warnings come from different toolset): your subject is pretty breaking
> every standard rule.
>
> It's redundant, not informative in various ways. It misses proper
> prefix, it misses even basic description WHAT. Everything can be a "new
> content".
>
it will be fixed in the next version.
> Please use subject prefixes matching the subsystem. You can get them for
> example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
> your patch is touching. For bindings, the preferred subjects are
> explained here:
> https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
>
> Please do not use "This commit/patch/change", but imperative mood. See
> longer explanation here:
> https://elixir.bootlin.com/linux/v6.16/source/Documentation/process/submitting-patches.rst#L94
>
> Drop second/last, redundant "bindings". The "dt-bindings" prefix is
> already stating that these are bindings.
> See also:
> https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
>
> And obviously "file" is pointless. Can you add content NOT to a file?
> Like add it to a directory?
>
it will be fixed in the next version. thks
>
> Best regards,
> Krzysztof
^ permalink raw reply
* Re: [PATCH v9 7/7] i3c: hub: p3h2x4x: Add support for NXP P3H2x4x I3C hub functionality
From: Frank Li @ 2026-04-21 3:50 UTC (permalink / raw)
To: Lakshay Piplani
Cc: linux-kernel, linux-i3c, alexandre.belloni, krzk+dt, robh,
conor+dt, devicetree, broonie, lee, lgirdwood, vikash.bansal,
priyanka.jain, aman.kumarpandey
In-Reply-To: <20260420105222.1562243-8-lakshay.piplani@nxp.com>
On Mon, Apr 20, 2026 at 04:22:22PM +0530, Lakshay Piplani wrote:
> From: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
>
> Add I3C hub functionality for the NXP P3H2x4x family of multiport hubs.
> These devices support downstream target ports that can be configured
> as I3C, I2C, or SMBus.
>
> This driver enables:
> - I3C/I2C communication between host and hub
> - Transparent communication with downstream devices
> - Target port configuration (I3C/I2C/SMBus)
> - MCTP device support
> - In-band interrupt handling
>
> P3H2440/P3H2441 support 4 target ports.
> P3H2840/P3H2841 support 8 target ports.
>
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@nxp.com>
> Signed-off-by: Vikash Bansal <vikash.bansal@nxp.com>
> Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
>
...
> +static int p3h2x4x_configure_ldo(struct device *dev)
> +{
> + static const char * const supplies[] = {
> + "vcc1",
> + "vcc2",
> + "vcc3",
> + "vcc4"
> + };
> + int ret, i;
> +
> + for (i = 0; i < ARRAY_SIZE(supplies); i++) {
> + ret = devm_regulator_get_enable_optional(dev->parent, supplies[i]);
> + if (ret == -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> +
> + if (ret && ret != -ENODEV)
> + dev_warn(dev, "Failed to enable %s (%d)\n",
> + supplies[i], ret);
> + }
> +
> + /* This delay is required for the regulator to stabilize its output voltage */
> + mdelay(5);
Now perfer use fsleep()
...
> +int p3h2x4x_tp_i3c_algo(struct p3h2x4x_i3c_hub_dev *p3h2x4x_hub)
> +{
> + struct i3c_master_controller *parent = i3c_dev_get_master(p3h2x4x_hub->i3cdev->desc);
> + u8 tp, ntwk_mask = 0;
> + int ret;
> +
> + p3h2x4x_hub->hub = i3c_hub_init(parent,
> + &p3h2x4x_hub_ops,
> + p3h2x4x_hub->i3cdev);
> +
> + if (IS_ERR(p3h2x4x_hub->hub))
> + return PTR_ERR(p3h2x4x_hub->hub);
> +
> + for (tp = 0; tp < P3H2X4X_TP_MAX_COUNT; tp++) {
> + if (!p3h2x4x_hub->tp_bus[tp].of_node ||
> + p3h2x4x_hub->hub_config.tp_config[tp].mode != P3H2X4X_TP_MODE_I3C)
> + continue;
> +
> + /* Assign DT node for this TP */
> + p3h2x4x_hub->dev->of_node = p3h2x4x_hub->tp_bus[tp].of_node;
device_set_of_node_from_dev()
...
> + * I2C algorithm Structure
> + */
> +static struct i2c_algorithm p3h2x4x_tp_i2c_algorithm = {
> + .master_xfer = p3h2x4x_tp_i2c_xfer,
> +#if IS_ENABLED(CONFIG_I2C_SLAVE)
If slave mode is not essesical, suggest add later, this patch is already
big.
Frank
^ permalink raw reply
* [PATCH 2/2] mmc: core: Parse property for aggressive power management
From: Shawn Lin @ 2026-04-21 2:46 UTC (permalink / raw)
To: Ulf Hansson
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, devicetree,
linux-kernel, linux-rockchip, Shawn Lin
In-Reply-To: <1776739609-122962-1-git-send-email-shawn.lin@rock-chips.com>
Aggressive power management is a framework-level policy rather than
a host driver or controller-specific feature. Currently, this
capability must be enabled by individual host drivers, which has led
to inconsistent adoption and limited real-world testing. This
all-or-nothing approach is inflexible, as the optimal setting depends
on the specific product requirements and usage patterns.
Introduce a new device-tree property "cap-aggressive-pm" to allow
platform-specific configuration of the MMC_CAP_AGGRESSIVE_PM flag.
This enables more aggressive runtime power management strategies that
can significantly improve power efficiency in certain scenarios.
However, the benefits of this feature are highly workload-dependent.
While it reduces power consumption during idle periods, it may also
introduce additional resume latency from low-power states. Therefore,
it should be configurable rather than hardcoded, allowing different
products to balance power savings against performance requirements.
By exposing this as a device-tree property, system integrators can
selectively enable aggressive power management for specific products
or use cases where power savings outweigh potential performance impact.
For example, it could be enabled on battery-powered devices where
power efficiency is critical, but disabled on always-connected devices
where low latency is more important.
This change provides the flexibility needed to optimize for different
market segments and user scenarios without requiring driver modifications.
Existing drivers that previously set MMC_CAP_AGGRESSIVE_PM can now
remove those hardcoded settings in favor of device-tree configuration.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---
drivers/mmc/core/host.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index b7ce313..abe61c7 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -400,6 +400,8 @@ int mmc_of_parse(struct mmc_host *host)
if (device_property_read_bool(dev, "no-mmc-hs400"))
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
+ if (device_property_read_bool(dev, "cap-aggressive-pm"))
+ host->caps |= MMC_CAP_AGGRESSIVE_PM;
/* Must be after "non-removable" check */
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
--
2.7.4
^ permalink raw reply related
* [PATCH 1/2] dt-bindings: mmc: Add cap-aggressive-pm property
From: Shawn Lin @ 2026-04-21 2:46 UTC (permalink / raw)
To: Ulf Hansson
Cc: Krzysztof Kozlowski, Rob Herring, Conor Dooley, devicetree,
linux-kernel, linux-rockchip, Shawn Lin
In-Reply-To: <1776739609-122962-1-git-send-email-shawn.lin@rock-chips.com>
Introduce a new optional device tree property cap-aggressive-pm for
the mmc framework to perform aggressive power management strategy.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---
Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml b/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
index 3d7195e..3c3e5ce 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
+++ b/Documentation/devicetree/bindings/mmc/mmc-controller-common.yaml
@@ -177,6 +177,11 @@ properties:
description:
enable SDIO IRQ signalling on this interface
+ cap-aggressive-pm:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ Enable aggressive power management strategy.
+
full-pwr-cycle:
$ref: /schemas/types.yaml#/definitions/flag
description:
--
2.7.4
^ permalink raw reply related
* [PATCH 0/2] Add SoC ID for Nord SA8797P
From: Shawn Guo @ 2026-04-21 4:02 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Dmitry Baryshkov, Bartosz Golaszewski, Deepti Jaggi, devicetree,
linux-arm-msm, linux-kernel, Shawn Guo
Nord is a SoC family from Qualcomm designed as the next generation of
Lemans series. SA8797P is the automotive variant of Nord, where the
platform resources such as clocks, regulators, interconnects, etc. are
managed by firmware through SCMI.
This series adds Nord SA8797P SoC ID to dt-bindngs header and socinfo
driver.
The SoC ID of Nord IoT variant will be added separately later.
Deepti Jaggi (2):
dt-bindings: arm: qcom,ids: Add SoC ID for Nord SA8797P
soc: qcom: socinfo: Add SoC ID for Nord SA8797P
drivers/soc/qcom/socinfo.c | 1 +
include/dt-bindings/arm/qcom,ids.h | 1 +
2 files changed, 2 insertions(+)
--
2.43.0
^ permalink raw reply
* [PATCH 1/2] dt-bindings: arm: qcom,ids: Add SoC ID for Nord SA8797P
From: Shawn Guo @ 2026-04-21 4:02 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Dmitry Baryshkov, Bartosz Golaszewski, Deepti Jaggi, devicetree,
linux-arm-msm, linux-kernel, Shawn Guo
In-Reply-To: <20260421040231.1256998-1-shengchao.guo@oss.qualcomm.com>
From: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
Nord is a SoC family from Qualcomm designed as the next generation of
Lemans series. SA8797P is the automotive variant of Nord, where
the platform resources such as clocks, regulators, interconnects, etc.
are managed by firmware through SCMI.
Add SoC ID for Nord SA8797P.
Signed-off-by: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
---
include/dt-bindings/arm/qcom,ids.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h
index 336f7bb7188a..be4657417192 100644
--- a/include/dt-bindings/arm/qcom,ids.h
+++ b/include/dt-bindings/arm/qcom,ids.h
@@ -297,6 +297,7 @@
#define QCOM_ID_QCS8275 675
#define QCOM_ID_QCS9075 676
#define QCOM_ID_QCS615 680
+#define QCOM_ID_SA8797P 690
#define QCOM_ID_CQ7790M 731
#define QCOM_ID_CQ7790S 732
#define QCOM_ID_IPQ5200 765
--
2.43.0
^ permalink raw reply related
* [PATCH 2/2] soc: qcom: socinfo: Add SoC ID for Nord SA8797P
From: Shawn Guo @ 2026-04-21 4:02 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Dmitry Baryshkov, Bartosz Golaszewski, Deepti Jaggi, devicetree,
linux-arm-msm, linux-kernel, Shawn Guo
In-Reply-To: <20260421040231.1256998-1-shengchao.guo@oss.qualcomm.com>
From: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
Nord is a SoC family from Qualcomm designed as the next generation of
Lemans series. SA8797P is the automotive variant of Nord, where
the platform resources such as clocks, regulators, interconnects, etc.
are managed by firmware through SCMI.
Add Nord SA8797P SoC ID to socinfo driver.
Signed-off-by: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
---
drivers/soc/qcom/socinfo.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 8ffd903ebddb..3a35f0f6898a 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -526,6 +526,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(QCS8275) },
{ qcom_board_id(QCS9075) },
{ qcom_board_id(QCS615) },
+ { qcom_board_id(SA8797P) },
{ qcom_board_id(CQ7790M) },
{ qcom_board_id(CQ7790S) },
{ qcom_board_id(IPQ5200) },
--
2.43.0
^ permalink raw reply related
* [PATCH v4 1/2] dt-bindings: input: Add PixArt PAJ7620 gesture sensor
From: Harpreet Saini @ 2026-04-21 4:12 UTC (permalink / raw)
To: dmitry.torokhov, robh, krzysztof.kozlowski
Cc: Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Bjorn Andersson, Marek Vasut, Lad Prabhakar, Kael D'Alcamo,
linux-input, devicetree, linux-kernel
In-Reply-To: <20260421041505.4548-1-sainiharpreet29@yahoo.com>
Add Device Tree bindings for Pixart PAJ7620 gesture sensor.
The sensor supports 9 hand gestures via I2C interface.
The GPIO controller properties are included to describe the
hardware's ability to repurpose SPI pins as GPIOs when the
sensor is used in I2C mode.
Signed-off-by: Harpreet Saini <sainiharpreet29@yahoo.com>
---
.../bindings/input/pixart,paj7620.yaml | 84 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
2 files changed, 86 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/pixart,paj7620.yaml
diff --git a/Documentation/devicetree/bindings/input/pixart,paj7620.yaml b/Documentation/devicetree/bindings/input/pixart,paj7620.yaml
new file mode 100644
index 000000000000..089e864e82ea
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/pixart,paj7620.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/pixart,paj7620.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PixArt PAJ7620 Gesture Sensor
+
+maintainers:
+ - Harpreet Saini <sainiharpreet29@yahoo.com>
+
+description:
+ The PixArt PAJ7620 is a gesture recognition sensor with an integrated
+ infrared LED and CMOS array. It communicates over an I2C interface and
+ provides gesture data via a dedicated interrupt pin. When operating in
+ I2C mode, the unused SPI pins can be repurposed as GPIOs.
+
+allOf:
+ - $ref: input.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: pixart,paj7620
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-supply:
+ description: Main power supply.
+
+ vbus-supply:
+ description: I/O and I2C bus power supply.
+
+ vled-supply:
+ description: Power for the integrated IR LED.
+
+ linux,keycodes:
+ minItems: 9
+ maxItems: 9
+ description:
+ List of keycodes mapping to the 9 supported gestures.
+
+ gpio-controller: true
+
+ "#gpio-cells":
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - vdd-supply
+ - vbus-supply
+ - vled-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/input/input.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gesture@73 {
+ compatible = "pixart,paj7620";
+ reg = <0x73>;
+ interrupt-parent = <&gpio>;
+ interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <®_3v3>;
+ vbus-supply = <®_1v8>;
+ vled-supply = <®_3v3>;
+ linux,keycodes = <KEY_UP KEY_DOWN KEY_LEFT KEY_RIGHT
+ KEY_ENTER KEY_BACK KEY_NEXT KEY_PREVIOUS
+ KEY_MENU>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ee7fd3cfe203..d73a0bf62b62 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1273,6 +1273,8 @@ patternProperties:
description: Pine64
"^pineriver,.*":
description: Shenzhen PineRiver Designs Co., Ltd.
+ "^pixart,.*":
+ description: PixArt Imaging Inc.
"^pixcir,.*":
description: PIXCIR MICROELECTRONICS Co., Ltd
"^plantower,.*":
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/2] dt-bindings: arm: qcom,ids: Add SoC ID for Nord SA8797P
From: Jingyi Wang @ 2026-04-21 4:19 UTC (permalink / raw)
To: Shawn Guo, Bjorn Andersson
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Dmitry Baryshkov, Bartosz Golaszewski, Deepti Jaggi, devicetree,
linux-arm-msm, linux-kernel
In-Reply-To: <20260421040231.1256998-2-shengchao.guo@oss.qualcomm.com>
On 4/21/2026 12:02 PM, Shawn Guo wrote:
> From: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
>
> Nord is a SoC family from Qualcomm designed as the next generation of
> Lemans series. SA8797P is the automotive variant of Nord, where
Nitpick: extra space. Ditto for patch2
Thanks,
Jingyi
> the platform resources such as clocks, regulators, interconnects, etc.
> are managed by firmware through SCMI.
>
> Add SoC ID for Nord SA8797P.
>
> Signed-off-by: Deepti Jaggi <deepti.jaggi@oss.qualcomm.com>
> Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
> ---
> include/dt-bindings/arm/qcom,ids.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h
> index 336f7bb7188a..be4657417192 100644
> --- a/include/dt-bindings/arm/qcom,ids.h
> +++ b/include/dt-bindings/arm/qcom,ids.h
> @@ -297,6 +297,7 @@
> #define QCOM_ID_QCS8275 675
> #define QCOM_ID_QCS9075 676
> #define QCOM_ID_QCS615 680
> +#define QCOM_ID_SA8797P 690
> #define QCOM_ID_CQ7790M 731
> #define QCOM_ID_CQ7790S 732
> #define QCOM_ID_IPQ5200 765
^ permalink raw reply
* Re: [PATCH v3 4/7] arm64: dts: qcom: talos: Add QSPI support
From: Viken Dadhaniya @ 2026-04-21 4:39 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, cros-qcom-dts-watchers,
linux-arm-msm, linux-spi, devicetree, linux-kernel
In-Reply-To: <ln66k6kv2jakmoi7nzvoven66ugd4xiagpazgpnxaw2u2ytdtm@42eikb6kyvs7>
On 4/20/2026 5:59 PM, Dmitry Baryshkov wrote:
> On Mon, Apr 20, 2026 at 11:42:51AM +0530, Viken Dadhaniya wrote:
>> The Talos (QCS615) platform includes a QSPI controller used for accessing
>> external flash storage. Add the QSPI OPP table, TLMM pinmux entries, and
>> the QSPI controller node to enable support for this hardware.
>>
>> Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
>> ---
>> arch/arm64/boot/dts/qcom/talos.dtsi | 80 +++++++++++++++++++++++++++++++++++++
>> 1 file changed, 80 insertions(+)
>>
>
> You got r-b's for v2. Looks like they got ignored...
>
Reviewed-by tags from v2 were not carried forward due to code changes
suggested by Konrad in the v2 review, which were implemented in v3.
^ permalink raw reply
* Re: [net-next v2 2/5] dt-bindings: net: starfive,jh7110-dwmac: Add JHB100 support
From: Minda Chen @ 2026-04-21 3:30 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Alexandre Torgue, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
Emil Renner Berthing, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
devicetree@vger.kernel.org
In-Reply-To: <20260420-messy-elite-panther-a7ffbc@quoll>
>
> On Fri, Apr 17, 2026 at 10:45:20AM +0800, Minda Chen wrote:
> > Add StarFive JHB100 dwmac support and compatible.
> > The JHB100 dwmac shares the same driver code as the JH7110 dwmac,
>
> Please describe the hardware or programming interface, not driver code.
>
> > which contains 2 SGMII interfaces, 1 RGMII/RMII interface and
> > 1 RMII interface.
> > JHB100 dwmac has only one reset signal and one main interrupt line.
>
>
> Drop all below, not relevant.
>
> >
> > Please refer to below:
> >
> > JHB100: reset-names = "stmmaceth";
> >
> > Example usage of JHB100 in the device tree:
> >
> > gmac0: ethernet@11b80000 {
> > compatible = "starfive,jhb100-dwmac",
> > "snps,dwmac-5.20";
> > interrupts = <225>;
> > interrupt-names = "macirq";
> > ...
> > };
> >
> > Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
> > ---
> > .../devicetree/bindings/net/snps,dwmac.yaml | 1 +
> > .../bindings/net/starfive,jh7110-dwmac.yaml | 23 +++++++++++++++++++
> > 2 files changed, 24 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> > b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> > index 38bc34dc4f09..85cd3252e8b1 100644
> > --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> > +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> > @@ -115,6 +115,7 @@ properties:
> > - sophgo,sg2044-dwmac
> > - starfive,jh7100-dwmac
> > - starfive,jh7110-dwmac
> > + - starfive,jhb100-dwmac
> > - tesla,fsd-ethqos
> > - thead,th1520-gmac
> >
> > diff --git
> > a/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > index 0d1962980f57..edc246a71ce3 100644
> > --- a/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > +++ b/Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml
> > @@ -18,6 +18,7 @@ select:
> > enum:
> > - starfive,jh7100-dwmac
> > - starfive,jh7110-dwmac
> > + - starfive,jhb100-dwmac
> > required:
> > - compatible
> >
> > @@ -30,6 +31,9 @@ properties:
> > - items:
> > - const: starfive,jh7110-dwmac
> > - const: snps,dwmac-5.20
> > + - items:
> > + - const: starfive,jhb100-dwmac
>
> So that's an enum in previous "items" list.... but your commit msg said your
> devices are compatible, so confusing.
>
> Best regards,
> Krzysztof
Got it . I will correct the commit messages. Thanks
^ permalink raw reply
* Re: [PATCH v3 0/2] Add LT9611C(EX/UXD) DRM bridge driver and device tree
From: Jingyi Wang @ 2026-04-21 5:09 UTC (permalink / raw)
To: syyang, robh, krzk+dt, conor+dt, andrzej.hajda, neil.armstrong,
dmitry.baryshkov, maarten.lankhorst, rfoss, mripard
Cc: Laurent.pinchart, tzimmermann, jonas, jernej.skrabec, devicetree,
dri-devel, linux-kernel, yangsunyun1993, xmzhu
In-Reply-To: <20260420061644.1251070-1-syyang@lontium.com>
On 4/20/2026 2:16 PM, syyang@lontium.com wrote:
> From: Sunyun Yang <syyang@lontium.com>
>
> This series adds support for the Lontium LT9611C(EX/UXD) MIPI DSI to HDMI
> chip:
>
> -dt-bindings: bridge: This patch adds new content to the lontium,lt9611.yaml
> binding file.
> -drm/bridge: This patch add new DRM bridge driver for LT9611C(EX/UXD) chip.
>
> Signed-off-by: Sunyun Yang<syyang@lontium.com>
"This patch" should be avoided in the commit msg, begin with "add" will be enough.
Thanks,
Jingyi
> ---
> Changes in v3:
> -dt-binding:
> 1. lt9611c(ex/uxd) content merged into lontium,lt9611.yaml
> -drm/bridge:
> 1. Drop the licence text, only use SPDX header
> 2. Sort the headers
> 3. Use library functions for crc8
> 4. Drop i2c_read_byte and i2c_write_byte
> 5. Lowercase all hex values
> 6. Use paged writes as implemented for LT9611C(EX/UXD)
> 7. Drop dev_info, use dev_dbg
> 8. Modify lt9611c_get_edid_block, don't store EDID in the long-term structures
> 9. Use HDMI audio helpers.
> 10.Remove unnecessary flags,Implement proper cleanup path, unwinding resources
> one by one.
> 11.Replace devm_kzalloc with devm_drm_bridge_alloc.
> 12.Remove extra kthread.
> -Link to v1: https://lore.kernel.org/lkml/20250903123825.1721443-1-syyang@lontium.com/
>
> Changes in v2:
> 1. Forget modify code, operation error, Please disregard this submit.
>
> Changes in v1:
> -dt-binding:
> 1. Submit the first version of the code.
> -drm/bridge:
> 1. Submit the first version of the code.
>
> ---
> Sunyun Yang (2):
> dt-bindings: bridge: This patch adds new content to the
> lontium,lt9611.yaml binding file
> drm/bridge: This patch add new DRM bridge driver for LT9611C chip
>
> .../display/bridge/lontium,lt9611.yaml | 8 +-
> drivers/gpu/drm/bridge/Kconfig | 18 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/lontium-lt9611c.c | 1365 +++++++++++++++++
> 4 files changed, 1390 insertions(+), 2 deletions(-)
> create mode 100755 drivers/gpu/drm/bridge/lontium-lt9611c.c
>
^ permalink raw reply
* Re: [PATCH v3 0/2] Add LT9611C(EX/UXD) DRM bridge driver and device tree
From: 杨孙运 @ 2026-04-21 5:49 UTC (permalink / raw)
To: Jingyi Wang
Cc: syyang, robh, krzk+dt, conor+dt, andrzej.hajda, neil.armstrong,
dmitry.baryshkov, maarten.lankhorst, rfoss, mripard,
Laurent.pinchart, jonas, jernej.skrabec, devicetree, dri-devel,
linux-kernel, xmzhu, tzimmermann, xmzhu, rlyu, xbpeng
In-Reply-To: <b2a5ef92-f312-4e0a-9772-4d430b80a46e@oss.qualcomm.com>
Jingyi Wang <jingyi.wang@oss.qualcomm.com> 于2026年4月21日周二 13:09写道:
>
>
>
> On 4/20/2026 2:16 PM, syyang@lontium.com wrote:
> > From: Sunyun Yang <syyang@lontium.com>
> >
> > This series adds support for the Lontium LT9611C(EX/UXD) MIPI DSI to HDMI
> > chip:
> >
> > -dt-bindings: bridge: This patch adds new content to the lontium,lt9611.yaml
> > binding file.
> > -drm/bridge: This patch add new DRM bridge driver for LT9611C(EX/UXD) chip.
> >
> > Signed-off-by: Sunyun Yang<syyang@lontium.com>
>
> "This patch" should be avoided in the commit msg, begin with "add" will be enough.
>
it will be fixed in the next version.
> Thanks,
> Jingyi
>
> > ---
> > Changes in v3:
> > -dt-binding:
> > 1. lt9611c(ex/uxd) content merged into lontium,lt9611.yaml
> > -drm/bridge:
> > 1. Drop the licence text, only use SPDX header
> > 2. Sort the headers
> > 3. Use library functions for crc8
> > 4. Drop i2c_read_byte and i2c_write_byte
> > 5. Lowercase all hex values
> > 6. Use paged writes as implemented for LT9611C(EX/UXD)
> > 7. Drop dev_info, use dev_dbg
> > 8. Modify lt9611c_get_edid_block, don't store EDID in the long-term structures
> > 9. Use HDMI audio helpers.
> > 10.Remove unnecessary flags,Implement proper cleanup path, unwinding resources
> > one by one.
> > 11.Replace devm_kzalloc with devm_drm_bridge_alloc.
> > 12.Remove extra kthread.
> > -Link to v1: https://lore.kernel.org/lkml/20250903123825.1721443-1-syyang@lontium.com/
> >
> > Changes in v2:
> > 1. Forget modify code, operation error, Please disregard this submit.
> >
> > Changes in v1:
> > -dt-binding:
> > 1. Submit the first version of the code.
> > -drm/bridge:
> > 1. Submit the first version of the code.
> >
> > ---
> > Sunyun Yang (2):
> > dt-bindings: bridge: This patch adds new content to the
> > lontium,lt9611.yaml binding file
> > drm/bridge: This patch add new DRM bridge driver for LT9611C chip
> >
> > .../display/bridge/lontium,lt9611.yaml | 8 +-
> > drivers/gpu/drm/bridge/Kconfig | 18 +
> > drivers/gpu/drm/bridge/Makefile | 1 +
> > drivers/gpu/drm/bridge/lontium-lt9611c.c | 1365 +++++++++++++++++
> > 4 files changed, 1390 insertions(+), 2 deletions(-)
> > create mode 100755 drivers/gpu/drm/bridge/lontium-lt9611c.c
> >
>
^ permalink raw reply
* Re: [PATCH v8 5/5] arm64: dts: qcom: monaco: Add OPP-table for ICE UFS and ICE eMMC nodes
From: Abhinaba Rakshit @ 2026-04-21 5:50 UTC (permalink / raw)
To: Kuldeep Singh
Cc: Bjorn Andersson, Konrad Dybcio, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, Adrian Hunter,
Ulf Hansson, Neeraj Soni, Harshal Dev, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, linux-kernel,
linux-scsi, linux-mmc, devicetree
In-Reply-To: <71c6c453-4a6b-414e-a039-80f36e948489@oss.qualcomm.com>
On Fri, Apr 10, 2026 at 04:27:35PM +0530, Kuldeep Singh wrote:
>
>
> On 4/9/2026 5:14 PM, Abhinaba Rakshit wrote:
> > Qualcomm Inline Crypto Engine (ICE) platform driver now, supports
> > an optional OPP-table.
> >
> > Add OPP-table for ICE UFS and ICE eMMC device nodes for Monaco
> > platform.
> >
> > Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
> > ---
> > arch/arm64/boot/dts/qcom/monaco.dtsi | 32 ++++++++++++++++++++++++++++++++
> > 1 file changed, 32 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
> > index 487bb682ae8620b819f022162edd11023ed07be8..cb0e554e94d237b0adccb55fa9ed967bae9eea05 100644
> > --- a/arch/arm64/boot/dts/qcom/monaco.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
> > @@ -2730,6 +2730,22 @@ ice: crypto@1d88000 {
> > clock-names = "core",
> > "iface";
> > power-domains = <&gcc GCC_UFS_PHY_GDSC>;
> > +
> > + operating-points-v2 = <&ice_opp_table>;
> > +
> > + ice_opp_table: opp-table {
> > + compatible = "operating-points-v2";
> > +
>
> 75MHz is supported too. Please add that entry.
Sure, will add the entry in the next patchset.
Abhinaba Rakshit
^ permalink raw reply
* Re: [PATCH v2 0/2] pinctrl: qcom: eliza: Split up some QUP pin groups
From: Abel Vesa @ 2026-04-21 5:55 UTC (permalink / raw)
To: Alexander Koskovich
Cc: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-arm-msm, linux-gpio, linux-kernel, devicetree
In-Reply-To: <20260420-fix-eliza-pinctrl-v2-0-b68329fd6701@pm.me>
On 26-04-20 14:27:46, Alexander Koskovich wrote:
> Multiple QUPs have lanes that can be routed to one of two GPIOs and
> collapsing them prevents devicetrees from requesting specific routing.
>
> For example, a board that wires an I2C SCL line to one of two GPIOs
> cannot request that specific pin with the groups collapsed.
>
> This series splits them up so devicetrees can request the configuration
> they need.
>
> Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
Nack. That's the downstream way. In upstream we group them.
If you want to play with the WIP bring-up, here is the tree we use:
https://github.com/qualcomm-linux/kernel-topics/tree/early/hwe/eliza
Qup nodes are already in there.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox