blob: 7e2d88f449cefe25bc07169583a7edea3f908bd0 [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
7#include <common.h>
8#include <env.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +08009#include <extension_board.h>
Ying-Chun Liu (PaulLiu)20dc0ba2021-08-24 17:44:19 +080010#include <hang.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080011#include <i2c.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080012#include <init.h>
13#include <miiphy.h>
14#include <netdev.h>
15
16#include <asm/arch/clock.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080017#include <asm/arch/imx8mm_pins.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080018#include <asm/arch/sys_proto.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080019#include <asm/global_data.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080020#include <asm/io.h>
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080021#include <asm/mach-imx/gpio.h>
22#include <asm/mach-imx/mxc_i2c.h>
23#include <asm/sections.h>
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080024
Ying-Chun Liu (PaulLiu)20dc0ba2021-08-24 17:44:19 +080025#include "ddr/ddr.h"
26
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080027DECLARE_GLOBAL_DATA_PTR;
28
Ying-Chun Liu (PaulLiu)20dc0ba2021-08-24 17:44:19 +080029int board_phys_sdram_size(phys_size_t *size)
30{
31 struct lpddr4_tcm_desc *lpddr4_tcm_desc =
32 (struct lpddr4_tcm_desc *)TCM_DATA_CFG;
33
34 switch (lpddr4_tcm_desc->size) {
35 case 4096:
36 case 2048:
37 case 1024:
38 *size = (1L << 20) * lpddr4_tcm_desc->size;
39 break;
40 default:
41 printf("%s: DRAM size %uM is not supported\n",
42 __func__,
43 lpddr4_tcm_desc->size);
44 hang();
45 break;
46 };
47
48 return 0;
49}
50
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +080051/* IOT_GATE-iMX8 extension boards ID */
52typedef enum {
53 IOT_GATE_EXT_EMPTY, /* No extension */
54 IOT_GATE_EXT_CAN, /* CAN bus */
55 IOT_GATE_EXT_IED, /* Bridge */
56 IOT_GATE_EXT_POE, /* POE */
57 IOT_GATE_EXT_POEV2, /* POEv2 */
58} iot_gate_imx8_ext;
59
60typedef enum {
61 IOT_GATE_IMX8_CARD_ID_EMPTY = 0, /* card id - uninhabited */
62 IOT_GATE_IMX8_CARD_ID_DI4O4 = 1, /* Card ID - IED-DI4O4 */
63 IOT_GATE_IMX8_CARD_ID_RS_485 = 2, /* Card ID - IED-RS485 */
64 IOT_GATE_IMX8_CARD_ID_TPM = 3, /* Card ID - IED-TPM */
65 IOT_GATE_IMX8_CARD_ID_CAN = 4, /* Card ID - IED-CAN */
66 IOT_GATE_IMX8_CARD_ID_CL420 = 5, /* Card ID - IED-CL420 */
67 IOT_GATE_IMX8_CARD_ID_RS_232 = 6, /* Card ID - IED-RS232 */
68} iot_gate_imx8_ied_ext;
69
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080070static int setup_fec(void)
71{
72 if (IS_ENABLED(CONFIG_FEC_MXC)) {
73 struct iomuxc_gpr_base_regs *gpr =
74 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
75
76 /* Use 125M anatop REF_CLK1 for ENET1, not from external */
77 clrsetbits_le32(&gpr->gpr[1], 0x2000, 0);
78 }
79
80 return 0;
81}
82
83int board_phy_config(struct phy_device *phydev)
84{
85 if (IS_ENABLED(CONFIG_FEC_MXC)) {
86 /* enable rgmii rxc skew and phy mode select to RGMII copper */
87 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
88 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8);
89
90 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x00);
91 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x82ee);
92 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
93 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
94
95 if (phydev->drv->config)
96 phydev->drv->config(phydev);
97 }
98 return 0;
99}
100
101int board_init(void)
102{
103 if (IS_ENABLED(CONFIG_FEC_MXC))
104 setup_fec();
105
106 return 0;
107}
108
109int board_mmc_get_env_dev(int devno)
110{
111 return devno;
112}
113
Ying-Chun Liu (PaulLiu)a96ed8d2021-11-05 17:13:25 +0800114#define IOT_GATE_IMX8_EXT_I2C 3 /* I2C ID of the extension board */
115#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM 0x54 /* I2C address of the EEPROM */
116
117/* I2C address of the EEPROM in the POE extension */
118#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POE 0x50
119#define IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POEV2 0x51
120#define IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO 0x22 /* I2C address of the GPIO
121 extender */
122
123static int iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY; /* Extension board ID */
124static int iot_gate_imx8_ext_ied_id [3] = {
125 IOT_GATE_IMX8_CARD_ID_EMPTY,
126 IOT_GATE_IMX8_CARD_ID_EMPTY,
127 IOT_GATE_IMX8_CARD_ID_EMPTY };
128
129/*
130 * iot_gate_imx8_detect_ext() - extended board detection
131 * The detection is done according to the detected I2C devices.
132 */
133static void iot_gate_imx8_detect_ext(void)
134{
135 int ret;
136 struct udevice *i2c_bus, *i2c_dev;
137
138 ret = uclass_get_device_by_seq(UCLASS_I2C, IOT_GATE_IMX8_EXT_I2C,
139 &i2c_bus);
140 if (ret) {
141 printf("%s: Failed getting i2c device\n", __func__);
142 return;
143 }
144
145 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POE, 0,
146 &i2c_dev);
147 if (!ret) {
148 iot_gate_imx8_ext_id = IOT_GATE_EXT_POE;
149 return;
150 }
151
152 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM_POEV2, 0,
153 &i2c_dev);
154 if (!ret) {
155 iot_gate_imx8_ext_id = IOT_GATE_EXT_POEV2;
156 return;
157 }
158
159 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_EEPROM, 0,
160 &i2c_dev);
161 if (ret){
162 iot_gate_imx8_ext_id = IOT_GATE_EXT_EMPTY;
163 return;
164 }
165 /* Only the bridge extension includes the GPIO extender */
166 ret = dm_i2c_probe(i2c_bus, IOT_GATE_IMX8_EXT_I2C_ADDR_GPIO, 0,
167 &i2c_dev);
168 if (ret) /* GPIO extender not detected */
169 iot_gate_imx8_ext_id = IOT_GATE_EXT_CAN;
170 else /* GPIO extender detected */
171 iot_gate_imx8_ext_id = IOT_GATE_EXT_IED;
172}
173
174static iomux_v3_cfg_t const iot_gate_imx8_ext_ied_pads[] = {
175 IMX8MM_PAD_NAND_ALE_GPIO3_IO0 | MUX_PAD_CTRL(PAD_CTL_PE),
176 IMX8MM_PAD_NAND_CE0_B_GPIO3_IO1 | MUX_PAD_CTRL(PAD_CTL_PE),
177 IMX8MM_PAD_NAND_DATA00_GPIO3_IO6 | MUX_PAD_CTRL(PAD_CTL_PE),
178 IMX8MM_PAD_NAND_DATA01_GPIO3_IO7 | MUX_PAD_CTRL(PAD_CTL_PE),
179 IMX8MM_PAD_NAND_DATA02_GPIO3_IO8 | MUX_PAD_CTRL(PAD_CTL_PE),
180 IMX8MM_PAD_NAND_DATA03_GPIO3_IO9 | MUX_PAD_CTRL(PAD_CTL_PE),
181};
182
183static iomux_v3_cfg_t const iot_gate_imx8_ext_poev2_pads[] = {
184 IMX8MM_PAD_SAI3_TXD_GPIO5_IO1 | MUX_PAD_CTRL(PAD_CTL_PE |
185 PAD_CTL_PUE),
186};
187
188/* Extension board bridge GPIOs */
189#define IOT_GATE_IMX8_GPIO_EXT_IED_I0 IMX_GPIO_NR(3, 0) /* IN 0 */
190#define IOT_GATE_IMX8_GPIO_EXT_IED_I1 IMX_GPIO_NR(3, 1) /* IN 1 */
191#define IOT_GATE_IMX8_GPIO_EXT_IED_I2 IMX_GPIO_NR(3, 6) /* IN 2 */
192#define IOT_GATE_IMX8_GPIO_EXT_IED_I3 IMX_GPIO_NR(3, 7) /* IN 3 */
193#define IOT_GATE_IMX8_GPIO_EXT_IED_O0 IMX_GPIO_NR(3, 8) /* OUT 0 */
194#define IOT_GATE_IMX8_GPIO_EXT_IED_O1 IMX_GPIO_NR(3, 9) /* OUT 1 */
195#define IOT_GATE_IMX8_GPIO_EXT_IED_O2 IMX_GPIO_NR(6, 9) /* OUT 2 */
196#define IOT_GATE_IMX8_GPIO_EXT_IED_O3 IMX_GPIO_NR(6, 10)/* OUT 3 */
197
198/* Extension board POE GPIOs */
199#define IOT_GATE_IMX8_GPIO_EXT_POE_MUX IMX_GPIO_NR(5, 1)/* USB_MUX */
200
201/*
202 * iot_gate_imx8_update_pinmux() - update the pinmux
203 * Update the pinmux according to the detected extended board.
204 */
205static void iot_gate_imx8_update_pinmux(void)
206{
207 if (iot_gate_imx8_ext_id == IOT_GATE_EXT_POEV2) {
208 imx_iomux_v3_setup_multiple_pads(iot_gate_imx8_ext_poev2_pads,
209 ARRAY_SIZE(iot_gate_imx8_ext_poev2_pads));
210 gpio_request(IOT_GATE_IMX8_GPIO_EXT_POE_MUX, "poev2_usb-mux");
211 /* Update USB MUX state */
212 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_POE_MUX, 1);
213
214 return;
215 }
216 if (iot_gate_imx8_ext_id != IOT_GATE_EXT_IED)
217 return;
218
219 imx_iomux_v3_setup_multiple_pads(iot_gate_imx8_ext_ied_pads,
220 ARRAY_SIZE(iot_gate_imx8_ext_ied_pads));
221
222 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I0, "ied-di4o4_i0");
223 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I0);
224 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I1, "ied-di4o4_i1");
225 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I1);
226 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I2, "ied-di4o4_i2");
227 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I2);
228 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_I3, "ied-di4o4_i3");
229 gpio_direction_input(IOT_GATE_IMX8_GPIO_EXT_IED_I3);
230 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O0, "ied-di4o4_o0");
231 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O0, 0);
232 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O1, "ied-di4o4_o1");
233 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O1, 0);
234 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O2, "ied-di4o4_o2");
235 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O2, 0);
236 gpio_request(IOT_GATE_IMX8_GPIO_EXT_IED_O3, "ied-di4o4_o3");
237 gpio_direction_output(IOT_GATE_IMX8_GPIO_EXT_IED_O3, 0);
238}
239
240#define IOT_GATE_IMX8_GPIO_S0B0 IMX_GPIO_NR(6, 0) /* Slot ID slot 0 bit 0 */
241#define IOT_GATE_IMX8_GPIO_S0B1 IMX_GPIO_NR(6, 1) /* Slot ID slot 0 bit 1 */
242#define IOT_GATE_IMX8_GPIO_S0B2 IMX_GPIO_NR(6, 2) /* Slot ID slot 0 bit 2 */
243#define IOT_GATE_IMX8_GPIO_S1B0 IMX_GPIO_NR(6, 3) /* Slot ID slot 1 bit 0 */
244#define IOT_GATE_IMX8_GPIO_S1B1 IMX_GPIO_NR(6, 4) /* Slot ID slot 1 bit 1 */
245#define IOT_GATE_IMX8_GPIO_S1B2 IMX_GPIO_NR(6, 5) /* Slot ID slot 1 bit 2 */
246#define IOT_GATE_IMX8_GPIO_S2B0 IMX_GPIO_NR(6, 6) /* Slot ID slot 2 bit 0 */
247#define IOT_GATE_IMX8_GPIO_S2B1 IMX_GPIO_NR(6, 7) /* Slot ID slot 2 bit 1 */
248#define IOT_GATE_IMX8_GPIO_S2B2 IMX_GPIO_NR(6, 8) /* Slot ID slot 2 bit 2 */
249
250/*
251 * iot_gate_imx8_update_ext_ied()
252 * Update device tree of the extended board IED-BASE.
253 * The device tree is updated according to the detected sub modules.
254 *
255 * Return 0 for success, 1 for failure.
256 */
257static int iot_gate_imx8_update_ext_ied(void)
258{
259 int revision;
260
261 if (iot_gate_imx8_ext_id != IOT_GATE_EXT_IED)
262 return 0;
263
264 /* ID GPIO initializations */
265 if (gpio_request(IOT_GATE_IMX8_GPIO_S0B0, "id_s0b0") ||
266 gpio_request(IOT_GATE_IMX8_GPIO_S0B1, "id_s0b1") ||
267 gpio_request(IOT_GATE_IMX8_GPIO_S0B2, "id_s0b2") ||
268 gpio_request(IOT_GATE_IMX8_GPIO_S1B0, "id_s1b0") ||
269 gpio_request(IOT_GATE_IMX8_GPIO_S1B1, "id_s1b1") ||
270 gpio_request(IOT_GATE_IMX8_GPIO_S1B2, "id_s1b2") ||
271 gpio_request(IOT_GATE_IMX8_GPIO_S2B0, "id_s2b0") ||
272 gpio_request(IOT_GATE_IMX8_GPIO_S2B1, "id_s2b1") ||
273 gpio_request(IOT_GATE_IMX8_GPIO_S2B2, "id_s2b2")) {
274 printf("%s: ID GPIO request failure\n", __func__);
275 return 1;
276 }
277 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B0);
278 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B1);
279 gpio_direction_input(IOT_GATE_IMX8_GPIO_S0B2);
280 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B0);
281 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B1);
282 gpio_direction_input(IOT_GATE_IMX8_GPIO_S1B2);
283 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B0);
284 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B1);
285 gpio_direction_input(IOT_GATE_IMX8_GPIO_S2B2);
286
287 /* Get slot 0 card ID */
288 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S0B0) |
289 gpio_get_value(IOT_GATE_IMX8_GPIO_S0B1) << 1 |
290 gpio_get_value(IOT_GATE_IMX8_GPIO_S0B2) << 2;
291 iot_gate_imx8_ext_ied_id[0] = revision;
292
293 /* Get slot 1 card ID */
294 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S1B0) |
295 gpio_get_value(IOT_GATE_IMX8_GPIO_S1B1) << 1 |
296 gpio_get_value(IOT_GATE_IMX8_GPIO_S1B2) << 2;
297 iot_gate_imx8_ext_ied_id[1] = revision;
298
299 /* Get slot 2 card ID */
300 revision = gpio_get_value(IOT_GATE_IMX8_GPIO_S2B0) |
301 gpio_get_value(IOT_GATE_IMX8_GPIO_S2B1) << 1 |
302 gpio_get_value(IOT_GATE_IMX8_GPIO_S2B2) << 2;
303 iot_gate_imx8_ext_ied_id[2] = revision;
304
305 return 0;
306}
307
308int board_fix_fdt(void *rw_fdt_blob)
309{
310 return 0;
311}
312
313int extension_board_scan(struct list_head *extension_list)
314{
315 struct extension *extension = NULL;
316 int i;
317 int ret = 0;
318
319 iot_gate_imx8_detect_ext(); /* Extended board detection */
320
321 switch(iot_gate_imx8_ext_id) {
322 case IOT_GATE_EXT_EMPTY:
323 break;
324 case IOT_GATE_EXT_CAN:
325 extension = calloc(1, sizeof(struct extension));
326 snprintf(extension->name, sizeof(extension->name),
327 "IOT_GATE_EXT_CAN");
328 break;
329 case IOT_GATE_EXT_IED:
330 extension = calloc(1, sizeof(struct extension));
331 snprintf(extension->name, sizeof(extension->name),
332 "IOT_GATE_EXT_IED");
333 snprintf(extension->overlay, sizeof(extension->overlay),
334 "imx8mm-cl-iot-gate-ied.dtbo");
335 break;
336 case IOT_GATE_EXT_POE:
337 extension = calloc(1, sizeof(struct extension));
338 snprintf(extension->name, sizeof(extension->name),
339 "IOT_GATE_EXT_POE");
340 break;
341 case IOT_GATE_EXT_POEV2:
342 extension = calloc(1, sizeof(struct extension));
343 snprintf(extension->name, sizeof(extension->name),
344 "IOT_GATE_EXT_POEV2");
345 break;
346 default:
347 printf("IOT_GATE-iMX8 extension board: unknown\n");
348 break;
349 }
350
351 if (extension) {
352 snprintf(extension->owner, sizeof(extension->owner),
353 "Compulab");
354 list_add_tail(&extension->list, extension_list);
355 ret = 1;
356 } else
357 return ret;
358
359 iot_gate_imx8_update_pinmux();
360
361 iot_gate_imx8_update_ext_ied();
362 for (i=0; i<ARRAY_SIZE(iot_gate_imx8_ext_ied_id); i++) {
363 extension = NULL;
364 switch (iot_gate_imx8_ext_ied_id[i]) {
365 case IOT_GATE_IMX8_CARD_ID_EMPTY:
366 break;
367 case IOT_GATE_IMX8_CARD_ID_RS_485:
368 extension = calloc(1, sizeof(struct extension));
369 snprintf(extension->name, sizeof(extension->name),
370 "IOT_GATE_IMX8_CARD_ID_RS_485");
371 break;
372 case IOT_GATE_IMX8_CARD_ID_RS_232:
373 extension = calloc(1, sizeof(struct extension));
374 snprintf(extension->name, sizeof(extension->name),
375 "IOT_GATE_IMX8_CARD_ID_RS_232");
376 break;
377 case IOT_GATE_IMX8_CARD_ID_CAN:
378 extension = calloc(1, sizeof(struct extension));
379 snprintf(extension->name, sizeof(extension->name),
380 "IOT_GATE_IMX8_CARD_ID_CAN");
381 snprintf(extension->overlay, sizeof(extension->overlay),
382 "imx8mm-cl-iot-gate-ied-can%d.dtbo", i);
383 break;
384 case IOT_GATE_IMX8_CARD_ID_TPM:
385 extension = calloc(1, sizeof(struct extension));
386 snprintf(extension->name, sizeof(extension->name),
387 "IOT_GATE_IMX8_CARD_ID_TPM");
388 snprintf(extension->overlay, sizeof(extension->overlay),
389 "imx8mm-cl-iot-gate-ied-tpm%d.dtbo", i);
390 break;
391 case IOT_GATE_IMX8_CARD_ID_CL420:
392 extension = calloc(1, sizeof(struct extension));
393 snprintf(extension->name, sizeof(extension->name),
394 "IOT_GATE_IMX8_CARD_ID_CL420");
395 snprintf(extension->overlay, sizeof(extension->overlay),
396 "imx8mm-cl-iot-gate-ied-can%d.dtbo", i);
397 break;
398 case IOT_GATE_IMX8_CARD_ID_DI4O4:
399 extension = calloc(1, sizeof(struct extension));
400 snprintf(extension->name, sizeof(extension->name),
401 "IOT_GATE_IMX8_CARD_ID_DI4O4");
402 break;
403 default:
404 printf("%s: invalid slot %d card ID: %d\n",
405 __func__, i, iot_gate_imx8_ext_ied_id[i]);
406 break;
407 }
408 if (extension) {
409 snprintf(extension->owner, sizeof(extension->owner),
410 "Compulab");
411 snprintf(extension->other, sizeof(extension->other),
412 "On slot %d", i);
413 list_add_tail(&extension->list, extension_list);
414 ret = ret + 1;
415 }
416 }
417
418 return ret;
419}
420
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800421int board_late_init(void)
422{
423 if (IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)) {
424 env_set("board_name", "IOT-GATE-IMX8");
425 env_set("board_rev", "SBC-IOTMX8");
426 }
427
428 return 0;
429}