bl2_setup.c 19.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
 * Copyright (c) 2016-2020, Broadcom
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/arm/sp805.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>

#include <chimp.h>
#include <chip_id.h>
#include <cmn_plat_util.h>
#include <dmu.h>
18
#include <emmc_api.h>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
#include <fru.h>
#ifdef USE_GPIO
#include <drivers/gpio.h>
#include <iproc_gpio.h>
#endif
#include <platform_def.h>
#include <sotp.h>
#include <swreg.h>
#include <sr_utils.h>
#ifdef USE_DDR
#include <ddr_init.h>
#else
#include <ext_sram_init.h>
#endif
#if DRIVER_OCOTP_ENABLE
#include <ocotp.h>
#endif
#include "board_info.h"

#define WORD_SIZE              8
#define SWREG_AVS_OTP_OFFSET   (13 * WORD_SIZE) /* 13th row byte offset */
#define AON_GPIO_OTP_OFFSET    (28 * WORD_SIZE) /* 28th row byte offset */
#define BYTES_TO_READ          8

/* OTP voltage step definitions */
#define MVOLT_STEP_MAX         0x18  /* 1v */
#define MVOLT_PER_STEP         10    /* 0.01mv per step */
#define MVOLT_BASE             760   /* 0.76v */

#define STEP_TO_UVOLTS(step) \
	((MVOLT_BASE + (MVOLT_PER_STEP * (step))) * 1000)

#define GET_BITS(first, last, data) \
	((data >> first) & ((1 << (last - first + 1)) - 1))

/*
 * SW-REG OTP encoding:
 *
 * SWREG_bits[11:0]  = OTP 13th row 12 bits[55:44]
 * SWREG_bits[11:10] - Valid Bits (0x2 - valid, if not 0x2 - Invalid)
 * SWREG_bits[9:5]   - iHost03, iHost12
 * SWREG_bits[4:0]   - Core VDDC
 */
#define SWREG_OTP_BITS_START        12    /* 44th bit in MSB 32-bits */
#define SWREG_OTP_BITS_END          23    /* 55th bit in MSB 32-bits */
#define SWREG_VDDC_FIELD_START      0
#define SWREG_VDDC_FIELD_END        4
#define SWREG_IHOST_FIELD_START     5
#define SWREG_IHOST_FIELD_END       9
#define SWREG_VALID_BIT_START       10
#define SWREG_VALID_BIT_END         11
#define SWREG_VALID_BITS            0x2

/*
 * Row 13 bit 56 is programmed as '1' today. It is not being used, so plan
 * is to flip this bit to '0' for B1 rev. Hence SW can leverage this bit
 * to identify Bx chip to program different sw-regulators.
 */
#define SPARE_BIT             24

#define IS_SR_B0(data)        (((data) >> SPARE_BIT) & 0x1)

#if DRIVER_OCOTP_ENABLE
static struct otpc_map otp_stingray_map = {
	.otpc_row_size = 2,
	.data_r_offset = {0x10, 0x5c},
	.data_w_offset = {0x2c, 0x64},
	.word_size = 8,
	.stride = 8,
};
#endif

void plat_bcm_bl2_early_platform_setup(void)
{
	/* Select UART0 for AP via mux setting*/
	if (PLAT_BRCM_BOOT_UART_BASE == UART0_BASE_ADDR) {
		mmio_write_32(UART0_SIN_MODE_SEL_CONTROL, 1);
		mmio_write_32(UART0_SOUT_MODE_SEL_CONTROL, 1);
	}
}

#ifdef USE_NAND
static void brcm_stingray_nand_init(void)
{
	unsigned int val;
	unsigned int nand_idm_reset_control = 0x68e0a800;

	VERBOSE(" stingray nand init start.\n");

	/* Reset NAND */
	VERBOSE(" - reset nand\n");
	val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0));
	mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val | 0x1);
	udelay(500);
	val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0));
	mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val & ~0x1);
	udelay(500);

	VERBOSE(" stingray nand init done.\n");
}
#endif

#if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA)
#define PCIE_RESCAL_CFG_0 0x40000130
#define PCIE_CFG_RESCAL_RSTB_R (1 << 16)
#define PCIE_CFG_RESCAL_PWRDNB_R (1 << 8)
#define PCIE_RESCAL_STATUS_0 0x4000014c
#define PCIE_STAT_PON_VALID_R (1 << 0)
#define PCIE_RESCAL_OUTPUT_STATUS 0x40000154
#define CDRU_PCIE_RESET_N_R (1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R)

