blob: 8676c44d0d159316b7d4b41a374e4ded90265e0e [file] [log] [blame]
Marek Vasutf670cd72022-05-21 16:56:26 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 Marek Vasut <marex@denx.de>
4 */
5
6#include <common.h>
7#include <asm/arch/clock.h>
8#include <asm/arch/sys_proto.h>
9#include <asm/io.h>
10#include <dm.h>
11#include <env.h>
12#include <env_internal.h>
13#include <i2c_eeprom.h>
14#include <malloc.h>
15#include <net.h>
16#include <miiphy.h>
17
18#include "lpddr4_timing.h"
19
20DECLARE_GLOBAL_DATA_PTR;
21
22int mach_cpu_init(void)
23{
24 icache_enable();
25 return 0;
26}
27
28int board_phys_sdram_size(phys_size_t *size)
29{
30 const u16 memsz[] = { 512, 1024, 1536, 2048, 3072, 4096, 6144, 8192 };
31 u8 memcfg = dh_get_memcfg();
32
33 *size = (u64)memsz[memcfg] << 20ULL;
34
35 return 0;
36}
37
38/* IMX8M SNVS registers needed for the bootcount functionality */
39#define SNVS_BASE_ADDR 0x30370000
40#define SNVS_LPSR 0x4c
41#define SNVS_LPLVDR 0x64
42#define SNVS_LPPGDR_INIT 0x41736166
43
44static void setup_snvs(void)
45{
46 /* Enable SNVS clock */
47 clock_enable(CCGR_SNVS, 1);
48 /* Initialize glitch detect */
49 writel(SNVS_LPPGDR_INIT, SNVS_BASE_ADDR + SNVS_LPLVDR);
50 /* Clear interrupt status */
51 writel(0xffffffff, SNVS_BASE_ADDR + SNVS_LPSR);
52}
53
54static void setup_eqos(void)
55{
56 struct iomuxc_gpr_base_regs *gpr =
57 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
58
59 /* Set INTF as RGMII, enable RGMII TXC clock. */
60 clrsetbits_le32(&gpr->gpr[1],
61 IOMUXC_GPR_GPR1_GPR_ENET_QOS_INTF_SEL_MASK, BIT(16));
62 setbits_le32(&gpr->gpr[1], BIT(19) | BIT(21));
63
64 set_clk_eqos(ENET_125MHZ);
65}
66
67static void setup_fec(void)
68{
69 struct iomuxc_gpr_base_regs *gpr =
70 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
71
72 /* Enable RGMII TX clk output. */
73 setbits_le32(&gpr->gpr[1], BIT(22));
74
75 set_clk_enet(ENET_125MHZ);
76}
77
78static int setup_mac_address_from_eeprom(char *alias, char *env, bool odd)
79{
80 unsigned char enetaddr[6];
81 struct udevice *dev;
82 int ret, offset;
83
84 offset = fdt_path_offset(gd->fdt_blob, alias);
85 if (offset < 0) {
86 printf("%s: No eeprom0 path offset\n", __func__);
87 return offset;
88 }
89
90 ret = uclass_get_device_by_of_offset(UCLASS_I2C_EEPROM, offset, &dev);
91 if (ret) {
92 printf("Cannot find EEPROM!\n");
93 return ret;
94 }
95
96 ret = i2c_eeprom_read(dev, 0xfa, enetaddr, 0x6);
97 if (ret) {
98 printf("Error reading configuration EEPROM!\n");
99 return ret;
100 }
101
102 /*
103 * Populate second ethernet MAC from first ethernet EEPROM with MAC
104 * address LSByte incremented by 1. This is only used on SoMs without
105 * second ethernet EEPROM, i.e. early prototypes.
106 */
107 if (odd)
108 enetaddr[5]++;
109
110 eth_env_set_enetaddr(env, enetaddr);
111
112 return 0;
113}
114
115static void setup_mac_address(void)
116{
117 unsigned char enetaddr[6];
118 bool skip_eth0 = false;
119 bool skip_eth1 = false;
120 int ret;
121
122 ret = eth_env_get_enetaddr("ethaddr", enetaddr);
123 if (ret) /* ethaddr is already set */
124 skip_eth0 = true;
125
126 ret = eth_env_get_enetaddr("eth1addr", enetaddr);
127 if (ret) /* eth1addr is already set */
128 skip_eth1 = true;
129
130 /* Both MAC addresses are already set in U-Boot environment. */
131 if (skip_eth0 && skip_eth1)
132 return;
133
134 /*
135 * If IIM fuses contain valid MAC address, use it.
136 * The IIM MAC address fuses are NOT programmed by default.
137 */
138 imx_get_mac_from_fuse(0, enetaddr);
139 if (is_valid_ethaddr(enetaddr)) {
140 if (!skip_eth0)
141 eth_env_set_enetaddr("ethaddr", enetaddr);
142 /*
143 * The LSbit of MAC address in fuses is always 0, use the
144 * next consecutive MAC address for the second ethernet.
145 */
146 enetaddr[5]++;
147 if (!skip_eth1)
148 eth_env_set_enetaddr("eth1addr", enetaddr);
149 return;
150 }
151
152 /* Use on-SoM EEPROMs with pre-programmed MAC address. */
153 if (!skip_eth0) {
154 /* We cannot do much more if this returns -ve . */
155 setup_mac_address_from_eeprom("eeprom0", "ethaddr", false);
156 }
157
158 if (!skip_eth1) {
159 ret = setup_mac_address_from_eeprom("eeprom1", "eth1addr",
160 false);
161 if (ret) { /* Second EEPROM might not be populated. */
162 /* We cannot do much more if this returns -ve . */
163 setup_mac_address_from_eeprom("eeprom0", "eth1addr",
164 true);
165 }
166 }
167}
168
169int board_init(void)
170{
171 setup_eqos();
172 setup_fec();
173 setup_snvs();
174 return 0;
175}
176
177int board_late_init(void)
178{
179 setup_mac_address();
180 return 0;
181}
182
183enum env_location env_get_location(enum env_operation op, int prio)
184{
185 return prio ? ENVL_UNKNOWN : ENVL_SPI_FLASH;
186}