at v5.16 4.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2016 Imagination Technologies 4 * Author: Paul Burton <paul.burton@mips.com> 5 */ 6 7#include <linux/clk.h> 8#include <linux/clocksource.h> 9#include <linux/init.h> 10#include <linux/irqchip.h> 11#include <linux/of_clk.h> 12#include <linux/of_fdt.h> 13 14#include <asm/bootinfo.h> 15#include <asm/fw/fw.h> 16#include <asm/irq_cpu.h> 17#include <asm/machine.h> 18#include <asm/mips-cps.h> 19#include <asm/prom.h> 20#include <asm/smp-ops.h> 21#include <asm/time.h> 22 23static __initconst const void *fdt; 24static __initconst const struct mips_machine *mach; 25static __initconst const void *mach_match_data; 26 27void __init prom_init(void) 28{ 29 plat_get_fdt(); 30 BUG_ON(!fdt); 31} 32 33void __init *plat_get_fdt(void) 34{ 35 const struct mips_machine *check_mach; 36 const struct of_device_id *match; 37 38 if (fdt) 39 /* Already set up */ 40 return (void *)fdt; 41 42 fdt = (void *)get_fdt(); 43 if (fdt && !fdt_check_header(fdt)) { 44 /* 45 * We have been provided with the appropriate device tree for 46 * the board. Make use of it & search for any machine struct 47 * based upon the root compatible string. 48 */ 49 for_each_mips_machine(check_mach) { 50 match = mips_machine_is_compatible(check_mach, fdt); 51 if (match) { 52 mach = check_mach; 53 mach_match_data = match->data; 54 break; 55 } 56 } 57 } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) { 58 /* 59 * We weren't booted using the UHI boot protocol, but do 60 * support some number of boards with legacy boot protocols. 61 * Attempt to find the right one. 62 */ 63 for_each_mips_machine(check_mach) { 64 if (!check_mach->detect) 65 continue; 66 67 if (!check_mach->detect()) 68 continue; 69 70 mach = check_mach; 71 } 72 73 /* 74 * If we don't recognise the machine then we can't continue, so 75 * die here. 76 */ 77 BUG_ON(!mach); 78 79 /* Retrieve the machine's FDT */ 80 fdt = mach->fdt; 81 } 82 return (void *)fdt; 83} 84 85#ifdef CONFIG_RELOCATABLE 86 87void __init plat_fdt_relocated(void *new_location) 88{ 89 /* 90 * reset fdt as the cached value would point to the location 91 * before relocations happened and update the location argument 92 * if it was passed using UHI 93 */ 94 fdt = NULL; 95 96 if (fw_arg0 == -2) 97 fw_arg1 = (unsigned long)new_location; 98} 99 100#endif /* CONFIG_RELOCATABLE */ 101 102void __init plat_mem_setup(void) 103{ 104 if (mach && mach->fixup_fdt) 105 fdt = mach->fixup_fdt(fdt, mach_match_data); 106 107 fw_init_cmdline(); 108 __dt_setup_arch((void *)fdt); 109} 110 111void __init device_tree_init(void) 112{ 113 int err; 114 115 unflatten_and_copy_device_tree(); 116 mips_cpc_probe(); 117 118 err = register_cps_smp_ops(); 119 if (err) 120 err = register_up_smp_ops(); 121} 122 123int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size, 124 const void *fdt_in, 125 const struct mips_fdt_fixup *fixups) 126{ 127 int err; 128 129 err = fdt_open_into(fdt_in, fdt_out, fdt_out_size); 130 if (err) { 131 pr_err("Failed to open FDT\n"); 132 return err; 133 } 134 135 for (; fixups->apply; fixups++) { 136 err = fixups->apply(fdt_out); 137 if (err) { 138 pr_err("Failed to apply FDT fixup \"%s\"\n", 139 fixups->description); 140 return err; 141 } 142 } 143 144 err = fdt_pack(fdt_out); 145 if (err) 146 pr_err("Failed to pack FDT\n"); 147 return err; 148} 149 150void __init plat_time_init(void) 151{ 152 struct device_node *np; 153 struct clk *clk; 154 155 of_clk_init(NULL); 156 157 if (!cpu_has_counter) { 158 mips_hpt_frequency = 0; 159 } else if (mach && mach->measure_hpt_freq) { 160 mips_hpt_frequency = mach->measure_hpt_freq(); 161 } else { 162 np = of_get_cpu_node(0, NULL); 163 if (!np) { 164 pr_err("Failed to get CPU node\n"); 165 return; 166 } 167 168 clk = of_clk_get(np, 0); 169 if (IS_ERR(clk)) { 170 pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); 171 return; 172 } 173 174 mips_hpt_frequency = clk_get_rate(clk); 175 clk_put(clk); 176 177 switch (boot_cpu_type()) { 178 case CPU_20KC: 179 case CPU_25KF: 180 /* The counter runs at the CPU clock rate */ 181 break; 182 default: 183 /* The counter runs at half the CPU clock rate */ 184 mips_hpt_frequency /= 2; 185 break; 186 } 187 } 188 189 timer_probe(); 190} 191 192void __init arch_init_irq(void) 193{ 194 struct device_node *intc_node; 195 196 intc_node = of_find_compatible_node(NULL, NULL, 197 "mti,cpu-interrupt-controller"); 198 if (!cpu_has_veic && !intc_node) 199 mips_cpu_irq_init(); 200 of_node_put(intc_node); 201 202 irqchip_init(); 203}