blob: 1b10923b62f30a244721dbf0daee02a08d5f6dfd [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>
8#include <asm/mach-imx/mxc_i2c.h>
9#include <asm/arch/sys_proto.h>
10#include <dm/device.h>
11#include <dm/uclass.h>
12#include <i2c.h>
13#include <u-boot/crc.h>
14
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;
56 int *ptr;
57
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);
67 return ret;
68 }
69
70 ret = dm_i2c_read(dev, 0, (uint8_t *)data,
71 sizeof(struct phytec_eeprom_data));
72 if (ret) {
73 pr_err("%s: Unable to read EEPROM data\n", __func__);
74 return ret;
75 }
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
82 if (data->api_rev == 0xff) {
83 pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
84 return -EINVAL;
85 }
86
87 ptr = (int *)data;
Yannic Moog7bbbe182023-12-20 09:45:34 +010088 for (i = 0; i < sizeof(struct phytec_eeprom_data); i++)
89 if (ptr[i] != 0x0)
Teresa Remmeta6f8da52023-08-17 10:57:06 +020090 break;
91
92 if (i == sizeof(struct phytec_eeprom_data)) {
93 pr_err("%s: EEPROM data is all zero. Erased?\n", __func__);
94 return -EINVAL;
95 }
96
97 /* We are done here for early revisions */
98 if (data->api_rev <= PHYTEC_API_REV1)
99 return 0;
100
101 crc = crc8(0, (const unsigned char *)data,
102 sizeof(struct phytec_eeprom_data));
103 debug("%s: crc: %x\n", __func__, crc);
104
105 if (crc) {
106 pr_err("%s: CRC mismatch. EEPROM data is not usable\n",
107 __func__);
108 return -EINVAL;
109 }
110
111 return 0;
112}
113
114void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
115{
116 struct phytec_api2_data *api2;
117 char pcb_sub_rev;
118 unsigned int ksp_no, sub_som_type1, sub_som_type2;
119
120 if (!data)
121 data = &eeprom_data;
122
123 if (data->api_rev < PHYTEC_API_REV2)
124 return;
125
126 api2 = &data->data.data_api2;
127
128 /* Calculate PCB subrevision */
129 pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f;
130 pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' ';
131
132 /* print standard product string */
133 if (api2->som_type <= 1) {
134 printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n",
135 phytec_som_type_str[api2->som_type], api2->som_no,
136 api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
137 return;
138 }
139 /* print KSP/KSM string */
140 if (api2->som_type <= 3) {
141 ksp_no = (api2->ksp_no << 8) | api2->som_no;
142 printf("SoM: %s-%u ",
143 phytec_som_type_str[api2->som_type], ksp_no);
144 /* print standard product based KSP/KSM strings */
145 } else {
146 switch (api2->som_type) {
147 case 4:
148 sub_som_type1 = 0;
149 sub_som_type2 = 3;
150 break;
151 case 5:
152 sub_som_type1 = 0;
153 sub_som_type2 = 2;
154 break;
155 case 6:
156 sub_som_type1 = 1;
157 sub_som_type2 = 3;
158 break;
159 case 7:
160 sub_som_type1 = 1;
161 sub_som_type2 = 2;
162 break;
163 default:
Yannic Moog46c507e2023-12-20 09:45:36 +0100164 pr_err("%s: Invalid SoM type: %i", __func__, api2->som_type);
165 return;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200166 };
167
168 printf("SoM: %s-%03u-%s-%03u ",
169 phytec_som_type_str[sub_som_type1],
170 api2->som_no, phytec_som_type_str[sub_som_type2],
171 api2->ksp_no);
172 }
173
174 printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
175 api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
176}
177
178char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
179{
180 char *opt;
181
182 if (!data)
183 data = &eeprom_data;
184
185 if (data->api_rev < PHYTEC_API_REV2)
186 opt = data->data.data_api0.opt;
187 else
188 opt = data->data.data_api2.opt;
189
190 return opt;
191}
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200192
193u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
194{
195 struct phytec_api2_data *api2;
196
197 if (!data)
198 data = &eeprom_data;
199
200 if (data->api_rev < PHYTEC_API_REV2)
201 return PHYTEC_EEPROM_INVAL;
202
203 api2 = &data->data.data_api2;
204
205 return api2->pcb_rev;
206}
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100207
208#else
209
210inline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
211 int bus_num, int addr)
212{
213 return PHYTEC_EEPROM_INVAL;
214}
215
216inline int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
217 int bus_num, int addr,
218 int addr_fallback)
219{
220 return PHYTEC_EEPROM_INVAL;
221}
222
223inline int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
224 int bus_num, int addr)
225{
226 return PHYTEC_EEPROM_INVAL;
227}
228
229inline void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
230{
231}
232
233inline char *__maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
234{
235 return NULL;
236}
237
238u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
239{
240 return PHYTEC_EEPROM_INVAL;
241}
242
243#endif /* IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) */