#ifdef EMULATION_SETUP
static void brcm_stingray_pcie_reset(void)
{
}
#else
static void brcm_stingray_pcie_reset(void)
{
	unsigned int data;
	int try;

	if (bcm_chimp_is_nic_mode()) {
		INFO("NIC mode detected; PCIe reset/rescal not executed\n");
		return;
	}

	mmio_clrbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R);
	mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R);
	/* Release reset */
	mmio_setbits_32(PCIE_RESCAL_CFG_0, PCIE_CFG_RESCAL_RSTB_R);
	mdelay(1);
	/* Power UP */
	mmio_setbits_32(PCIE_RESCAL_CFG_0,
			(PCIE_CFG_RESCAL_RSTB_R | PCIE_CFG_RESCAL_PWRDNB_R));

	try = 1000;
	do {
		udelay(1);
		data = mmio_read_32(PCIE_RESCAL_STATUS_0);
		try--;
	} while ((data & PCIE_STAT_PON_VALID_R) == 0x0 && (try > 0));

	if (try <= 0)
		ERROR("PCIE_RESCAL_STATUS_0: 0x%x\n", data);

	VERBOSE("PCIE_SATA_RESCAL_STATUS_0 0x%x.\n",
			mmio_read_32(PCIE_RESCAL_STATUS_0));
	VERBOSE("PCIE_SATA_RESCAL_OUTPUT_STATUS 0x%x.\n",
			mmio_read_32(PCIE_RESCAL_OUTPUT_STATUS));
	INFO("PCIE SATA Rescal Init done\n");
}
#endif /* EMULATION_SETUP */
#endif /* USE_PAXB || USE_PAXC || USE_SATA */

#ifdef USE_PAXC
void brcm_stingray_chimp_check_and_fastboot(void)
{
	int fastboot_init_result;

	if (bcm_chimp_is_nic_mode())
		/* Do not wait here */
		return;

#if WARMBOOT_DDR_S3_SUPPORT
	/*
	 * Currently DDR shmoo parameters and QSPI boot source are
	 * tied. DDR shmoo parameters are stored in QSPI, which is
	 * used for warmboot.
	 * Do not reset nitro for warmboot
	 */
	if (is_warmboot() && (boot_source_get() == BOOT_SOURCE_QSPI))
		return;
#endif /* WARMBOOT_DDR_S3_SUPPORT */

	/*
	 * Not in NIC mode,
	 * initiate fastboot (if enabled)
	 */
	if (FASTBOOT_TYPE == CHIMP_FASTBOOT_NITRO_RESET) {

		VERBOSE("Bring up Nitro/ChiMP\n");

		if (boot_source_get() == BOOT_SOURCE_QSPI)
			WARN("Nitro boots from QSPI when AP has booted from QSPI.\n");
		brcm_stingray_set_qspi_mux(0);
		VERBOSE("Nitro controls the QSPI\n");
	}

	fastboot_init_result = bcm_chimp_initiate_fastboot(FASTBOOT_TYPE);
	if (fastboot_init_result && boot_source_get() != BOOT_SOURCE_QSPI)
		ERROR("Nitro init error %d. Status: 0x%x; bpe_mod reg: 0x%x\n"
			"fastboot register: 0x%x; handshake register 0x%x\n",
			fastboot_init_result,
			bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG),
			bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_MODE_REG),
			bcm_chimp_read_ctrl(CHIMP_REG_CTRL_FSTBOOT_PTR_REG),
			bcm_chimp_read(CHIMP_REG_ECO_RESERVED));

	/*
	 * CRMU watchdog kicks is an example, which is L1 reset,
	 * does not clear Nitro scratch pad ram.
	 * For Nitro resets: Clear the Nitro health status memory.
	 */
	bcm_chimp_write((CHIMP_REG_CHIMP_SCPAD + CHIMP_HEALTH_STATUS_OFFSET),
			0);
}
#endif

void set_ihost_vddc_swreg(uint32_t ihost_uvolts, uint32_t vddc_uvolts)
{
	NOTICE("ihost_uvolts: %duv, vddc_uvolts: %duv\n",
	       ihost_uvolts, vddc_uvolts);

	set_swreg(VDDC_CORE, vddc_uvolts);
	set_swreg(IHOST03, ihost_uvolts);
	set_swreg(IHOST12, ihost_uvolts);
}

