blob: 8571541b0af67e47c709319ab2031dc1395d133a [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/*
3 * Copyright (C) 2017 Marek Behun <marek.behun@nic.cz>
4 * 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>
Alex Kiernan9c215492018-04-01 09:22:38 +000011#include <environment.h>
Marek Behún09e16b82017-06-09 19:28:45 +020012#include <i2c.h>
13#include <miiphy.h>
14#include <netdev.h>
15#include <asm/io.h>
16#include <asm/arch/cpu.h>
17#include <asm/arch/soc.h>
18#include <dm/uclass.h>
19#include <fdt_support.h>
20#include <time.h>
Marek Behún09e16b82017-06-09 19:28:45 +020021# include <atsha204a-i2c.h>
Marek Behún09e16b82017-06-09 19:28:45 +020022
23#ifdef CONFIG_WDT_ORION
24# include <wdt.h>
25#endif
26
Chris Packham1a07d212018-05-10 13:28:29 +120027#include "../drivers/ddr/marvell/a38x/ddr3_init.h"
Marek Behún09e16b82017-06-09 19:28:45 +020028#include <../serdes/a38x/high_speed_env_spec.h>
29
30DECLARE_GLOBAL_DATA_PTR;
31
Marek Behúnba53b6b2019-05-02 16:53:30 +020032#define OMNIA_I2C_BUS_NAME "i2c@11000->i2cmux@70->i2c@0"
33
34#define OMNIA_I2C_MCU_CHIP_ADDR 0x2a
35#define OMNIA_I2C_MCU_CHIP_LEN 1
36
37#define OMNIA_I2C_EEPROM_CHIP_ADDR 0x54
38#define OMNIA_I2C_EEPROM_CHIP_LEN 2
Marek Behún09e16b82017-06-09 19:28:45 +020039#define OMNIA_I2C_EEPROM_MAGIC 0x0341a034
40
Marek Behúnba53b6b2019-05-02 16:53:30 +020041enum mcu_commands {
42 CMD_GET_STATUS_WORD = 0x01,
43 CMD_GET_RESET = 0x09,
44 CMD_WATCHDOG_STATE = 0x0b,
45};
46
47enum status_word_bits {
48 CARD_DET_STSBIT = 0x0010,
49 MSATA_IND_STSBIT = 0x0020,
50};
Marek Behún09e16b82017-06-09 19:28:45 +020051
52#define OMNIA_ATSHA204_OTP_VERSION 0
53#define OMNIA_ATSHA204_OTP_SERIAL 1
54#define OMNIA_ATSHA204_OTP_MAC0 3
55#define OMNIA_ATSHA204_OTP_MAC1 4
56
Marek Behún09e16b82017-06-09 19:28:45 +020057/*
58 * Those values and defines are taken from the Marvell U-Boot version
59 * "u-boot-2013.01-2014_T3.0"
60 */
61#define OMNIA_GPP_OUT_ENA_LOW \
62 (~(BIT(1) | BIT(4) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | \
63 BIT(10) | BIT(11) | BIT(19) | BIT(22) | BIT(23) | BIT(25) | \
64 BIT(26) | BIT(27) | BIT(29) | BIT(30) | BIT(31)))
65#define OMNIA_GPP_OUT_ENA_MID \
66 (~(BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(15) | \
67 BIT(16) | BIT(17) | BIT(18)))
68
69#define OMNIA_GPP_OUT_VAL_LOW 0x0
70#define OMNIA_GPP_OUT_VAL_MID 0x0
71#define OMNIA_GPP_POL_LOW 0x0
72#define OMNIA_GPP_POL_MID 0x0
73
74static struct serdes_map board_serdes_map_pex[] = {
75 {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
76 {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
77 {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
78 {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
79 {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
80 {SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}
81};
82
83static struct serdes_map board_serdes_map_sata[] = {
84 {SATA0, SERDES_SPEED_6_GBPS, SERDES_DEFAULT_MODE, 0, 0},
85 {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
86 {PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
87 {USB3_HOST1, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
88 {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
89 {SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}
90};
91
Marek Behúnba53b6b2019-05-02 16:53:30 +020092static struct udevice *omnia_get_i2c_chip(const char *name, uint addr,
93 uint offset_len)
Marek Behún09e16b82017-06-09 19:28:45 +020094{
95 struct udevice *bus, *dev;
Marek Behúnba53b6b2019-05-02 16:53:30 +020096 int ret;
Marek Behún09e16b82017-06-09 19:28:45 +020097
Marek Behúnba53b6b2019-05-02 16:53:30 +020098 ret = uclass_get_device_by_name(UCLASS_I2C, OMNIA_I2C_BUS_NAME, &bus);
99 if (ret) {
100 printf("Cannot get I2C bus %s: uclass_get_device_by_name failed: %i\n",
101 OMNIA_I2C_BUS_NAME, ret);
102 return NULL;
Marek Behún09e16b82017-06-09 19:28:45 +0200103 }
104
Marek Behúnba53b6b2019-05-02 16:53:30 +0200105 ret = i2c_get_chip(bus, addr, offset_len, &dev);
Marek Behún09e16b82017-06-09 19:28:45 +0200106 if (ret) {
Marek Behúnba53b6b2019-05-02 16:53:30 +0200107 printf("Cannot get %s I2C chip: i2c_get_chip failed: %i\n",
108 name, ret);
109 return NULL;
Marek Behún09e16b82017-06-09 19:28:45 +0200110 }
111
Marek Behúnba53b6b2019-05-02 16:53:30 +0200112 return dev;
113}
Marek Behúnd0b374d2017-08-04 15:28:25 +0200114
Marek Behúnba53b6b2019-05-02 16:53:30 +0200115static int omnia_mcu_read(u8 cmd, void *buf, int len)
116{
117 struct udevice *chip;
118
119 chip = omnia_get_i2c_chip("MCU", OMNIA_I2C_MCU_CHIP_ADDR,
120 OMNIA_I2C_MCU_CHIP_LEN);
121 if (!chip)
122 return -ENODEV;
123
124 return dm_i2c_read(chip, cmd, buf, len);
125}
126
127#ifndef CONFIG_SPL_BUILD
128static int omnia_mcu_write(u8 cmd, const void *buf, int len)
129{
130 struct udevice *chip;
131
132 chip = omnia_get_i2c_chip("MCU", OMNIA_I2C_MCU_CHIP_ADDR,
133 OMNIA_I2C_MCU_CHIP_LEN);
134 if (!chip)
135 return -ENODEV;
136
137 return dm_i2c_write(chip, cmd, buf, len);
138}
139
140static bool disable_mcu_watchdog(void)
141{
142 int ret;
143
144 puts("Disabling MCU watchdog... ");
145
146 ret = omnia_mcu_write(CMD_WATCHDOG_STATE, "\x00", 1);
147 if (ret) {
148 printf("omnia_mcu_write failed: %i\n", ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200149 return false;
150 }
151
Marek Behúnba53b6b2019-05-02 16:53:30 +0200152 puts("disabled\n");
153
154 return true;
155}
156#endif
157
158static bool omnia_detect_sata(void)
159{
160 int ret;
161 u16 stsword;
162
163 puts("MiniPCIe/mSATA card detection... ");
164
165 ret = omnia_mcu_read(CMD_GET_STATUS_WORD, &stsword, sizeof(stsword));
166 if (ret) {
167 printf("omnia_mcu_read failed: %i, defaulting to MiniPCIe card\n",
168 ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200169 return false;
170 }
171
Marek Behúnba53b6b2019-05-02 16:53:30 +0200172 if (!(stsword & CARD_DET_STSBIT)) {
173 puts("none\n");
Marek Behún09e16b82017-06-09 19:28:45 +0200174 return false;
175 }
Marek Behúnba53b6b2019-05-02 16:53:30 +0200176
177 if (stsword & MSATA_IND_STSBIT)
178 puts("mSATA\n");
179 else
180 puts("MiniPCIe\n");
181
182 return stsword & MSATA_IND_STSBIT ? true : false;
Marek Behún09e16b82017-06-09 19:28:45 +0200183}
184
185int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count)
186{
187 if (omnia_detect_sata()) {
188 *serdes_map_array = board_serdes_map_sata;
189 *count = ARRAY_SIZE(board_serdes_map_sata);
190 } else {
191 *serdes_map_array = board_serdes_map_pex;
192 *count = ARRAY_SIZE(board_serdes_map_pex);
193 }
194
195 return 0;
196}
197
198struct omnia_eeprom {
199 u32 magic;
200 u32 ramsize;
201 char region[4];
202 u32 crc;
203};
204
205static bool omnia_read_eeprom(struct omnia_eeprom *oep)
206{
Marek Behúnba53b6b2019-05-02 16:53:30 +0200207 struct udevice *chip;
208 u32 crc;
209 int ret;
Marek Behún09e16b82017-06-09 19:28:45 +0200210
Marek Behúnba53b6b2019-05-02 16:53:30 +0200211 chip = omnia_get_i2c_chip("EEPROM", OMNIA_I2C_EEPROM_CHIP_ADDR,
212 OMNIA_I2C_EEPROM_CHIP_LEN);
213
214 if (!chip)
Marek Behún09e16b82017-06-09 19:28:45 +0200215 return false;
Marek Behún09e16b82017-06-09 19:28:45 +0200216
Marek Behúnba53b6b2019-05-02 16:53:30 +0200217 ret = dm_i2c_read(chip, 0, (void *)oep, sizeof(*oep));
Marek Behún09e16b82017-06-09 19:28:45 +0200218 if (ret) {
Marek Behúnba53b6b2019-05-02 16:53:30 +0200219 printf("dm_i2c_read failed: %i, cannot read EEPROM\n", ret);
Marek Behún09e16b82017-06-09 19:28:45 +0200220 return false;
221 }
222
Marek Behúnba53b6b2019-05-02 16:53:30 +0200223 if (oep->magic != OMNIA_I2C_EEPROM_MAGIC) {
224 printf("bad EEPROM magic number (%08x, should be %08x)\n",
225 oep->magic, OMNIA_I2C_EEPROM_MAGIC);
226 return false;
Marek Behún09e16b82017-06-09 19:28:45 +0200227 }
228
Marek Behúnba53b6b2019-05-02 16:53:30 +0200229 crc = crc32(0, (void *)oep, sizeof(*oep) - 4);
230 if (crc != oep->crc) {
231 printf("bad EEPROM CRC (stored %08x, computed %08x)\n",
232 oep->crc, crc);
Marek Behún09e16b82017-06-09 19:28:45 +0200233 return false;
234 }
235
236 return true;
237}
238
Marek Behún77652c72019-05-02 16:53:33 +0200239static int omnia_get_ram_size_gb(void)
240{
241 static int ram_size;
242 struct omnia_eeprom oep;
243
244 if (!ram_size) {
245 /* Get the board config from EEPROM */
246 if (omnia_read_eeprom(&oep)) {
247 debug("Memory config in EEPROM: 0x%02x\n", oep.ramsize);
248
249 if (oep.ramsize == 0x2)
250 ram_size = 2;
251 else
252 ram_size = 1;
253 } else {
254 /* Hardcoded fallback */
255 puts("Memory config from EEPROM read failed!\n");
256 puts("Falling back to default 1 GiB!\n");
257 ram_size = 1;
258 }
259 }
260
261 return ram_size;
262}
263
Marek Behún09e16b82017-06-09 19:28:45 +0200264/*
265 * Define the DDR layout / topology here in the board file. This will
266 * be used by the DDR3 init code in the SPL U-Boot version to configure
267 * the DDR3 controller.
268 */
Chris Packham1a07d212018-05-10 13:28:29 +1200269static struct mv_ddr_topology_map board_topology_map_1g = {
270 DEBUG_LEVEL_ERROR,
Marek Behún09e16b82017-06-09 19:28:45 +0200271 0x1, /* active interfaces */
272 /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */
273 { { { {0x1, 0, 0, 0},
274 {0x1, 0, 0, 0},
275 {0x1, 0, 0, 0},
276 {0x1, 0, 0, 0},
277 {0x1, 0, 0, 0} },
278 SPEED_BIN_DDR_1600K, /* speed_bin */
Chris Packham1a07d212018-05-10 13:28:29 +1200279 MV_DDR_DEV_WIDTH_16BIT, /* memory_width */
280 MV_DDR_DIE_CAP_4GBIT, /* mem_size */
Chris Packham4bf81db2018-12-03 14:26:49 +1300281 MV_DDR_FREQ_800, /* frequency */
Chris Packhamdd092bd2017-11-29 10:38:34 +1300282 0, 0, /* cas_wl cas_l */
Chris Packham3a09e132018-05-10 13:28:30 +1200283 MV_DDR_TEMP_NORMAL, /* temperature */
284 MV_DDR_TIM_2T} }, /* timing */
Chris Packham1a07d212018-05-10 13:28:29 +1200285 BUS_MASK_32BIT, /* Busses mask */
286 MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
287 { {0} }, /* raw spd data */
288 {0} /* timing parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200289};
290
Chris Packham1a07d212018-05-10 13:28:29 +1200291static struct mv_ddr_topology_map board_topology_map_2g = {
292 DEBUG_LEVEL_ERROR,
Marek Behún09e16b82017-06-09 19:28:45 +0200293 0x1, /* active interfaces */
294 /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */
295 { { { {0x1, 0, 0, 0},
296 {0x1, 0, 0, 0},
297 {0x1, 0, 0, 0},
298 {0x1, 0, 0, 0},
299 {0x1, 0, 0, 0} },
300 SPEED_BIN_DDR_1600K, /* speed_bin */
Chris Packham1a07d212018-05-10 13:28:29 +1200301 MV_DDR_DEV_WIDTH_16BIT, /* memory_width */
302 MV_DDR_DIE_CAP_8GBIT, /* mem_size */
Chris Packham4bf81db2018-12-03 14:26:49 +1300303 MV_DDR_FREQ_800, /* frequency */
Chris Packhamdd092bd2017-11-29 10:38:34 +1300304 0, 0, /* cas_wl cas_l */
Chris Packham3a09e132018-05-10 13:28:30 +1200305 MV_DDR_TEMP_NORMAL, /* temperature */
306 MV_DDR_TIM_2T} }, /* timing */
Chris Packham1a07d212018-05-10 13:28:29 +1200307 BUS_MASK_32BIT, /* Busses mask */
308 MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
309 { {0} }, /* raw spd data */
310 {0} /* timing parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200311};
312
Chris Packham1a07d212018-05-10 13:28:29 +1200313struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
Marek Behún09e16b82017-06-09 19:28:45 +0200314{
Marek Behún77652c72019-05-02 16:53:33 +0200315 if (omnia_get_ram_size_gb() == 2)
Marek Behún09e16b82017-06-09 19:28:45 +0200316 return &board_topology_map_2g;
Marek Behún77652c72019-05-02 16:53:33 +0200317 else
318 return &board_topology_map_1g;
Marek Behún09e16b82017-06-09 19:28:45 +0200319}
320
321#ifndef CONFIG_SPL_BUILD
322static int set_regdomain(void)
323{
324 struct omnia_eeprom oep;
325 char rd[3] = {' ', ' ', 0};
326
327 if (omnia_read_eeprom(&oep))
328 memcpy(rd, &oep.region, 2);
329 else
330 puts("EEPROM regdomain read failed.\n");
331
332 printf("Regdomain set to %s\n", rd);
Simon Glass6a38e412017-08-03 12:22:09 -0600333 return env_set("regdomain", rd);
Marek Behún09e16b82017-06-09 19:28:45 +0200334}
335#endif
336
337int board_early_init_f(void)
338{
Marek Behún09e16b82017-06-09 19:28:45 +0200339 /* Configure MPP */
340 writel(0x11111111, MVEBU_MPP_BASE + 0x00);
341 writel(0x11111111, MVEBU_MPP_BASE + 0x04);
342 writel(0x11244011, MVEBU_MPP_BASE + 0x08);
343 writel(0x22222111, MVEBU_MPP_BASE + 0x0c);
344 writel(0x22200002, MVEBU_MPP_BASE + 0x10);
345 writel(0x30042022, MVEBU_MPP_BASE + 0x14);
346 writel(0x55550555, MVEBU_MPP_BASE + 0x18);
347 writel(0x00005550, MVEBU_MPP_BASE + 0x1c);
348
349 /* Set GPP Out value */
350 writel(OMNIA_GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00);
351 writel(OMNIA_GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00);
352
353 /* Set GPP Polarity */
354 writel(OMNIA_GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c);
355 writel(OMNIA_GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c);
356
357 /* Set GPP Out Enable */
358 writel(OMNIA_GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04);
359 writel(OMNIA_GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04);
360
Marek Behún09e16b82017-06-09 19:28:45 +0200361 return 0;
362}
363
Marek Behún09e16b82017-06-09 19:28:45 +0200364int board_init(void)
365{
Marek Behún4dfc57e2019-05-02 16:53:31 +0200366 /* address of boot parameters */
Marek Behún09e16b82017-06-09 19:28:45 +0200367 gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
368
369#ifndef CONFIG_SPL_BUILD
Marek Behúnba53b6b2019-05-02 16:53:30 +0200370 disable_mcu_watchdog();
Marek Behún09e16b82017-06-09 19:28:45 +0200371 set_regdomain();
372#endif
373
374 return 0;
375}
Marek Behún09e16b82017-06-09 19:28:45 +0200376
377int board_late_init(void)
378{
379#ifndef CONFIG_SPL_BUILD
380 set_regdomain();
381#endif
382
383 return 0;
384}
385
Marek Behún09e16b82017-06-09 19:28:45 +0200386static struct udevice *get_atsha204a_dev(void)
387{
Marek Behún4dfc57e2019-05-02 16:53:31 +0200388 static struct udevice *dev;
Marek Behún09e16b82017-06-09 19:28:45 +0200389
Marek Behún4dfc57e2019-05-02 16:53:31 +0200390 if (dev)
Marek Behún09e16b82017-06-09 19:28:45 +0200391 return dev;
392
393 if (uclass_get_device_by_name(UCLASS_MISC, "atsha204a@64", &dev)) {
394 puts("Cannot find ATSHA204A on I2C bus!\n");
395 dev = NULL;
396 }
397
398 return dev;
399}
Marek Behún09e16b82017-06-09 19:28:45 +0200400
401int checkboard(void)
402{
403 u32 version_num, serial_num;
404 int err = 1;
405
Marek Behún09e16b82017-06-09 19:28:45 +0200406 struct udevice *dev = get_atsha204a_dev();
407
408 if (dev) {
409 err = atsha204a_wakeup(dev);
410 if (err)
411 goto out;
412
413 err = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
414 OMNIA_ATSHA204_OTP_VERSION,
Marek Behún4dfc57e2019-05-02 16:53:31 +0200415 (u8 *)&version_num);
Marek Behún09e16b82017-06-09 19:28:45 +0200416 if (err)
417 goto out;
418
419 err = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
420 OMNIA_ATSHA204_OTP_SERIAL,
Marek Behún4dfc57e2019-05-02 16:53:31 +0200421 (u8 *)&serial_num);
Marek Behún09e16b82017-06-09 19:28:45 +0200422 if (err)
423 goto out;
424
425 atsha204a_sleep(dev);
426 }
427
428out:
Marek Behún09e16b82017-06-09 19:28:45 +0200429 if (err)
430 printf("Board: Turris Omnia (ver N/A). SN: N/A\n");
431 else
432 printf("Board: Turris Omnia SNL %08X%08X\n",
433 be32_to_cpu(version_num), be32_to_cpu(serial_num));
434
435 return 0;
436}
437
438static void increment_mac(u8 *mac)
439{
440 int i;
441
442 for (i = 5; i >= 3; i--) {
443 mac[i] += 1;
444 if (mac[i])
445 break;
446 }
447}
448
449int misc_init_r(void)
450{
Marek Behún09e16b82017-06-09 19:28:45 +0200451 int err;
452 struct udevice *dev = get_atsha204a_dev();
453 u8 mac0[4], mac1[4], mac[6];
454
455 if (!dev)
456 goto out;
457
458 err = atsha204a_wakeup(dev);
459 if (err)
460 goto out;
461
462 err = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
463 OMNIA_ATSHA204_OTP_MAC0, mac0);
464 if (err)
465 goto out;
466
467 err = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
468 OMNIA_ATSHA204_OTP_MAC1, mac1);
469 if (err)
470 goto out;
471
472 atsha204a_sleep(dev);
473
474 mac[0] = mac0[1];
475 mac[1] = mac0[2];
476 mac[2] = mac0[3];
477 mac[3] = mac1[1];
478 mac[4] = mac1[2];
479 mac[5] = mac1[3];
480
481 if (is_valid_ethaddr(mac))
Simon Glass8551d552017-08-03 12:22:11 -0600482 eth_env_set_enetaddr("ethaddr", mac);
Marek Behún09e16b82017-06-09 19:28:45 +0200483
484 increment_mac(mac);
485
486 if (is_valid_ethaddr(mac))
Simon Glass8551d552017-08-03 12:22:11 -0600487 eth_env_set_enetaddr("eth1addr", mac);
Marek Behún09e16b82017-06-09 19:28:45 +0200488
489 increment_mac(mac);
490
491 if (is_valid_ethaddr(mac))
Simon Glass8551d552017-08-03 12:22:11 -0600492 eth_env_set_enetaddr("eth2addr", mac);
Marek Behún09e16b82017-06-09 19:28:45 +0200493
494out:
Marek Behún09e16b82017-06-09 19:28:45 +0200495 return 0;
496}
497