blob: 2ce7462c56f54ccccc8caa4348b657142dd3e87a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Heiko Schocher5e51b482008-10-15 09:39:08 +02002/*
3 * (C) Copyright 2008
4 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
5 *
Holger Brunckbf20a882011-06-05 22:22:18 +00006 * (C) Copyright 2011
7 * Holger Brunck, Keymile GmbH Hannover, holger.brunck@keymile.com
Heiko Schocher5e51b482008-10-15 09:39:08 +02008 */
9
10#include <common.h>
Simon Glass5e6201b2019-08-01 09:46:51 -060011#include <env.h>
Heiko Schocher5e51b482008-10-15 09:39:08 +020012#include <ioports.h>
Holger Brunck30664922011-05-04 01:47:30 +000013#include <command.h>
Heiko Schocher5e51b482008-10-15 09:39:08 +020014#include <malloc.h>
Simon Glass299f0be2014-04-10 20:01:24 -060015#include <cli_hush.h>
Heiko Schocherd19a6ec2008-11-21 08:29:40 +010016#include <net.h>
Heiko Schocher466924f2010-02-18 08:08:25 +010017#include <netdev.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060018#include <asm/global_data.h>
Heiko Schocherd19a6ec2008-11-21 08:29:40 +010019#include <asm/io.h>
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +000020#include <linux/ctype.h>
Simon Glassdbd79542020-05-10 11:40:11 -060021#include <linux/delay.h>
Heiko Schocher5e51b482008-10-15 09:39:08 +020022
Thomas Herzmannb2c31602012-05-04 10:55:58 +020023#if defined(CONFIG_POST)
24#include "post.h"
25#endif
Holger Brunckbf20a882011-06-05 22:22:18 +000026#include "common.h"
Heiko Schocher5e51b482008-10-15 09:39:08 +020027#include <i2c.h>
Heiko Schocher5e51b482008-10-15 09:39:08 +020028
Heiko Schochercfc58042010-04-26 13:07:28 +020029DECLARE_GLOBAL_DATA_PTR;
Heiko Schocherd9e10952011-03-08 10:51:15 +010030
Heiko Schochercfc58042010-04-26 13:07:28 +020031/*
32 * Set Keymile specific environment variables
33 * Currently only some memory layout variables are calculated here
34 * ... ------------------------------------------------
35 * ... |@rootfsaddr |@pnvramaddr |@varaddr |@reserved |@END_OF_RAM
36 * ... |<------------------- pram ------------------->|
37 * ... ------------------------------------------------
38 * @END_OF_RAM: denotes the RAM size
39 * @pnvramaddr: Startadress of pseudo non volatile RAM in hex
40 * @pram : preserved ram size in k
41 * @varaddr : startadress for /var mounted into RAM
42 */
43int set_km_env(void)
44{
Heiko Schochercfc58042010-04-26 13:07:28 +020045 unsigned int pnvramaddr;
46 unsigned int pram;
47 unsigned int varaddr;
Andreas Huber28c63c72011-09-13 23:06:11 +000048 unsigned int kernelmem;
49 char *p;
50 unsigned long rootfssize = 0;
Heiko Schochercfc58042010-04-26 13:07:28 +020051
Aleksandar Gerasimovskif9da5262021-01-19 10:41:00 +000052 pnvramaddr = CONFIG_SYS_SDRAM_BASE + gd->ram_size -
53 CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM - CONFIG_KM_PNVRAM;
Niel Fouriede553f52021-01-21 13:19:19 +010054 env_set_hex("pnvramaddr", pnvramaddr);
Heiko Schochercfc58042010-04-26 13:07:28 +020055
Robert P. J. Day8d56db92016-07-15 13:44:45 -040056 /* try to read rootfssize (ram image) from environment */
Simon Glass64b723f2017-08-03 12:22:12 -060057 p = env_get("rootfssize");
Holger Brunckff41a752020-10-30 12:45:49 +010058 if (p)
Andreas Huber28c63c72011-09-13 23:06:11 +000059 strict_strtoul(p, 16, &rootfssize);
60 pram = (rootfssize + CONFIG_KM_RESERVED_PRAM + CONFIG_KM_PHRAM +
61 CONFIG_KM_PNVRAM) / 0x400;
Niel Fouriede553f52021-01-21 13:19:19 +010062 env_set_ulong("pram", pram);
Heiko Schochercfc58042010-04-26 13:07:28 +020063
Aleksandar Gerasimovskif9da5262021-01-19 10:41:00 +000064 varaddr = CONFIG_SYS_SDRAM_BASE + gd->ram_size -
65 CONFIG_KM_RESERVED_PRAM - CONFIG_KM_PHRAM;
Niel Fouriede553f52021-01-21 13:19:19 +010066 env_set_hex("varaddr", varaddr);
Andreas Huber28c63c72011-09-13 23:06:11 +000067
68 kernelmem = gd->ram_size - 0x400 * pram;
Niel Fouriede553f52021-01-21 13:19:19 +010069 env_set_hex("kernelmem", kernelmem);
Andreas Huber28c63c72011-09-13 23:06:11 +000070
Heiko Schochercfc58042010-04-26 13:07:28 +020071 return 0;
72}
73
Holger Brunck015a60f2011-09-14 10:54:12 +020074#if defined(CONFIG_SYS_I2C_INIT_BOARD)
Heiko Schocherd9e10952011-03-08 10:51:15 +010075static void i2c_write_start_seq(void)
Heiko Schocher5e51b482008-10-15 09:39:08 +020076{
Heiko Schocher8ce3dd52011-03-15 16:52:29 +010077 set_sda(1);
78 udelay(DELAY_HALF_PERIOD);
79 set_scl(1);
80 udelay(DELAY_HALF_PERIOD);
81 set_sda(0);
82 udelay(DELAY_HALF_PERIOD);
83 set_scl(0);
84 udelay(DELAY_HALF_PERIOD);
Heiko Schocher5e51b482008-10-15 09:39:08 +020085}
86
Heiko Schocher8ce3dd52011-03-15 16:52:29 +010087/*
88 * I2C is a synchronous protocol and resets of the processor in the middle
89 * of an access can block the I2C Bus until a powerdown of the full unit is
90 * done. This function toggles the SCL until the SCL and SCA line are
91 * released, but max. 16 times, after this a I2C start-sequence is sent.
92 * This I2C Deblocking mechanism was developed by Keymile in association
93 * with Anatech and Atmel in 1998.
Heiko Schocher5e51b482008-10-15 09:39:08 +020094 */
Holger Brunckbf20a882011-06-05 22:22:18 +000095int i2c_make_abort(void)
Heiko Schocher5e51b482008-10-15 09:39:08 +020096{
97 int scl_state = 0;
98 int sda_state = 0;
99 int i = 0;
100 int ret = 0;
101
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100102 if (!get_sda()) {
Heiko Schocher5e51b482008-10-15 09:39:08 +0200103 ret = -1;
104 while (i < 16) {
105 i++;
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100106 set_scl(0);
107 udelay(DELAY_ABORT_SEQ);
108 set_scl(1);
109 udelay(DELAY_ABORT_SEQ);
110 scl_state = get_scl();
111 sda_state = get_sda();
Heiko Schocher5e51b482008-10-15 09:39:08 +0200112 if (scl_state && sda_state) {
113 ret = 0;
114 break;
115 }
116 }
117 }
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100118 if (ret == 0)
119 for (i = 0; i < 5; i++)
Heiko Schocherd9e10952011-03-08 10:51:15 +0100120 i2c_write_start_seq();
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100121
Heiko Schocherd9e10952011-03-08 10:51:15 +0100122 /* respect stop setup time */
123 udelay(DELAY_ABORT_SEQ);
124 set_scl(1);
125 udelay(DELAY_ABORT_SEQ);
126 set_sda(1);
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100127 get_sda();
Heiko Schocherd9e10952011-03-08 10:51:15 +0100128
Heiko Schocher5e51b482008-10-15 09:39:08 +0200129 return ret;
130}
Heiko Schocher5e51b482008-10-15 09:39:08 +0200131
Heiko Schocherd9e10952011-03-08 10:51:15 +0100132/**
133 * i2c_init_board - reset i2c bus. When the board is powercycled during a
134 * bus transfer it might hang; for details see doc/I2C_Edge_Conditions.
135 */
136void i2c_init_board(void)
137{
Heiko Schocher5e51b482008-10-15 09:39:08 +0200138 /* Now run the AbortSequence() */
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100139 i2c_make_abort();
Heiko Schocher5e51b482008-10-15 09:39:08 +0200140}
Holger Brunck015a60f2011-09-14 10:54:12 +0200141#endif
142
Valentin Longchamp391cc9b2013-10-18 11:47:18 +0200143#if defined(CONFIG_KM_COMMON_ETH_INIT)
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900144int board_eth_init(struct bd_info *bis)
Heiko Schocherd19a6ec2008-11-21 08:29:40 +0100145{
Heiko Schocher8ce3dd52011-03-15 16:52:29 +0100146 if (ethernet_present())
Heiko Schocher466924f2010-02-18 08:08:25 +0100147 return cpu_eth_init(bis);
148
149 return -1;
Heiko Schocherd19a6ec2008-11-21 08:29:40 +0100150}
Valentin Longchamp391cc9b2013-10-18 11:47:18 +0200151#endif
Holger Brunck30664922011-05-04 01:47:30 +0000152
153/*
154 * do_setboardid command
155 * read out the board id and the hw key from the intventory EEPROM and set
156 * this values as environment variables.
157 */
Simon Glassed38aef2020-05-10 11:40:03 -0600158static int do_setboardid(struct cmd_tbl *cmdtp, int flag, int argc,
159 char *const argv[])
Holger Brunck30664922011-05-04 01:47:30 +0000160{
161 unsigned char buf[32];
162 char *p;
163
164 p = get_local_var("IVM_BoardId");
Holger Brunckff41a752020-10-30 12:45:49 +0100165 if (!p) {
Holger Brunck30664922011-05-04 01:47:30 +0000166 printf("can't get the IVM_Boardid\n");
167 return 1;
168 }
Ben Whitten34fd6c92015-12-30 13:05:58 +0000169 strcpy((char *)buf, p);
Simon Glass6a38e412017-08-03 12:22:09 -0600170 env_set("boardid", (char *)buf);
Holger Brunckde799842011-07-04 22:23:59 +0000171 printf("set boardid=%s\n", buf);
Holger Brunck30664922011-05-04 01:47:30 +0000172
173 p = get_local_var("IVM_HWKey");
Holger Brunckff41a752020-10-30 12:45:49 +0100174 if (!p) {
Holger Brunck30664922011-05-04 01:47:30 +0000175 printf("can't get the IVM_HWKey\n");
176 return 1;
177 }
Ben Whitten34fd6c92015-12-30 13:05:58 +0000178 strcpy((char *)buf, p);
Simon Glass6a38e412017-08-03 12:22:09 -0600179 env_set("hwkey", (char *)buf);
Holger Brunckde799842011-07-04 22:23:59 +0000180 printf("set hwkey=%s\n", buf);
181 printf("Execute manually saveenv for persistent storage.\n");
Holger Brunck30664922011-05-04 01:47:30 +0000182
183 return 0;
184}
185
Holger Brunckff41a752020-10-30 12:45:49 +0100186U_BOOT_CMD(km_setboardid, 1, 0, do_setboardid, "setboardid",
187 "read out bid and hwkey from IVM and set in environment");
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000188
189/*
190 * command km_checkbidhwk
191 * if "boardid" and "hwkey" are not already set in the environment, do:
192 * if a "boardIdListHex" exists in the environment:
193 * - read ivm data for boardid and hwkey
194 * - compare each entry of the boardIdListHex with the
195 * IVM data:
196 * if match:
197 * set environment variables boardid, boardId,
198 * hwkey, hwKey to the found values
199 * both (boardid and boardId) are set because
200 * they might be used differently in the
201 * application and in the init scripts (?)
202 * return 0 in case of match, 1 if not match or error
203 */
Simon Glassed38aef2020-05-10 11:40:03 -0600204static int do_checkboardidhwk(struct cmd_tbl *cmdtp, int flag, int argc,
205 char *const argv[])
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000206{
207 unsigned long ivmbid = 0, ivmhwkey = 0;
208 unsigned long envbid = 0, envhwkey = 0;
209 char *p;
210 int verbose = argc > 1 && *argv[1] == 'v';
211 int rc = 0;
212
213 /*
214 * first read out the real inventory values, these values are
215 * already stored in the local hush variables
216 */
217 p = get_local_var("IVM_BoardId");
Holger Brunckff41a752020-10-30 12:45:49 +0100218 if (!p) {
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000219 printf("can't get the IVM_Boardid\n");
220 return 1;
221 }
222 rc = strict_strtoul(p, 16, &ivmbid);
223
224 p = get_local_var("IVM_HWKey");
Holger Brunckff41a752020-10-30 12:45:49 +0100225 if (!p) {
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000226 printf("can't get the IVM_HWKey\n");
227 return 1;
228 }
229 rc = strict_strtoul(p, 16, &ivmhwkey);
230
231 if (!ivmbid || !ivmhwkey) {
232 printf("Error: IVM_BoardId and/or IVM_HWKey not set!\n");
233 return rc;
234 }
235
236 /* now try to read values from environment if available */
Simon Glass64b723f2017-08-03 12:22:12 -0600237 p = env_get("boardid");
Holger Brunckff41a752020-10-30 12:45:49 +0100238 if (p)
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000239 rc = strict_strtoul(p, 16, &envbid);
Simon Glass64b723f2017-08-03 12:22:12 -0600240 p = env_get("hwkey");
Holger Brunckff41a752020-10-30 12:45:49 +0100241 if (p)
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000242 rc = strict_strtoul(p, 16, &envhwkey);
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000243 if (rc != 0) {
244 printf("strict_strtoul returns error: %d", rc);
245 return rc;
246 }
247
248 if (!envbid || !envhwkey) {
249 /*
250 * BoardId/HWkey not available in the environment, so try the
251 * environment variable for BoardId/HWkey list
252 */
Simon Glass64b723f2017-08-03 12:22:12 -0600253 char *bidhwklist = env_get("boardIdListHex");
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000254
255 if (bidhwklist) {
256 int found = 0;
257 char *rest = bidhwklist;
258 char *endp;
259
260 if (verbose) {
261 printf("IVM_BoardId: %ld, IVM_HWKey=%ld\n",
Holger Brunckff41a752020-10-30 12:45:49 +0100262 ivmbid, ivmhwkey);
263 printf("boardIdHwKeyList: %s\n", bidhwklist);
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000264 }
265 while (!found) {
266 /* loop over each bid/hwkey pair in the list */
267 unsigned long bid = 0;
268 unsigned long hwkey = 0;
269
270 while (*rest && !isxdigit(*rest))
271 rest++;
272 /*
273 * use simple_strtoul because we need &end and
274 * we know we got non numeric char at the end
275 */
276 bid = simple_strtoul(rest, &endp, 16);
277 /* BoardId and HWkey are separated with a "_" */
278 if (*endp == '_') {
279 rest = endp + 1;
280 /*
281 * use simple_strtoul because we need
282 * &end
283 */
284 hwkey = simple_strtoul(rest, &endp, 16);
285 rest = endp;
286 while (*rest && !isxdigit(*rest))
287 rest++;
288 }
Holger Brunckff41a752020-10-30 12:45:49 +0100289 if (!bid || !hwkey) {
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000290 /* end of list */
291 break;
292 }
293 if (verbose) {
294 printf("trying bid=0x%lX, hwkey=%ld\n",
Holger Brunckff41a752020-10-30 12:45:49 +0100295 bid, hwkey);
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000296 }
297 /*
298 * Compare the values of the found entry in the
299 * list with the valid values which are stored
300 * in the inventory eeprom. If they are equal
Holger Brunckbc4e15f2011-06-05 22:22:17 +0000301 * set the values in environment variables.
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000302 */
Holger Brunckff41a752020-10-30 12:45:49 +0100303 if (bid == ivmbid && hwkey == ivmhwkey) {
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000304 found = 1;
305 envbid = bid;
306 envhwkey = hwkey;
Niel Fouriede553f52021-01-21 13:19:19 +0100307 env_set_hex("boardid", bid);
308 env_set_hex("hwkey", hwkey);
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000309 }
310 } /* end while( ! found ) */
311 }
312 }
313
314 /* compare now the values */
Holger Brunckff41a752020-10-30 12:45:49 +0100315 if (ivmbid == envbid && ivmhwkey == envhwkey) {
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000316 printf("boardid=0x%3lX, hwkey=%ld\n", envbid, envhwkey);
317 rc = 0; /* match */
318 } else {
Holger Brunckde799842011-07-04 22:23:59 +0000319 printf("Error: env boardid=0x%3lX, hwkey=%ld\n", envbid,
Holger Brunckff41a752020-10-30 12:45:49 +0100320 envhwkey);
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000321 printf(" IVM bId=0x%3lX, hwKey=%ld\n", ivmbid, ivmhwkey);
322 rc = 1; /* don't match */
323 }
324 return rc;
325}
326
327U_BOOT_CMD(km_checkbidhwk, 2, 0, do_checkboardidhwk,
Holger Brunckff41a752020-10-30 12:45:49 +0100328 "check boardid and hwkey",
329 "[v]\n - check environment parameter \"boardIdListHex\" against stored boardid and hwkey from the IVM\n v: verbose output"
Thomas Herzmann2c8a0c82011-05-12 19:59:22 +0000330);
Thomas Herzmannb2c31602012-05-04 10:55:58 +0200331
332/*
333 * command km_checktestboot
334 * if the testpin of the board is asserted, return 1
335 * * else return 0
336 */
Simon Glassed38aef2020-05-10 11:40:03 -0600337static int do_checktestboot(struct cmd_tbl *cmdtp, int flag, int argc,
338 char *const argv[])
Thomas Herzmannb2c31602012-05-04 10:55:58 +0200339{
340 int testpin = 0;
341 char *s = NULL;
342 int testboot = 0;
343 int verbose = argc > 1 && *argv[1] == 'v';
344
345#if defined(CONFIG_POST)
346 testpin = post_hotkeys_pressed();
Thomas Herzmannb2c31602012-05-04 10:55:58 +0200347#endif
Holger Brunckff41a752020-10-30 12:45:49 +0100348
Simon Glass64b723f2017-08-03 12:22:12 -0600349 s = env_get("test_bank");
Thomas Herzmannb2c31602012-05-04 10:55:58 +0200350 /* when test_bank is not set, act as if testpin is not asserted */
351 testboot = (testpin != 0) && (s);
352 if (verbose) {
353 printf("testpin = %d\n", testpin);
Wolfgang Denk6ae80832014-11-06 14:02:57 +0100354 /* cppcheck-suppress nullPointer */
Thomas Herzmannb2c31602012-05-04 10:55:58 +0200355 printf("test_bank = %s\n", s ? s : "not set");
356 printf("boot test app : %s\n", (testboot) ? "yes" : "no");
357 }
358 /* return 0 means: testboot, therefore we need the inversion */
359 return !testboot;
360}
361
362U_BOOT_CMD(km_checktestboot, 2, 0, do_checktestboot,
Holger Brunckff41a752020-10-30 12:45:49 +0100363 "check if testpin is asserted",
364 "[v]\n v - verbose output"
Thomas Herzmannb2c31602012-05-04 10:55:58 +0200365);