Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2196309/?format=api
{ "id": 2196309, "url": "http://patchwork.ozlabs.org/api/patches/2196309/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260213112717.1256823-3-aswin.murugan@oss.qualcomm.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": "<20260213112717.1256823-3-aswin.murugan@oss.qualcomm.com>", "list_archive_url": null, "date": "2026-02-13T11:27:13", "name": "[v2,2/6] misc: Add support for bit fields in NVMEM cells", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "2fdbb286b960e3edd51890f141ad4159d10b80de", "submitter": { "id": 90811, "url": "http://patchwork.ozlabs.org/api/people/90811/?format=api", "name": "Aswin Murugan", "email": "aswin.murugan@oss.qualcomm.com" }, "delegate": { "id": 151538, "url": "http://patchwork.ozlabs.org/api/users/151538/?format=api", "username": "kcxt", "first_name": "Casey", "last_name": "Connolly", "email": "casey.connolly@linaro.org" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260213112717.1256823-3-aswin.murugan@oss.qualcomm.com/mbox/", "series": [ { "id": 492084, "url": "http://patchwork.ozlabs.org/api/series/492084/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=492084", "date": "2026-02-13T11:27:11", "name": "qcom: Add NVMEM bitfield support and reboot‑mode integration", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/492084/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2196309/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2196309/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=qualcomm.com header.i=@qualcomm.com header.a=rsa-sha256\n header.s=qcppdkim1 header.b=GdnPLhg7;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n header.a=rsa-sha256 header.s=google header.b=M5DSjSj7;\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.qualcomm.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=qualcomm.com header.i=@qualcomm.com\n header.b=\"GdnPLhg7\";\n\tdkim=pass (2048-bit key;\n unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n header.b=\"M5DSjSj7\";\n\tdkim-atps=neutral", "phobos.denx.de; dmarc=none (p=none dis=none)\n header.from=oss.qualcomm.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=aswin.murugan@oss.qualcomm.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 4fC8zg083yz1xr1\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 13 Feb 2026 22:27:59 +1100 (AEDT)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 68A3D83CEE;\n\tFri, 13 Feb 2026 12:27:54 +0100 (CET)", "by phobos.denx.de (Postfix, from userid 109)\n id 5CA7483CBD; Fri, 13 Feb 2026 12:27:53 +0100 (CET)", "from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com\n [205.220.168.131])\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 8093E83CEE\n for <u-boot@lists.denx.de>; Fri, 13 Feb 2026 12:27:50 +0100 (CET)", "from pps.filterd (m0279864.ppops.net [127.0.0.1])\n by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n 61D4i0RE3951637\n for <u-boot@lists.denx.de>; Fri, 13 Feb 2026 11:27:48 GMT", "from mail-pj1-f69.google.com (mail-pj1-f69.google.com\n [209.85.216.69])\n by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4c9ps2tmqv-1\n (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT)\n for <u-boot@lists.denx.de>; Fri, 13 Feb 2026 11:27:48 +0000 (GMT)", "by mail-pj1-f69.google.com with SMTP id\n 98e67ed59e1d1-35301003062so3600672a91.2\n for <u-boot@lists.denx.de>; Fri, 13 Feb 2026 03:27:48 -0800 (PST)", "from hu-aswinm-blr.qualcomm.com\n (blr-bdr-fw-01_GlobalNAT_AllZones-Outside.qualcomm.com. [103.229.18.19])\n by smtp.gmail.com with ESMTPSA id\n 41be03b00d2f7-c6e1969f314sm7996939a12.8.2026.02.13.03.27.41\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 13 Feb 2026 03:27:46 -0800 (PST)" ], "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 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED,\n SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2", "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h=\n cc:content-transfer-encoding:date:from:in-reply-to:message-id\n :mime-version:references:subject:to; s=qcppdkim1; bh=4fdNZ/nnmDA\n qKBhzVNkMUmbM3aVDC7uqk4LwzdSB48Y=; b=GdnPLhg7MsmvS86hiAVbn0wdi0Y\n +xG/5lqpSepmjWTxaXyw19lR2d0Gg5JCKfdpSv8zZqfSclP+wfIOrbRHLil2ikYD\n em7n0j7gt+jmXH9w7Nr6YnrC3Ee8+d4t/uylQ3MqLLXUgWp8JNg9JqvxdDtv6SxE\n A15ViZGZ2ruOtQzYNvkRbiwEWAq6f3JSQFxRN/2coBwyA6aEdS0KBzUy0GFk4Gze\n yQuAkhSyBCCC9P+s66WUQvTgFLH50fB7A8n/xLhSGVwGcRt7GGszTY3dXskq6yy1\n fDkfT0L54fWIe6NUsZJCCVdoE1HQ1AD6VDUNHR6xz32k1Sfjtwu5MBG/EvQ==", "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=oss.qualcomm.com; s=google; t=1770982068; x=1771586868; darn=lists.denx.de;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=4fdNZ/nnmDAqKBhzVNkMUmbM3aVDC7uqk4LwzdSB48Y=;\n b=M5DSjSj7IzWiDymziNNjd4fnwhAMUdbLfKxXJiVrf79DPrY9kPkuXjPCmEFUq1bDao\n xr2biuj//TfNpVYokQ1mt7KP72JsBCgdCZ87/hsJiqKTeKRfwWMVkIrFjidRPFR0sr7Y\n CtpCSTl51fTk+fYsYBI7G6gJlJVO2tz2iqWlItXFq1aNFcxbp2JandIjgpeL85u/MUk6\n +L+2Dr1+jxbSl6ihald8Wi/e2zJrEJrdP45EdYaojxRzraDxmrRQ/MSktfZbCIvIQAdy\n Aa1eQXO+ZzcGWBD6E72StfFwUZufE+E9Oow7OlLJO1SRFKTIW0SeB9e4ARNLxbXPoBCB\n oEaA==" ], "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1770982068; x=1771586868;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=4fdNZ/nnmDAqKBhzVNkMUmbM3aVDC7uqk4LwzdSB48Y=;\n b=DlUJnvAVVyRp9xzMGm/k0QmbP1QG7Bzr1rqC+Cba9Kd/NEbN+HHZNtXZXSNNwsTN+/\n +aY+fgwa+VfyW3bPV8XMgERyM9OKrMDTTyOf706H+zjcOWZOgnsMZNEtvcqh0c5EI0nD\n lZdi6VfuMoIVwgL8C5m2kxO4qVAYewBZSQ+Sg3td3nGVqyCpjFqOWwBf5dG2ikG9tHrX\n L8CN08B5wSAf0c6XRNvRb6poPuScbqXhAKhd4/4CYu/NGIcnkyUo7l1G2Ag/C1lA9299\n lfdDVkSL5AqKJt/IJUMrOr/+nR/zeUZG4I1jliO4Bf2K1jwP7QlfS0/o0VkBXfLeq3I6\n xxbA==", "X-Gm-Message-State": "AOJu0Ywg0osdr0ViU3bNXr6KFnJ8mOpcU1v0mdm1C8GU1unviT+3yhVP\n LoyFwD3KF2xMZvJta+6JMIar3Vn8N9qUBofO8K9OH4lPhexwRHRvRrY07KdaP3TdVjc/voWLR3f\n y1LwaQyQXhxZtzmt9kNVoZmjDyvwIbjNCPSK+zcCG9hiz0jCp8NozAPI3WtAy5OiH", "X-Gm-Gg": "AZuq6aJS1cfI+vtosFd+TCbwv0KWMltadnZgYzPKUQrIPFxBDYR7Qf6TPYUn4+cON4R\n D8VE20HoPNwIXhA64KaRvMZgKejlCKoI6f37CAoM2ufPabi+S6bFuNqqikCDKVse4pB/MTX1Lb0\n z/VL12TpG4YZHCjhVrp+/jabQjmJ+pMNVuTOT29KXVDsmEjJDViKahVmS/oea8qxL8q0RbUQNsR\n 3GSjf1uaOBlkwAN0cEv8hlWoNXjWJ2M5rGXqbfrFB9K/Y0p9iXHvL3c7Sz+Xw+iZLjE1H08K8hr\n XOhOZO9CwgB7j72vu3UqQcclYmPxGKbzL23yHYBjBiTkW+cTFiuYm3XBFsanb9y3ScDMZgm9dsX\n m9l52EmZU7zWxY+v6g7TxIzAMbLm+HRURpfQqOYYGdbUoVF5FCan57t+Og5ngqwyqxFJ3UzAFuA\n fXQyRrx2j+u8X+CeJrOUPWnpQwYwll48ugUpq776n4", "X-Received": [ "by 2002:a05:6a20:3d0f:b0:38e:9acd:97aa with SMTP id\n adf61e73a8af0-3946c7869bdmr1435547637.28.1770982067618;\n Fri, 13 Feb 2026 03:27:47 -0800 (PST)", "by 2002:a05:6a20:3d0f:b0:38e:9acd:97aa with SMTP id\n adf61e73a8af0-3946c7869bdmr1435517637.28.1770982067079;\n Fri, 13 Feb 2026 03:27:47 -0800 (PST)" ], "From": "Aswin Murugan <aswin.murugan@oss.qualcomm.com>", "To": "u-boot@lists.denx.de, sumit.garg@kernel.org, casey.connolly@linaro.org,\n u-boot-qcom@groups.io", "Cc": "seanga2@gmail.com, trini@konsulko.com, marek.vasut+renesas@mailbox.org,\n neil.armstrong@linaro.org, peng.fan@nxp.com, quentin.schulz@cherry.de,\n n-francis@ti.com, xypron.glpk@gmx.de, h-vm@ti.com, justin@tidylabs.net,\n jamie.gibbons@microchip.com, ycliang@andestech.com, me@samcday.com,\n sughosh.ganu@arm.com, gchan9527@gmail.com, ilias.apalodimas@linaro.org,\n Aswin Murugan <aswin.murugan@oss.qualcomm.com>", "Subject": "[PATCH v2 2/6] misc: Add support for bit fields in NVMEM cells", "Date": "Fri, 13 Feb 2026 16:57:13 +0530", "Message-Id": "<20260213112717.1256823-3-aswin.murugan@oss.qualcomm.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20260213112717.1256823-1-aswin.murugan@oss.qualcomm.com>", "References": "<20260213112717.1256823-1-aswin.murugan@oss.qualcomm.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Proofpoint-ORIG-GUID": "y2U67xwVBKKBkQXEhM8AU9dv36AiADld", "X-Proofpoint-Spam-Details-Enc": "AW1haW4tMjYwMjEzMDA4NyBTYWx0ZWRfX84xIacRRvfdO\n z13lKwBPfO7oVgpaDw7ARjwrkcUz2efL3y2YcfoXBe5Rf4CGd39K8LS1GqptwoaKArYUlAcMdDv\n lY8+tijRfo0uB20K47Y/08rlKGdGl+bMQX0wXn8TL6Sp1GjmpqveTkCPCGGIj+/bD4oL5qDGIpz\n 9sMAIEdNx+VCkgL2J1SUogw457nBlsRQn7nPq9cMkpgthi3gGxVpJ340GZHriByGpuTAzI4EW/g\n 8JBpS8Pcb+E+kRFZwJvUR5IFALID1oaT3m5yzOkiGIfMzhn0uFjd2GXH4k/tjuApTcD1afFqkEt\n j3WYPor0U+8rfrVimZ5bUr5vRBhwHOP1dCx3RrclllFJgYhi9hO9wbtp+MFhCc5AEybJEsEgl1N\n GFezRZmbrpynvEqyceRRt3mb0+PCxMadctubgFxBbUqpEyOM8Se3dIRq8ASTNsJVKboCGBuKEGU\n DQGli+/FXZoGm9kwg/w==", "X-Authority-Analysis": "v=2.4 cv=LoOfC3dc c=1 sm=1 tr=0 ts=698f0ab4 cx=c_pps\n a=vVfyC5vLCtgYJKYeQD43oA==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17\n a=HzLeVaNsDn8A:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22\n a=Mpw57Om8IfrbqaoTuvik:22 a=GgsMoib0sEa3-_RKJdDe:22 a=VwQbUJbxAAAA:8\n a=EUspDBNiAAAA:8 a=g_Wre9PPLzhfHXV9akwA:9 a=rl5im9kqc5Lf4LNbBjHf:22", "X-Proofpoint-GUID": "y2U67xwVBKKBkQXEhM8AU9dv36AiADld", "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49\n definitions=2026-02-13_02,2026-02-12_03,2025-10-01_01", "X-Proofpoint-Spam-Details": "rule=outbound_notspam policy=outbound score=0\n lowpriorityscore=0 impostorscore=0 spamscore=0 phishscore=0 bulkscore=0\n malwarescore=0 adultscore=0 suspectscore=0 clxscore=1015 priorityscore=1501\n classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0\n reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2602130087", "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": "NVMEM cells currently only support byte-level access. Many hardware\nregisters pack multiple fields into single bytes, requiring bit-level\ngranularity. For example, Qualcomm PMIC PON registers store a 7-bit\nreboot reason field within a single byte, with bit 0 reserved for other\npurposes.\n\nAdd support for the optional 'bits' property in NVMEM cell device tree\nbindings. This property specifies <bit_offset num_bits> to define a bit\nfield within the cell's register space.\n\nImplement multi-byte bit field support by porting bit manipulation\nalgorithms from the Linux kernel driver [1]:\n\n1. nvmem_shift_read_buffer_in_place() - Extract bit fields from raw\n bytes by shifting and masking across byte boundaries. Handles fields\n that span multiple bytes.\n\n2. nvmem_cell_prepare_write_buffer() - Perform Read-Modify-Write to\n preserve bits outside the target field. Read current values, mask to\n preserve adjacent bits, and combine with new value.\n\nExample device tree usage:\n reboot-reason@48 {\n reg = <0x48 0x01>;\n bits = <0x01 0x07>; /* 7 bits starting at bit 1 */\n };\n\nThis reads bits [7:1] from the byte at offset 0x48, leaving bit 0\nuntouched during write operations.\n\nCells without the 'bits' property continue to work unchanged, ensuring\nbackward compatibility with existing device trees.\n\n[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/nvmem/core.c\n\nSigned-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>\n---\n drivers/misc/nvmem.c | 241 ++++++++++++++++++++++++++++++++++++++++---\n include/nvmem.h | 4 +\n 2 files changed, 231 insertions(+), 14 deletions(-)", "diff": "diff --git a/drivers/misc/nvmem.c b/drivers/misc/nvmem.c\nindex 33e80858565..6a75c326189 100644\n--- a/drivers/misc/nvmem.c\n+++ b/drivers/misc/nvmem.c\n@@ -12,52 +12,251 @@\n #include <dm/ofnode.h>\n #include <dm/read.h>\n #include <dm/uclass.h>\n+#include <linux/bitops.h>\n+#include <linux/kernel.h>\n+\n+/**\n+ * nvmem_shift_read_buffer_in_place() - Shift read buffer to extract bit field\n+ * @cell: NVMEM cell with bit field information\n+ * @buf: Buffer containing raw bytes read from NVMEM\n+ *\n+ * This function shifts and masks the buffer to extract only the bits specified\n+ * by cell->bit_offset and cell->nbits. It handles bit fields that span multiple\n+ * bytes by shifting bits across byte boundaries.\n+ *\n+ */\n+static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf)\n+{\n+\tu8 *prev_byte, *buf_ptr;\n+\tint i, extra, bit_offset = cell->bit_offset;\n+\tint bytes_needed;\n+\n+\tbytes_needed = DIV_ROUND_UP(cell->nbits + cell->bit_offset, BITS_PER_BYTE);\n+\n+\tprev_byte = buf_ptr = buf;\n+\tif (bit_offset) {\n+\t\t/* First byte: shift right by bit_offset */\n+\t\t*buf_ptr++ >>= bit_offset;\n+\n+\t\t/* Process remaining bytes, combining bits across boundaries */\n+\t\tfor (i = 1; i < bytes_needed; i++) {\n+\t\t\t/* Get bits from next byte and shift them towards MSB */\n+\t\t\t*prev_byte |= *buf_ptr << (BITS_PER_BYTE - bit_offset);\n+\n+\t\t\tprev_byte = buf_ptr;\n+\t\t\t*buf_ptr++ >>= bit_offset;\n+\t\t}\n+\t} else {\n+\t\t/* Point to the MSB */\n+\t\tprev_byte += bytes_needed - 1;\n+\t}\n+\n+\t/* Clear extra bytes if result fits in fewer bytes */\n+\textra = bytes_needed - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE);\n+\twhile (--extra >= 0)\n+\t\t*prev_byte-- = 0;\n+\n+\t/* Clear MSB bits if any leftover in the last byte */\n+\tif (cell->nbits % BITS_PER_BYTE)\n+\t\t*prev_byte &= GENMASK((cell->nbits % BITS_PER_BYTE) - 1, 0);\n+}\n+\n+/**\n+ * nvmem_cell_prepare_write_buffer() - Prepare buffer for writing bit field\n+ * @cell: NVMEM cell with bit field information\n+ * @buf: Buffer containing value to write\n+ * @size: Size of buf\n+ * @data: Output buffer with prepared data for writing\n+ *\n+ * This function performs Read-Modify-Write to preserve bits outside the\n+ * specified bit field. It reads current values, modifies only the target\n+ * bits, and prepares the complete bytes for writing back.\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,\n+\t\t\t\t\t const void *buf, size_t size,\n+\t\t\t\t\t u8 *data)\n+{\n+\tint i, rc, nbits, bit_offset = cell->bit_offset;\n+\tint bytes_needed;\n+\tu8 current_val, *prev_byte, *buf_ptr, prev_byte_val, prev_bits;\n+\n+\tnbits = cell->nbits;\n+\tbytes_needed = DIV_ROUND_UP(nbits + bit_offset, BITS_PER_BYTE);\n+\n+\tmemcpy(data, buf, size);\n+\tprev_byte = buf_ptr = data;\n+\n+\tif (bit_offset) {\n+\t\tprev_byte_val = *buf_ptr;\n+\t\t*buf_ptr <<= bit_offset;\n+\n+\t\t/* Setup the first byte with LSB bits from NVMEM */\n+\t\tswitch (cell->nvmem->driver->id) {\n+\t\tcase UCLASS_I2C_EEPROM:\n+\t\t\trc = i2c_eeprom_read(cell->nvmem, cell->offset, ¤t_val, 1);\n+\t\t\tbreak;\n+\t\tcase UCLASS_MISC:\n+\t\t\trc = misc_read(cell->nvmem, cell->offset, ¤t_val, 1);\n+\t\t\tif (rc < 0)\n+\t\t\t\treturn rc;\n+\t\t\tif (rc != 1)\n+\t\t\t\treturn -EIO;\n+\t\t\trc = 0;\n+\t\t\tbreak;\n+\t\tcase UCLASS_RTC:\n+\t\t\trc = dm_rtc_read(cell->nvmem, cell->offset, ¤t_val, 1);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -ENOSYS;\n+\t\t}\n+\n+\t\tif (rc)\n+\t\t\treturn rc;\n+\n+\t\t*buf_ptr++ |= GENMASK(bit_offset - 1, 0) & current_val;\n+\n+\t\t/* Setup rest of the bytes if any */\n+\t\tfor (i = 1; i < bytes_needed; i++) {\n+\t\t\t/* Get last byte bits and shift them towards LSB */\n+\t\t\tprev_bits = prev_byte_val >> (BITS_PER_BYTE - 1 - bit_offset);\n+\t\t\tprev_byte_val = *buf_ptr;\n+\t\t\tprev_byte = buf_ptr;\n+\t\t\t*buf_ptr <<= bit_offset;\n+\t\t\t*buf_ptr++ |= prev_bits;\n+\t\t}\n+\t}\n+\n+\t/* If it's not end on byte boundary */\n+\tif ((nbits + bit_offset) % BITS_PER_BYTE) {\n+\t\t/* Setup the last byte with MSB bits from NVMEM */\n+\t\tswitch (cell->nvmem->driver->id) {\n+\t\tcase UCLASS_I2C_EEPROM:\n+\t\t\trc = i2c_eeprom_read(cell->nvmem,\n+\t\t\t\t\t cell->offset + bytes_needed - 1,\n+\t\t\t\t\t ¤t_val, 1);\n+\t\t\tbreak;\n+\t\tcase UCLASS_MISC:\n+\t\t\trc = misc_read(cell->nvmem,\n+\t\t\t\t cell->offset + bytes_needed - 1,\n+\t\t\t\t ¤t_val, 1);\n+\t\t\tif (rc < 0)\n+\t\t\t\treturn rc;\n+\t\t\tif (rc != 1)\n+\t\t\t\treturn -EIO;\n+\t\t\trc = 0;\n+\t\t\tbreak;\n+\t\tcase UCLASS_RTC:\n+\t\t\trc = dm_rtc_read(cell->nvmem,\n+\t\t\t\t\t cell->offset + bytes_needed - 1,\n+\t\t\t\t\t ¤t_val, 1);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -ENOSYS;\n+\t\t}\n+\n+\t\tif (rc)\n+\t\t\treturn rc;\n+\n+\t\t*prev_byte |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & current_val;\n+\t}\n+\n+\treturn 0;\n+}\n \n int nvmem_cell_read(struct nvmem_cell *cell, void *buf, size_t size)\n {\n+\tu8 data[size];\n+\tint bytes_needed;\n+\tint ret;\n+\n \tdev_dbg(cell->nvmem, \"%s: off=%u size=%zu\\n\", __func__, cell->offset, size);\n+\n \tif (size != cell->size)\n \t\treturn -EINVAL;\n \n+\t/* Calculate how many bytes we need to read */\n+\tif (cell->nbits > 0) {\n+\t\tbytes_needed = DIV_ROUND_UP(cell->nbits + cell->bit_offset, BITS_PER_BYTE);\n+\t\tif (bytes_needed > sizeof(data))\n+\t\t\treturn -EINVAL;\n+\t} else {\n+\t\tbytes_needed = size;\n+\t}\n+\n \tswitch (cell->nvmem->driver->id) {\n \tcase UCLASS_I2C_EEPROM:\n-\t\treturn i2c_eeprom_read(cell->nvmem, cell->offset, buf, size);\n-\tcase UCLASS_MISC: {\n-\t\tint ret = misc_read(cell->nvmem, cell->offset, buf, size);\n-\n+\t\tret = i2c_eeprom_read(cell->nvmem, cell->offset, data, bytes_needed);\n+\t\tbreak;\n+\tcase UCLASS_MISC:\n+\t\tret = misc_read(cell->nvmem, cell->offset, data, bytes_needed);\n \t\tif (ret < 0)\n \t\t\treturn ret;\n-\t\tif (ret != size)\n+\t\tif (ret != bytes_needed)\n \t\t\treturn -EIO;\n-\t\treturn 0;\n-\t}\n+\t\tret = 0;\n+\t\tbreak;\n \tcase UCLASS_RTC:\n-\t\treturn dm_rtc_read(cell->nvmem, cell->offset, buf, size);\n+\t\tret = dm_rtc_read(cell->nvmem, cell->offset, data, bytes_needed);\n+\t\tbreak;\n \tdefault:\n \t\treturn -ENOSYS;\n \t}\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (cell->nbits > 0) {\n+\t\t/* Extract bit field from raw bytes */\n+\t\tnvmem_shift_read_buffer_in_place(cell, data);\n+\t\t/* Copy only the bytes containing the bit field result */\n+\t\tmemcpy(buf, data, DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE));\n+\t} else {\n+\t\tmemcpy(buf, data, size);\n+\t}\n+\n+\treturn 0;\n }\n \n int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, size_t size)\n {\n+\tu8 data[size];\n+\tint bytes_needed;\n+\tint ret;\n+\n \tdev_dbg(cell->nvmem, \"%s: off=%u size=%zu\\n\", __func__, cell->offset, size);\n+\n \tif (size != cell->size)\n \t\treturn -EINVAL;\n \n+\tif (cell->nbits > 0) {\n+\t\tbytes_needed = DIV_ROUND_UP(cell->nbits + cell->bit_offset, BITS_PER_BYTE);\n+\t\tif (bytes_needed > sizeof(data))\n+\t\t\treturn -EINVAL;\n+\n+\t\t/* Prepare write buffer with Read-Modify-Write */\n+\t\tret = nvmem_cell_prepare_write_buffer(cell, buf, size, data);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t} else {\n+\t\tbytes_needed = size;\n+\t\tmemcpy(data, buf, size);\n+\t}\n+\n \tswitch (cell->nvmem->driver->id) {\n \tcase UCLASS_I2C_EEPROM:\n-\t\treturn i2c_eeprom_write(cell->nvmem, cell->offset, buf, size);\n+\t\treturn i2c_eeprom_write(cell->nvmem, cell->offset, data, bytes_needed);\n \tcase UCLASS_MISC: {\n-\t\tint ret = misc_write(cell->nvmem, cell->offset, buf, size);\n-\n+\t\tret = misc_write(cell->nvmem, cell->offset, data, bytes_needed);\n \t\tif (ret < 0)\n \t\t\treturn ret;\n-\t\tif (ret != size)\n+\t\tif (ret != bytes_needed)\n \t\t\treturn -EIO;\n \t\treturn 0;\n \t}\n \tcase UCLASS_RTC:\n-\t\treturn dm_rtc_write(cell->nvmem, cell->offset, buf, size);\n+\t\treturn dm_rtc_write(cell->nvmem, cell->offset, data, bytes_needed);\n \tdefault:\n \t\treturn -ENOSYS;\n \t}\n@@ -121,13 +320,27 @@ int nvmem_cell_get_by_index(struct udevice *dev, int index,\n \n \toffset = ofnode_get_addr_size_index_notrans(args.node, 0, &size);\n \tif (offset == FDT_ADDR_T_NONE || size == FDT_SIZE_T_NONE) {\n-\t\tdev_dbg(cell->nvmem, \"missing address or size for %s\\n\",\n+\t\tdev_err(cell->nvmem, \"missing address or size for %s\\n\",\n \t\t\tofnode_get_name(args.node));\n \t\treturn -EINVAL;\n \t}\n \n \tcell->offset = offset;\n \tcell->size = size;\n+\n+\tret = ofnode_read_u32_index(args.node, \"bits\", 0, &cell->bit_offset);\n+\tif (ret) {\n+\t\tcell->bit_offset = 0;\n+\t\tcell->nbits = 0;\n+\t} else {\n+\t\tret = ofnode_read_u32_index(args.node, \"bits\", 1, &cell->nbits);\n+\t\tif (ret)\n+\t\t\treturn -EINVAL;\n+\n+\t\tif (cell->bit_offset + cell->nbits > cell->size * 8)\n+\t\t\treturn -EINVAL;\n+\t}\n+\n \treturn 0;\n }\n \ndiff --git a/include/nvmem.h b/include/nvmem.h\nindex e6a8a98828b..dd82122f16f 100644\n--- a/include/nvmem.h\n+++ b/include/nvmem.h\n@@ -26,11 +26,15 @@\n * @nvmem: The backing storage device\n * @offset: The offset of the cell from the start of @nvmem\n * @size: The size of the cell, in bytes\n+ * @bit_offset: Bit offset within the cell (0 for byte-level access)\n+ * @nbits: Number of bits to use (0 for byte-level access)\n */\n struct nvmem_cell {\n \tstruct udevice *nvmem;\n \tunsigned int offset;\n \tsize_t size;\n+\tunsigned int bit_offset;\n+\tunsigned int nbits;\n };\n \n struct udevice;\n", "prefixes": [ "v2", "2/6" ] }