blob: bda7aac5be4b3006447c251cec55bd24511701d6 [file] [log] [blame]
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018 NXP
4 * Copyright 2020 Linaro
5 */
6
Sughosh Ganuccb36462022-04-15 11:29:34 +05307#include <efi.h>
8#include <efi_loader.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +08009#include <env.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080010#include <extension_board.h>
Fabio Estevam838b2e82024-05-28 16:15:10 -030011#include <fdt_support.h>
Ying-Chun Liu (PaulLiu)20dc0ba2021-08-24 17:44:19 +080012#include <hang.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080013#include <i2c.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080014#include <init.h>
15#include <miiphy.h>
16#include <netdev.h>
Fabio Estevamf2acfc72022-04-12 13:05:37 -030017#include <i2c_eeprom.h>
18#include <i2c.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080019
20#include <asm/arch/clock.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080021#include <asm/arch/imx8mm_pins.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080022#include <asm/arch/sys_proto.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080023#include <asm/global_data.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080024#include <asm/io.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080025#include <asm/mach-imx/gpio.h>
26#include <asm/mach-imx/mxc_i2c.h>
27#include <asm/sections.h>
Sughosh Ganuccb36462022-04-15 11:29:34 +053028#include <linux/kernel.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080029
Ying-Chun Liu (PaulLiu)20dc0ba2021-08-24 17:44:19 +080030#include "ddr/ddr.h"
31
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080032DECLARE_GLOBAL_DATA_PTR;
33
Fabio Estevam838b2e82024-05-28 16:15:10 -030034static int fec_phyaddr = -1;
35
Simon Glassb8196212023-02-05 15:39:42 -070036#if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
Sughosh Ganuccb36462022-04-15 11:29:34 +053037struct efi_fw_image fw_images[] = {
38#if defined(CONFIG_TARGET_IMX8MM_CL_IOT_GATE)
39 {
40 .image_type_id = IMX8MM_CL_IOT_GATE_FIT_IMAGE_GUID,
41 .fw_name = u"IMX8MM-CL-IOT-GATE-FIT",
42 .image_index = 1,
43 },
44#elif defined(CONFIG_TARGET_IMX8MM_CL_IOT_GATE_OPTEE)
45 {
46 .image_type_id = IMX8MM_CL_IOT_GATE_OPTEE_FIT_IMAGE_GUID,
47 .fw_name = u"IMX8MM-CL-IOT-GATE-FIT",
48 .image_index = 1,
49 },
50#endif
51};
52
53struct efi_capsule_update_info update_info = {
54 .dfu_string = "mmc 2=flash-bin raw 0x42 0x1D00 mmcpart 1",
Masahisa Kojima5d2438b2023-06-07 14:41:51 +090055 .num_images = ARRAY_SIZE(fw_images),
Sughosh Ganuccb36462022-04-15 11:29:34 +053056 .images = fw_images,
57};
58
Sughosh Ganuccb36462022-04-15 11:29:34 +053059#endif /* EFI_HAVE_CAPSULE_SUPPORT */
60
Ying-Chun Liu (PaulLiu)20dc0ba2021-08-24 17:44:19 +080061int board_phys_sdram_size(phys_size_t *size)
62{
63 struct lpddr4_tcm_desc *lpddr4_tcm_desc =
64 (struct lpddr4_tcm_desc *)TCM_DATA_CFG;
65
66 switch (lpddr4_tcm_desc->size) {
67 case 4096:
68 case 2048:
69 case 1024:
70 *size = (1L << 20) * lpddr4_tcm_desc->size;
71 break;
72 default:
73 printf("%s: DRAM size %uM is not supported\n",
74 __func__,
75 lpddr4_tcm_desc->size);
76 hang();
77 break;
78 };
79
80 return 0;
81}
82
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080083/* IOT_GATE-iMX8 extension boards ID */
84typedef enum {
85 IOT_GATE_EXT_EMPTY, /* No extension */
86 IOT_GATE_EXT_CAN, /* CAN bus */
87 IOT_GATE_EXT_IED, /* Bridge */
88 IOT_GATE_EXT_POE, /* POE */
89 IOT_GATE_EXT_POEV2, /* POEv2 */
90} iot_gate_imx8_ext;
91
92typedef enum {
93 IOT_GATE_IMX8_CARD_ID_EMPTY = 0, /* card id - uninhabited */
94 IOT_GATE_IMX8_CARD_ID_DI4O4 = 1, /* Card ID - IED-DI4O4 */
95 IOT_GATE_IMX8_CARD_ID_RS_485 = 2, /* Card ID - IED-RS485 */
96 IOT_GATE_IMX8_CARD_ID_TPM = 3, /* Card ID - IED-TPM */
97 IOT_GATE_IMX8_CARD_ID_CAN = 4, /* Card ID - IED-CAN */
98 IOT_GATE_IMX8_CARD_ID_CL420 = 5, /* Card ID - IED-CL420 */
99 IOT_GATE_IMX8_CARD_ID_RS_232 = 6, /* Card ID - IED-RS232 */
100} iot_gate_imx8_ied_ext;
101
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800102static int setup_fec(void)
103{
104 if (IS_ENABLED(CONFIG_FEC_MXC)) {
105 struct iomuxc_gpr_base_regs *gpr =
106 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
107
108 /* Use 125M anatop REF_CLK1 for ENET1, not from external */
109 clrsetbits_le32(&gpr->gpr[1], 0x2000, 0);
110 }
111
112 return 0;
113}
114
Fabio Estevam838b2e82024-05-28 16:15:10 -0300115#define FDT_PHYADDR "/soc@0/bus@30800000/ethernet@30be0000/mdio/ethernet-phy@0"
116#define FLIP_32B(val) (((val >> 24) & 0xff) | ((val << 8) & 0xff0000) | ((val >> 8) & 0xff00) | ((val << 24) & 0xff000000))
117static int fdt_set_fec_phy_addr(void *blob)
118{
119 u32 val;
120
121 if (fec_phyaddr < 0)
122 return -EINVAL;
123
124 val = FLIP_32B(fec_phyaddr);
125 return fdt_find_and_setprop(blob, FDT_PHYADDR, "reg", (const void *)&val,
126 sizeof(val), 0);
127}
128
129int ft_board_setup(void *blob, struct bd_info *bd)
130{
131 fdt_set_fec_phy_addr(blob);
132 return 0;
133}
134
135/*
136 * These are specific ID, purposed to distiguish between PHY vendors.
137 * These values are not equal to real vendors' OUI (half of MAC address)
138 */
139#define OUI_PHY_ATHEROS 0x1374
140#define OUI_PHY_REALTEK 0x0732
141
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800142int board_phy_config(struct phy_device *phydev)
143{
Fabio Estevam838b2e82024-05-28 16:15:10 -0300144 unsigned int model, rev, oui;
145 int phyid1, phyid2;
146 unsigned int reg;
147
148 if (!IS_ENABLED(CONFIG_FEC_MXC))
149 return 0;
150
151 phyid1 = phy_read(phydev, MDIO_DEVAD_NONE, MII_PHYSID1);
152 if (phyid1 < 0) {
153 printf("%s: PHYID1 registry read fail %i\n", __func__, phyid1);
154 return phyid1;
155 }
156
157 phyid2 = phy_read(phydev, MDIO_DEVAD_NONE, MII_PHYSID2);
158 if (phyid2 < 0) {
159 printf("%s: PHYID2 registry read fail %i\n", __func__, phyid2);
160 return phyid2;
161 }
162
163 reg = phyid2 | phyid1 << 16;
164 if (reg == 0xffff) {
165 printf("%s: There is no device @%i\n", __func__, phydev->addr);
166 return -ENODEV;
167 }
168
169 rev = reg & 0xf;
170 reg >>= 4;
171 model = reg & 0x3f;
172 reg >>= 6;
173 oui = reg;
174 debug("%s: PHY @0x%x OUI 0x%06x model 0x%x rev 0x%x\n",
175 __func__, phydev->addr, oui, model, rev);
176
177 switch (oui) {
178 case OUI_PHY_ATHEROS:
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800179 /* enable rgmii rxc skew and phy mode select to RGMII copper */
Fabio Estevam838b2e82024-05-28 16:15:10 -0300180 printf("phy: AR803x@%x\t", phydev->addr);
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800181 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
182 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8);
183
184 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x00);
185 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x82ee);
186 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
187 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
Fabio Estevam838b2e82024-05-28 16:15:10 -0300188 break;
189 case OUI_PHY_REALTEK:
190 printf("phy: RTL8211E@%x\t", phydev->addr);
191 /* RTL8211E-VB-CG - add TX and RX delay */
192 unsigned short val;
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800193
Fabio Estevam838b2e82024-05-28 16:15:10 -0300194 phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x07);
195 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0xa4);
196 val = phy_read(phydev, MDIO_DEVAD_NONE, 0x1c);
197 val |= (0x1 << 13) | (0x1 << 12) | (0x1 << 11);
198 phy_write(phydev, MDIO_DEVAD_NONE, 0x1c, val);
199 /* LEDs: set to extension page */
200 phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x0007);
201 /* extension Page44 */
202 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x002c);
203 phy_write(phydev, MDIO_DEVAD_NONE, 0x1c, 0x0430);//LCR
204 phy_write(phydev, MDIO_DEVAD_NONE, 0x1a, 0x0010);//LACR
205 /*
206 * To disable EEE LED mode (blinking .4s/2s)
207 * Extension Page5
208 */
209 phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x0005);
210 phy_write(phydev, MDIO_DEVAD_NONE, 0x05, 0x8b82);//magic const
211 phy_write(phydev, MDIO_DEVAD_NONE, 0x06, 0x052b);//magic const
212
213 phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x00);// Back to Page0
214
215 break;
216 default:
217 printf("%s: ERROR: unknown PHY @0x%x OUI 0x%06x model 0x%x rev 0x%x\n",
218 __func__, phydev->addr, oui, model, rev);
219 return -ENOSYS;
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800220 }
Fabio Estevam838b2e82024-05-28 16:15:10 -0300221
222 fec_phyaddr = phydev->addr;
223
224 if (phydev->drv->config)
225 phydev->drv->config(phydev);
226
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800227 return 0;
228}
229
230int board_init(void)
231{
232 if (IS_ENABLED(CONFIG_FEC_MXC))
233 setup_fec();
234
235 return 0;
236}
237
238int board_mmc_get_env_dev(int devno)
239{
240 return devno;
241}
242
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +0800243#define IOT_GATE_IMX8_EXT_I2C 3 /* I2C ID of the extension board */
244#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM 0x54 /* I2C address of the EEPROM */
245
246/* I2C address of the EEPROM in the POE extension */
247#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POE 0x50
248#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POEV2 0x51
249#define IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO 0x22 /* I2C address of the GPIO
250 extender */
251
252static int iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY; /* Extension board ID */
253static int iot_gate_imx8_ext_ied_id [3] = {
254 IOT_GATE_IMX8_CARD_ID_EMPTY,
255 IOT_GATE_IMX8_CARD_ID_EMPTY,
256 IOT_GATE_IMX8_CARD_ID_EMPTY };
257
258/*
259 * iot_gate_imx8_detect_ext() - extended board detection
260 * The detection is done according to the detected I2C devices.
261 */
262static void iot_gate_imx8_detect_ext(void)
263{
264 int ret;
265 struct udevice *i2c_bus, *i2c_dev;
266
267 ret = uclass_get_device_by_seq(UCLASS_I2C, IOT_GATE_IMX8_EXT_I2C,
268 &i2c_bus);
269 if (ret) {
270 printf("%s: Failed getting i2c device\n", __func__);
271 return;
272 }
273
274 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POE, 0,
275 &i2c_dev);
276 if (!ret) {
277 iot_gate_imx8_ext_id = IOT_GATE_EXT_POE;
278 return;
279 }
280
281 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POEV2, 0,
282 &i2c_dev);
283 if (!ret) {
284 iot_gate_imx8_ext_id = IOT_GATE_EXT_POEV2;
285 return;
286 }
287
288 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM, 0,
289 &i2c_dev);
290 if (ret){
291 iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY;
292 return;
293 }
294 /* Only the bridge extension includes the GPIO extender */
295 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO, 0,
296 &i2c_dev);
297 if (ret) /* GPIO extender not detected */
298 iot_gate_imx8_ext_id = IOT_GATE_EXT_CAN;
299 else /* GPIO extender detected */
300 iot_gate_imx8_ext_id = IOT_GATE_EXT_IED;
301}
302
303static iomux_v3_cfg_t const iot_gate_imx8_ext_ied_pads[] = {
304 IMX8MM_PAD_NAND_ALE_GPIO3_IO0 | MUX_PAD_CTRL(PAD_CTL_PE),
305 IMX8MM_PAD_NAND_CE0_B_GPIO3_IO1 | MUX_PAD_CTRL(PAD_CTL_PE),
306 IMX8MM_PAD_NAND_DATA00_GPIO3_IO6 | MUX_PAD_CTRL(PAD_CTL_PE),
307 IMX8MM_PAD_NAND_DATA01_GPIO3_IO7 | MUX_PAD_CTRL(PAD_CTL_PE),
308 IMX8MM_PAD_NAND_DATA02_GPIO3_IO8 | MUX_PAD_CTRL(PAD_CTL_PE),
309 IMX8MM_PAD_NAND_DATA03_GPIO3_IO9 | MUX_PAD_CTRL(PAD_CTL_PE),
310};
311
312static iomux_v3_cfg_t const iot_gate_imx8_ext_poev2_pads[] = {
313 IMX8MM_PAD_SAI3_TXD_GPIO5_IO1 | MUX_PAD_CTRL(PAD_CTL_PE |
314 PAD_CTL_PUE),
315};
316
317/* Extension board bridge GPIOs */
318#define IOT_GATE_IMX8_GPIO_EXT_IED_I0 IMX_GPIO_NR(3, 0) /* IN 0 */
319#define IOT_GATE_IMX8_GPIO_EXT_IED_I1 IMX_GPIO_NR(3, 1) /* IN 1 */
320#define IOT_GATE_IMX8_GPIO_EXT_IED_I2 IMX_GPIO_NR(3, 6) /* IN 2 */
321#define IOT_GATE_IMX8_GPIO_EXT_IED_I3 IMX_GPIO_NR(3, 7) /* IN 3 */
322#define IOT_GATE_IMX8_GPIO_EXT_IED_O0 IMX_GPIO_NR(3, 8) /* OUT 0 */
323#define IOT_GATE_IMX8_GPIO_EXT_IED_O1 IMX_GPIO_NR(3, 9) /* OUT 1 */
324#define IOT_GATE_IMX8_GPIO_EXT_IED_O2 IMX_GPIO_NR(6, 9) /* OUT 2 */
325#define IOT_GATE_IMX8_GPIO_EXT_IED_O3 IMX_GPIO_NR(6, 10)/* OUT 3 */
326
327/* Extension board POE GPIOs */
328#define IOT_GATE_IMX8_GPIO_EXT_POE_MUX IMX_GPIO_NR(5, 1)/* USB_MUX */
329
330/*
331 * iot_gate_imx8_update_pinmux() - update the pinmux
332 * Update the pinmux according to the detected extended board.
333 */
334static void iot_gate_imx8_update_pinmux(void)
335{
336 if (iot_gate_imx8_ext_id == IOT_GATE_EXT_POEV2) {
337 imx_iomux_v3_setup_multiple_pads(iot_gate_imx8_ext_poev2_pads,
338 ARRAY_SIZE(iot_gate_imx8_ext_poev2_pads));
339 gpio_request(IOT_GATE_IMX8_GPIO_EXT_POE_MUX, "poev2_usb-mux");
340 /* Update USB MUX state */
341 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_POE_MUX, 1);
342
343 return;
344 }
345 if (iot_gate_imx8_ext_id != IOT_GATE_EXT_IED)
346 return;
347
348 imx_iomux_v3_setup_multiple_pads(iot_gate_imx8_ext_ied_pads,
349 ARRAY_SIZE(iot_gate_imx8_ext_ied_pads));
350
351 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I0, "ied-di4o4_i0");
352 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I0);
353 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I1, "ied-di4o4_i1");
354 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I1);
355 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I2, "ied-di4o4_i2");
356 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I2);
357 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I3, "ied-di4o4_i3");
358 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I3);
359 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O0, "ied-di4o4_o0");
360 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O0, 0);
361 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O1, "ied-di4o4_o1");
362 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O1, 0);
363 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O2, "ied-di4o4_o2");
364 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O2, 0);
365 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O3, "ied-di4o4_o3");
366 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O3, 0);
367}
368
369#define IOT_GATE_IMX8_GPIO_S0B0 IMX_GPIO_NR(6, 0) /* Slot ID slot 0 bit 0 */
370#define IOT_GATE_IMX8_GPIO_S0B1 IMX_GPIO_NR(6, 1) /* Slot ID slot 0 bit 1 */
371#define IOT_GATE_IMX8_GPIO_S0B2 IMX_GPIO_NR(6, 2) /* Slot ID slot 0 bit 2 */
372#define IOT_GATE_IMX8_GPIO_S1B0 IMX_GPIO_NR(6, 3) /* Slot ID slot 1 bit 0 */
373#define IOT_GATE_IMX8_GPIO_S1B1 IMX_GPIO_NR(6, 4) /* Slot ID slot 1 bit 1 */
374#define IOT_GATE_IMX8_GPIO_S1B2 IMX_GPIO_NR(6, 5) /* Slot ID slot 1 bit 2 */
375#define IOT_GATE_IMX8_GPIO_S2B0 IMX_GPIO_NR(6, 6) /* Slot ID slot 2 bit 0 */
376#define IOT_GATE_IMX8_GPIO_S2B1 IMX_GPIO_NR(6, 7) /* Slot ID slot 2 bit 1 */
377#define IOT_GATE_IMX8_GPIO_S2B2 IMX_GPIO_NR(6, 8) /* Slot ID slot 2 bit 2 */
378
379/*
380 * iot_gate_imx8_update_ext_ied()
381 * Update device tree of the extended board IED-BASE.
382 * The device tree is updated according to the detected sub modules.
383 *
384 * Return 0 for success, 1 for failure.
385 */
386static int iot_gate_imx8_update_ext_ied(void)
387{
388 int revision;
389
390 if (iot_gate_imx8_ext_id != IOT_GATE_EXT_IED)
391 return 0;
392
393 /* ID GPIO initializations */
394 if (gpio_request(IOT_GATE_IMX8_GPIO_S0B0, "id_s0b0") ||
395 gpio_request(IOT_GATE_IMX8_GPIO_S0B1, "id_s0b1") ||
396 gpio_request(IOT_GATE_IMX8_GPIO_S0B2, "id_s0b2") ||
397 gpio_request(IOT_GATE_IMX8_GPIO_S1B0, "id_s1b0") ||
398 gpio_request(IOT_GATE_IMX8_GPIO_S1B1, "id_s1b1") ||
399 gpio_request(IOT_GATE_IMX8_GPIO_S1B2, "id_s1b2") ||
400 gpio_request(IOT_GATE_IMX8_GPIO_S2B0, "id_s2b0") ||
401 gpio_request(IOT_GATE_IMX8_GPIO_S2B1, "id_s2b1") ||
402 gpio_request(IOT_GATE_IMX8_GPIO_S2B2, "id_s2b2")) {
403 printf("%s: ID GPIO request failure\n", __func__);
404 return 1;
405 }
406 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B0);
407 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B1);
408 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B2);
409 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B0);
410 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B1);
411 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B2);
412 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B0);
413 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B1);
414 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B2);
415
416 /* Get slot 0 card ID */
417 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S0B0) |
418 gpio_get_value(IOT_GATE_IMX8_GPIO_S0B1) << 1 |
419 gpio_get_value(IOT_GATE_IMX8_GPIO_S0B2) << 2;
420 iot_gate_imx8_ext_ied_id[0] = revision;
421
422 /* Get slot 1 card ID */
423 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S1B0) |
424 gpio_get_value(IOT_GATE_IMX8_GPIO_S1B1) << 1 |
425 gpio_get_value(IOT_GATE_IMX8_GPIO_S1B2) << 2;
426 iot_gate_imx8_ext_ied_id[1] = revision;
427
428 /* Get slot 2 card ID */
429 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S2B0) |
430 gpio_get_value(IOT_GATE_IMX8_GPIO_S2B1) << 1 |
431 gpio_get_value(IOT_GATE_IMX8_GPIO_S2B2) << 2;
432 iot_gate_imx8_ext_ied_id[2] = revision;
433
434 return 0;
435}
436
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +0800437int extension_board_scan(struct list_head *extension_list)
438{
439 struct extension *extension = NULL;
440 int i;
441 int ret = 0;
442
443 iot_gate_imx8_detect_ext(); /* Extended board detection */
444
445 switch(iot_gate_imx8_ext_id) {
446 case IOT_GATE_EXT_EMPTY:
447 break;
448 case IOT_GATE_EXT_CAN:
449 extension = calloc(1, sizeof(struct extension));
450 snprintf(extension->name, sizeof(extension->name),
451 "IOT_GATE_EXT_CAN");
452 break;
453 case IOT_GATE_EXT_IED:
454 extension = calloc(1, sizeof(struct extension));
455 snprintf(extension->name, sizeof(extension->name),
456 "IOT_GATE_EXT_IED");
457 snprintf(extension->overlay, sizeof(extension->overlay),
458 "imx8mm-cl-iot-gate-ied.dtbo");
459 break;
460 case IOT_GATE_EXT_POE:
461 extension = calloc(1, sizeof(struct extension));
462 snprintf(extension->name, sizeof(extension->name),
463 "IOT_GATE_EXT_POE");
464 break;
465 case IOT_GATE_EXT_POEV2:
466 extension = calloc(1, sizeof(struct extension));
467 snprintf(extension->name, sizeof(extension->name),
468 "IOT_GATE_EXT_POEV2");
469 break;
470 default:
471 printf("IOT_GATE-iMX8 extension board: unknown\n");
472 break;
473 }
474
475 if (extension) {
476 snprintf(extension->owner, sizeof(extension->owner),
477 "Compulab");
478 list_add_tail(&extension->list, extension_list);
479 ret = 1;
480 } else
481 return ret;
482
483 iot_gate_imx8_update_pinmux();
484
485 iot_gate_imx8_update_ext_ied();
486 for (i=0; i<ARRAY_SIZE(iot_gate_imx8_ext_ied_id); i++) {
487 extension = NULL;
488 switch (iot_gate_imx8_ext_ied_id[i]) {
489 case IOT_GATE_IMX8_CARD_ID_EMPTY:
490 break;
491 case IOT_GATE_IMX8_CARD_ID_RS_485:
492 extension = calloc(1, sizeof(struct extension));
493 snprintf(extension->name, sizeof(extension->name),
494 "IOT_GATE_IMX8_CARD_ID_RS_485");
495 break;
496 case IOT_GATE_IMX8_CARD_ID_RS_232:
497 extension = calloc(1, sizeof(struct extension));
498 snprintf(extension->name, sizeof(extension->name),
499 "IOT_GATE_IMX8_CARD_ID_RS_232");
500 break;
501 case IOT_GATE_IMX8_CARD_ID_CAN:
502 extension = calloc(1, sizeof(struct extension));
503 snprintf(extension->name, sizeof(extension->name),
504 "IOT_GATE_IMX8_CARD_ID_CAN");
505 snprintf(extension->overlay, sizeof(extension->overlay),
506 "imx8mm-cl-iot-gate-ied-can%d.dtbo", i);
507 break;
508 case IOT_GATE_IMX8_CARD_ID_TPM:
509 extension = calloc(1, sizeof(struct extension));
510 snprintf(extension->name, sizeof(extension->name),
511 "IOT_GATE_IMX8_CARD_ID_TPM");
512 snprintf(extension->overlay, sizeof(extension->overlay),
513 "imx8mm-cl-iot-gate-ied-tpm%d.dtbo", i);
514 break;
515 case IOT_GATE_IMX8_CARD_ID_CL420:
516 extension = calloc(1, sizeof(struct extension));
517 snprintf(extension->name, sizeof(extension->name),
518 "IOT_GATE_IMX8_CARD_ID_CL420");
519 snprintf(extension->overlay, sizeof(extension->overlay),
520 "imx8mm-cl-iot-gate-ied-can%d.dtbo", i);
521 break;
522 case IOT_GATE_IMX8_CARD_ID_DI4O4:
523 extension = calloc(1, sizeof(struct extension));
524 snprintf(extension->name, sizeof(extension->name),
525 "IOT_GATE_IMX8_CARD_ID_DI4O4");
526 break;
527 default:
528 printf("%s: invalid slot %d card ID: %d\n",
529 __func__, i, iot_gate_imx8_ext_ied_id[i]);
530 break;
531 }
532 if (extension) {
533 snprintf(extension->owner, sizeof(extension->owner),
534 "Compulab");
535 snprintf(extension->other, sizeof(extension->other),
536 "On slot %d", i);
537 list_add_tail(&extension->list, extension_list);
538 ret = ret + 1;
539 }
540 }
541
542 return ret;
543}
544
Fabio Estevamf2acfc72022-04-12 13:05:37 -0300545static int setup_mac_address(void)
546{
547 unsigned char enetaddr[6];
548 struct udevice *dev;
549 int ret, off;
550
551 ret = eth_env_get_enetaddr("ethaddr", enetaddr);
552 if (ret)
553 return 0;
554
555 off = fdt_path_offset(gd->fdt_blob, "eeprom1");
556 if (off < 0) {
557 printf("No eeprom0 path offset found in DT\n");
558 return off;
559 }
560
561 ret = uclass_get_device_by_of_offset(UCLASS_I2C_EEPROM, off, &dev);
562 if (ret) {
563 printf("%s: Could not find EEPROM\n", __func__);
564 return ret;
565 }
566
567 ret = i2c_set_chip_offset_len(dev, 1);
568 if (ret)
569 return ret;
570
571 ret = i2c_eeprom_read(dev, 4, enetaddr, sizeof(enetaddr));
572 if (ret) {
573 printf("%s: Could not read EEPROM\n", __func__);
574 return ret;
575 }
576
577 ret = is_valid_ethaddr(enetaddr);
578 if (!ret)
579 return -EINVAL;
580
581 ret = eth_env_set_enetaddr("ethaddr", enetaddr);
582 if (ret)
583 return ret;
584
585 return 0;
586}
587
Fabio Estevam938f70f2022-04-12 13:05:38 -0300588static int read_serial_number(void)
589{
590 unsigned char serialnumber[6];
591 unsigned char reversed[6];
592 char serial_string[12];
593 struct udevice *dev;
594 int ret, off, i;
595
596 off = fdt_path_offset(gd->fdt_blob, "eeprom0");
597 if (off < 0) {
598 printf("No eeprom0 path offset found in DT\n");
599 return off;
600 }
601
602 ret = uclass_get_device_by_of_offset(UCLASS_I2C_EEPROM, off, &dev);
603 if (ret) {
604 printf("%s: Could not find EEPROM\n", __func__);
605 return ret;
606 }
607
608 ret = i2c_set_chip_offset_len(dev, 1);
609 if (ret)
610 return ret;
611
612 ret = i2c_eeprom_read(dev, 0x14, serialnumber, sizeof(serialnumber));
613 if (ret) {
614 printf("%s: Could not read EEPROM\n", __func__);
615 return ret;
616 }
617
618 for (i = sizeof(serialnumber) - 1; i >= 0; i--)
619 reversed[i] = serialnumber[sizeof(serialnumber) - 1 - i];
620
621 for (i = 0; i < sizeof(reversed); i++) {
622 serial_string[i * 2] = (reversed[i] >> 4) & 0xf;
623 serial_string[i * 2 + 1] = reversed[i] & 0xf;
624 }
625
626 for (i = 0; i < sizeof(serial_string); i++)
627 serial_string[i] += '0';
628
629 env_set("serial#", serial_string);
630
631 return 0;
632}
633
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800634int board_late_init(void)
635{
Fabio Estevamf2acfc72022-04-12 13:05:37 -0300636 int ret;
637
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800638 if (IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)) {
639 env_set("board_name", "IOT-GATE-IMX8");
640 env_set("board_rev", "SBC-IOTMX8");
641 }
642
Fabio Estevamf2acfc72022-04-12 13:05:37 -0300643 ret = setup_mac_address();
644 if (ret < 0)
645 printf("Cannot set MAC address from EEPROM\n");
646
Fabio Estevam938f70f2022-04-12 13:05:38 -0300647 ret = read_serial_number();
648 if (ret < 0)
649 printf("Cannot read serial number from EEPROM\n");
650
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800651 return 0;
652}