blob: c73bf9721b2f883189bc8ca7ba2cca99113097f1 [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>
12
13#include "phytec_som_detection.h"
14
15struct phytec_eeprom_data eeprom_data;
16
Yannic Moog5dd7f7c2023-12-20 09:45:35 +010017#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION)
18
Teresa Remmeta6f8da52023-08-17 10:57:06 +020019int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
20 int bus_num, int addr, int addr_fallback)
21{
22 int ret;
23
24 ret = phytec_eeprom_data_init(data, bus_num, addr);
25 if (ret) {
26 pr_err("%s: init failed. Trying fall back address 0x%x\n",
27 __func__, addr_fallback);
28 ret = phytec_eeprom_data_init(data, bus_num, addr_fallback);
29 }
30
31 if (ret)
32 pr_err("%s: EEPROM data init failed\n", __func__);
33
34 return ret;
35}
36
37int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
38 int bus_num, int addr)
39{
40 int ret;
41
42 ret = phytec_eeprom_data_init(data, bus_num, addr);
43 if (ret)
44 pr_err("%s: EEPROM data init failed\n", __func__);
45
46 return ret;
47}
48
49int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
50 int bus_num, int addr)
51{
52 int ret, i;
53 unsigned int crc;
54 int *ptr;
55
56 if (!data)
57 data = &eeprom_data;
58
59#if CONFIG_IS_ENABLED(DM_I2C)
60 struct udevice *dev;
61
62 ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev);
63 if (ret) {
64 pr_err("%s: i2c EEPROM not found: %i.\n", __func__, ret);
65 return ret;
66 }
67
68 ret = dm_i2c_read(dev, 0, (uint8_t *)data,
69 sizeof(struct phytec_eeprom_data));
70 if (ret) {
71 pr_err("%s: Unable to read EEPROM data\n", __func__);
72 return ret;
73 }
74#else
75 i2c_set_bus_num(bus_num);
76 ret = i2c_read(addr, 0, 2, (uint8_t *)data,
77 sizeof(struct phytec_eeprom_data));
78#endif
79
80 if (data->api_rev == 0xff) {
81 pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
82 return -EINVAL;
83 }
84
85 ptr = (int *)data;
Yannic Moog7bbbe182023-12-20 09:45:34 +010086 for (i = 0; i < sizeof(struct phytec_eeprom_data); i++)
87 if (ptr[i] != 0x0)
Teresa Remmeta6f8da52023-08-17 10:57:06 +020088 break;
89
90 if (i == sizeof(struct phytec_eeprom_data)) {
91 pr_err("%s: EEPROM data is all zero. Erased?\n", __func__);
92 return -EINVAL;
93 }
94
95 /* We are done here for early revisions */
96 if (data->api_rev <= PHYTEC_API_REV1)
97 return 0;
98
99 crc = crc8(0, (const unsigned char *)data,
100 sizeof(struct phytec_eeprom_data));
101 debug("%s: crc: %x\n", __func__, crc);
102
103 if (crc) {
104 pr_err("%s: CRC mismatch. EEPROM data is not usable\n",
105 __func__);
106 return -EINVAL;
107 }
108
109 return 0;
110}
111
112void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
113{
114 struct phytec_api2_data *api2;
115 char pcb_sub_rev;
116 unsigned int ksp_no, sub_som_type1, sub_som_type2;
117
118 if (!data)
119 data = &eeprom_data;
120
121 if (data->api_rev < PHYTEC_API_REV2)
122 return;
123
124 api2 = &data->data.data_api2;
125
126 /* Calculate PCB subrevision */
127 pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f;
128 pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' ';
129
130 /* print standard product string */
131 if (api2->som_type <= 1) {
132 printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n",
133 phytec_som_type_str[api2->som_type], api2->som_no,
134 api2->opt, api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
135 return;
136 }
137 /* print KSP/KSM string */
138 if (api2->som_type <= 3) {
139 ksp_no = (api2->ksp_no << 8) | api2->som_no;
140 printf("SoM: %s-%u ",
141 phytec_som_type_str[api2->som_type], ksp_no);
142 /* print standard product based KSP/KSM strings */
143 } else {
144 switch (api2->som_type) {
145 case 4:
146 sub_som_type1 = 0;
147 sub_som_type2 = 3;
148 break;
149 case 5:
150 sub_som_type1 = 0;
151 sub_som_type2 = 2;
152 break;
153 case 6:
154 sub_som_type1 = 1;
155 sub_som_type2 = 3;
156 break;
157 case 7:
158 sub_som_type1 = 1;
159 sub_som_type2 = 2;
160 break;
161 default:
Yannic Moog46c507e2023-12-20 09:45:36 +0100162 pr_err("%s: Invalid SoM type: %i", __func__, api2->som_type);
163 return;
Teresa Remmeta6f8da52023-08-17 10:57:06 +0200164 };
165
166 printf("SoM: %s-%03u-%s-%03u ",
167 phytec_som_type_str[sub_som_type1],
168 api2->som_no, phytec_som_type_str[sub_som_type2],
169 api2->ksp_no);
170 }
171
172 printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
173 api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
174}
175
176char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
177{
178 char *opt;
179
180 if (!data)
181 data = &eeprom_data;
182
183 if (data->api_rev < PHYTEC_API_REV2)
184 opt = data->data.data_api0.opt;
185 else
186 opt = data->data.data_api2.opt;
187
188 return opt;
189}
Teresa Remmete3d3ac42023-08-17 10:57:10 +0200190
191u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
192{
193 struct phytec_api2_data *api2;
194
195 if (!data)
196 data = &eeprom_data;
197
198 if (data->api_rev < PHYTEC_API_REV2)
199 return PHYTEC_EEPROM_INVAL;
200
201 api2 = &data->data.data_api2;
202
203 return api2->pcb_rev;
204}
Yannic Moog5dd7f7c2023-12-20 09:45:35 +0100205
206#else
207
208inline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
209 int bus_num, int addr)
210{
211 return PHYTEC_EEPROM_INVAL;
212}
213
214inline int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data *data,
215 int bus_num, int addr,
216 int addr_fallback)
217{
218 return PHYTEC_EEPROM_INVAL;
219}
220
221inline int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
222 int bus_num, int addr)
223{
224 return PHYTEC_EEPROM_INVAL;
225}
226
227inline void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data *data)
228{
229}
230
231inline char *__maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
232{
233 return NULL;
234}
235
236u8 __maybe_unused phytec_get_rev(struct phytec_eeprom_data *data)
237{
238 return PHYTEC_EEPROM_INVAL;
239}
240
241#endif /* IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) */