blob: 78c173df20d44c415d9ba8a3460e63e489452e3a [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
7#include <common.h>
Teresa Remmeta6f8da52023-08-17 10:57:06 +02008#include <dm/device.h>
9#include <dm/uclass.h>
10#include <i2c.h>
11#include <u-boot/crc.h>
Daniel Schultza440ec22024-04-19 08:55:36 -070012#include <malloc.h>
13#include <extension_board.h>
Teresa Remmeta6f8da52023-08-17 10:57:06 +020014
15#include "phytec_som_detection.h"
16
17struct phytec_eeprom_data eeprom_data;
18
Yannic Moog5dd7f7c2023-12-20 09:45:35 +010019#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION)
20
Teresa Remmeta6f8da52023-08-17 10:57:06 +020021int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
22 int bus_num, int addr, int addr_fallback)
23{
24 int ret;
25
26 ret = phytec_eeprom_data_init(data, bus_num, addr);
27 if (ret) {
28 pr_err("%s: init failed. Trying fall back address 0x%x\n",
29 __func__, addr_fallback);
30 ret = phytec_eeprom_data_init(data, bus_num, addr_fallback);
31 }
32
33 if (ret)
34 pr_err("%s: EEPROM data init failed\n", __func__);
35
36 return ret;
37}
38
39int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
40 int bus_num, int addr)
41{
42 int ret;
43
44 ret = phytec_eeprom_data_init(data, bus_num, addr);
45 if (ret)
46 pr_err("%s: EEPROM data init failed\n", __func__);
47
48 return ret;
49}
50
51int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
52 int bus_num, int addr)
53{
54 int ret, i;
55 unsigned int crc;
Daniel Schultza132b302024-04-19 08:55:39 -070056 u8 *ptr;
Yannic Moogdb2dfb02024-04-19 08:55:37 -070057 const unsigned int payload_size = sizeof(struct phytec_eeprom_payload);
Teresa Remmeta6f8da52023-08-17 10:57:06 +020058
59 if (!data)
60 data = &eeprom_data;
61
62#if CONFIG_IS_ENABLED(DM_I2C)
63 struct udevice *dev;
64
65 ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev);
66 if (ret) {
67 pr_err("%s: i2c EEPROM not found: %i.\n", __func__, ret);
Yannic Moogdb2dfb02024-04-19 08:55:37 -070068 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020069 }
70
Yannic Moogdb2dfb02024-04-19 08:55:37 -070071 ret = dm_i2c_read(dev, 0, (uint8_t *)data, payload_size);
Teresa Remmeta6f8da52023-08-17 10:57:06 +020072 if (ret) {
Yannic Moogdb2dfb02024-04-19 08:55:37 -070073 pr_err("%s: Unable to read EEPROM data: %i\n", __func__, ret);
74 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020075 }
76#else
77 i2c_set_bus_num(bus_num);
78 ret = i2c_read(addr, 0, 2, (uint8_t *)data,
79 sizeof(struct phytec_eeprom_data));
80#endif
81
Yannic Moogdb2dfb02024-04-19 08:55:37 -070082 if (data->payload.api_rev == 0xff) {
Teresa Remmeta6f8da52023-08-17 10:57:06 +020083 pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
Yannic Moogdb2dfb02024-04-19 08:55:37 -070084 ret = -EINVAL;
85 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020086 }
87
Daniel Schultza132b302024-04-19 08:55:39 -070088 ptr = (u8 *)data;
Yannic Moogdb2dfb02024-04-19 08:55:37 -070089 for (i = 0; i < payload_size; ++i)
Yannic Moog7bbbe182023-12-20 09:45:34 +010090 if (ptr[i] != 0x0)
Teresa Remmeta6f8da52023-08-17 10:57:06 +020091 break;
92
Yannic Moogdb2dfb02024-04-19 08:55:37 -070093 if (i == payload_size) {
Teresa Remmeta6f8da52023-08-17 10:57:06 +020094 pr_err("%s: EEPROM data is all zero. Erased?\n", __func__);
Yannic Moogdb2dfb02024-04-19 08:55:37 -070095 ret = -EINVAL;
96 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +020097 }
98
99 /* We are done here for early revisions */
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700100 if (data->payload.api_rev <= PHYTEC_API_REV1) {
101 data->valid = true;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200102 return 0;
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700103 }
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200104
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700105 crc = crc8(0, (const unsigned char *)&data->payload, payload_size);
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200106 debug("%s: crc: %x\n", __func__, crc);
107
108 if (crc) {
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700109 pr_err("%s: CRC mismatch. EEPROM data is not usable.\n",
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200110 __func__);
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700111 ret = -EINVAL;
112 goto err;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200113 }
114
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700115 data->valid = true;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200116 return 0;
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700117err:
118 data->valid = false;
119 return ret;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200120}
121
122void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
123{
124 struct phytec_api2_data *api2;
125 char pcb_sub_rev;
126 unsigned int ksp_no, sub_som_type1, sub_som_type2;
127
128 if (!data)
129 data = &eeprom_data;
130
Yannic Moog51b9d532024-04-19 08:55:38 -0700131 if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200132 return;
133
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700134 api2 = &data->payload.data.data_api2;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200135
136 /* Calculate PCB subrevision */
137 pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f;
138 pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' ';
139
140 /* print standard product string */
141 if (api2->som_type <= 1) {
142 printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n",
143 phytec_som_type_str[api2->som_type], api2->som_no,
144 api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
145 return;
146 }
147 /* print KSP/KSM string */
148 if (api2->som_type <= 3) {
149 ksp_no = (api2->ksp_no << 8) | api2->som_no;
150 printf("SoM: %s-%u ",
151 phytec_som_type_str[api2->som_type], ksp_no);
152 /* print standard product based KSP/KSM strings */
153 } else {
154 switch (api2->som_type) {
155 case 4:
156 sub_som_type1 = 0;
157 sub_som_type2 = 3;
158 break;
159 case 5:
160 sub_som_type1 = 0;
161 sub_som_type2 = 2;
162 break;
163 case 6:
164 sub_som_type1 = 1;
165 sub_som_type2 = 3;
166 break;
167 case 7:
168 sub_som_type1 = 1;
169 sub_som_type2 = 2;
170 break;
171 default:
Yannic Moog46c507e2023-12-20 09:45:36 +0100172 pr_err("%s: Invalid SoM type: %i", __func__, api2->som_type);
173 return;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200174 };
175
176 printf("SoM: %s-%03u-%s-%03u ",
177 phytec_som_type_str[sub_som_type1],
178 api2->som_no, phytec_som_type_str[sub_som_type2],
179 api2->ksp_no);
180 }
181
182 printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
183 api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
184}
185
186char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
187{
188 char *opt;
189
190 if (!data)
191 data = &eeprom_data;
192
Yannic Moog51b9d532024-04-19 08:55:38 -0700193 if (!data->valid)
194 return NULL;
195
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700196 if (data->payload.api_rev < PHYTEC_API_REV2)
197 opt = data->payload.data.data_api0.opt;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200198 else
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700199 opt = data->payload.data.data_api2.opt;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200200
201 return opt;
202}
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200203
204u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
205{
206 struct phytec_api2_data *api2;
207
208 if (!data)
209 data = &eeprom_data;
210
Yannic Moog51b9d532024-04-19 08:55:38 -0700211 if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200212 return PHYTEC_EEPROM_INVAL;
213
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700214 api2 = &data->payload.data.data_api2;
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200215
216 return api2->pcb_rev;
217}
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100218
Benjamin Hahn455dcf72024-03-06 17:18:31 +0100219u8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data)
220{
221 if (!data)
222 data = &eeprom_data;
Yannic Moog51b9d532024-04-19 08:55:38 -0700223
224 if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
Benjamin Hahn455dcf72024-03-06 17:18:31 +0100225 return PHYTEC_EEPROM_INVAL;
226
Yannic Moogdb2dfb02024-04-19 08:55:37 -0700227 return data->payload.data.data_api2.som_type;
Benjamin Hahn455dcf72024-03-06 17:18:31 +0100228}
229
Daniel Schultza440ec22024-04-19 08:55:36 -0700230#if IS_ENABLED(CONFIG_CMD_EXTENSION)
231struct extension *phytec_add_extension(const char *name, const char *overlay,
232 const char *other)
233{
234 struct extension *extension;
235
236 if (strlen(overlay) > sizeof(extension->overlay)) {
237 pr_err("Overlay name %s is longer than %lu.\n", overlay,
238 sizeof(extension->overlay));
239 return NULL;
240 }
241
242 extension = calloc(1, sizeof(struct extension));
243 snprintf(extension->name, sizeof(extension->name), name);
244 snprintf(extension->overlay, sizeof(extension->overlay), overlay);
245 snprintf(extension->other, sizeof(extension->other), other);
246 snprintf(extension->owner, sizeof(extension->owner), "PHYTEC");
247
248 return extension;
249}
250#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */
251
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100252#else
253
254inline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
255 int bus_num, int addr)
256{
257 return PHYTEC_EEPROM_INVAL;
258}
259
260inline int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
261 int bus_num, int addr,
262 int addr_fallback)
263{
264 return PHYTEC_EEPROM_INVAL;
265}
266
267inline int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
268 int bus_num, int addr)
269{
270 return PHYTEC_EEPROM_INVAL;
271}
272
273inline void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
274{
275}
276
277inline char *__maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
278{
279 return NULL;
280}
281
282u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
283{
284 return PHYTEC_EEPROM_INVAL;
285}
286
Benjamin Hahn69ea0e32024-03-12 10:39:11 +0100287u8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data)
288{
289 return PHYTEC_EEPROM_INVAL;
290}
Daniel Schultza440ec22024-04-19 08:55:36 -0700291
292#if IS_ENABLED(CONFIG_CMD_EXTENSION)
293inline struct extension *phytec_add_extension(const char *name,
294 const char *overlay,
295 const char *other)
296{
297 return NULL;
298}
299#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */
Benjamin Hahn69ea0e32024-03-12 10:39:11 +0100300
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100301#endif /* IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) */