Received: by 2002:a05:6358:3188:b0:123:57c1:9b43 with SMTP id q8csp4129885rwd; Tue, 23 May 2023 03:41:48 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4PU/itClhyQcLM1rpXFP6QU1Sa1me938861rxM6awoWCqPA/g9W2FwVAjA/chv8391J5nd X-Received: by 2002:a05:6a20:1587:b0:104:d82a:63c5 with SMTP id h7-20020a056a20158700b00104d82a63c5mr15151343pzj.53.1684838508499; Tue, 23 May 2023 03:41:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684838508; cv=none; d=google.com; s=arc-20160816; b=S5e2SNKk7s91l0x92e3x1G78RP/X5z2Q8r6KnLZe5oZ3t3osU8BnfMbFDU15OpIYXv 8irzPhgCfWdsgB20d/S1Rwiqfr5UFX35FVUhrEaJ4nVt3Jjct4r8Ru1QRzzPJhVO6G0/ q1RseYu5DH7aCe2k67AiSGh9J23xhIlU+bpcbaIqIdJ7QZ6XLJV72CvPHoGAQ0f4AhKP G3v86Ag8cjdBdJulbkgyDDm8qkXi75XvuL8QZFl2WmrWBcBTyeU1T0DC+KvONROl0vnl jSWRFsQdPMqrwciqyKMst75IEuiNwvehKo8/XvXpcJTvvWBBILfpkfZ+w2z0OEa5lnlj i2XQ== 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=YVSNlUFqOfOENIf/2FPJt1QNdXnjHRXeUW+g6HMwMHY=; b=h1SO/Ks+Wg2AuVbAxM8zuj+2VN6H9td7AIgsSATdBIuTFPyjlmMbAkZWKtezidzR1I rw8a6qrVMp8mCp/JAL8NDspJP2f03wofkiPnrw/Vh7g2l/v3Bfzvep1pHWDGSY2z2Qyo pR1gvg6owhCb/1x0AiO/tW3ABt1QsCU/axiEIjEx1YH0wfRBbP8HDEbJm8p6tFKU/DGa xRA8KZOktNErFdgSaLmEa5hhJ9EC0RtQD98C/vUrwMM1z7Z3zqm9KnEPXlxBpU8O3Ain CCLMUoDzToRu7fcdUx9HBnChWfu50mzgvvF7GrktVERe2+ySixrf5kuDod8pPl6lDPar XtIw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sberdevices.ru header.s=mail header.b="iBV/XXpw"; 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 u8-20020a637908000000b00535a6ef4139si5032413pgc.503.2023.05.23.03.41.35; Tue, 23 May 2023 03:41:48 -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="iBV/XXpw"; 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 S236546AbjEWKXO (ORCPT + 99 others); Tue, 23 May 2023 06:23:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52560 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236537AbjEWKXM (ORCPT ); Tue, 23 May 2023 06:23:12 -0400 Received: from mx.sberdevices.ru (mx.sberdevices.ru [45.89.227.171]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E938C119; Tue, 23 May 2023 03:23:06 -0700 (PDT) Received: from s-lin-edge02.sberdevices.ru (localhost [127.0.0.1]) by mx.sberdevices.ru (Postfix) with ESMTP id 5779F5FD39; Tue, 23 May 2023 13:23:05 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sberdevices.ru; s=mail; t=1684837385; bh=YVSNlUFqOfOENIf/2FPJt1QNdXnjHRXeUW+g6HMwMHY=; h=Message-ID:Date:MIME-Version:Subject:To:From:Content-Type; b=iBV/XXpwaO9FpIEk88A+AMBB+thI4vZgb+TDs1CwgYJUqs8zf/7dL5Nf1AExROIZG wraUd6STLJ6yjI5QAEe8ARueOCmOtUibNteaCopfKwXHeIVrJ5X6WwS224Mj+fXwjC nuz+D4OtEVK/3g7s/J85xf4Bjq/glDvgNW/KRrh/IrK/fAIDc+0wqBfzW4Ilyi9AKn 2pfBgE8A0eYEfmjR7XzkcjRzwLWfZ9uNHHB+V5g7qUyq+8uMais1I0BrLvkD40LXJK 2P3qxhjGI+g9jRv4nJ/bW9wrBjycR4Dp75PJ7bHtQvbXqCLZ5bbhj26xgNNQPxNski 2MFcBxH0ljzgg== Received: from S-MS-EXCH01.sberdevices.ru (S-MS-EXCH01.sberdevices.ru [172.16.1.4]) by mx.sberdevices.ru (Postfix) with ESMTP; Tue, 23 May 2023 13:23:03 +0300 (MSK) Message-ID: <0c929cb9-4de9-bc65-c81c-2f2d968df120@sberdevices.ru> Date: Tue, 23 May 2023 13:18:42 +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 CC: Richard Weinberger , Vignesh Raghavendra , Sumit Semwal , =?UTF-8?Q?Christian_K=c3=b6nig?= , , , , , , , , Mason Yang , Boris Brezillon , Jaime Liao , Jaime Liao References: <20230511152120.3297853-1-AVKrasnov@sberdevices.ru> <20230522161446.16d1f307@xps-13> From: Arseniy Krasnov In-Reply-To: <20230522161446.16d1f307@xps-13> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Originating-IP: [172.16.1.6] X-ClientProxiedBy: S-MS-EXCH01.sberdevices.ru (172.16.1.4) 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/23 05:11:00 #21371280 X-KSMG-AntiVirus-Status: Clean, skipped X-Spam-Status: No, score=-2.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,URIBL_BLOCKED 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 On 22.05.2023 17:14, Miquel Raynal wrote: > Hi Arseniy, > > avkrasnov@sberdevices.ru wrote on Mon, 15 May 2023 12:49:50 +0300: > >> Hello @Miquel! >> >> Sorry, but who could review this patch? :) IIUC this logic is very hw specific and we need >> someone who knows it well? I tested this patch on our devices (with already known Meson NAND >> controller). > > + Jaime, who might test > >> >> Thanks, Arseniy >> >> On 11.05.2023 21:21, Arseniy Krasnov wrote: >>> 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. */ > > Jaime, any idea? > That will be great, because i didn't found any doc about that Thanks >>>> + 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"); > > Let's avoid WARN() calls (none in this driver are relevant IMHO). Just a > dev_err() should be enough. Done in v4 > >>>> + 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; > > I would start by checking the model, then it's list of supported ops. > Done in v4 >>>> + >>>> + 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; >>>> } > > > Thanks, > Miquèl Thanks, Arseniy