From nobody Sun Oct 5 14:30:47 2025 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B278E24677F; Mon, 4 Aug 2025 10:03:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.153.233 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754301794; cv=none; b=DR/1wfKvo4f7qvY0NEKJAAme6ZIUZaG/LbvxVdZkZMMWXKoo0UR9ZCcyXt921/EV2X1b4lkIaPP9wBE0PvTYpOnyap6yU3GZO4070LVrA4mMhqYtjFSLN+hrOF/hkn3Tqlxia4+8Xq3FIhl6L0y3ZMr6NCagD6LrLKLN86q1dVk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754301794; c=relaxed/simple; bh=GoN/D1fysbMjHLdBfvRUxq+AyYb+K0pTz06myBTGEEQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lsNU7Zo54neQkh9YF2AliQVjfeEE0agYeeP+iLCaBHHH3J6nae64hJyG85x0elIoTMS112SnPxjBWb7VZ00Okb8BjnJSSZ9y3+dW9CsJ1ARFxXVpzZJrS8kAlCg1TjV39A7J6W8A1RatXm9BhoRrvAJRUh3kaIA+xC2hC2BPy3A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=FXSVU6mF; arc=none smtp.client-ip=68.232.153.233 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="FXSVU6mF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1754301792; x=1785837792; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=GoN/D1fysbMjHLdBfvRUxq+AyYb+K0pTz06myBTGEEQ=; b=FXSVU6mFSxDxClNn/l5OQyJIuczlrZadCJrPBxC1f+XfDlvrG+p1A7hJ ZyrZZn3RDoQ8t7ROOAw/jHunsmnPZSzWP6cH3DvnA27MVlGAlUl/UBCkO qP2yjGgMJfcuXh8aizu1L8RCfP6OrKDTFf1CGCjg8bIlU+mnX4ZwUsuYA n3mWCdThlQWqo1YVzoeTVJVSXZ2ys3//KMbkjIvtrh8T/vXEeI1Oz6ESq UlcwFMwosu6yDt3YvzoDYSWFhyxUN30ePI/JERDTZW9ynXfo366nPoPFD 8W5Vz+2gjtuP7q52OdXwrrAA/589u/OMOHBRW+vkSnOszSgCLL9u0tBs7 w==; X-CSE-ConnectionGUID: Liqowa5KRuKZ85yXFKRAhg== X-CSE-MsgGUID: QJiDf9GrRGW3RZ2GGFZX4A== X-IronPort-AV: E=Sophos;i="6.17,258,1747724400"; d="scan'208";a="50182871" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 04 Aug 2025 03:03:11 -0700 Received: from chn-vm-ex02.mchp-main.com (10.10.85.144) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.44; Mon, 4 Aug 2025 03:02:41 -0700 Received: from che-ll-i67070.microchip.com (10.10.85.11) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server id 15.1.2507.44 via Frontend Transport; Mon, 4 Aug 2025 03:02:35 -0700 From: Varshini Rajendran To: , , , , , , , , , , , , , , , CC: Subject: [PATCH 02/15] nvmem: microchip-otpc: rework to access packets based on tag Date: Mon, 4 Aug 2025 15:32:06 +0530 Message-ID: <20250804100219.63325-3-varshini.rajendran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250804100219.63325-1-varshini.rajendran@microchip.com> References: <20250804100219.63325-1-varshini.rajendran@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rework the driver to change the packet access technique based on the TAG instead of the currently in use "id". Since there is no way of knowing the OTP memory mapping in advance or the changes it can go through with time, the id based approach is not reliable. Accessing the packets based on the associated tags is a fail-proof approach. This method is aided by adding a table of contents to store the payload information which makes it easier to traverse through the OTP memory and read the data of the intended packet. The stride of the nvmem device is adjusted to 1 to support the TAG being treated as an offset. The only reliable way to recognize a packet without being aware of the flashed contents of the OTP memory is the TAG of the packet. Signed-off-by: Varshini Rajendran --- drivers/nvmem/microchip-otpc.c | 130 +++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 29 deletions(-) diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c index df979e8549fd..e922c882af72 100644 --- a/drivers/nvmem/microchip-otpc.c +++ b/drivers/nvmem/microchip-otpc.c @@ -18,16 +18,27 @@ #define MCHP_OTPC_CR_READ BIT(6) #define MCHP_OTPC_MR (0x4) #define MCHP_OTPC_MR_ADDR GENMASK(31, 16) +#define MCHP_OTPC_MR_EMUL BIT(7) #define MCHP_OTPC_AR (0x8) #define MCHP_OTPC_SR (0xc) #define MCHP_OTPC_SR_READ BIT(6) #define MCHP_OTPC_HR (0x20) #define MCHP_OTPC_HR_SIZE GENMASK(15, 8) +#define MCHP_OTPC_HR_PACKET_TYPE GENMASK(2, 0) #define MCHP_OTPC_DR (0x24) =20 #define MCHP_OTPC_NAME "mchp-otpc" #define MCHP_OTPC_SIZE (11 * 1024) =20 +enum packet_type { + PACKET_TYPE_REGULAR =3D 1, + PACKET_TYPE_KEY =3D 2, + PACKET_TYPE_BOOT_CONFIG =3D 3, + PACKET_TYPE_SECURE_BOOT_CONFIG =3D 4, + PACKET_TYPE_HARDWARE_CONFIG =3D 5, + PACKET_TYPE_CUSTOM =3D 6, +}; + /** * struct mchp_otpc - OTPC private data structure * @base: base address @@ -42,6 +53,25 @@ struct mchp_otpc { u32 npackets; }; =20 +/** + * struct mchp_otpc_payload_info - OTP packet's payload information + * retrieved from the packet's header + * @id: driver assigned packet ID + * @packet_offset: offset address of the packet to be written in the + * register OTPC_MR.ADDR to access the packet + * @payload_length: length of the packet's payload + * @packet_type: type of the packet + * @packet_tag: TAG corresponding to the packet. Applicable for most + * of the regular packets + */ +struct mchp_otpc_payload_info { + u32 id; + u32 packet_offset; + u32 payload_length; + u32 packet_type; + u32 packet_tag; +}; + /** * struct mchp_otpc_packet - OTPC packet data structure * @list: list head @@ -50,20 +80,16 @@ struct mchp_otpc { */ struct mchp_otpc_packet { struct list_head list; - u32 id; - u32 offset; + struct mchp_otpc_payload_info payload_info; }; =20 -static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *o= tpc, - u32 id) +static struct mchp_otpc_packet *mchp_otpc_tag_to_packet(struct mchp_otpc *= otpc, + u32 tag) { struct mchp_otpc_packet *packet; =20 - if (id >=3D otpc->npackets) - return NULL; - list_for_each_entry(packet, &otpc->packets, list) { - if (packet->id =3D=3D id) + if (packet->payload_info.packet_tag =3D=3D tag) return packet; } =20 @@ -140,8 +166,27 @@ static int mchp_otpc_prepare_read(struct mchp_otpc *ot= pc, * offset returned by hardware. * * For this, the read function will return the first requested bytes in the - * packet. The user will have to be aware of the memory footprint before d= oing - * the read request. + * packet. The user won't have to be aware of the memory footprint before = doing + * the read request since it is abstracted and taken care by this driver. + * + * There is no way of knowing the Mapping of the OTP memory table in advan= ce. In + * this read function the offset requested is treated as the identifier st= ring + * i.e., Packet TAG, to acquire the payload with reliability. The packet T= ag + * is the only way to recognize a packet without being aware of the flashed + * OTP memory map table. + */ + +/** + * mchp_otpc_read() - Read the OTP packets and fill the buffer based on th= e TAG + * of the packet treated as the offset. + * @priv: Pointer to device structure. + * @off: offset of the OTP packet to be read. In this case, the TAG of the + * corresponding packet. + * @val: Pointer to data buffer + * @bytes: length of the buffer + * + * A value of zero will be returned on success, a negative errno will be + * returned in error cases. */ static int mchp_otpc_read(void *priv, unsigned int off, void *val, size_t bytes) @@ -154,30 +199,23 @@ static int mchp_otpc_read(void *priv, unsigned int of= f, void *val, int ret, payload_size; =20 /* - * We reach this point with off being multiple of stride =3D 4 to - * be able to cross the subsystem. Inside the driver we use continuous - * unsigned integer numbers for packet id, thus divide off by 4 - * before passing it to mchp_otpc_id_to_packet(). + * From this point the packet tag received as the offset has to be transl= ated + * into the actual packet. For this we traverse the table of contents sto= red + * in a list "packet" and look for the tag. */ - packet =3D mchp_otpc_id_to_packet(otpc, off / 4); + + packet =3D mchp_otpc_tag_to_packet(otpc, off); if (!packet) return -EINVAL; - offset =3D packet->offset; + offset =3D packet->payload_info.packet_offset; =20 - while (len < bytes) { + if (len < bytes) { ret =3D mchp_otpc_prepare_read(otpc, offset); if (ret) return ret; =20 - /* Read and save header content. */ - *buf++ =3D readl_relaxed(otpc->base + MCHP_OTPC_HR); - len +=3D sizeof(*buf); - offset++; - if (len >=3D bytes) - break; - /* Read and save payload content. */ - payload_size =3D FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1)); + payload_size =3D packet->payload_info.payload_length; writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR); do { *buf++ =3D readl_relaxed(otpc->base + MCHP_OTPC_DR); @@ -190,6 +228,20 @@ static int mchp_otpc_read(void *priv, unsigned int off= , void *val, return 0; } =20 +static int mchp_otpc_read_packet_tag(struct mchp_otpc *otpc, unsigned int = offset, unsigned int *val) +{ + int ret; + + ret =3D mchp_otpc_prepare_read(otpc, offset); + if (ret) + return ret; + + writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR); + *val =3D readl_relaxed(otpc->base + MCHP_OTPC_DR); + + return 0; +} + static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size) { struct mchp_otpc_packet *packet; @@ -213,8 +265,15 @@ static int mchp_otpc_init_packets_list(struct mchp_otp= c *otpc, u32 *size) if (!packet) return -ENOMEM; =20 - packet->id =3D id++; - packet->offset =3D word_pos; + packet->payload_info.id =3D id++; + packet->payload_info.packet_offset =3D word_pos; + packet->payload_info.payload_length =3D payload_size; + packet->payload_info.packet_type =3D FIELD_GET(MCHP_OTPC_HR_PACKET_TYPE,= word); + + if (packet->payload_info.packet_type =3D=3D PACKET_TYPE_REGULAR) + ret =3D mchp_otpc_read_packet_tag(otpc, packet->payload_info.packet_off= set, + &packet->payload_info.packet_tag); + INIT_LIST_HEAD(&packet->list); list_add_tail(&packet->list, &otpc->packets); =20 @@ -236,7 +295,7 @@ static struct nvmem_config mchp_nvmem_config =3D { .type =3D NVMEM_TYPE_OTP, .read_only =3D true, .word_size =3D 4, - .stride =3D 4, + .stride =3D 1, .reg_read =3D mchp_otpc_read, }; =20 @@ -244,8 +303,9 @@ static int mchp_otpc_probe(struct platform_device *pdev) { struct nvmem_device *nvmem; struct mchp_otpc *otpc; - u32 size; + u32 size, tmp; int ret; + bool emul_enable; =20 otpc =3D devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL); if (!otpc) @@ -256,10 +316,22 @@ static int mchp_otpc_probe(struct platform_device *pd= ev) return PTR_ERR(otpc->base); =20 otpc->dev =3D &pdev->dev; + + tmp =3D readl_relaxed(otpc->base + MCHP_OTPC_MR); + emul_enable =3D tmp & MCHP_OTPC_MR_EMUL; + if (emul_enable) + dev_info(otpc->dev, "Emulation mode enabled\n"); + ret =3D mchp_otpc_init_packets_list(otpc, &size); if (ret) return ret; =20 + if (size =3D=3D 0) { + dev_err(otpc->dev, "Cannot access OTP memory !\n"); + if (!emul_enable) + dev_err(otpc->dev, "Boot packet not configured & Emulation mode not ena= bled !\n"); + } + mchp_nvmem_config.dev =3D otpc->dev; mchp_nvmem_config.add_legacy_fixed_of_cells =3D true; mchp_nvmem_config.size =3D size; --=20 2.34.1