// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2022 MediaTek Inc. All rights reserved. * * Author: Weijie Gao */ #include #include #include #include #include #include #include #include #include "launch.h" #include "../mt7621.h" /* Cluster Power Controller (CPC) offsets */ #define CPC_CL_OTHER 0x2010 #define CPC_CO_CMD 0x4000 /* CPC_CL_OTHER fields */ #define CPC_CL_OTHER_CORENUM_SHIFT 16 #define CPC_CL_OTHER_CORENUM GENMASK(23, 16) /* CPC_CO_CMD */ #define PWR_UP 3 #define NUM_CORES 2 #define NUM_CPUS 4 #define WAIT_CPUS_TIMEOUT 4000 static void copy_launch_wait_code(void) { memset((void *)KSEG1, 0, SZ_4K); memcpy((void *)KSEG1ADDR(LAUNCH_WAITCODE), &launch_wait_code_start, &launch_wait_code_end - &launch_wait_code_start); invalidate_dcache_range(KSEG0, SZ_4K); } static void bootup_secondary_core(void) { void __iomem *cpcbase = (void __iomem *)KSEG1ADDR(MIPS_CPC_BASE); int i; for (i = 1; i < NUM_CORES; i++) { writel(i << CPC_CL_OTHER_CORENUM_SHIFT, cpcbase + CPC_CL_OTHER); writel(PWR_UP, cpcbase + CPC_CO_CMD); } } void secondary_cpu_init(void) { void __iomem *sysc = (void __iomem *)KSEG1ADDR(SYSCTL_BASE); u32 i, dual_core = 0, cpuready = 1, cpumask = 0x03; ulong wait_tick; struct cpulaunch_t *c; /* Copy LAUNCH wait code used by other VPEs */ copy_launch_wait_code(); dual_core = readl(sysc + SYSCTL_CHIP_REV_ID_REG) & CPU_ID; if (dual_core) { /* Bootup secondary core for MT7621A */ cpumask = 0x0f; /* Make BootROM/TPL redirect Core1's bootup flow to our entry point */ writel((uintptr_t)&_start, sysc + BOOT_SRAM_BASE_REG); bootup_secondary_core(); } /* Join the coherent domain */ join_coherent_domain(dual_core ? 2 : 1); /* Bootup Core0/VPE1 */ boot_vpe1(); /* Wait for all CPU ready */ wait_tick = get_timer(0) + WAIT_CPUS_TIMEOUT; while (time_before(get_timer(0), wait_tick)) { /* CPU0 is obviously ready */ for (i = 1; i < NUM_CPUS; i++) { c = (struct cpulaunch_t *)(KSEG0ADDR(CPULAUNCH) + (i << LOG2CPULAUNCH)); if (c->flags & LAUNCH_FREADY) cpuready |= BIT(i); } if ((cpuready & cpumask) == cpumask) break; } }