1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <environment.h> 8 #include <memalign.h> 9 #include <boot_rkimg.h> 10 11 #define __STR(X) #X 12 #define STR(X) __STR(X) 13 14 #if defined(CONFIG_ENV_SIZE_REDUND) && \ 15 (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE) 16 #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE 17 #endif 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 int get_env_addr(struct blk_desc *blk_desc, int copy, u32 *env_addr) 22 { 23 s64 offset = CONFIG_ENV_OFFSET; 24 25 #if defined(CONFIG_ENV_OFFSET_REDUND) 26 if (copy) 27 offset = CONFIG_ENV_OFFSET_REDUND; 28 #endif 29 if (offset < 0) 30 return -EINVAL; 31 32 *env_addr = offset; 33 34 return 0; 35 } 36 37 int get_env_dev(void) 38 { 39 return CONFIG_SYS_MMC_ENV_DEV; 40 } 41 42 #ifdef CONFIG_SYS_MMC_ENV_PART 43 static unsigned char env_org_hwpart; 44 45 int get_env_part(void) 46 { 47 return CONFIG_SYS_MMC_ENV_PART; 48 } 49 50 static const char *init_blk_hwpart_for_env(struct blk_desc *blk_desc) 51 { 52 enum if_type if_type; 53 const char *devtype; 54 int devnum, devpart, ret; 55 56 devtype = env_get("devtype"); 57 devnum = env_get_ulong("devnum", 10, 0); 58 devpart = get_env_part(); 59 if_type = if_typename_to_iftype(devtype); 60 61 env_org_hwpart = blk_desc->hwpart; 62 ret = blk_select_hwpart_devnum(if_type, devnum, devpart); 63 if (ret) 64 return "!Partition switch failed"; 65 66 return NULL; 67 } 68 69 static void fini_blk_hwpart_for_env(void) 70 { 71 enum if_type if_type; 72 const char *devtype; 73 int devnum; 74 75 devtype = env_get("devtype"); 76 devnum = env_get_ulong("devnum", 10, 0); 77 if_type = if_typename_to_iftype(devtype); 78 79 blk_select_hwpart_devnum(if_type, devnum, env_org_hwpart); 80 } 81 #else 82 static inline const char *init_blk_hwpart_for_env(struct blk_desc *blk_desc) 83 { return NULL; } 84 static inline void fini_blk_hwpart_for_env(void) {} 85 #endif 86 87 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD) 88 static inline int write_env(struct blk_desc *blk_desc, unsigned long size, 89 unsigned long offset, const void *buffer) 90 { 91 uint blk_start, blk_cnt, n; 92 93 blk_start = ALIGN(offset, blk_desc->blksz) / blk_desc->blksz; 94 blk_cnt = ALIGN(size, blk_desc->blksz) / blk_desc->blksz; 95 96 n = blk_dwrite(blk_desc, blk_start, blk_cnt, (u_char *)buffer); 97 98 return (n == blk_cnt) ? 0 : -1; 99 } 100 101 static int env_blk_save(void) 102 { 103 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); 104 struct blk_desc *blk_desc; 105 const char *errmsg = NULL; 106 int ret, copy = 0; 107 u32 offset; 108 109 blk_desc = rockchip_get_bootdev(); 110 if (!blk_desc) { 111 puts("Can't find bootdev\n"); 112 return -EIO; 113 } 114 115 errmsg = init_blk_hwpart_for_env(blk_desc); 116 if (errmsg) { 117 puts(errmsg); 118 return -EIO; 119 } 120 121 ret = env_export(env_new); 122 if (ret) 123 goto fini; 124 125 #ifdef CONFIG_ENV_OFFSET_REDUND 126 if (gd->env_valid == ENV_VALID) 127 copy = 1; 128 #endif 129 130 if (get_env_addr(blk_desc, copy, &offset)) { 131 ret = 1; 132 goto fini; 133 } 134 135 printf("Writing to %s%s(%s)... ", copy ? "redundant " : "", 136 env_get("devtype"), env_get("devnum")); 137 138 if (write_env(blk_desc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) { 139 puts("failed\n"); 140 ret = 1; 141 goto fini; 142 } 143 144 puts("done\n"); 145 ret = 0; 146 147 #ifdef CONFIG_ENV_OFFSET_REDUND 148 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND; 149 #endif 150 151 fini: 152 fini_blk_hwpart_for_env(); 153 154 return ret; 155 } 156 #endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */ 157 158 static inline int read_env(struct blk_desc *blk_desc, unsigned long size, 159 unsigned long offset, const void *buffer) 160 { 161 uint blk_start, blk_cnt, n; 162 163 blk_start = ALIGN(offset, blk_desc->blksz) / blk_desc->blksz; 164 blk_cnt = ALIGN(size, blk_desc->blksz) / blk_desc->blksz; 165 166 n = blk_dread(blk_desc, blk_start, blk_cnt, (uchar *)buffer); 167 168 return (n == blk_cnt) ? 0 : -1; 169 } 170 171 #ifdef CONFIG_ENV_OFFSET_REDUND 172 static int env_blk_load(void) 173 { 174 #if !defined(ENV_IS_EMBEDDED) 175 struct blk_desc *blk_desc; 176 const char *errmsg = NULL; 177 int read1_fail = 0, read2_fail = 0; 178 u32 offset1, offset2; 179 int ret; 180 181 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1); 182 ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1); 183 184 blk_desc = rockchip_get_bootdev(); 185 if (!blk_desc) { 186 puts("Can't find bootdev\n"); 187 return -EIO; 188 } 189 190 errmsg = init_blk_hwpart_for_env(blk_desc); 191 if (errmsg) { 192 ret = -EIO; 193 goto err; 194 } 195 196 if (get_env_addr(blk_desc, 0, &offset1) || 197 get_env_addr(blk_desc, 1, &offset2)) { 198 ret = -EIO; 199 goto fini; 200 } 201 202 read1_fail = read_env(blk_desc, CONFIG_ENV_SIZE, offset1, tmp_env1); 203 read2_fail = read_env(blk_desc, CONFIG_ENV_SIZE, offset2, tmp_env2); 204 205 if (read1_fail && read2_fail) 206 puts("*** Error - No Valid Environment Area found\n"); 207 else if (read1_fail || read2_fail) 208 puts("*** Warning - some problems detected " 209 "reading environment; recovered successfully\n"); 210 211 if (read1_fail && read2_fail) { 212 errmsg = "!bad CRC"; 213 ret = -EIO; 214 goto fini; 215 } else if (!read1_fail && read2_fail) { 216 gd->env_valid = ENV_VALID; 217 env_import((char *)tmp_env1, 1); 218 } else if (read1_fail && !read2_fail) { 219 gd->env_valid = ENV_REDUND; 220 env_import((char *)tmp_env2, 1); 221 } else { 222 env_import_redund((char *)tmp_env1, (char *)tmp_env2); 223 } 224 225 ret = 0; 226 227 fini: 228 fini_blk_hwpart_for_env(); 229 err: 230 if (ret) 231 set_default_env(errmsg); 232 233 #endif 234 return ret; 235 } 236 #else /* ! CONFIG_ENV_OFFSET_REDUND */ 237 static int env_blk_load(void) 238 { 239 #if !defined(ENV_IS_EMBEDDED) 240 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); 241 struct blk_desc *blk_desc; 242 const char *errmsg = NULL; 243 u32 offset; 244 int ret; 245 246 blk_desc = rockchip_get_bootdev(); 247 if (!blk_desc) { 248 puts("Can't find bootdev\n"); 249 return -EIO; 250 } 251 252 errmsg = init_blk_hwpart_for_env(blk_desc); 253 if (errmsg) { 254 ret = -EIO; 255 puts(errmsg); 256 goto err; 257 } 258 259 if (get_env_addr(blk_desc, 0, &offset)) { 260 ret = -EIO; 261 goto fini; 262 } 263 264 if (read_env(blk_desc, CONFIG_ENV_SIZE, offset, buf)) { 265 errmsg = "!read failed"; 266 ret = -EIO; 267 goto fini; 268 } 269 270 env_import(buf, 1); 271 ret = 0; 272 273 fini: 274 fini_blk_hwpart_for_env(); 275 err: 276 if (ret) 277 set_default_env(errmsg); 278 #endif 279 return ret; 280 } 281 #endif /* CONFIG_ENV_OFFSET_REDUND */ 282 283 U_BOOT_ENV_LOCATION(env_blk) = { 284 .location = ENVL_BLK, 285 ENV_NAME("ENV_BLK") 286 .load = env_blk_load, 287 #ifndef CONFIG_SPL_BUILD 288 .save = env_save_ptr(env_blk_save), 289 #endif 290 }; 291