From patchwork Wed May 15 12:41:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukas Funke X-Patchwork-Id: 1935583 X-Patchwork-Delegate: monstr@monstr.eu Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=weidmueller.onmicrosoft.com header.i=@weidmueller.onmicrosoft.com header.a=rsa-sha256 header.s=selector1-weidmueller-onmicrosoft-com header.b=NOfYLDFS; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VfXt16Jm0z1yfq for ; Wed, 15 May 2024 22:42:01 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 6320188307; Wed, 15 May 2024 14:41:43 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=weidmueller.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=weidmueller.onmicrosoft.com header.i=@weidmueller.onmicrosoft.com header.b="NOfYLDFS"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 19ED28826C; Wed, 15 May 2024 14:41:42 +0200 (CEST) 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, DKIM_VALID,FORGED_SPF_HELO,SPF_HELO_PASS,T_SPF_PERMERROR autolearn=no autolearn_force=no version=3.4.2 Received: from EUR04-VI1-obe.outbound.protection.outlook.com (mail-vi1eur04on20700.outbound.protection.outlook.com [IPv6:2a01:111:f403:2611::700]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 804C7882FE for ; Wed, 15 May 2024 14:41:39 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=weidmueller.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=Lukas.Funke-oss@weidmueller.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=QLejZWS05yM1Lql5byx4JLhHEWOtMU1DaynGk/SZK2F4TYECC3bLN/sbXdCPAeZkZuQjphYQIG8zKq1o/bX5xMdazs6yQaeXyr6+UGe+R6iPbtaZZK751n+xXofX4dTAgNtx6UiYR3CNEeQBr+9axBME2Y4+rlc4knK2cbG6XRC0XSmT9lbj0h95VBTKQzoiA6ZUTHV16kBzOqZMSLOJhqq8p7trAIRcZFeglubG7Nyto5LqKe0+STbF0R5tqnlSm7C/Qe8dWsFMFPKRIj/aUZWcnP5qqrMf1d151KL0XnsnB/6/qKPsMXRtmNLk/zMiqzyifGIspTOjSLVy3BuPbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; 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; bh=iydIl1uZsud8V92Ko0veGp3WkpOSxDo/CaRjcywzdVE=; b=Eal/g6yC43KrOMddsIAoWmA4ykjflLB6InzN5HengWLT972bO+8Npqq1Nys3x673X8b2XRKMKeTHI7iAGzRcUiLJ0OM7oaSb0TjqiO63bqJTa/4dvoVaI942FXZafQnnqlunp8+QIU1xe4kP4fuMPrLK5piuR7TiYE0y7Xjt/B2gTnc1Zjl2Bt9Se0bWyz0xqNvINYISKFbekgk4wXx/GVRpZixM/ETVsJohSlwU1s8SUPJralcCsGeHDVbh+Zl3iJnoBYZ3fw+C6X3aCbSb+A2ShDpy8t5UByJ3GaehjU8KSNYYQEvi77u2GIaN5CJLpsn4bqlrGOAxqdQdCUxg4A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=weidmueller.com; dmarc=pass action=none header.from=weidmueller.com; dkim=pass header.d=weidmueller.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=weidmueller.onmicrosoft.com; s=selector1-weidmueller-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=iydIl1uZsud8V92Ko0veGp3WkpOSxDo/CaRjcywzdVE=; b=NOfYLDFSWtUmMv9mV0oISsr51yJQUbch3tW3rOBxgirJ84Dwx2xPnC1G/Nf3kgLVNxwDNJq8KXYyIJKXYPSZN+Os/fkGmux2jF2Qaqz9wd+ylHbvYbwBJjCXKT34mWn6mtTn9y4Rg9xMdvtyM295dDL1fRdMP6mzPqHla9bgbR4= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=weidmueller.com; Received: from AS2PR08MB8431.eurprd08.prod.outlook.com (2603:10a6:20b:55a::18) by AS4PR08MB8118.eurprd08.prod.outlook.com (2603:10a6:20b:58a::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.27; Wed, 15 May 2024 12:41:37 +0000 Received: from AS2PR08MB8431.eurprd08.prod.outlook.com ([fe80::aeb:1738:d59a:cee6]) by AS2PR08MB8431.eurprd08.prod.outlook.com ([fe80::aeb:1738:d59a:cee6%7]) with mapi id 15.20.7544.052; Wed, 15 May 2024 12:41:37 +0000 From: lukas.funke-oss@weidmueller.com To: u-boot@lists.denx.de Cc: =?utf-8?q?Marek_Beh=C3=BAn?= , Michal Simek , Stefan Roese , Lukas Funke , Bin Meng , Caleb Connolly , Heinrich Schuchardt , Ilias Apalodimas , Jonas Karlman , Kever Yang , Peng Fan , Simon Glass , Tom Rini , Wan Yee Lau Subject: [PATCH v2 2/2] drivers: misc: Add driver to access ZynqMP efuses Date: Wed, 15 May 2024 14:41:25 +0200 Message-Id: <20240515124125.732487-3-lukas.funke-oss@weidmueller.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20240515124125.732487-1-lukas.funke-oss@weidmueller.com> References: <20240515124125.732487-1-lukas.funke-oss@weidmueller.com> X-ClientProxiedBy: FR3P281CA0103.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:a1::19) To AS2PR08MB8431.eurprd08.prod.outlook.com (2603:10a6:20b:55a::18) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AS2PR08MB8431:EE_|AS4PR08MB8118:EE_ X-MS-Office365-Filtering-Correlation-Id: 45702f20-c696-4b78-ded0-08dc74dc5c85 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230031|376005|366007|1800799015|7416005|52116005|38350700005; X-Microsoft-Antispam-Message-Info: =?utf-8?q?0hrG3rzFfJCeLNLgmB/tf4Ucp8E3xIj?= =?utf-8?q?xmHyZbO3N2hFrhcRV7vOtENR4V2n1bMlTKCo6dCCPAYhvYGkHT4w4Dc+mnNau1yFI?= =?utf-8?q?GiMdLOiouCUy0fKNSmpxsceiM6nulq6lHF1EpsDhainbx3c8hi7RiM7EagZXKFwHI?= =?utf-8?q?Fp8cjSXh4I6tqYpfRD6oOfu51HQuvrAp1h7Nguy3R+hNVv6Vsvs83/cuc/BLREB54?= =?utf-8?q?FmJVy3PZOFnDquZYip1lv8VWlAXI5q1v8NX8+2USve0nkVQmmkc6xn4Dvnkee/PuF?= =?utf-8?q?5VWESQJRf02HnMgjfQdR1siYN9VoOtD6WVgNNwWPoQTsPrxpbbu+5rAlbku/XiwWo?= =?utf-8?q?AJ2+c4qMbgIzIfm7Jrrsyq1MaWoBpYm59Rn7O9NfYwoPT70Oelo6mqHB+0Y5R6z2u?= =?utf-8?q?OD9KtoUVuKqke1nBVX2m2lDUZ72vDIBc8WjlKmKaddfznSj//3RIl87w5dSGjKrAu?= =?utf-8?q?6ajPi9qTwT/Q5+xG0h5iMinn2bZTW/Nj3bJq10u3hbD/NzcpaqyWEX+qUsfKLjq39?= =?utf-8?q?fBqqP5jUQI9kDD/vL5aFB86Z6NkqCCVqryptW5L9wCpbMLCwloW/qOqJ6eQqzGprt?= =?utf-8?q?jwiWa8z4dKIVie3UqrwWOU3fW4y4Y9lCzczy/BhYlcpS3NyjqL1Z2eeoODE8m+xMf?= =?utf-8?q?uRgUi/iajStXATNoqtRBmQK/+1a89kVkdfWo6zn8DBLLEFTVDlk5IkwuyIXzL3TZ+?= =?utf-8?q?1gV6VJl6ZjDEFEkCbPP9Iyiw8eCaiS3zEtp9hQ6dEOB20uSVGF5HGoqjEO694Hr+4?= =?utf-8?q?m3zg5HhsCH7GviD6YYpMMgxllrTKii+1Hkb4Pr8sICHRfd86X637UPQ1D3alYKPYe?= =?utf-8?q?OC2WZbbO6e4mD/W5TW4n4BhjXLuc/rmn/98eQ12a3j8+KsvOJY2SNZPanAv0Qekta?= =?utf-8?q?XnxqjTzCjqAoJqCB1d1ZohOEdqrDM0RFi1hRTfg116fulJKP7kWmixUW6yn6JhZYu?= =?utf-8?q?mNnB6PYChRps1tTqKJIQxyvzF+fTrhSZaOD9I+3hhBl+4TjC5C68gGvo/2R6l+Tfz?= =?utf-8?q?QnMBoZULjU8FEQ7wMdsnI5KppTATUAmR0vBTmvbqI9gIsufNXy3BXE7LAueku8w0z?= =?utf-8?q?VsLqoFHU30qBrTLW3ngPrASTYhQ+x9F8eUBPu097y1marm2RdpidC1aXDH2d2zwU4?= =?utf-8?q?kIspLYPhKOgiO+4gEU2sIudA/sIa3h7S2P2GBkPPmD1Y6+DjrL9cXx2k3gUVNJqt0?= =?utf-8?q?+JBBd6DGQrVM6E6bMiMLF7i+RnkJ+y7q6JxQ=3D=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:AS2PR08MB8431.eurprd08.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(376005)(366007)(1800799015)(7416005)(52116005)(38350700005); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?GJLDuy2Tdp5qKO4h3DkJOZu3DxQ3?= =?utf-8?q?ddMY/Piqn9ZdTlLha9Fu9O/aPuo3A7u4hfZj14YSlAFdKP9eou4LHzNRLIn4dlAFc?= =?utf-8?q?BC6IALm5kT3aqOknqpGs7NCXhYRx7/j6mgNvZqjpvFe5BBjI56LyVFTrLw4sutQz+?= =?utf-8?q?TLakNlPE1a4C46ErhJaBOh1h5dKvy8UFqJ92Fqjp3JKTsZDxdOFbtvpwDwIh2KFgL?= =?utf-8?q?U+Oo4YjueHi9nGL2HpnGclCj40nSMsqpjXnsSL40AcUbsd34EZpHeikWYyAEmwrfO?= =?utf-8?q?2VX1tSCNqQhvaYpK09bs3tk0FPAWk0Qgf+PfAuFV0OSexU4+2ewcgxpXzJGr8nEob?= =?utf-8?q?RFYFVjaTOTPSb3D+cOtzQgSt+zKU+gPcs4wJDDWwo2pgouc6Ae4wYXmRgoGJxRolc?= =?utf-8?q?Y4Bmjw6nXql3NJK024NsOq7RZdA/W6YTYmI/XWE6oJfO32O2maVfEwVeIXP77Ef3/?= =?utf-8?q?es4Qq2RA9wjLW98iAnhPkor1wFXLw2KT38EQcAphWLx/hK44Tyolpz4WSZZtKSfRU?= =?utf-8?q?z45JR4PKgsYasHgpRD2V+PYOU4slLCh1Q6TbuAZ57/EXydv/vwT3hbnnrPnOHaHAi?= =?utf-8?q?UaHI5bL1uhpKW9RRCB6Jwd/HRKICydS/mlJR8wikZ8Z3+5l32eUj37YjZGiEkKE9x?= =?utf-8?q?3gBxNs5wmIWJD4dlMU09wDDrBDj0Lh7bwf+bW4FgPVg2jvK1Hd2WQ4Oql4g7WlDRu?= =?utf-8?q?3w76DtdYte+d7YflMYKLsBWyvaZ0c4xbDpXe7TBg0AYo+tv5pV46H610QWjF0N28t?= =?utf-8?q?jAKPgMl7PmFpUrdVcxefdqsl1S6IV3/1RZX/9tK9ImKH4GiIsOxkt0vy+XDM1Ac2P?= =?utf-8?q?YhqZZ3tAkH8V3FIrYF2UCb+Q93EgYWYgnT448bVBe/sDYDuWazofoNDN7a48nLZN2?= =?utf-8?q?bLjYnmKJY5g33bVEdhkKe0FDZq/sTr+LVTlF4p+mfNZQ5RpMITaxU7tXWuDV6HCO8?= =?utf-8?q?3TaemAQJ0y7IeYceLSxdURPQOmeE+CXKlkF+rzqltBBHgkxxbpVgoA4SgIzTXNKdw?= =?utf-8?q?YsgaaQWgVEJ/NSNheInP53cug4dP4njn/5uqx+IQsjfZg2hKBmz50O7cmemSUVIUG?= =?utf-8?q?2Dmm1oeZrqEz8FWdY7p7hCcp0rDJtB4/HxsZKdGskSP8gTJusXkvsRjbLUwnlYC3h?= =?utf-8?q?A1tU5sit1lTRedZEvqp9fEOmaB7GBs9AQOqS2Y12VR+WNS/Xri9gFpKWmLxlCzvhg?= =?utf-8?q?5asfuBxfrbPfF7MWkO0FP9zLZ7H7NPk28PkiBdxEojkabVNVgkrih8Z1Cp86LyFd1?= =?utf-8?q?+6WAxqAGWUKZ9l6v2jhk1LtaRzERktD3yDWYFuVJ8HjfYS8iV+kzpUd4/w4bwlLPF?= =?utf-8?q?cRlK8Hq4cEnf9TXWgRkqAgHW3LmcE/mFn4yRBRK83LUATUHXLua7Bng+bP5ICT3CD?= =?utf-8?q?ZwXIzaQdwif7oSi5rUswy5r1YOfVP7+7myVckN59QbKKGaou4H1iS1ZYIaa58P7CT?= =?utf-8?q?RU2vIrPHYX697DzlVP9s0nM6CYYThPcwvai2Cll/tAYDH9qnktpKkuBlfgSyRmBmO?= =?utf-8?q?a+1C3Xa08kBrSH5TnXZnol1PN858haXUIw=3D=3D?= X-OriginatorOrg: weidmueller.com X-MS-Exchange-CrossTenant-Network-Message-Id: 45702f20-c696-4b78-ded0-08dc74dc5c85 X-MS-Exchange-CrossTenant-AuthSource: AS2PR08MB8431.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 May 2024 12:41:37.4955 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: e4289438-1c5f-4c95-a51a-ee553b8b18ec X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: epPqPTDKYzlpQhA1MOXRve035aJDv4VXUAAYXZRV2whgmZaDsCvmk8VxDBF6vBVHumy+zdHmhX+QTrrHR/D9EA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS4PR08MB8118 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean From: Lukas Funke Add driver to access ZynqMP efuses. This is a u-boot port of [1]. [1] https://lore.kernel.org/all/20240224114516.86365-8-srinivas.kandagatla@linaro.org/ Signed-off-by: Lukas Funke --- Changes in v2: - Drop vendor specific fuse cmd, use existing fuse cmd - Minor code refactoring (reverse x-mas tree) drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/zynqmp_efuse.c | 324 ++++++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 drivers/misc/zynqmp_efuse.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..c07f50c9a76 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -298,6 +298,14 @@ config FSL_SEC_MON Security Monitor can be transitioned on any security failures, like software violations or hardware security violations. +config ZYNQMP_EFUSE + bool "Enable ZynqMP eFUSE Driver" + depends on ZYNQMP_FIRMWARE + help + Enable access to Zynq UltraScale (ZynqMP) eFUSEs thought PMU firmware + interface. ZnyqMP has 256 eFUSEs where some of them are security related + and cannot be read back (i.e. AES key). + choice prompt "Security monitor interaction endianess" depends on FSL_SEC_MON diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..68ba5648eab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -92,3 +92,4 @@ obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o +obj-$(CONFIG_ZYNQMP_EFUSE) += zynqmp_efuse.o diff --git a/drivers/misc/zynqmp_efuse.c b/drivers/misc/zynqmp_efuse.c new file mode 100644 index 00000000000..98a39c1ebdd --- /dev/null +++ b/drivers/misc/zynqmp_efuse.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 - 2015 Xilinx, Inc. + * Michal Simek + * + * (C) Copyright 2024 Weidmueller Interface GmbH + * Lukas Funke + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SILICON_REVISION_MASK 0xF +#define P_USER_0_64_UPPER_MASK 0x5FFF0000 +#define P_USER_127_LOWER_4_BIT_MASK 0xF +#define WORD_INBYTES (4) +#define SOC_VER_SIZE (0x4) +#define SOC_VERSION_OFFSET (0x0) +#define EFUSE_START_OFFSET (0xC) +#define EFUSE_END_OFFSET (0xFC) +#define EFUSE_PUF_START_OFFSET (0x100) +#define EFUSE_PUF_MID_OFFSET (0x140) +#define EFUSE_PUF_END_OFFSET (0x17F) +#define EFUSE_NOT_ENABLED (29) +#define EFUSE_READ (0) +#define EFUSE_WRITE (1) + +/** + * struct efuse_map_entry - offset and length of zynqmp fuses + * @offset: offset of efuse to be read/write + * @length: length of efuse + */ +struct efuse_map_entry { + u32 offset; + u32 length; +}; + +struct efuse_map_entry zynqmp_efuse_table[] = { + {0x000, 0x04}, /* soc revision */ + {0x00c, 0x0c}, /* SoC DNA */ + {0x020, 0x04}, /* efuse-usr0 */ + {0x024, 0x04}, /* efuse-usr1 */ + {0x028, 0x04}, /* efuse-usr2 */ + {0x02c, 0x04}, /* efuse-usr3 */ + {0x030, 0x04}, /* efuse-usr4 */ + {0x034, 0x04}, /* efuse-usr5 */ + {0x038, 0x04}, /* efuse-usr6 */ + {0x03c, 0x04}, /* efuse-usr7 */ + {0x040, 0x04}, /* efuse-miscusr */ + {0x050, 0x04}, /* efuse-chash */ + {0x054, 0x04}, /* efuse-pufmisc */ + {0x058, 0x04}, /* efuse-sec */ + {0x05c, 0x04}, /* efuse-spkid */ + {0x060, 0x30}, /* efuse-aeskey */ + {0x0a0, 0x30}, /* ppk0-hash */ + {0x0d0, 0x30}, /* ppk1-hash */ + {0x100, 0x7f}, /* pufuser */ +}; + +/** + * struct xilinx_efuse - the basic structure + * @src: address of the buffer to store the data to be write/read + * @size: no of words to be read/write + * @offset: offset to be read/write` + * @flag: 0 - represents efuse read and 1- represents efuse write + * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write + * 1 - represents puf user fuse row number. + * + * this structure stores all the required details to + * read/write efuse memory. + */ +struct xilinx_efuse { + u64 src; + u32 size; + u32 offset; + u32 flag; + u32 pufuserfuse; +}; + +static int zynqmp_efuse_get_length(u32 offset, u32 *base_offset, u32 *len) +{ + struct efuse_map_entry *fuse; + int i; + + for (i = 0; i < ARRAY_SIZE(zynqmp_efuse_table); ++i) { + fuse = &zynqmp_efuse_table[i]; + if (offset >= fuse->offset && + offset < fuse->offset + fuse->length) { + *base_offset = fuse->offset; + *len = fuse->length; + return 0; + } + } + + return -ENOENT; +} + +static int zynqmp_efuse_access(struct udevice *dev, unsigned int offset, + void *val, size_t bytes, unsigned int flag, + unsigned int pufflag) +{ + size_t words = bytes / WORD_INBYTES; + struct xilinx_efuse *efuse; + ulong dma_addr, dma_buf; + int ret, value; + char *data; + + if (bytes % WORD_INBYTES != 0) { + dev_err(dev, "Bytes requested should be word aligned\n"); + return -EOPNOTSUPP; + } + + if (pufflag == 0 && offset % WORD_INBYTES) { + dev_err(dev, "Offset requested should be word aligned\n"); + return -EOPNOTSUPP; + } + + if (pufflag == 1 && flag == EFUSE_WRITE) { + memcpy(&value, val, bytes); + if ((offset == EFUSE_PUF_START_OFFSET || + offset == EFUSE_PUF_MID_OFFSET) && + value & P_USER_0_64_UPPER_MASK) { + dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n"); + return -EOPNOTSUPP; + } + + if (offset == EFUSE_PUF_END_OFFSET && + (value & P_USER_127_LOWER_4_BIT_MASK)) { + dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n"); + return -EOPNOTSUPP; + } + } + + efuse = dma_alloc_coherent(sizeof(struct xilinx_efuse), &dma_addr); + if (!efuse) + return -ENOMEM; + + data = dma_alloc_coherent(bytes, &dma_buf); + if (!data) { + dma_free_coherent(efuse); + return -ENOMEM; + } + + if (flag == EFUSE_WRITE) { + memcpy(data, val, bytes); + efuse->flag = EFUSE_WRITE; + } else { + efuse->flag = EFUSE_READ; + } + + efuse->src = dma_buf; + efuse->size = words; + efuse->offset = offset; + efuse->pufuserfuse = pufflag; + + flush_dcache_range((ulong)efuse, (ulong)efuse + + roundup(sizeof(struct xilinx_efuse), ARCH_DMA_MINALIGN)); + flush_dcache_range((ulong)data, (ulong)data + + roundup(sizeof(struct xilinx_efuse), ARCH_DMA_MINALIGN)); + + zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret); + if (ret != 0) { + if (ret == EFUSE_NOT_ENABLED) { + dev_err(dev, "efuse access is not enabled\n"); + ret = -EOPNOTSUPP; + goto END; + } + dev_err(dev, "Error in efuse read %x\n", ret); + ret = -EPERM; + goto END; + } + + if (flag == EFUSE_READ) + memcpy(val, data, bytes); +END: + + dma_free_coherent(efuse); + dma_free_coherent(data); + + return ret; +} + +static int zynqmp_nvmem_read(struct udevice *dev, int offset, + void *val, int bytes) +{ + int ret, pufflag = 0; + int idcode, version; + + if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET) + pufflag = 1; + + dev_dbg(dev, "reading from offset=0x%x, bytes=%d\n", offset, bytes); + + switch (offset) { + /* Soc version offset is zero */ + case SOC_VERSION_OFFSET: + if (bytes != SOC_VER_SIZE) + return -EOPNOTSUPP; + + ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version); + if (ret < 0) + return ret; + + *(int *)val = version & SILICON_REVISION_MASK; + break; + /* Efuse offset starts from 0xc */ + case EFUSE_START_OFFSET ... EFUSE_END_OFFSET: + case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET: + ret = zynqmp_efuse_access(dev, offset, val, + bytes, EFUSE_READ, pufflag); + break; + default: + *(u32 *)val = 0xDEADBEEF; + ret = 0; + break; + } + + return ret; +} + +static int zynqmp_nvmem_write(struct udevice *dev, int offset, const void *val, + int bytes) +{ + int pufflag = 0; + + dev_dbg(dev, "writing to offset=0x%x, bytes=%d", offset, bytes); + + if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET) + return -EOPNOTSUPP; + + if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET) + pufflag = 1; + + return zynqmp_efuse_access(dev, offset, + (void *)val, bytes, EFUSE_WRITE, pufflag); +} + +int fuse_read(u32 bank, u32 word, u32 *val) +{ + u32 base_offset, offset, len; + struct udevice *dev; + u8 buf[128]; + int ret; + + memset(buf, 0, sizeof(buf)); + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(zynqmp_efuse), &dev); + if (ret) + return log_msg_ret("uclass_drv", ret); + + ret = zynqmp_efuse_get_length(word, &base_offset, &len); + if (ret) + return log_msg_ret("efuse_offset", ret); + + ret = misc_read(dev, base_offset, (void *)buf, len); + if (ret) + return log_msg_ret("misc_read", ret); + + offset = word - base_offset; + *val = ((u32 *)buf)[offset]; + + return 0; +} + +int fuse_prog(u32 bank, u32 word, u32 val) +{ + u32 base_offset, len; + struct udevice *dev; + int ret; + + ret = zynqmp_efuse_get_length(word, &base_offset, &len); + if (ret) + return log_msg_ret("efuse_offset", ret); + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(zynqmp_efuse), &dev); + if (ret) + return log_msg_ret("uclass_drv", ret); + + if (word != base_offset || len != sizeof(val)) + return -EINVAL; + + ret = misc_write(dev, word, (void *)&val, sizeof(val)); + if (ret) + return log_msg_ret("misc_write", ret); + + return 0; +} + +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + /* We do not support sense */ + return -ENOSYS; +} + +int fuse_override(u32 bank, u32 word, u32 val) +{ + /* We do not support overriding */ + return -ENOSYS; +} + +static const struct udevice_id zynqmp_efuse_match[] = { + { .compatible = "xlnx,zynqmp-nvmem-fw", }, + { /* sentinel */ }, +}; + +static const struct misc_ops zynqmp_efuse_ops = { + .read = zynqmp_nvmem_read, + .write = zynqmp_nvmem_write, +}; + +U_BOOT_DRIVER(zynqmp_efuse) = { + .name = "zynqmp_efuse", + .id = UCLASS_MISC, + .of_match = zynqmp_efuse_match, + .ops = &zynqmp_efuse_ops, +};