1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2008 4 * Heiko Schocher, DENX Software Engineering, hs@denx.de. 5 * 6 * (C) Copyright 2011 7 * Holger Brunck, Keymile GmbH Hannover, holger.brunck@keymile.com 8 */ 9 10#include <common.h> 11#include <env.h> 12#include <ioports.h> 13#include <command.h> 14#include <malloc.h> 15#include <cli_hush.h> 16#include <net.h> 17#include <netdev.h> 18#include <asm/global_data.h> 19#include <asm/io.h> 20#include <linux/ctype.h> 21#include <linux/delay.h> 22#include <linux/bug.h> 23#include <bootcount.h> 24 25#if defined(CONFIG_POST) 26#include "post.h" 27#endif 28#include "common.h" 29#include <i2c.h> 30 31DECLARE_GLOBAL_DATA_PTR; 32 33/* 34 * Set Keymile specific environment variables 35 * Currently only some memory layout variables are calculated here 36 * ... ------------------------------------------------ 37 * ... |@rootfsaddr |@pnvramaddr |@varaddr |@reserved |@END_OF_RAM 38 * ... |<------------------- pram ------------------->| 39 * ... ------------------------------------------------ 40 * @END_OF_RAM: denotes the RAM size 41 * @pnvramaddr: Startadress of pseudo non volatile RAM in hex 42 * @pram : preserved ram size in k 43 * @varaddr : startadress for /var mounted into RAM 44 */ 45int set_km_env(void) 46{ 47 unsigned int pnvramaddr; 48 unsigned int pram; 49 unsigned int varaddr; 50 unsigned int kernelmem; 51 unsigned long rootfssize = 0; 52 char envval[16]; 53 char *p; 54 55 pnvramaddr = CFG_SYS_SDRAM_BASE + gd->ram_size - 56 CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM - CONFIG_KM_PNVRAM; 57 sprintf(envval, "0x%x", pnvramaddr); 58 env_set("pnvramaddr", envval); 59 60 /* try to read rootfssize (ram image) from environment */ 61 p = env_get("rootfssize"); 62 if (p) 63 strict_strtoul(p, 16, &rootfssize); 64 pram = (rootfssize + CONFIG_KM_RESERVED_PRAM + CONFIG_KM_PHRAM + 65 CONFIG_KM_PNVRAM) / 0x400; 66 env_set_ulong("pram", pram); 67 68 varaddr = CFG_SYS_SDRAM_BASE + gd->ram_size - 69 CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM; 70 env_set_hex("varaddr", varaddr); 71 sprintf(envval, "0x%x", varaddr); 72 env_set("varaddr", envval); 73 74 kernelmem = gd->ram_size - 0x400 * pram; 75 sprintf(envval, "0x%x", kernelmem); 76 env_set("kernelmem", envval); 77 78 return 0; 79} 80 81#if IS_ENABLED(CONFIG_PG_WCOM_UBOOT_UPDATE_SUPPORTED) 82#if ((!IS_ENABLED(CONFIG_PG_WCOM_UBOOT_BOOTPACKAGE) && \ 83 !IS_ENABLED(CONFIG_PG_WCOM_UBOOT_UPDATE)) || \ 84 (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_BOOTPACKAGE) && \ 85 IS_ENABLED(CONFIG_PG_WCOM_UBOOT_UPDATE))) 86#error "It has to be either bootpackage or update u-boot image!" 87#endif 88void check_for_uboot_update(void) 89{ 90 void (*uboot_update_entry)(void) = 91 (void (*)(void)) CONFIG_PG_WCOM_UBOOT_UPDATE_TEXT_BASE; 92 char *isupdated = env_get("updateduboot"); 93 ulong bootcount = bootcount_load(); 94 ulong ebootcount = 0; 95 96 if (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_BOOTPACKAGE)) { 97 /* 98 * When running in factory burned u-boot move to the updated 99 * u-boot version only if updateduboot envvar is set to 'yes' 100 * and bootcount limit is not exceeded. 101 * Board must be able to start in factory bootloader mode! 102 */ 103 if (isupdated && !strncmp(isupdated, "yes", 3) && 104 bootcount <= CONFIG_BOOTCOUNT_BOOTLIMIT) { 105 printf("Check update: update detected, "); 106 printf("starting new image @%08x ...\n", 107 CONFIG_PG_WCOM_UBOOT_UPDATE_TEXT_BASE); 108 ebootcount = early_bootcount_load(); 109 if (ebootcount <= CONFIG_BOOTCOUNT_BOOTLIMIT) { 110 early_bootcount_store(++ebootcount); 111 uboot_update_entry(); 112 } else { 113 printf("Check update: warning: "); 114 printf("early bootcount exceeded (%lu)\n", 115 ebootcount); 116 } 117 } 118 printf("Check update: starting factory image @%08x ...\n", 119 CONFIG_TEXT_BASE); 120 } else if (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_UPDATE)) { 121 /* 122 * When running in field updated u-boot, make sure that 123 * bootcount limit is never exceeded. Must never happen! 124 */ 125 WARN_ON(bootcount > CONFIG_BOOTCOUNT_BOOTLIMIT); 126 printf("Check update: updated u-boot starting @%08x ...\n", 127 CONFIG_TEXT_BASE); 128 } 129} 130#endif 131 132#if defined(CONFIG_SYS_I2C_INIT_BOARD) 133static void i2c_write_start_seq(void) 134{ 135 set_sda(1); 136 udelay(DELAY_HALF_PERIOD); 137 set_scl(1); 138 udelay(DELAY_HALF_PERIOD); 139 set_sda(0); 140 udelay(DELAY_HALF_PERIOD); 141 set_scl(0); 142 udelay(DELAY_HALF_PERIOD); 143} 144 145/* 146 * I2C is a synchronous protocol and resets of the processor in the middle 147 * of an access can block the I2C Bus until a powerdown of the full unit is 148 * done. This function toggles the SCL until the SCL and SCA line are 149 * released, but max. 16 times, after this a I2C start-sequence is sent. 150 * This I2C Deblocking mechanism was developed by Keymile in association 151 * with Anatech and Atmel in 1998. 152 */ 153int i2c_make_abort(void) 154{ 155 int scl_state = 0; 156 int sda_state = 0; 157 int i = 0; 158 int ret = 0; 159 160 if (!get_sda()) { 161 ret = -1; 162 while (i < 16) { 163 i++; 164 set_scl(0); 165 udelay(DELAY_ABORT_SEQ); 166 set_scl(1); 167 udelay(DELAY_ABORT_SEQ); 168 scl_state = get_scl(); 169 sda_state = get_sda(); 170 if (scl_state && sda_state) { 171 ret = 0; 172 break; 173 } 174 } 175 } 176 if (ret == 0) 177 for (i = 0; i < 5; i++) 178 i2c_write_start_seq(); 179 180 /* respect stop setup time */ 181 udelay(DELAY_ABORT_SEQ); 182 set_scl(1); 183 udelay(DELAY_ABORT_SEQ); 184 set_sda(1); 185 get_sda(); 186 187 return ret; 188} 189 190/** 191 * i2c_init_board - reset i2c bus. When the board is powercycled during a 192 * bus transfer it might hang; for details see doc/I2C_Edge_Conditions. 193 */ 194void i2c_init_board(void) 195{ 196 /* Now run the AbortSequence() */ 197 i2c_make_abort(); 198} 199#endif 200 201#if defined(CONFIG_KM_COMMON_ETH_INIT) 202int board_eth_init(struct bd_info *bis) 203{ 204 if (ethernet_present()) 205 return cpu_eth_init(bis); 206 207 return -1; 208} 209#endif 210 211/* 212 * do_setboardid command 213 * read out the board id and the hw key from the intventory EEPROM and set 214 * this values as environment variables. 215 */ 216static int do_setboardid(struct cmd_tbl *cmdtp, int flag, int argc, 217 char *const argv[]) 218{ 219 unsigned char buf[32]; 220 char *p; 221 222 p = get_local_var("IVM_BoardId"); 223 if (!p) { 224 printf("can't get the IVM_Boardid\n"); 225 return 1; 226 } 227 strcpy((char *)buf, p); 228 env_set("boardid", (char *)buf); 229 printf("set boardid=%s\n", buf); 230 231 p = get_local_var("IVM_HWKey"); 232 if (!p) { 233 printf("can't get the IVM_HWKey\n"); 234 return 1; 235 } 236 strcpy((char *)buf, p); 237 env_set("hwkey", (char *)buf); 238 printf("set hwkey=%s\n", buf); 239 printf("Execute manually saveenv for persistent storage.\n"); 240 241 return 0; 242} 243 244U_BOOT_CMD(km_setboardid, 1, 0, do_setboardid, "setboardid", 245 "read out bid and hwkey from IVM and set in environment"); 246 247/* 248 * command km_checkbidhwk 249 * if "boardid" and "hwkey" are not already set in the environment, do: 250 * if a "boardIdListHex" exists in the environment: 251 * - read ivm data for boardid and hwkey 252 * - compare each entry of the boardIdListHex with the 253 * IVM data: 254 * if match: 255 * set environment variables boardid, boardId, 256 * hwkey, hwKey to the found values 257 * both (boardid and boardId) are set because 258 * they might be used differently in the 259 * application and in the init scripts (?) 260 * return 0 in case of match, 1 if not match or error 261 */ 262static int do_checkboardidhwk(struct cmd_tbl *cmdtp, int flag, int argc, 263 char *const argv[]) 264{ 265 unsigned long ivmbid = 0, ivmhwkey = 0; 266 unsigned long envbid = 0, envhwkey = 0; 267 char *p; 268 int verbose = argc > 1 && *argv[1] == 'v'; 269 int rc = 0; 270 271 /* 272 * first read out the real inventory values, these values are 273 * already stored in the local hush variables 274 */ 275 p = get_local_var("IVM_BoardId"); 276 if (!p) { 277 printf("can't get the IVM_Boardid\n"); 278 return 1; 279 } 280 rc = strict_strtoul(p, 16, &ivmbid); 281 282 p = get_local_var("IVM_HWKey"); 283 if (!p) { 284 printf("can't get the IVM_HWKey\n"); 285 return 1; 286 } 287 rc = strict_strtoul(p, 16, &ivmhwkey); 288 289 if (!ivmbid || !ivmhwkey) { 290 printf("Error: IVM_BoardId and/or IVM_HWKey not set!\n"); 291 return rc; 292 } 293 294 /* now try to read values from environment if available */ 295 p = env_get("boardid"); 296 if (p) 297 rc = strict_strtoul(p, 16, &envbid); 298 p = env_get("hwkey"); 299 if (p) 300 rc = strict_strtoul(p, 16, &envhwkey); 301 if (rc != 0) { 302 printf("strict_strtoul returns error: %d", rc); 303 return rc; 304 } 305 306 if (!envbid || !envhwkey) { 307 /* 308 * BoardId/HWkey not available in the environment, so try the 309 * environment variable for BoardId/HWkey list 310 */ 311 char *bidhwklist = env_get("boardIdListHex"); 312 313 if (bidhwklist) { 314 int found = 0; 315 char *rest = bidhwklist; 316 char *endp; 317 318 if (verbose) { 319 printf("IVM_BoardId: %ld, IVM_HWKey=%ld\n", 320 ivmbid, ivmhwkey); 321 printf("boardIdHwKeyList: %s\n", bidhwklist); 322 } 323 while (!found) { 324 /* loop over each bid/hwkey pair in the list */ 325 unsigned long bid = 0; 326 unsigned long hwkey = 0; 327 328 while (*rest && !isxdigit(*rest)) 329 rest++; 330 /* 331 * use simple_strtoul because we need &end and 332 * we know we got non numeric char at the end 333 */ 334 bid = hextoul(rest, &endp); 335 /* BoardId and HWkey are separated with a "_" */ 336 if (*endp == '_') { 337 rest = endp + 1; 338 /* 339 * use simple_strtoul because we need 340 * &end 341 */ 342 hwkey = hextoul(rest, &endp); 343 rest = endp; 344 while (*rest && !isxdigit(*rest)) 345 rest++; 346 } 347 if (!bid || !hwkey) { 348 /* end of list */ 349 break; 350 } 351 if (verbose) { 352 printf("trying bid=0x%lX, hwkey=%ld\n", 353 bid, hwkey); 354 } 355 /* 356 * Compare the values of the found entry in the 357 * list with the valid values which are stored 358 * in the inventory eeprom. If they are equal 359 * set the values in environment variables. 360 */ 361 if (bid == ivmbid && hwkey == ivmhwkey) { 362 found = 1; 363 envbid = bid; 364 envhwkey = hwkey; 365 env_set_hex("boardid", bid); 366 env_set_hex("hwkey", hwkey); 367 } 368 } /* end while( ! found ) */ 369 } 370 } 371 372 /* compare now the values */ 373 if (ivmbid == envbid && ivmhwkey == envhwkey) { 374 printf("boardid=0x%3lX, hwkey=%ld\n", envbid, envhwkey); 375 rc = 0; /* match */ 376 } else { 377 printf("Error: env boardid=0x%3lX, hwkey=%ld\n", envbid, 378 envhwkey); 379 printf(" IVM bId=0x%3lX, hwKey=%ld\n", ivmbid, ivmhwkey); 380 rc = 1; /* don't match */ 381 } 382 return rc; 383} 384 385U_BOOT_CMD(km_checkbidhwk, 2, 0, do_checkboardidhwk, 386 "check boardid and hwkey", 387 "[v]\n - check environment parameter \"boardIdListHex\" against stored boardid and hwkey from the IVM\n v: verbose output" 388); 389 390/* 391 * command km_checktestboot 392 * if the testpin of the board is asserted, return 1 393 * * else return 0 394 */ 395static int do_checktestboot(struct cmd_tbl *cmdtp, int flag, int argc, 396 char *const argv[]) 397{ 398 int testpin = 0; 399 char *s = NULL; 400 int testboot = 0; 401 int verbose = argc > 1 && *argv[1] == 'v'; 402 403#if defined(CONFIG_POST) 404 testpin = post_hotkeys_pressed(); 405#endif 406 407 s = env_get("test_bank"); 408 /* when test_bank is not set, act as if testpin is not asserted */ 409 testboot = (testpin != 0) && (s); 410 if (verbose) { 411 printf("testpin = %d\n", testpin); 412 /* cppcheck-suppress nullPointer */ 413 printf("test_bank = %s\n", s ? s : "not set"); 414 printf("boot test app : %s\n", (testboot) ? "yes" : "no"); 415 } 416 /* return 0 means: testboot, therefore we need the inversion */ 417 return !testboot; 418} 419 420U_BOOT_CMD(km_checktestboot, 2, 0, do_checktestboot, 421 "check if testpin is asserted", 422 "[v]\n v - verbose output" 423); 424