xref: /openbmc/u-boot/env/onenand.c (revision 9b643e312d528f291966c1f30b0d90bf3b1d43dc)
1  /*
2   * (C) Copyright 2010 DENX Software Engineering
3   * Wolfgang Denk <wd@denx.de>
4   *
5   * (C) Copyright 2005-2009 Samsung Electronics
6   * Kyungmin Park <kyungmin.park@samsung.com>
7   *
8   * SPDX-License-Identifier:	GPL-2.0+
9   */
10  
11  #include <common.h>
12  #include <command.h>
13  #include <environment.h>
14  #include <linux/stddef.h>
15  #include <malloc.h>
16  #include <search.h>
17  #include <errno.h>
18  #include <onenand_uboot.h>
19  
20  #include <linux/compat.h>
21  #include <linux/mtd/mtd.h>
22  #include <linux/mtd/onenand.h>
23  
24  #define ONENAND_MAX_ENV_SIZE	CONFIG_ENV_SIZE
25  #define ONENAND_ENV_SIZE(mtd)	(ONENAND_MAX_ENV_SIZE - ENV_HEADER_SIZE)
26  
27  DECLARE_GLOBAL_DATA_PTR;
28  
29  static int env_onenand_load(void)
30  {
31  	struct mtd_info *mtd = &onenand_mtd;
32  #ifdef CONFIG_ENV_ADDR_FLEX
33  	struct onenand_chip *this = &onenand_chip;
34  #endif
35  	int rc;
36  	size_t retlen;
37  #ifdef ENV_IS_EMBEDDED
38  	char *buf = (char *)&environment;
39  #else
40  	loff_t env_addr = CONFIG_ENV_ADDR;
41  	char onenand_env[ONENAND_MAX_ENV_SIZE];
42  	char *buf = (char *)&onenand_env[0];
43  #endif /* ENV_IS_EMBEDDED */
44  
45  #ifndef ENV_IS_EMBEDDED
46  # ifdef CONFIG_ENV_ADDR_FLEX
47  	if (FLEXONENAND(this))
48  		env_addr = CONFIG_ENV_ADDR_FLEX;
49  # endif
50  	/* Check OneNAND exist */
51  	if (mtd->writesize)
52  		/* Ignore read fail */
53  		mtd_read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
54  				&retlen, (u_char *)buf);
55  	else
56  		mtd->writesize = MAX_ONENAND_PAGESIZE;
57  #endif /* !ENV_IS_EMBEDDED */
58  
59  	rc = env_import(buf, 1);
60  	if (rc)
61  		gd->env_valid = ENV_VALID;
62  
63  	return rc ? 0 : -EIO;
64  }
65  
66  static int env_onenand_save(void)
67  {
68  	env_t	env_new;
69  	int ret;
70  	struct mtd_info *mtd = &onenand_mtd;
71  #ifdef CONFIG_ENV_ADDR_FLEX
72  	struct onenand_chip *this = &onenand_chip;
73  #endif
74  	loff_t	env_addr = CONFIG_ENV_ADDR;
75  	size_t	retlen;
76  	struct erase_info instr = {
77  		.callback	= NULL,
78  	};
79  
80  	ret = env_export(&env_new);
81  	if (ret)
82  		return ret;
83  
84  	instr.len = CONFIG_ENV_SIZE;
85  #ifdef CONFIG_ENV_ADDR_FLEX
86  	if (FLEXONENAND(this)) {
87  		env_addr = CONFIG_ENV_ADDR_FLEX;
88  		instr.len = CONFIG_ENV_SIZE_FLEX;
89  		instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ?
90  				1 : 0;
91  	}
92  #endif
93  	instr.addr = env_addr;
94  	instr.mtd = mtd;
95  	if (mtd_erase(mtd, &instr)) {
96  		printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
97  		return 1;
98  	}
99  
100  	if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
101  			(u_char *)&env_new)) {
102  		printf("OneNAND: write failed at 0x%llx\n", instr.addr);
103  		return 2;
104  	}
105  
106  	return 0;
107  }
108  
109  U_BOOT_ENV_LOCATION(onenand) = {
110  	.location	= ENVL_ONENAND,
111  	ENV_NAME("OneNAND")
112  	.load		= env_onenand_load,
113  	.save		= env_save_ptr(env_onenand_save),
114  };
115