diff options
Diffstat (limited to 'arch/mips/bmips/setup.c')
| -rw-r--r-- | arch/mips/bmips/setup.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index e95b3f78e7cd..2572fd49a6e9 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -16,7 +16,6 @@ #include <linux/of.h> #include <linux/of_clk.h> #include <linux/of_fdt.h> -#include <linux/of_platform.h> #include <linux/libfdt.h> #include <linux/smp.h> #include <asm/addrspace.h> @@ -35,6 +34,15 @@ #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c)) #define BCM6328_TP1_DISABLED BIT(9) +/* + * CBR addr doesn't change and we can cache it. + * For broken SoC/Bootloader CBR addr might also be provided via DT + * with "brcm,bmips-cbr-reg" in the "cpus" node. + */ +void __iomem *bmips_cbr_addr __read_mostly; + +extern bool bmips_rac_flush_disable; + static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000; struct bmips_quirk { @@ -104,6 +112,13 @@ static void bcm6358_quirks(void) * disable SMP for now */ bmips_smp_enabled = 0; + + /* + * RAC flush causes kernel panics on BCM6358 when booting from TP1 + * because the bootloader is not initializing it properly. + */ + bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31)) || + !!bmips_cbr_addr; } static void bcm6368_quirks(void) @@ -136,6 +151,8 @@ static void __init bmips_init_cfe(void) void __init prom_init(void) { + /* Cache CBR addr before CPU/DMA setup */ + bmips_cbr_addr = BMIPS_GET_CBR(); bmips_init_cfe(); bmips_cpu_setup(); register_bmips_smp_ops(); @@ -170,7 +187,10 @@ void __init plat_mem_setup(void) ioport_resource.start = 0; ioport_resource.end = ~0; - /* intended to somewhat resemble ARM; see Documentation/arm/booting.rst */ + /* + * intended to somewhat resemble ARM; see + * Documentation/arch/arm/booting.rst + */ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) dtb = phys_to_virt(fw_arg2); else @@ -192,13 +212,35 @@ void __init plat_mem_setup(void) void __init device_tree_init(void) { struct device_node *np; + u32 addr; unflatten_and_copy_device_tree(); /* Disable SMP boot unless both CPUs are listed in DT and !disabled */ np = of_find_node_by_name(NULL, "cpus"); - if (np && of_get_available_child_count(np) <= 1) + if (!np) + return; + + if (of_get_available_child_count(np) <= 1) bmips_smp_enabled = 0; + + /* Check if DT provide a CBR address */ + if (of_property_read_u32(np, "brcm,bmips-cbr-reg", &addr)) + goto exit; + + /* Make sure CBR address is outside DRAM window */ + if (addr >= (u32)memblock_start_of_DRAM() && + addr < (u32)memblock_end_of_DRAM()) { + WARN(1, "DT CBR %x inside DRAM window. Ignoring DT CBR.\n", + addr); + goto exit; + } + + bmips_cbr_addr = (void __iomem *)addr; + /* Since CBR is provided by DT, enable RAC flush */ + bmips_rac_flush_disable = false; + +exit: of_node_put(np); } |
