summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/zii-imx8mq-dev/lowlevel.c
blob: 64008338090694ebea05b4ddb210187bd4b33583 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2019 Zodiac Inflight Innovation
 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
 */

#include <common.h>
#include <firmware.h>
#include <linux/sizes.h>
#include <mach/generic.h>
#include <asm/barebox-arm-head.h>
#include <asm/barebox-arm.h>
#include <mach/imx8m-ccm-regs.h>
#include <mach/iomux-mx8mq.h>
#include <soc/imx8m/ddr.h>
#include <mach/xload.h>
#include <io.h>
#include <debug_ll.h>
#include <asm/cache.h>
#include <asm/sections.h>
#include <asm/mmu.h>
#include <mach/atf.h>
#include <mach/esdctl.h>

#include "ddr.h"

#define UART_PAD_CTRL	MUX_PAD_CTRL(PAD_CTL_DSE_3P3V_45_OHM)

static void setup_uart(void)
{
	imx8m_early_setup_uart_clock();

	imx8mq_setup_pad(IMX8MQ_PAD_UART1_TXD__UART1_TX | UART_PAD_CTRL);

	imx8m_uart_setup_ll();

	putc_ll('>');
}

/*
 * Two functions below are used when Barebox is used as a DDR
 * initializing payload for OpenOCD
 */
#define RDU3_TCM_MAGIC_LOCATION	0x007e1028
#define RDU3_TCM_MAGIC_REQUEST	0xdeadbeef
#define RDU3_TCM_MAGIC_REPLY	0xbaadf00d

static bool running_as_ddr_helper(void)
{
	return readl(RDU3_TCM_MAGIC_LOCATION) == RDU3_TCM_MAGIC_REQUEST;
}

static __noreturn void ddr_helper_halt(void)
{
	writel(RDU3_TCM_MAGIC_REPLY, RDU3_TCM_MAGIC_LOCATION);
	asm volatile("hlt 0");
	BUG(); 	/* To prevent noreturn warnings */
}

static void zii_imx8mq_dev_sram_setup(void)
{
	enum bootsource src = BOOTSOURCE_UNKNOWN;
	int instance = BOOTSOURCE_INSTANCE_UNKNOWN;
	int ret = -ENOTSUPP;

	ddr_init();

	if (running_as_ddr_helper())
		ddr_helper_halt();

	imx8mq_get_boot_source(&src, &instance);

	if (src == BOOTSOURCE_MMC)
		ret = imx8m_esdhc_load_image(instance, true);

	BUG_ON(ret);
}

enum zii_platform_imx8mq_type {
	ZII_PLATFORM_IMX8MQ_ULTRA_RMB3 = 0b0000,
	ZII_PLATFORM_IMX8MQ_ULTRA_ZEST = 0b1000,
};

static unsigned int get_system_type(void)
{
#define GPIO_DR		0x000
#define GPIO_GDIR	0x004
#define SYSTEM_TYPE	GENMASK(24, 21)

	u32 gdir, dr;
	void __iomem *gpio3 = IOMEM(MX8MQ_GPIO3_BASE_ADDR);
	void __iomem *iomuxbase = IOMEM(MX8MQ_IOMUXC_BASE_ADDR);

	/*
	 * System type is encoded as a 4-bit number specified by the
	 * following pins (pulled up or down with resistors on the
	 * board).
	*/
	imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD0__GPIO3_IO21);
	imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD1__GPIO3_IO22);
	imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD2__GPIO3_IO23);
	imx_setup_pad(iomuxbase, IMX8MQ_PAD_SAI5_RXD3__GPIO3_IO24);

	gdir = readl(gpio3 + GPIO_GDIR);
	gdir &= ~SYSTEM_TYPE;
	writel(gdir, gpio3 + GPIO_GDIR);

	dr = readl(gpio3 + GPIO_DR);

	return FIELD_GET(SYSTEM_TYPE, dr);
}

extern char __dtb_z_imx8mq_zii_ultra_rmb3_start[];
extern char __dtb_z_imx8mq_zii_ultra_zest_start[];

static __noreturn noinline void zii_imx8mq_dev_start(void)
{
	unsigned int system_type;
	void *fdt;

	if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) {
		/*
		 * We assume that we were just loaded by MaskROM into
		 * SRAM if we are not running from DDR. We also assume
		 * that means DDR needs to be initialized for the
		 * first time.
		 */
		zii_imx8mq_dev_sram_setup();
	}
	/*
	 * Straight from the power-on we are at EL3, so the following
	 * code _will_ load and jump to ATF.
	 *
	 * However when we are re-executed upon exit from ATF's
	 * initialization routine, it is EL2 which means we'll skip
	 * loadting ATF blob again
	 */
	if (current_el() == 3) {
		const u8 *bl31;
		size_t bl31_size;

		get_builtin_firmware(imx8mq_bl31_bin, &bl31, &bl31_size);
		imx8mq_atf_load_bl31(bl31, bl31_size);
	}

	system_type = get_system_type();

	switch (system_type) {
	default:
		if (IS_ENABLED(CONFIG_DEBUG_LL)) {
			puts_ll("\n*********************************\n");
			puts_ll("* Unknown system type: ");
			puthex_ll(system_type);
			puts_ll("\n* Assuming Ultra RMB3\n");
			puts_ll("*********************************\n");
		}
		/* FALLTHROUGH */
	case ZII_PLATFORM_IMX8MQ_ULTRA_RMB3:
		fdt = __dtb_z_imx8mq_zii_ultra_rmb3_start;
		break;
	case ZII_PLATFORM_IMX8MQ_ULTRA_ZEST:
		fdt = __dtb_z_imx8mq_zii_ultra_zest_start;
		break;
	}

	/*
	 * Standard entry we hit once we initialized both DDR and ATF
	 */
	imx8mq_barebox_entry(fdt);
}

/*
 * Power-on execution flow of start_zii_imx8mq_dev() might not be
 * obvious for a very frist read, so here's, hopefully helpful,
 * summary:
 *
 * 1. MaskROM uploads PBL into OCRAM and that's where this function is
 *    executed for the first time
 *
 * 2. DDR is initialized and full i.MX image is loaded to the
 *    beginning of RAM
 *
 * 3. start_nxp_imx8mq_evk, now in RAM, is executed again
 *
 * 4. BL31 blob is uploaded to OCRAM and the control is transfer to it
 *
 * 5. BL31 exits EL3 into EL2 at address MX8MQ_ATF_BL33_BASE_ADDR,
 *    executing start_nxp_imx8mq_evk() the third time
 *
 * 6. Standard barebox boot flow continues
 */
ENTRY_FUNCTION(start_zii_imx8mq_dev, r0, r1, r2)
{
	imx8mq_cpu_lowlevel_init();
	relocate_to_current_adr();
	setup_c();
	
	if (IS_ENABLED(CONFIG_DEBUG_LL))
		setup_uart();

	zii_imx8mq_dev_start();
}