blob: 366bdd4ace4bb4913989085f2a22d2b5d6fd0c7f [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
19int 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;
86 for (i = 0; i < sizeof(struct phytec_eeprom_data); i += sizeof(ptr))
87 if (*ptr != 0x0)
88 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:
162 break;
163 };
164
165 printf("SoM: %s-%03u-%s-%03u ",
166 phytec_som_type_str[sub_som_type1],
167 api2->som_no, phytec_som_type_str[sub_som_type2],
168 api2->ksp_no);
169 }
170
171 printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
172 api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
173}
174
175char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
176{
177 char *opt;
178
179 if (!data)
180 data = &eeprom_data;
181
182 if (data->api_rev < PHYTEC_API_REV2)
183 opt = data->data.data_api0.opt;
184 else
185 opt = data->data.data_api2.opt;
186
187 return opt;
188}