blob: 19c5043fcbaaac3f21d20f9a66e179da187424b2 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Behún09e16b82017-06-09 19:28:45 +02002/*
Marek Behúnd63726e2022-06-01 17:17:06 +02003 * Copyright (C) 2017 Marek Behún <kabel@kernel.org>
Marek Behún09e16b82017-06-09 19:28:45 +02004 * Copyright (C) 2016 Tomas Hlavacek <tomas.hlavacek@nic.cz>
5 *
6 * Derived from the code for
7 * Marvell/db-88f6820-gp by Stefan Roese <sr@denx.de>
Marek Behún09e16b82017-06-09 19:28:45 +02008 */
9
10#include <common.h>
Simon Glass07dc93c2019-08-01 09:46:47 -060011#include <env.h>
Marek Behún09e16b82017-06-09 19:28:45 +020012#include <i2c.h>
Simon Glassa7b51302019-11-14 12:57:46 -070013#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Marek Behún09e16b82017-06-09 19:28:45 +020015#include <miiphy.h>
Marek Behún91ef59c2021-07-15 19:21:02 +020016#include <mtd.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Marek Behún09e16b82017-06-09 19:28:45 +020018#include <asm/io.h>
19#include <asm/arch/cpu.h>
20#include <asm/arch/soc.h>
21#include <dm/uclass.h>
Pali Rohár1e0a9752022-07-29 13:29:07 +020022#include <dt-bindings/gpio/gpio.h>
Marek Behún09e16b82017-06-09 19:28:45 +020023#include <fdt_support.h>
Pali Roháre16cc982022-08-10 11:00:25 +020024#include <hexdump.h>
Marek Behún09e16b82017-06-09 19:28:45 +020025#include <time.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060026#include <linux/bitops.h>
Pali Rohár1e0a9752022-07-29 13:29:07 +020027#include <linux/delay.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070028#include <u-boot/crc.h>
Marek Behún09e16b82017-06-09 19:28:45 +020029
Chris Packham1a07d212018-05-10 13:28:29 +120030#include "../drivers/ddr/marvell/a38x/ddr3_init.h"
Marek Behún09e16b82017-06-09 19:28:45 +020031#include <../serdes/a38x/high_speed_env_spec.h>
Pali Rohár0387f7f2022-04-08 16:30:12 +020032#include "../turris_atsha_otp.h"
Marek Behún09e16b82017-06-09 19:28:45 +020033
34DECLARE_GLOBAL_DATA_PTR;
35
Marek Behúnba53b6b2019-05-02 16:53:30 +020036#define OMNIA_I2C_BUS_NAME "i2c@11000->i2cmux@70->i2c@0"
37
38#define OMNIA_I2C_MCU_CHIP_ADDR 0x2a
39#define OMNIA_I2C_MCU_CHIP_LEN 1
40
41#define OMNIA_I2C_EEPROM_CHIP_ADDR 0x54
42#define OMNIA_I2C_EEPROM_CHIP_LEN 2
Marek Behún09e16b82017-06-09 19:28:45 +020043#define OMNIA_I2C_EEPROM_MAGIC 0x0341a034
44
Pali Rohár30e398d2022-04-29 13:53:25 +020045#define A385_SYS_RSTOUT_MASK MVEBU_REGISTER(0x18260)
46#define A385_SYS_RSTOUT_MASK_WD BIT(10)
Pali Rohár7fcda0c2021-11-09 17:14:02 +010047
48#define A385_WDT_GLOBAL_CTRL MVEBU_REGISTER(0x20300)
49#define A385_WDT_GLOBAL_RATIO_MASK GENMASK(18, 16)
50#define A385_WDT_GLOBAL_RATIO_SHIFT 16
51#define A385_WDT_GLOBAL_25MHZ BIT(10)
52#define A385_WDT_GLOBAL_ENABLE BIT(8)
53
54#define A385_WDT_GLOBAL_STATUS MVEBU_REGISTER(0x20304)
55#define A385_WDT_GLOBAL_EXPIRED BIT(31)
56
57#define A385_WDT_DURATION MVEBU_REGISTER(0x20334)
58
59#define A385_WD_RSTOUT_UNMASK MVEBU_REGISTER(0x20704)
60#define A385_WD_RSTOUT_UNMASK_GLOBAL BIT(8)
61
Marek Behúnba53b6b2019-05-02 16:53:30 +020062enum mcu_commands {
63 CMD_GET_STATUS_WORD = 0x01,
64 CMD_GET_RESET = 0x09,
Pali Roháre16cc982022-08-10 11:00:25 +020065 CMD_GET_FW_VERSION_APP = 0x0a,
Marek Behúnba53b6b2019-05-02 16:53:30 +020066 CMD_WATCHDOG_STATE = 0x0b,
Pali Roháre16cc982022-08-10 11:00:25 +020067 CMD_GET_FW_VERSION_BOOT = 0x0e,
Pali Rohár4798ba92022-07-29 13:29:06 +020068
69 /* available if STS_FEATURES_SUPPORTED bit set in status word */
70 CMD_GET_FEATURES = 0x10,
Pali Rohár1e0a9752022-07-29 13:29:07 +020071
72 /* available if EXT_CMD bit set in features */
73 CMD_EXT_CONTROL = 0x12,
Marek Behúnba53b6b2019-05-02 16:53:30 +020074};
75
76enum status_word_bits {
Pali Rohár4798ba92022-07-29 13:29:06 +020077 STS_MCU_TYPE_MASK = GENMASK(1, 0),
78 STS_MCU_TYPE_STM32 = 0,
79 STS_MCU_TYPE_GD32 = 1,
80 STS_MCU_TYPE_MKL = 2,
81 STS_MCU_TYPE_UNKN = 3,
82 STS_FEATURES_SUPPORTED = BIT(2),
Marek Behúnba53b6b2019-05-02 16:53:30 +020083 CARD_DET_STSBIT = 0x0010,
84 MSATA_IND_STSBIT = 0x0020,
85};
Marek Behún09e16b82017-06-09 19:28:45 +020086
Pali Rohár4798ba92022-07-29 13:29:06 +020087/* CMD_GET_FEATURES */
88enum features_e {
89 FEAT_PERIPH_MCU = BIT(0),
Pali Rohár1e0a9752022-07-29 13:29:07 +020090 FEAT_EXT_CMDS = BIT(1),
91};
92
93/* CMD_EXT_CONTROL */
94enum ext_ctl_e {
95 EXT_CTL_nRES_LAN = BIT(1),
96 EXT_CTL_nRES_PHY = BIT(2),
97 EXT_CTL_nPERST0 = BIT(3),
98 EXT_CTL_nPERST1 = BIT(4),
99 EXT_CTL_nPERST2 = BIT(5),
Pali Rohár4798ba92022-07-29 13:29:06 +0200100};
101
Marek Behún09e16b82017-06-09 19:28:45 +0200102/*
103 * Those values and defines are taken from the Marvell U-Boot version
104 * "u-boot-2013.01-2014_T3.0"
105 */
106#define OMNIA_GPP_OUT_ENA_LOW \
107 (~(BIT(1) | BIT(4) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | \
108 BIT(10) | BIT(11) | BIT(19) | BIT(22) | BIT(23) | BIT(25) | \
109 BIT(26) | BIT(27) | BIT(29) | BIT(30) | BIT(31)))
110#define OMNIA_GPP_OUT_ENA_MID \
111 (~(BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(15) | \
112 BIT(16) | BIT(17) | BIT(18)))
113
114#define OMNIA_GPP_OUT_VAL_LOW 0x0
115#define OMNIA_GPP_OUT_VAL_MID 0x0
116#define OMNIA_GPP_POL_LOW 0x0
117#define OMNIA_GPP_POL_MID 0x0
118
Pali Rohár3c4dd982022-03-02 12:47:54 +0100119static struct serdes_map board_serdes_map[] = {
Marek Behún09e16b82017-06-09 19:28:45 +0200120 {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
121 {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
122 {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
123 {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
124 {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
125 {SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}
126};
127
Marek Behúnba53b6b2019-05-02 16:53:30 +0200128static struct udevice *omnia_get_i2c_chip(const char *name, uint addr,
129 uint offset_len)
Marek Behún09e16b82017-06-09 19:28:45 +0200130{
131 struct udevice *bus, *dev;
Marek Behúnba53b6b2019-05-02 16:53:30 +0200132 int ret;
Marek Behún09e16b82017-06-09 19:28:45 +0200133
Marek Behúnba53b6b2019-05-02 16:53:30 +0200134 ret = uclass_get_device_by_name(UCLASS_I2C, OMNIA_I2C_BUS_NAME, &bus);
135 if (ret) {
136 printf("Cannot get I2C bus %s: uclass_get_device_by_name failed: %i\n",
137 OMNIA_I2C_BUS_NAME, ret);
138 return NULL;
Marek Behún09e16b82017-06-09 19:28:45 +0200139 }
140
Marek Behúnba53b6b2019-05-02 16:53:30 +0200141 ret = i2c_get_chip(bus, addr, offset_len, &dev);
Marek Behún09e16b82017-06-09 19:28:45 +0200142 if (ret) {
Marek Behúnba53b6b2019-05-02 16:53:30 +0200143 printf("Cannot get %s I2C chip: i2c_get_chip failed: %i\n",
144 name, ret);
145 return NULL;
Marek Behún09e16b82017-06-09 19:28:45 +0200146 }
147
Marek Behúnba53b6b2019-05-02 16:53:30 +0200148 return dev;
149}
Marek Behúnd0b374d2017-08-04 15:28:25 +0200150
Marek Behúnba53b6b2019-05-02 16:53:30 +0200151static int omnia_mcu_read(u8 cmd, void *buf, int len)
152{
153 struct udevice *chip;
154
155 chip = omnia_get_i2c_chip("MCU", OMNIA_I2C_MCU_CHIP_ADDR,
156 OMNIA_I2C_MCU_CHIP_LEN);
157 if (!chip)
158 return -ENODEV;
159
160 return dm_i2c_read(chip, cmd, buf, len);
161}
162
Marek Behúnba53b6b2019-05-02 16:53:30 +0200163static int omnia_mcu_write(u8 cmd, const void *buf, int len)
164{
165 struct udevice *chip;
166
167 chip = omnia_get_i2c_chip("MCU", OMNIA_I2C_MCU_CHIP_ADDR,
168 OMNIA_I2C_MCU_CHIP_LEN);
169 if (!chip)
170 return -ENODEV;
171
172 return dm_i2c_write(chip, cmd, buf, len);
173}
174
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100175static void enable_a385_watchdog(unsigned int timeout_minutes)
176{
177 struct sar_freq_modes sar_freq;
178 u32 watchdog_freq;
179
180 printf("Enabling A385 watchdog with %u minutes timeout...\n",
181 timeout_minutes);
182
183 /*
184 * Use NBCLK clock (a.k.a. L2 clock) as watchdog input clock with
185 * its maximal ratio 7 instead of default fixed 25 MHz clock.
186 * It allows to set watchdog duration up to the 22 minutes.
187 */
188 clrsetbits_32(A385_WDT_GLOBAL_CTRL,
189 A385_WDT_GLOBAL_25MHZ | A385_WDT_GLOBAL_RATIO_MASK,
190 7 << A385_WDT_GLOBAL_RATIO_SHIFT);
191
192 /*
193 * Calculate watchdog clock frequency. It is defined by formula:
194 * freq = NBCLK / 2 / (2 ^ ratio)
195 * We set ratio to the maximal possible value 7.
196 */
197 get_sar_freq(&sar_freq);
198 watchdog_freq = sar_freq.nb_clk * 1000000 / 2 / (1 << 7);
199
200 /* Set watchdog duration */
201 writel(timeout_minutes * 60 * watchdog_freq, A385_WDT_DURATION);
202
203 /* Clear the watchdog expiration bit */
204 clrbits_32(A385_WDT_GLOBAL_STATUS, A385_WDT_GLOBAL_EXPIRED);
205
206 /* Enable watchdog timer */
207 setbits_32(A385_WDT_GLOBAL_CTRL, A385_WDT_GLOBAL_ENABLE);
208
209 /* Enable reset on watchdog */
210 setbits_32(A385_WD_RSTOUT_UNMASK, A385_WD_RSTOUT_UNMASK_GLOBAL);
211
212 /* Unmask reset for watchdog */
Pali Rohár30e398d2022-04-29 13:53:25 +0200213 clrbits_32(A385_SYS_RSTOUT_MASK, A385_SYS_RSTOUT_MASK_WD);
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100214}
215
Marek Behúnba53b6b2019-05-02 16:53:30 +0200216static bool disable_mcu_watchdog(void)
217{
218 int ret;
219
220 puts("Disabling MCU watchdog... ");
221
222 ret = omnia_mcu_write(CMD_WATCHDOG_STATE, "\x00", 1);
223 if (ret) {
224 printf("omnia_mcu_write failed: %i\n", ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200225 return false;
226 }
227
Marek Behúnba53b6b2019-05-02 16:53:30 +0200228 puts("disabled\n");
229
230 return true;
231}
Marek Behúnba53b6b2019-05-02 16:53:30 +0200232
Pali Rohárf8f305b2022-03-02 12:47:55 +0100233static bool omnia_detect_sata(const char *msata_slot)
Marek Behúnba53b6b2019-05-02 16:53:30 +0200234{
235 int ret;
236 u16 stsword;
237
238 puts("MiniPCIe/mSATA card detection... ");
239
Pali Rohárf8f305b2022-03-02 12:47:55 +0100240 if (msata_slot) {
241 if (strcmp(msata_slot, "pcie") == 0) {
242 puts("forced to MiniPCIe via env\n");
243 return false;
244 } else if (strcmp(msata_slot, "sata") == 0) {
245 puts("forced to mSATA via env\n");
246 return true;
247 } else if (strcmp(msata_slot, "auto") != 0) {
248 printf("unsupported env value '%s', fallback to... ", msata_slot);
249 }
250 }
251
Marek Behúnba53b6b2019-05-02 16:53:30 +0200252 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
253 if (ret) {
254 printf("omnia_mcu_read failed: %i, defaulting to MiniPCIe card\n",
255 ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200256 return false;
257 }
258
Marek Behúnba53b6b2019-05-02 16:53:30 +0200259 if (!(stsword & CARD_DET_STSBIT)) {
260 puts("none\n");
Marek Behún09e16b82017-06-09 19:28:45 +0200261 return false;
262 }
Marek Behúnba53b6b2019-05-02 16:53:30 +0200263
264 if (stsword & MSATA_IND_STSBIT)
265 puts("mSATA\n");
266 else
267 puts("MiniPCIe\n");
268
269 return stsword & MSATA_IND_STSBIT ? true : false;
Marek Behún09e16b82017-06-09 19:28:45 +0200270}
271
Pali Rohár93a89c52022-03-02 12:47:58 +0100272static bool omnia_detect_wwan_usb3(const char *wwan_slot)
273{
274 puts("WWAN slot configuration... ");
275
276 if (wwan_slot && strcmp(wwan_slot, "usb3") == 0) {
277 puts("USB3.0\n");
278 return true;
279 }
280
281 if (wwan_slot && strcmp(wwan_slot, "pcie") != 0)
282 printf("unsupported env value '%s', fallback to... ", wwan_slot);
283
284 puts("PCIe+USB2.0\n");
285 return false;
286}
287
Marek Behún09e16b82017-06-09 19:28:45 +0200288int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count)
289{
Pali Rohárf8f305b2022-03-02 12:47:55 +0100290#ifdef CONFIG_SPL_ENV_SUPPORT
291 /* Do not use env_load() as malloc() pool is too small at this stage */
292 bool has_env = (env_init() == 0);
293#endif
294 const char *env_value = NULL;
295
296#ifdef CONFIG_SPL_ENV_SUPPORT
297 /* beware that env_get() returns static allocated memory */
298 env_value = has_env ? env_get("omnia_msata_slot") : NULL;
299#endif
300
301 if (omnia_detect_sata(env_value)) {
Pali Rohár3c4dd982022-03-02 12:47:54 +0100302 /* Change SerDes for first mPCIe port (mSATA) from PCIe to SATA */
303 board_serdes_map[0].serdes_type = SATA0;
304 board_serdes_map[0].serdes_speed = SERDES_SPEED_6_GBPS;
305 board_serdes_map[0].serdes_mode = SERDES_DEFAULT_MODE;
Marek Behún09e16b82017-06-09 19:28:45 +0200306 }
307
Pali Rohár93a89c52022-03-02 12:47:58 +0100308#ifdef CONFIG_SPL_ENV_SUPPORT
309 /* beware that env_get() returns static allocated memory */
310 env_value = has_env ? env_get("omnia_wwan_slot") : NULL;
311#endif
312
313 if (omnia_detect_wwan_usb3(env_value)) {
314 /* Disable SerDes for USB 3.0 pins on the front USB-A port */
315 board_serdes_map[1].serdes_type = DEFAULT_SERDES;
316 /* Change SerDes for third mPCIe port (WWAN) from PCIe to USB 3.0 */
317 board_serdes_map[4].serdes_type = USB3_HOST0;
318 board_serdes_map[4].serdes_speed = SERDES_SPEED_5_GBPS;
319 board_serdes_map[4].serdes_mode = SERDES_DEFAULT_MODE;
320 }
321
Pali Rohár3c4dd982022-03-02 12:47:54 +0100322 *serdes_map_array = board_serdes_map;
323 *count = ARRAY_SIZE(board_serdes_map);
324
Marek Behún09e16b82017-06-09 19:28:45 +0200325 return 0;
326}
327
328struct omnia_eeprom {
329 u32 magic;
330 u32 ramsize;
331 char region[4];
332 u32 crc;
333};
334
335static bool omnia_read_eeprom(struct omnia_eeprom *oep)
336{
Marek Behúnba53b6b2019-05-02 16:53:30 +0200337 struct udevice *chip;
338 u32 crc;
339 int ret;
Marek Behún09e16b82017-06-09 19:28:45 +0200340
Marek Behúnba53b6b2019-05-02 16:53:30 +0200341 chip = omnia_get_i2c_chip("EEPROM", OMNIA_I2C_EEPROM_CHIP_ADDR,
342 OMNIA_I2C_EEPROM_CHIP_LEN);
343
344 if (!chip)
Marek Behún09e16b82017-06-09 19:28:45 +0200345 return false;
Marek Behún09e16b82017-06-09 19:28:45 +0200346
Marek Behúnba53b6b2019-05-02 16:53:30 +0200347 ret = dm_i2c_read(chip, 0, (void *)oep, sizeof(*oep));
Marek Behún09e16b82017-06-09 19:28:45 +0200348 if (ret) {
Marek Behúnba53b6b2019-05-02 16:53:30 +0200349 printf("dm_i2c_read failed: %i, cannot read EEPROM\n", ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200350 return false;
351 }
352
Marek Behúnba53b6b2019-05-02 16:53:30 +0200353 if (oep->magic != OMNIA_I2C_EEPROM_MAGIC) {
354 printf("bad EEPROM magic number (%08x, should be %08x)\n",
355 oep->magic, OMNIA_I2C_EEPROM_MAGIC);
356 return false;
Marek Behún09e16b82017-06-09 19:28:45 +0200357 }
358
Marek Behúnba53b6b2019-05-02 16:53:30 +0200359 crc = crc32(0, (void *)oep, sizeof(*oep) - 4);
360 if (crc != oep->crc) {
361 printf("bad EEPROM CRC (stored %08x, computed %08x)\n",
362 oep->crc, crc);
Marek Behún09e16b82017-06-09 19:28:45 +0200363 return false;
364 }
365
366 return true;
367}
368
Marek Behún77652c72019-05-02 16:53:33 +0200369static int omnia_get_ram_size_gb(void)
370{
371 static int ram_size;
372 struct omnia_eeprom oep;
373
374 if (!ram_size) {
375 /* Get the board config from EEPROM */
376 if (omnia_read_eeprom(&oep)) {
377 debug("Memory config in EEPROM: 0x%02x\n", oep.ramsize);
378
379 if (oep.ramsize == 0x2)
380 ram_size = 2;
381 else
382 ram_size = 1;
383 } else {
384 /* Hardcoded fallback */
385 puts("Memory config from EEPROM read failed!\n");
386 puts("Falling back to default 1 GiB!\n");
387 ram_size = 1;
388 }
389 }
390
391 return ram_size;
392}
393
Pali Rohár4798ba92022-07-29 13:29:06 +0200394static const char * const omnia_get_mcu_type(void)
395{
396 static const char * const mcu_types[] = {
397 [STS_MCU_TYPE_STM32] = "STM32",
398 [STS_MCU_TYPE_GD32] = "GD32",
399 [STS_MCU_TYPE_MKL] = "MKL",
400 [STS_MCU_TYPE_UNKN] = "unknown",
401 };
402 static const char * const mcu_types_with_perip_resets[] = {
403 [STS_MCU_TYPE_STM32] = "STM32 (with peripheral resets)",
404 [STS_MCU_TYPE_GD32] = "GD32 (with peripheral resets)",
405 [STS_MCU_TYPE_MKL] = "MKL (with peripheral resets)",
406 [STS_MCU_TYPE_UNKN] = "unknown (with peripheral resets)",
407 };
408 u16 stsword, features;
409 int ret;
410
411 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
412 if (ret)
413 return "unknown";
414
415 if (stsword & STS_FEATURES_SUPPORTED) {
416 ret = omnia_mcu_read(CMD_GET_FEATURES, &features, sizeof(features));
417 if (ret == 0 && (features & FEAT_PERIPH_MCU))
418 return mcu_types_with_perip_resets[stsword & STS_MCU_TYPE_MASK];
419 }
420
421 return mcu_types[stsword & STS_MCU_TYPE_MASK];
422}
423
Pali Roháre16cc982022-08-10 11:00:25 +0200424static const char * const omnia_get_mcu_version(void)
425{
426 static char version[82];
427 u8 version_app[20];
428 u8 version_boot[20];
429 int ret;
430
431 ret = omnia_mcu_read(CMD_GET_FW_VERSION_APP, &version_app, sizeof(version_app));
432 if (ret)
433 return "unknown";
434
435 ret = omnia_mcu_read(CMD_GET_FW_VERSION_BOOT, &version_boot, sizeof(version_boot));
436 if (ret)
437 return "unknown";
438
439 /*
440 * If git commits of MCU bootloader and MCU application are same then
441 * show version only once. If they are different then show both commits.
442 */
443 if (!memcmp(version_app, version_boot, 20)) {
444 bin2hex(version, version_app, 20);
445 version[40] = '\0';
446 } else {
447 bin2hex(version, version_boot, 20);
448 version[40] = '/';
449 bin2hex(version + 41, version_app, 20);
450 version[81] = '\0';
451 }
452
453 return version;
454}
455
Marek Behún09e16b82017-06-09 19:28:45 +0200456/*
457 * Define the DDR layout / topology here in the board file. This will
458 * be used by the DDR3 init code in the SPL U-Boot version to configure
459 * the DDR3 controller.
460 */
Chris Packham1a07d212018-05-10 13:28:29 +1200461static struct mv_ddr_topology_map board_topology_map_1g = {
462 DEBUG_LEVEL_ERROR,
Marek Behún09e16b82017-06-09 19:28:45 +0200463 0x1, /* active interfaces */
464 /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */
465 { { { {0x1, 0, 0, 0},
466 {0x1, 0, 0, 0},
467 {0x1, 0, 0, 0},
468 {0x1, 0, 0, 0},
469 {0x1, 0, 0, 0} },
470 SPEED_BIN_DDR_1600K, /* speed_bin */
Chris Packham1a07d212018-05-10 13:28:29 +1200471 MV_DDR_DEV_WIDTH_16BIT, /* memory_width */
472 MV_DDR_DIE_CAP_4GBIT, /* mem_size */
Chris Packham4bf81db2018-12-03 14:26:49 +1300473 MV_DDR_FREQ_800, /* frequency */
Chris Packhamdd092bd2017-11-29 10:38:34 +1300474 0, 0, /* cas_wl cas_l */
Chris Packham3a09e132018-05-10 13:28:30 +1200475 MV_DDR_TEMP_NORMAL, /* temperature */
476 MV_DDR_TIM_2T} }, /* timing */
Chris Packham1a07d212018-05-10 13:28:29 +1200477 BUS_MASK_32BIT, /* Busses mask */
478 MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
Moti Buskila498475e2021-02-19 17:11:19 +0100479 NOT_COMBINED, /* ddr twin-die combined */
Chris Packham1a07d212018-05-10 13:28:29 +1200480 { {0} }, /* raw spd data */
481 {0} /* timing parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200482};
483
Chris Packham1a07d212018-05-10 13:28:29 +1200484static struct mv_ddr_topology_map board_topology_map_2g = {
485 DEBUG_LEVEL_ERROR,
Marek Behún09e16b82017-06-09 19:28:45 +0200486 0x1, /* active interfaces */
487 /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */
488 { { { {0x1, 0, 0, 0},
489 {0x1, 0, 0, 0},
490 {0x1, 0, 0, 0},
491 {0x1, 0, 0, 0},
492 {0x1, 0, 0, 0} },
493 SPEED_BIN_DDR_1600K, /* speed_bin */
Chris Packham1a07d212018-05-10 13:28:29 +1200494 MV_DDR_DEV_WIDTH_16BIT, /* memory_width */
495 MV_DDR_DIE_CAP_8GBIT, /* mem_size */
Chris Packham4bf81db2018-12-03 14:26:49 +1300496 MV_DDR_FREQ_800, /* frequency */
Chris Packhamdd092bd2017-11-29 10:38:34 +1300497 0, 0, /* cas_wl cas_l */
Chris Packham3a09e132018-05-10 13:28:30 +1200498 MV_DDR_TEMP_NORMAL, /* temperature */
499 MV_DDR_TIM_2T} }, /* timing */
Chris Packham1a07d212018-05-10 13:28:29 +1200500 BUS_MASK_32BIT, /* Busses mask */
501 MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
Moti Buskila498475e2021-02-19 17:11:19 +0100502 NOT_COMBINED, /* ddr twin-die combined */
Chris Packham1a07d212018-05-10 13:28:29 +1200503 { {0} }, /* raw spd data */
504 {0} /* timing parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200505};
506
Chris Packham1a07d212018-05-10 13:28:29 +1200507struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
Marek Behún09e16b82017-06-09 19:28:45 +0200508{
Marek Behún77652c72019-05-02 16:53:33 +0200509 if (omnia_get_ram_size_gb() == 2)
Marek Behún09e16b82017-06-09 19:28:45 +0200510 return &board_topology_map_2g;
Marek Behún77652c72019-05-02 16:53:33 +0200511 else
512 return &board_topology_map_1g;
Marek Behún09e16b82017-06-09 19:28:45 +0200513}
514
Marek Behún09e16b82017-06-09 19:28:45 +0200515static int set_regdomain(void)
516{
517 struct omnia_eeprom oep;
518 char rd[3] = {' ', ' ', 0};
519
520 if (omnia_read_eeprom(&oep))
521 memcpy(rd, &oep.region, 2);
522 else
523 puts("EEPROM regdomain read failed.\n");
524
525 printf("Regdomain set to %s\n", rd);
Simon Glass6a38e412017-08-03 12:22:09 -0600526 return env_set("regdomain", rd);
Marek Behún09e16b82017-06-09 19:28:45 +0200527}
Marek Behún0f2e66a2019-05-02 16:53:37 +0200528
Marek Behún0f2e66a2019-05-02 16:53:37 +0200529static void handle_reset_button(void)
530{
Pali Rohár905c3bf2021-06-14 16:45:58 +0200531 const char * const vars[1] = { "bootcmd_rescue", };
Marek Behún0f2e66a2019-05-02 16:53:37 +0200532 int ret;
533 u8 reset_status;
534
Pali Rohár905c3bf2021-06-14 16:45:58 +0200535 /*
536 * Ensure that bootcmd_rescue has always stock value, so that running
537 * run bootcmd_rescue
538 * always works correctly.
539 */
540 env_set_default_vars(1, (char * const *)vars, 0);
541
Marek Behún0f2e66a2019-05-02 16:53:37 +0200542 ret = omnia_mcu_read(CMD_GET_RESET, &reset_status, 1);
543 if (ret) {
544 printf("omnia_mcu_read failed: %i, reset status unknown!\n",
545 ret);
546 return;
547 }
548
549 env_set_ulong("omnia_reset", reset_status);
550
551 if (reset_status) {
Pali Rohár8adec652022-08-27 20:49:20 +0200552 const char * const vars[3] = {
Marek Behún09f8de22021-05-28 10:00:49 +0200553 "bootcmd",
Pali Rohár8adec652022-08-27 20:49:20 +0200554 "bootdelay",
Marek Behún09f8de22021-05-28 10:00:49 +0200555 "distro_bootcmd",
556 };
557
558 /*
559 * Set the above envs to their default values, in case the user
560 * managed to break them.
561 */
Pali Rohár8adec652022-08-27 20:49:20 +0200562 env_set_default_vars(3, (char * const *)vars, 0);
Marek Behún09f8de22021-05-28 10:00:49 +0200563
564 /* Ensure bootcmd_rescue is used by distroboot */
565 env_set("boot_targets", "rescue");
566
Pali Rohár4f9e6fb2022-04-06 11:39:32 +0200567 printf("RESET button was pressed, overwriting boot_targets!\n");
Marek Behún09f8de22021-05-28 10:00:49 +0200568 } else {
569 /*
570 * In case the user somehow managed to save environment with
571 * boot_targets=rescue, reset boot_targets to default value.
572 * This could happen in subsequent commands if bootcmd_rescue
573 * failed.
574 */
575 if (!strcmp(env_get("boot_targets"), "rescue")) {
576 const char * const vars[1] = {
577 "boot_targets",
578 };
579
580 env_set_default_vars(1, (char * const *)vars, 0);
581 }
Marek Behún0f2e66a2019-05-02 16:53:37 +0200582 }
583}
Marek Behún09e16b82017-06-09 19:28:45 +0200584
Pali Rohár1e0a9752022-07-29 13:29:07 +0200585static void initialize_switch(void)
586{
587 u32 val, val04, val08, val10, val14;
588 u16 ctrl[2];
589 int err;
590
591 printf("Initializing LAN eth switch... ");
592
593 /* Change RGMII pins to GPIO mode */
594
595 val = val04 = readl(MVEBU_MPP_BASE + 0x04);
596 val &= ~GENMASK(19, 16); /* MPP[12] := GPIO */
597 val &= ~GENMASK(23, 20); /* MPP[13] := GPIO */
598 val &= ~GENMASK(27, 24); /* MPP[14] := GPIO */
599 val &= ~GENMASK(31, 28); /* MPP[15] := GPIO */
600 writel(val, MVEBU_MPP_BASE + 0x04);
601
602 val = val08 = readl(MVEBU_MPP_BASE + 0x08);
603 val &= ~GENMASK(3, 0); /* MPP[16] := GPIO */
604 val &= ~GENMASK(23, 20); /* MPP[21] := GPIO */
605 writel(val, MVEBU_MPP_BASE + 0x08);
606
607 val = val10 = readl(MVEBU_MPP_BASE + 0x10);
608 val &= ~GENMASK(27, 24); /* MPP[38] := GPIO */
609 val &= ~GENMASK(31, 28); /* MPP[39] := GPIO */
610 writel(val, MVEBU_MPP_BASE + 0x10);
611
612 val = val14 = readl(MVEBU_MPP_BASE + 0x14);
613 val &= ~GENMASK(3, 0); /* MPP[40] := GPIO */
614 val &= ~GENMASK(7, 4); /* MPP[41] := GPIO */
615 writel(val, MVEBU_MPP_BASE + 0x14);
616
617 /* Set initial values for switch reset strapping pins */
618
619 val = readl(MVEBU_GPIO0_BASE + 0x00);
620 val |= BIT(12); /* GPIO[12] := 1 */
621 val |= BIT(13); /* GPIO[13] := 1 */
622 val |= BIT(14); /* GPIO[14] := 1 */
623 val |= BIT(15); /* GPIO[15] := 1 */
624 val &= ~BIT(16); /* GPIO[16] := 0 */
625 val |= BIT(21); /* GPIO[21] := 1 */
626 writel(val, MVEBU_GPIO0_BASE + 0x00);
627
628 val = readl(MVEBU_GPIO1_BASE + 0x00);
629 val |= BIT(6); /* GPIO[38] := 1 */
630 val |= BIT(7); /* GPIO[39] := 1 */
631 val |= BIT(8); /* GPIO[40] := 1 */
632 val &= ~BIT(9); /* GPIO[41] := 0 */
633 writel(val, MVEBU_GPIO1_BASE + 0x00);
634
635 val = readl(MVEBU_GPIO0_BASE + 0x04);
636 val &= ~BIT(12); /* GPIO[12] := Out Enable */
637 val &= ~BIT(13); /* GPIO[13] := Out Enable */
638 val &= ~BIT(14); /* GPIO[14] := Out Enable */
639 val &= ~BIT(15); /* GPIO[15] := Out Enable */
640 val &= ~BIT(16); /* GPIO[16] := Out Enable */
641 val &= ~BIT(21); /* GPIO[21] := Out Enable */
642 writel(val, MVEBU_GPIO0_BASE + 0x04);
643
644 val = readl(MVEBU_GPIO1_BASE + 0x04);
645 val &= ~BIT(6); /* GPIO[38] := Out Enable */
646 val &= ~BIT(7); /* GPIO[39] := Out Enable */
647 val &= ~BIT(8); /* GPIO[40] := Out Enable */
648 val &= ~BIT(9); /* GPIO[41] := Out Enable */
649 writel(val, MVEBU_GPIO1_BASE + 0x04);
650
651 /* Release switch reset */
652
653 ctrl[0] = EXT_CTL_nRES_LAN;
654 ctrl[1] = EXT_CTL_nRES_LAN;
655 err = omnia_mcu_write(CMD_EXT_CONTROL, ctrl, sizeof(ctrl));
656
Marek Behún59aa4652022-09-13 18:10:28 +0200657 mdelay(50);
Pali Rohár1e0a9752022-07-29 13:29:07 +0200658
659 /* Change RGMII pins back to RGMII mode */
660
661 writel(val04, MVEBU_MPP_BASE + 0x04);
662 writel(val08, MVEBU_MPP_BASE + 0x08);
663 writel(val10, MVEBU_MPP_BASE + 0x10);
664 writel(val14, MVEBU_MPP_BASE + 0x14);
665
666 puts(err ? "failed\n" : "done\n");
667}
668
Marek Behún09e16b82017-06-09 19:28:45 +0200669int board_early_init_f(void)
670{
Marek Behún09e16b82017-06-09 19:28:45 +0200671 /* Configure MPP */
672 writel(0x11111111, MVEBU_MPP_BASE + 0x00);
673 writel(0x11111111, MVEBU_MPP_BASE + 0x04);
674 writel(0x11244011, MVEBU_MPP_BASE + 0x08);
675 writel(0x22222111, MVEBU_MPP_BASE + 0x0c);
676 writel(0x22200002, MVEBU_MPP_BASE + 0x10);
677 writel(0x30042022, MVEBU_MPP_BASE + 0x14);
678 writel(0x55550555, MVEBU_MPP_BASE + 0x18);
679 writel(0x00005550, MVEBU_MPP_BASE + 0x1c);
680
681 /* Set GPP Out value */
682 writel(OMNIA_GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00);
683 writel(OMNIA_GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00);
684
685 /* Set GPP Polarity */
686 writel(OMNIA_GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c);
687 writel(OMNIA_GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c);
688
689 /* Set GPP Out Enable */
690 writel(OMNIA_GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04);
691 writel(OMNIA_GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04);
692
Marek Behún09e16b82017-06-09 19:28:45 +0200693 return 0;
694}
695
Marek Behúnf3556162021-08-16 15:19:39 +0200696void spl_board_init(void)
697{
Pali Rohár1e0a9752022-07-29 13:29:07 +0200698 u16 val;
699 int ret;
700
Marek Behúnf3556162021-08-16 15:19:39 +0200701 /*
702 * If booting from UART, disable MCU watchdog in SPL, since uploading
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100703 * U-Boot proper can take too much time and trigger it. Instead enable
704 * A385 watchdog with very high timeout (10 minutes) to prevent hangup.
Marek Behúnf3556162021-08-16 15:19:39 +0200705 */
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100706 if (get_boot_device() == BOOT_DEVICE_UART) {
707 enable_a385_watchdog(10);
Marek Behúnf3556162021-08-16 15:19:39 +0200708 disable_mcu_watchdog();
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100709 }
Pali Rohár1e0a9752022-07-29 13:29:07 +0200710
711 /*
712 * When MCU controls peripheral resets then release LAN eth switch from
713 * the reset and initialize it. When MCU does not control peripheral
714 * resets then LAN eth switch is initialized automatically by bootstrap
715 * pins when A385 is released from the reset.
716 */
717 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &val, sizeof(val));
718 if (ret == 0 && (val & STS_FEATURES_SUPPORTED)) {
719 ret = omnia_mcu_read(CMD_GET_FEATURES, &val, sizeof(val));
720 if (ret == 0 && (val & FEAT_PERIPH_MCU))
721 initialize_switch();
722 }
Marek Behúnf3556162021-08-16 15:19:39 +0200723}
724
Pali Rohárcbda3e22022-01-10 11:47:18 +0100725#if IS_ENABLED(CONFIG_OF_BOARD_FIXUP) || IS_ENABLED(CONFIG_OF_BOARD_SETUP)
726
Pali Rohár7cd41732022-03-02 12:47:56 +0100727static void disable_sata_node(void *blob)
Pali Rohárcbda3e22022-01-10 11:47:18 +0100728{
Pali Rohárcbda3e22022-01-10 11:47:18 +0100729 int node;
730
Pali Rohár7cd41732022-03-02 12:47:56 +0100731 fdt_for_each_node_by_compatible(node, blob, -1, "marvell,armada-380-ahci") {
732 if (!fdtdec_get_is_enabled(blob, node))
733 continue;
734
735 if (fdt_status_disabled(blob, node) < 0)
736 printf("Cannot disable SATA DT node!\n");
737 else
738 debug("Disabled SATA DT node\n");
739
Pali Roháre9105262022-03-02 12:47:57 +0100740 return;
Pali Rohár7cd41732022-03-02 12:47:56 +0100741 }
Pali Roháre9105262022-03-02 12:47:57 +0100742
743 printf("Cannot find SATA DT node!\n");
Pali Rohár7cd41732022-03-02 12:47:56 +0100744}
745
746static void disable_pcie_node(void *blob, int port)
747{
748 int node;
749
750 fdt_for_each_node_by_compatible(node, blob, -1, "marvell,armada-370-pcie") {
751 int port_node;
752
753 if (!fdtdec_get_is_enabled(blob, node))
754 continue;
755
756 fdt_for_each_subnode (port_node, blob, node) {
757 if (!fdtdec_get_is_enabled(blob, port_node))
758 continue;
759
760 if (fdtdec_get_int(blob, port_node, "marvell,pcie-port", -1) != port)
761 continue;
762
763 if (fdt_status_disabled(blob, port_node) < 0)
764 printf("Cannot disable PCIe port %d DT node!\n", port);
765 else
766 debug("Disabled PCIe port %d DT node\n", port);
767
768 return;
769 }
770 }
Pali Roháre9105262022-03-02 12:47:57 +0100771
772 printf("Cannot find PCIe port %d DT node!\n", port);
Pali Rohár7cd41732022-03-02 12:47:56 +0100773}
774
775static void fixup_msata_port_nodes(void *blob)
776{
777 bool mode_sata;
778
Pali Rohárcbda3e22022-01-10 11:47:18 +0100779 /*
780 * Determine if SerDes 0 is configured to SATA mode.
781 * We do this instead of calling omnia_detect_sata() to avoid another
782 * call to the MCU. By this time the common PHYs are initialized (it is
783 * done in SPL), so we can read this common PHY register.
784 */
785 mode_sata = (readl(MVEBU_REGISTER(0x183fc)) & GENMASK(3, 0)) == 2;
786
787 /*
788 * We're either adding status = "disabled" property, or changing
789 * status = "okay" to status = "disabled". In both cases we'll need more
790 * space. Increase the size a little.
791 */
792 if (fdt_increase_size(blob, 32) < 0) {
793 printf("Cannot increase FDT size!\n");
794 return;
795 }
796
Pali Rohárcbda3e22022-01-10 11:47:18 +0100797 if (!mode_sata) {
Pali Rohár7cd41732022-03-02 12:47:56 +0100798 /* If mSATA card is not present, disable SATA DT node */
799 disable_sata_node(blob);
800 } else {
801 /* Otherwise disable PCIe port 0 DT node (MiniPCIe / mSATA port) */
802 disable_pcie_node(blob, 0);
Pali Rohárcbda3e22022-01-10 11:47:18 +0100803 }
Pali Rohár93a89c52022-03-02 12:47:58 +0100804}
805
806static void fixup_wwan_port_nodes(void *blob)
807{
808 bool mode_usb3;
809
810 /* Determine if SerDes 4 is configured to USB3 mode */
811 mode_usb3 = ((readl(MVEBU_REGISTER(0x183fc)) & GENMASK(19, 16)) >> 16) == 4;
812
813 /* If SerDes 4 is not configured to USB3 mode then nothing is needed to fixup */
814 if (!mode_usb3)
815 return;
816
817 /*
818 * We're either adding status = "disabled" property, or changing
819 * status = "okay" to status = "disabled". In both cases we'll need more
820 * space. Increase the size a little.
821 */
822 if (fdt_increase_size(blob, 32) < 0) {
823 printf("Cannot increase FDT size!\n");
824 return;
825 }
826
827 /* Disable PCIe port 2 DT node (WWAN) */
828 disable_pcie_node(blob, 2);
Pali Rohárcbda3e22022-01-10 11:47:18 +0100829}
830
Pali Rohár1e0a9752022-07-29 13:29:07 +0200831static int insert_mcu_gpio_prop(void *blob, int node, const char *prop,
832 unsigned int phandle, u32 bank, u32 gpio,
833 u32 flags)
834{
835 fdt32_t val[4] = { cpu_to_fdt32(phandle), cpu_to_fdt32(bank),
836 cpu_to_fdt32(gpio), cpu_to_fdt32(flags) };
837 return fdt_setprop(blob, node, prop, &val, sizeof(val));
838}
839
840static int fixup_mcu_gpio_in_pcie_nodes(void *blob)
841{
842 unsigned int mcu_phandle;
843 int port, gpio;
844 int pcie_node;
845 int port_node;
846 int ret;
847
848 ret = fdt_increase_size(blob, 128);
849 if (ret < 0) {
850 printf("Cannot increase FDT size!\n");
851 return ret;
852 }
853
854 mcu_phandle = fdt_create_phandle_by_compatible(blob, "cznic,turris-omnia-mcu");
855 if (!mcu_phandle)
856 return -FDT_ERR_NOPHANDLES;
857
858 fdt_for_each_node_by_compatible(pcie_node, blob, -1, "marvell,armada-370-pcie") {
859 if (!fdtdec_get_is_enabled(blob, pcie_node))
860 continue;
861
862 fdt_for_each_subnode(port_node, blob, pcie_node) {
863 if (!fdtdec_get_is_enabled(blob, port_node))
864 continue;
865
866 port = fdtdec_get_int(blob, port_node, "marvell,pcie-port", -1);
867
868 if (port == 0)
869 gpio = ilog2(EXT_CTL_nPERST0);
870 else if (port == 1)
871 gpio = ilog2(EXT_CTL_nPERST1);
872 else if (port == 2)
873 gpio = ilog2(EXT_CTL_nPERST2);
874 else
875 continue;
876
877 /* insert: reset-gpios = <&mcu 2 gpio GPIO_ACTIVE_LOW>; */
878 ret = insert_mcu_gpio_prop(blob, port_node, "reset-gpios",
879 mcu_phandle, 2, gpio, GPIO_ACTIVE_LOW);
880 if (ret < 0)
881 return ret;
882 }
883 }
884
885 return 0;
886}
887
888static int fixup_mcu_gpio_in_eth_wan_node(void *blob)
889{
890 unsigned int mcu_phandle;
891 int eth_wan_node;
892 int ret;
893
894 ret = fdt_increase_size(blob, 64);
895 if (ret < 0) {
896 printf("Cannot increase FDT size!\n");
897 return ret;
898 }
899
900 eth_wan_node = fdt_path_offset(blob, "ethernet2");
901 if (eth_wan_node < 0)
902 return eth_wan_node;
903
904 mcu_phandle = fdt_create_phandle_by_compatible(blob, "cznic,turris-omnia-mcu");
905 if (!mcu_phandle)
906 return -FDT_ERR_NOPHANDLES;
907
908 /* insert: phy-reset-gpios = <&mcu 2 gpio GPIO_ACTIVE_LOW>; */
909 ret = insert_mcu_gpio_prop(blob, eth_wan_node, "phy-reset-gpios",
910 mcu_phandle, 2, ilog2(EXT_CTL_nRES_PHY), GPIO_ACTIVE_LOW);
911 if (ret < 0)
912 return ret;
913
914 return 0;
915}
916
Pali Rohárcbda3e22022-01-10 11:47:18 +0100917#endif
918
919#if IS_ENABLED(CONFIG_OF_BOARD_FIXUP)
920int board_fix_fdt(void *blob)
921{
Pali Rohár1e0a9752022-07-29 13:29:07 +0200922 u16 val;
923 int ret;
924
925 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &val, sizeof(val));
926 if (ret == 0 && (val & STS_FEATURES_SUPPORTED)) {
927 ret = omnia_mcu_read(CMD_GET_FEATURES, &val, sizeof(val));
928 if (ret == 0 && (val & FEAT_PERIPH_MCU)) {
929 fixup_mcu_gpio_in_pcie_nodes(blob);
930 fixup_mcu_gpio_in_eth_wan_node(blob);
931 }
932 }
933
Pali Rohár7cd41732022-03-02 12:47:56 +0100934 fixup_msata_port_nodes(blob);
Pali Rohár93a89c52022-03-02 12:47:58 +0100935 fixup_wwan_port_nodes(blob);
Pali Rohárcbda3e22022-01-10 11:47:18 +0100936
937 return 0;
938}
939#endif
940
Marek Behún09e16b82017-06-09 19:28:45 +0200941int board_init(void)
942{
Marek Behún4dfc57e2019-05-02 16:53:31 +0200943 /* address of boot parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200944 gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
945
Marek Behún88dc0242021-08-16 15:19:40 +0200946 return 0;
947}
948
949int board_late_init(void)
950{
Marek Behúnf3556162021-08-16 15:19:39 +0200951 /*
952 * If not booting from UART, MCU watchdog was not disabled in SPL,
953 * disable it now.
954 */
955 if (get_boot_device() != BOOT_DEVICE_UART)
956 disable_mcu_watchdog();
Marek Behún09e16b82017-06-09 19:28:45 +0200957
Marek Behún09e16b82017-06-09 19:28:45 +0200958 set_regdomain();
Marek Behún0f2e66a2019-05-02 16:53:37 +0200959 handle_reset_button();
Marek Behúndb1e5c62019-05-24 14:57:53 +0200960 pci_init();
Marek Behún09e16b82017-06-09 19:28:45 +0200961
962 return 0;
963}
964
Marek Behúnab9447f2021-10-09 19:33:44 +0200965int show_board_info(void)
Marek Behún09e16b82017-06-09 19:28:45 +0200966{
Pali Rohár38ecdab2022-08-27 20:06:30 +0200967 char serial[17];
Pali Rohár0387f7f2022-04-08 16:30:12 +0200968 int err;
Marek Behún09e16b82017-06-09 19:28:45 +0200969
Pali Rohár38ecdab2022-08-27 20:06:30 +0200970 err = turris_atsha_otp_get_serial_number(serial);
Marek Behúnab9447f2021-10-09 19:33:44 +0200971 printf("Model: Turris Omnia\n");
Pali Rohár4798ba92022-07-29 13:29:06 +0200972 printf(" MCU type: %s\n", omnia_get_mcu_type());
Pali Roháre16cc982022-08-10 11:00:25 +0200973 printf(" MCU version: %s\n", omnia_get_mcu_version());
Marek Behúnc4ba72a2019-05-02 16:53:34 +0200974 printf(" RAM size: %i MiB\n", omnia_get_ram_size_gb() * 1024);
Pali Rohár38ecdab2022-08-27 20:06:30 +0200975 printf(" Serial Number: %s\n", !err ? serial : "unknown");
Marek Behún09e16b82017-06-09 19:28:45 +0200976
977 return 0;
978}
979
Marek Behún09e16b82017-06-09 19:28:45 +0200980int misc_init_r(void)
981{
Pali Rohár60f37e82022-04-08 16:30:14 +0200982 turris_atsha_otp_init_mac_addresses(1);
Pali Rohár38ecdab2022-08-27 20:06:30 +0200983 turris_atsha_otp_init_serial_number();
Marek Behún09e16b82017-06-09 19:28:45 +0200984 return 0;
985}
986
Marek Behún91ef59c2021-07-15 19:21:02 +0200987#if defined(CONFIG_OF_BOARD_SETUP)
988/*
989 * I plan to generalize this function and move it to common/fdt_support.c.
990 * This will require some more work on multiple boards, though, so for now leave
991 * it here.
992 */
993static bool fixup_mtd_partitions(void *blob, int offset, struct mtd_info *mtd)
994{
995 struct mtd_info *slave;
996 int parts;
997
998 parts = fdt_subnode_offset(blob, offset, "partitions");
Pali Roháre2b1ba02022-08-01 12:02:19 +0200999 if (parts >= 0) {
1000 if (fdt_del_node(blob, parts) < 0)
1001 return false;
1002 }
Marek Behún91ef59c2021-07-15 19:21:02 +02001003
Pali Rohárd35b6f22022-08-01 12:02:20 +02001004 if (fdt_increase_size(blob, 512) < 0)
1005 return false;
1006
Marek Behún91ef59c2021-07-15 19:21:02 +02001007 parts = fdt_add_subnode(blob, offset, "partitions");
1008 if (parts < 0)
1009 return false;
1010
1011 if (fdt_setprop_u32(blob, parts, "#address-cells", 1) < 0)
1012 return false;
1013
1014 if (fdt_setprop_u32(blob, parts, "#size-cells", 1) < 0)
1015 return false;
1016
1017 if (fdt_setprop_string(blob, parts, "compatible",
1018 "fixed-partitions") < 0)
1019 return false;
1020
1021 mtd_probe_devices();
1022
Pali Rohárd8210ef2021-10-21 17:55:48 +02001023 list_for_each_entry_reverse(slave, &mtd->partitions, node) {
Marek Behún91ef59c2021-07-15 19:21:02 +02001024 char name[32];
1025 int part;
1026
1027 snprintf(name, sizeof(name), "partition@%llx", slave->offset);
1028 part = fdt_add_subnode(blob, parts, name);
1029 if (part < 0)
1030 return false;
1031
1032 if (fdt_setprop_u32(blob, part, "reg", slave->offset) < 0)
1033 return false;
1034
1035 if (fdt_appendprop_u32(blob, part, "reg", slave->size) < 0)
1036 return false;
1037
1038 if (fdt_setprop_string(blob, part, "label", slave->name) < 0)
1039 return false;
1040
1041 if (!(slave->flags & MTD_WRITEABLE))
1042 if (fdt_setprop_empty(blob, part, "read-only") < 0)
1043 return false;
1044
1045 if (slave->flags & MTD_POWERUP_LOCK)
1046 if (fdt_setprop_empty(blob, part, "lock") < 0)
1047 return false;
1048 }
1049
1050 return true;
1051}
1052
Pali Rohárcbda3e22022-01-10 11:47:18 +01001053static void fixup_spi_nor_partitions(void *blob)
Marek Behún91ef59c2021-07-15 19:21:02 +02001054{
Pali Rohár3215c032022-08-01 23:58:42 +02001055 struct mtd_info *mtd = NULL;
1056 char mtd_path[64];
Marek Behún91ef59c2021-07-15 19:21:02 +02001057 int node;
1058
Pali Rohár3215c032022-08-01 23:58:42 +02001059 node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "jedec,spi-nor");
1060 if (node < 0)
1061 goto fail;
1062
1063 if (fdt_get_path(gd->fdt_blob, node, mtd_path, sizeof(mtd_path)) < 0)
1064 goto fail;
1065
1066 mtd = get_mtd_device_nm(mtd_path);
Marek Behún91ef59c2021-07-15 19:21:02 +02001067 if (IS_ERR_OR_NULL(mtd))
1068 goto fail;
1069
Pali Rohár3215c032022-08-01 23:58:42 +02001070 node = fdt_node_offset_by_compatible(blob, -1, "jedec,spi-nor");
Marek Behún91ef59c2021-07-15 19:21:02 +02001071 if (node < 0)
1072 goto fail;
1073
1074 if (!fixup_mtd_partitions(blob, node, mtd))
1075 goto fail;
1076
Marek Behún36feac92021-09-25 02:49:18 +02001077 put_mtd_device(mtd);
Pali Rohárcbda3e22022-01-10 11:47:18 +01001078 return;
Marek Behún91ef59c2021-07-15 19:21:02 +02001079
1080fail:
1081 printf("Failed fixing SPI NOR partitions!\n");
Marek Behún36feac92021-09-25 02:49:18 +02001082 if (!IS_ERR_OR_NULL(mtd))
1083 put_mtd_device(mtd);
Pali Rohárcbda3e22022-01-10 11:47:18 +01001084}
1085
1086int ft_board_setup(void *blob, struct bd_info *bd)
1087{
Pali Rohár1e0a9752022-07-29 13:29:07 +02001088 int node;
1089
1090 /*
1091 * U-Boot's FDT blob contains phy-reset-gpios in ethernet2
1092 * node when MCU controls all peripherals resets.
1093 * Fixup MCU GPIO nodes in PCIe and eth wan nodes in this case.
1094 */
1095 node = fdt_path_offset(gd->fdt_blob, "ethernet2");
1096 if (node >= 0 && fdt_getprop(gd->fdt_blob, node, "phy-reset-gpios", NULL)) {
1097 fixup_mcu_gpio_in_pcie_nodes(blob);
1098 fixup_mcu_gpio_in_eth_wan_node(blob);
1099 }
1100
Pali Rohárcbda3e22022-01-10 11:47:18 +01001101 fixup_spi_nor_partitions(blob);
Pali Rohár7cd41732022-03-02 12:47:56 +01001102 fixup_msata_port_nodes(blob);
Pali Rohár93a89c52022-03-02 12:47:58 +01001103 fixup_wwan_port_nodes(blob);
Pali Rohárcbda3e22022-01-10 11:47:18 +01001104
Marek Behún91ef59c2021-07-15 19:21:02 +02001105 return 0;
1106}
1107#endif