1// 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/arch/sys_proto.h>
9#include <dm/device.h>
10#include <dm/uclass.h>
11#include <i2c.h>
12#include <u-boot/crc.h>
13
14#include "imx8m_som_detection.h"
15
16extern struct phytec_eeprom_data eeprom_data;
17
18#if IS_ENABLED(CONFIG_PHYTEC_IMX8M_SOM_DETECTION)
19
20/* Check if the SoM is actually one of the following products:
21 * - i.MX8MM
22 * - i.MX8MN
23 * - i.MX8MP
24 * - i.MX8MQ
25 *
26 * Returns 0 in case it's a known SoM. Otherwise, returns -1.
27 */
28int __maybe_unused phytec_imx8m_detect(struct phytec_eeprom_data *data)
29{
30	char *opt;
31	u8 som;
32
33	if (!data)
34		data = &eeprom_data;
35
36	/* We can not do the check for early API revisions */
37	if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
38		return -1;
39
40	som = data->payload.data.data_api2.som_no;
41	debug("%s: som id: %u\n", __func__, som);
42
43	opt = phytec_get_opt(data);
44	if (!opt)
45		return -1;
46
47	if (som == PHYTEC_IMX8MP_SOM && is_imx8mp())
48		return 0;
49
50	if (som == PHYTEC_IMX8MM_SOM) {
51		if ((PHYTEC_GET_OPTION(opt[0]) != 0) &&
52		    (PHYTEC_GET_OPTION(opt[1]) == 0) && is_imx8mm())
53			return 0;
54		else if ((PHYTEC_GET_OPTION(opt[0]) == 0) &&
55			 (PHYTEC_GET_OPTION(opt[1]) != 0) && is_imx8mn())
56			return 0;
57	}
58
59	if (som == PHYTEC_IMX8MQ_SOM && is_imx8mq())
60		return 0;
61
62	pr_err("%s: SoM ID does not match. Wrong EEPROM data?\n", __func__);
63	return -1;
64}
65
66/*
67 * All PHYTEC i.MX8M boards have RAM size definition at the
68 * same location.
69 */
70u8 __maybe_unused phytec_get_imx8m_ddr_size(struct phytec_eeprom_data *data)
71{
72	char *opt;
73	u8 ddr_id;
74
75	if (!data)
76		data = &eeprom_data;
77
78	if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
79		return PHYTEC_EEPROM_INVAL;
80
81	opt = phytec_get_opt(data);
82	if (opt)
83		ddr_id = PHYTEC_GET_OPTION(opt[2]);
84	else
85		ddr_id = PHYTEC_EEPROM_INVAL;
86
87	debug("%s: ddr id: %u\n", __func__, ddr_id);
88	return ddr_id;
89}
90
91/*
92 * Filter SPI-NOR flash information. All i.MX8M boards have this at
93 * the same location.
94 * returns: 0x0 if no SPI is populated. Otherwise a board depended
95 * code for the size. PHYTEC_EEPROM_INVAL when the data is invalid.
96 */
97u8 __maybe_unused phytec_get_imx8m_spi(struct phytec_eeprom_data *data)
98{
99	char *opt;
100	u8 spi;
101
102	if (!data)
103		data = &eeprom_data;
104
105	if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
106		return PHYTEC_EEPROM_INVAL;
107
108	opt = phytec_get_opt(data);
109	if (opt)
110		spi = PHYTEC_GET_OPTION(opt[4]);
111	else
112		spi = PHYTEC_EEPROM_INVAL;
113
114	debug("%s: spi: %u\n", __func__, spi);
115	return spi;
116}
117
118/*
119 * Filter ethernet phy information. All i.MX8M boards have this at
120 * the same location.
121 * returns: 0x0 if no ethernet phy is populated. 0x1 if it is populated.
122 * PHYTEC_EEPROM_INVAL when the data is invalid.
123 */
124u8 __maybe_unused phytec_get_imx8m_eth(struct phytec_eeprom_data *data)
125{
126	char *opt;
127	u8 eth;
128
129	if (!data)
130		data = &eeprom_data;
131
132	if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
133		return PHYTEC_EEPROM_INVAL;
134
135	opt = phytec_get_opt(data);
136	if (opt) {
137		eth = PHYTEC_GET_OPTION(opt[5]);
138		eth &= 0x1;
139	} else {
140		eth = PHYTEC_EEPROM_INVAL;
141	}
142
143	debug("%s: eth: %u\n", __func__, eth);
144	return eth;
145}
146
147/*
148 * Filter RTC information for phyCORE-i.MX8MP.
149 * returns: 0 if no RTC is populated. 1 if it is populated.
150 * PHYTEC_EEPROM_INVAL when the data is invalid.
151 */
152u8 __maybe_unused phytec_get_imx8mp_rtc(struct phytec_eeprom_data *data)
153{
154	char *opt;
155	u8 rtc;
156
157	if (!data)
158		data = &eeprom_data;
159
160	if (!data->valid || data->payload.api_rev < PHYTEC_API_REV2)
161		return PHYTEC_EEPROM_INVAL;
162
163	opt = phytec_get_opt(data);
164	if (opt) {
165		rtc = PHYTEC_GET_OPTION(opt[5]);
166		rtc &= 0x4;
167		rtc = !(rtc >> 2);
168	} else {
169		rtc = PHYTEC_EEPROM_INVAL;
170	}
171	debug("%s: rtc: %u\n", __func__, rtc);
172	return rtc;
173}
174
175#else
176
177inline int __maybe_unused phytec_imx8m_detect(struct phytec_eeprom_data *data)
178{
179	return -1;
180}
181
182inline u8 __maybe_unused
183phytec_get_imx8m_ddr_size(struct phytec_eeprom_data *data)
184{
185	return PHYTEC_EEPROM_INVAL;
186}
187
188inline u8 __maybe_unused phytec_get_imx8mp_rtc(struct phytec_eeprom_data *data)
189{
190	return PHYTEC_EEPROM_INVAL;
191}
192
193inline u8 __maybe_unused phytec_get_imx8m_spi(struct phytec_eeprom_data *data)
194{
195	return PHYTEC_EEPROM_INVAL;
196}
197
198inline u8 __maybe_unused phytec_get_imx8m_eth(struct phytec_eeprom_data *data)
199{
200	return PHYTEC_EEPROM_INVAL;
201}
202
203#endif /* IS_ENABLED(CONFIG_PHYTEC_IMX8M_SOM_DETECTION) */
204