/*
 * Reads SWREG AVS OTP bits (13th row) with ECC enabled and get voltage
 * defined in OTP if valid OTP is found
 */
void read_avs_otp_bits(uint32_t *ihost_uvolts, uint32_t *vddc_uvolts)
{
	uint32_t offset = SWREG_AVS_OTP_OFFSET;
	uint32_t ihost_step, vddc_step;
	uint32_t avs_bits;
	uint32_t buf[2];

	if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1)
		return;

	VERBOSE("AVS OTP %d ROW: 0x%x.0x%x\n",
		offset/WORD_SIZE, buf[1], buf[0]);

	/* get voltage readings from AVS OTP bits */
	avs_bits = GET_BITS(SWREG_OTP_BITS_START,
			    SWREG_OTP_BITS_END,
			    buf[1]);

	/* check for valid otp bits */
	if (GET_BITS(SWREG_VALID_BIT_START, SWREG_VALID_BIT_END, avs_bits) !=
	    SWREG_VALID_BITS) {
		WARN("Invalid AVS OTP bits at %d row\n", offset/WORD_SIZE);
		return;
	}

	/* get ihost and vddc step value */
	vddc_step = GET_BITS(SWREG_VDDC_FIELD_START,
			     SWREG_VDDC_FIELD_END,
			     avs_bits);

	ihost_step = GET_BITS(SWREG_IHOST_FIELD_START,
			      SWREG_IHOST_FIELD_END,
			      avs_bits);

	if ((ihost_step > MVOLT_STEP_MAX) || (vddc_step > MVOLT_STEP_MAX)) {
		WARN("OTP entry invalid\n");
		return;
	}

	/* get voltage in micro-volts */
	*ihost_uvolts = STEP_TO_UVOLTS(ihost_step);
	*vddc_uvolts = STEP_TO_UVOLTS(vddc_step);
}

/*
 * This api reads otp bits and program internal swreg's - ihos12, ihost03,
 * vddc_core and ddr_core based on different chip. External swreg's
 * programming will be done from crmu.
 *
 * For A2 chip:
 *   Read OTP row 20, bit 50. This bit will be set for A2 chip. Once A2 chip is
 *   found, read AVS OTP row 13, 12bits[55:44], if valid otp bits are found
 *   then set ihost and vddc according to avs otp bits else set them to 0.94v
 *   and 0.91v respectively. Also update the firmware after setting voltage.
 *
 * For B0 chip:
 *   Read OTP row 13, bit 56. This bit will be set for B0 chip. Once B0 chip is
 *   found then set ihost and vddc to 0.95v and ddr_core to 1v. No AVS OTP bits
 *   are used get ihost/vddc voltages.
 *
 * For B1 chip:
 *   Read AVS OTP row 13, 12bits[55:44], if valid otp bits are found then set
 *   ihost and vddc according to avs otp bits else set them to 0.94v and 0.91v
 *   respectively.
 */
void set_swreg_based_on_otp(void)
{
	/* default voltage if no valid OTP */
	uint32_t vddc_uvolts = VDDC_CORE_DEF_VOLT;
	uint32_t ihost_uvolts = IHOST_DEF_VOLT;
	uint32_t ddrc_uvolts;
	uint32_t offset;
	uint32_t buf[2];

	offset = SWREG_AVS_OTP_OFFSET;
	if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1)
		return;

	VERBOSE("OTP %d ROW: 0x%x.0x%x\n",
		offset/WORD_SIZE, buf[1], buf[0]);

	if (IS_SR_B0(buf[1])) {
		/* don't read AVS OTP for B0 */
		ihost_uvolts = B0_IHOST_DEF_VOLT;
		vddc_uvolts = B0_VDDC_CORE_DEF_VOLT;
		ddrc_uvolts = B0_DDR_VDDC_DEF_VOLT;
	} else {
		read_avs_otp_bits(&ihost_uvolts, &vddc_uvolts);
	}

#if (IHOST_REG_TYPE == IHOST_REG_INTEGRATED) && \
	(VDDC_REG_TYPE == VDDC_REG_INTEGRATED)
	/* enable IHOST12 cluster before changing voltage */
	NOTICE("Switching on the Regulator idx: %u\n",
	       SWREG_IHOST1_DIS);
	mmio_clrsetbits_32(CRMU_SWREG_CTRL_ADDR,
			   BIT(SWREG_IHOST1_DIS),
			   BIT(SWREG_IHOST1_REG_RESETB));

	/* wait for regulator supply gets stable */
	while (!(mmio_read_32(CRMU_SWREG_STATUS_ADDR) &
	       (1 << SWREG_IHOST1_PMU_STABLE)))
		;

	INFO("Regulator supply got stable\n");

