Received: by 2002:a05:6358:9144:b0:117:f937:c515 with SMTP id r4csp9211479rwr; Thu, 11 May 2023 11:29:21 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4g4AZywrw+5NMdbs7QK/2mTByI/XZs3tqfM+10SEBppzaefX1LJZgkKCD/kivc+BY7so5G X-Received: by 2002:a05:6a20:7f8c:b0:103:8138:f27d with SMTP id d12-20020a056a207f8c00b001038138f27dmr5902765pzj.47.1683829760718; Thu, 11 May 2023 11:29:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683829760; cv=none; d=google.com; s=arc-20160816; b=qEFibAh/ihHaR+m8ROOJ/DeRmC0LsnPkmhhGN23IafbhlJWd1Mh4Wguif0Pad0uc7R g1nRvD5dnzf9fepuDyA4EWuZl3tAu5YMX9onP7b9vGuhUXlbOZpMYzDWgg9n70uX26Nu vUEFFbv6PLflJ1bfBpf5mH6evmY4nwRdhy3C1bw4sApqNKPlz2QeK63tfT9aJyL/eNGZ YBpcVdLuL5Bqovy/IM6ozCPXpWnicVuUB6EedBy2oCLO+Tyjg7YPsGpIYMyRonpZynse SEI5H0oTZ0+uSmW4hEBp2JN/v+lkrhH2XcuFvzMQRddVkTP9Oc8VveYN+Wr22LIRLIGB 44lQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:in-reply-to:from :references:cc:to:content-language:subject:user-agent:mime-version :date:message-id:dkim-signature; bh=5nTAfm/pvw11kHJn8DB2F1CXjcxkc985Z7SnZU2jNZw=; b=yqZKvoaAPfWz8FDXmTaDjgrWM4utfPaj7XefdVU+8iTmEa5tv3RbKW3LDi4K9DcYxH lUYaEztKiM4Ak+8qSwY90s6hL+in8Xqo6nmJ5RXV2xzDcJMLQTRtMTCXy3Qds3kAKaGZ O+GXSVEhbmRh99REpL9yOLA70GKOOnkFEg2Pxnr/jnJatykhErMi5TTO6KnxZDoeRzue ot7aAF47e9ToRuH0CvCAz9l4mXbXntr6iNU+jpdoHGCIqcytwX+KiI8d8zqbaPuTJJZ3 whsE9TK6BoRltQF09DjyKbqWV9AxB1KTtcvI4oU/kBIsBF2wQNSDaB3hrdmwlAabp64P PHYw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sberdevices.ru header.s=mail header.b=AgMOHm0+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=sberdevices.ru Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id u187-20020a6379c4000000b005034a5a0a58si7011470pgc.434.2023.05.11.11.29.08; Thu, 11 May 2023 11:29:20 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@sberdevices.ru header.s=mail header.b=AgMOHm0+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=sberdevices.ru Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238673AbjEKS02 (ORCPT + 99 others); Thu, 11 May 2023 14:26:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48876 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238411AbjEKS00 (ORCPT ); Thu, 11 May 2023 14:26:26 -0400 Received: from mx.sberdevices.ru (mx.sberdevices.ru [45.89.227.171]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D09BE10C6; Thu, 11 May 2023 11:26:22 -0700 (PDT) Received: from s-lin-edge02.sberdevices.ru (localhost [127.0.0.1]) by mx.sberdevices.ru (Postfix) with ESMTP id D310E5FD0C; Thu, 11 May 2023 21:26:20 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sberdevices.ru; s=mail; t=1683829580; bh=5nTAfm/pvw11kHJn8DB2F1CXjcxkc985Z7SnZU2jNZw=; h=Message-ID:Date:MIME-Version:Subject:To:From:Content-Type; b=AgMOHm0+2/cEkhAS9xFjJ3Watg2imQsL3Nimrvhnksp0qHif0wmln6Iavj/w451dv jJNEdbOuhpuDfNa1h+S4SjZEazN2+v+NFJ+AB+7+0xl8zyBEhant2cu0l7G0SMO1Pz vNK9qbrNjnn+oRsju0bDj8J2hOgubkP1FMvLzTcLJuwEjHEywCroEAJzEg3J9DXWSp v24jfo6DMf/y+vvEs+nl2mF89lgsaEMMSyAF8tEeczWIpU4bTDuec6vWoFCxsFCvV+ x3qIK3d163DzMdNrKTjKYSMegDJvg7NyXV7WlBnGXRqZwZgFgGcc1OK2fCpXDn26fd /AJM8X2VaQt7g== Received: from S-MS-EXCH01.sberdevices.ru (S-MS-EXCH01.sberdevices.ru [172.16.1.4]) by mx.sberdevices.ru (Postfix) with ESMTP; Thu, 11 May 2023 21:26:16 +0300 (MSK) Message-ID: Date: Thu, 11 May 2023 21:21:34 +0300 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.7.1 Subject: Re: [RESEND PATCH v3] mtd: rawnand: macronix: OTP access for MX30LFxG18AC Content-Language: en-US To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Sumit Semwal , =?UTF-8?Q?Christian_K=c3=b6nig?= CC: , , , , , , , Mason Yang , Boris Brezillon References: <20230511152120.3297853-1-AVKrasnov@sberdevices.ru> From: Arseniy Krasnov In-Reply-To: <20230511152120.3297853-1-AVKrasnov@sberdevices.ru> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit X-Originating-IP: [172.16.1.6] X-ClientProxiedBy: S-MS-EXCH02.sberdevices.ru (172.16.1.5) To S-MS-EXCH01.sberdevices.ru (172.16.1.4) X-KSMG-Rule-ID: 4 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Status: not scanned, disabled by settings X-KSMG-AntiSpam-Interceptor-Info: not scanned X-KSMG-AntiPhishing: not scanned, disabled by settings X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 1.1.2.30, bases: 2023/05/11 10:21:00 #21259776 X-KSMG-AntiVirus-Status: Clean, skipped X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,NICE_REPLY_A,SPF_HELO_NONE, SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Cc: Mason Yang and Boris Brezillon On 11.05.2023 18:21, Arseniy Krasnov wrote: > This adds support for OTP area access on MX30LFxG18AC chip series. > > Changelog: > v1 -> v2: > * Add slab.h include due to kernel test robot error. > v2 -> v3: > * Use 'uint64_t' as input argument for 'do_div()' instead > of 'unsigned long' due to kernel test robot error. > > Signed-off-by: Arseniy Krasnov > --- > drivers/mtd/nand/raw/nand_macronix.c | 213 +++++++++++++++++++++++++++ > 1 file changed, 213 insertions(+) > > diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c > index 1472f925f386..2301f990678e 100644 > --- a/drivers/mtd/nand/raw/nand_macronix.c > +++ b/drivers/mtd/nand/raw/nand_macronix.c > @@ -6,6 +6,7 @@ > * Author: Boris Brezillon > */ > > +#include > #include "linux/delay.h" > #include "internals.h" > > @@ -31,6 +32,20 @@ > > #define MXIC_CMD_POWER_DOWN 0xB9 > > +#define ONFI_FEATURE_ADDR_30LFXG18AC_OTP 0x90 > +#define MACRONIX_30LFXG18AC_OTP_START_PAGE 0 > +#define MACRONIX_30LFXG18AC_OTP_PAGES 30 > +#define MACRONIX_30LFXG18AC_OTP_PAGE_SIZE 2112 > +#define MACRONIX_30LFXG18AC_OTP_START_BYTE \ > + (MACRONIX_30LFXG18AC_OTP_START_PAGE * \ > + MACRONIX_30LFXG18AC_OTP_PAGE_SIZE) > +#define MACRONIX_30LFXG18AC_OTP_SIZE_BYTES \ > + (MACRONIX_30LFXG18AC_OTP_PAGES * \ > + MACRONIX_30LFXG18AC_OTP_PAGE_SIZE) > + > +#define MACRONIX_30LFXG18AC_OTP_EN BIT(0) > +#define MACRONIX_30LFXG18AC_OTP_LOCKED BIT(1) > + > struct nand_onfi_vendor_macronix { > u8 reserved; > u8 reliability_func; > @@ -316,6 +331,203 @@ static void macronix_nand_deep_power_down_support(struct nand_chip *chip) > chip->ops.resume = mxic_nand_resume; > } > > +static int macronix_30lfxg18ac_get_otp_info(struct mtd_info *mtd, size_t len, > + size_t *retlen, > + struct otp_info *buf) > +{ > + if (len < sizeof(*buf)) > + return -EINVAL; > + > + /* Don't know how to check that OTP is locked. */ > + buf->locked = 0; > + buf->start = MACRONIX_30LFXG18AC_OTP_START_BYTE; > + buf->length = MACRONIX_30LFXG18AC_OTP_SIZE_BYTES; > + > + *retlen = sizeof(*buf); > + > + return 0; > +} > + > +static int macronix_30lfxg18ac_otp_enable(struct nand_chip *nand) > +{ > + uint8_t feature_buf[ONFI_SUBFEATURE_PARAM_LEN] = { 0 }; > + > + feature_buf[0] = MACRONIX_30LFXG18AC_OTP_EN; > + return nand_set_features(nand, ONFI_FEATURE_ADDR_30LFXG18AC_OTP, > + feature_buf); > +} > + > +static int macronix_30lfxg18ac_otp_disable(struct nand_chip *nand) > +{ > + uint8_t feature_buf[ONFI_SUBFEATURE_PARAM_LEN] = { 0 }; > + > + return nand_set_features(nand, ONFI_FEATURE_ADDR_30LFXG18AC_OTP, > + feature_buf); > +} > + > +static int __macronix_30lfxg18ac_rw_otp(struct mtd_info *mtd, > + loff_t offs_in_flash, > + size_t len, size_t *retlen, > + u_char *buf, bool write) > +{ > + struct nand_chip *nand; > + size_t bytes_handled; > + off_t offs_in_page; > + uint64_t page; > + void *dma_buf; > + int ret; > + > + /* 'nand_prog/read_page_op()' may use 'buf' as DMA buffer, > + * so allocate properly aligned memory for it. This is > + * needed because cross page accesses may lead to unaligned > + * buffer address for DMA. > + */ > + dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); > + if (!dma_buf) > + return -ENOMEM; > + > + nand = mtd_to_nand(mtd); > + nand_select_target(nand, 0); > + > + ret = macronix_30lfxg18ac_otp_enable(nand); > + if (ret) > + goto out_otp; > + > + page = offs_in_flash; > + /* 'page' will be result of division. */ > + offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); > + bytes_handled = 0; > + > + while (bytes_handled < len && > + page < MACRONIX_30LFXG18AC_OTP_PAGES) { > + size_t bytes_to_handle; > + > + bytes_to_handle = min_t(size_t, len - bytes_handled, > + MACRONIX_30LFXG18AC_OTP_PAGE_SIZE - > + offs_in_page); > + > + if (write) { > + memcpy(dma_buf, &buf[bytes_handled], bytes_to_handle); > + ret = nand_prog_page_op(nand, page, offs_in_page, > + dma_buf, bytes_to_handle); > + } else { > + ret = nand_read_page_op(nand, page, offs_in_page, > + dma_buf, bytes_to_handle); > + if (!ret) > + memcpy(&buf[bytes_handled], dma_buf, > + bytes_to_handle); > + } > + if (ret) > + goto out_otp; > + > + bytes_handled += bytes_to_handle; > + offs_in_page = 0; > + page++; > + } > + > + *retlen = bytes_handled; > + > +out_otp: > + if (ret) > + dev_err(&mtd->dev, "failed to perform OTP IO: %i\n", ret); > + > + ret = macronix_30lfxg18ac_otp_disable(nand); > + WARN(ret, "failed to leave OTP mode after %s\n", > + write ? "write" : "read"); > + nand_deselect_target(nand); > + kfree(dma_buf); > + > + return ret; > +} > + > +static int macronix_30lfxg18ac_write_otp(struct mtd_info *mtd, loff_t to, > + size_t len, size_t *rlen, > + const u_char *buf) > +{ > + return __macronix_30lfxg18ac_rw_otp(mtd, to, len, rlen, (u_char *)buf, > + true); > +} > + > +static int macronix_30lfxg18ac_read_otp(struct mtd_info *mtd, loff_t from, > + size_t len, size_t *rlen, > + u_char *buf) > +{ > + return __macronix_30lfxg18ac_rw_otp(mtd, from, len, rlen, buf, false); > +} > + > +static int macronix_30lfxg18ac_lock_otp(struct mtd_info *mtd, loff_t from, > + size_t len) > +{ > + uint8_t feature_buf[ONFI_SUBFEATURE_PARAM_LEN] = { 0 }; > + struct nand_chip *nand; > + int ret; > + > + if (from != MACRONIX_30LFXG18AC_OTP_START_BYTE || > + len != MACRONIX_30LFXG18AC_OTP_SIZE_BYTES) > + return -EINVAL; > + > + dev_dbg(&mtd->dev, "locking OTP\n"); > + > + nand = mtd_to_nand(mtd); > + nand_select_target(nand, 0); > + > + feature_buf[0] = MACRONIX_30LFXG18AC_OTP_EN | > + MACRONIX_30LFXG18AC_OTP_LOCKED; > + ret = nand_set_features(nand, ONFI_FEATURE_ADDR_30LFXG18AC_OTP, > + feature_buf); > + if (ret) { > + dev_err(&mtd->dev, > + "failed to lock OTP (set features): %i\n", ret); > + nand_deselect_target(nand); > + return ret; > + } > + > + /* Do dummy page prog with zero address. */ > + feature_buf[0] = 0; > + ret = nand_prog_page_op(nand, 0, 0, feature_buf, 1); > + if (ret) > + dev_err(&mtd->dev, > + "failed to lock OTP (page prog): %i\n", ret); > + > + ret = macronix_30lfxg18ac_otp_disable(nand); > + WARN(ret, "failed to leave OTP mode after lock\n"); > + > + nand_deselect_target(nand); > + > + return ret; > +} > + > +static void macronix_nand_setup_otp(struct nand_chip *chip) > +{ > + static const char * const supported_otp_models[] = { > + "MX30LF1G18AC", > + "MX30LF2G18AC", > + "MX30LF4G18AC", > + }; > + struct mtd_info *mtd; > + > + if (!chip->parameters.supports_set_get_features) > + return; > + > + if (match_string(supported_otp_models, > + ARRAY_SIZE(supported_otp_models), > + chip->parameters.model) < 0) > + return; > + > + bitmap_set(chip->parameters.get_feature_list, > + ONFI_FEATURE_ADDR_30LFXG18AC_OTP, 1); > + bitmap_set(chip->parameters.set_feature_list, > + ONFI_FEATURE_ADDR_30LFXG18AC_OTP, 1); > + > + mtd = nand_to_mtd(chip); > + mtd->_get_fact_prot_info = macronix_30lfxg18ac_get_otp_info; > + mtd->_read_fact_prot_reg = macronix_30lfxg18ac_read_otp; > + mtd->_get_user_prot_info = macronix_30lfxg18ac_get_otp_info; > + mtd->_read_user_prot_reg = macronix_30lfxg18ac_read_otp; > + mtd->_write_user_prot_reg = macronix_30lfxg18ac_write_otp; > + mtd->_lock_user_prot_reg = macronix_30lfxg18ac_lock_otp; > +} > + > static int macronix_nand_init(struct nand_chip *chip) > { > if (nand_is_slc(chip)) > @@ -325,6 +537,7 @@ static int macronix_nand_init(struct nand_chip *chip) > macronix_nand_onfi_init(chip); > macronix_nand_block_protection_support(chip); > macronix_nand_deep_power_down_support(chip); > + macronix_nand_setup_otp(chip); > > return 0; > }