1 /*
2 * Copyright (c) 2025-2026, Texas Instruments Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch.h>
8 #include <arch_helpers.h>
9 #include <common/bl_common.h>
10 #include <common/debug.h>
11 #include <errno.h>
12 #include <lib/mmio.h>
13 #include <lib/xlat_tables/xlat_tables_v2.h>
14 #include <ti_sci_transport.h>
15
16 #include <am62l_ddrss.h>
17 #include <board_config.h>
18 #include <cps_drv_lpddr4.h>
19 #include <k3_console.h>
20 #include <plat_private.h>
21 #include <platform_def.h>
22 #include <plat/common/platform.h>
23
24 #define WKUP_BOOT_MODE (0x43010030)
25 #define MAIN_PLL_MMR_BASE (0x04060000UL)
26 /*
27 * PLL8 is distinct from PLL0 (which drives DDR at 2 GHz VCO).
28 * PLL8 drives the A53 cores and has a VCO frequency of 2.5 GHz.
29 * HSDIV0 of PLL8 feeds the A53 cluster.
30 */
31 #define MAIN_PLL_MMR_CFG_PLL8_HSDIV_CTRL0 (0x00008080UL)
32 /* bit 15: enable HSDIV0 clock output */
33 #define MAIN_PLL8_HSDIV0_CLKOUT_EN GENMASK(15, 15)
34 /* bits [6:0]: divider value; output = VCO_FREQ / (div + 1) */
35 #define MAIN_PLL8_HSDIV0_DIV_MASK GENMASK(6, 0)
36 /* div=1 → 2.5 GHz / 2 = 1.25 GHz */
37 #define MAIN_PLL8_HSDIV0_1250MHZ (MAIN_PLL8_HSDIV0_CLKOUT_EN | U(1))
38 /* div=2 → 2.5 GHz / 3 = 833.33 MHz */
39 #define MAIN_PLL8_HSDIV0_833MHZ (MAIN_PLL8_HSDIV0_CLKOUT_EN | U(2))
40 #define BL1_DONE_MSG_ID (0x810A)
41 #define BL1_HANDOFF_MAGIC_NUM (0x11112222)
42 #define BL1_MSG_SIZE_FLAG (0x0c000000)
43
44 #define DEVSTAT_PRIMARY_BOOTMODE_MASK GENMASK(6, 3)
45 #define DEVSTAT_PRIMARY_BOOTMODE_SHIFT (3)
46 #define BOOT_DEVICE_MMC (0x08)
47 #define WKUP_JTAG_DEVICE_ID (WKUP_CTRL_MMR0_BASE + 0x18)
48 #define JTAG_DEV_SPEED_MASK GENMASK(10, 6)
49 #define JTAG_DEV_SPEED_SHIFT (6)
50
51 #define AM62L3_EFUSE_E_MPU_OPP 5
52 #define AM62L3_EFUSE_O_MPU_OPP 15
53
54 const mmap_region_t plat_k3_mmap[] = {
55 K3_MAP_REGION_FLAT(0, PLAT_PHY_ADDR_SPACE_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
56 { /* sentinel */ }
57 };
58
59 /**
60 * Handoff message for 2nd stage boot
61 *
62 * @cmdid: The command ID
63 * @hostid: Identifies the queue number used for replies to a received message
64 * @sizeandflags: Flags in LSB 3 bytes and the MSB byte set to size.
65 * @magicnum: Magic number for payload validation.
66 * @rsvd: Reserved word.
67 * @imageoffset: Image offset for block/image mode.
68 * @filename: File name for filesystem mode.
69 */
70 struct a53_rom_msg {
71 uint16_t cmdid;
72 uint8_t hostid;
73 uint8_t seqnum;
74 uint32_t sizeandflags;
75 uint32_t magicnum;
76 uint32_t rsvd;
77 union {
78 uint32_t imageoffset[4];
79 char filename[32];
80 } imagelocator;
81 } __packed;
82
bl1_plat_sec_mem_layout(void)83 meminfo_t *bl1_plat_sec_mem_layout(void)
84 {
85 /*
86 * AM62L BL1 never loads BL2: after DDR init it signals the ROM via
87 * the secure transport and enters WFI (see k3_bl1_handoff / bl1_platform_setup).
88 * Returning NULL is intentional — the BL2 load path is never reached.
89 */
90 return NULL;
91 }
92
bl1_early_platform_setup(void)93 void bl1_early_platform_setup(void)
94 {
95 uint32_t device_id;
96 uint32_t speed_grade;
97
98 #if DEBUG
99 ERROR("AM62L k3low BL1: DEBUG builds are not supported on this platform!\n");
100 panic();
101 #endif
102
103 board_init();
104 /* Read OPN and set the A53 clock rate */
105 device_id = mmio_read_32(WKUP_JTAG_DEVICE_ID);
106 speed_grade = (device_id & JTAG_DEV_SPEED_MASK) >>
107 JTAG_DEV_SPEED_SHIFT;
108 if (speed_grade == AM62L3_EFUSE_O_MPU_OPP) {
109 /* PLL8_HSDIV0 feeds A53, set to 1.25 GHz (PLL8 VCO = 2.5 GHz) */
110 mmio_write_32(MAIN_PLL_MMR_BASE + MAIN_PLL_MMR_CFG_PLL8_HSDIV_CTRL0,
111 MAIN_PLL8_HSDIV0_1250MHZ);
112 } else {
113 /* PLL8_HSDIV0 feeds A53, set to 833.33 MHz (PLL8 VCO = 2.5 GHz) */
114 mmio_write_32(MAIN_PLL_MMR_BASE + MAIN_PLL_MMR_CFG_PLL8_HSDIV_CTRL0,
115 MAIN_PLL8_HSDIV0_833MHZ);
116 }
117 }
118
bl1_plat_arch_setup(void)119 void bl1_plat_arch_setup(void)
120 {
121 INFO("K3 BL1 arch setup\n");
122
123 const mmap_region_t bl_regions[] = {
124 MAP_REGION_FLAT(BL1_RO_BASE,
125 BL_RO_DATA_BASE - BL1_RO_BASE,
126 MT_CODE | MT_SECURE),
127 MAP_REGION_FLAT(BL_RO_DATA_BASE,
128 BL1_RW_BASE - BL_RO_DATA_BASE,
129 MT_MEMORY | MT_RO | MT_SECURE),
130 MAP_REGION_FLAT(BL1_RW_BASE,
131 BL1_RW_LIMIT - BL1_RW_BASE,
132 MT_MEMORY | MT_RW | MT_SECURE),
133 { /* sentinel */ }
134 };
135
136 setup_page_tables(bl_regions, plat_k3_mmap);
137 enable_mmu_el3(0);
138 }
139
k3_bl1_handoff(void)140 static void __dead2 k3_bl1_handoff(void)
141 {
142 struct a53_rom_msg a53_rom_msg_obj = { 0 };
143 struct ti_sci_msg msg;
144 volatile uint32_t devstat;
145 uint32_t boot_mode;
146
147 a53_rom_msg_obj.cmdid = BL1_DONE_MSG_ID;
148 a53_rom_msg_obj.sizeandflags = BL1_MSG_SIZE_FLAG;
149 a53_rom_msg_obj.magicnum = BL1_HANDOFF_MAGIC_NUM;
150
151 devstat = mmio_read_32(WKUP_BOOT_MODE);
152 boot_mode = (devstat & DEVSTAT_PRIMARY_BOOTMODE_MASK) >>
153 DEVSTAT_PRIMARY_BOOTMODE_SHIFT;
154
155 switch (boot_mode) {
156 case BOOT_DEVICE_MMC:
157 /*
158 * snprintf writes into a char[] member of a __packed struct.
159 * The pointer is naturally byte-aligned so the access is safe,
160 * but GCC still warns about address-of-packed-member.
161 */
162 #pragma GCC diagnostic push
163 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
164 snprintf(a53_rom_msg_obj.imagelocator.filename,
165 sizeof(a53_rom_msg_obj.imagelocator.filename),
166 "%s%s", "\\", "tispl.bin");
167 #pragma GCC diagnostic pop
168 break;
169 default:
170 a53_rom_msg_obj.imagelocator.imageoffset[0] = K3_SPL_IMG_OFFSET;
171 break;
172 }
173
174 msg.buf = (uint8_t *)&a53_rom_msg_obj;
175 msg.len = sizeof(a53_rom_msg_obj);
176 ti_sci_transport_send(TX_SECURE_TRANSPORT_CHANNEL_ID, &msg);
177 NOTICE("ENTERING WFI - end of bl1\n");
178 console_flush();
179 while (true)
180 wfi();
181 }
182
bl1_platform_setup(void)183 void bl1_platform_setup(void)
184 {
185 /*
186 * AM62L uses a non-standard BL1 flow: instead of loading BL2, BL1
187 * initialises DDR, then calls k3_bl1_handoff() which sends a message
188 * to the ROM over the secure transport and enters WFI. This function
189 * therefore never returns; the BL2 load path in the generic BL1 code
190 * is dead for this platform.
191 */
192 if (am62l_lpddr4_init() != 0) {
193 ERROR("DDR init failed\n");
194 panic();
195 } else {
196 NOTICE("DDR init done\n");
197 k3_bl1_handoff();
198 }
199 }
200
platform_mem_init(void)201 void platform_mem_init(void)
202 {
203 }
204
plat_get_image_source(unsigned int image_id,uintptr_t * dev_handle,uintptr_t * image_spec)205 int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
206 uintptr_t *image_spec)
207 {
208 return -ENOTSUP;
209 }
210