#ifndef DEFAULT_SWREG_CONFIG
	swreg_firmware_update();
#endif

	set_ihost_vddc_swreg(ihost_uvolts, vddc_uvolts);
#endif
	if (IS_SR_B0(buf[1])) {
		NOTICE("ddrc_uvolts: %duv\n", ddrc_uvolts);
		set_swreg(DDR_VDDC, ddrc_uvolts);
	}
}

#ifdef USE_DDR
static struct ddr_info ddr_info;
#endif
#ifdef USE_FRU
static struct fru_area_info fru_area[FRU_MAX_NR_AREAS];
static struct fru_board_info board_info;
static struct fru_time fru_tm;
static uint8_t fru_tbl[BCM_MAX_FRU_LEN];

static void board_detect_fru(void)
{
	uint32_t i, result;
	int ret = -1;

	result = bcm_emmc_init(false);
	if (!result) {
		ERROR("eMMC init failed\n");
		return;
	}

	/* go through eMMC boot partitions looking for FRU table */
	for (i = EMMC_BOOT_PARTITION1; i <= EMMC_BOOT_PARTITION2; i++) {
		result = emmc_partition_select(i);
		if (!result) {
			ERROR("Switching to eMMC part %u failed\n", i);
			return;
		}

		result = emmc_read(BCM_FRU_TBL_OFFSET, (uintptr_t)fru_tbl,
				   BCM_MAX_FRU_LEN, BCM_MAX_FRU_LEN);
		if (!result) {
			ERROR("Failed to read from eMMC part %u\n", i);
			return;
		}

		/*
		 * Run sanity check and checksum to make sure valid FRU table
		 * is detected
		 */
		ret = fru_validate(fru_tbl, fru_area);
		if (ret < 0) {
			WARN("FRU table not found in eMMC part %u\n", i);
			continue;
		}

		/* parse DDR information from FRU table */
		ret = fru_parse_ddr(fru_tbl, &fru_area[FRU_AREA_INTERNAL],
				    &ddr_info);
		if (ret < 0) {
			WARN("No FRU DDR info found in eMMC part %u\n", i);
			continue;
		}

		/* parse board information from FRU table */
		ret = fru_parse_board(fru_tbl, &fru_area[FRU_AREA_BOARD_INFO],
				      &board_info);
		if (ret < 0) {
			WARN("No FRU board info found in eMMC part %u\n", i);
			continue;
		}

		/* if we reach here, valid FRU table is parsed */
		break;
	}

	if (ret < 0) {
		WARN("FRU table missing for this board\n");
		return;
	}

	for (i = 0; i < BCM_MAX_NR_DDR; i++) {
		INFO("DDR channel index: %d\n", ddr_info.mcb[i].idx);
		INFO("DDR size %u GB\n", ddr_info.mcb[i].size_mb / 1024);
		INFO("DDR ref ID by SW (Not MCB Ref ID) 0x%x\n",
		     ddr_info.mcb[i].ref_id);
	}

	fru_format_time(board_info.mfg_date, &fru_tm);

	INFO("**** FRU board information ****\n");
	INFO("Language 0x%x\n", board_info.lang);
	INFO("Manufacturing Date %u.%02u.%02u, %02u:%02u\n",
	     fru_tm.year, fru_tm.month, fru_tm.day,
	     fru_tm.hour, fru_tm.min);
	INFO("Manufacturing Date(Raw) 0x%x\n", board_info.mfg_date);
	INFO("Manufacturer %s\n", board_info.manufacturer);
	INFO("Product Name %s\n", board_info.product_name);
	INFO("Serial number %s\n", board_info.serial_number);
	INFO("Part number %s\n", board_info.part_number);
	INFO("File ID %s\n", board_info.file_id);
}
#endif /* USE_FRU */

#ifdef USE_GPIO

#define INVALID_GPIO    0xffff

static const int gpio_cfg_bitmap[MAX_NR_GPIOS] = {
#ifdef BRD_DETECT_GPIO_BIT0
	BRD_DETECT_GPIO_BIT0,
#else
	INVALID_GPIO,
#endif
#ifdef BRD_DETECT_GPIO_BIT1
	BRD_DETECT_GPIO_BIT1,
#else
	INVALID_GPIO,
#endif
#ifdef BRD_DETECT_GPIO_BIT2
	BRD_DETECT_GPIO_BIT2,
#else
	INVALID_GPIO,
#endif
#ifdef BRD_DETECT_GPIO_BIT3
	BRD_DETECT_GPIO_BIT3,
#else
	INVALID_GPIO,
#endif
};

