summaryrefslogtreecommitdiff
path: root/board/toradex/verdin-am62/verdin-am62.c
blob: e718eb0030ba67179d00212271ce575910309344 (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
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
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Board specific initialization for Verdin AM62 SoM
 *
 * Copyright 2023 Toradex - https://www.toradex.com/
 *
 */

#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
#include <asm/io.h>
#include <common.h>
#include <dm/uclass.h>
#include <env.h>
#include <fdt_support.h>
#include <i2c.h>
#include <k3-ddrss.h>
#include <power/tps65219.h>
#include <spl.h>

#include "../common/tdx-cfg-block.h"

DECLARE_GLOBAL_DATA_PTR;

/* from 5.8 Boot Memory Maps */
#define BOOT_PARAMETER_TABLE 0x43c3f298
/* from 5.6.1 Common Header */
#define BOOT_PARAMETER_PRIMARY_PERIPHERAL (*(u16 *)(BOOT_PARAMETER_TABLE + 0x04))
#define BOOT_PARAMETER_SECONDARY_PERIPHERAL (*(u16 *)(BOOT_PARAMETER_TABLE + 0x204))
#define BOOT_PARAMETER_EMMC 101
#define BOOT_PARAMETER_SD 100
#define BOOT_PARAMETER_USB_DFU 70

#define PMIC_I2C_BUS		0x0
#define PMIC_I2C_ADDRESS	0x30
#define PMIC_BUCK1_VSET_850	0xa

int board_init(void)
{
	struct udevice *dev;
	u8 addr, data[1];
	int err;

	/* Set PMIC Buck1 aka +VDD_CORE to 850 mV */
	err = i2c_get_chip_for_busnum(PMIC_I2C_BUS, PMIC_I2C_ADDRESS, 1, &dev);
	if (err) {
		printf("%s: Cannot find PMIC I2C chip (err=%d)\n", __func__, err);
	} else {
		addr = TPS65219_BUCK1_VOUT_REG;
		err = dm_i2c_read(dev, addr, data, 1);
		if (err)
			debug("failed to get TPS65219_BUCK1_VOUT_REG (err=%d)\n", err);
		data[0] &= ~TPS65219_VOLT_MASK;
		data[0] |= PMIC_BUCK1_VSET_850;
		err = dm_i2c_write(dev, addr, data, 1);
		if (err)
			debug("failed to set TPS65219_BUCK1_VOUT_REG (err=%d)\n", err);
	}

	return 0;
}

int dram_init(void)
{
	return fdtdec_setup_mem_size_base();
}

int dram_init_banksize(void)
{
	return fdtdec_setup_memory_banksize();
}

#if defined(CONFIG_SPL_LOAD_FIT)
int board_fit_config_name_match(const char *name)
{
	return 0;
}
#endif

#if IS_ENABLED(CONFIG_SPL_BUILD)
#if IS_ENABLED(CONFIG_K3_AM64_DDRSS)
static void fixup_ddr_driver_for_ecc(struct spl_image_info *spl_image)
{
	struct udevice *dev;
	int ret;

	dram_init_banksize();

	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
	if (ret)
		panic("Cannot get RAM device for ddr size fixup: %d\n", ret);

	ret = k3_ddrss_ddr_fdt_fixup(dev, spl_image->fdt_addr, gd->bd);
	if (ret)
		printf("Error fixing up ddr node for ECC use! %d\n", ret);
}
#else
static void fixup_memory_node(struct spl_image_info *spl_image)
{
	u64 start[CONFIG_NR_DRAM_BANKS];
	u64 size[CONFIG_NR_DRAM_BANKS];
	int bank;
	int ret;

	dram_init();
	dram_init_banksize();

	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
		start[bank] = gd->bd->bi_dram[bank].start;
		size[bank] = gd->bd->bi_dram[bank].size;
	}

	/* dram_init functions use SPL fdt, and we must fixup u-boot fdt */
	ret = fdt_fixup_memory_banks(spl_image->fdt_addr, start, size,
				     CONFIG_NR_DRAM_BANKS);
	if (ret)
		printf("Error fixing up memory node! %d\n", ret);
}
#endif

void spl_perform_fixups(struct spl_image_info *spl_image)
{
#if IS_ENABLED(CONFIG_K3_AM64_DDRSS)
	fixup_ddr_driver_for_ecc(spl_image);
#else
	fixup_memory_node(spl_image);
#endif
}
#endif

#if IS_ENABLED(CONFIG_OF_LIBFDT) && IS_ENABLED(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, struct bd_info *bd)
{
	return ft_common_board_setup(blob, bd);
}
#endif

