difos/target/linux/realtek/files-6.12/arch/mips/rtl838x/prom.c
Markus Stockhausen e124859587 realtek: 6.12: relocate R4K deactivation to late CPU init
To avoid unneeded interrupts the R4K timer is deactivated during
secondary cpu initialization. This is currently done during
phase init_secondary(). With the upgrade to 6.12 the kernel runs
a primary/secondary cpu timer/counter synchronization to verify the
proper setup in synchronise_count_slave(). That runs at a later
point in time and expects the secondary counter to be fully
functional. Finding a deactivated counter results in the following
messages:

WARNING: CPU: 1 PID: 0 at arch/mips/kernel/sync-r4k.c:99 check_counter_warp+0x220/0x254
Warning: zero counter calibration delta: 0 [max: 6500000]
Counter synchronization [CPU#0 -> CPU#1]:
Measured 278760029 cycles counter warp between CPUs

Relocate the deactivation to smp_finsh() at the end of the cpu
startup sequence. Additionally polish the startup code and remove
all unneeded parts.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/18935
Signed-off-by: Robert Marko <robimarko@gmail.com>
2025-06-11 22:27:22 +02:00

228 lines
5.1 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* prom.c
* Early intialization code for the Realtek RTL838X SoC
*
* based on the original BSP by
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
* Copyright (C) 2020 B. Koblitz
*
*/
#include <asm/fw/fw.h>
#include <asm/mips-cps.h>
#include <asm/prom.h>
#include <asm/smp-ops.h>
#include <mach-rtl83xx.h>
struct rtl83xx_soc_info soc_info;
const void *fdt;
#ifdef CONFIG_MIPS_MT_SMP
extern const struct plat_smp_ops vsmp_smp_ops;
static struct plat_smp_ops rtlops;
static void rtlsmp_init_secondary(void)
{
/*
* Enable all CPU interrupts, as everything is managed by the external controller.
* TODO: Standard vsmp_init_secondary() has special treatment for Malta if external
* GIC is available. Maybe we need this too.
*/
if (mips_gic_present())
pr_warn("%s: GIC present. Maybe interrupt enabling required.\n", __func__);
else
set_c0_status(ST0_IM);
}
static void rtlsmp_finish(void)
{
/* These devices are low on resources. There might be the chance that CEVT_R4K is
* not enabled in kernel build. Nevertheless the timer and interrupt 7 might be
* active by default after startup of secondary VPE. With no registered handler
* that leads to continuous unhandeled interrupts. In this case disable counting
* (DC) in the core and confirm a pending interrupt.
*/
if (!IS_ENABLED(CONFIG_CEVT_R4K)) {
write_c0_cause(read_c0_cause() | CAUSEF_DC);
write_c0_compare(0);
}
local_irq_enable();
}
static int rtlsmp_register(void)
{
if (!cpu_has_mipsmt)
return 1;
rtlops = vsmp_smp_ops;
rtlops.init_secondary = rtlsmp_init_secondary;
rtlops.smp_finish = rtlsmp_finish;
register_smp_ops(&rtlops);
return 0;
}
#else /* !CONFIG_MIPS_MT_SMP */
#define rtlsmp_register() (1)
#endif
void __init device_tree_init(void)
{
if (!fdt_check_header(&__appended_dtb)) {
fdt = &__appended_dtb;
pr_info("Using appended Device Tree.\n");
}
initial_boot_params = (void *)fdt;
unflatten_and_copy_device_tree();
/* delay cpc & smp probing to allow devicetree access */
mips_cpc_probe();
if (!register_cps_smp_ops())
return;
if (!rtlsmp_register())
return;
register_up_smp_ops();
}
const char *get_system_type(void)
{
return soc_info.name;
}
static void __init identify_rtl9302(void)
{
switch (sw_r32(RTL93XX_MODEL_NAME_INFO) & 0xfffffff0) {
case 0x93020810:
soc_info.name = "RTL9302A 12x2.5G";
break;
case 0x93021010:
soc_info.name = "RTL9302B 8x2.5G";
break;
case 0x93021810:
soc_info.name = "RTL9302C 16x2.5G";
break;
case 0x93022010:
soc_info.name = "RTL9302D 24x2.5G";
break;
case 0x93020800:
soc_info.name = "RTL9302A";
break;
case 0x93021000:
soc_info.name = "RTL9302B";
break;
case 0x93021800:
soc_info.name = "RTL9302C";
break;
case 0x93022000:
soc_info.name = "RTL9302D";
break;
case 0x93023001:
soc_info.name = "RTL9302F";
break;
default:
soc_info.name = "RTL9302";
}
}
void __init prom_init(void)
{
uint32_t model;
model = sw_r32(RTL838X_MODEL_NAME_INFO);
pr_info("RTL838X model is %x\n", model);
model = model >> 16 & 0xFFFF;
if ((model != 0x8328) && (model != 0x8330) && (model != 0x8332)
&& (model != 0x8380) && (model != 0x8382)) {
model = sw_r32(RTL839X_MODEL_NAME_INFO);
pr_info("RTL839X model is %x\n", model);
model = model >> 16 & 0xFFFF;
}
if ((model & 0x8390) != 0x8380 && (model & 0x8390) != 0x8390) {
model = sw_r32(RTL93XX_MODEL_NAME_INFO);
pr_info("RTL93XX model is %x\n", model);
model = model >> 16 & 0xFFFF;
}
soc_info.id = model;
switch (model) {
case 0x8328:
soc_info.name = "RTL8328";
soc_info.family = RTL8328_FAMILY_ID;
break;
case 0x8332:
soc_info.name = "RTL8332";
soc_info.family = RTL8380_FAMILY_ID;
break;
case 0x8380:
soc_info.name = "RTL8380";
soc_info.family = RTL8380_FAMILY_ID;
break;
case 0x8382:
soc_info.name = "RTL8382";
soc_info.family = RTL8380_FAMILY_ID;
break;
case 0x8390:
soc_info.name = "RTL8390";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x8391:
soc_info.name = "RTL8391";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x8392:
soc_info.name = "RTL8392";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x8393:
soc_info.name = "RTL8393";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x9301:
soc_info.name = "RTL9301";
soc_info.family = RTL9300_FAMILY_ID;
break;
case 0x9302:
identify_rtl9302();
soc_info.family = RTL9300_FAMILY_ID;
break;
case 0x9303:
soc_info.name = "RTL9303";
soc_info.family = RTL9300_FAMILY_ID;
break;
case 0x9311:
soc_info.name = "RTL9311";
soc_info.family = RTL9310_FAMILY_ID;
break;
case 0x9313:
soc_info.name = "RTL9313";
soc_info.family = RTL9310_FAMILY_ID;
break;
default:
soc_info.name = "DEFAULT";
soc_info.family = 0;
}
pr_info("SoC Type: %s\n", get_system_type());
/*
* fw_arg2 is be the pointer to the environment. Some devices (e.g. HP JG924A) hand
* over other than expected kernel boot arguments. Something like 0xfffdffff looks
* suspicous. Do extra cleanup for fw_init_cmdline() to avoid a hang during boot.
*/
if (fw_arg2 >= CKSEG2)
fw_arg2 = 0;
fw_init_cmdline();
}