static uint8_t gpio_bitmap;

/*
 * Use an odd number to avoid potential conflict with public GPIO level
 * defines
 */
#define GPIO_STATE_FLOAT         15

/*
 * If GPIO_SUPPORT_FLOAT_DETECTION is disabled, simply return GPIO level
 *
 * If GPIO_SUPPORT_FLOAT_DETECTION is enabled, add additional test for possible
 * pin floating (unconnected) scenario. This support is assuming externally
 * applied pull up / pull down will have a stronger pull than the internal pull
 * up / pull down.
 */
static uint8_t gpio_get_state(int gpio)
{
	uint8_t val;

	/* set direction to GPIO input */
	gpio_set_direction(gpio, GPIO_DIR_IN);

#ifndef GPIO_SUPPORT_FLOAT_DETECTION
	if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH)
		val = GPIO_LEVEL_HIGH;
	else
		val = GPIO_LEVEL_LOW;

	return val;
#else
	/*
	 * Enable internal pull down. If GPIO level is still high, there must
	 * be an external pull up
	 */
	gpio_set_pull(gpio, GPIO_PULL_DOWN);
	if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH) {
		val = GPIO_LEVEL_HIGH;
		goto exit;
	}

	/*
	 * Enable internal pull up. If GPIO level is still low, there must
	 * be an external pull down
	 */
	gpio_set_pull(gpio, GPIO_PULL_UP);
	if (gpio_get_value(gpio) == GPIO_LEVEL_LOW) {
		val = GPIO_LEVEL_LOW;
		goto exit;
	}

	/* if reached here, the pin must be not connected */
	val = GPIO_STATE_FLOAT;

exit:
	/* make sure internall pull is disabled */
	if (gpio_get_pull(gpio) != GPIO_PULL_NONE)
		gpio_set_pull(gpio, GPIO_PULL_NONE);

	return val;
#endif
}

static void board_detect_gpio(void)
{
	unsigned int i, val;
	int gpio;

	iproc_gpio_init(IPROC_GPIO_S_BASE, IPROC_GPIO_NR,
			IPROC_IOPAD_MODE_BASE, HSLS_IOPAD_BASE);

	gpio_bitmap = 0;
	for (i = 0; i < MAX_NR_GPIOS; i++) {
		if (gpio_cfg_bitmap[i] == INVALID_GPIO)
			continue;

		/*
		 * Construct the bitmap based on GPIO value. Floating pin
		 * detection is a special case. As soon as a floating pin is
		 * detected, a special value of MAX_GPIO_BITMAP_VAL is
		 * assigned and we break out of the loop immediately
		 */
		gpio = gpio_cfg_bitmap[i];
		val = gpio_get_state(gpio);
		if (val == GPIO_STATE_FLOAT) {
			gpio_bitmap = MAX_GPIO_BITMAP_VAL;
			break;
		}

		if (val == GPIO_LEVEL_HIGH)
			gpio_bitmap |= BIT(i);
	}

	memcpy(&ddr_info, &gpio_ddr_info[gpio_bitmap], sizeof(ddr_info));
	INFO("Board detection GPIO bitmap = 0x%x\n", gpio_bitmap);
}
#endif /* USE_GPIO */

static void bcm_board_detect(void)
{
#ifdef DDR_LEGACY_MCB_SUPPORTED
	/* Loading default DDR info */
	memcpy(&ddr_info, &default_ddr_info, sizeof(ddr_info));
#endif
#ifdef USE_FRU
	board_detect_fru();
#endif
#ifdef USE_GPIO
	board_detect_gpio();
#endif
}

