blob: b14bb3dbb7fa78dce7a74d67f294ff0a9d8b88bb [file] [log] [blame]
Teresa Remmeta6f8da52023-08-17 10:57:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2023 PHYTEC Messtechnik GmbH
4 * Author: Teresa Remmet <t.remmet@phytec.de>
5 */
6
Teresa Remmeta6f8da52023-08-17 10:57:06 +02007#include <dm/device.h>
8#include <dm/uclass.h>
9#include <i2c.h>
10#include <u-boot/crc.h>
Daniel Schultza440ec22024-04-19 08:55:36 -070011#include <malloc.h>
12#include <extension_board.h>
Teresa Remmeta6f8da52023-08-17 10:57:06 +020013
14#include "phytec_som_detection.h"
15
16struct phytec_eeprom_data eeprom_data;
17
Yannic Moog5dd7f7c2023-12-20 09:45:35 +010018#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION)
19
Teresa Remmeta6f8da52023-08-17 10:57:06 +020020int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
21 int bus_num, int addr, int addr_fallback)
22{
23 int ret;
24
25 ret = phytec_eeprom_data_init(data, bus_num, addr);
26 if (ret) {
27 pr_err("%s: init failed. Trying fall back address 0x%x\n",
28 __func__, addr_fallback);
29 ret = phytec_eeprom_data_init(data, bus_num, addr_fallback);
30 }
31
32 if (ret)
33 pr_err("%s: EEPROM data init failed\n", __func__);
34
35 return ret;
36}
37
38int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
39 int bus_num, int addr)
40{
41 int ret;
42
43 ret = phytec_eeprom_data_init(data, bus_num, addr);
44 if (ret)
45 pr_err("%s: EEPROM data init failed\n", __func__);
46
47 return ret;
48}
49
50int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
51 int bus_num, int addr)
52{
53 int ret, i;
54 unsigned int crc;
Daniel Schultza132b302024-04-19 08:55:39 -070055 u8 *ptr;
Yannic Moogdb2dfb02024-04-19 08:55:37 -070056 const unsigned int payload_size = sizeof(struct phytec_eeprom_payload);
Teresa Remmeta6f8da52023-08-17 10:57:06 +020057
58 if (!data)
59 data = &eeprom_data;
60
61#if CONFIG_IS_ENABLED(DM_I2C)
62 struct udevice *dev;
63
64 ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev);
65 if (ret) {
66 pr_err("%s: i2c EEPROM not found: %i.\n", __func__, ret);
Yannic Moogdb2dfb02024-04-19 08:55:37 -070067 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020068 }
69
Yannic Moogdb2dfb02024-04-19 08:55:37 -070070 ret = dm_i2c_read(dev, 0, (uint8_t *)data, payload_size);
Teresa Remmeta6f8da52023-08-17 10:57:06 +020071 if (ret) {
Yannic Moogdb2dfb02024-04-19 08:55:37 -070072 pr_err("%s: Unable to read EEPROM data: %i\n", __func__, ret);
73 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020074 }
75#else
76 i2c_set_bus_num(bus_num);
77 ret = i2c_read(addr, 0, 2, (uint8_t *)data,
78 sizeof(struct phytec_eeprom_data));
79#endif
80
Yannic Moogdb2dfb02024-04-19 08:55:37 -070081 if (data->payload.api_rev == 0xff) {
Teresa Remmeta6f8da52023-08-17 10:57:06 +020082 pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
Yannic Moogdb2dfb02024-04-19 08:55:37 -070083 ret = -EINVAL;
84 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020085 }
86
Daniel Schultza132b302024-04-19 08:55:39 -070087 ptr = (u8 *)data;
Yannic Moogdb2dfb02024-04-19 08:55:37 -070088 for (i = 0; i < payload_size; ++i)
Yannic Moog7bbbe182023-12-20 09:45:34 +010089 if (ptr[i] != 0x0)
Teresa Remmeta6f8da52023-08-17 10:57:06 +020090 break;
91
Yannic Moogdb2dfb02024-04-19 08:55:37 -070092 if (i == payload_size) {
Teresa Remmeta6f8da52023-08-17 10:57:06 +020093 pr_err("%s: EEPROM data is all zero. Erased?\n", __func__);
Yannic Moogdb2dfb02024-04-19 08:55:37 -070094 ret = -EINVAL;
95 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020096 }
97
98 /* We are done here for early revisions */
Yannic Moogdb2dfb02024-04-19 08:55:37 -070099 if (data->payload.api_rev <= PHYTEC_API_REV1) {
100 data->valid = true;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200101 return 0;
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700102 }
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200103
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700104 crc = crc8(0, (const unsigned char *)&data->payload, payload_size);
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200105 debug("%s: crc: %x\n", __func__, crc);
106
107 if (crc) {
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700108 pr_err("%s: CRC mismatch. EEPROM data is not usable.\n",
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200109 __func__);
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700110 ret = -EINVAL;
111 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200112 }
113
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700114 data->valid = true;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200115 return 0;
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700116err:
117 data->valid = false;
118 return ret;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200119}
120
121void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
122{
123 struct phytec_api2_data *api2;
124 char pcb_sub_rev;
125 unsigned int ksp_no, sub_som_type1, sub_som_type2;
126
127 if (!data)
128 data = &eeprom_data;
129
Yannic Moog51b9d532024-04-19 08:55:38 -0700130 if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200131 return;
132
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700133 api2 = &data->payload.data.data_api2;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200134
135 /* Calculate PCB subrevision */
136 pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f;
137 pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' ';
138
139 /* print standard product string */
140 if (api2->som_type <= 1) {
141 printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n",
142 phytec_som_type_str[api2->som_type], api2->som_no,
143 api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
144 return;
145 }
146 /* print KSP/KSM string */
147 if (api2->som_type <= 3) {
148 ksp_no = (api2->ksp_no << 8) | api2->som_no;
149 printf("SoM: %s-%u ",
150 phytec_som_type_str[api2->som_type], ksp_no);
151 /* print standard product based KSP/KSM strings */
152 } else {
153 switch (api2->som_type) {
154 case 4:
155 sub_som_type1 = 0;
156 sub_som_type2 = 3;
157 break;
158 case 5:
159 sub_som_type1 = 0;
160 sub_som_type2 = 2;
161 break;
162 case 6:
163 sub_som_type1 = 1;
164 sub_som_type2 = 3;
165 break;
166 case 7:
167 sub_som_type1 = 1;
168 sub_som_type2 = 2;
169 break;
170 default:
Yannic Moog46c507e2023-12-20 09:45:36 +0100171 pr_err("%s: Invalid SoM type: %i", __func__, api2->som_type);
172 return;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200173 };
174
175 printf("SoM: %s-%03u-%s-%03u ",
176 phytec_som_type_str[sub_som_type1],
177 api2->som_no, phytec_som_type_str[sub_som_type2],
178 api2->ksp_no);
179 }
180
181 printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
182 api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
183}
184
185char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
186{
187 char *opt;
188
189 if (!data)
190 data = &eeprom_data;
191
Yannic Moog51b9d532024-04-19 08:55:38 -0700192 if (!data->valid)
193 return NULL;
194
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700195 if (data->payload.api_rev < PHYTEC_API_REV2)
196 opt = data->payload.data.data_api0.opt;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200197 else
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700198 opt = data->payload.data.data_api2.opt;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200199
200 return opt;
201}
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200202
203u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
204{
205 struct phytec_api2_data *api2;
206
207 if (!data)
208 data = &eeprom_data;
209
Yannic Moog51b9d532024-04-19 08:55:38 -0700210 if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200211 return PHYTEC_EEPROM_INVAL;
212
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700213 api2 = &data->payload.data.data_api2;
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200214
215 return api2->pcb_rev;
216}
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100217
Benjamin Hahn455dcf72024-03-06 17:18:31 +0100218u8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data)
219{
220 if (!data)
221 data = &eeprom_data;
Yannic Moog51b9d532024-04-19 08:55:38 -0700222
223 if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
Benjamin Hahn455dcf72024-03-06 17:18:31 +0100224 return PHYTEC_EEPROM_INVAL;
225
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700226 return data->payload.data.data_api2.som_type;
Benjamin Hahn455dcf72024-03-06 17:18:31 +0100227}
228
Daniel Schultza440ec22024-04-19 08:55:36 -0700229#if IS_ENABLED(CONFIG_CMD_EXTENSION)
230struct extension *phytec_add_extension(const char *name, const char *overlay,
231 const char *other)
232{
233 struct extension *extension;
234
235 if (strlen(overlay) > sizeof(extension->overlay)) {
236 pr_err("Overlay name %s is longer than %lu.\n", overlay,
237 sizeof(extension->overlay));
238 return NULL;
239 }
240
241 extension = calloc(1, sizeof(struct extension));
242 snprintf(extension->name, sizeof(extension->name), name);
243 snprintf(extension->overlay, sizeof(extension->overlay), overlay);
244 snprintf(extension->other, sizeof(extension->other), other);
245 snprintf(extension->owner, sizeof(extension->owner), "PHYTEC");
246
247 return extension;
248}
249#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */
250
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100251#else
252
253inline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
254 int bus_num, int addr)
255{
256 return PHYTEC_EEPROM_INVAL;
257}
258
259inline int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
260 int bus_num, int addr,
261 int addr_fallback)
262{
263 return PHYTEC_EEPROM_INVAL;
264}
265
266inline int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
267 int bus_num, int addr)
268{
269 return PHYTEC_EEPROM_INVAL;
270}
271
272inline void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
273{
274}
275
276inline char *__maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
277{
278 return NULL;
279}
280
281u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
282{
283 return PHYTEC_EEPROM_INVAL;
284}
285
Benjamin Hahn69ea0e32024-03-12 10:39:11 +0100286u8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data)
287{
288 return PHYTEC_EEPROM_INVAL;
289}
Daniel Schultza440ec22024-04-19 08:55:36 -0700290
291#if IS_ENABLED(CONFIG_CMD_EXTENSION)
292inline struct extension *phytec_add_extension(const char *name,
293 const char *overlay,
294 const char *other)
295{
296 return NULL;
297}
298#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */
Benjamin Hahn69ea0e32024-03-12 10:39:11 +0100299
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100300#endif /* IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) */