blob: 98bad11537d3b0816b830cd0f54bb57237831f9d [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>
24#include <time.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060025#include <linux/bitops.h>
Pali Rohár1e0a9752022-07-29 13:29:07 +020026#include <linux/delay.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070027#include <u-boot/crc.h>
Marek Behún09e16b82017-06-09 19:28:45 +020028
Chris Packham1a07d212018-05-10 13:28:29 +120029#include "../drivers/ddr/marvell/a38x/ddr3_init.h"
Marek Behún09e16b82017-06-09 19:28:45 +020030#include <../serdes/a38x/high_speed_env_spec.h>
Pali Rohár0387f7f2022-04-08 16:30:12 +020031#include "../turris_atsha_otp.h"
Marek Behún09e16b82017-06-09 19:28:45 +020032
33DECLARE_GLOBAL_DATA_PTR;
34
Marek Behún91ef59c2021-07-15 19:21:02 +020035#define OMNIA_SPI_NOR_PATH "/soc/spi@10600/spi-nor@0"
36
Marek Behúnba53b6b2019-05-02 16:53:30 +020037#define OMNIA_I2C_BUS_NAME "i2c@11000->i2cmux@70->i2c@0"
38
39#define OMNIA_I2C_MCU_CHIP_ADDR 0x2a
40#define OMNIA_I2C_MCU_CHIP_LEN 1
41
42#define OMNIA_I2C_EEPROM_CHIP_ADDR 0x54
43#define OMNIA_I2C_EEPROM_CHIP_LEN 2
Marek Behún09e16b82017-06-09 19:28:45 +020044#define OMNIA_I2C_EEPROM_MAGIC 0x0341a034
45
Pali Rohár30e398d2022-04-29 13:53:25 +020046#define A385_SYS_RSTOUT_MASK MVEBU_REGISTER(0x18260)
47#define A385_SYS_RSTOUT_MASK_WD BIT(10)
Pali Rohár7fcda0c2021-11-09 17:14:02 +010048
49#define A385_WDT_GLOBAL_CTRL MVEBU_REGISTER(0x20300)
50#define A385_WDT_GLOBAL_RATIO_MASK GENMASK(18, 16)
51#define A385_WDT_GLOBAL_RATIO_SHIFT 16
52#define A385_WDT_GLOBAL_25MHZ BIT(10)
53#define A385_WDT_GLOBAL_ENABLE BIT(8)
54
55#define A385_WDT_GLOBAL_STATUS MVEBU_REGISTER(0x20304)
56#define A385_WDT_GLOBAL_EXPIRED BIT(31)
57
58#define A385_WDT_DURATION MVEBU_REGISTER(0x20334)
59
60#define A385_WD_RSTOUT_UNMASK MVEBU_REGISTER(0x20704)
61#define A385_WD_RSTOUT_UNMASK_GLOBAL BIT(8)
62
Marek Behúnba53b6b2019-05-02 16:53:30 +020063enum mcu_commands {
64 CMD_GET_STATUS_WORD = 0x01,
65 CMD_GET_RESET = 0x09,
66 CMD_WATCHDOG_STATE = 0x0b,
Pali Rohár4798ba92022-07-29 13:29:06 +020067
68 /* available if STS_FEATURES_SUPPORTED bit set in status word */
69 CMD_GET_FEATURES = 0x10,
Pali Rohár1e0a9752022-07-29 13:29:07 +020070
71 /* available if EXT_CMD bit set in features */
72 CMD_EXT_CONTROL = 0x12,
Marek Behúnba53b6b2019-05-02 16:53:30 +020073};
74
75enum status_word_bits {
Pali Rohár4798ba92022-07-29 13:29:06 +020076 STS_MCU_TYPE_MASK = GENMASK(1, 0),
77 STS_MCU_TYPE_STM32 = 0,
78 STS_MCU_TYPE_GD32 = 1,
79 STS_MCU_TYPE_MKL = 2,
80 STS_MCU_TYPE_UNKN = 3,
81 STS_FEATURES_SUPPORTED = BIT(2),
Marek Behúnba53b6b2019-05-02 16:53:30 +020082 CARD_DET_STSBIT = 0x0010,
83 MSATA_IND_STSBIT = 0x0020,
84};
Marek Behún09e16b82017-06-09 19:28:45 +020085
Pali Rohár4798ba92022-07-29 13:29:06 +020086/* CMD_GET_FEATURES */
87enum features_e {
88 FEAT_PERIPH_MCU = BIT(0),
Pali Rohár1e0a9752022-07-29 13:29:07 +020089 FEAT_EXT_CMDS = BIT(1),
90};
91
92/* CMD_EXT_CONTROL */
93enum ext_ctl_e {
94 EXT_CTL_nRES_LAN = BIT(1),
95 EXT_CTL_nRES_PHY = BIT(2),
96 EXT_CTL_nPERST0 = BIT(3),
97 EXT_CTL_nPERST1 = BIT(4),
98 EXT_CTL_nPERST2 = BIT(5),
Pali Rohár4798ba92022-07-29 13:29:06 +020099};
100
Marek Behún09e16b82017-06-09 19:28:45 +0200101/*
102 * Those values and defines are taken from the Marvell U-Boot version
103 * "u-boot-2013.01-2014_T3.0"
104 */
105#define OMNIA_GPP_OUT_ENA_LOW \
106 (~(BIT(1) | BIT(4) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | \
107 BIT(10) | BIT(11) | BIT(19) | BIT(22) | BIT(23) | BIT(25) | \
108 BIT(26) | BIT(27) | BIT(29) | BIT(30) | BIT(31)))
109#define OMNIA_GPP_OUT_ENA_MID \
110 (~(BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(15) | \
111 BIT(16) | BIT(17) | BIT(18)))
112
113#define OMNIA_GPP_OUT_VAL_LOW 0x0
114#define OMNIA_GPP_OUT_VAL_MID 0x0
115#define OMNIA_GPP_POL_LOW 0x0
116#define OMNIA_GPP_POL_MID 0x0
117
Pali Rohár3c4dd982022-03-02 12:47:54 +0100118static struct serdes_map board_serdes_map[] = {
Marek Behún09e16b82017-06-09 19:28:45 +0200119 {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
120 {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
121 {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
122 {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
123 {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
124 {SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}
125};
126
Marek Behúnba53b6b2019-05-02 16:53:30 +0200127static struct udevice *omnia_get_i2c_chip(const char *name, uint addr,
128 uint offset_len)
Marek Behún09e16b82017-06-09 19:28:45 +0200129{
130 struct udevice *bus, *dev;
Marek Behúnba53b6b2019-05-02 16:53:30 +0200131 int ret;
Marek Behún09e16b82017-06-09 19:28:45 +0200132
Marek Behúnba53b6b2019-05-02 16:53:30 +0200133 ret = uclass_get_device_by_name(UCLASS_I2C, OMNIA_I2C_BUS_NAME, &bus);
134 if (ret) {
135 printf("Cannot get I2C bus %s: uclass_get_device_by_name failed: %i\n",
136 OMNIA_I2C_BUS_NAME, ret);
137 return NULL;
Marek Behún09e16b82017-06-09 19:28:45 +0200138 }
139
Marek Behúnba53b6b2019-05-02 16:53:30 +0200140 ret = i2c_get_chip(bus, addr, offset_len, &dev);
Marek Behún09e16b82017-06-09 19:28:45 +0200141 if (ret) {
Marek Behúnba53b6b2019-05-02 16:53:30 +0200142 printf("Cannot get %s I2C chip: i2c_get_chip failed: %i\n",
143 name, ret);
144 return NULL;
Marek Behún09e16b82017-06-09 19:28:45 +0200145 }
146
Marek Behúnba53b6b2019-05-02 16:53:30 +0200147 return dev;
148}
Marek Behúnd0b374d2017-08-04 15:28:25 +0200149
Marek Behúnba53b6b2019-05-02 16:53:30 +0200150static int omnia_mcu_read(u8 cmd, void *buf, int len)
151{
152 struct udevice *chip;
153
154 chip = omnia_get_i2c_chip("MCU", OMNIA_I2C_MCU_CHIP_ADDR,
155 OMNIA_I2C_MCU_CHIP_LEN);
156 if (!chip)
157 return -ENODEV;
158
159 return dm_i2c_read(chip, cmd, buf, len);
160}
161
Marek Behúnba53b6b2019-05-02 16:53:30 +0200162static int omnia_mcu_write(u8 cmd, const void *buf, int len)
163{
164 struct udevice *chip;
165
166 chip = omnia_get_i2c_chip("MCU", OMNIA_I2C_MCU_CHIP_ADDR,
167 OMNIA_I2C_MCU_CHIP_LEN);
168 if (!chip)
169 return -ENODEV;
170
171 return dm_i2c_write(chip, cmd, buf, len);
172}
173
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100174static void enable_a385_watchdog(unsigned int timeout_minutes)
175{
176 struct sar_freq_modes sar_freq;
177 u32 watchdog_freq;
178
179 printf("Enabling A385 watchdog with %u minutes timeout...\n",
180 timeout_minutes);
181
182 /*
183 * Use NBCLK clock (a.k.a. L2 clock) as watchdog input clock with
184 * its maximal ratio 7 instead of default fixed 25 MHz clock.
185 * It allows to set watchdog duration up to the 22 minutes.
186 */
187 clrsetbits_32(A385_WDT_GLOBAL_CTRL,
188 A385_WDT_GLOBAL_25MHZ | A385_WDT_GLOBAL_RATIO_MASK,
189 7 << A385_WDT_GLOBAL_RATIO_SHIFT);
190
191 /*
192 * Calculate watchdog clock frequency. It is defined by formula:
193 * freq = NBCLK / 2 / (2 ^ ratio)
194 * We set ratio to the maximal possible value 7.
195 */
196 get_sar_freq(&sar_freq);
197 watchdog_freq = sar_freq.nb_clk * 1000000 / 2 / (1 << 7);
198
199 /* Set watchdog duration */
200 writel(timeout_minutes * 60 * watchdog_freq, A385_WDT_DURATION);
201
202 /* Clear the watchdog expiration bit */
203 clrbits_32(A385_WDT_GLOBAL_STATUS, A385_WDT_GLOBAL_EXPIRED);
204
205 /* Enable watchdog timer */
206 setbits_32(A385_WDT_GLOBAL_CTRL, A385_WDT_GLOBAL_ENABLE);
207
208 /* Enable reset on watchdog */
209 setbits_32(A385_WD_RSTOUT_UNMASK, A385_WD_RSTOUT_UNMASK_GLOBAL);
210
211 /* Unmask reset for watchdog */
Pali Rohár30e398d2022-04-29 13:53:25 +0200212 clrbits_32(A385_SYS_RSTOUT_MASK, A385_SYS_RSTOUT_MASK_WD);
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100213}
214
Marek Behúnba53b6b2019-05-02 16:53:30 +0200215static bool disable_mcu_watchdog(void)
216{
217 int ret;
218
219 puts("Disabling MCU watchdog... ");
220
221 ret = omnia_mcu_write(CMD_WATCHDOG_STATE, "\x00", 1);
222 if (ret) {
223 printf("omnia_mcu_write failed: %i\n", ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200224 return false;
225 }
226
Marek Behúnba53b6b2019-05-02 16:53:30 +0200227 puts("disabled\n");
228
229 return true;
230}
Marek Behúnba53b6b2019-05-02 16:53:30 +0200231
Pali Rohárf8f305b2022-03-02 12:47:55 +0100232static bool omnia_detect_sata(const char *msata_slot)
Marek Behúnba53b6b2019-05-02 16:53:30 +0200233{
234 int ret;
235 u16 stsword;
236
237 puts("MiniPCIe/mSATA card detection... ");
238
Pali Rohárf8f305b2022-03-02 12:47:55 +0100239 if (msata_slot) {
240 if (strcmp(msata_slot, "pcie") == 0) {
241 puts("forced to MiniPCIe via env\n");
242 return false;
243 } else if (strcmp(msata_slot, "sata") == 0) {
244 puts("forced to mSATA via env\n");
245 return true;
246 } else if (strcmp(msata_slot, "auto") != 0) {
247 printf("unsupported env value '%s', fallback to... ", msata_slot);
248 }
249 }
250
Marek Behúnba53b6b2019-05-02 16:53:30 +0200251 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
252 if (ret) {
253 printf("omnia_mcu_read failed: %i, defaulting to MiniPCIe card\n",
254 ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200255 return false;
256 }
257
Marek Behúnba53b6b2019-05-02 16:53:30 +0200258 if (!(stsword & CARD_DET_STSBIT)) {
259 puts("none\n");
Marek Behún09e16b82017-06-09 19:28:45 +0200260 return false;
261 }
Marek Behúnba53b6b2019-05-02 16:53:30 +0200262
263 if (stsword & MSATA_IND_STSBIT)
264 puts("mSATA\n");
265 else
266 puts("MiniPCIe\n");
267
268 return stsword & MSATA_IND_STSBIT ? true : false;
Marek Behún09e16b82017-06-09 19:28:45 +0200269}
270
Pali Rohár93a89c52022-03-02 12:47:58 +0100271static bool omnia_detect_wwan_usb3(const char *wwan_slot)
272{
273 puts("WWAN slot configuration... ");
274
275 if (wwan_slot && strcmp(wwan_slot, "usb3") == 0) {
276 puts("USB3.0\n");
277 return true;
278 }
279
280 if (wwan_slot && strcmp(wwan_slot, "pcie") != 0)
281 printf("unsupported env value '%s', fallback to... ", wwan_slot);
282
283 puts("PCIe+USB2.0\n");
284 return false;
285}
286
Pali Rohárc13401b2022-03-02 12:47:52 +0100287void *env_sf_get_env_addr(void)
288{
289 /* SPI Flash is mapped to address 0xD4000000 only in SPL */
290#ifdef CONFIG_SPL_BUILD
291 return (void *)0xD4000000 + CONFIG_ENV_OFFSET;
292#else
293 return NULL;
294#endif
295}
296
Marek Behún09e16b82017-06-09 19:28:45 +0200297int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count)
298{
Pali Rohárf8f305b2022-03-02 12:47:55 +0100299#ifdef CONFIG_SPL_ENV_SUPPORT
300 /* Do not use env_load() as malloc() pool is too small at this stage */
301 bool has_env = (env_init() == 0);
302#endif
303 const char *env_value = NULL;
304
305#ifdef CONFIG_SPL_ENV_SUPPORT
306 /* beware that env_get() returns static allocated memory */
307 env_value = has_env ? env_get("omnia_msata_slot") : NULL;
308#endif
309
310 if (omnia_detect_sata(env_value)) {
Pali Rohár3c4dd982022-03-02 12:47:54 +0100311 /* Change SerDes for first mPCIe port (mSATA) from PCIe to SATA */
312 board_serdes_map[0].serdes_type = SATA0;
313 board_serdes_map[0].serdes_speed = SERDES_SPEED_6_GBPS;
314 board_serdes_map[0].serdes_mode = SERDES_DEFAULT_MODE;
Marek Behún09e16b82017-06-09 19:28:45 +0200315 }
316
Pali Rohár93a89c52022-03-02 12:47:58 +0100317#ifdef CONFIG_SPL_ENV_SUPPORT
318 /* beware that env_get() returns static allocated memory */
319 env_value = has_env ? env_get("omnia_wwan_slot") : NULL;
320#endif
321
322 if (omnia_detect_wwan_usb3(env_value)) {
323 /* Disable SerDes for USB 3.0 pins on the front USB-A port */
324 board_serdes_map[1].serdes_type = DEFAULT_SERDES;
325 /* Change SerDes for third mPCIe port (WWAN) from PCIe to USB 3.0 */
326 board_serdes_map[4].serdes_type = USB3_HOST0;
327 board_serdes_map[4].serdes_speed = SERDES_SPEED_5_GBPS;
328 board_serdes_map[4].serdes_mode = SERDES_DEFAULT_MODE;
329 }
330
Pali Rohár3c4dd982022-03-02 12:47:54 +0100331 *serdes_map_array = board_serdes_map;
332 *count = ARRAY_SIZE(board_serdes_map);
333
Marek Behún09e16b82017-06-09 19:28:45 +0200334 return 0;
335}
336
337struct omnia_eeprom {
338 u32 magic;
339 u32 ramsize;
340 char region[4];
341 u32 crc;
342};
343
344static bool omnia_read_eeprom(struct omnia_eeprom *oep)
345{
Marek Behúnba53b6b2019-05-02 16:53:30 +0200346 struct udevice *chip;
347 u32 crc;
348 int ret;
Marek Behún09e16b82017-06-09 19:28:45 +0200349
Marek Behúnba53b6b2019-05-02 16:53:30 +0200350 chip = omnia_get_i2c_chip("EEPROM", OMNIA_I2C_EEPROM_CHIP_ADDR,
351 OMNIA_I2C_EEPROM_CHIP_LEN);
352
353 if (!chip)
Marek Behún09e16b82017-06-09 19:28:45 +0200354 return false;
Marek Behún09e16b82017-06-09 19:28:45 +0200355
Marek Behúnba53b6b2019-05-02 16:53:30 +0200356 ret = dm_i2c_read(chip, 0, (void *)oep, sizeof(*oep));
Marek Behún09e16b82017-06-09 19:28:45 +0200357 if (ret) {
Marek Behúnba53b6b2019-05-02 16:53:30 +0200358 printf("dm_i2c_read failed: %i, cannot read EEPROM\n", ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200359 return false;
360 }
361
Marek Behúnba53b6b2019-05-02 16:53:30 +0200362 if (oep->magic != OMNIA_I2C_EEPROM_MAGIC) {
363 printf("bad EEPROM magic number (%08x, should be %08x)\n",
364 oep->magic, OMNIA_I2C_EEPROM_MAGIC);
365 return false;
Marek Behún09e16b82017-06-09 19:28:45 +0200366 }
367
Marek Behúnba53b6b2019-05-02 16:53:30 +0200368 crc = crc32(0, (void *)oep, sizeof(*oep) - 4);
369 if (crc != oep->crc) {
370 printf("bad EEPROM CRC (stored %08x, computed %08x)\n",
371 oep->crc, crc);
Marek Behún09e16b82017-06-09 19:28:45 +0200372 return false;
373 }
374
375 return true;
376}
377
Marek Behún77652c72019-05-02 16:53:33 +0200378static int omnia_get_ram_size_gb(void)
379{
380 static int ram_size;
381 struct omnia_eeprom oep;
382
383 if (!ram_size) {
384 /* Get the board config from EEPROM */
385 if (omnia_read_eeprom(&oep)) {
386 debug("Memory config in EEPROM: 0x%02x\n", oep.ramsize);
387
388 if (oep.ramsize == 0x2)
389 ram_size = 2;
390 else
391 ram_size = 1;
392 } else {
393 /* Hardcoded fallback */
394 puts("Memory config from EEPROM read failed!\n");
395 puts("Falling back to default 1 GiB!\n");
396 ram_size = 1;
397 }
398 }
399
400 return ram_size;
401}
402
Pali Rohár4798ba92022-07-29 13:29:06 +0200403static const char * const omnia_get_mcu_type(void)
404{
405 static const char * const mcu_types[] = {
406 [STS_MCU_TYPE_STM32] = "STM32",
407 [STS_MCU_TYPE_GD32] = "GD32",
408 [STS_MCU_TYPE_MKL] = "MKL",
409 [STS_MCU_TYPE_UNKN] = "unknown",
410 };
411 static const char * const mcu_types_with_perip_resets[] = {
412 [STS_MCU_TYPE_STM32] = "STM32 (with peripheral resets)",
413 [STS_MCU_TYPE_GD32] = "GD32 (with peripheral resets)",
414 [STS_MCU_TYPE_MKL] = "MKL (with peripheral resets)",
415 [STS_MCU_TYPE_UNKN] = "unknown (with peripheral resets)",
416 };
417 u16 stsword, features;
418 int ret;
419
420 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
421 if (ret)
422 return "unknown";
423
424 if (stsword & STS_FEATURES_SUPPORTED) {
425 ret = omnia_mcu_read(CMD_GET_FEATURES, &features, sizeof(features));
426 if (ret == 0 && (features & FEAT_PERIPH_MCU))
427 return mcu_types_with_perip_resets[stsword & STS_MCU_TYPE_MASK];
428 }
429
430 return mcu_types[stsword & STS_MCU_TYPE_MASK];
431}
432
Marek Behún09e16b82017-06-09 19:28:45 +0200433/*
434 * Define the DDR layout / topology here in the board file. This will
435 * be used by the DDR3 init code in the SPL U-Boot version to configure
436 * the DDR3 controller.
437 */
Chris Packham1a07d212018-05-10 13:28:29 +1200438static struct mv_ddr_topology_map board_topology_map_1g = {
439 DEBUG_LEVEL_ERROR,
Marek Behún09e16b82017-06-09 19:28:45 +0200440 0x1, /* active interfaces */
441 /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */
442 { { { {0x1, 0, 0, 0},
443 {0x1, 0, 0, 0},
444 {0x1, 0, 0, 0},
445 {0x1, 0, 0, 0},
446 {0x1, 0, 0, 0} },
447 SPEED_BIN_DDR_1600K, /* speed_bin */
Chris Packham1a07d212018-05-10 13:28:29 +1200448 MV_DDR_DEV_WIDTH_16BIT, /* memory_width */
449 MV_DDR_DIE_CAP_4GBIT, /* mem_size */
Chris Packham4bf81db2018-12-03 14:26:49 +1300450 MV_DDR_FREQ_800, /* frequency */
Chris Packhamdd092bd2017-11-29 10:38:34 +1300451 0, 0, /* cas_wl cas_l */
Chris Packham3a09e132018-05-10 13:28:30 +1200452 MV_DDR_TEMP_NORMAL, /* temperature */
453 MV_DDR_TIM_2T} }, /* timing */
Chris Packham1a07d212018-05-10 13:28:29 +1200454 BUS_MASK_32BIT, /* Busses mask */
455 MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
Moti Buskila498475e2021-02-19 17:11:19 +0100456 NOT_COMBINED, /* ddr twin-die combined */
Chris Packham1a07d212018-05-10 13:28:29 +1200457 { {0} }, /* raw spd data */
458 {0} /* timing parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200459};
460
Chris Packham1a07d212018-05-10 13:28:29 +1200461static struct mv_ddr_topology_map board_topology_map_2g = {
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_8GBIT, /* 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 +1200484struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
Marek Behún09e16b82017-06-09 19:28:45 +0200485{
Marek Behún77652c72019-05-02 16:53:33 +0200486 if (omnia_get_ram_size_gb() == 2)
Marek Behún09e16b82017-06-09 19:28:45 +0200487 return &board_topology_map_2g;
Marek Behún77652c72019-05-02 16:53:33 +0200488 else
489 return &board_topology_map_1g;
Marek Behún09e16b82017-06-09 19:28:45 +0200490}
491
Marek Behún09e16b82017-06-09 19:28:45 +0200492static int set_regdomain(void)
493{
494 struct omnia_eeprom oep;
495 char rd[3] = {' ', ' ', 0};
496
497 if (omnia_read_eeprom(&oep))
498 memcpy(rd, &oep.region, 2);
499 else
500 puts("EEPROM regdomain read failed.\n");
501
502 printf("Regdomain set to %s\n", rd);
Simon Glass6a38e412017-08-03 12:22:09 -0600503 return env_set("regdomain", rd);
Marek Behún09e16b82017-06-09 19:28:45 +0200504}
Marek Behún0f2e66a2019-05-02 16:53:37 +0200505
Marek Behún0f2e66a2019-05-02 16:53:37 +0200506static void handle_reset_button(void)
507{
Pali Rohár905c3bf2021-06-14 16:45:58 +0200508 const char * const vars[1] = { "bootcmd_rescue", };
Marek Behún0f2e66a2019-05-02 16:53:37 +0200509 int ret;
510 u8 reset_status;
511
Pali Rohár905c3bf2021-06-14 16:45:58 +0200512 /*
513 * Ensure that bootcmd_rescue has always stock value, so that running
514 * run bootcmd_rescue
515 * always works correctly.
516 */
517 env_set_default_vars(1, (char * const *)vars, 0);
518
Marek Behún0f2e66a2019-05-02 16:53:37 +0200519 ret = omnia_mcu_read(CMD_GET_RESET, &reset_status, 1);
520 if (ret) {
521 printf("omnia_mcu_read failed: %i, reset status unknown!\n",
522 ret);
523 return;
524 }
525
526 env_set_ulong("omnia_reset", reset_status);
527
528 if (reset_status) {
Pali Rohár905c3bf2021-06-14 16:45:58 +0200529 const char * const vars[2] = {
Marek Behún09f8de22021-05-28 10:00:49 +0200530 "bootcmd",
Marek Behún09f8de22021-05-28 10:00:49 +0200531 "distro_bootcmd",
532 };
533
534 /*
535 * Set the above envs to their default values, in case the user
536 * managed to break them.
537 */
Pali Rohár905c3bf2021-06-14 16:45:58 +0200538 env_set_default_vars(2, (char * const *)vars, 0);
Marek Behún09f8de22021-05-28 10:00:49 +0200539
540 /* Ensure bootcmd_rescue is used by distroboot */
541 env_set("boot_targets", "rescue");
542
Pali Rohár4f9e6fb2022-04-06 11:39:32 +0200543 printf("RESET button was pressed, overwriting boot_targets!\n");
Marek Behún09f8de22021-05-28 10:00:49 +0200544 } else {
545 /*
546 * In case the user somehow managed to save environment with
547 * boot_targets=rescue, reset boot_targets to default value.
548 * This could happen in subsequent commands if bootcmd_rescue
549 * failed.
550 */
551 if (!strcmp(env_get("boot_targets"), "rescue")) {
552 const char * const vars[1] = {
553 "boot_targets",
554 };
555
556 env_set_default_vars(1, (char * const *)vars, 0);
557 }
Marek Behún0f2e66a2019-05-02 16:53:37 +0200558 }
559}
Marek Behún09e16b82017-06-09 19:28:45 +0200560
Pali Rohár1e0a9752022-07-29 13:29:07 +0200561static void initialize_switch(void)
562{
563 u32 val, val04, val08, val10, val14;
564 u16 ctrl[2];
565 int err;
566
567 printf("Initializing LAN eth switch... ");
568
569 /* Change RGMII pins to GPIO mode */
570
571 val = val04 = readl(MVEBU_MPP_BASE + 0x04);
572 val &= ~GENMASK(19, 16); /* MPP[12] := GPIO */
573 val &= ~GENMASK(23, 20); /* MPP[13] := GPIO */
574 val &= ~GENMASK(27, 24); /* MPP[14] := GPIO */
575 val &= ~GENMASK(31, 28); /* MPP[15] := GPIO */
576 writel(val, MVEBU_MPP_BASE + 0x04);
577
578 val = val08 = readl(MVEBU_MPP_BASE + 0x08);
579 val &= ~GENMASK(3, 0); /* MPP[16] := GPIO */
580 val &= ~GENMASK(23, 20); /* MPP[21] := GPIO */
581 writel(val, MVEBU_MPP_BASE + 0x08);
582
583 val = val10 = readl(MVEBU_MPP_BASE + 0x10);
584 val &= ~GENMASK(27, 24); /* MPP[38] := GPIO */
585 val &= ~GENMASK(31, 28); /* MPP[39] := GPIO */
586 writel(val, MVEBU_MPP_BASE + 0x10);
587
588 val = val14 = readl(MVEBU_MPP_BASE + 0x14);
589 val &= ~GENMASK(3, 0); /* MPP[40] := GPIO */
590 val &= ~GENMASK(7, 4); /* MPP[41] := GPIO */
591 writel(val, MVEBU_MPP_BASE + 0x14);
592
593 /* Set initial values for switch reset strapping pins */
594
595 val = readl(MVEBU_GPIO0_BASE + 0x00);
596 val |= BIT(12); /* GPIO[12] := 1 */
597 val |= BIT(13); /* GPIO[13] := 1 */
598 val |= BIT(14); /* GPIO[14] := 1 */
599 val |= BIT(15); /* GPIO[15] := 1 */
600 val &= ~BIT(16); /* GPIO[16] := 0 */
601 val |= BIT(21); /* GPIO[21] := 1 */
602 writel(val, MVEBU_GPIO0_BASE + 0x00);
603
604 val = readl(MVEBU_GPIO1_BASE + 0x00);
605 val |= BIT(6); /* GPIO[38] := 1 */
606 val |= BIT(7); /* GPIO[39] := 1 */
607 val |= BIT(8); /* GPIO[40] := 1 */
608 val &= ~BIT(9); /* GPIO[41] := 0 */
609 writel(val, MVEBU_GPIO1_BASE + 0x00);
610
611 val = readl(MVEBU_GPIO0_BASE + 0x04);
612 val &= ~BIT(12); /* GPIO[12] := Out Enable */
613 val &= ~BIT(13); /* GPIO[13] := Out Enable */
614 val &= ~BIT(14); /* GPIO[14] := Out Enable */
615 val &= ~BIT(15); /* GPIO[15] := Out Enable */
616 val &= ~BIT(16); /* GPIO[16] := Out Enable */
617 val &= ~BIT(21); /* GPIO[21] := Out Enable */
618 writel(val, MVEBU_GPIO0_BASE + 0x04);
619
620 val = readl(MVEBU_GPIO1_BASE + 0x04);
621 val &= ~BIT(6); /* GPIO[38] := Out Enable */
622 val &= ~BIT(7); /* GPIO[39] := Out Enable */
623 val &= ~BIT(8); /* GPIO[40] := Out Enable */
624 val &= ~BIT(9); /* GPIO[41] := Out Enable */
625 writel(val, MVEBU_GPIO1_BASE + 0x04);
626
627 /* Release switch reset */
628
629 ctrl[0] = EXT_CTL_nRES_LAN;
630 ctrl[1] = EXT_CTL_nRES_LAN;
631 err = omnia_mcu_write(CMD_EXT_CONTROL, ctrl, sizeof(ctrl));
632
633 mdelay(10);
634
635 /* Change RGMII pins back to RGMII mode */
636
637 writel(val04, MVEBU_MPP_BASE + 0x04);
638 writel(val08, MVEBU_MPP_BASE + 0x08);
639 writel(val10, MVEBU_MPP_BASE + 0x10);
640 writel(val14, MVEBU_MPP_BASE + 0x14);
641
642 puts(err ? "failed\n" : "done\n");
643}
644
Marek Behún09e16b82017-06-09 19:28:45 +0200645int board_early_init_f(void)
646{
Marek Behún09e16b82017-06-09 19:28:45 +0200647 /* Configure MPP */
648 writel(0x11111111, MVEBU_MPP_BASE + 0x00);
649 writel(0x11111111, MVEBU_MPP_BASE + 0x04);
650 writel(0x11244011, MVEBU_MPP_BASE + 0x08);
651 writel(0x22222111, MVEBU_MPP_BASE + 0x0c);
652 writel(0x22200002, MVEBU_MPP_BASE + 0x10);
653 writel(0x30042022, MVEBU_MPP_BASE + 0x14);
654 writel(0x55550555, MVEBU_MPP_BASE + 0x18);
655 writel(0x00005550, MVEBU_MPP_BASE + 0x1c);
656
657 /* Set GPP Out value */
658 writel(OMNIA_GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00);
659 writel(OMNIA_GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00);
660
661 /* Set GPP Polarity */
662 writel(OMNIA_GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c);
663 writel(OMNIA_GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c);
664
665 /* Set GPP Out Enable */
666 writel(OMNIA_GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04);
667 writel(OMNIA_GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04);
668
Marek Behún09e16b82017-06-09 19:28:45 +0200669 return 0;
670}
671
Marek Behúnf3556162021-08-16 15:19:39 +0200672void spl_board_init(void)
673{
Pali Rohár1e0a9752022-07-29 13:29:07 +0200674 u16 val;
675 int ret;
676
Marek Behúnf3556162021-08-16 15:19:39 +0200677 /*
678 * If booting from UART, disable MCU watchdog in SPL, since uploading
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100679 * U-Boot proper can take too much time and trigger it. Instead enable
680 * A385 watchdog with very high timeout (10 minutes) to prevent hangup.
Marek Behúnf3556162021-08-16 15:19:39 +0200681 */
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100682 if (get_boot_device() == BOOT_DEVICE_UART) {
683 enable_a385_watchdog(10);
Marek Behúnf3556162021-08-16 15:19:39 +0200684 disable_mcu_watchdog();
Pali Rohár7fcda0c2021-11-09 17:14:02 +0100685 }
Pali Rohár1e0a9752022-07-29 13:29:07 +0200686
687 /*
688 * When MCU controls peripheral resets then release LAN eth switch from
689 * the reset and initialize it. When MCU does not control peripheral
690 * resets then LAN eth switch is initialized automatically by bootstrap
691 * pins when A385 is released from the reset.
692 */
693 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &val, sizeof(val));
694 if (ret == 0 && (val & STS_FEATURES_SUPPORTED)) {
695 ret = omnia_mcu_read(CMD_GET_FEATURES, &val, sizeof(val));
696 if (ret == 0 && (val & FEAT_PERIPH_MCU))
697 initialize_switch();
698 }
Marek Behúnf3556162021-08-16 15:19:39 +0200699}
700
Pali Rohárcbda3e22022-01-10 11:47:18 +0100701#if IS_ENABLED(CONFIG_OF_BOARD_FIXUP) || IS_ENABLED(CONFIG_OF_BOARD_SETUP)
702
Pali Rohár7cd41732022-03-02 12:47:56 +0100703static void disable_sata_node(void *blob)
Pali Rohárcbda3e22022-01-10 11:47:18 +0100704{
Pali Rohárcbda3e22022-01-10 11:47:18 +0100705 int node;
706
Pali Rohár7cd41732022-03-02 12:47:56 +0100707 fdt_for_each_node_by_compatible(node, blob, -1, "marvell,armada-380-ahci") {
708 if (!fdtdec_get_is_enabled(blob, node))
709 continue;
710
711 if (fdt_status_disabled(blob, node) < 0)
712 printf("Cannot disable SATA DT node!\n");
713 else
714 debug("Disabled SATA DT node\n");
715
Pali Roháre9105262022-03-02 12:47:57 +0100716 return;
Pali Rohár7cd41732022-03-02 12:47:56 +0100717 }
Pali Roháre9105262022-03-02 12:47:57 +0100718
719 printf("Cannot find SATA DT node!\n");
Pali Rohár7cd41732022-03-02 12:47:56 +0100720}
721
722static void disable_pcie_node(void *blob, int port)
723{
724 int node;
725
726 fdt_for_each_node_by_compatible(node, blob, -1, "marvell,armada-370-pcie") {
727 int port_node;
728
729 if (!fdtdec_get_is_enabled(blob, node))
730 continue;
731
732 fdt_for_each_subnode (port_node, blob, node) {
733 if (!fdtdec_get_is_enabled(blob, port_node))
734 continue;
735
736 if (fdtdec_get_int(blob, port_node, "marvell,pcie-port", -1) != port)
737 continue;
738
739 if (fdt_status_disabled(blob, port_node) < 0)
740 printf("Cannot disable PCIe port %d DT node!\n", port);
741 else
742 debug("Disabled PCIe port %d DT node\n", port);
743
744 return;
745 }
746 }
Pali Roháre9105262022-03-02 12:47:57 +0100747
748 printf("Cannot find PCIe port %d DT node!\n", port);
Pali Rohár7cd41732022-03-02 12:47:56 +0100749}
750
751static void fixup_msata_port_nodes(void *blob)
752{
753 bool mode_sata;
754
Pali Rohárcbda3e22022-01-10 11:47:18 +0100755 /*
756 * Determine if SerDes 0 is configured to SATA mode.
757 * We do this instead of calling omnia_detect_sata() to avoid another
758 * call to the MCU. By this time the common PHYs are initialized (it is
759 * done in SPL), so we can read this common PHY register.
760 */
761 mode_sata = (readl(MVEBU_REGISTER(0x183fc)) & GENMASK(3, 0)) == 2;
762
763 /*
764 * We're either adding status = "disabled" property, or changing
765 * status = "okay" to status = "disabled". In both cases we'll need more
766 * space. Increase the size a little.
767 */
768 if (fdt_increase_size(blob, 32) < 0) {
769 printf("Cannot increase FDT size!\n");
770 return;
771 }
772
Pali Rohárcbda3e22022-01-10 11:47:18 +0100773 if (!mode_sata) {
Pali Rohár7cd41732022-03-02 12:47:56 +0100774 /* If mSATA card is not present, disable SATA DT node */
775 disable_sata_node(blob);
776 } else {
777 /* Otherwise disable PCIe port 0 DT node (MiniPCIe / mSATA port) */
778 disable_pcie_node(blob, 0);
Pali Rohárcbda3e22022-01-10 11:47:18 +0100779 }
Pali Rohár93a89c52022-03-02 12:47:58 +0100780}
781
782static void fixup_wwan_port_nodes(void *blob)
783{
784 bool mode_usb3;
785
786 /* Determine if SerDes 4 is configured to USB3 mode */
787 mode_usb3 = ((readl(MVEBU_REGISTER(0x183fc)) & GENMASK(19, 16)) >> 16) == 4;
788
789 /* If SerDes 4 is not configured to USB3 mode then nothing is needed to fixup */
790 if (!mode_usb3)
791 return;
792
793 /*
794 * We're either adding status = "disabled" property, or changing
795 * status = "okay" to status = "disabled". In both cases we'll need more
796 * space. Increase the size a little.
797 */
798 if (fdt_increase_size(blob, 32) < 0) {
799 printf("Cannot increase FDT size!\n");
800 return;
801 }
802
803 /* Disable PCIe port 2 DT node (WWAN) */
804 disable_pcie_node(blob, 2);
Pali Rohárcbda3e22022-01-10 11:47:18 +0100805}
806
Pali Rohár1e0a9752022-07-29 13:29:07 +0200807static int insert_mcu_gpio_prop(void *blob, int node, const char *prop,
808 unsigned int phandle, u32 bank, u32 gpio,
809 u32 flags)
810{
811 fdt32_t val[4] = { cpu_to_fdt32(phandle), cpu_to_fdt32(bank),
812 cpu_to_fdt32(gpio), cpu_to_fdt32(flags) };
813 return fdt_setprop(blob, node, prop, &val, sizeof(val));
814}
815
816static int fixup_mcu_gpio_in_pcie_nodes(void *blob)
817{
818 unsigned int mcu_phandle;
819 int port, gpio;
820 int pcie_node;
821 int port_node;
822 int ret;
823
824 ret = fdt_increase_size(blob, 128);
825 if (ret < 0) {
826 printf("Cannot increase FDT size!\n");
827 return ret;
828 }
829
830 mcu_phandle = fdt_create_phandle_by_compatible(blob, "cznic,turris-omnia-mcu");
831 if (!mcu_phandle)
832 return -FDT_ERR_NOPHANDLES;
833
834 fdt_for_each_node_by_compatible(pcie_node, blob, -1, "marvell,armada-370-pcie") {
835 if (!fdtdec_get_is_enabled(blob, pcie_node))
836 continue;
837
838 fdt_for_each_subnode(port_node, blob, pcie_node) {
839 if (!fdtdec_get_is_enabled(blob, port_node))
840 continue;
841
842 port = fdtdec_get_int(blob, port_node, "marvell,pcie-port", -1);
843
844 if (port == 0)
845 gpio = ilog2(EXT_CTL_nPERST0);
846 else if (port == 1)
847 gpio = ilog2(EXT_CTL_nPERST1);
848 else if (port == 2)
849 gpio = ilog2(EXT_CTL_nPERST2);
850 else
851 continue;
852
853 /* insert: reset-gpios = <&mcu 2 gpio GPIO_ACTIVE_LOW>; */
854 ret = insert_mcu_gpio_prop(blob, port_node, "reset-gpios",
855 mcu_phandle, 2, gpio, GPIO_ACTIVE_LOW);
856 if (ret < 0)
857 return ret;
858 }
859 }
860
861 return 0;
862}
863
864static int fixup_mcu_gpio_in_eth_wan_node(void *blob)
865{
866 unsigned int mcu_phandle;
867 int eth_wan_node;
868 int ret;
869
870 ret = fdt_increase_size(blob, 64);
871 if (ret < 0) {
872 printf("Cannot increase FDT size!\n");
873 return ret;
874 }
875
876 eth_wan_node = fdt_path_offset(blob, "ethernet2");
877 if (eth_wan_node < 0)
878 return eth_wan_node;
879
880 mcu_phandle = fdt_create_phandle_by_compatible(blob, "cznic,turris-omnia-mcu");
881 if (!mcu_phandle)
882 return -FDT_ERR_NOPHANDLES;
883
884 /* insert: phy-reset-gpios = <&mcu 2 gpio GPIO_ACTIVE_LOW>; */
885 ret = insert_mcu_gpio_prop(blob, eth_wan_node, "phy-reset-gpios",
886 mcu_phandle, 2, ilog2(EXT_CTL_nRES_PHY), GPIO_ACTIVE_LOW);
887 if (ret < 0)
888 return ret;
889
890 return 0;
891}
892
Pali Rohárcbda3e22022-01-10 11:47:18 +0100893#endif
894
895#if IS_ENABLED(CONFIG_OF_BOARD_FIXUP)
896int board_fix_fdt(void *blob)
897{
Pali Rohár1e0a9752022-07-29 13:29:07 +0200898 u16 val;
899 int ret;
900
901 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &val, sizeof(val));
902 if (ret == 0 && (val & STS_FEATURES_SUPPORTED)) {
903 ret = omnia_mcu_read(CMD_GET_FEATURES, &val, sizeof(val));
904 if (ret == 0 && (val & FEAT_PERIPH_MCU)) {
905 fixup_mcu_gpio_in_pcie_nodes(blob);
906 fixup_mcu_gpio_in_eth_wan_node(blob);
907 }
908 }
909
Pali Rohár7cd41732022-03-02 12:47:56 +0100910 fixup_msata_port_nodes(blob);
Pali Rohár93a89c52022-03-02 12:47:58 +0100911 fixup_wwan_port_nodes(blob);
Pali Rohárcbda3e22022-01-10 11:47:18 +0100912
913 return 0;
914}
915#endif
916
Marek Behún09e16b82017-06-09 19:28:45 +0200917int board_init(void)
918{
Marek Behún4dfc57e2019-05-02 16:53:31 +0200919 /* address of boot parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200920 gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
921
Marek Behún88dc0242021-08-16 15:19:40 +0200922 return 0;
923}
924
925int board_late_init(void)
926{
Marek Behúnf3556162021-08-16 15:19:39 +0200927 /*
928 * If not booting from UART, MCU watchdog was not disabled in SPL,
929 * disable it now.
930 */
931 if (get_boot_device() != BOOT_DEVICE_UART)
932 disable_mcu_watchdog();
Marek Behún09e16b82017-06-09 19:28:45 +0200933
Marek Behún09e16b82017-06-09 19:28:45 +0200934 set_regdomain();
Marek Behún0f2e66a2019-05-02 16:53:37 +0200935 handle_reset_button();
Marek Behúndb1e5c62019-05-24 14:57:53 +0200936 pci_init();
Marek Behún09e16b82017-06-09 19:28:45 +0200937
938 return 0;
939}
940
Marek Behúnab9447f2021-10-09 19:33:44 +0200941int show_board_info(void)
Marek Behún09e16b82017-06-09 19:28:45 +0200942{
943 u32 version_num, serial_num;
Pali Rohár0387f7f2022-04-08 16:30:12 +0200944 int err;
Marek Behún09e16b82017-06-09 19:28:45 +0200945
Pali Rohár0387f7f2022-04-08 16:30:12 +0200946 err = turris_atsha_otp_get_serial_number(&version_num, &serial_num);
Marek Behúnab9447f2021-10-09 19:33:44 +0200947 printf("Model: Turris Omnia\n");
Pali Rohár4798ba92022-07-29 13:29:06 +0200948 printf(" MCU type: %s\n", omnia_get_mcu_type());
Marek Behúnc4ba72a2019-05-02 16:53:34 +0200949 printf(" RAM size: %i MiB\n", omnia_get_ram_size_gb() * 1024);
Marek Behún09e16b82017-06-09 19:28:45 +0200950 if (err)
Marek Behúnc4ba72a2019-05-02 16:53:34 +0200951 printf(" Serial Number: unknown\n");
Marek Behún09e16b82017-06-09 19:28:45 +0200952 else
Marek Behúnc4ba72a2019-05-02 16:53:34 +0200953 printf(" Serial Number: %08X%08X\n", be32_to_cpu(version_num),
954 be32_to_cpu(serial_num));
Marek Behún09e16b82017-06-09 19:28:45 +0200955
956 return 0;
957}
958
Marek Behún09e16b82017-06-09 19:28:45 +0200959int misc_init_r(void)
960{
Pali Rohár60f37e82022-04-08 16:30:14 +0200961 turris_atsha_otp_init_mac_addresses(1);
Marek Behún09e16b82017-06-09 19:28:45 +0200962 return 0;
963}
964
Marek Behún91ef59c2021-07-15 19:21:02 +0200965#if defined(CONFIG_OF_BOARD_SETUP)
966/*
967 * I plan to generalize this function and move it to common/fdt_support.c.
968 * This will require some more work on multiple boards, though, so for now leave
969 * it here.
970 */
971static bool fixup_mtd_partitions(void *blob, int offset, struct mtd_info *mtd)
972{
973 struct mtd_info *slave;
974 int parts;
975
976 parts = fdt_subnode_offset(blob, offset, "partitions");
Pali Roháre2b1ba02022-08-01 12:02:19 +0200977 if (parts >= 0) {
978 if (fdt_del_node(blob, parts) < 0)
979 return false;
980 }
Marek Behún91ef59c2021-07-15 19:21:02 +0200981
Pali Rohárd35b6f22022-08-01 12:02:20 +0200982 if (fdt_increase_size(blob, 512) < 0)
983 return false;
984
Marek Behún91ef59c2021-07-15 19:21:02 +0200985 parts = fdt_add_subnode(blob, offset, "partitions");
986 if (parts < 0)
987 return false;
988
989 if (fdt_setprop_u32(blob, parts, "#address-cells", 1) < 0)
990 return false;
991
992 if (fdt_setprop_u32(blob, parts, "#size-cells", 1) < 0)
993 return false;
994
995 if (fdt_setprop_string(blob, parts, "compatible",
996 "fixed-partitions") < 0)
997 return false;
998
999 mtd_probe_devices();
1000
Pali Rohárd8210ef2021-10-21 17:55:48 +02001001 list_for_each_entry_reverse(slave, &mtd->partitions, node) {
Marek Behún91ef59c2021-07-15 19:21:02 +02001002 char name[32];
1003 int part;
1004
1005 snprintf(name, sizeof(name), "partition@%llx", slave->offset);
1006 part = fdt_add_subnode(blob, parts, name);
1007 if (part < 0)
1008 return false;
1009
1010 if (fdt_setprop_u32(blob, part, "reg", slave->offset) < 0)
1011 return false;
1012
1013 if (fdt_appendprop_u32(blob, part, "reg", slave->size) < 0)
1014 return false;
1015
1016 if (fdt_setprop_string(blob, part, "label", slave->name) < 0)
1017 return false;
1018
1019 if (!(slave->flags & MTD_WRITEABLE))
1020 if (fdt_setprop_empty(blob, part, "read-only") < 0)
1021 return false;
1022
1023 if (slave->flags & MTD_POWERUP_LOCK)
1024 if (fdt_setprop_empty(blob, part, "lock") < 0)
1025 return false;
1026 }
1027
1028 return true;
1029}
1030
Pali Rohárcbda3e22022-01-10 11:47:18 +01001031static void fixup_spi_nor_partitions(void *blob)
Marek Behún91ef59c2021-07-15 19:21:02 +02001032{
1033 struct mtd_info *mtd;
1034 int node;
1035
1036 mtd = get_mtd_device_nm(OMNIA_SPI_NOR_PATH);
1037 if (IS_ERR_OR_NULL(mtd))
1038 goto fail;
1039
1040 node = fdt_path_offset(blob, OMNIA_SPI_NOR_PATH);
1041 if (node < 0)
1042 goto fail;
1043
1044 if (!fixup_mtd_partitions(blob, node, mtd))
1045 goto fail;
1046
Marek Behún36feac92021-09-25 02:49:18 +02001047 put_mtd_device(mtd);
Pali Rohárcbda3e22022-01-10 11:47:18 +01001048 return;
Marek Behún91ef59c2021-07-15 19:21:02 +02001049
1050fail:
1051 printf("Failed fixing SPI NOR partitions!\n");
Marek Behún36feac92021-09-25 02:49:18 +02001052 if (!IS_ERR_OR_NULL(mtd))
1053 put_mtd_device(mtd);
Pali Rohárcbda3e22022-01-10 11:47:18 +01001054}
1055
1056int ft_board_setup(void *blob, struct bd_info *bd)
1057{
Pali Rohár1e0a9752022-07-29 13:29:07 +02001058 int node;
1059
1060 /*
1061 * U-Boot's FDT blob contains phy-reset-gpios in ethernet2
1062 * node when MCU controls all peripherals resets.
1063 * Fixup MCU GPIO nodes in PCIe and eth wan nodes in this case.
1064 */
1065 node = fdt_path_offset(gd->fdt_blob, "ethernet2");
1066 if (node >= 0 && fdt_getprop(gd->fdt_blob, node, "phy-reset-gpios", NULL)) {
1067 fixup_mcu_gpio_in_pcie_nodes(blob);
1068 fixup_mcu_gpio_in_eth_wan_node(blob);
1069 }
1070
Pali Rohárcbda3e22022-01-10 11:47:18 +01001071 fixup_spi_nor_partitions(blob);
Pali Rohár7cd41732022-03-02 12:47:56 +01001072 fixup_msata_port_nodes(blob);
Pali Rohár93a89c52022-03-02 12:47:58 +01001073 fixup_wwan_port_nodes(blob);
Pali Rohárcbda3e22022-01-10 11:47:18 +01001074
Marek Behún91ef59c2021-07-15 19:21:02 +02001075 return 0;
1076}
1077#endif