static void dump_persistent_regs(void)
{
	NOTICE("pr0: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG0));
	NOTICE("pr1: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1));
	NOTICE("pr2: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG2));
	NOTICE("pr3: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG3));
	NOTICE("pr4: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG4));
	NOTICE("pr5: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG5));
	NOTICE("pr6: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG6));
	NOTICE("pr7: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG7));
	NOTICE("pr8: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG8));
	NOTICE("pr9: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));
	NOTICE("pr10: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG10));
	NOTICE("pr11: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG11));
}

void plat_bcm_bl2_plat_arch_setup(void)
{
	if (chip_get_rev_id_major() == CHIP_REV_MAJOR_AX) {
		if (!(sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
		      SOTP_ATF_WATCHDOG_ENABLE_MASK)) {
			/*
			 * Stop sp805 watchdog timer immediately.
			 * It might has been set up by MCU patch earlier for
			 * eMMC workaround.
			 *
			 * Note the watchdog timer started in CRMU has a very
			 * short timeout and needs to be stopped immediately.
			 * Down below we restart it with a much longer timeout
			 * for BL2 and BL31
			 */
			sp805_stop(ARM_SP805_TWDG_BASE);
		}
	}

#if !BRCM_DISABLE_TRUSTED_WDOG
	/*
	 * start secure watchdog for BL2 and BL31.
	 * Note that UART download can take a longer time,
	 * so do not allow watchdog for UART download,
	 * as this boot source is not a standard modus operandi.
	 */
	if (boot_source_get() != BOOT_SOURCE_UART)
		sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
#endif

#ifdef BCM_ELOG
	/* Ensure logging is started out fresh in BL2. */
	mmio_write_32(BCM_ELOG_BL2_BASE, 0);
#endif
	/*
	 * In BL2, since we have very limited space to store logs, we only
	 * save logs that are >= the WARNING level.
	 */
	bcm_elog_init((void *)BCM_ELOG_BL2_BASE, BCM_ELOG_BL2_SIZE,
		      LOG_LEVEL_WARNING);

	dump_persistent_regs();

	/* Read CRMU mailbox 0 */
	NOTICE("RESET (reported by CRMU): 0x%x\n",
	       mmio_read_32(CRMU_READ_MAIL_BOX0));

	/*
	 * All non-boot-source PADs are in forced input-mode at
	 * reset so clear the force on non-boot-source PADs using
	 * CDRU register.
	 */
	mmio_clrbits_32((uintptr_t)CDRU_CHIP_IO_PAD_CONTROL,
		(1 << CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PAD_IN_R));

#if DRIVER_OCOTP_ENABLE
	bcm_otpc_init(&otp_stingray_map);
#endif

	set_swreg_based_on_otp();

#if IHOST_PLL_FREQ != 0
	bcm_set_ihost_pll_freq(0x0, IHOST_PLL_FREQ);
#endif

#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
	/* The erasable unit of the eMMC is the "Erase Group";
	 * Erase group is measured in write blocks which are the
	 * basic writable units of the Device.
	 * The size of the Erase Group is a Device specific parameter
	 */
	emmc_erase(EMMC_ERASE_START_BLOCK, EMMC_ERASE_BLOCK_COUNT,
		   EMMC_ERASE_PARTITION);
#endif

	bcm_board_detect();
#ifdef DRIVER_EMMC_ENABLE
	/* Initialize the card, if it is not */
	if (bcm_emmc_init(true) < 0)
		WARN("eMMC Card Initialization Failed!!!\n");
#endif

#if BL2_TEST_I2C
	i2c_test();
#endif

#ifdef USE_DDR
	ddr_initialize(&ddr_info);

	ddr_secure_region_config(SECURE_DDR_BASE_ADDRESS,
				 SECURE_DDR_END_ADDRESS);
#ifdef NITRO_SECURE_ACCESS
	ddr_secure_region_config(DDR_NITRO_SECURE_REGION_START,
				 DDR_NITRO_SECURE_REGION_END);
#endif
#else
	ext_sram_init();
#endif

#if BL2_TEST_MEM
	ddr_test();
#endif

#ifdef USE_NAND
	brcm_stingray_nand_init();
#endif

#if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA)
	brcm_stingray_pcie_reset();
#endif

#ifdef USE_PAXC
	if (boot_source_get() != BOOT_SOURCE_QSPI)
		brcm_stingray_chimp_check_and_fastboot();
#endif

#if ((!CLEAN_DDR || MMU_DISABLED))
	/*
	 * Now DDR has been initialized. We want to copy all the logs in SRAM
	 * into DDR so we will have much more space to store the logs in the
	 * next boot stage
	 */
	bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
			   MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
			 );

	/*
	 * We are not yet at the end of BL2, but we can stop log here so we do
	 * not need to add 'bcm_elog_exit' to the standard BL2 code. The
	 * benefit of capturing BL2 logs after this is very minimal in a
	 * production system
	 * NOTE: BL2 logging must be exited before going forward to setup
	 * page tables
	 */
	bcm_elog_exit();
#endif
}