allow multiple bitbang interfaces
[openocd/ztw.git] / src / flash / nor / str7x.c
blobb8f463fe99bd6f138dd2c0ef209d94602a6f9a00
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include "imp.h"
28 #include "str7x.h"
29 #include <target/arm.h>
30 #include <helper/binarybuffer.h>
31 #include <target/algorithm.h>
34 struct str7x_mem_layout mem_layout_str7bank0[] = {
35 {0x00000000, 0x02000, 0x01},
36 {0x00002000, 0x02000, 0x02},
37 {0x00004000, 0x02000, 0x04},
38 {0x00006000, 0x02000, 0x08},
39 {0x00008000, 0x08000, 0x10},
40 {0x00010000, 0x10000, 0x20},
41 {0x00020000, 0x10000, 0x40},
42 {0x00030000, 0x10000, 0x80}
45 struct str7x_mem_layout mem_layout_str7bank1[] = {
46 {0x00000000, 0x02000, 0x10000},
47 {0x00002000, 0x02000, 0x20000}
50 static struct str7x_flash_bank *str7x_bank_data(struct flash_bank *bank)
52 return (struct str7x_flash_bank *)flash_bank_data(bank);
55 static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg)
57 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
58 return (str7x_info->register_base | reg);
61 static int str7x_build_block_list(struct flash_bank *bank)
63 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
65 int i;
66 int num_sectors;
67 int b0_sectors = 0, b1_sectors = 0;
69 switch (bank->size)
71 case 16 * 1024:
72 b1_sectors = 2;
73 break;
74 case 64 * 1024:
75 b0_sectors = 5;
76 break;
77 case 128 * 1024:
78 b0_sectors = 6;
79 break;
80 case 256 * 1024:
81 b0_sectors = 8;
82 break;
83 default:
84 LOG_ERROR("BUG: unknown bank->size encountered");
85 exit(-1);
88 num_sectors = b0_sectors + b1_sectors;
90 bank->num_sectors = num_sectors;
91 bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
92 str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
94 num_sectors = 0;
96 for (i = 0; i < b0_sectors; i++)
98 bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start;
99 bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size;
100 bank->sectors[num_sectors].is_erased = -1;
101 bank->sectors[num_sectors].is_protected = 1;
102 str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit;
105 for (i = 0; i < b1_sectors; i++)
107 bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start;
108 bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size;
109 bank->sectors[num_sectors].is_erased = -1;
110 bank->sectors[num_sectors].is_protected = 1;
111 str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit;
114 return ERROR_OK;
117 /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
119 FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command)
121 struct str7x_flash_bank *str7x_info;
123 if (CMD_ARGC < 7)
125 LOG_WARNING("incomplete flash_bank str7x configuration");
126 return ERROR_FLASH_BANK_INVALID;
129 str7x_info = malloc(sizeof(struct str7x_flash_bank));
131 struct flash_bank *bank = flash_bank_from_object(object);
132 set_flash_bank_data(bank, str7x_info);
134 /* set default bits for str71x flash */
135 str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
136 str7x_info->disable_bit = (1 << 1);
138 if (strcmp(CMD_ARGV[6], "STR71x") == 0)
140 str7x_info->register_base = 0x40100000;
142 else if (strcmp(CMD_ARGV[6], "STR73x") == 0)
144 str7x_info->register_base = 0x80100000;
145 str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
147 else if (strcmp(CMD_ARGV[6], "STR75x") == 0)
149 str7x_info->register_base = 0x20100000;
150 str7x_info->disable_bit = (1 << 0);
152 else
154 LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]);
155 free(str7x_info);
156 return ERROR_FLASH_BANK_INVALID;
159 str7x_build_block_list(bank);
161 str7x_info->write_algorithm = NULL;
163 return ERROR_OK;
166 static uint32_t str7x_status(struct flash_bank *bank)
168 struct target *target = bank->target;
169 uint32_t retval;
171 target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
173 return retval;
176 static uint32_t str7x_result(struct flash_bank *bank)
178 struct target *target = bank->target;
179 uint32_t retval;
181 target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
183 return retval;
186 static int str7x_protect_check(struct flash_bank *bank)
188 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
189 struct target *target = bank->target;
191 int i;
192 uint32_t retval;
194 if (bank->target->state != TARGET_HALTED)
196 LOG_ERROR("Target not halted");
197 return ERROR_TARGET_NOT_HALTED;
200 target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &retval);
202 for (i = 0; i < bank->num_sectors; i++)
204 if (retval & str7x_info->sector_bits[i])
205 bank->sectors[i].is_protected = 0;
206 else
207 bank->sectors[i].is_protected = 1;
210 return ERROR_OK;
213 static int str7x_erase(struct flash_bank *bank, int first, int last)
215 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
216 struct target *target = bank->target;
218 int i;
219 uint32_t cmd;
220 uint32_t retval;
221 uint32_t sectors = 0;
223 if (bank->target->state != TARGET_HALTED)
225 LOG_ERROR("Target not halted");
226 return ERROR_TARGET_NOT_HALTED;
229 for (i = first; i <= last; i++)
231 sectors |= str7x_info->sector_bits[i];
234 LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors);
236 /* clear FLASH_ER register */
237 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
239 cmd = FLASH_SER;
240 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
242 cmd = sectors;
243 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
245 cmd = FLASH_SER | FLASH_WMS;
246 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
248 while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
249 alive_sleep(1);
252 retval = str7x_result(bank);
254 if (retval)
256 LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32 "", retval);
257 return ERROR_FLASH_OPERATION_FAILED;
260 for (i = first; i <= last; i++)
261 bank->sectors[i].is_erased = 1;
263 return ERROR_OK;
266 static int str7x_protect(struct flash_bank *bank, int set, int first, int last)
268 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
269 struct target *target = bank->target;
270 int i;
271 uint32_t cmd;
272 uint32_t retval;
273 uint32_t protect_blocks;
275 if (bank->target->state != TARGET_HALTED)
277 LOG_ERROR("Target not halted");
278 return ERROR_TARGET_NOT_HALTED;
281 protect_blocks = 0xFFFFFFFF;
283 if (set)
285 for (i = first; i <= last; i++)
286 protect_blocks &= ~(str7x_info->sector_bits[i]);
289 /* clear FLASH_ER register */
290 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
292 cmd = FLASH_SPR;
293 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
295 cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
296 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
298 cmd = protect_blocks;
299 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
301 cmd = FLASH_SPR | FLASH_WMS;
302 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
304 while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
305 alive_sleep(1);
308 retval = str7x_result(bank);
310 LOG_DEBUG("retval: 0x%8.8" PRIx32 "", retval);
312 if (retval & FLASH_ERER)
313 return ERROR_FLASH_SECTOR_NOT_ERASED;
314 else if (retval & FLASH_WPF)
315 return ERROR_FLASH_OPERATION_FAILED;
317 return ERROR_OK;
320 static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
322 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
323 struct target *target = bank->target;
324 uint32_t buffer_size = 8192;
325 struct working_area *source;
326 uint32_t address = bank->base + offset;
327 struct reg_param reg_params[6];
328 struct arm_algorithm armv4_5_info;
329 int retval = ERROR_OK;
331 uint32_t str7x_flash_write_code[] = {
332 /* write: */
333 0xe3a04201, /* mov r4, #0x10000000 */
334 0xe5824000, /* str r4, [r2, #0x0] */
335 0xe5821010, /* str r1, [r2, #0x10] */
336 0xe4904004, /* ldr r4, [r0], #4 */
337 0xe5824008, /* str r4, [r2, #0x8] */
338 0xe4904004, /* ldr r4, [r0], #4 */
339 0xe582400c, /* str r4, [r2, #0xc] */
340 0xe3a04209, /* mov r4, #0x90000000 */
341 0xe5824000, /* str r4, [r2, #0x0] */
342 /* busy: */
343 0xe5924000, /* ldr r4, [r2, #0x0] */
344 0xe1140005, /* tst r4, r5 */
345 0x1afffffc, /* bne busy */
346 0xe5924014, /* ldr r4, [r2, #0x14] */
347 0xe31400ff, /* tst r4, #0xff */
348 0x03140c01, /* tsteq r4, #0x100 */
349 0x1a000002, /* bne exit */
350 0xe2811008, /* add r1, r1, #0x8 */
351 0xe2533001, /* subs r3, r3, #1 */
352 0x1affffec, /* bne write */
353 /* exit: */
354 0xeafffffe, /* b exit */
357 /* flash write code */
358 if (target_alloc_working_area(target, 4 * 20, &str7x_info->write_algorithm) != ERROR_OK)
360 LOG_WARNING("no working area available, can't do block memory writes");
361 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
364 target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (uint8_t*)str7x_flash_write_code);
366 /* memory buffer */
367 while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
369 buffer_size /= 2;
370 if (buffer_size <= 256)
372 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
373 if (str7x_info->write_algorithm)
374 target_free_working_area(target, str7x_info->write_algorithm);
376 LOG_WARNING("no large enough working area available, can't do block memory writes");
377 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
381 armv4_5_info.common_magic = ARM_COMMON_MAGIC;
382 armv4_5_info.core_mode = ARM_MODE_SVC;
383 armv4_5_info.core_state = ARM_STATE_ARM;
385 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
386 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
387 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
388 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
389 init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
390 init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
392 while (count > 0)
394 uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
396 target_write_buffer(target, source->address, thisrun_count * 8, buffer);
398 buf_set_u32(reg_params[0].value, 0, 32, source->address);
399 buf_set_u32(reg_params[1].value, 0, 32, address);
400 buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
401 buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
402 buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
404 if ((retval = target_run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
406 LOG_ERROR("error executing str7x flash write algorithm");
407 retval = ERROR_FLASH_OPERATION_FAILED;
408 break;
411 if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
413 retval = ERROR_FLASH_OPERATION_FAILED;
414 break;
417 buffer += thisrun_count * 8;
418 address += thisrun_count * 8;
419 count -= thisrun_count;
422 target_free_working_area(target, source);
423 target_free_working_area(target, str7x_info->write_algorithm);
425 destroy_reg_param(&reg_params[0]);
426 destroy_reg_param(&reg_params[1]);
427 destroy_reg_param(&reg_params[2]);
428 destroy_reg_param(&reg_params[3]);
429 destroy_reg_param(&reg_params[4]);
430 destroy_reg_param(&reg_params[5]);
432 return retval;
435 static int str7x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
437 struct target *target = bank->target;
438 struct str7x_flash_bank *str7x_info = str7x_bank_data(bank);
439 uint32_t dwords_remaining = (count / 8);
440 uint32_t bytes_remaining = (count & 0x00000007);
441 uint32_t address = bank->base + offset;
442 uint32_t bytes_written = 0;
443 uint32_t cmd;
444 int retval;
445 uint32_t check_address = offset;
446 int i;
448 if (bank->target->state != TARGET_HALTED)
450 LOG_ERROR("Target not halted");
451 return ERROR_TARGET_NOT_HALTED;
454 if (offset & 0x7)
456 LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
457 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
460 for (i = 0; i < bank->num_sectors; i++)
462 uint32_t sec_start = bank->sectors[i].offset;
463 uint32_t sec_end = sec_start + bank->sectors[i].size;
465 /* check if destination falls within the current sector */
466 if ((check_address >= sec_start) && (check_address < sec_end))
468 /* check if destination ends in the current sector */
469 if (offset + count < sec_end)
470 check_address = offset + count;
471 else
472 check_address = sec_end;
476 if (check_address != offset + count)
477 return ERROR_FLASH_DST_OUT_OF_BANK;
479 /* clear FLASH_ER register */
480 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
482 /* multiple dwords (8-byte) to be programmed? */
483 if (dwords_remaining > 0)
485 /* try using a block write */
486 if ((retval = str7x_write_block(bank, buffer, offset, dwords_remaining)) != ERROR_OK)
488 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
490 /* if block write failed (no sufficient working area),
491 * we use normal (slow) single dword accesses */
492 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
494 else if (retval == ERROR_FLASH_OPERATION_FAILED)
496 /* if an error occured, we examine the reason, and quit */
497 retval = str7x_result(bank);
499 LOG_ERROR("flash writing failed with error code: 0x%x", retval);
500 return ERROR_FLASH_OPERATION_FAILED;
503 else
505 buffer += dwords_remaining * 8;
506 address += dwords_remaining * 8;
507 dwords_remaining = 0;
511 while (dwords_remaining > 0)
513 /* command */
514 cmd = FLASH_DWPG;
515 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
517 /* address */
518 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
520 /* data word 1 */
521 target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
522 bytes_written += 4;
524 /* data word 2 */
525 target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
526 bytes_written += 4;
528 /* start programming cycle */
529 cmd = FLASH_DWPG | FLASH_WMS;
530 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
532 while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
534 alive_sleep(1);
537 retval = str7x_result(bank);
539 if (retval & FLASH_PGER)
540 return ERROR_FLASH_OPERATION_FAILED;
541 else if (retval & FLASH_WPF)
542 return ERROR_FLASH_OPERATION_FAILED;
544 dwords_remaining--;
545 address += 8;
548 if (bytes_remaining)
550 uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
551 int i = 0;
553 while (bytes_remaining > 0)
555 last_dword[i++] = *(buffer + bytes_written);
556 bytes_remaining--;
557 bytes_written++;
560 /* command */
561 cmd = FLASH_DWPG;
562 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
564 /* address */
565 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
567 /* data word 1 */
568 target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
569 bytes_written += 4;
571 /* data word 2 */
572 target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
573 bytes_written += 4;
575 /* start programming cycle */
576 cmd = FLASH_DWPG | FLASH_WMS;
577 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
579 while (((retval = str7x_status(bank)) & str7x_info->busy_bits))
581 alive_sleep(1);
584 retval = str7x_result(bank);
586 if (retval & FLASH_PGER)
587 return ERROR_FLASH_OPERATION_FAILED;
588 else if (retval & FLASH_WPF)
589 return ERROR_FLASH_OPERATION_FAILED;
592 return ERROR_OK;
595 static int str7x_probe(struct flash_bank *bank)
597 return ERROR_OK;
600 #if 0
601 COMMAND_HANDLER(str7x_handle_part_id_command)
603 return ERROR_OK;
605 #endif
607 static int str7x_info(struct flash_bank *bank, char *buf, int buf_size)
609 snprintf(buf, buf_size, "str7x flash driver info");
610 return ERROR_OK;
613 COMMAND_HANDLER(str7x_handle_disable_jtag_command)
615 struct target *target = NULL;
616 struct str7x_flash_bank *str7x_info = NULL;
618 uint32_t flash_cmd;
619 uint16_t ProtectionLevel = 0;
620 uint16_t ProtectionRegs;
622 if (CMD_ARGC < 1)
624 command_print(CMD_CTX, "str7x disable_jtag <bank>");
625 return ERROR_OK;
628 struct flash_bank *bank;
629 int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
630 if (ERROR_OK != retval)
631 return retval;
633 str7x_info = str7x_bank_data(bank);
635 target = bank->target;
637 if (target->state != TARGET_HALTED)
639 LOG_ERROR("Target not halted");
640 return ERROR_TARGET_NOT_HALTED;
643 /* first we get protection status */
644 uint32_t reg;
645 target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &reg);
647 if (!(reg & str7x_info->disable_bit))
649 ProtectionLevel = 1;
652 target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &reg);
653 ProtectionRegs = ~(reg >> 16);
655 while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))
657 ProtectionRegs >>= 1;
658 ProtectionLevel++;
661 if (ProtectionLevel == 0)
663 flash_cmd = FLASH_SPR;
664 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
665 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);
666 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);
667 flash_cmd = FLASH_SPR | FLASH_WMS;
668 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
670 else
672 flash_cmd = FLASH_SPR;
673 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
674 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
675 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1 << (15 + ProtectionLevel)));
676 flash_cmd = FLASH_SPR | FLASH_WMS;
677 target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
680 return ERROR_OK;
683 static const struct command_registration str7x_exec_command_handlers[] = {
685 .name = "disable_jtag",
686 .handler = &str7x_handle_disable_jtag_command,
687 .mode = COMMAND_EXEC,
688 .help = "disable jtag access",
690 COMMAND_REGISTRATION_DONE
692 static const struct command_registration str7x_command_handlers[] = {
694 .name = "str7x",
695 .mode = COMMAND_ANY,
696 .help = "str7x flash command group",
697 .chain = str7x_exec_command_handlers,
699 COMMAND_REGISTRATION_DONE
702 FLASH_DRIVER(str7x, &str7x_flash_bank_command, str7x_command_handlers,
703 .erase = &str7x_erase,
704 .protect = &str7x_protect,
705 .write = &str7x_write,
706 .probe = &str7x_probe,
707 .auto_probe = &str7x_probe,
708 .erase_check = &default_flash_blank_check,
709 .protect_check = &str7x_protect_check,
710 .info = &str7x_info,