12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2eed0eabdSPaul Burton /* 3eed0eabdSPaul Burton * Copyright (C) 2016 Imagination Technologies 448c834beSPaul Burton * Author: Paul Burton <paul.burton@mips.com> 5eed0eabdSPaul Burton */ 6eed0eabdSPaul Burton 7eed0eabdSPaul Burton #include <linux/clk.h> 8eed0eabdSPaul Burton #include <linux/clocksource.h> 9eed0eabdSPaul Burton #include <linux/init.h> 10eed0eabdSPaul Burton #include <linux/irqchip.h> 11089a792cSGeert Uytterhoeven #include <linux/of_clk.h> 12eed0eabdSPaul Burton #include <linux/of_fdt.h> 13eed0eabdSPaul Burton 14b47e9c62SPaul Burton #include <asm/bootinfo.h> 15eed0eabdSPaul Burton #include <asm/fw/fw.h> 16eed0eabdSPaul Burton #include <asm/irq_cpu.h> 17eed0eabdSPaul Burton #include <asm/machine.h> 187f005f11SMatt Redfearn #include <asm/mips-cps.h> 19eed0eabdSPaul Burton #include <asm/prom.h> 20eed0eabdSPaul Burton #include <asm/smp-ops.h> 21eed0eabdSPaul Burton #include <asm/time.h> 22eed0eabdSPaul Burton 23a14bf1dcSTiezhu Yang static __initconst const void *fdt; 24a14bf1dcSTiezhu Yang static __initconst const struct mips_machine *mach; 25a14bf1dcSTiezhu Yang static __initconst const void *mach_match_data; 26eed0eabdSPaul Burton 27eed0eabdSPaul Burton void __init prom_init(void) 28eed0eabdSPaul Burton { 299a59061cSMatt Redfearn plat_get_fdt(); 309a59061cSMatt Redfearn BUG_ON(!fdt); 319a59061cSMatt Redfearn } 329a59061cSMatt Redfearn 339a59061cSMatt Redfearn void __init *plat_get_fdt(void) 349a59061cSMatt Redfearn { 35eed0eabdSPaul Burton const struct mips_machine *check_mach; 36eed0eabdSPaul Burton const struct of_device_id *match; 37eed0eabdSPaul Burton 389a59061cSMatt Redfearn if (fdt) 399a59061cSMatt Redfearn /* Already set up */ 409a59061cSMatt Redfearn return (void *)fdt; 419a59061cSMatt Redfearn 42323690d2SPaul Cercueil if (fw_passed_dtb && !fdt_check_header((void *)fw_passed_dtb)) { 43eed0eabdSPaul Burton /* 44323690d2SPaul Cercueil * We have been provided with the appropriate device tree for 45323690d2SPaul Cercueil * the board. Make use of it & search for any machine struct 46323690d2SPaul Cercueil * based upon the root compatible string. 47eed0eabdSPaul Burton */ 4867eebf72SMarcin Nowakowski fdt = (void *)fw_passed_dtb; 49eed0eabdSPaul Burton 50eed0eabdSPaul Burton for_each_mips_machine(check_mach) { 51eed0eabdSPaul Burton match = mips_machine_is_compatible(check_mach, fdt); 52eed0eabdSPaul Burton if (match) { 53eed0eabdSPaul Burton mach = check_mach; 54eed0eabdSPaul Burton mach_match_data = match->data; 55eed0eabdSPaul Burton break; 56eed0eabdSPaul Burton } 57eed0eabdSPaul Burton } 58eed0eabdSPaul Burton } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) { 59eed0eabdSPaul Burton /* 60eed0eabdSPaul Burton * We weren't booted using the UHI boot protocol, but do 61eed0eabdSPaul Burton * support some number of boards with legacy boot protocols. 62eed0eabdSPaul Burton * Attempt to find the right one. 63eed0eabdSPaul Burton */ 64eed0eabdSPaul Burton for_each_mips_machine(check_mach) { 65eed0eabdSPaul Burton if (!check_mach->detect) 66eed0eabdSPaul Burton continue; 67eed0eabdSPaul Burton 68eed0eabdSPaul Burton if (!check_mach->detect()) 69eed0eabdSPaul Burton continue; 70eed0eabdSPaul Burton 71eed0eabdSPaul Burton mach = check_mach; 72eed0eabdSPaul Burton } 73eed0eabdSPaul Burton 74eed0eabdSPaul Burton /* 75eed0eabdSPaul Burton * If we don't recognise the machine then we can't continue, so 76eed0eabdSPaul Burton * die here. 77eed0eabdSPaul Burton */ 78eed0eabdSPaul Burton BUG_ON(!mach); 79eed0eabdSPaul Burton 80eed0eabdSPaul Burton /* Retrieve the machine's FDT */ 81eed0eabdSPaul Burton fdt = mach->fdt; 82eed0eabdSPaul Burton } 83eed0eabdSPaul Burton return (void *)fdt; 84eed0eabdSPaul Burton } 85eed0eabdSPaul Burton 86b47e9c62SPaul Burton #ifdef CONFIG_RELOCATABLE 87b47e9c62SPaul Burton 880063fdedSMarcin Nowakowski void __init plat_fdt_relocated(void *new_location) 890063fdedSMarcin Nowakowski { 900063fdedSMarcin Nowakowski /* 910063fdedSMarcin Nowakowski * reset fdt as the cached value would point to the location 920063fdedSMarcin Nowakowski * before relocations happened and update the location argument 930063fdedSMarcin Nowakowski * if it was passed using UHI 940063fdedSMarcin Nowakowski */ 950063fdedSMarcin Nowakowski fdt = NULL; 960063fdedSMarcin Nowakowski 970063fdedSMarcin Nowakowski if (fw_arg0 == -2) 980063fdedSMarcin Nowakowski fw_arg1 = (unsigned long)new_location; 990063fdedSMarcin Nowakowski } 1000063fdedSMarcin Nowakowski 101b47e9c62SPaul Burton #endif /* CONFIG_RELOCATABLE */ 102b47e9c62SPaul Burton 103eed0eabdSPaul Burton void __init plat_mem_setup(void) 104eed0eabdSPaul Burton { 105eed0eabdSPaul Burton if (mach && mach->fixup_fdt) 106eed0eabdSPaul Burton fdt = mach->fixup_fdt(fdt, mach_match_data); 107eed0eabdSPaul Burton 10813a0ea28SPaul Cercueil fw_init_cmdline(); 109eed0eabdSPaul Burton __dt_setup_arch((void *)fdt); 110eed0eabdSPaul Burton } 111eed0eabdSPaul Burton 112eed0eabdSPaul Burton void __init device_tree_init(void) 113eed0eabdSPaul Burton { 114eed0eabdSPaul Burton int err; 115eed0eabdSPaul Burton 116eed0eabdSPaul Burton unflatten_and_copy_device_tree(); 117eed0eabdSPaul Burton mips_cpc_probe(); 118eed0eabdSPaul Burton 119eed0eabdSPaul Burton err = register_cps_smp_ops(); 120eed0eabdSPaul Burton if (err) 121eed0eabdSPaul Burton err = register_up_smp_ops(); 122eed0eabdSPaul Burton } 123eed0eabdSPaul Burton 124e889dfcaSPaul Burton int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size, 125e889dfcaSPaul Burton const void *fdt_in, 126e889dfcaSPaul Burton const struct mips_fdt_fixup *fixups) 127e889dfcaSPaul Burton { 128e889dfcaSPaul Burton int err; 129e889dfcaSPaul Burton 130e889dfcaSPaul Burton err = fdt_open_into(fdt_in, fdt_out, fdt_out_size); 131e889dfcaSPaul Burton if (err) { 132e889dfcaSPaul Burton pr_err("Failed to open FDT\n"); 133e889dfcaSPaul Burton return err; 134e889dfcaSPaul Burton } 135e889dfcaSPaul Burton 136e889dfcaSPaul Burton for (; fixups->apply; fixups++) { 137e889dfcaSPaul Burton err = fixups->apply(fdt_out); 138e889dfcaSPaul Burton if (err) { 139e889dfcaSPaul Burton pr_err("Failed to apply FDT fixup \"%s\"\n", 140e889dfcaSPaul Burton fixups->description); 141e889dfcaSPaul Burton return err; 142e889dfcaSPaul Burton } 143e889dfcaSPaul Burton } 144e889dfcaSPaul Burton 145e889dfcaSPaul Burton err = fdt_pack(fdt_out); 146e889dfcaSPaul Burton if (err) 147e889dfcaSPaul Burton pr_err("Failed to pack FDT\n"); 148e889dfcaSPaul Burton return err; 149e889dfcaSPaul Burton } 150e889dfcaSPaul Burton 151eed0eabdSPaul Burton void __init plat_time_init(void) 152eed0eabdSPaul Burton { 153eed0eabdSPaul Burton struct device_node *np; 154eed0eabdSPaul Burton struct clk *clk; 155eed0eabdSPaul Burton 156eed0eabdSPaul Burton of_clk_init(NULL); 157eed0eabdSPaul Burton 158eed0eabdSPaul Burton if (!cpu_has_counter) { 159eed0eabdSPaul Burton mips_hpt_frequency = 0; 160eed0eabdSPaul Burton } else if (mach && mach->measure_hpt_freq) { 161eed0eabdSPaul Burton mips_hpt_frequency = mach->measure_hpt_freq(); 162eed0eabdSPaul Burton } else { 163eed0eabdSPaul Burton np = of_get_cpu_node(0, NULL); 164eed0eabdSPaul Burton if (!np) { 165eed0eabdSPaul Burton pr_err("Failed to get CPU node\n"); 166eed0eabdSPaul Burton return; 167eed0eabdSPaul Burton } 168eed0eabdSPaul Burton 169eed0eabdSPaul Burton clk = of_clk_get(np, 0); 170eed0eabdSPaul Burton if (IS_ERR(clk)) { 171eed0eabdSPaul Burton pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); 172eed0eabdSPaul Burton return; 173eed0eabdSPaul Burton } 174eed0eabdSPaul Burton 175eed0eabdSPaul Burton mips_hpt_frequency = clk_get_rate(clk); 176eed0eabdSPaul Burton clk_put(clk); 177eed0eabdSPaul Burton 178eed0eabdSPaul Burton switch (boot_cpu_type()) { 179eed0eabdSPaul Burton case CPU_20KC: 180eed0eabdSPaul Burton case CPU_25KF: 181eed0eabdSPaul Burton /* The counter runs at the CPU clock rate */ 182eed0eabdSPaul Burton break; 183eed0eabdSPaul Burton default: 184eed0eabdSPaul Burton /* The counter runs at half the CPU clock rate */ 185eed0eabdSPaul Burton mips_hpt_frequency /= 2; 186eed0eabdSPaul Burton break; 187eed0eabdSPaul Burton } 188eed0eabdSPaul Burton } 189eed0eabdSPaul Burton 190ba5d08c0SDaniel Lezcano timer_probe(); 191eed0eabdSPaul Burton } 192eed0eabdSPaul Burton 193eed0eabdSPaul Burton void __init arch_init_irq(void) 194eed0eabdSPaul Burton { 195eed0eabdSPaul Burton struct device_node *intc_node; 196eed0eabdSPaul Burton 197eed0eabdSPaul Burton intc_node = of_find_compatible_node(NULL, NULL, 198eed0eabdSPaul Burton "mti,cpu-interrupt-controller"); 199eed0eabdSPaul Burton if (!cpu_has_veic && !intc_node) 200eed0eabdSPaul Burton mips_cpu_irq_init(); 20128ec2238SNicholas Mc Guire of_node_put(intc_node); 202eed0eabdSPaul Burton 203eed0eabdSPaul Burton irqchip_init(); 204eed0eabdSPaul Burton } 205eed0eabdSPaul Burton 206eed0eabdSPaul Burton void __init prom_free_prom_memory(void) 207eed0eabdSPaul Burton { 208eed0eabdSPaul Burton } 209