blob: 085e7320bd8f426c6913418bf2deef154d9086f0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Lokesh Vutla35f7a972016-02-24 12:30:54 -06002/*
3 * Library to support early TI EVM EEPROM handling
4 *
5 * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
6 * Lokesh Vutla
7 * Steve Kipisz
Lokesh Vutla35f7a972016-02-24 12:30:54 -06008 */
9
10#include <common.h>
11#include <asm/omap_common.h>
Cooper Jr., Franklinf2598de2017-04-20 10:25:44 -050012#include <dm/uclass.h>
Lokesh Vutla35f7a972016-02-24 12:30:54 -060013#include <i2c.h>
14
15#include "board_detect.h"
16
Cooper Jr., Franklinf2598de2017-04-20 10:25:44 -050017#if defined(CONFIG_DM_I2C_COMPAT)
18/**
19 * ti_i2c_set_alen - Set chip's i2c address length
20 * @bus_addr - I2C bus number
21 * @dev_addr - I2C eeprom id
22 * @alen - I2C address length in bytes
23 *
24 * DM_I2C by default sets the address length to be used to 1. This
25 * function allows this address length to be changed to match the
26 * eeprom used for board detection.
27 */
28int __maybe_unused ti_i2c_set_alen(int bus_addr, int dev_addr, int alen)
29{
30 struct udevice *dev;
31 struct udevice *bus;
32 int rc;
33
34 rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus);
35 if (rc)
36 return rc;
37 rc = i2c_get_chip(bus, dev_addr, 1, &dev);
38 if (rc)
39 return rc;
40 rc = i2c_set_chip_offset_len(dev, alen);
41 if (rc)
42 return rc;
43
44 return 0;
45}
46#else
47int __maybe_unused ti_i2c_set_alen(int bus_addr, int dev_addr, int alen)
48{
49 return 0;
50}
51#endif
52
Andreas Dannenberge315a662018-12-07 14:50:47 +010053#if !defined(CONFIG_DM_I2C) || defined(CONFIG_DM_I2C_COMPAT)
Lokesh Vutla35f7a972016-02-24 12:30:54 -060054/**
55 * ti_i2c_eeprom_init - Initialize an i2c bus and probe for a device
56 * @i2c_bus: i2c bus number to initialize
57 * @dev_addr: Device address to probe for
58 *
59 * Return: 0 on success or corresponding error on failure.
60 */
61static int __maybe_unused ti_i2c_eeprom_init(int i2c_bus, int dev_addr)
62{
63 int rc;
64
65 if (i2c_bus >= 0) {
66 rc = i2c_set_bus_num(i2c_bus);
67 if (rc)
68 return rc;
69 }
70
71 return i2c_probe(dev_addr);
72}
73
74/**
75 * ti_i2c_eeprom_read - Read data from an EEPROM
76 * @dev_addr: The device address of the EEPROM
77 * @offset: Offset to start reading in the EEPROM
78 * @ep: Pointer to a buffer to read into
79 * @epsize: Size of buffer
80 *
81 * Return: 0 on success or corresponding result of i2c_read
82 */
83static int __maybe_unused ti_i2c_eeprom_read(int dev_addr, int offset,
84 uchar *ep, int epsize)
85{
Cooper Jr., Franklin5b89c972017-04-20 10:25:45 -050086 int bus_num, rc, alen;
87
88 bus_num = i2c_get_bus_num();
89
90 alen = 2;
91
92 rc = ti_i2c_set_alen(bus_num, dev_addr, alen);
93 if (rc)
94 return rc;
95
96 return i2c_read(dev_addr, offset, alen, ep, epsize);
Lokesh Vutla35f7a972016-02-24 12:30:54 -060097}
Andreas Dannenberge315a662018-12-07 14:50:47 +010098#endif
Lokesh Vutla35f7a972016-02-24 12:30:54 -060099
100/**
101 * ti_eeprom_string_cleanup() - Handle eeprom programming errors
102 * @s: eeprom string (should be NULL terminated)
103 *
104 * Some Board manufacturers do not add a NULL termination at the
105 * end of string, instead some binary information is kludged in, hence
106 * convert the string to just printable characters of ASCII chart.
107 */
108static void __maybe_unused ti_eeprom_string_cleanup(char *s)
109{
110 int i, l;
111
112 l = strlen(s);
113 for (i = 0; i < l; i++, s++)
114 if (*s < ' ' || *s > '~') {
115 *s = 0;
116 break;
117 }
118}
119
120__weak void gpi2c_init(void)
121{
122}
123
124static int __maybe_unused ti_i2c_eeprom_get(int bus_addr, int dev_addr,
125 u32 header, u32 size, uint8_t *ep)
126{
Andreas Dannenberge315a662018-12-07 14:50:47 +0100127 u32 hdr_read;
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600128 int rc;
129
Andreas Dannenberge315a662018-12-07 14:50:47 +0100130#if defined(CONFIG_DM_I2C) && !defined(CONFIG_DM_I2C_COMPAT)
131 struct udevice *dev;
132 struct udevice *bus;
133
134 rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus);
135 if (rc)
136 return rc;
137 rc = i2c_get_chip(bus, dev_addr, 1, &dev);
138 if (rc)
139 return rc;
140
141 /*
142 * Read the header first then only read the other contents.
143 */
144 rc = i2c_set_chip_offset_len(dev, 2);
145 if (rc)
146 return rc;
147
148 rc = dm_i2c_read(dev, 0, (uint8_t *)&hdr_read, 4);
149 if (rc)
150 return rc;
151
152 /* Corrupted data??? */
153 if (hdr_read != header) {
154 rc = dm_i2c_read(dev, 0, (uint8_t *)&hdr_read, 4);
155 /*
156 * read the eeprom header using i2c again, but use only a
157 * 1 byte address (some legacy boards need this..)
158 */
159 if (rc) {
160 rc = i2c_set_chip_offset_len(dev, 1);
161 if (rc)
162 return rc;
163
164 rc = dm_i2c_read(dev, 0, (uint8_t *)&hdr_read, 4);
165 }
166 if (rc)
167 return rc;
168 }
169 if (hdr_read != header)
170 return -1;
171
172 rc = dm_i2c_read(dev, 0, ep, size);
173 if (rc)
174 return rc;
175#else
176 u32 byte;
177
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600178 gpi2c_init();
179 rc = ti_i2c_eeprom_init(bus_addr, dev_addr);
180 if (rc)
181 return rc;
182
183 /*
184 * Read the header first then only read the other contents.
185 */
186 byte = 2;
Cooper Jr., Franklin5b89c972017-04-20 10:25:45 -0500187
188 rc = ti_i2c_set_alen(bus_addr, dev_addr, byte);
189 if (rc)
190 return rc;
191
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600192 rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read, 4);
193 if (rc)
194 return rc;
195
196 /* Corrupted data??? */
197 if (hdr_read != header) {
198 rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read, 4);
199 /*
200 * read the eeprom header using i2c again, but use only a
201 * 1 byte address (some legacy boards need this..)
202 */
203 byte = 1;
Cooper Jr., Franklin5b89c972017-04-20 10:25:45 -0500204 if (rc) {
205 rc = ti_i2c_set_alen(bus_addr, dev_addr, byte);
206 if (rc)
207 return rc;
208
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600209 rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read,
210 4);
Cooper Jr., Franklin5b89c972017-04-20 10:25:45 -0500211 }
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600212 if (rc)
213 return rc;
214 }
215 if (hdr_read != header)
216 return -1;
217
218 rc = i2c_read(dev_addr, 0x0, byte, ep, size);
219 if (rc)
220 return rc;
Andreas Dannenberge315a662018-12-07 14:50:47 +0100221#endif
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600222 return 0;
223}
224
Nishanth Menon27856ff2017-06-16 17:25:04 -0500225int __maybe_unused ti_i2c_eeprom_am_set(const char *name, const char *rev)
226{
227 struct ti_common_eeprom *ep;
228
229 if (!name || !rev)
230 return -1;
231
232 ep = TI_EEPROM_DATA;
233 if (ep->header == TI_EEPROM_HEADER_MAGIC)
234 goto already_set;
235
236 /* Set to 0 all fields */
237 memset(ep, 0, sizeof(*ep));
238 strncpy(ep->name, name, TI_EEPROM_HDR_NAME_LEN);
239 strncpy(ep->version, rev, TI_EEPROM_HDR_REV_LEN);
240 /* Some dummy serial number to identify the platform */
241 strncpy(ep->serial, "0000", TI_EEPROM_HDR_SERIAL_LEN);
242 /* Mark it with a valid header */
243 ep->header = TI_EEPROM_HEADER_MAGIC;
244
245already_set:
246 return 0;
247}
248
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600249int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
250{
251 int rc;
252 struct ti_am_eeprom am_ep;
253 struct ti_common_eeprom *ep;
254
255 ep = TI_EEPROM_DATA;
Jean-Jacques Hiblota096a762016-12-01 10:37:03 +0100256#ifndef CONFIG_SPL_BUILD
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600257 if (ep->header == TI_EEPROM_HEADER_MAGIC)
Jean-Jacques Hiblota096a762016-12-01 10:37:03 +0100258 return 0; /* EEPROM has already been read */
259#endif
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600260
261 /* Initialize with a known bad marker for i2c fails.. */
262 ep->header = TI_DEAD_EEPROM_MAGIC;
263 ep->name[0] = 0x0;
264 ep->version[0] = 0x0;
265 ep->serial[0] = 0x0;
Nishanth Menone2b0a522016-10-11 12:39:04 -0500266 ep->config[0] = 0x0;
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600267
268 rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC,
269 sizeof(am_ep), (uint8_t *)&am_ep);
270 if (rc)
271 return rc;
272
273 ep->header = am_ep.header;
274 strlcpy(ep->name, am_ep.name, TI_EEPROM_HDR_NAME_LEN + 1);
275 ti_eeprom_string_cleanup(ep->name);
276
277 /* BeagleBone Green '1' eeprom, board_rev: 0x1a 0x00 0x00 0x00 */
278 if (am_ep.version[0] == 0x1a && am_ep.version[1] == 0x00 &&
279 am_ep.version[2] == 0x00 && am_ep.version[3] == 0x00)
280 strlcpy(ep->version, "BBG1", TI_EEPROM_HDR_REV_LEN + 1);
281 else
282 strlcpy(ep->version, am_ep.version, TI_EEPROM_HDR_REV_LEN + 1);
283 ti_eeprom_string_cleanup(ep->version);
284 strlcpy(ep->serial, am_ep.serial, TI_EEPROM_HDR_SERIAL_LEN + 1);
285 ti_eeprom_string_cleanup(ep->serial);
286 strlcpy(ep->config, am_ep.config, TI_EEPROM_HDR_CONFIG_LEN + 1);
287 ti_eeprom_string_cleanup(ep->config);
288
289 memcpy(ep->mac_addr, am_ep.mac_addr,
290 TI_EEPROM_HDR_NO_OF_MAC_ADDR * TI_EEPROM_HDR_ETH_ALEN);
291
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600292 return 0;
293}
294
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530295int __maybe_unused ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr)
296{
297 int rc, offset = 0;
298 struct dra7_eeprom dra7_ep;
299 struct ti_common_eeprom *ep;
300
301 ep = TI_EEPROM_DATA;
Jean-Jacques Hiblota096a762016-12-01 10:37:03 +0100302#ifndef CONFIG_SPL_BUILD
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530303 if (ep->header == DRA7_EEPROM_HEADER_MAGIC)
Jean-Jacques Hiblota096a762016-12-01 10:37:03 +0100304 return 0; /* EEPROM has already been read */
305#endif
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530306
307 /* Initialize with a known bad marker for i2c fails.. */
Nishanth Menon21e54c02016-10-11 12:39:03 -0500308 ep->header = TI_DEAD_EEPROM_MAGIC;
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530309 ep->name[0] = 0x0;
310 ep->version[0] = 0x0;
311 ep->serial[0] = 0x0;
Nishanth Menone2b0a522016-10-11 12:39:04 -0500312 ep->config[0] = 0x0;
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530313 ep->emif1_size = 0;
314 ep->emif2_size = 0;
315
316 rc = ti_i2c_eeprom_get(bus_addr, dev_addr, DRA7_EEPROM_HEADER_MAGIC,
317 sizeof(dra7_ep), (uint8_t *)&dra7_ep);
318 if (rc)
319 return rc;
320
321 ep->header = dra7_ep.header;
322 strlcpy(ep->name, dra7_ep.name, TI_EEPROM_HDR_NAME_LEN + 1);
323 ti_eeprom_string_cleanup(ep->name);
324
325 offset = dra7_ep.version_major - 1;
326
327 /* Rev F is skipped */
328 if (offset >= 5)
329 offset = offset + 1;
330 snprintf(ep->version, TI_EEPROM_HDR_REV_LEN + 1, "%c.%d",
331 'A' + offset, dra7_ep.version_minor);
332 ti_eeprom_string_cleanup(ep->version);
333 ep->emif1_size = (u64)dra7_ep.emif1_size;
334 ep->emif2_size = (u64)dra7_ep.emif2_size;
335 strlcpy(ep->config, dra7_ep.config, TI_EEPROM_HDR_CONFIG_LEN + 1);
336 ti_eeprom_string_cleanup(ep->config);
337
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530338 return 0;
339}
340
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600341bool __maybe_unused board_ti_is(char *name_tag)
342{
343 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
344
345 if (ep->header == TI_DEAD_EEPROM_MAGIC)
346 return false;
347 return !strncmp(ep->name, name_tag, TI_EEPROM_HDR_NAME_LEN);
348}
349
350bool __maybe_unused board_ti_rev_is(char *rev_tag, int cmp_len)
351{
352 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
353 int l;
354
355 if (ep->header == TI_DEAD_EEPROM_MAGIC)
356 return false;
357
358 l = cmp_len > TI_EEPROM_HDR_REV_LEN ? TI_EEPROM_HDR_REV_LEN : cmp_len;
359 return !strncmp(ep->version, rev_tag, l);
360}
361
362char * __maybe_unused board_ti_get_rev(void)
363{
364 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
365
Nishanth Menon23afc8a2016-10-11 12:39:05 -0500366 /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600367 return ep->version;
368}
369
370char * __maybe_unused board_ti_get_config(void)
371{
372 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
373
Nishanth Menon23afc8a2016-10-11 12:39:05 -0500374 /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600375 return ep->config;
376}
377
378char * __maybe_unused board_ti_get_name(void)
379{
380 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
381
Nishanth Menon23afc8a2016-10-11 12:39:05 -0500382 /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600383 return ep->name;
384}
385
386void __maybe_unused
387board_ti_get_eth_mac_addr(int index,
388 u8 mac_addr[TI_EEPROM_HDR_ETH_ALEN])
389{
390 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
391
392 if (ep->header == TI_DEAD_EEPROM_MAGIC)
393 goto fail;
394
395 if (index < 0 || index >= TI_EEPROM_HDR_NO_OF_MAC_ADDR)
396 goto fail;
397
398 memcpy(mac_addr, ep->mac_addr[index], TI_EEPROM_HDR_ETH_ALEN);
399 return;
400
401fail:
402 memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
403}
404
Lokesh Vutla7c08a782016-03-08 09:18:04 +0530405u64 __maybe_unused board_ti_get_emif1_size(void)
406{
407 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
408
409 if (ep->header != DRA7_EEPROM_HEADER_MAGIC)
410 return 0;
411
412 return ep->emif1_size;
413}
414
415u64 __maybe_unused board_ti_get_emif2_size(void)
416{
417 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
418
419 if (ep->header != DRA7_EEPROM_HEADER_MAGIC)
420 return 0;
421
422 return ep->emif2_size;
423}
424
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600425void __maybe_unused set_board_info_env(char *name)
426{
427 char *unknown = "unknown";
428 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
429
430 if (name)
Simon Glass6a38e412017-08-03 12:22:09 -0600431 env_set("board_name", name);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600432 else if (ep->name)
Simon Glass6a38e412017-08-03 12:22:09 -0600433 env_set("board_name", ep->name);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600434 else
Simon Glass6a38e412017-08-03 12:22:09 -0600435 env_set("board_name", unknown);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600436
437 if (ep->version)
Simon Glass6a38e412017-08-03 12:22:09 -0600438 env_set("board_rev", ep->version);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600439 else
Simon Glass6a38e412017-08-03 12:22:09 -0600440 env_set("board_rev", unknown);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600441
442 if (ep->serial)
Simon Glass6a38e412017-08-03 12:22:09 -0600443 env_set("board_serial", ep->serial);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600444 else
Simon Glass6a38e412017-08-03 12:22:09 -0600445 env_set("board_serial", unknown);
Lokesh Vutla35f7a972016-02-24 12:30:54 -0600446}
Roger Quadros44c7d9a2017-03-14 15:04:19 +0200447
448static u64 mac_to_u64(u8 mac[6])
449{
450 int i;
451 u64 addr = 0;
452
453 for (i = 0; i < 6; i++) {
454 addr <<= 8;
455 addr |= mac[i];
456 }
457
458 return addr;
459}
460
461static void u64_to_mac(u64 addr, u8 mac[6])
462{
463 mac[5] = addr;
464 mac[4] = addr >> 8;
465 mac[3] = addr >> 16;
466 mac[2] = addr >> 24;
467 mac[1] = addr >> 32;
468 mac[0] = addr >> 40;
469}
470
471void board_ti_set_ethaddr(int index)
472{
473 uint8_t mac_addr[6];
474 int i;
475 u64 mac1, mac2;
476 u8 mac_addr1[6], mac_addr2[6];
477 int num_macs;
478 /*
479 * Export any Ethernet MAC addresses from EEPROM.
480 * The 2 MAC addresses in EEPROM define the address range.
481 */
482 board_ti_get_eth_mac_addr(0, mac_addr1);
483 board_ti_get_eth_mac_addr(1, mac_addr2);
484
485 if (is_valid_ethaddr(mac_addr1) && is_valid_ethaddr(mac_addr2)) {
486 mac1 = mac_to_u64(mac_addr1);
487 mac2 = mac_to_u64(mac_addr2);
488
489 /* must contain an address range */
490 num_macs = mac2 - mac1 + 1;
491 if (num_macs <= 0)
492 return;
493
494 if (num_macs > 50) {
495 printf("%s: Too many MAC addresses: %d. Limiting to 50\n",
496 __func__, num_macs);
497 num_macs = 50;
498 }
499
500 for (i = 0; i < num_macs; i++) {
501 u64_to_mac(mac1 + i, mac_addr);
502 if (is_valid_ethaddr(mac_addr)) {
Simon Glass8551d552017-08-03 12:22:11 -0600503 eth_env_set_enetaddr_by_index("eth", i + index,
504 mac_addr);
Roger Quadros44c7d9a2017-03-14 15:04:19 +0200505 }
506 }
507 }
508}
Cooper Jr., Frankline1328c72017-06-16 17:25:08 -0500509
510bool __maybe_unused board_ti_was_eeprom_read(void)
511{
512 struct ti_common_eeprom *ep = TI_EEPROM_DATA;
513
514 if (ep->header == TI_EEPROM_HEADER_MAGIC)
515 return true;
516 else
517 return false;
518}