blob: 37c20a5f564009de9c702a8002d1fb430d456174 [file] [log] [blame]
developer2fddd722022-05-20 11:22:21 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2022 MediaTek Inc. All rights reserved.
4 *
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
6 */
7
8#include <asm/io.h>
9#include <asm/cm.h>
10#include <asm/sections.h>
11#include <asm/addrspace.h>
12#include <asm/mipsmtregs.h>
13#include <linux/sizes.h>
14#include <time.h>
15#include <cpu_func.h>
16#include "launch.h"
17#include "../mt7621.h"
18
19/* Cluster Power Controller (CPC) offsets */
20#define CPC_CL_OTHER 0x2010
21#define CPC_CO_CMD 0x4000
22
23/* CPC_CL_OTHER fields */
24#define CPC_CL_OTHER_CORENUM_SHIFT 16
25#define CPC_CL_OTHER_CORENUM GENMASK(23, 16)
26
27/* CPC_CO_CMD */
28#define PWR_UP 3
29
30#define NUM_CORES 2
31#define NUM_CPUS 4
32#define WAIT_CPUS_TIMEOUT 4000
33
34static void copy_launch_wait_code(void)
35{
36 memset((void *)KSEG1, 0, SZ_4K);
37
38 memcpy((void *)KSEG1ADDR(LAUNCH_WAITCODE),
39 &launch_wait_code_start,
40 &launch_wait_code_end - &launch_wait_code_start);
41
42 invalidate_dcache_range(KSEG0, SZ_4K);
43}
44
45static void bootup_secondary_core(void)
46{
47 void __iomem *cpcbase = (void __iomem *)KSEG1ADDR(MIPS_CPC_BASE);
48 int i;
49
50 for (i = 1; i < NUM_CORES; i++) {
51 writel(i << CPC_CL_OTHER_CORENUM_SHIFT, cpcbase + CPC_CL_OTHER);
52 writel(PWR_UP, cpcbase + CPC_CO_CMD);
53 }
54}
55
56void secondary_cpu_init(void)
57{
58 void __iomem *sysc = (void __iomem *)KSEG1ADDR(SYSCTL_BASE);
59 u32 i, dual_core = 0, cpuready = 1, cpumask = 0x03;
60 ulong wait_tick;
61 struct cpulaunch_t *c;
62
63 /* Copy LAUNCH wait code used by other VPEs */
64 copy_launch_wait_code();
65
66 dual_core = readl(sysc + SYSCTL_CHIP_REV_ID_REG) & CPU_ID;
67
68 if (dual_core) {
69 /* Bootup secondary core for MT7621A */
70 cpumask = 0x0f;
71
72 /* Make BootROM/TPL redirect Core1's bootup flow to our entry point */
73 writel((uintptr_t)&_start, sysc + BOOT_SRAM_BASE_REG);
74
75 bootup_secondary_core();
76 }
77
78 /* Join the coherent domain */
79 join_coherent_domain(dual_core ? 2 : 1);
80
81 /* Bootup Core0/VPE1 */
82 boot_vpe1();
83
84 /* Wait for all CPU ready */
85 wait_tick = get_timer(0) + WAIT_CPUS_TIMEOUT;
86
87 while (time_before(get_timer(0), wait_tick)) {
88 /* CPU0 is obviously ready */
89 for (i = 1; i < NUM_CPUS; i++) {
90 c = (struct cpulaunch_t *)(KSEG0ADDR(CPULAUNCH) +
91 (i << LOG2CPULAUNCH));
92
93 if (c->flags & LAUNCH_FREADY)
94 cpuready |= BIT(i);
95 }
96
97 if ((cpuready & cpumask) == cpumask)
98 break;
99 }
100}