get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2218990/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2218990,
    "url": "http://patchwork.ozlabs.org/api/patches/2218990/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/7edcce04b39aabc1f58e09814e7fadff226e2bb8.1775121078.git.simona.toaca@nxp.com/",
    "project": {
        "id": 18,
        "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api",
        "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,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<7edcce04b39aabc1f58e09814e7fadff226e2bb8.1775121078.git.simona.toaca@nxp.com>",
    "list_archive_url": null,
    "date": "2026-04-02T09:40:43",
    "name": "[v3,1/6] imx9: Add support for saving DDR training data to NVM",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "72bea5e4fefde1f354c4c7cb6c54cd0afdf71fe6",
    "submitter": {
        "id": 92829,
        "url": "http://patchwork.ozlabs.org/api/people/92829/?format=api",
        "name": "Simona Toaca",
        "email": "simona.toaca@oss.nxp.com"
    },
    "delegate": {
        "id": 151988,
        "url": "http://patchwork.ozlabs.org/api/users/151988/?format=api",
        "username": "festevam",
        "first_name": "Fabio",
        "last_name": "Estevam",
        "email": "festevam@gmail.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/7edcce04b39aabc1f58e09814e7fadff226e2bb8.1775121078.git.simona.toaca@nxp.com/mbox/",
    "series": [
        {
            "id": 498456,
            "url": "http://patchwork.ozlabs.org/api/series/498456/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=498456",
            "date": "2026-04-02T09:40:42",
            "name": "imx9{4,5,52}: Add Quickboot support",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/498456/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2218990/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2218990/checks/",
    "tags": {},
    "related": [],
    "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=NXP1.onmicrosoft.com header.i=@NXP1.onmicrosoft.com\n header.a=rsa-sha256 header.s=selector1-NXP1-onmicrosoft-com\n header.b=heFut8uS;\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=none (p=none dis=none) header.from=oss.nxp.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=NXP1.onmicrosoft.com header.i=@NXP1.onmicrosoft.com\n header.b=\"heFut8uS\";\n\tdkim-atps=neutral",
            "phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=oss.nxp.com",
            "phobos.denx.de;\n spf=pass smtp.mailfrom=simona.toaca@oss.nxp.com",
            "dkim=none (message not signed)\n header.d=none;dmarc=none action=none header.from=oss.nxp.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 4fmc5265frz1yCs\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 02 Apr 2026 20:29:42 +1100 (AEDT)",
            "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 216B784101;\n\tThu,  2 Apr 2026 11:29:37 +0200 (CEST)",
            "by phobos.denx.de (Postfix, from userid 109)\n id 45BFC8416F; Thu,  2 Apr 2026 11:29:36 +0200 (CEST)",
            "from AS8PR04CU009.outbound.protection.outlook.com\n (mail-westeuropeazlp170110003.outbound.protection.outlook.com\n [IPv6:2a01:111:f403:c201::3])\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 1ADE584105\n for <u-boot@lists.denx.de>; Thu,  2 Apr 2026 11:29:31 +0200 (CEST)",
            "from VI0PR04MB11917.eurprd04.prod.outlook.com (2603:10a6:800:306::9)\n by AM7PR04MB7095.eurprd04.prod.outlook.com (2603:10a6:20b:11c::21)\n with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.28; Thu, 2 Apr\n 2026 09:29:29 +0000",
            "from VI0PR04MB11917.eurprd04.prod.outlook.com\n ([fe80::a506:3460:d2bc:26e7]) by VI0PR04MB11917.eurprd04.prod.outlook.com\n ([fe80::a506:3460:d2bc:26e7%4]) with mapi id 15.20.9769.016; Thu, 2 Apr 2026\n 09:29:28 +0000"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-0.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,FORGED_SPF_HELO,RCVD_IN_DNSWL_BLOCKED,SPF_HELO_PASS,\n T_SPF_PERMERROR autolearn=no autolearn_force=no version=3.4.2",
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=FVfBe5QTSVY4QcX2zI1r7GyARd3c8jOFh1d04PrSgv1UE/VxdZJUP9lodZ5KASztNGg8w2j0+WKUgBVb9iV+HfnjWINv/jcRG78JO+QoCMkcrGXFpJK6SNaUXXz6OWqgLhmbuP4JU302T4YjJ0GmeZU2dDh3kI1c5p0QVlJR7aLYS/KiIUrGNM0F2WXfMGSBdyyzQ2iWuD6IqTrm3ETvr3mVwGXfOqwJT7qYjfmKdS9YFb/JkxzNLEmdqjW0+JyT9+cdDgvW0W/El28+O0ZAbDrC8DuKQeJ8kdEXGX0Kn758k2l34cF+y2Zewd/6yStqshnjO0bDsgkrfrgxqnu6BA==",
        "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=9i87pC02SZqITDDg6vBNSC75GOF//gNORXhM/kl/3AI=;\n b=Vnj62THmuRqMECjUAYZWHq+xTmL5ajecCMmVgnwuMIqAiiFDTfGgxutA+gl2rMMqkWVX42v+wAVPxObgpMFoOpRoxhO6yhZNfK53jTvg2+qHYhYQi6e3b4V8kedYOk02rtppVSkOSv73VliVjBJ9dWBAD0i+5cIm6qMDxZWjQY4+xlCEW0XKoGMRN8TqR1cexgSAM/1bqz49cEksjbbPpxFFauUrmDM7WpM5/0T5zpbagV7PV+5tPDnTgTL93j6sJ7GKtgAY9zvpybvyz8Ml5l+NqLejuMsdpWxZSzLjQeYzejA12HgIRCFcf3JEDnWPRZvFNBc+ZUwukSKsvmltjg==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=oss.nxp.com; dmarc=pass action=none header.from=oss.nxp.com;\n dkim=pass header.d=oss.nxp.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=NXP1.onmicrosoft.com;\n s=selector1-NXP1-onmicrosoft-com;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=9i87pC02SZqITDDg6vBNSC75GOF//gNORXhM/kl/3AI=;\n b=heFut8uSIBM2r8hdm3oa36twAzQpVszduNq3l/eyR0tPpBt4wD8ui+lc0rD9gwLFVtzCRn4ihKs/1DdDDH49eR4U+AFioe/sXYAPBR1BYhoq43FbBR3cLtnZB4S/jBfS79KW5D6jEtfDVRtSjQafZfS78tynuIUfYNN33w6Iip5oe5/z67VG1IfNK7hseTUzMIZ5P3Al0BmjVHJynrtFBKE8L7pB/RIh0naOMcDH8e6SqtfxONi6MW4rATf28pVFVOMCPa1zF4LZUx9gPJENb0VSnXAZT5AKwihlWG266p+AdfbbaYMMkWalBXYcp6wfP70f0x7Y3mVl75ZluniZVg==",
        "From": "\"Simona Toaca (OSS)\" <simona.toaca@oss.nxp.com>",
        "To": "uboot-imx@nxp.com,\n\tu-boot@lists.denx.de",
        "Cc": "Stefano Babic <sbabic@nabladev.com>, festevam@gmail.com, peng.fan@nxp.com,\n alice.guo@nxp.com, viorel.suman@nxp.com, simona.toaca@nxp.com,\n ye.li@nxp.com, ping.bai@nxp.com, marex@nabladev.com,\n sebastien.szymanski@armadeus.com, ravi@prevas.dk,\n joao.goncalves@toradex.com, ji.luo@nxp.com, semen.protsenko@linaro.org,\n tharvey@gateworks.com, qijian.guo@nxp.com",
        "Subject": "[PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM",
        "Date": "Thu,  2 Apr 2026 12:40:43 +0300",
        "Message-ID": "\n <7edcce04b39aabc1f58e09814e7fadff226e2bb8.1775121078.git.simona.toaca@nxp.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<cover.1775121078.git.simona.toaca@nxp.com>",
        "References": "<cover.1775121078.git.simona.toaca@nxp.com>",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "FR4P281CA0122.DEUP281.PROD.OUTLOOK.COM\n (2603:10a6:d10:b9::6) To VI0PR04MB11917.eurprd04.prod.outlook.com\n (2603:10a6:800:306::9)",
        "MIME-Version": "1.0",
        "X-MS-Exchange-MessageSentRepresentingType": "1",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "VI0PR04MB11917:EE_|AM7PR04MB7095:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "1c71b885-b63d-4dbc-2732-08de909a5692",
        "X-MS-Exchange-SharedMailbox-RoutingAgent-Processed": "True",
        "X-LD-Processed": "686ea1d3-bc2b-4c6f-a92c-d99c5c301635,ExtAddr",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;\n ARA:13230040|366016|19092799006|376014|1800799024|18002099003|22082099003|56012099003;",
        "X-Microsoft-Antispam-Message-Info": "\n ygE95mLB/fLNhRmnlj5ob6UxgUUCtvLYtXLkWG7qA+o8pOtETOl+DVvLUoTOKgFTXK4JNzeWg9VBd/l7l4CunzADC8+zu1oKYwRBZ9MMeN0yC9satj0DvdTrSHg7AN3bOt2EjIKk9+v8myKGJN98mBZ6O0Zz4q/ZQWGf/cG1mqf8tvjBdHzSOjJdUtQ5QVJw5l/9PT9wMhXsXd0pELSOlWP0mCRd8+V5T4uk4sR8VYMEsQeYOpgE0X6MILM3hu/tn/oVpodmCmappkQEdzhkWWbjoOLpKDF39ozgRudAx/Ef8CnWO3T4GtnT72501q8UxGGQ8qllSfgeKZA37elunEXxBGt1j/YvRm94sO7jgXvGqSxMWHzbtbeImlH42QJ08FjcU7chJCov/oQzzdA43+0CLg3sq7KlgF5Wo6WcVwBmBmPgTBflLZe1C+1EJJc3Aq+jGHMJ9s5yuOiLcYM65Ok9rBQwrHjvRkTomtqJRrPpELATi8y6HP28AAWon7CX23+g939JSfi186+Ga8mEv7wjw00+dP9QPd/jtUcmwiv3UepOX+ci0sGQpmBpXcWyea0oBUATeuu8uXHD55LijwlCnaxfJnES2jRyPddS2kKDAYKcDtgLEar7X30SSo4cALxKbwwhXMmh32VTfaXJtx3elvQ13yUhtBIcfhzs+Gdmpxgvs93fkW8jo48D5mMpNCyUUB6lajRppNUFQiSDUcq/dWrnJVrzTHu03uzAy14=",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:VI0PR04MB11917.eurprd04.prod.outlook.com; PTR:;\n CAT:NONE;\n SFS:(13230040)(366016)(19092799006)(376014)(1800799024)(18002099003)(22082099003)(56012099003);\n DIR:OUT; SFP:1101;",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "\n w94le6s5+0M24LFTBtYp4VpRzyaNEGoZJV27TGpuDX8EOZgRaUudK05/mLtlZqpx71umk5fLUGBisTlvL0vJgnh6rIidv5t9LqscoIGe9vlWSlmYXoykD+CHFgVMHNAVYKUDrke98BUw6CX+D+fjBD7P/8hjnGOpDQjjlVSFajW95I9NgoESvrJGb8e4cei5Yx03ZnvUq8je3c/haQdD1qoiBvTKrzBLnCQxAqIwKSYFr5yFzBzusDeMQcaonGgHPoZGO3W9bmQhYNTj2NmkQZ4wzln+2Z1gfFRuzIvdnlCmR4NcsjQico4XMv7xthr/d0B1txc/mTVEamCogWWMinlep9VJe1I8l+9ubHuDhh9UanovkAM3Hp3VPDxiC7kLfepG/ir2kPOS04mNPckjqW/5+pJsMNCaKGyIRLr0IUtZP3hCVdDxClYvYJ/2Ckw4z4OeFnsqT5JNqdRmqmXDPmzsyEugJgvQ1p9CK7n/b1uRxxxihsSmeAH4/vPTqLSAl3/oRSsAlHsqkHOYBrJ6WV+f+Ono3/tvH0n6AFSXDoZSWmWTmqJx6r19u4v7+UBqiB0WW4jCQ2oKB7NFSXTfOCAbYfxtuXzjJmW0dM7Gb2P3EIAVjQgZ1G7jUujSz2uScWzxuQU8XhHnE1iaDxE0sPr7LeuxnW3hEaWkZLcoBR1CejUPZVMCy9Z31Lxx91i8MVHGzkAgsYKEeY5r3JaehwZWyQA2oTprf5LjU6libD/PxA0mUiFQThC2hvccE+N8iWY67AhvlVCMDLPvzpGFEGnGtqhszMNMev1uexSeWpKJ71O+EypjqaktSs65E9cR2kwgfBbxlAr4FNxUnGs5blhYQfiEywBWgifVj75xZC6/JV4O2rTULiUomeieO/Ec6DcjWHeoX5fuyOGV+PKGyH3YnGdNaV9y02I8O4ljIaJ9ENvDKmyPsKyhG5jlsihSo0cdv7Fxkd5lRIzRt904vT/e0Pfd+nckv5L7AlBVqApEy4GzWxP+tH0bEZEnn9CW8S3VFtu2bIEP1YhQvdmjQGKsCyuOUSMZlAleuNUr7H438gJgAOflYM9p0fsA4YAGT92NSgQA6ld2sjKOC0TSUfPoWtrxs1BHAAF3Pue7Hs0C0P8c2x5MdtBR6uqg08toEEvwK2jI3ofDNYARnJMqGwVlm6oYVxMxQ351DLlHwYE/cwpL/xsm5WSobfCXTGqZ5D2O37297mI3dL1Y5fPyKBWeeZ8OBy3MSrVb2IauxVLm2Rhfy2fB2ElYEhXFFF+awGDvzZBBfHN6X9RB9+T2hfLwKT4Y59YVRN8kK2GV+aGdDWRA7lI1/T2kPq4pVv1BJ/9rpKnPkiMeRFgZWxBXVh0I2i0en9KfVBYWpLikDw86ZNz9R/CQ5tAtsPKl6+tgja/Hs14LlrGbLcFHNHi2ks1dMYNuviV12wX7TwYg9oRvqfLmFi3a84ZQLAsJmdSCt48CsYyXOEh9s2HYV3J3TAkbqj+wFyH2DFSbEsOdCEwsEsdh2bDEqalOm2Cfa37dGot58Kvky69lRnRzlbjG80xPXtuoMkurUvq8WwGxTA42shlCvMtmLcf7AvJiCs1GxVqmaUE6S/WycZkk7FPjgqSur7yQkFgEcjQo6nXyKCaJFAC+JTU2hfXwHhLSvQZna7lBrvCJFGwcNVdYK5eFNTOYPiPCQfLqQDRbqfVWtAWyXRJnwYOMnLMEE0Q/i3PhqbiBaRCaX0TfzPkhXgDewg==",
        "X-OriginatorOrg": "oss.nxp.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 1c71b885-b63d-4dbc-2732-08de909a5692",
        "X-MS-Exchange-CrossTenant-AuthSource": "VI0PR04MB11917.eurprd04.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "02 Apr 2026 09:29:28.8564 (UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "686ea1d3-bc2b-4c6f-a92c-d99c5c301635",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n lQkQ++/i/GrN0MzrdlaHk0CwE0QLyJaS5eOJBwf99UriAh93/9NhCQLnAln3YmhRQOZ7BZwYJo7PWUmmCGYBpQ==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AM7PR04MB7095",
        "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": "From: Simona Toaca <simona.toaca@nxp.com>\n\nDDR training data can be saved to NVM and be available\nto OEI at boot time, which will trigger QuickBoot flow.\n\nU-Boot only checks for data integrity (CRC32), while\nOEI is in charge of authentication when it tries to\nload the data from NVM.\n\nOn iMX95 A0/A1, 'authentication' is done via another\nCRC32. On the other boards, authentication is done by\nusing ELE to check the MAC stored in the ddrphy_qb_state\nstructure.\n\nSupported platforms: iMX94, iMX95, iMX952 (using OEI)\nSupported storage types: eMMC, SD, SPI flash.\n\nSigned-off-by: Viorel Suman <viorel.suman@nxp.com>\nSigned-off-by: Ye Li <ye.li@nxp.com>\nSigned-off-by: Simona Toaca <simona.toaca@nxp.com>\n---\n arch/arm/include/asm/arch-imx9/ddr.h |  48 +++-\n arch/arm/include/asm/mach-imx/qb.h   |  15 ++\n arch/arm/mach-imx/imx9/Makefile      |   6 +-\n arch/arm/mach-imx/imx9/qb.c          | 379 +++++++++++++++++++++++++++\n arch/arm/mach-imx/imx9/scmi/soc.c    |   7 +\n drivers/ddr/imx/imx9/Kconfig         |   7 +\n 6 files changed, 459 insertions(+), 3 deletions(-)\n create mode 100644 arch/arm/include/asm/mach-imx/qb.h\n create mode 100644 arch/arm/mach-imx/imx9/qb.c",
    "diff": "diff --git a/arch/arm/include/asm/arch-imx9/ddr.h b/arch/arm/include/asm/arch-imx9/ddr.h\nindex a8e3f7354c7..290e3e4e06e 100644\n--- a/arch/arm/include/asm/arch-imx9/ddr.h\n+++ b/arch/arm/include/asm/arch-imx9/ddr.h\n@@ -1,6 +1,6 @@\n /* SPDX-License-Identifier: GPL-2.0+ */\n /*\n- * Copyright 2022 NXP\n+ * Copyright 2022-2026 NXP\n  */\n \n #ifndef __ASM_ARCH_IMX8M_DDR_H\n@@ -100,6 +100,52 @@ struct dram_timing_info {\n \n extern struct dram_timing_info dram_timing;\n \n+/* Quick Boot related */\n+#define DDRPHY_QB_CSR_SIZE\t5168\n+#define DDRPHY_QB_ACSM_SIZE\t(4 * 1024)\n+#define DDRPHY_QB_MSB_SIZE\t0x200\n+#define DDRPHY_QB_PSTATES\t0\n+#define DDRPHY_QB_PST_SIZE\t(DDRPHY_QB_PSTATES * 4 * 1024)\n+\n+/**\n+ * This structure needs to be aligned with the one in OEI.\n+ */\n+struct ddrphy_qb_state {\n+\tu32 crc;\t\t  /* Used for ensuring integrity in DRAM */\n+#define MAC_LENGTH              8 /* 256 bits, 32-bit aligned */\n+\tu32 mac[MAC_LENGTH];\t  /* For 95A0/1 use mac[0] to keep CRC32 value */\n+\tu8 trained_vrefca_a0;\n+\tu8 trained_vrefca_a1;\n+\tu8 trained_vrefca_b0;\n+\tu8 trained_vrefca_b1;\n+\tu8 trained_vrefdq_a0;\n+\tu8 trained_vrefdq_a1;\n+\tu8 trained_vrefdq_b0;\n+\tu8 trained_vrefdq_b1;\n+\tu8 trained_vrefdqu_a0;\n+\tu8 trained_vrefdqu_a1;\n+\tu8 trained_vrefdqu_b0;\n+\tu8 trained_vrefdqu_b1;\n+\tu8 trained_dramdfe_a0;\n+\tu8 trained_dramdfe_a1;\n+\tu8 trained_dramdfe_b0;\n+\tu8 trained_dramdfe_b1;\n+\tu8 trained_dramdca_a0;\n+\tu8 trained_dramdca_a1;\n+\tu8 trained_dramdca_b0;\n+\tu8 trained_dramdca_b1;\n+\tu16 qb_pll_upll_prog0;\n+\tu16 qb_pll_upll_prog1;\n+\tu16 qb_pll_upll_prog2;\n+\tu16 qb_pll_upll_prog3;\n+\tu16 qb_pll_ctrl1;\n+\tu16 qb_pll_ctrl4;\n+\tu16 qb_pll_ctrl5;\n+\tu16 csr[DDRPHY_QB_CSR_SIZE];\n+\tu16 acsm[DDRPHY_QB_ACSM_SIZE];\n+\tu16 pst[DDRPHY_QB_PST_SIZE];\n+};\n+\n void ddr_load_train_firmware(enum fw_type type);\n int ddr_init(struct dram_timing_info *timing_info);\n int ddr_cfg_phy(struct dram_timing_info *timing_info);\ndiff --git a/arch/arm/include/asm/mach-imx/qb.h b/arch/arm/include/asm/mach-imx/qb.h\nnew file mode 100644\nindex 00000000000..aeec26718cb\n--- /dev/null\n+++ b/arch/arm/include/asm/mach-imx/qb.h\n@@ -0,0 +1,15 @@\n+/* SPDX-License-Identifier: GPL-2.0+ */\n+/*\n+ * Copyright 2026 NXP\n+ */\n+\n+#ifndef __IMX_QB_H__\n+#define __IMX_QB_H__\n+\n+#include <stdbool.h>\n+\n+bool qb_check(void);\n+int qb(int qb_dev, bool save);\n+void spl_qb_save(void);\n+\n+#endif\ndiff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile\nindex 53cc97c6b47..d2e44f0d5f9 100644\n--- a/arch/arm/mach-imx/imx9/Makefile\n+++ b/arch/arm/mach-imx/imx9/Makefile\n@@ -1,6 +1,6 @@\n # SPDX-License-Identifier: GPL-2.0+\n #\n-# Copyright 2022 NXP\n+# Copyright 2022,2026 NXP\n \n obj-y += lowlevel_init.o\n \n@@ -12,4 +12,6 @@ endif\n \n ifneq ($(CONFIG_SPL_BUILD),y)\n obj-y += imx_bootaux.o\n-endif\n\\ No newline at end of file\n+endif\n+\n+obj-y += qb.o\ndiff --git a/arch/arm/mach-imx/imx9/qb.c b/arch/arm/mach-imx/imx9/qb.c\nnew file mode 100644\nindex 00000000000..220545192d4\n--- /dev/null\n+++ b/arch/arm/mach-imx/imx9/qb.c\n@@ -0,0 +1,379 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/**\n+ * Copyright 2024-2026 NXP\n+ */\n+#include <dm/device-internal.h>\n+#include <dm/uclass.h>\n+#include <errno.h>\n+#include <imx_container.h>\n+#include <linux/bitfield.h>\n+#include <mmc.h>\n+#include <spi_flash.h>\n+#include <spl.h>\n+#include <stdlib.h>\n+#include <u-boot/crc.h>\n+\n+#include <asm/arch/ddr.h>\n+#include <asm/mach-imx/boot_mode.h>\n+#include <asm/mach-imx/sys_proto.h>\n+\n+#define QB_STATE_LOAD_SIZE    SZ_64K\n+\n+#define MMC_DEV\t\t0\n+#define QSPI_DEV\t1\n+\n+#define IMG_FLAGS_IMG_TYPE_MASK   0xF\n+#define IMG_FLAGS_IMG_TYPE(x)     FIELD_GET(IMG_FLAGS_IMG_TYPE_MASK, (x))\n+\n+#define IMG_TYPE_DDR_TDATA_DUMMY  0xD   /* dummy DDR training data image */\n+\n+bool qb_check(void)\n+{\n+\tstruct ddrphy_qb_state *qb_state;\n+\tu32 size, crc;\n+\n+\t/**\n+\t * Ensure CRC is not empty, the reason is that\n+\t * the data is invalidated after first save run\n+\t * or after it is overwritten.\n+\t */\n+\tqb_state = (struct ddrphy_qb_state *)CONFIG_QB_SAVED_STATE_BASE;\n+\tsize = sizeof(struct ddrphy_qb_state) - sizeof(qb_state->crc);\n+\tcrc = crc32(0, (u8 *)qb_state->mac, size);\n+\n+\tif (!qb_state->crc || crc != qb_state->crc)\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n+static unsigned long qb_get_boot_device_offset(void *dev, int dev_type)\n+{\n+\tunsigned long offset = 0;\n+\tstruct mmc *mmc;\n+\n+\tswitch (dev_type) {\n+\tcase MMC_DEV:\n+\t\tmmc = dev;\n+\n+\t\tif (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) {\n+\t\t\toffset = CONTAINER_HDR_MMCSD_OFFSET;\n+\t\t} else {\n+\t\t\tu8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);\n+\n+\t\t\tif (part == EMMC_BOOT_PART_BOOT1 || part == EMMC_BOOT_PART_BOOT2)\n+\t\t\t\toffset = CONTAINER_HDR_EMMC_OFFSET;\n+\t\t\telse\n+\t\t\t\toffset = CONTAINER_HDR_MMCSD_OFFSET;\n+\t\t}\n+\t\tbreak;\n+\tcase QSPI_DEV:\n+\t\toffset = CONTAINER_HDR_QSPI_OFFSET;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\treturn offset;\n+}\n+\n+static int qb_parse_container(void *addr, u32 *qb_data_off)\n+{\n+\tstruct container_hdr *phdr;\n+\tstruct boot_img_t *img_entry;\n+\tint i = 0;\n+\tu32 img_type, img_end;\n+\n+\tphdr = addr;\n+\tif (phdr->tag != 0x87 || (phdr->version != 0x0 && phdr->version != 0x2))\n+\t\treturn -EINVAL;\n+\n+\timg_entry = addr + sizeof(struct container_hdr);\n+\tfor (i = 0; i < phdr->num_images; i++) {\n+\t\timg_type = IMG_FLAGS_IMG_TYPE(img_entry->hab_flags);\n+\t\tif (img_type == IMG_TYPE_DDR_TDATA_DUMMY && img_entry->size == 0) {\n+\t\t\t/* Image entry pointing to DDR Training Data */\n+\t\t\t*qb_data_off = img_entry->offset;\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\timg_end = img_entry->offset + img_entry->size;\n+\t\tif (i + 1 < phdr->num_images) {\n+\t\t\timg_entry++;\n+\t\t\tif (img_end + QB_STATE_LOAD_SIZE == img_entry->offset) {\n+\t\t\t\t/* hole detected */\n+\t\t\t\t*qb_data_off = img_end;\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+static int get_dev_qbdata_offset(void *dev, int dev_type, unsigned long offset,\n+\t\t\t\t u32 *qbdata_offset)\n+{\n+\tint ret = -EOPNOTSUPP;\n+\tu16 ctnr_hdr_align = CONTAINER_HDR_ALIGNMENT;\n+\tvoid *buf = kmalloc(ctnr_hdr_align, GFP_KERNEL);\n+\n+\tif (!buf) {\n+\t\tprintf(\"kmalloc buffer failed\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tswitch (dev_type) {\n+\tcase MMC_DEV:\n+\t\tunsigned long count = 0;\n+\t\tstruct mmc *mmc = dev;\n+\n+\t\tif (!(CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE)))\n+\t\t\tgoto get_dev_qbdata_offset_exit;\n+\n+\t\tcount = blk_dread(mmc_get_blk_desc(mmc),\n+\t\t\t\t  offset / mmc->read_bl_len,\n+\t\t\t\t  ctnr_hdr_align / mmc->read_bl_len,\n+\t\t\t\t  buf);\n+\t\tif (count == 0) {\n+\t\t\tprintf(\"Read container image from MMC/SD failed\\n\");\n+\t\t\tret = -EIO;\n+\t\t\tgoto get_dev_qbdata_offset_exit;\n+\t\t}\n+\t\tbreak;\n+\tcase QSPI_DEV:\n+\t\tif (!CONFIG_IS_ENABLED(SPI))\n+\t\t\tgoto get_dev_qbdata_offset_exit;\n+\n+\t\tret = spi_flash_read(dev, offset,\n+\t\t\t\t     ctnr_hdr_align, buf);\n+\t\tif (ret) {\n+\t\t\tprintf(\"Read container header from QSPI failed\\n\");\n+\t\t\tret = -EIO;\n+\t\t\tgoto get_dev_qbdata_offset_exit;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tprintf(\"Support for device %d not enabled\\n\", dev_type);\n+\t\tgoto get_dev_qbdata_offset_exit;\n+\t}\n+\n+\tret = qb_parse_container(buf, qbdata_offset);\n+\n+get_dev_qbdata_offset_exit:\n+\tfree(buf);\n+\n+\treturn ret;\n+}\n+\n+static int get_qbdata_offset(void *dev, int dev_type, u32 *qbdata_offset)\n+{\n+\tu32 offset = qb_get_boot_device_offset(dev, dev_type);\n+\tu16 ctnr_hdr_align = CONTAINER_HDR_ALIGNMENT;\n+\tu32 cont_offset;\n+\tint ret, i;\n+\n+\tfor (i = 0; i < 3; i++) {\n+\t\tcont_offset = offset + i * ctnr_hdr_align;\n+\t\tret = get_dev_qbdata_offset(dev, dev_type, cont_offset, qbdata_offset);\n+\t\tif (ret == 0) {\n+\t\t\t(*qbdata_offset) += cont_offset;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int qb_mmc_get_device_index(u32 dev)\n+{\n+\tswitch (dev) {\n+\tcase BOOT_DEVICE_MMC1:\n+\t\treturn 0;\n+\tcase BOOT_DEVICE_MMC2:\n+\tcase BOOT_DEVICE_MMC2_2:\n+\t\treturn 1;\n+\t}\n+\n+\treturn -ENODEV;\n+}\n+\n+static int qb_mmc_find_device(struct mmc **mmcp, int mmc_dev)\n+{\n+\tint ret;\n+\n+\tret = mmc_init_device(mmc_dev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t*mmcp = find_mmc_device(mmc_dev);\n+\n+\treturn *mmcp ? 0 : -ENODEV;\n+}\n+\n+static int qb_mmc(int dev, bool save)\n+{\n+\tstruct mmc *mmc;\n+\tint ret = 0, mmc_dev;\n+\tbool has_hw_part;\n+\tu8 orig_part, part;\n+\tu32 offset;\n+\tvoid *buf;\n+\n+\tif (!(CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE))) {\n+\t\tprintf(\"Please enable MMC and MMC_WRITE.\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tmmc_dev = qb_mmc_get_device_index(dev);\n+\tif (mmc_dev < 0)\n+\t\treturn mmc_dev;\n+\n+\tret = qb_mmc_find_device(&mmc, mmc_dev);\n+\tif (ret) {\n+\t\tprintf(\"MMC %d not found.\\n\", mmc_dev);\n+\t\treturn ret;\n+\t}\n+\n+\tret = mmc_init(mmc);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\thas_hw_part = !IS_SD(mmc) && mmc->part_config != MMCPART_NOAVAILABLE;\n+\n+\tif (has_hw_part) {\n+\t\torig_part = mmc_get_blk_desc(mmc)->hwpart;\n+\t\tpart = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);\n+\n+\t\t/* Select the partition */\n+\t\tret = mmc_switch_part(mmc, part);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\tret = get_qbdata_offset(mmc, MMC_DEV, &offset);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (save) {\n+\t\t/* QB data is stored in DDR -> can use it as buf */\n+\t\tbuf = (void *)CONFIG_QB_SAVED_STATE_BASE;\n+\t\tret = blk_dwrite(mmc_get_blk_desc(mmc),\n+\t\t\t\t offset / mmc->write_bl_len,\n+\t\t\t\t QB_STATE_LOAD_SIZE / mmc->write_bl_len,\n+\t\t\t\t (const void *)buf);\n+\t} else {\n+\t\t/* erase */\n+\t\tret = blk_derase(mmc_get_blk_desc(mmc),\n+\t\t\t\t offset / mmc->write_bl_len,\n+\t\t\t\t QB_STATE_LOAD_SIZE / mmc->write_bl_len);\n+\t}\n+\n+\tif (!ret)\n+\t\treturn -EIO;\n+\n+\tif (!has_hw_part)\n+\t\treturn 0;\n+\n+\t/* Return to original partition */\n+\treturn mmc_switch_part(mmc, orig_part);\n+}\n+\n+static int qb_spi_find_device(struct spi_flash **dev)\n+{\n+\tint ret;\n+\tstruct udevice *udev;\n+\n+\tret = uclass_first_device_err(UCLASS_SPI_FLASH, &udev);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t*dev = dev_get_uclass_priv(udev);\n+\n+\treturn *dev ? 0 : -ENODEV;\n+}\n+\n+static int qb_spi(int dev, bool save)\n+{\n+\tint ret = 0;\n+\tu32 offset;\n+\tvoid *buf;\n+\tstruct spi_flash *flash;\n+\n+\tif (!CONFIG_IS_ENABLED(SPI)) {\n+\t\tprintf(\"Please enable SPI.\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tret = qb_spi_find_device(&flash);\n+\tif (ret) {\n+\t\tprintf(\"SPI flash not found.\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tret = get_qbdata_offset(flash, QSPI_DEV, &offset);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = spi_flash_erase(flash, offset,\n+\t\t\t      QB_STATE_LOAD_SIZE);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!save)\n+\t\treturn 0;\n+\n+\t/* QB data is stored in DDR -> can use it as buf */\n+\tbuf = (void *)CONFIG_QB_SAVED_STATE_BASE;\n+\tret = spi_flash_write(flash, offset,\n+\t\t\t      QB_STATE_LOAD_SIZE, buf);\n+\n+\treturn ret;\n+}\n+\n+int qb(int qb_dev, bool save)\n+{\n+\tint ret = -EINVAL;\n+\n+\tif (save && !qb_check())\n+\t\treturn ret;\n+\n+\tswitch (qb_dev) {\n+\tcase BOOT_DEVICE_MMC1:\n+\tcase BOOT_DEVICE_MMC2:\n+\tcase BOOT_DEVICE_MMC2_2:\n+\t\tret = qb_mmc(qb_dev, save);\n+\t\tbreak;\n+\tcase BOOT_DEVICE_SPI:\n+\t\tret = qb_spi(qb_dev, save);\n+\t\tbreak;\n+\tdefault:\n+\t\tprintf(\"Unsupported quickboot device\\n\");\n+\t\tbreak;\n+\t}\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!save)\n+\t\treturn 0;\n+\n+\t/**\n+\t * invalidate qb_state mem so that at next boot\n+\t * the check function will fail and save won't happen\n+\t */\n+\tmemset((void *)CONFIG_QB_SAVED_STATE_BASE, 0, sizeof(struct ddrphy_qb_state));\n+\n+\treturn 0;\n+}\n+\n+void spl_qb_save(void)\n+{\n+\tint dev = spl_boot_device();\n+\n+\t/* Save QB data on current boot device */\n+\tif (qb(dev, true))\n+\t\tprintf(\"QB save failed\\n\");\n+}\ndiff --git a/arch/arm/mach-imx/imx9/scmi/soc.c b/arch/arm/mach-imx/imx9/scmi/soc.c\nindex fbee435786c..86570e763d7 100644\n--- a/arch/arm/mach-imx/imx9/scmi/soc.c\n+++ b/arch/arm/mach-imx/imx9/scmi/soc.c\n@@ -310,6 +310,13 @@ static struct mm_region imx9_mem_map[] = {\n \t\t.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |\n \t\t\t PTE_BLOCK_NON_SHARE |\n \t\t\t PTE_BLOCK_PXN | PTE_BLOCK_UXN\n+\t}, {\n+\t\t/* QB data */\n+\t\t.virt = CONFIG_QB_SAVED_STATE_BASE,\n+\t\t.phys = CONFIG_QB_SAVED_STATE_BASE,\n+\t\t.size = 0x200000UL,\t/* 2M */\n+\t\t.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |\n+\t\t\t PTE_BLOCK_OUTER_SHARE\n \t}, {\n \t\t/* empty entry to split table entry 5 if needed when TEEs are used */\n \t\t0,\ndiff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig\nindex 0a45340ffb6..de1f59bfaf5 100644\n--- a/drivers/ddr/imx/imx9/Kconfig\n+++ b/drivers/ddr/imx/imx9/Kconfig\n@@ -29,4 +29,11 @@ config SAVED_DRAM_TIMING_BASE\n \t  info into memory for low power use.\n \tdefault 0x2051C000\n \n+config QB_SAVED_STATE_BASE\n+\thex \"Define the base address for saved QuickBoot state\"\n+\tdefault 0x8fe00000\n+\thelp\n+\t  Once DRAM is trained, the resulted training info is\n+\t  saved into memory in order to be reachable from U-Boot.\n+\n endmenu\n",
    "prefixes": [
        "v3",
        "1/6"
    ]
}