2 * NVRAM variable manipulation (direct mapped flash)
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: nvram_rw.c 258972 2011-05-11 08:57:26Z $
28 #include <bcmendian.h>
35 #endif /* NFLASH_SUPPORT */
37 #include <hndsflash.h>
42 struct nvram_tuple
*_nvram_realloc(struct nvram_tuple
*t
, const char *name
, const char *value
);
43 void _nvram_free(struct nvram_tuple
*t
);
44 int _nvram_read(void *buf
, int idx
);
46 extern char *_nvram_get(const char *name
);
47 extern int _nvram_set(const char *name
, const char *value
);
48 extern int _nvram_unset(const char *name
);
49 extern int _nvram_getall(char *buf
, int count
);
50 extern int _nvram_commit(struct nvram_header
*header
);
51 extern int _nvram_init(void *si
, int idx
);
52 extern void _nvram_exit(void);
54 static struct nvram_header
*nvram_header
= NULL
;
55 static int nvram_do_reset
= FALSE
;
57 #if defined(_CFE_) && defined(BCM_DEVINFO)
58 int _nvram_hash_sync(void);
60 char *devinfo_flashdrv_nvram
= "flash0.devinfo";
62 static struct nvram_header
*devinfo_nvram_header
= NULL
;
63 static unsigned char devinfo_nvram_nvh
[MAX_NVRAM_SPACE
];
67 /* For NAND boot, flash0.nvram will be changed to nflash0.nvram */
68 char *flashdrv_nvram
= "flash0.nvram";
72 extern int kernel_initial
;
73 #define NVRAM_LOCK() cyg_scheduler_lock()
74 #define NVRAM_UNLOCK() cyg_scheduler_unlock()
76 #define NVRAM_LOCK() do {} while (0)
77 #define NVRAM_UNLOCK() do {} while (0)
82 #define MB * 1024 * 1024
84 #ifndef NVRAM_RESET_GPIO_WAIT
85 #define NVRAM_RESET_GPIO_WAIT 5000 /* in ms */
89 nvram_get(const char *name
)
99 value
= _nvram_get(name
);
106 nvram_getall(char *buf
, int count
)
111 ret
= _nvram_getall(buf
, count
);
118 BCMINITFN(nvram_set
)(const char *name
, const char *value
)
123 ret
= _nvram_set(name
, value
);
130 BCMINITFN(nvram_unset
)(const char *name
)
135 ret
= _nvram_unset(name
);
141 #define WPS_GPIO_BUTTON_VALUE "wps_button"
142 #define BCMGPIO_MAXPINS 32
145 findmatch(const char *string
, const char *name
)
151 while ((c
= strchr(string
, ',')) != NULL
) {
152 if (len
== (uint
)(c
- string
) && !strncmp(string
, name
, len
))
157 return (!strcmp(string
, name
));
161 bcmgpio_getpin(char *pin_name
)
163 char name
[] = "gpioXXXX";
167 /* Go thru all possibilities till a match in pin name */
168 for (pin
= 0; pin
< BCMGPIO_MAXPINS
; pin
++) {
169 sprintf(name
, "gpio%d", pin
);
170 val
= nvram_get(name
);
171 if (val
&& findmatch(val
, pin_name
))
179 BCMINITFN(nvram_resetgpio_init
)(void *si
)
189 value
= nvram_get("reset_gpio");
193 gpio
= (int) bcm_atoi(value
);
197 gpio
= bcmgpio_getpin(WPS_GPIO_BUTTON_VALUE
);
198 if ((gpio
> 31) || (gpio
< 0))
201 /* Setup GPIO input */
202 si_gpioouten(sih
, ((uint32
) 1 << gpio
), 0, GPIO_DRV_PRIORITY
);
208 BCMINITFN(nvram_reset
)(void *si
)
212 si_t
* sih
= (si_t
*)si
;
214 if ((gpio
= nvram_resetgpio_init((void *)sih
)) < 0)
217 /* GPIO reset is asserted low */
218 for (msec
= 0; msec
< NVRAM_RESET_GPIO_WAIT
; msec
++) {
219 if (si_gpioin(sih
) & ((uint32
) 1 << gpio
))
224 nvram_do_reset
= TRUE
;
228 #ifdef NFLASH_SUPPORT
229 static unsigned char nand_nvh
[MAX_NVRAM_SPACE
];
231 static struct nvram_header
*
232 BCMINITFN(nand_find_nvram
)(hndnand_t
*nfl
, uint32 off
)
234 int blocksize
= nfl
->blocksize
;
235 unsigned char *buf
= nand_nvh
;
236 int rlen
= sizeof(nand_nvh
);
239 for (; off
< NFL_BOOT_SIZE
; off
+= blocksize
) {
240 if (hndnand_checkbadb(nfl
, off
) != 0)
247 if (hndnand_read(nfl
, off
, len
, buf
) == 0)
253 return (struct nvram_header
*)nand_nvh
;
258 #endif /* NFLASH_SUPPORT */
260 extern unsigned char embedded_nvram
[];
262 static struct nvram_header
*
263 BCMINITFN(find_nvram
)(si_t
*sih
, bool embonly
, bool *isemb
)
265 struct nvram_header
*nvh
;
266 uint32 off
, lim
= SI_FLASH2_SZ
;
267 uint32 flbase
= SI_FLASH2
;
269 #ifdef NFLASH_SUPPORT
270 hndnand_t
*nfl_info
= NULL
;
273 hndsflash_t
*sfl_info
= NULL
;
276 bootdev
= soc_boot_dev((void *)sih
);
277 #ifdef NFLASH_SUPPORT
278 if (bootdev
== SOC_BOOTDEV_NANDFLASH
) {
279 /* Init nand anyway */
280 nfl_info
= hndnand_init(sih
);
282 flbase
= nfl_info
->phybase
;
285 #endif /* NFLASH_SUPPORT */
286 if (bootdev
== SOC_BOOTDEV_SFLASH
) {
288 /* Init nand anyway */
289 sfl_info
= hndsflash_init(sih
);
291 flbase
= sfl_info
->phybase
;
292 lim
= sfl_info
->size
;
295 if (sih
->ccrev
== 42)
296 flbase
= SI_NS_NORFLASH
;
302 #ifdef NFLASH_SUPPORT
306 blocksize
= nfl_info
->blocksize
;
308 for (; off
< NFL_BOOT_SIZE
; off
+= blocksize
) {
309 if (hndnand_checkbadb(nfl_info
, off
) != 0)
311 nvh
= (struct nvram_header
*)OSL_UNCACHED(flbase
+ off
);
312 if (nvh
->magic
!= NVRAM_MAGIC
)
315 /* Read into the nand_nvram */
316 if ((nvh
= nand_find_nvram(nfl_info
, off
)) == NULL
)
318 if (nvram_calc_crc(nvh
) == (uint8
)nvh
->crc_ver_init
)
323 #endif /* NFLASH_SUPPORT */
327 nvh
= (struct nvram_header
*)
328 OSL_UNCACHED(flbase
+ off
- MAX_NVRAM_SPACE
);
329 if (nvh
->magic
== NVRAM_MAGIC
) {
330 if (nvram_calc_crc(nvh
) == (uint8
) nvh
->crc_ver_init
) {
338 printf("find_nvram: nvram not found, trying embedded nvram next\n");
343 * Provide feedback to user when nvram corruption detected.
344 * Must be non-BCMDBG for customer release.
346 printf("Corrupt NVRAM found, trying embedded NVRAM next.\n");
348 /* Now check embedded nvram */
350 nvh
= (struct nvram_header
*)OSL_UNCACHED(flbase
+ (4 * 1024));
351 if (nvh
->magic
== NVRAM_MAGIC
)
353 nvh
= (struct nvram_header
*)OSL_UNCACHED(flbase
+ 1024);
354 if (nvh
->magic
== NVRAM_MAGIC
)
357 nvh
= (struct nvram_header
*)embedded_nvram
;
358 if (nvh
->magic
== NVRAM_MAGIC
)
361 printf("find_nvram: no nvram found\n");
366 BCMATTACHFN(nvram_init
)(void *si
)
371 static int nvram_status
= -1;
378 /* Check for previous 'restore defaults' condition */
379 if (nvram_status
== 1)
382 /* Check whether nvram already initilized */
383 if (nvram_status
== 0 && !nvram_do_reset
)
388 /* Restore defaults from embedded NVRAM if button held down */
389 if (nvram_do_reset
) {
390 /* Initialize with embedded NVRAM */
391 nvram_header
= find_nvram(sih
, TRUE
, &isemb
);
392 ret
= _nvram_init(si
, 0);
402 nvram_header
= find_nvram(sih
, FALSE
, &isemb
);
403 ret
= _nvram_init(si
, 0);
405 /* Restore defaults if embedded NVRAM used */
406 if (nvram_header
&& isemb
) {
415 BCMINITFN(nvram_append
)(void *si
, char *vars
, uint varsz
)
421 BCMINITFN(nvram_exit
)(void *si
)
430 /* LZMA need to be able to allocate memory,
431 * so set it up to use the OSL memory routines,
432 * only the linux debug osl uses the osh on malloc and the osh and size on
433 * free, and the debug code checks if they are valid, so pass NULL as the osh
434 * to tell the OSL that we don't have a valid osh
436 static void *SzAlloc(void *p
, size_t size
) { p
= p
; return MALLOC(NULL
, size
); }
437 static void SzFree(void *p
, void *address
) { p
= p
; MFREE(NULL
, address
, 0); }
438 static ISzAlloc g_Alloc
= { SzAlloc
, SzFree
};
441 BCMINITFN(_nvram_read
)(void *buf
, int idx
)
447 return -19; /* -ENODEV */
449 #if defined(_CFE_) && defined(BCM_DEVINFO)
450 if ((!devinfo_nvram_header
) && (idx
== 1)) {
451 return -19; /* -ENODEV */
454 src
= idx
== 0 ? (uint32
*) nvram_header
: (uint32
*) devinfo_nvram_nvh
;
456 src
= (uint32
*) nvram_header
;
459 dst
= (uint32
*) buf
;
461 for (i
= 0; i
< sizeof(struct nvram_header
); i
+= 4)
464 /* Since we know what the first 3 bytes of the lzma properties
465 * should be based on what we used to compress, check them
466 * to see if we need to decompress (uncompressed this would show up a
467 * a single [ and then the end of nvram marker so its invalid in an
468 * uncompressed nvram block
470 if ((((unsigned char *)src
)[0] == 0x5d) &&
471 (((unsigned char *)src
)[1] == 0) &&
472 (((unsigned char *)src
)[2] == 0)) {
473 unsigned int dstlen
= nvram_header
->len
;
474 unsigned int srclen
= MAX_NVRAM_SPACE
-LZMA_PROPS_SIZE
-NVRAM_HEADER_SIZE
;
475 unsigned char *cp
= (unsigned char *)src
;
480 LzmaDec_Construct(&state
);
481 res
= LzmaDec_Allocate(&state
, cp
, LZMA_PROPS_SIZE
, &g_Alloc
);
483 printf("Error Initializing LZMA Library\n");
486 LzmaDec_Init(&state
);
487 res
= LzmaDec_DecodeToBuf(&state
,
488 (unsigned char *)dst
, &dstlen
,
489 &cp
[LZMA_PROPS_SIZE
], &srclen
,
493 LzmaDec_Free(&state
, &g_Alloc
);
495 printf("Error Decompressing eNVRAM\n");
499 for (; i
< nvram_header
->len
&& i
< MAX_NVRAM_SPACE
; i
+= 4)
500 *dst
++ = ltoh32(*src
++);
506 BCMINITFN(_nvram_realloc
)(struct nvram_tuple
*t
, const char *name
, const char *value
)
508 if (!(t
= MALLOC(NULL
, sizeof(struct nvram_tuple
) + strlen(name
) + 1 +
509 strlen(value
) + 1))) {
510 printf("_nvram_realloc: our of memory\n");
515 t
->name
= (char *) &t
[1];
516 strcpy(t
->name
, name
);
519 t
->value
= t
->name
+ strlen(name
) + 1;
520 strcpy(t
->value
, value
);
526 BCMINITFN(_nvram_free
)(struct nvram_tuple
*t
)
529 MFREE(NULL
, t
, sizeof(struct nvram_tuple
) + strlen(t
->name
) + 1 +
530 strlen(t
->value
) + 1);
535 BCMINITFN(nvram_reinit_hash
)(void)
537 struct nvram_header
*header
;
540 if (!(header
= (struct nvram_header
*) MALLOC(NULL
, MAX_NVRAM_SPACE
))) {
541 printf("nvram_reinit_hash: out of memory\n");
542 return -12; /* -ENOMEM */
547 /* Regenerate NVRAM */
548 ret
= _nvram_commit(header
);
551 MFREE(NULL
, header
, MAX_NVRAM_SPACE
);
557 BCMINITFN(nvram_commit_internal
)(bool nvram_corrupt
)
559 struct nvram_header
*header
;
564 if (!(header
= (struct nvram_header
*) MALLOC(NULL
, MAX_NVRAM_SPACE
))) {
565 printf("nvram_commit: out of memory\n");
566 return -12; /* -ENOMEM */
571 /* Regenerate NVRAM */
572 ret
= _nvram_commit(header
);
576 src
= (uint32
*) &header
[1];
579 for (i
= sizeof(struct nvram_header
); i
< header
->len
&& i
< MAX_NVRAM_SPACE
; i
+= 4)
580 *dst
++ = htol32(*src
++);
583 if ((ret
= cfe_open(flashdrv_nvram
)) >= 0) {
585 printf("Corrupting NVRAM...\n");
586 header
->magic
= NVRAM_INVALID_MAGIC
;
588 cfe_writeblk(ret
, 0, (unsigned char *) header
, header
->len
);
592 if (sysFlashInit(NULL
) == 0) {
593 /* set/write invalid MAGIC # (in case writing image fails/is interrupted)
594 * write the NVRAM image to flash(with invalid magic)
595 * set/write valid MAGIC #
597 header
->magic
= NVRAM_CLEAR_MAGIC
;
598 nvWriteChars((unsigned char *)&header
->magic
, sizeof(header
->magic
));
600 header
->magic
= NVRAM_INVALID_MAGIC
;
601 nvWrite((unsigned short *) header
, MAX_NVRAM_SPACE
);
603 header
->magic
= NVRAM_MAGIC
;
604 nvWriteChars((unsigned char *)&header
->magic
, sizeof(header
->magic
));
606 #endif /* ifdef _CFE_ */
610 MFREE(NULL
, header
, MAX_NVRAM_SPACE
);
615 BCMINITFN(nvram_commit
)(void)
617 /* do not corrupt nvram */
618 return nvram_commit_internal(FALSE
);
621 #if defined(_CFE_) && defined(BCM_DEVINFO)
622 static struct nvram_header
*
623 BCMINITFN(find_devinfo_nvram
)(si_t
*sih
)
627 if (devinfo_nvram_header
!= NULL
) {
628 return (devinfo_nvram_header
);
631 if ((cfe_fd
= cfe_open(devinfo_flashdrv_nvram
)) < 0) {
635 ret
= cfe_read(cfe_fd
, (unsigned char *)devinfo_nvram_nvh
, NVRAM_SPACE
);
637 devinfo_nvram_header
= (struct nvram_header
*) devinfo_nvram_nvh
;
642 return (devinfo_nvram_header
);
646 BCMINITFN(devinfo_nvram_init
)(void *si
)
649 si_t
*sih
= (si_t
*)si
;
651 nvram_header
= find_devinfo_nvram(sih
);
652 _nvram_hash_select(1);
653 ret
= _nvram_init(si
, 1);
654 _nvram_hash_select(0);
659 /* sync nvram hash table with devinfo nvram hash table, and commit nvram */
661 BCMINITFN(devinfo_nvram_sync
)(void)
668 #endif /* _CFE_ && BCM_DEVINFO */