Message ID | 20230426072455.3887717-1-AVKrasnov@sberdevices.ru (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v1] mtd: rawnand: macronix: OTP access for MX30LFxG18AC | expand |
Hi Arseniy, kernel test robot noticed the following build errors: [auto build test ERROR on mtd/nand/next] [also build test ERROR on linus/master v6.3 next-20230425] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Arseniy-Krasnov/mtd-rawnand-macronix-OTP-access-for-MX30LFxG18AC/20230426-153143 base: https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next patch link: https://lore.kernel.org/r/20230426072455.3887717-1-AVKrasnov%40sberdevices.ru patch subject: [PATCH v1] mtd: rawnand: macronix: OTP access for MX30LFxG18AC config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230426/202304261704.eyrD5KVk-lkp@intel.com/config) compiler: m68k-linux-gcc (GCC) 12.1.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/3529f3465e99379489b59c035a8a0506c3756ef4 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Arseniy-Krasnov/mtd-rawnand-macronix-OTP-access-for-MX30LFxG18AC/20230426-153143 git checkout 3529f3465e99379489b59c035a8a0506c3756ef4 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/mtd/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304261704.eyrD5KVk-lkp@intel.com/ All error/warnings (new ones prefixed by >>): drivers/mtd/nand/raw/nand_macronix.c: In function '__macronix_30lfxg18ac_rw_otp': >> drivers/mtd/nand/raw/nand_macronix.c:384:19: error: implicit declaration of function 'kmalloc'; did you mean 'mm_alloc'? [-Werror=implicit-function-declaration] 384 | dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); | ^~~~~~~ | mm_alloc >> drivers/mtd/nand/raw/nand_macronix.c:384:17: warning: assignment to 'void *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 384 | dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); | ^ >> drivers/mtd/nand/raw/nand_macronix.c:437:9: error: implicit declaration of function 'kfree'; did you mean 'kvfree'? [-Werror=implicit-function-declaration] 437 | kfree(dma_buf); | ^~~~~ | kvfree cc1: some warnings being treated as errors vim +384 drivers/mtd/nand/raw/nand_macronix.c 366 367 static int __macronix_30lfxg18ac_rw_otp(struct mtd_info *mtd, 368 loff_t offs_in_flash, 369 size_t len, size_t *retlen, 370 u_char *buf, bool write) 371 { 372 struct nand_chip *nand; 373 size_t bytes_handled; 374 unsigned long page; 375 off_t offs_in_page; 376 void *dma_buf; 377 int ret; 378 379 /* 'nand_prog/read_page_op()' may use 'buf' as DMA buffer, 380 * so allocate properly aligned memory for it. This is 381 * needed because cross page accesses may lead to unaligned 382 * buffer address for DMA. 383 */ > 384 dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); 385 if (!dma_buf) 386 return -ENOMEM; 387 388 nand = mtd_to_nand(mtd); 389 nand_select_target(nand, 0); 390 391 ret = macronix_30lfxg18ac_otp_enable(nand); 392 if (ret) 393 goto out_otp; 394 395 page = offs_in_flash; 396 /* 'page' will be result of division. */ 397 offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); 398 bytes_handled = 0; 399 400 while (bytes_handled < len && 401 page < MACRONIX_30LFXG18AC_OTP_PAGES) { 402 size_t bytes_to_handle; 403 404 bytes_to_handle = min_t(size_t, len - bytes_handled, 405 MACRONIX_30LFXG18AC_OTP_PAGE_SIZE - 406 offs_in_page); 407 408 if (write) { 409 memcpy(dma_buf, &buf[bytes_handled], bytes_to_handle); 410 ret = nand_prog_page_op(nand, page, offs_in_page, 411 dma_buf, bytes_to_handle); 412 } else { 413 ret = nand_read_page_op(nand, page, offs_in_page, 414 dma_buf, bytes_to_handle); 415 if (!ret) 416 memcpy(&buf[bytes_handled], dma_buf, 417 bytes_to_handle); 418 } 419 if (ret) 420 goto out_otp; 421 422 bytes_handled += bytes_to_handle; 423 offs_in_page = 0; 424 page++; 425 } 426 427 *retlen = bytes_handled; 428 429 out_otp: 430 if (ret) 431 dev_err(&mtd->dev, "failed to perform OTP IO: %i\n", ret); 432 433 ret = macronix_30lfxg18ac_otp_disable(nand); 434 WARN(ret, "failed to leave OTP mode after %s\n", 435 write ? "write" : "read"); 436 nand_deselect_target(nand); > 437 kfree(dma_buf); 438 439 return ret; 440 } 441
Hi Arseniy, kernel test robot noticed the following build errors: [auto build test ERROR on mtd/nand/next] [also build test ERROR on linus/master v6.3 next-20230425] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Arseniy-Krasnov/mtd-rawnand-macronix-OTP-access-for-MX30LFxG18AC/20230426-153143 base: https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next patch link: https://lore.kernel.org/r/20230426072455.3887717-1-AVKrasnov%40sberdevices.ru patch subject: [PATCH v1] mtd: rawnand: macronix: OTP access for MX30LFxG18AC config: i386-randconfig-a001-20230424 (https://download.01.org/0day-ci/archive/20230426/202304262003.Lzpyh2BA-lkp@intel.com/config) compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/3529f3465e99379489b59c035a8a0506c3756ef4 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Arseniy-Krasnov/mtd-rawnand-macronix-OTP-access-for-MX30LFxG18AC/20230426-153143 git checkout 3529f3465e99379489b59c035a8a0506c3756ef4 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/mtd/nand/raw/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304262003.Lzpyh2BA-lkp@intel.com/ All error/warnings (new ones prefixed by >>): >> drivers/mtd/nand/raw/nand_macronix.c:384:12: error: implicit declaration of function 'kmalloc' is invalid in C99 [-Werror,-Wimplicit-function-declaration] dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); ^ drivers/mtd/nand/raw/nand_macronix.c:384:12: note: did you mean 'mm_alloc'? include/linux/sched/mm.h:16:26: note: 'mm_alloc' declared here extern struct mm_struct *mm_alloc(void); ^ >> drivers/mtd/nand/raw/nand_macronix.c:384:10: warning: incompatible integer to pointer conversion assigning to 'void *' from 'int' [-Wint-conversion] dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/mtd/nand/raw/nand_macronix.c:437:2: error: implicit declaration of function 'kfree' is invalid in C99 [-Werror,-Wimplicit-function-declaration] kfree(dma_buf); ^ 1 warning and 2 errors generated. vim +/kmalloc +384 drivers/mtd/nand/raw/nand_macronix.c 366 367 static int __macronix_30lfxg18ac_rw_otp(struct mtd_info *mtd, 368 loff_t offs_in_flash, 369 size_t len, size_t *retlen, 370 u_char *buf, bool write) 371 { 372 struct nand_chip *nand; 373 size_t bytes_handled; 374 unsigned long page; 375 off_t offs_in_page; 376 void *dma_buf; 377 int ret; 378 379 /* 'nand_prog/read_page_op()' may use 'buf' as DMA buffer, 380 * so allocate properly aligned memory for it. This is 381 * needed because cross page accesses may lead to unaligned 382 * buffer address for DMA. 383 */ > 384 dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); 385 if (!dma_buf) 386 return -ENOMEM; 387 388 nand = mtd_to_nand(mtd); 389 nand_select_target(nand, 0); 390 391 ret = macronix_30lfxg18ac_otp_enable(nand); 392 if (ret) 393 goto out_otp; 394 395 page = offs_in_flash; 396 /* 'page' will be result of division. */ 397 offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); 398 bytes_handled = 0; 399 400 while (bytes_handled < len && 401 page < MACRONIX_30LFXG18AC_OTP_PAGES) { 402 size_t bytes_to_handle; 403 404 bytes_to_handle = min_t(size_t, len - bytes_handled, 405 MACRONIX_30LFXG18AC_OTP_PAGE_SIZE - 406 offs_in_page); 407 408 if (write) { 409 memcpy(dma_buf, &buf[bytes_handled], bytes_to_handle); 410 ret = nand_prog_page_op(nand, page, offs_in_page, 411 dma_buf, bytes_to_handle); 412 } else { 413 ret = nand_read_page_op(nand, page, offs_in_page, 414 dma_buf, bytes_to_handle); 415 if (!ret) 416 memcpy(&buf[bytes_handled], dma_buf, 417 bytes_to_handle); 418 } 419 if (ret) 420 goto out_otp; 421 422 bytes_handled += bytes_to_handle; 423 offs_in_page = 0; 424 page++; 425 } 426 427 *retlen = bytes_handled; 428 429 out_otp: 430 if (ret) 431 dev_err(&mtd->dev, "failed to perform OTP IO: %i\n", ret); 432 433 ret = macronix_30lfxg18ac_otp_disable(nand); 434 WARN(ret, "failed to leave OTP mode after %s\n", 435 write ? "write" : "read"); 436 nand_deselect_target(nand); > 437 kfree(dma_buf); 438 439 return ret; 440 } 441
Hi Arseniy, kernel test robot noticed the following build errors: [auto build test ERROR on mtd/nand/next] [also build test ERROR on linus/master v6.3 next-20230425] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Arseniy-Krasnov/mtd-rawnand-macronix-OTP-access-for-MX30LFxG18AC/20230426-153143 base: https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next patch link: https://lore.kernel.org/r/20230426072455.3887717-1-AVKrasnov%40sberdevices.ru patch subject: [PATCH v1] mtd: rawnand: macronix: OTP access for MX30LFxG18AC config: hexagon-randconfig-r041-20230425 (https://download.01.org/0day-ci/archive/20230426/202304262101.pP2ae1ol-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project 437b7602e4a998220871de78afcb020b9c14a661) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/3529f3465e99379489b59c035a8a0506c3756ef4 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Arseniy-Krasnov/mtd-rawnand-macronix-OTP-access-for-MX30LFxG18AC/20230426-153143 git checkout 3529f3465e99379489b59c035a8a0506c3756ef4 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/mtd/nand/raw/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304262101.pP2ae1ol-lkp@intel.com/ All error/warnings (new ones prefixed by >>): >> drivers/mtd/nand/raw/nand_macronix.c:384:12: error: call to undeclared function 'kmalloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); ^ drivers/mtd/nand/raw/nand_macronix.c:384:12: note: did you mean 'mm_alloc'? include/linux/sched/mm.h:16:26: note: 'mm_alloc' declared here extern struct mm_struct *mm_alloc(void); ^ >> drivers/mtd/nand/raw/nand_macronix.c:384:10: error: incompatible integer to pointer conversion assigning to 'void *' from 'int' [-Wint-conversion] dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/mtd/nand/raw/nand_macronix.c:397:17: warning: comparison of distinct pointer types ('typeof ((page)) *' (aka 'unsigned long *') and 'uint64_t *' (aka 'unsigned long long *')) [-Wcompare-distinct-pointer-types] offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/asm-generic/div64.h:222:28: note: expanded from macro 'do_div' (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~ >> drivers/mtd/nand/raw/nand_macronix.c:397:17: error: incompatible pointer types passing 'unsigned long *' to parameter of type 'uint64_t *' (aka 'unsigned long long *') [-Werror,-Wincompatible-pointer-types] offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/asm-generic/div64.h:238:22: note: expanded from macro 'do_div' __rem = __div64_32(&(n), __base); \ ^~~~ include/asm-generic/div64.h:213:38: note: passing argument to parameter 'dividend' here extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); ^ >> drivers/mtd/nand/raw/nand_macronix.c:437:2: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] kfree(dma_buf); ^ drivers/mtd/nand/raw/nand_macronix.c:437:2: note: did you mean 'kvfree'? include/linux/rcutiny.h:99:13: note: 'kvfree' declared here extern void kvfree(const void *addr); ^ >> drivers/mtd/nand/raw/nand_macronix.c:397:17: warning: shift count >= width of type [-Wshift-count-overflow] offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/asm-generic/div64.h:234:25: note: expanded from macro 'do_div' } else if (likely(((n) >> 32) == 0)) { \ ^ ~~ include/linux/compiler.h:77:40: note: expanded from macro 'likely' # define likely(x) __builtin_expect(!!(x), 1) ^ 2 warnings and 4 errors generated. vim +/kmalloc +384 drivers/mtd/nand/raw/nand_macronix.c 366 367 static int __macronix_30lfxg18ac_rw_otp(struct mtd_info *mtd, 368 loff_t offs_in_flash, 369 size_t len, size_t *retlen, 370 u_char *buf, bool write) 371 { 372 struct nand_chip *nand; 373 size_t bytes_handled; 374 unsigned long page; 375 off_t offs_in_page; 376 void *dma_buf; 377 int ret; 378 379 /* 'nand_prog/read_page_op()' may use 'buf' as DMA buffer, 380 * so allocate properly aligned memory for it. This is 381 * needed because cross page accesses may lead to unaligned 382 * buffer address for DMA. 383 */ > 384 dma_buf = kmalloc(MACRONIX_30LFXG18AC_OTP_PAGE_SIZE, GFP_KERNEL); 385 if (!dma_buf) 386 return -ENOMEM; 387 388 nand = mtd_to_nand(mtd); 389 nand_select_target(nand, 0); 390 391 ret = macronix_30lfxg18ac_otp_enable(nand); 392 if (ret) 393 goto out_otp; 394 395 page = offs_in_flash; 396 /* 'page' will be result of division. */ > 397 offs_in_page = do_div(page, MACRONIX_30LFXG18AC_OTP_PAGE_SIZE); 398 bytes_handled = 0; 399 400 while (bytes_handled < len && 401 page < MACRONIX_30LFXG18AC_OTP_PAGES) { 402 size_t bytes_to_handle; 403 404 bytes_to_handle = min_t(size_t, len - bytes_handled, 405 MACRONIX_30LFXG18AC_OTP_PAGE_SIZE - 406 offs_in_page); 407 408 if (write) { 409 memcpy(dma_buf, &buf[bytes_handled], bytes_to_handle); 410 ret = nand_prog_page_op(nand, page, offs_in_page, 411 dma_buf, bytes_to_handle); 412 } else { 413 ret = nand_read_page_op(nand, page, offs_in_page, 414 dma_buf, bytes_to_handle); 415 if (!ret) 416 memcpy(&buf[bytes_handled], dma_buf, 417 bytes_to_handle); 418 } 419 if (ret) 420 goto out_otp; 421 422 bytes_handled += bytes_to_handle; 423 offs_in_page = 0; 424 page++; 425 } 426 427 *retlen = bytes_handled; 428 429 out_otp: 430 if (ret) 431 dev_err(&mtd->dev, "failed to perform OTP IO: %i\n", ret); 432 433 ret = macronix_30lfxg18ac_otp_disable(nand); 434 WARN(ret, "failed to leave OTP mode after %s\n", 435 write ? "write" : "read"); 436 nand_deselect_target(nand); > 437 kfree(dma_buf); 438 439 return ret; 440 } 441
diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 1472f925f386..c0d12979933a 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -31,6 +31,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 +330,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; + unsigned long page; + off_t offs_in_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 +536,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; }
This adds support for OTP area access on MX30LFxG18AC chip series. Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru> --- drivers/mtd/nand/raw/nand_macronix.c | 212 +++++++++++++++++++++++++++ 1 file changed, 212 insertions(+)