You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

641 lines
17 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2011 by James K. Larson *
  3. * jlarson@pacifier.com *
  4. * *
  5. * Copyright (C) 2013 Nemui Trinomius *
  6. * nemuisan_kawausogasuki@live.jp *
  7. * *
  8. * This program is free software; you can redistribute it and/or modify *
  9. * it under the terms of the GNU General Public License as published by *
  10. * the Free Software Foundation; either version 2 of the License, or *
  11. * (at your option) any later version. *
  12. * *
  13. * This program is distributed in the hope that it will be useful, *
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  16. * GNU General Public License for more details. *
  17. * *
  18. * You should have received a copy of the GNU General Public License *
  19. * along with this program; if not, write to the *
  20. * Free Software Foundation, Inc., *
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
  22. ***************************************************************************/
  23. #ifdef HAVE_CONFIG_H
  24. #include <config.h>
  25. #endif
  26. #include "imp.h"
  27. /* nuc1x register locations */
  28. #define NUC1X_SYS_BASE 0x50000000
  29. #define NUC1X_SYS_WRPROT 0x50000100
  30. #define NUC1X_SYS_IPRSTC1 0x50000008
  31. #define NUC1X_SYSCLK_BASE 0x50000200
  32. #define NUC1X_SYSCLK_PWRCON 0x50000200
  33. #define NUC1X_SYSCLK_CLKSEL0 0x50000210
  34. #define NUC1X_SYSCLK_CLKDIV 0x50000218
  35. #define NUC1X_SYSCLK_AHBCLK 0x50000204
  36. #define NUC1X_FLASH_BASE 0x5000C000
  37. #define NUC1X_FLASH_ISPCON 0x5000C000
  38. #define NUC1X_FLASH_ISPCMD 0x5000C00C
  39. #define NUC1X_FLASH_ISPADR 0x5000C004
  40. #define NUC1X_FLASH_ISPDAT 0x5000C008
  41. #define NUC1X_FLASH_ISPTRG 0x5000C010
  42. /* Command register bits */
  43. #define PWRCON_OSC22M (1 << 2)
  44. #define PWRCON_XTL12M (1 << 0)
  45. #define IPRSTC1_CPU_RST (1<<1)
  46. #define IPRSTC1_CHIP_RST (1<<0)
  47. #define AHBCLK_ISP_EN (1 << 2)
  48. #define ISPCON_ISPEN (1 << 0)
  49. #define ISPCON_BS_AP (0 << 1)
  50. #define ISPCON_BS_LP (1 << 1)
  51. #define ISPCON_CFGUEN (1 << 4)
  52. #define ISPCON_LDUEN (1 << 5)
  53. #define ISPCON_ISPFF (1 << 6)
  54. /* isp commands */
  55. #define ISPCMD_FCTRL (0x2)
  56. #define ISPCMD_FCEN (1 << 4)
  57. #define ISPCMD_FOEN (1 << 5)
  58. #define ISPCMD_ERASE (0x2 | ISPCMD_FOEN)
  59. #define ISPCMD_WRITE (0x1 | ISPCMD_FOEN)
  60. #define ISPTRG_ISPGO (1 << 0)
  61. /* access unlock keys */
  62. #define KEY1 0x59
  63. #define KEY2 0x16
  64. #define KEY3 0x88
  65. #define LOCK 0x00
  66. /* part structs */
  67. static const struct {
  68. const char *partname;
  69. uint32_t partno;
  70. uint16_t num_page;
  71. }
  72. NuMicroParts[] = {
  73. /*PART NO*/ /*PART ID*/ /*NUM PAGE*/
  74. {"NUC100LC1", 0x00010008, 64},
  75. {"NUC100LD1", 0x00010005, 128},
  76. {"NUC100LD2", 0x00010004, 128},
  77. {"NUC100RC1", 0x00010017, 64},
  78. {"NUC100RD1", 0x00010014, 128},
  79. {"NUC100RD2", 0x00010013, 128},
  80. {"NUC100LD3", 0x00010003, 128},
  81. {"NUC100LE3", 0x00010000, 256},
  82. {"NUC100RD3", 0x00010012, 128},
  83. {"NUC100RE3", 0x00010009, 256},
  84. {"NUC100VD2", 0x00010022, 128},
  85. {"NUC100VD3", 0x00010021, 128},
  86. {"NUC100VE3", 0x00010018, 256},
  87. {"NUC120LC1", 0x00012008, 64},
  88. {"NUC120LD1", 0x00012005, 128},
  89. {"NUC120LD2", 0x00012004, 128},
  90. {"NUC120RC1", 0x00012017, 64},
  91. {"NUC120RD1", 0x00012014, 128},
  92. {"NUC120RD2", 0x00012013, 128},
  93. {"NUC120LD3", 0x00012003, 128},
  94. {"NUC120LE3", 0x00012000, 256},
  95. {"NUC120RD3", 0x00012012, 128},
  96. {"NUC120RE3", 0x00012009, 256},
  97. {"NUC120VD2", 0x00012022, 128},
  98. {"NUC120VD3", 0x00012021, 128},
  99. {"NUC120VE3", 0x00012018, 256},
  100. {"NUC122ZD2", 0x00012231, 128},
  101. {"NUC122ZC1", 0x00012235, 64},
  102. {"NUC122LD2", 0x00012204, 128},
  103. {"NUC122LC1", 0x00012208, 64},
  104. {"NUC122RD2", 0x00012213, 128},
  105. {"NUC122RC1", 0x00012217, 64},
  106. {"NUC123ZD4", 0x00012255, 136},
  107. {"NUC123ZC2", 0x00012245, 68},
  108. {"NUC123LD4", 0x00012235, 136},
  109. {"NUC123LC2", 0x00012225, 68},
  110. {"NUC123SD4", 0x00012215, 136},
  111. {"NUC123SC2", 0x00012205, 68},
  112. {"NUC130LC1", 0x00013008, 64},
  113. {"NUC130LD2", 0x00013004, 128},
  114. {"NUC130LE3", 0x00013000, 256},
  115. {"NUC130RC1", 0x00013017, 64},
  116. {"NUC130RD2", 0x00013013, 128},
  117. {"NUC130RE3", 0x00013009, 256},
  118. {"NUC130VE3", 0x00013018, 256},
  119. {"M052L", 0x00005200, 16},
  120. {"M052Z", 0x00005203, 16},
  121. {"M054L", 0x00005400, 32},
  122. {"M054Z", 0x00005403, 32},
  123. {"M058L", 0x00005800, 64},
  124. {"M058Z", 0x00005803, 64},
  125. {"M0516L", 0x00005A00, 128},
  126. {"M0516Z", 0x00005A03, 128},
  127. {"MINI51L", 0x00205100, 8},
  128. {"MINI51Z", 0x00205103, 8},
  129. {"MINI52L", 0x00205200, 16},
  130. {"MINI52Z", 0x00205203, 16},
  131. {"MINI54L", 0x00205400, 32},
  132. {"MINI54Z", 0x00205403, 32},
  133. {"UNKNOWN", 0x00000000, 256},
  134. };
  135. static int nuc1x_unlock(struct flash_bank *bank)
  136. {
  137. uint32_t is_protected;
  138. struct target *target = bank->target;
  139. /* Check to see if Nuc is unlocked or not */
  140. int retval = target_read_u32(target, NUC1X_SYS_WRPROT, &is_protected);
  141. if (retval != ERROR_OK)
  142. return retval;
  143. LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected);
  144. if (is_protected == 0) { /* means protected - so unlock it */
  145. /* unlock flash registers */
  146. retval = target_write_u32(target, NUC1X_SYS_WRPROT, KEY1);
  147. if (retval != ERROR_OK)
  148. return retval;
  149. retval = target_write_u32(target, NUC1X_SYS_WRPROT, KEY2);
  150. if (retval != ERROR_OK)
  151. return retval;
  152. retval = target_write_u32(target, NUC1X_SYS_WRPROT, KEY3);
  153. if (retval != ERROR_OK)
  154. return retval;
  155. }
  156. /* Check that unlock worked */
  157. retval = target_read_u32(target, NUC1X_SYS_WRPROT, &is_protected);
  158. if (retval != ERROR_OK)
  159. return retval;
  160. if (is_protected == 1) { /* means unprotected */
  161. LOG_DEBUG("protection removed");
  162. } else {
  163. LOG_DEBUG("still protected!!");
  164. }
  165. return ERROR_OK;
  166. }
  167. static int nuc1x_reset(struct flash_bank *bank)
  168. {
  169. struct target *target = bank->target;
  170. nuc1x_unlock(bank);
  171. int retval = target_write_u32(target, NUC1X_SYS_IPRSTC1, IPRSTC1_CPU_RST);
  172. if (retval != ERROR_OK)
  173. return retval;
  174. return ERROR_OK;
  175. }
  176. static int nuc1x_reset2lprom(struct flash_bank *bank)
  177. {
  178. struct target *target = bank->target;
  179. nuc1x_unlock(bank);
  180. int retval = target_write_u32(target, NUC1X_FLASH_ISPCON, ISPCON_BS_LP);
  181. if (retval != ERROR_OK)
  182. return retval;
  183. nuc1x_reset(bank);
  184. return ERROR_OK;
  185. }
  186. static int nuc1x_init_iap(struct flash_bank *bank)
  187. {
  188. struct target *target = bank->target;
  189. if (target->state != TARGET_HALTED) {
  190. LOG_ERROR("Target not halted");
  191. return ERROR_TARGET_NOT_HALTED;
  192. }
  193. int retval = nuc1x_unlock(bank);
  194. if (retval != ERROR_OK)
  195. return retval;
  196. /* enable isp clock and ispen bit */
  197. retval = target_write_u32(target, NUC1X_SYSCLK_AHBCLK, AHBCLK_ISP_EN);
  198. if (retval != ERROR_OK)
  199. return retval;
  200. retval = target_write_u32(target, NUC1X_FLASH_ISPCON, ISPCON_ISPFF | ISPCON_LDUEN | ISPCON_CFGUEN | ISPCON_ISPEN);
  201. if (retval != ERROR_OK)
  202. return retval;
  203. return ERROR_OK;
  204. }
  205. /* Private bank information for nuc1x. */
  206. struct nuc1x_flash_bank {
  207. struct working_area *write_algorithm;
  208. int probed;
  209. };
  210. /* This is the function called in the config file. */
  211. FLASH_BANK_COMMAND_HANDLER(nuc1x_flash_bank_command)
  212. {
  213. struct nuc1x_flash_bank *bank_info;
  214. if (CMD_ARGC < 6)
  215. return ERROR_COMMAND_SYNTAX_ERROR;
  216. LOG_INFO("add flash_bank nuc1x %s", bank->name);
  217. bank_info = malloc(sizeof(struct nuc1x_flash_bank));
  218. memset(bank_info, 0, sizeof(struct nuc1x_flash_bank));
  219. bank->driver_priv = bank_info;
  220. return ERROR_OK;
  221. }
  222. /* Protection checking - examines the lock bit. */
  223. static int nuc1x_protect_check(struct flash_bank *bank)
  224. {
  225. uint32_t is_protected, set;
  226. struct target *target = bank->target;
  227. int i;
  228. if (target->state != TARGET_HALTED) {
  229. LOG_ERROR("Target not halted");
  230. return ERROR_TARGET_NOT_HALTED;
  231. }
  232. /* Check to see if Nuc is unlocked or not */
  233. int retval = target_read_u32(target, NUC1X_SYS_WRPROT, &is_protected);
  234. if (retval != ERROR_OK)
  235. return retval;
  236. LOG_INFO("is_protected = 0x%08" PRIx32 "", is_protected);
  237. if (is_protected == 0) { /* means protected */
  238. set = 1;
  239. } else {
  240. set = 0;
  241. }
  242. for (i = 0; i < bank->num_sectors; i++)
  243. bank->sectors[i].is_protected = set;
  244. return ERROR_OK;
  245. }
  246. static int nuc1x_erase(struct flash_bank *bank, int first, int last)
  247. {
  248. struct target *target = bank->target;
  249. uint32_t timeout, status;
  250. int i;
  251. if (bank->target->state != TARGET_HALTED) {
  252. LOG_ERROR("Target not halted");
  253. return ERROR_TARGET_NOT_HALTED;
  254. }
  255. LOG_INFO("Nuvoton NUC: Sector Erase ... (%d to %d)", first, last);
  256. int retval = nuc1x_reset2lprom(bank);
  257. if (retval != ERROR_OK)
  258. return retval;
  259. retval = nuc1x_init_iap(bank);
  260. if (retval != ERROR_OK)
  261. return retval;
  262. retval = nuc1x_unlock(bank);
  263. if (retval != ERROR_OK)
  264. return retval;
  265. retval = target_write_u32(target, NUC1X_FLASH_ISPCMD, ISPCMD_ERASE);
  266. if (retval != ERROR_OK)
  267. return retval;
  268. for (i = first; i <= last; i++) {
  269. LOG_DEBUG("erasing sector %d at address 0x%" PRIx32 "", i, bank->base + bank->sectors[i].offset);
  270. retval = target_write_u32(target, NUC1X_FLASH_ISPADR, bank->base + bank->sectors[i].offset);
  271. if (retval != ERROR_OK)
  272. return retval;
  273. retval = target_write_u32(target, NUC1X_FLASH_ISPTRG, ISPTRG_ISPGO); /* This is the only bit available */
  274. if (retval != ERROR_OK)
  275. return retval;
  276. /* wait for busy to clear - check the GO flag */
  277. timeout = 100;
  278. for (;;) {
  279. retval = target_read_u32(target, NUC1X_FLASH_ISPTRG, &status);
  280. if (retval != ERROR_OK)
  281. return retval;
  282. LOG_DEBUG("status: 0x%" PRIx32 "", status);
  283. if (status == 0)
  284. break;
  285. if (timeout-- <= 0) {
  286. LOG_DEBUG("timed out waiting for flash");
  287. return ERROR_FAIL;
  288. }
  289. busy_sleep(1); /* can use busy sleep for short times. */
  290. }
  291. /* check for failure */
  292. retval = target_read_u32(target, NUC1X_FLASH_ISPCON, &status);
  293. if (retval != ERROR_OK)
  294. return retval;
  295. if ((status & ISPCON_ISPFF) != 0) {
  296. LOG_DEBUG("failure: 0x%" PRIx32 "", status);
  297. /* if bit is set, then must write to it to clear it. */
  298. retval = target_write_u32(target, NUC1X_FLASH_ISPCON, ISPCON_ISPFF);
  299. if (retval != ERROR_OK)
  300. return retval;
  301. } else {
  302. bank->sectors[i].is_erased = 1;
  303. }
  304. }
  305. retval = nuc1x_reset(bank);
  306. if (retval != ERROR_OK)
  307. return retval;
  308. /* done, */
  309. LOG_DEBUG("Erase done.");
  310. return ERROR_OK;
  311. }
  312. /* The write routine stub. */
  313. static int nuc1x_write(struct flash_bank *bank, const uint8_t *buffer,
  314. uint32_t offset, uint32_t count)
  315. {
  316. struct target *target = bank->target;
  317. uint32_t i, timeout, status;
  318. if (bank->target->state != TARGET_HALTED) {
  319. LOG_ERROR("Target not halted");
  320. return ERROR_TARGET_NOT_HALTED;
  321. }
  322. LOG_INFO("Nuvoton NUC: FLASH Write ...");
  323. int retval = nuc1x_reset2lprom(bank);
  324. if (retval != ERROR_OK)
  325. return retval;
  326. retval = nuc1x_init_iap(bank);
  327. if (retval != ERROR_OK)
  328. return retval;
  329. retval = nuc1x_unlock(bank);
  330. if (retval != ERROR_OK)
  331. return retval;
  332. retval = target_write_u32(target, NUC1X_FLASH_ISPCMD, ISPCMD_WRITE);
  333. if (retval != ERROR_OK)
  334. return retval;
  335. /* program command */
  336. for (i = 0; i < count; i += 4) {
  337. LOG_DEBUG("write longword @ %08" PRIX32, (uint32_t)(offset + i));
  338. uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
  339. memcpy(padding, buffer + i, MIN(4, count-i));
  340. retval = target_write_u32(target, NUC1X_FLASH_ISPADR, bank->base + offset + i);
  341. if (retval != ERROR_OK)
  342. return retval;
  343. retval = target_write_memory(target, NUC1X_FLASH_ISPDAT, 4, 1, padding);
  344. if (retval != ERROR_OK)
  345. return retval;
  346. retval = target_write_u32(target, NUC1X_FLASH_ISPTRG, ISPTRG_ISPGO);
  347. if (retval != ERROR_OK)
  348. return retval;
  349. /* wait for busy to clear - check the GO flag */
  350. timeout = 100;
  351. for (;;) {
  352. retval = target_read_u32(target, NUC1X_FLASH_ISPTRG, &status);
  353. if (retval != ERROR_OK)
  354. return retval;
  355. LOG_DEBUG("status: 0x%" PRIx32 "", status);
  356. if (status == 0)
  357. break;
  358. if (timeout-- <= 0) {
  359. LOG_DEBUG("timed out waiting for flash");
  360. return ERROR_FAIL;
  361. }
  362. busy_sleep(1); /* can use busy sleep for short times. */
  363. }
  364. /* check for failure */
  365. retval = target_read_u32(target, NUC1X_FLASH_ISPCON, &status);
  366. if (retval != ERROR_OK)
  367. return retval;
  368. if ((status & ISPCON_ISPFF) != 0) {
  369. LOG_DEBUG("failure: 0x%" PRIx32 "", status);
  370. /* if bit is set, then must write to it to clear it. */
  371. retval = target_write_u32(target, NUC1X_FLASH_ISPCON, ISPCON_ISPFF);
  372. if (retval != ERROR_OK)
  373. return retval;
  374. } else {
  375. LOG_DEBUG("Write OK");
  376. }
  377. }
  378. retval = nuc1x_reset(bank);
  379. if (retval != ERROR_OK)
  380. return retval;
  381. /* done, */
  382. LOG_DEBUG("Write done.");
  383. return ERROR_OK;
  384. }
  385. /* The probe routine for the nuc. Only recognizes the nuc120 right now. */
  386. static int nuc1x_probe(struct flash_bank *bank)
  387. {
  388. struct target *target = bank->target;
  389. struct nuc1x_flash_bank *nuc1x_info = bank->driver_priv;
  390. int i;
  391. uint16_t num_pages;
  392. uint32_t device_id;
  393. int page_size;
  394. uint32_t base_address = 0x00000000;
  395. nuc1x_info->probed = 0;
  396. /* read nuc1x device id register */
  397. int retval = target_read_u32(target, 0x50000000, &device_id);
  398. if (retval != ERROR_OK)
  399. return retval;
  400. page_size = 512; /* all nuc parts has 512 byte per sector */
  401. /* search part numbers */
  402. for (i = 0; NuMicroParts[i].partno; i++) {
  403. if (NuMicroParts[i].partno == (device_id & 0x0FFFFFFF)) {
  404. num_pages = NuMicroParts[i].num_page;
  405. break;
  406. }
  407. }
  408. if (!(NuMicroParts[i].partno == 0x00000000)) {
  409. LOG_INFO("DeviceID : 0x%08" PRIx32 "", device_id);
  410. LOG_INFO("Detect %s%cN!", NuMicroParts[i].partname, (char)('A'+(device_id>>28)));
  411. } else {
  412. LOG_INFO("No NUC Device Detected...");
  413. return ERROR_FAIL;
  414. }
  415. if (bank->sectors) {
  416. free(bank->sectors);
  417. bank->sectors = NULL;
  418. }
  419. bank->base = base_address;
  420. bank->size = (num_pages * page_size);
  421. bank->num_sectors = num_pages;
  422. bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
  423. for (i = 0; i < num_pages; i++) {
  424. bank->sectors[i].offset = i * page_size;
  425. bank->sectors[i].size = page_size;
  426. bank->sectors[i].is_erased = -1;
  427. bank->sectors[i].is_protected = 1;
  428. }
  429. nuc1x_info->probed = 1;
  430. LOG_DEBUG("Nuvoton NUC: Probed ...");
  431. return ERROR_OK;
  432. }
  433. /* Standard approach to autoprobing. */
  434. static int nuc1x_auto_probe(struct flash_bank *bank)
  435. {
  436. struct nuc1x_flash_bank *nuc1x_info = bank->driver_priv;
  437. if (nuc1x_info->probed)
  438. return ERROR_OK;
  439. return nuc1x_probe(bank);
  440. }
  441. /* Info doesn't really add much, but works correctly. */
  442. static int get_nuc1x_info(struct flash_bank *bank, char *buf, int buf_size)
  443. {
  444. struct target *target = bank->target;
  445. uint32_t i, device_id;
  446. /* read nuc1x device id register */
  447. int retval = target_read_u32(target, 0x50000000, &device_id);
  448. if (retval != ERROR_OK)
  449. return retval;
  450. /* search part numbers */
  451. for (i = 0; NuMicroParts[i].partno; i++) {
  452. if (NuMicroParts[i].partno == (device_id & 0x0FFFFFFF))
  453. break;
  454. }
  455. if (!(NuMicroParts[i].partno == 0x00000000)) {
  456. LOG_INFO("DeviceID : 0x%08" PRIx32 "", device_id);
  457. LOG_INFO("Detect %s%cN!", NuMicroParts[i].partname, (char)('A'+(device_id>>28)));
  458. } else {
  459. LOG_INFO("No NUC Device Detected...");
  460. return ERROR_FAIL;
  461. }
  462. return ERROR_OK;
  463. }
  464. /* The nuc120 doesn't support mass erase, so this will probably be removed soon.
  465. * The structure is left for now until I am sure I don't want to add any custom
  466. * commands. */
  467. static int nuc1x_mass_erase(struct flash_bank *bank)
  468. {
  469. struct target *target = bank->target;
  470. int retval = ERROR_OK;
  471. if (target->state != TARGET_HALTED) {
  472. LOG_ERROR("Target not halted");
  473. return ERROR_TARGET_NOT_HALTED;
  474. }
  475. LOG_INFO("Nuvoton NUC: Chip Erase ... (may take several seconds)");
  476. return retval;
  477. }
  478. COMMAND_HANDLER(nuc1x_handle_mass_erase_command)
  479. {
  480. int i; /* for erasing sectors */
  481. if (CMD_ARGC < 1) {
  482. command_print(CMD_CTX, "nuc1x mass_erase <bank>");
  483. return ERROR_OK;
  484. }
  485. struct flash_bank *bank;
  486. int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
  487. if (ERROR_OK != retval)
  488. return retval;
  489. retval = nuc1x_mass_erase(bank);
  490. if (retval == ERROR_OK) {
  491. /* set all sectors as erased */
  492. for (i = 0; i < bank->num_sectors; i++)
  493. bank->sectors[i].is_erased = 1;
  494. command_print(CMD_CTX, "nuc1x mass erase complete");
  495. } else
  496. command_print(CMD_CTX, "nuc1x mass erase failed");
  497. return retval;
  498. }
  499. static const struct command_registration nuc1x_exec_command_handlers[] = {
  500. {
  501. .name = "mass_erase",
  502. .handler = nuc1x_handle_mass_erase_command,
  503. .mode = COMMAND_EXEC,
  504. .usage = "bank_id",
  505. .help = "Erase entire Flash device.",
  506. },
  507. COMMAND_REGISTRATION_DONE
  508. };
  509. static const struct command_registration nuc1x_command_handlers[] = {
  510. {
  511. .name = "nuc1x",
  512. .mode = COMMAND_ANY,
  513. .help = "nuc1x Flash command group",
  514. .chain = nuc1x_exec_command_handlers,
  515. },
  516. COMMAND_REGISTRATION_DONE
  517. };
  518. struct flash_driver nuc1x_flash = {
  519. .name = "nuc1x",
  520. .commands = nuc1x_command_handlers,
  521. .flash_bank_command = nuc1x_flash_bank_command,
  522. .erase = nuc1x_erase,
  523. .write = nuc1x_write,
  524. .read = default_flash_read,
  525. .probe = nuc1x_probe,
  526. .auto_probe = nuc1x_auto_probe,
  527. .erase_check = default_flash_blank_check,
  528. .protect_check = nuc1x_protect_check,
  529. .info = get_nuc1x_info,
  530. };