#if !defined(CONFIG_SPL_BUILD)
/* Should check if we were booted over dfu, and if so go to DFU / UMS for download */
void decide_on_dfu(void)
{
	/*
	 * SD boot with sdcard,		7000f290: 00000000
	 * SD boot without sdcard, dfu,	7000f290: 00000001
	 * eMMC Boot, eMMC flashed	7000f290: 00000000
	 * eMMC Boot, eMMC zeroed	7000f290: 00000001
	 * DFU Boot			7000f290: 00000000
	 *
	 * If this Memory location will stay untouched in future versions is
	 * unknown, so the code might break.
	 * Compare with arch/arm/mach-k3/am625_init.c which however is SPL only
	 */
	u32 bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX);
	u32 bootmode = bootindex & 1 ? BOOT_PARAMETER_SECONDARY_PERIPHERAL :
				       BOOT_PARAMETER_PRIMARY_PERIPHERAL;

	if (bootmode == BOOT_PARAMETER_USB_DFU) {
		printf("DFU boot mode detected, going to DFU again for further downloads\n");
		env_set("bootcmd", "setenv dfu_alt_info $dfu_alt_info_emmc;"
				   "dfu 0 mmc 0; ums 0 mmc 0");
	}

	debug("Booting from %s boot device\n", bootindex & 1 ? "Secondary" :
							       "Primary");
	debug("Primary boot device as read from boot parameters %hd\n",
	      BOOT_PARAMETER_PRIMARY_PERIPHERAL);
	debug("Secondary boot device as read from boot parameters %hd\n",
	      BOOT_PARAMETER_SECONDARY_PERIPHERAL);
}
#else
void decide_on_dfu(void) {}
#endif /* CONFIG_SPL_BUILD */

static void select_dt_from_module_version(void)
{
	char variant[32];
	char *env_variant = env_get("variant");
	int is_wifi = 0;

	if (IS_ENABLED(CONFIG_TDX_CFG_BLOCK)) {
		/*
		 * If we have a valid config block and it says we are a module with
		 * Wi-Fi/Bluetooth make sure we use the -wifi device tree.
		 */
		is_wifi = (tdx_hw_tag.prodid == VERDIN_AM62Q_WIFI_BT_IT);
	}

	if (is_wifi)
		strlcpy(&variant[0], "wifi", sizeof(variant));
	else
		strlcpy(&variant[0], "nonwifi", sizeof(variant));

	if (strcmp(variant, env_variant)) {
		printf("Setting variant to %s\n", variant);
		env_set("variant", variant);
	}
}

int board_late_init(void)
{
	select_dt_from_module_version();

	/* set bootcmd to start DFU and then UMS mode if booted from DFU */
	decide_on_dfu();

	return 0;
}

#define CTRLMMR_USB0_PHY_CTRL	0x43004008
#define CTRLMMR_USB1_PHY_CTRL	0x43004018
#define CORE_VOLTAGE		0x80000000

#ifdef CONFIG_SPL_BOARD_INIT
void spl_board_init(void)
{
	u32 val;

	/* Set USB0 PHY core voltage to 0.85V */
	val = readl(CTRLMMR_USB0_PHY_CTRL);
	val &= ~(CORE_VOLTAGE);
	writel(val, CTRLMMR_USB0_PHY_CTRL);

	/* Set USB1 PHY core voltage to 0.85V */
	val = readl(CTRLMMR_USB1_PHY_CTRL);
	val &= ~(CORE_VOLTAGE);
	writel(val, CTRLMMR_USB1_PHY_CTRL);

	/* We use the 32k FOUT from the Epson RX8130CE RTC chip */
	/* In WKUP_LFOSC0 clear the power down bit and set the bypass bit
	 * The bypass bit is required as we provide a CMOS clock signal and
	 * the power down seems to be required also in the bypass case
	 * despite of the datasheet stating otherwise
	 */
	/* Compare with the AM62 datasheet,
	 * Table 7-21. LFXOSC Modes of Operation
	 */
	val = readl(MCU_CTRL_LFXOSC_CTRL);
	val &= ~MCU_CTRL_LFXOSC_32K_DISABLE_VAL;
	val |= MCU_CTRL_LFXOSC_32K_BYPASS_VAL;
	writel(val, MCU_CTRL_LFXOSC_CTRL);
	/* Make sure to mux up to take the SoC 32k from the LFOSC input */
	writel(MCU_CTRL_DEVICE_CLKOUT_LFOSC_SELECT_VAL,
	       MCU_CTRL_DEVICE_CLKOUT_32K_CTRL);

	/* Init DRAM size for R5/A53 SPL */
	dram_init_banksize();
}
#endif