{"id":2175542,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2175542/?format=json","project":{"id":18,"url":"http://patchwork.ozlabs.org/api/1.0/projects/18/?format=json","name":"U-Boot","link_name":"uboot","list_id":"u-boot.lists.denx.de","list_email":"u-boot@lists.denx.de","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<20251218083326.644326-8-brian.ruley@gehealthcare.com>","date":"2025-12-18T08:33:26","name":"[v1,7/7] video: imx: ipuv3: refactor to use dm-managed state","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"0545f1ce0c6f29708a9f2559d4bf136cd38b331a","submitter":{"id":89422,"url":"http://patchwork.ozlabs.org/api/1.0/people/89422/?format=json","name":"Brian Ruley","email":"brian.ruley@gehealthcare.com"},"delegate":{"id":151988,"url":"http://patchwork.ozlabs.org/api/1.0/users/151988/?format=json","username":"festevam","first_name":"Fabio","last_name":"Estevam","email":"festevam@gmail.com"},"mbox":"http://patchwork.ozlabs.org/project/uboot/patch/20251218083326.644326-8-brian.ruley@gehealthcare.com/mbox/","series":[{"id":485836,"url":"http://patchwork.ozlabs.org/api/1.0/series/485836/?format=json","date":"2025-12-18T08:33:20","name":"Refactor i.MX IPU driver","version":1,"mbox":"http://patchwork.ozlabs.org/series/485836/mbox/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2175542/checks/","tags":{},"headers":{"Return-Path":"<u-boot-bounces@lists.denx.de>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gehealthcare.com header.i=@gehealthcare.com\n header.a=rsa-sha256 header.s=selector1 header.b=mdp0Oxvj;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)","phobos.denx.de;\n dmarc=pass (p=quarantine dis=none) header.from=gehealthcare.com","phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de","phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gehealthcare.com header.i=@gehealthcare.com\n header.b=\"mdp0Oxvj\";\n\tdkim-atps=neutral","phobos.denx.de; dmarc=pass (p=quarantine dis=none)\n header.from=gehealthcare.com","phobos.denx.de;\n spf=pass smtp.mailfrom=Brian.Ruley@gehealthcare.com"],"Received":["from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4dX8jl4Bqxz1y2f\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 18 Dec 2025 23:14:35 +1100 (AEDT)","from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id BF04B83E16;\n\tThu, 18 Dec 2025 13:13:47 +0100 (CET)","by phobos.denx.de (Postfix, from userid 109)\n id 4945983D6C; Thu, 18 Dec 2025 09:33:44 +0100 (CET)","from BL0PR03CU003.outbound.protection.outlook.com\n (mail-eastusazlp170120007.outbound.protection.outlook.com\n [IPv6:2a01:111:f403:c101::7])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 06C5483D3D\n for <u-boot@lists.denx.de>; Thu, 18 Dec 2025 09:33:41 +0100 (CET)","from SA9PR13CA0133.namprd13.prod.outlook.com (2603:10b6:806:27::18)\n by CH3PR22MB5545.namprd22.prod.outlook.com (2603:10b6:610:1e2::13)\n with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9434.6; Thu, 18 Dec\n 2025 08:33:35 +0000","from SA2PEPF00003AE4.namprd02.prod.outlook.com\n (2603:10b6:806:27:cafe::4a) by SA9PR13CA0133.outlook.office365.com\n (2603:10b6:806:27::18) with Microsoft SMTP Server (version=TLS1_3,\n cipher=TLS_AES_256_GCM_SHA384) id 15.20.9434.6 via Frontend Transport; Thu,\n 18 Dec 2025 08:33:11 +0000","from atlrelay2.compute.ge-healthcare.net (165.85.157.49) by\n SA2PEPF00003AE4.mail.protection.outlook.com (10.167.248.4) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.9434.6 via Frontend Transport; Thu, 18 Dec 2025 08:33:35 +0000","from zoo11.fihel.lab.ge-healthcare.net\n (zoo11.fihel.lab.ge-healthcare.net [10.168.174.93])\n by builder1.fihel.lab.ge-healthcare.net (Postfix) with ESMTP id F0020D9C01;\n Thu, 18 Dec 2025 10:33:32 +0200 (EET)"],"X-Spam-Checker-Version":"SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de","X-Spam-Level":"","X-Spam-Status":"No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED,\n SPF_HELO_NONE,T_SPF_PERMERROR autolearn=ham autolearn_force=no\n version=3.4.2","ARC-Seal":"i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=cemwL4x0C64mnMDu18hjZlhxAQLytR7B5vWDvua3T8BgAhAYHqakxxPxbG4i/iecnG0GFSwz03pHM3QeLNyrNEm596+heh80SyVr8YVuyQqHvLtIaWESbRIq4wWrXHS8sECf/eX6TYaN7OPXmlR9sUDPzv8Tbhut8T4nYsxlcyMrTJxt/d0gWhCANq6h/PShpbWDTFHA0+HbujbGAuh2uCCxnEIZvhmJCctJWI277ZyV0nNt1WexDstzIud/AlEbA5bxM3XuvzH7CtANGIuYcWpbIrI0NF16Ex04T+sV3XJSuQ+ZCeV45e1y/IHhVAm/JWwiHnOXKbHQOhPsWBWC9Q==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector10001;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=LJ3LmQqT+h9pATejcGSTHDDNqsYNnJCChY9Cv04WgE4=;\n b=OJcoElmKCZvVHsB+pGemd10T2I2UBfQ89Q9GJeH1HwCgdke3DtKsYVfyeIcUVXX7IGJOLZ/aXht3424I9xDTm305vWNNtuIh7A1E3riJ9hp/GwpGHjiK+RvwTEdAaksgPyTzWkFnBWkJekVAFHJqFjXW0E3EgOkki/6wfvHvjve7EkICUIkIUUrV1Oj7a3W8xiVaxODkFHLanmH2OuGlOXgf44ysqJitm1mv4/hC6+LoqxhAXNZOr3gD9naRiNi8bBRqmV54OzLB4Mzi5Og8b59vee3WLs5kzDQr57tz8+oVRLCnbI2nE/rs1ZvT7K8GwEeMl/xCMdlYqQj/CXkdZg==","ARC-Authentication-Results":"i=1; mx.microsoft.com 1; spf=fail (sender ip is\n 165.85.157.49) smtp.rcpttodomain=lists.denx.de\n smtp.mailfrom=gehealthcare.com; dmarc=fail (p=quarantine sp=quarantine\n pct=100) action=quarantine header.from=gehealthcare.com; dkim=none (message\n not signed); arc=none (0)","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gehealthcare.com;\n s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=LJ3LmQqT+h9pATejcGSTHDDNqsYNnJCChY9Cv04WgE4=;\n b=mdp0Oxvjbu5t1ncJZWmq9IIdOILuu0RfOkL4Ynzh7kQ22O0KIOU+XXMO6dQtdIQQB0OqQ7VMrOPRF/9QaPVTCmQT3iE+ev/mmPusyZbIhvYLUBbOKqImLPRL2ov6JP2M2FU4wbHkeYh/zezUU6C1RwMx9zzmNbVwJHJeknPT9HNRPxkYZSUH5UvMvk2da/LMiouZOyGAeG7goDnleHLVwVkqSSLUPB2xpJHO12jeLJYTLVboxNjnTFow+yADPpcnLT/ywYeDLWT2hdmRlUBtDb3b5h7RUMPm9O1f91CjmYyMjuXvttJFrTG2YmsbiiGLm177f51gSEoB/0yk1f6qGg==","X-MS-Exchange-Authentication-Results":"spf=fail (sender IP is 165.85.157.49)\n smtp.mailfrom=gehealthcare.com; dkim=none (message not signed)\n header.d=none;dmarc=fail action=quarantine header.from=gehealthcare.com;","Received-SPF":"Fail (protection.outlook.com: domain of gehealthcare.com does\n not designate 165.85.157.49 as permitted sender)\n receiver=protection.outlook.com; client-ip=165.85.157.49;\n helo=atlrelay2.compute.ge-healthcare.net;","From":"Brian Ruley <brian.ruley@gehealthcare.com>","To":"u-boot@lists.denx.de, Stefano Babic <sbabic@nabladev.com>,\n Fabio Estevam <festevam@gmail.com>,\n \"NXP i.MX U-Boot Team\" <uboot-imx@nxp.com>, Tom Rini <trini@konsulko.com>,\n Anatolij Gustschin <ag.dev.uboot@gmail.com>","Cc":"Brian Ruley <brian.ruley@gehealthcare.com>,\n David Zang <davidzangcs@gmail.com>,\n Marek Vasut <marek.vasut+renesas@mailbox.org>,\n Quentin Schulz <quentin.schulz@cherry.de>","Subject":"[PATCH v1 7/7] video: imx: ipuv3: refactor to use dm-managed state","Date":"Thu, 18 Dec 2025 10:33:26 +0200","Message-Id":"<20251218083326.644326-8-brian.ruley@gehealthcare.com>","X-Mailer":"git-send-email 2.39.5","In-Reply-To":"<20251218083326.644326-1-brian.ruley@gehealthcare.com>","References":"<20251218083326.644326-1-brian.ruley@gehealthcare.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-EOPAttributedMessage":"0","X-MS-PublicTrafficType":"Email","X-MS-TrafficTypeDiagnostic":"SA2PEPF00003AE4:EE_|CH3PR22MB5545:EE_","Content-Type":"text/plain","X-MS-Office365-Filtering-Correlation-Id":"55aa55ed-1241-4640-8384-08de3e10228d","X-MS-Exchange-SenderADCheck":"1","X-MS-Exchange-AntiSpam-Relay":"0","X-Microsoft-Antispam":"BCL:0;\n ARA:13230040|1800799024|82310400026|36860700013|376014;","X-Microsoft-Antispam-Message-Info":"\n 6VIA12YkaPLHaKX4uaETS64VrpjrK/lWylliLMIRd4LOgYOnsEN7yNNXUuks2hYUzt/XtzZzLGi1RqFkJF50fQ86bY+4c099FruHMrLO8cRSBl0COnQ0HW2aCOWkeIurV8zttmL7G5MvxSoqy/vhVBO5LlVVrqXcvhpo1Oam+f0XmFV6dz5YS7y8lf2Dwi3PW3K4pOBi8xE/ssdgMtWt6c0NqMBeasAzOZP0YyBZb8NNX/qSomFrqLd+KS34n4SxhFiKukw2x9Hcx5wXtE4jo2nhlgZva9R73+kVIU/DyZmJ9+6hagToKXGzhoWLMCyr24BRT6sESpCpFd5b6PKxbggz1sXjF86Ttt4OnzqVgsQbxxScI96Q5dwsHERYHSSp5+oWw/NB4tgK69BujiyVdLbSzZNYcEzB40RsuVaJa38aW/z+V79UCA0BnSRsF/i32DnQDgC12Exr+M//JoIEs/FVZdIpamirWXdVZ67Ccz3p0uJOwJoYfeOvGKA/qQ9wHVIDMow16kUDZE/yZIUCCPbFarnqX/Rtz1SohSrfbMiMXd4W1Qrv2vfLfc5Tc2ICAa37riWRJksmveLT0S8qObMdTX24ivpeZjirRq8Ixn4vQAsW/BPf44ayiumBzL4aFOUh7wVNtQKLYNEzPZeOz4KAuXha8zcIczsaUc+BeISYRsUID3q5AbLs3g0Pv+JCcUV+2S5C5Ui3MgIHVyJ4otXAh/D1By86IrXxqvxbtUvOHHzhrUuz31y/+mMwHMbGSIHVfCdOcA7ctKZ7SH3eZW7VBHdY3joQCL0/3r0tmWKa//f4GdtwH5KYNTSAajOu5U46zdhYxSlUF7o1voNQM3x7uX4aumbTFKeedecaTWESspuZXBEYa4cLPnR68nz34hiS5A8OnYPnV93kkBW6tVdGPFcsezYoPPR7ps/lFMFGBiONjWfTKCH+QkxcjFL3wLqhdhByPQKwqGFtj9PhgNHDOhUfZa1iUPS5nDe508LCjVk4e+ja/TBoZ8b0UmXgSo86L26B9uS9T863/sjzOlmzIIiil13wZBVyMSJd4z9mBT+iuVPRhSk85llJsGir8TnvJQWUEwQRfp1vRfj4MUfrFNo1nmDMH0rixQfovfCV9ZX6Aow/Aaov+qdD8LyrPdXMvbE78tyo+hZEHp3hjnfh30YR/9HMyh9o79yCmgz+uDBwFT6lxI26y4A8gMW+L4Mhv7CHg3Srd9pTDCDzkK9xxM4chIA1NDcd5FOxaDN2jHbDrhgx/oAbkReh/XZR5Pi0U9yG1KbaqNwxAgV3L7ydJmHc5sVDH17mFa/Ua7qK2vJnBW64RdkSfIThsTOPlWaUKbuBfzU9dm74MCjZC/Ped6/UKFWoQHG00tdhhCbcqxIknUNMv1P8QWaStcJnCaIVb8g/Xpup9KwA3WfEpCOI0X99mzCjiS2UXgMwJXbiM0acRGl8kVXn4aoqrL8TpRLspjEkubaEJGzpFPdtgOwTs62FtE07kc0gou3I0lpkr7oJ47RhGORFadD/6WnV2Q03tG+dM+7nDqs9hbmDi+yUURvv6HC0AwDh3qzqIXQ=","X-Forefront-Antispam-Report":"CIP:165.85.157.49; CTRY:US; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:atlrelay2.compute.ge-healthcare.net;\n PTR:InfoDomainNonexistent; CAT:NONE;\n SFS:(13230040)(1800799024)(82310400026)(36860700013)(376014); DIR:OUT;\n SFP:1101;","X-OriginatorOrg":"gehealthcare.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"18 Dec 2025 08:33:35.1319 (UTC)","X-MS-Exchange-CrossTenant-Network-Message-Id":"\n 55aa55ed-1241-4640-8384-08de3e10228d","X-MS-Exchange-CrossTenant-Id":"9a309606-d6ec-4188-a28a-298812b4bbbf","X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp":"\n TenantId=9a309606-d6ec-4188-a28a-298812b4bbbf; Ip=[165.85.157.49];\n Helo=[atlrelay2.compute.ge-healthcare.net]","X-MS-Exchange-CrossTenant-AuthAs":"Internal","X-MS-Exchange-CrossTenant-AuthSource":"\n TreatMessagesAsInternal-SA2PEPF00003AE4.namprd02.prod.outlook.com","X-MS-Exchange-CrossTenant-FromEntityHeader":"HybridOnPrem","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"CH3PR22MB5545","X-Mailman-Approved-At":"Thu, 18 Dec 2025 13:13:44 +0100","X-BeenThere":"u-boot@lists.denx.de","X-Mailman-Version":"2.1.39","Precedence":"list","List-Id":"U-Boot discussion <u-boot.lists.denx.de>","List-Unsubscribe":"<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>","List-Archive":"<https://lists.denx.de/pipermail/u-boot/>","List-Post":"<mailto:u-boot@lists.denx.de>","List-Help":"<mailto:u-boot-request@lists.denx.de?subject=help>","List-Subscribe":"<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>","Errors-To":"u-boot-bounces@lists.denx.de","Sender":"\"U-Boot\" <u-boot-bounces@lists.denx.de>","X-Virus-Scanned":"clamav-milter 0.103.8 at phobos.denx.de","X-Virus-Status":"Clean"},"content":"Get rid of most globals that are spread around between TU's and place\nthem in their own structs managed by dm. Device state is now owned by\neach driver instance. This design mirrors the Linux IPUv3 driver\narchitecture.\n\nThis work is done in preparation to migrate the driver to the clock\nframework. While not the primary intent, this change also enables\nmultiple IPU instances to exist contemporarily.\n\nSigned-off-by: Brian Ruley <brian.ruley@gehealthcare.com>\n---\n\n arch/arm/mach-imx/cpu.c          |   8 +-\n drivers/video/imx/ipu.h          |  97 +++++++--\n drivers/video/imx/ipu_common.c   | 361 +++++++++++++++++++------------\n drivers/video/imx/ipu_disp.c     | 145 +++++--------\n drivers/video/imx/mxc_ipuv3_fb.c | 103 +++++----\n include/ipu_pixfmt.h             |   3 +-\n 6 files changed, 434 insertions(+), 283 deletions(-)","diff":"diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c\nindex cc215b771ef..2aa9d9c9666 100644\n--- a/arch/arm/mach-imx/cpu.c\n+++ b/arch/arm/mach-imx/cpu.c\n@@ -285,10 +285,10 @@ u32 get_ahb_clk(void)\n \n void arch_preboot_os(void)\n {\n-#if defined(CONFIG_IMX_AHCI)\n \tstruct udevice *dev;\n \tint rc;\n \n+#if defined(CONFIG_IMX_AHCI)\n \trc = uclass_find_device(UCLASS_AHCI, 0, &dev);\n \tif (!rc && dev) {\n \t\trc = device_remove(dev, DM_REMOVE_NORMAL);\n@@ -308,7 +308,11 @@ void arch_preboot_os(void)\n #endif\n #if defined(CONFIG_VIDEO_IPUV3)\n \t/* disable video before launching O/S */\n-\tipuv3_fb_shutdown();\n+\trc = uclass_find_first_device(UCLASS_VIDEO, &dev);\n+\twhile (!rc && dev) {\n+\t\tipuv3_fb_shutdown(dev);\n+\t\tuclass_find_next_device(&dev);\n+\t}\n #endif\n #if defined(CONFIG_VIDEO_MXS) && !defined(CONFIG_VIDEO)\n \tlcdif_power_down();\ndiff --git a/drivers/video/imx/ipu.h b/drivers/video/imx/ipu.h\nindex f7d9d809529..62827dc480d 100644\n--- a/drivers/video/imx/ipu.h\n+++ b/drivers/video/imx/ipu.h\n@@ -1,5 +1,10 @@\n /* SPDX-License-Identifier: GPL-2.0+ */\n /*\n+ * Code fixes:\n+ *\n+ * (C) Copyright 2025\n+ * Brian Ruley, GE HealthCare, brian.ruley@gehealthcare.com\n+ *\n  * Porting to u-boot:\n  *\n  * (C) Copyright 2010\n@@ -19,9 +24,14 @@\n #define IDMA_CHAN_INVALID 0xFF\n #define HIGH_RESOLUTION_WIDTH 1024\n \n+struct ipu_ctx;\n+struct ipu_di_config;\n+\n struct clk {\n \tconst char *name;\n \tint id;\n+\t/* The IPU context of this clock */\n+\tstruct ipu_ctx *ctx;\n \t/* Source clock this clk depends on */\n \tstruct clk *parent;\n \t/* Secondary clock to enable/disable with this clock */\n@@ -65,6 +75,69 @@ struct clk {\n \tint (*set_parent)(struct clk *clk, struct clk *parent);\n };\n \n+struct udevice;\n+\n+/*\n+ * Per-IPU context used by ipu_common to manage clocks and channel state.\n+ * Lifetime is owned by the IPU DM driver\n+ */\n+struct ipu_ctx {\n+\tstruct udevice *dev;\n+\tint dev_id;\n+\n+\tstruct clk *ipu_clk;\n+\tstruct clk *ldb_clk;\n+\tunsigned char ipu_clk_enabled;\n+\tstruct clk *di_clk[2];\n+\tstruct clk *pixel_clk[2];\n+\n+\tu8 dc_di_assignment[10];\n+\tu32 channel_init_mask;\n+\tu32 channel_enable_mask;\n+\n+\tint ipu_dc_use_count;\n+\tint ipu_dp_use_count;\n+\tint ipu_dmfc_use_count;\n+\tint ipu_di_use_count[2];\n+};\n+\n+/**\n+ * @disp:\t    The DI the panel is attached to.\n+ * @pixel_clk_rate: Desired pixel clock frequency in Hz.\n+ * @pixel_fmt:\t    Input parameter for pixel format of buffer.\n+ *\t\t    Pixel format is a FOURCC ASCII code.\n+ * @width:\t    The width of panel in pixels.\n+ * @height:\t    The height of panel in pixels.\n+ * @h_start_width:  The number of pixel clocks between the HSYNC\n+ *\t\t    signal pulse and the start of valid data.\n+ * @h_sync_width:   The width of the HSYNC signal in units of pixel\n+ *\t\t    clocks.\n+ * @h_end_width:    The number of pixel clocks between the end of\n+ *\t\t    valid data and the HSYNC signal for next line.\n+ * @v_start_width:  The number of lines between the VSYNC\n+ *\t\t    signal pulse and the start of valid data.\n+ * @v_sync_width:   The width of the VSYNC signal in units of lines\n+ * @v_end_width:    The number of lines between the end of valid\n+ *\t\t    data and the VSYNC signal for next frame.\n+ * @ctx:\t    The IPU context of the display.\n+ */\n+struct ipu_di_config {\n+\tint disp;\n+\tu32 pixel_clk_rate;\n+\tu32 pixel_fmt;\n+\tu16 width;\n+\tu16 height;\n+\tu16 h_start_width;\n+\tu16 h_sync_width;\n+\tu16 h_end_width;\n+\tu16 v_start_width;\n+\tu16 v_sync_width;\n+\tu16 v_end_width;\n+\tu32 v_to_h_sync;\n+\n+\tstruct ipu_ctx *ctx;\n+};\n+\n /*\n  * Enumeration of Synchronous (Memory-less) panel types\n  */\n@@ -201,8 +274,9 @@ typedef struct {\n typedef enum { RGB, YCBCR, YUV } ipu_color_space_t;\n \n /* Common IPU API */\n-int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params);\n-void ipu_uninit_channel(ipu_channel_t channel);\n+int32_t ipu_init_channel(struct ipu_ctx *ctx, ipu_channel_t channel,\n+\t\t\t ipu_channel_params_t *params);\n+void ipu_uninit_channel(struct ipu_ctx *ctx, ipu_channel_t channel);\n \n int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,\n \t\t\t\tu32 pixel_fmt, u16 width, u16 height,\n@@ -212,14 +286,10 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,\n \n void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,\n \t\t\t    u32 buf_num);\n-int32_t ipu_enable_channel(ipu_channel_t channel);\n-int32_t ipu_disable_channel(ipu_channel_t channel);\n+int32_t ipu_enable_channel(struct ipu_ctx *ctx, ipu_channel_t channel);\n+int32_t ipu_disable_channel(struct ipu_ctx *ctx, ipu_channel_t channel);\n \n-int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n-\t\t\t    u32 pixel_fmt, u16 h_start_width, u16 h_sync_width,\n-\t\t\t    u16 h_end_width, u16 v_start_width,\n-\t\t\t    u16 v_sync_width, u16 v_end_width, u32 v_to_h_sync,\n-\t\t\t    ipu_di_signal_cfg_t sig);\n+int32_t ipu_init_sync_panel(struct ipu_di_config *di, ipu_di_signal_cfg_t sig);\n \n int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable,\n \t\t\t\t  u8 alpha);\n@@ -238,17 +308,18 @@ int clk_get_usecount(struct clk *clk);\n struct clk *clk_get_parent(struct clk *clk);\n \n void ipu_dump_registers(void);\n-int ipu_probe(void);\n-bool ipu_clk_enabled(void);\n+struct ipu_ctx *ipu_probe(struct udevice *dev);\n+bool ipu_clk_enabled(struct ipu_ctx *ctx);\n \n void ipu_dmfc_init(int dmfc_type, int first);\n void ipu_init_dc_mappings(void);\n void ipu_dmfc_set_wait4eot(int dma_chan, int width);\n void ipu_dc_init(int dc_chan, int di, unsigned char interlaced);\n void ipu_dc_uninit(int dc_chan);\n-void ipu_dp_dc_enable(ipu_channel_t channel);\n+void ipu_dp_dc_enable(struct ipu_ctx *ctx, ipu_channel_t channel);\n int ipu_dp_init(ipu_channel_t channel, u32 in_pixel_fmt, u32 out_pixel_fmt);\n void ipu_dp_uninit(ipu_channel_t channel);\n-void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap);\n+void ipu_dp_dc_disable(struct ipu_ctx *ctx, ipu_channel_t channel,\n+\t\t       unsigned char swap);\n ipu_color_space_t format_to_colorspace(u32 fmt);\n #endif\ndiff --git a/drivers/video/imx/ipu_common.c b/drivers/video/imx/ipu_common.c\nindex 4ca81d48a5f..ac3e90a9f3d 100644\n--- a/drivers/video/imx/ipu_common.c\n+++ b/drivers/video/imx/ipu_common.c\n@@ -1,5 +1,10 @@\n // SPDX-License-Identifier: GPL-2.0+\n /*\n+ * Code fixes:\n+ *\n+ * (C) Copyright 2025\n+ * Brian Ruley, GE HealthCare, brian.ruley@gehealthcare.com\n+ *\n  * Porting to u-boot:\n  *\n  * (C) Copyright 2010\n@@ -10,7 +15,6 @@\n  * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.\n  */\n \n-/* #define DEBUG */\n #include \"ipu.h\"\n #include \"ipu_regs.h\"\n #include <asm/arch/crm_regs.h>\n@@ -19,6 +23,8 @@\n #include <asm/io.h>\n #include <config.h>\n #include <div64.h>\n+#include <dm.h>\n+#include <dm/devres.h>\n #include <linux/delay.h>\n #include <linux/err.h>\n #include <linux/errno.h>\n@@ -206,46 +212,76 @@ static void clk_ipu_disable(struct clk *clk)\n #endif\n }\n \n-static struct clk ipu_clk = {\n-\t.name = \"ipu_clk\",\n+/*\n+ * Function to initialize the ipu clock\n+ *\n+ * @param   ctx\t    The ipu context for which the function is called\n+ *\n+ * Return:  Returns 0 on success or negative error code on error\n+ */\n+static int ipu_clk_init(struct ipu_ctx *ctx)\n+{\n+\tstruct clk *ipu_clk;\n+\n+\tipu_clk = devm_kzalloc(ctx->dev, sizeof(*ipu_clk), GFP_KERNEL);\n+\tif (!ipu_clk)\n+\t\treturn -ENOMEM;\n+\n+\tipu_clk->name = \"ipu_clk\";\n+\tipu_clk->ctx = ctx;\n #if CONFIG_IS_ENABLED(MX51) || CONFIG_IS_ENABLED(MX53)\n-\t.enable_reg =\n-\t\t(u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR5)),\n-\t.enable_shift = MXC_CCM_CCGR5_IPU_OFFSET,\n+\tipu_clk->enable_reg =\n+\t\t(u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR5));\n+\tipu_clk->enable_shift = MXC_CCM_CCGR5_IPU_OFFSET;\n #else\n-\t.enable_reg =\n-\t\t(u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR3)),\n-\t.enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET,\n+\tipu_clk->enable_reg =\n+\t\t(u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR3));\n+\tipu_clk->enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET;\n #endif\n-\t.enable = clk_ipu_enable,\n-\t.disable = clk_ipu_disable,\n-\t.usecount = 0,\n+\n+\tipu_clk->enable = clk_ipu_enable;\n+\tipu_clk->disable = clk_ipu_disable;\n+\tipu_clk->usecount = 0;\n+\n+#if CONFIG_IS_ENABLED(MX51)\n+\tipu_clk->rate = IPUV3_CLK_MX51;\n+#elif CONFIG_IS_ENABLED(MX53)\n+\tipu_clk->rate = IPUV3_CLK_MX53;\n+#else\n+\tipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q;\n+#endif\n+\n+\tctx->ipu_clk = ipu_clk;\n+\treturn 0;\n };\n \n #if !defined CFG_SYS_LDB_CLOCK\n #define CFG_SYS_LDB_CLOCK 65000000\n #endif\n \n-static struct clk ldb_clk = {\n-\t.name = \"ldb_clk\",\n-\t.rate = CFG_SYS_LDB_CLOCK,\n-\t.usecount = 0,\n-};\n+/*\n+ * Function to initialize the ldb dummy clock\n+ *\n+ * @param   ctx\t    The ipu context for which the function is called\n+ *\n+ * Return:  Returns 0 on success or negative error code on error\n+ */\n+static int ipu_ldb_clk_init(struct ipu_ctx *ctx)\n+{\n+\tstruct clk *ldb_clk;\n+\n+\tldb_clk = devm_kzalloc(ctx->dev, sizeof(*ldb_clk), GFP_KERNEL);\n+\tif (!ldb_clk)\n+\t\treturn -ENOMEM;\n \n-/* Globals */\n-struct clk *g_ipu_clk;\n-struct clk *g_ldb_clk;\n-unsigned char g_ipu_clk_enabled;\n-struct clk *g_di_clk[2];\n-struct clk *g_pixel_clk[2];\n-unsigned char g_dc_di_assignment[10];\n-u32 g_channel_init_mask;\n-u32 g_channel_enable_mask;\n-\n-static int ipu_dc_use_count;\n-static int ipu_dp_use_count;\n-static int ipu_dmfc_use_count;\n-static int ipu_di_use_count[2];\n+\tldb_clk->name = \"ldb_clk\";\n+\tldb_clk->ctx = ctx;\n+\tldb_clk->rate = CFG_SYS_LDB_CLOCK;\n+\tldb_clk->usecount = 0;\n+\n+\tctx->ldb_clk = ldb_clk;\n+\treturn 0;\n+};\n \n u32 *ipu_cpmem_base;\n u32 *ipu_dc_tmpl_reg;\n@@ -388,10 +424,11 @@ static void ipu_pixel_clk_disable(struct clk *clk)\n static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)\n {\n \tu32 di_gen = __raw_readl(DI_GENERAL(clk->id));\n+\tstruct ipu_ctx *ctx = clk->ctx;\n \n-\tif (parent == g_ipu_clk)\n+\tif (parent == ctx->ipu_clk)\n \t\tdi_gen &= ~DI_GEN_DI_CLK_EXT;\n-\telse if (!IS_ERR(g_di_clk[clk->id]) && parent == g_ldb_clk)\n+\telse if (!IS_ERR(ctx->di_clk[clk->id]) && parent == ctx->ldb_clk)\n \t\tdi_gen |= DI_GEN_DI_CLK_EXT;\n \telse\n \t\treturn -EINVAL;\n@@ -401,29 +438,34 @@ static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)\n \treturn 0;\n }\n \n-static struct clk pixel_clk[] = {\n-\t{\n-\t\t.name = \"pixel_clk\",\n-\t\t.id = 0,\n-\t\t.recalc = ipu_pixel_clk_recalc,\n-\t\t.set_rate = ipu_pixel_clk_set_rate,\n-\t\t.round_rate = ipu_pixel_clk_round_rate,\n-\t\t.set_parent = ipu_pixel_clk_set_parent,\n-\t\t.enable = ipu_pixel_clk_enable,\n-\t\t.disable = ipu_pixel_clk_disable,\n-\t\t.usecount = 0,\n-\t},\n-\t{\n-\t\t.name = \"pixel_clk\",\n-\t\t.id = 1,\n-\t\t.recalc = ipu_pixel_clk_recalc,\n-\t\t.set_rate = ipu_pixel_clk_set_rate,\n-\t\t.round_rate = ipu_pixel_clk_round_rate,\n-\t\t.set_parent = ipu_pixel_clk_set_parent,\n-\t\t.enable = ipu_pixel_clk_enable,\n-\t\t.disable = ipu_pixel_clk_disable,\n-\t\t.usecount = 0,\n-\t},\n+/*\n+ * Function to initialize the pixel clock\n+ *\n+ * @param   ctx\t    The ipu context for which the function is called\n+ *\n+ * Return:  Returns 0 on success or negative error code on error\n+ */\n+static int ipu_pixel_clk_init(struct ipu_ctx *ctx, int id)\n+{\n+\tstruct clk *pixel_clk;\n+\n+\tpixel_clk = devm_kzalloc(ctx->dev, sizeof(*pixel_clk), GFP_KERNEL);\n+\tif (!pixel_clk)\n+\t\treturn -ENOMEM;\n+\n+\tpixel_clk->name = \"pixel_clk\";\n+\tpixel_clk->id = id;\n+\tpixel_clk->ctx = ctx;\n+\tpixel_clk->recalc = ipu_pixel_clk_recalc;\n+\tpixel_clk->set_rate = ipu_pixel_clk_set_rate;\n+\tpixel_clk->round_rate = ipu_pixel_clk_round_rate;\n+\tpixel_clk->set_parent = ipu_pixel_clk_set_parent;\n+\tpixel_clk->enable = ipu_pixel_clk_enable;\n+\tpixel_clk->disable = ipu_pixel_clk_disable;\n+\tpixel_clk->usecount = 0;\n+\n+\tctx->pixel_clk[id] = pixel_clk;\n+\treturn 0;\n };\n \n /*\n@@ -456,11 +498,24 @@ static void ipu_reset(void)\n  * @param\tdev\tThe device structure for the IPU passed in by the\n  *\t\t\tdriver framework.\n  *\n- * Return:\tReturns 0 on success or negative error code on error\n+ * Return:\tReturns pointer to IPU context on success or pointer error code\n+ *\t\ton error\n  */\n-int ipu_probe(void)\n+struct ipu_ctx *ipu_probe(struct udevice *dev)\n {\n \tunsigned long ipu_base;\n+\tstruct ipu_ctx *ctx;\n+\tint ret = 0;\n+\n+\tctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);\n+\tif (!ctx) {\n+\t\tret = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\n+\tctx->dev = dev;\n+\tctx->dev_id = dev_seq(dev);\n+\n #if defined CONFIG_MX51\n \tu32 temp;\n \n@@ -481,29 +536,33 @@ int ipu_probe(void)\n \tipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE);\n \tipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE);\n \n-\tg_pixel_clk[0] = &pixel_clk[0];\n-\tg_pixel_clk[1] = &pixel_clk[1];\n+\tret = ipu_pixel_clk_init(ctx, 0);\n+\tif (ret)\n+\t\tgoto err;\n \n-\tg_ipu_clk = &ipu_clk;\n-#if CONFIG_IS_ENABLED(MX51)\n-\tg_ipu_clk->rate = IPUV3_CLK_MX51;\n-#elif CONFIG_IS_ENABLED(MX53)\n-\tg_ipu_clk->rate = IPUV3_CLK_MX53;\n-#else\n-\tg_ipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q;\n-#endif\n+\tret = ipu_pixel_clk_init(ctx, 1);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tret = ipu_clk_init(ctx);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tdebug(\"ipu_clk = %u\\n\", clk_get_rate(ctx->ipu_clk));\n+\n+\tret = ipu_ldb_clk_init(ctx);\n+\tif (ret)\n+\t\tgoto err;\n \n-\tdebug(\"ipu_clk = %u\\n\", clk_get_rate(g_ipu_clk));\n-\tg_ldb_clk = &ldb_clk;\n-\tdebug(\"ldb_clk = %u\\n\", clk_get_rate(g_ldb_clk));\n+\tdebug(\"ldb_clk = %u\\n\", clk_get_rate(ctx->ldb_clk));\n \tipu_reset();\n \n-\tclk_set_parent(g_pixel_clk[0], g_ipu_clk);\n-\tclk_set_parent(g_pixel_clk[1], g_ipu_clk);\n-\tclk_enable(g_ipu_clk);\n+\tclk_set_parent(ctx->pixel_clk[0], ctx->ipu_clk);\n+\tclk_set_parent(ctx->pixel_clk[1], ctx->ipu_clk);\n+\tclk_enable(ctx->ipu_clk);\n \n-\tg_di_clk[0] = NULL;\n-\tg_di_clk[1] = NULL;\n+\tctx->di_clk[0] = NULL;\n+\tctx->di_clk[1] = NULL;\n \n \t__raw_writel(0x807FFFFF, IPU_MEM_RST);\n \twhile (__raw_readl(IPU_MEM_RST) & 0x80000000)\n@@ -525,9 +584,11 @@ int ipu_probe(void)\n \t/* Set MCU_T to divide MCU access window into 2 */\n \t__raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);\n \n-\tclk_disable(g_ipu_clk);\n+\tclk_disable(ctx->ipu_clk);\n \n-\treturn 0;\n+\treturn ctx;\n+err:\n+\treturn ERR_PTR(ret);\n }\n \n void ipu_dump_registers(void)\n@@ -556,26 +617,32 @@ void ipu_dump_registers(void)\n /*\n  * This function is called to initialize a logical IPU channel.\n  *\n- * @param\tchannel Input parameter for the logical channel ID to init.\n+ * @param   ctx\t\tThe ipu context for which the function is called\n+ *\n+ * @param   channel\tInput parameter for the logical channel ID to init.\n  *\n- * @param\tparams\tInput parameter containing union of channel\n+ * @param   params\tInput parameter containing union of channel\n  *\t\t\tinitialization parameters.\n  *\n- * Return:\tReturns 0 on success or negative error code on fail\n+ * Return:  Returns 0 on success or negative error code on fail\n  */\n-int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)\n+int32_t ipu_init_channel(struct ipu_ctx *ctx, ipu_channel_t channel,\n+\t\t\t ipu_channel_params_t *params)\n {\n+\tstruct clk *ipu_clk = ctx->ipu_clk;\n+\tu8 *dc_di_assignment = ctx->dc_di_assignment;\n+\tu32 *channel_init_mask = &ctx->channel_init_mask;\n \tint ret = 0;\n \tu32 ipu_conf;\n \n \tdebug(\"init channel = %d\\n\", IPU_CHAN_ID(channel));\n \n-\tif (g_ipu_clk_enabled == 0) {\n-\t\tg_ipu_clk_enabled = 1;\n-\t\tclk_enable(g_ipu_clk);\n+\tif (ctx->ipu_clk_enabled == 0) {\n+\t\tctx->ipu_clk_enabled = 1;\n+\t\tclk_enable(ipu_clk);\n \t}\n \n-\tif (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) {\n+\tif (*channel_init_mask & (1L << IPU_CHAN_ID(channel))) {\n \t\tprintf(\"Warning: channel already initialized %d\\n\",\n \t\t       IPU_CHAN_ID(channel));\n \t}\n@@ -589,12 +656,12 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)\n \t\t\tgoto err;\n \t\t}\n \n-\t\tg_dc_di_assignment[1] = params->mem_dc_sync.di;\n+\t\tdc_di_assignment[1] = params->mem_dc_sync.di;\n \t\tipu_dc_init(1, params->mem_dc_sync.di,\n \t\t\t    params->mem_dc_sync.interlaced);\n-\t\tipu_di_use_count[params->mem_dc_sync.di]++;\n-\t\tipu_dc_use_count++;\n-\t\tipu_dmfc_use_count++;\n+\t\tctx->ipu_di_use_count[params->mem_dc_sync.di]++;\n+\t\tctx->ipu_dc_use_count++;\n+\t\tctx->ipu_dmfc_use_count++;\n \t\tbreak;\n \tcase MEM_BG_SYNC:\n \t\tif (params->mem_dp_bg_sync.di > 1) {\n@@ -602,23 +669,23 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)\n \t\t\tgoto err;\n \t\t}\n \n-\t\tg_dc_di_assignment[5] = params->mem_dp_bg_sync.di;\n+\t\tdc_di_assignment[5] = params->mem_dp_bg_sync.di;\n \t\tipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt,\n \t\t\t    params->mem_dp_bg_sync.out_pixel_fmt);\n \t\tipu_dc_init(5, params->mem_dp_bg_sync.di,\n \t\t\t    params->mem_dp_bg_sync.interlaced);\n-\t\tipu_di_use_count[params->mem_dp_bg_sync.di]++;\n-\t\tipu_dc_use_count++;\n-\t\tipu_dp_use_count++;\n-\t\tipu_dmfc_use_count++;\n+\t\tctx->ipu_di_use_count[params->mem_dp_bg_sync.di]++;\n+\t\tctx->ipu_dc_use_count++;\n+\t\tctx->ipu_dp_use_count++;\n+\t\tctx->ipu_dmfc_use_count++;\n \t\tbreak;\n \tcase MEM_FG_SYNC:\n \t\tipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt,\n \t\t\t    params->mem_dp_fg_sync.out_pixel_fmt);\n \n-\t\tipu_dc_use_count++;\n-\t\tipu_dp_use_count++;\n-\t\tipu_dmfc_use_count++;\n+\t\tctx->ipu_dc_use_count++;\n+\t\tctx->ipu_dp_use_count++;\n+\t\tctx->ipu_dmfc_use_count++;\n \t\tbreak;\n \tdefault:\n \t\tprintf(\"Missing channel initialization\\n\");\n@@ -626,16 +693,16 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)\n \t}\n \n \t/* Enable IPU sub module */\n-\tg_channel_init_mask |= 1L << IPU_CHAN_ID(channel);\n-\tif (ipu_dc_use_count == 1)\n+\t*channel_init_mask |= 1L << IPU_CHAN_ID(channel);\n+\tif (ctx->ipu_dc_use_count == 1)\n \t\tipu_conf |= IPU_CONF_DC_EN;\n-\tif (ipu_dp_use_count == 1)\n+\tif (ctx->ipu_dp_use_count == 1)\n \t\tipu_conf |= IPU_CONF_DP_EN;\n-\tif (ipu_dmfc_use_count == 1)\n+\tif (ctx->ipu_dmfc_use_count == 1)\n \t\tipu_conf |= IPU_CONF_DMFC_EN;\n-\tif (ipu_di_use_count[0] == 1)\n+\tif (ctx->ipu_di_use_count[0] == 1)\n \t\tipu_conf |= IPU_CONF_DI0_EN;\n-\tif (ipu_di_use_count[1] == 1)\n+\tif (ctx->ipu_di_use_count[1] == 1)\n \t\tipu_conf |= IPU_CONF_DI1_EN;\n \n \t__raw_writel(ipu_conf, IPU_CONF);\n@@ -647,15 +714,19 @@ err:\n /*\n  * This function is called to uninitialize a logical IPU channel.\n  *\n+ * @param   ctx\t\tThe ipu context for which the function is called\n+ *\n  * @param\tchannel Input parameter for the logical channel ID to uninit.\n  */\n-void ipu_uninit_channel(ipu_channel_t channel)\n+void ipu_uninit_channel(struct ipu_ctx *ctx, ipu_channel_t channel)\n {\n+\tu8 *dc_di_assignment = ctx->dc_di_assignment;\n+\tu32 *channel_init_mask = &ctx->channel_init_mask;\n \tu32 reg;\n \tu32 in_dma, out_dma = 0;\n \tu32 ipu_conf;\n \n-\tif ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {\n+\tif ((*channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {\n \t\tdebug(\"Channel already uninitialized %d\\n\",\n \t\t      IPU_CHAN_ID(channel));\n \t\treturn;\n@@ -686,46 +757,46 @@ void ipu_uninit_channel(ipu_channel_t channel)\n \tswitch (channel) {\n \tcase MEM_DC_SYNC:\n \t\tipu_dc_uninit(1);\n-\t\tipu_di_use_count[g_dc_di_assignment[1]]--;\n-\t\tipu_dc_use_count--;\n-\t\tipu_dmfc_use_count--;\n+\t\tctx->ipu_di_use_count[dc_di_assignment[1]]--;\n+\t\tctx->ipu_dc_use_count--;\n+\t\tctx->ipu_dmfc_use_count--;\n \t\tbreak;\n \tcase MEM_BG_SYNC:\n \t\tipu_dp_uninit(channel);\n \t\tipu_dc_uninit(5);\n-\t\tipu_di_use_count[g_dc_di_assignment[5]]--;\n-\t\tipu_dc_use_count--;\n-\t\tipu_dp_use_count--;\n-\t\tipu_dmfc_use_count--;\n+\t\tctx->ipu_di_use_count[dc_di_assignment[5]]--;\n+\t\tctx->ipu_dc_use_count--;\n+\t\tctx->ipu_dp_use_count--;\n+\t\tctx->ipu_dmfc_use_count--;\n \t\tbreak;\n \tcase MEM_FG_SYNC:\n \t\tipu_dp_uninit(channel);\n-\t\tipu_dc_use_count--;\n-\t\tipu_dp_use_count--;\n-\t\tipu_dmfc_use_count--;\n+\t\tctx->ipu_dc_use_count--;\n+\t\tctx->ipu_dp_use_count--;\n+\t\tctx->ipu_dmfc_use_count--;\n \t\tbreak;\n \tdefault:\n \t\tbreak;\n \t}\n \n-\tg_channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));\n+\t*channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));\n \n-\tif (ipu_dc_use_count == 0)\n+\tif (ctx->ipu_dc_use_count == 0)\n \t\tipu_conf &= ~IPU_CONF_DC_EN;\n-\tif (ipu_dp_use_count == 0)\n+\tif (ctx->ipu_dp_use_count == 0)\n \t\tipu_conf &= ~IPU_CONF_DP_EN;\n-\tif (ipu_dmfc_use_count == 0)\n+\tif (ctx->ipu_dmfc_use_count == 0)\n \t\tipu_conf &= ~IPU_CONF_DMFC_EN;\n-\tif (ipu_di_use_count[0] == 0)\n+\tif (ctx->ipu_di_use_count[0] == 0)\n \t\tipu_conf &= ~IPU_CONF_DI0_EN;\n-\tif (ipu_di_use_count[1] == 0)\n+\tif (ctx->ipu_di_use_count[1] == 0)\n \t\tipu_conf &= ~IPU_CONF_DI1_EN;\n \n \t__raw_writel(ipu_conf, IPU_CONF);\n \n \tif (ipu_conf == 0) {\n-\t\tclk_disable(g_ipu_clk);\n-\t\tg_ipu_clk_enabled = 0;\n+\t\tclk_disable(ctx->ipu_clk);\n+\t\tctx->ipu_clk_enabled = 0;\n \t}\n }\n \n@@ -1031,18 +1102,21 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,\n /*\n  * This function enables a logical channel.\n  *\n- * @param\tchannel\t\tInput parameter for the logical channel ID.\n+ * @param   ctx\t\tThe ipu context for which the function is called\n  *\n- * Return:\tThis function returns 0 on success or negative error code on\n- *\t\tfail.\n+ * @param   channel\tInput parameter for the logical channel ID.\n+ *\n+ * Return:  This function returns 0 on success or negative error code on\n+ *\t    fail.\n  */\n-int32_t ipu_enable_channel(ipu_channel_t channel)\n+int32_t ipu_enable_channel(struct ipu_ctx *ctx, ipu_channel_t channel)\n {\n+\tu32 *channel_enable_mask = &ctx->channel_enable_mask;\n \tu32 reg;\n \tu32 in_dma;\n \tu32 out_dma;\n \n-\tif (g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {\n+\tif (*channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {\n \t\tprintf(\"Warning: channel already enabled %d\\n\",\n \t\t       IPU_CHAN_ID(channel));\n \t}\n@@ -1062,9 +1136,9 @@ int32_t ipu_enable_channel(ipu_channel_t channel)\n \n \tif ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||\n \t    (channel == MEM_FG_SYNC))\n-\t\tipu_dp_dc_enable(channel);\n+\t\tipu_dp_dc_enable(ctx, channel);\n \n-\tg_channel_enable_mask |= 1L << IPU_CHAN_ID(channel);\n+\t*channel_enable_mask |= 1L << IPU_CHAN_ID(channel);\n \n \treturn 0;\n }\n@@ -1103,21 +1177,24 @@ void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,\n /*\n  * This function disables a logical channel.\n  *\n- * @param\tchannel\t\tInput parameter for the logical channel ID.\n+ * @param   ctx\t\t    The ipu context for which the function is called\n+ *\n+ * @param   channel\t    Input parameter for the logical channel ID.\n  *\n- * @param\twait_for_stop\tFlag to set whether to wait for channel end\n- *\t\t\t\tof frame or return immediately.\n+ * @param   wait_for_stop   Flag to set whether to wait for channel end\n+ *\t\t\t    of frame or return immediately.\n  *\n- * Return:\tThis function returns 0 on success or negative error code on\n- *\t\tfail.\n+ * Return:  This function returns 0 on success or negative error code on\n+ *\t    fail.\n  */\n-int32_t ipu_disable_channel(ipu_channel_t channel)\n+int32_t ipu_disable_channel(struct ipu_ctx *ctx, ipu_channel_t channel)\n {\n+\tu32 *channel_enable_mask = &ctx->channel_enable_mask;\n \tu32 reg;\n \tu32 in_dma;\n \tu32 out_dma;\n \n-\tif ((g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {\n+\tif ((*channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {\n \t\tdebug(\"Channel already disabled %d\\n\", IPU_CHAN_ID(channel));\n \t\treturn 0;\n \t}\n@@ -1132,7 +1209,7 @@ int32_t ipu_disable_channel(ipu_channel_t channel)\n \n \tif ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||\n \t    (channel == MEM_DC_SYNC)) {\n-\t\tipu_dp_dc_disable(channel, 0);\n+\t\tipu_dp_dc_disable(ctx, channel, 0);\n \t}\n \n \t/* Disable DMA channel(s) */\n@@ -1147,7 +1224,7 @@ int32_t ipu_disable_channel(ipu_channel_t channel)\n \t\t__raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma));\n \t}\n \n-\tg_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));\n+\t*channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));\n \n \t/* Set channel buffers NOT to be ready */\n \tif (idma_is_valid(in_dma)) {\n@@ -1219,7 +1296,7 @@ ipu_color_space_t format_to_colorspace(u32 fmt)\n \treturn RGB;\n }\n \n-bool ipu_clk_enabled(void)\n+bool ipu_clk_enabled(struct ipu_ctx *ctx)\n {\n-\treturn g_ipu_clk_enabled;\n+\treturn ctx->ipu_clk_enabled;\n }\ndiff --git a/drivers/video/imx/ipu_disp.c b/drivers/video/imx/ipu_disp.c\nindex 89dead372cd..6a337b13af6 100644\n--- a/drivers/video/imx/ipu_disp.c\n+++ b/drivers/video/imx/ipu_disp.c\n@@ -1,5 +1,10 @@\n // SPDX-License-Identifier: GPL-2.0+\n /*\n+ * Code fixes:\n+ *\n+ * (C) Copyright 2025\n+ * Brian Ruley, GE HealthCare, brian.ruley@gehealthcare.com\n+ *\n  * Porting to u-boot:\n  *\n  * (C) Copyright 2010\n@@ -10,8 +15,6 @@\n  * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.\n  */\n \n-/* #define DEBUG */\n-\n #include \"ipu.h\"\n #include \"ipu_regs.h\"\n #include <asm/arch/imx-regs.h>\n@@ -40,14 +43,6 @@ int dmfc_type_setup;\n static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23;\n int g_di1_tvout;\n \n-extern struct clk *g_ipu_clk;\n-extern struct clk *g_ldb_clk;\n-extern struct clk *g_di_clk[2];\n-extern struct clk *g_pixel_clk[2];\n-\n-extern unsigned char g_ipu_clk_enabled;\n-extern unsigned char g_dc_di_assignment[];\n-\n void ipu_dmfc_init(int dmfc_type, int first)\n {\n \tu32 dmfc_wr_chan, dmfc_dp_chan;\n@@ -579,7 +574,7 @@ void ipu_dc_uninit(int dc_chan)\n \t}\n }\n \n-void ipu_dp_dc_enable(ipu_channel_t channel)\n+void ipu_dp_dc_enable(struct ipu_ctx *ctx, ipu_channel_t channel)\n {\n \tint di;\n \tu32 reg;\n@@ -602,7 +597,7 @@ void ipu_dp_dc_enable(ipu_channel_t channel)\n \t\treturn;\n \t}\n \n-\tdi = g_dc_di_assignment[dc_chan];\n+\tdi = ctx->dc_di_assignment[dc_chan];\n \n \t/* Make sure other DC sync channel is not assigned same DI */\n \treg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan));\n@@ -616,12 +611,13 @@ void ipu_dp_dc_enable(ipu_channel_t channel)\n \treg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;\n \t__raw_writel(reg, DC_WR_CH_CONF(dc_chan));\n \n-\tclk_enable(g_pixel_clk[di]);\n+\tclk_enable(ctx->pixel_clk[di]);\n }\n \n static unsigned char dc_swap;\n \n-void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)\n+void ipu_dp_dc_disable(struct ipu_ctx *ctx, ipu_channel_t channel,\n+\t\t       unsigned char swap)\n {\n \tu32 reg;\n \tu32 csc;\n@@ -658,7 +654,7 @@ void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)\n \t\t * Wait for DC triple buffer to empty,\n \t\t * this check is useful for tv overlay.\n \t\t */\n-\t\tif (g_dc_di_assignment[dc_chan] == 0)\n+\t\tif (ctx->dc_di_assignment[dc_chan] == 0)\n \t\t\twhile ((__raw_readl(DC_STAT) & 0x00000002) !=\n \t\t\t       0x00000002) {\n \t\t\t\tudelay(2000);\n@@ -666,7 +662,7 @@ void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)\n \t\t\t\tif (timeout <= 0)\n \t\t\t\t\tbreak;\n \t\t\t}\n-\t\telse if (g_dc_di_assignment[dc_chan] == 1)\n+\t\telse if (ctx->dc_di_assignment[dc_chan] == 1)\n \t\t\twhile ((__raw_readl(DC_STAT) & 0x00000020) !=\n \t\t\t       0x00000020) {\n \t\t\t\tudelay(2000);\n@@ -698,7 +694,7 @@ void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)\n \t\t__raw_writel(reg, DC_WR_CH_CONF(dc_chan));\n \n \t\treg = __raw_readl(IPU_DISP_GEN);\n-\t\tif (g_dc_di_assignment[dc_chan])\n+\t\tif (ctx->dc_di_assignment[dc_chan])\n \t\t\treg &= ~DI1_COUNTER_RELEASE;\n \t\telse\n \t\t\treg &= ~DI0_COUNTER_RELEASE;\n@@ -706,7 +702,7 @@ void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)\n \n \t\t/* Clock is already off because it must be done quickly, but\n \t\t   we need to fix the ref count */\n-\t\tclk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]);\n+\t\tclk_disable(ctx->pixel_clk[ctx->dc_di_assignment[dc_chan]]);\n \t}\n }\n \n@@ -765,46 +761,18 @@ static int ipu_pixfmt_to_map(u32 fmt)\n /*\n  * This function is called to initialize a synchronous LCD panel.\n  *\n- * @param\tdisp\t\tThe DI the panel is attached to.\n- *\n- * @param\tpixel_clk\tDesired pixel clock frequency in Hz.\n- *\n- * @param\tpixel_fmt\tInput parameter for pixel format of buffer.\n- *\t\t\t\tPixel format is a FOURCC ASCII code.\n- *\n- * @param\twidth\t\tThe width of panel in pixels.\n- *\n- * @param\theight\t\tThe height of panel in pixels.\n+ * @param\tdi\tPointer to display data.\n  *\n- * @param\thStartWidth\tThe number of pixel clocks between the HSYNC\n- *\t\t\t\tsignal pulse and the start of valid data.\n- *\n- * @param\thSyncWidth\tThe width of the HSYNC signal in units of pixel\n- *\t\t\t\tclocks.\n- *\n- * @param\thEndWidth\tThe number of pixel clocks between the end of\n- *\t\t\t\tvalid data and the HSYNC signal for next line.\n- *\n- * @param\tvStartWidth\tThe number of lines between the VSYNC\n- *\t\t\t\tsignal pulse and the start of valid data.\n- *\n- * @param\tvSyncWidth\tThe width of the VSYNC signal in units of lines\n- *\n- * @param\tvEndWidth\tThe number of lines between the end of valid\n- *\t\t\t\tdata and the VSYNC signal for next frame.\n- *\n- * @param\tsig\t\tBitfield of signal polarities for LCD interface.\n+ * @param\tsig\tBitfield of signal polarities for LCD interface.\n  *\n  * Return:\tThis function returns 0 on success or negative error code on\n  *\t\tfail.\n  */\n \n-int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n-\t\t\t    u32 pixel_fmt, u16 h_start_width, u16 h_sync_width,\n-\t\t\t    u16 h_end_width, u16 v_start_width,\n-\t\t\t    u16 v_sync_width, u16 v_end_width, u32 v_to_h_sync,\n-\t\t\t    ipu_di_signal_cfg_t sig)\n+int32_t ipu_init_sync_panel(struct ipu_di_config *di, ipu_di_signal_cfg_t sig)\n {\n+\tstruct ipu_ctx *ctx = di->ctx;\n+\tint disp = di->disp;\n \tu32 reg;\n \tu32 di_gen, vsync_cnt;\n \tu32 div, rounded_pixel_clk;\n@@ -812,22 +780,24 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \tint map;\n \tstruct clk *di_parent;\n \n-\tdebug(\"panel size = %d x %d\\n\", width, height);\n+\tdebug(\"panel size = %d x %d\\n\", di->width, di->height);\n \n-\tif ((v_sync_width == 0) || (h_sync_width == 0))\n+\tif ((di->v_sync_width == 0) || (di->h_sync_width == 0))\n \t\treturn -EINVAL;\n \n \t/* adapt panel to ipu restricitions */\n-\tif (v_end_width < 2) {\n-\t\tv_end_width = 2;\n+\tif (di->v_end_width < 2) {\n+\t\tdi->v_end_width = 2;\n \t\tputs(\"WARNING: v_end_width (lower_margin) must be >= 2, adjusted\\n\");\n \t}\n \n-\th_total = width + h_sync_width + h_start_width + h_end_width;\n-\tv_total = height + v_sync_width + v_start_width + v_end_width;\n+\th_total = di->width + di->h_sync_width + di->h_start_width +\n+\t\t  di->h_end_width;\n+\tv_total = di->height + di->v_sync_width + di->v_start_width +\n+\t\t  di->v_end_width;\n \n \t/* Init clocking */\n-\tdebug(\"pixel clk = %dHz\\n\", pixel_clk);\n+\tdebug(\"pixel clk = %dHz\\n\", di->pixel_clk_rate);\n \n \tif (sig.ext_clk) {\n \t\tif (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/\n@@ -835,11 +805,12 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \t\t\t * Set the  PLL to be an even multiple\n \t\t\t * of the pixel clock.\n \t\t\t */\n-\t\t\tif ((clk_get_usecount(g_pixel_clk[0]) == 0) &&\n-\t\t\t    (clk_get_usecount(g_pixel_clk[1]) == 0)) {\n-\t\t\t\tdi_parent = clk_get_parent(g_di_clk[disp]);\n-\t\t\t\trounded_pixel_clk = clk_round_rate(\n-\t\t\t\t\tg_pixel_clk[disp], pixel_clk);\n+\t\t\tif ((clk_get_usecount(ctx->pixel_clk[0]) == 0) &&\n+\t\t\t    (clk_get_usecount(ctx->pixel_clk[1]) == 0)) {\n+\t\t\t\tdi_parent = clk_get_parent(ctx->di_clk[disp]);\n+\t\t\t\trounded_pixel_clk =\n+\t\t\t\t\tclk_round_rate(ctx->pixel_clk[disp],\n+\t\t\t\t\t\t       di->pixel_clk_rate);\n \t\t\t\tdiv = clk_get_rate(di_parent) /\n \t\t\t\t      rounded_pixel_clk;\n \t\t\t\tif (div % 2)\n@@ -849,27 +820,28 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \t\t\t\t\tclk_set_rate(di_parent,\n \t\t\t\t\t\t     div * rounded_pixel_clk);\n \t\t\t\tudelay(10000);\n-\t\t\t\tclk_set_rate(g_di_clk[disp],\n+\t\t\t\tclk_set_rate(ctx->di_clk[disp],\n \t\t\t\t\t     2 * rounded_pixel_clk);\n \t\t\t\tudelay(10000);\n \t\t\t}\n \t\t}\n-\t\tclk_set_parent(g_pixel_clk[disp], g_ldb_clk);\n+\t\tclk_set_parent(ctx->pixel_clk[disp], ctx->ldb_clk);\n \t} else {\n-\t\tif (clk_get_usecount(g_pixel_clk[disp]) != 0)\n-\t\t\tclk_set_parent(g_pixel_clk[disp], g_ipu_clk);\n+\t\tif (clk_get_usecount(ctx->pixel_clk[disp]) != 0)\n+\t\t\tclk_set_parent(ctx->pixel_clk[disp], ctx->ipu_clk);\n \t}\n-\trounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk);\n-\tclk_set_rate(g_pixel_clk[disp], rounded_pixel_clk);\n+\trounded_pixel_clk =\n+\t\tclk_round_rate(ctx->pixel_clk[disp], di->pixel_clk_rate);\n+\tclk_set_rate(ctx->pixel_clk[disp], rounded_pixel_clk);\n \tudelay(5000);\n \t/* Get integer portion of divider */\n-\tdiv = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) /\n+\tdiv = clk_get_rate(clk_get_parent(ctx->pixel_clk[disp])) /\n \t      rounded_pixel_clk;\n \n \tipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1);\n \tipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);\n \n-\tmap = ipu_pixfmt_to_map(pixel_fmt);\n+\tmap = ipu_pixfmt_to_map(di->pixel_fmt);\n \tif (map < 0) {\n \t\tdebug(\"IPU_DISP: No MAP\\n\");\n \t\treturn -EINVAL;\n@@ -931,7 +903,7 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \t\t\t\t   4, /* counter */\n \t\t\t\t   v_total / 2 - 1, /* run count */\n \t\t\t\t   DI_SYNC_HSYNC, /* run_resolution */\n-\t\t\t\t   v_start_width, /*  offset */\n+\t\t\t\t   di->v_start_width, /*  offset */\n \t\t\t\t   DI_SYNC_HSYNC, /* offset resolution */\n \t\t\t\t   2, /* repeat count */\n \t\t\t\t   DI_SYNC_VSYNC, /* CNT_CLR_SEL */\n@@ -949,7 +921,7 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \t\t\t\t   DI_SYNC_HSYNC, /* run_resolution */\n \t\t\t\t   0, /*  offset */\n \t\t\t\t   DI_SYNC_NONE, /* offset resolution */\n-\t\t\t\t   height / 2, /* repeat count */\n+\t\t\t\t   di->height / 2, /* repeat count */\n \t\t\t\t   4, /* CNT_CLR_SEL */\n \t\t\t\t   0, /* CNT_POLARITY_GEN_EN */\n \t\t\t\t   DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */\n@@ -996,9 +968,9 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \t\t\t\t   8, /* counter */\n \t\t\t\t   0, /* run count  */\n \t\t\t\t   DI_SYNC_CLK, /* run_resolution */\n-\t\t\t\t   h_start_width, /* offset  */\n+\t\t\t\t   di->h_start_width, /* offset  */\n \t\t\t\t   DI_SYNC_CLK, /* offset resolution */\n-\t\t\t\t   width, /* repeat count  */\n+\t\t\t\t   di->width, /* repeat count  */\n \t\t\t\t   5, /* CNT_CLR_SEL  */\n \t\t\t\t   0, /* CNT_POLARITY_GEN_EN  */\n \t\t\t\t   DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */\n@@ -1042,26 +1014,27 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \n \t\t/* Setup external (delayed) HSYNC waveform */\n \t\tipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1,\n-\t\t\t\t   DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,\n-\t\t\t\t   0, DI_SYNC_NONE, 1, DI_SYNC_NONE,\n-\t\t\t\t   DI_SYNC_CLK, 0, h_sync_width * 2);\n+\t\t\t\t   DI_SYNC_CLK, div * di->v_to_h_sync,\n+\t\t\t\t   DI_SYNC_CLK, 0, DI_SYNC_NONE, 1,\n+\t\t\t\t   DI_SYNC_NONE, DI_SYNC_CLK, 0,\n+\t\t\t\t   di->h_sync_width * 2);\n \t\t/* Setup VSYNC waveform */\n \t\tvsync_cnt = DI_SYNC_VSYNC;\n \t\tipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1,\n \t\t\t\t   DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,\n \t\t\t\t   DI_SYNC_NONE, 1, DI_SYNC_NONE,\n-\t\t\t\t   DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);\n+\t\t\t\t   DI_SYNC_INT_HSYNC, 0, di->v_sync_width * 2);\n \t\t__raw_writel(v_total - 1, DI_SCR_CONF(disp));\n \n \t\t/* Setup active data waveform to sync with DC */\n \t\tipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC,\n-\t\t\t\t   v_sync_width + v_start_width, DI_SYNC_HSYNC,\n-\t\t\t\t   height, DI_SYNC_VSYNC, 0, DI_SYNC_NONE,\n-\t\t\t\t   DI_SYNC_NONE, 0, 0);\n+\t\t\t\t   di->v_sync_width + di->v_start_width,\n+\t\t\t\t   DI_SYNC_HSYNC, di->height, DI_SYNC_VSYNC, 0,\n+\t\t\t\t   DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);\n \t\tipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK,\n-\t\t\t\t   h_sync_width + h_start_width, DI_SYNC_CLK,\n-\t\t\t\t   width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,\n-\t\t\t\t   0);\n+\t\t\t\t   di->h_sync_width + di->h_start_width,\n+\t\t\t\t   DI_SYNC_CLK, di->width, 4, 0, DI_SYNC_NONE,\n+\t\t\t\t   DI_SYNC_NONE, 0, 0);\n \n \t\t/* reset all unused counters */\n \t\t__raw_writel(0, DI_SW_GEN0(disp, 6));\n@@ -1112,7 +1085,7 @@ int32_t ipu_init_sync_panel(int disp, u32 pixel_clk, u16 width, u16 height,\n \t\treg |= DI_POL_DRDY_DATA_POLARITY;\n \t__raw_writel(reg, DI_POL(disp));\n \n-\t__raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));\n+\t__raw_writel(di->width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));\n \n \treturn 0;\n }\ndiff --git a/drivers/video/imx/mxc_ipuv3_fb.c b/drivers/video/imx/mxc_ipuv3_fb.c\nindex fb9d364d23a..ab416fdd33c 100644\n--- a/drivers/video/imx/mxc_ipuv3_fb.c\n+++ b/drivers/video/imx/mxc_ipuv3_fb.c\n@@ -1,5 +1,10 @@\n // SPDX-License-Identifier: GPL-2.0+\n /*\n+ * Code fixes:\n+ *\n+ * (C) Copyright 2025\n+ * Brian Ruley, GE HealthCare, brian.ruley@gehealthcare.com\n+ *\n  * Porting to u-boot:\n  *\n  * (C) Copyright 2010\n@@ -19,16 +24,17 @@\n #include <asm/global_data.h>\n #include <asm/io.h>\n #include <asm/mach-imx/video.h>\n+#include <linux/err.h>\n #include <linux/errno.h>\n #include <linux/fb.h>\n #include <linux/list.h>\n #include <linux/string.h>\n #include <log.h>\n-#include <malloc.h>\n #include <panel.h>\n #include <part.h>\n \n #include <dm.h>\n+#include <dm/devres.h>\n #include <video.h>\n \n DECLARE_GLOBAL_DATA_PTR;\n@@ -60,6 +66,11 @@ static void fb_videomode_to_var(struct fb_var_screeninfo *var,\n \tvar->vmode = mode->vmode & FB_VMODE_MASK;\n }\n \n+struct ipuv3_video_priv {\n+\tstruct ipu_ctx *ctx;\n+\tulong regs;\n+};\n+\n /*\n  * Structure containing the MXC specific framebuffer information.\n  */\n@@ -67,7 +78,7 @@ struct mxcfb_info {\n \tstruct udevice *udev;\n \tint blank;\n \tipu_channel_t ipu_ch;\n-\tint ipu_di;\n+\tstruct ipu_di_config *di;\n \tu32 ipu_di_pix_fmt;\n \tunsigned char overlay;\n \tunsigned char alpha_chan_en;\n@@ -80,6 +91,8 @@ struct mxcfb_info {\n \tu32 cur_ipu_alpha_buf;\n \n \tu32 pseudo_palette[16];\n+\n+\tstruct ipu_ctx *ctx;\n };\n \n enum { BOTH_ON, SRC_ON, TGT_ON, BOTH_OFF };\n@@ -118,7 +131,7 @@ static int setup_disp_channel1(struct fb_info *fbi)\n \tstruct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;\n \n \tmemset(&params, 0, sizeof(params));\n-\tparams.mem_dp_bg_sync.di = mxc_fbi->ipu_di;\n+\tparams.mem_dp_bg_sync.di = mxc_fbi->di->disp;\n \n \tdebug(\"%s called\\n\", __func__);\n \t/*\n@@ -137,9 +150,7 @@ static int setup_disp_channel1(struct fb_info *fbi)\n \tif (mxc_fbi->alpha_chan_en)\n \t\tparams.mem_dp_bg_sync.alpha_chan_en = 1;\n \n-\tipu_init_channel(mxc_fbi->ipu_ch, &params);\n-\n-\treturn 0;\n+\treturn ipu_init_channel(mxc_fbi->ctx, mxc_fbi->ipu_ch, &params);\n }\n \n static int setup_disp_channel2(struct fb_info *fbi)\n@@ -182,8 +193,8 @@ static int mxcfb_set_par(struct fb_info *fbi)\n \tstruct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;\n \tu32 out_pixel_fmt;\n \n-\tipu_disable_channel(mxc_fbi->ipu_ch);\n-\tipu_uninit_channel(mxc_fbi->ipu_ch);\n+\tipu_disable_channel(mxc_fbi->ctx, mxc_fbi->ipu_ch);\n+\tipu_uninit_channel(mxc_fbi->ctx, mxc_fbi->ipu_ch);\n \n \tmem_len = fbi->var.yres_virtual * fbi->fix.line_length;\n \tif (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {\n@@ -225,13 +236,19 @@ static int mxcfb_set_par(struct fb_info *fbi)\n \n \tdebug(\"pixclock = %lu Hz\\n\", PICOS2KHZ(fbi->var.pixclock) * 1000UL);\n \n-\tif (ipu_init_sync_panel(mxc_fbi->ipu_di,\n-\t\t\t\t(PICOS2KHZ(fbi->var.pixclock)) * 1000UL,\n-\t\t\t\tfbi->var.xres, fbi->var.yres, out_pixel_fmt,\n-\t\t\t\tfbi->var.left_margin, fbi->var.hsync_len,\n-\t\t\t\tfbi->var.right_margin, fbi->var.upper_margin,\n-\t\t\t\tfbi->var.vsync_len, fbi->var.lower_margin, 0,\n-\t\t\t\tsig_cfg) != 0) {\n+\tmxc_fbi->di->pixel_clk_rate = (PICOS2KHZ(fbi->var.pixclock)) * 1000UL;\n+\tmxc_fbi->di->pixel_fmt = out_pixel_fmt;\n+\tmxc_fbi->di->width = fbi->var.xres;\n+\tmxc_fbi->di->height = fbi->var.yres;\n+\tmxc_fbi->di->h_start_width = fbi->var.left_margin;\n+\tmxc_fbi->di->h_sync_width = fbi->var.hsync_len;\n+\tmxc_fbi->di->h_end_width = fbi->var.right_margin;\n+\tmxc_fbi->di->v_start_width = fbi->var.upper_margin;\n+\tmxc_fbi->di->v_sync_width = fbi->var.vsync_len;\n+\tmxc_fbi->di->v_end_width = fbi->var.lower_margin;\n+\tmxc_fbi->di->v_to_h_sync = 0;\n+\n+\tif (ipu_init_sync_panel(mxc_fbi->di, sig_cfg) != 0) {\n \t\tputs(\"mxcfb: Error initializing panel.\\n\");\n \t\treturn -EINVAL;\n \t}\n@@ -241,7 +258,7 @@ static int mxcfb_set_par(struct fb_info *fbi)\n \t\treturn retval;\n \n \tif (mxc_fbi->blank == FB_BLANK_UNBLANK)\n-\t\tipu_enable_channel(mxc_fbi->ipu_ch);\n+\t\tipu_enable_channel(mxc_fbi->ctx, mxc_fbi->ipu_ch);\n \n \treturn retval;\n }\n@@ -403,9 +420,12 @@ static int mxcfb_unmap_video_memory(struct fb_info *fbi)\n  * structures.\tThis includes information such as bits per pixel,\n  * color maps, screen width/height and RGBA offsets.\n  *\n+ * @param\tdev\tThe device structure for the IPU passed in by the\n+ *\t\t\tdriver framework.\n+ *\n  * Return:\tFramebuffer structure initialized with our information\n  */\n-static struct fb_info *mxcfb_init_fbinfo(void)\n+static struct fb_info *mxcfb_init_fbinfo(struct udevice *dev)\n {\n #define BYTES_PER_LONG 4\n #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))\n@@ -419,13 +439,10 @@ static struct fb_info *mxcfb_init_fbinfo(void)\n \t/*\n \t * Allocate sufficient memory for the fb structure\n \t */\n-\n-\tp = malloc(size);\n+\tp = devm_kzalloc(dev, size, GFP_KERNEL);\n \tif (!p)\n \t\treturn NULL;\n \n-\tmemset(p, 0, size);\n-\n \tfbi = (struct fb_info *)p;\n \tfbi->par = p + sizeof(struct fb_info) + PADDING;\n \n@@ -441,8 +458,6 @@ static struct fb_info *mxcfb_init_fbinfo(void)\n \treturn fbi;\n }\n \n-extern struct clk *g_ipu_clk;\n-\n /*\n  * Probe routine for the framebuffer driver. It is called during the\n  * driver binding process. The following functions are performed in\n@@ -454,13 +469,15 @@ extern struct clk *g_ipu_clk;\n static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt, u8 disp,\n \t\t       struct fb_videomode const *mode)\n {\n+\tstruct ipuv3_video_priv *ipu_priv = dev_get_priv(dev);\n+\tstruct ipu_ctx *ctx = ipu_priv->ctx;\n \tstruct fb_info *fbi;\n \tstruct mxcfb_info *mxcfbi;\n \n \t/*\n \t * Initialize FB structures\n \t */\n-\tfbi = mxcfb_init_fbinfo();\n+\tfbi = mxcfb_init_fbinfo(dev);\n \tif (!fbi)\n \t\treturn -ENOMEM;\n \n@@ -474,18 +491,24 @@ static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt, u8 disp,\n \t\tmxcfbi->blank = FB_BLANK_POWERDOWN;\n \t}\n \n-\tmxcfbi->ipu_di = disp;\n+\tmxcfbi->di = devm_kzalloc(ctx->dev, sizeof(*mxcfbi->di), GFP_KERNEL);\n+\tif (!mxcfbi->di)\n+\t\treturn -ENOMEM;\n+\n+\tmxcfbi->di->disp = disp;\n+\tmxcfbi->di->ctx = ctx;\n+\tmxcfbi->ctx = ctx;\n \tmxcfbi->udev = dev;\n \n-\tif (!ipu_clk_enabled())\n-\t\tclk_enable(g_ipu_clk);\n+\tif (!ipu_clk_enabled(ctx))\n+\t\tclk_enable(ctx->ipu_clk);\n \n \tipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);\n \tipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);\n \n \tg_dp_in_use = 1;\n \n-\tmxcfb_info[mxcfbi->ipu_di] = fbi;\n+\tmxcfb_info[mxcfbi->di->disp] = fbi;\n \n \t/* Need dummy values until real panel is configured */\n \n@@ -514,20 +537,22 @@ static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt, u8 disp,\n \treturn 0;\n }\n \n-void ipuv3_fb_shutdown(void)\n+void ipuv3_fb_shutdown(struct udevice *dev)\n {\n \tint i;\n \tstruct ipu_stat *stat = (struct ipu_stat *)IPU_STAT;\n+\tstruct ipuv3_video_priv *ipu_priv = dev_get_priv(dev);\n+\tstruct ipu_ctx *ctx = ipu_priv->ctx;\n \n-\tif (!ipu_clk_enabled())\n+\tif (!ipu_clk_enabled(ctx))\n \t\treturn;\n \n \tfor (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) {\n \t\tstruct fb_info *fbi = mxcfb_info[i];\n \t\tif (fbi) {\n \t\t\tstruct mxcfb_info *mxc_fbi = fbi->par;\n-\t\t\tipu_disable_channel(mxc_fbi->ipu_ch);\n-\t\t\tipu_uninit_channel(mxc_fbi->ipu_ch);\n+\t\t\tipu_disable_channel(ctx, mxc_fbi->ipu_ch);\n+\t\t\tipu_uninit_channel(ctx, mxc_fbi->ipu_ch);\n \t\t}\n \t}\n \tfor (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) {\n@@ -556,18 +581,22 @@ static int ipuv3_video_probe(struct udevice *dev)\n {\n \tstruct video_uc_plat *plat = dev_get_uclass_plat(dev);\n \tstruct video_priv *uc_priv = dev_get_uclass_priv(dev);\n+\tstruct ipuv3_video_priv *ipu_priv = dev_get_priv(dev);\n #if defined(CONFIG_DISPLAY)\n \tstruct udevice *disp_dev;\n #endif\n+\tstruct ipu_ctx *ctx;\n \tu32 fb_start, fb_end;\n \tint ret;\n \n \tdebug(\"%s() plat: base 0x%lx, size 0x%x\\n\", __func__, plat->base,\n \t      plat->size);\n \n-\tret = ipu_probe();\n-\tif (ret)\n-\t\treturn ret;\n+\tctx = ipu_probe(dev);\n+\tif (IS_ERR(ctx))\n+\t\treturn PTR_ERR(ctx);\n+\n+\tipu_priv->ctx = ctx;\n \n \tret = ipu_displays_init();\n \tif (ret < 0)\n@@ -607,10 +636,6 @@ static int ipuv3_video_probe(struct udevice *dev)\n \treturn 0;\n }\n \n-struct ipuv3_video_priv {\n-\tulong regs;\n-};\n-\n static int ipuv3_video_bind(struct udevice *dev)\n {\n \tstruct video_uc_plat *plat = dev_get_uclass_plat(dev);\ndiff --git a/include/ipu_pixfmt.h b/include/ipu_pixfmt.h\nindex 866ead0ec71..a485d713805 100644\n--- a/include/ipu_pixfmt.h\n+++ b/include/ipu_pixfmt.h\n@@ -11,6 +11,7 @@\n #ifndef __IPU_PIXFMT_H__\n #define __IPU_PIXFMT_H__\n \n+#include <dm/device.h>\n #include <linux/list.h>\n #include <linux/fb.h>\n \n@@ -62,6 +63,6 @@\n int ipuv3_fb_init(struct fb_videomode const *mode,\n \t\t  uint8_t disp,\n \t\t  uint32_t pixfmt);\n-void ipuv3_fb_shutdown(void);\n+void ipuv3_fb_shutdown(struct udevice *dev);\n \n #endif\n","prefixes":["v1","7/7"]}