1 /* 2 * Copyright (C) 2016 Imagination Technologies 3 * Author: Paul Burton <paul.burton@imgtec.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 */ 10 11 #include <linux/clk.h> 12 #include <linux/clk-provider.h> 13 #include <linux/clocksource.h> 14 #include <linux/init.h> 15 #include <linux/irqchip.h> 16 #include <linux/of_fdt.h> 17 #include <linux/of_platform.h> 18 19 #include <asm/fw/fw.h> 20 #include <asm/irq_cpu.h> 21 #include <asm/machine.h> 22 #include <asm/mips-cpc.h> 23 #include <asm/prom.h> 24 #include <asm/smp-ops.h> 25 #include <asm/time.h> 26 27 static __initdata const void *fdt; 28 static __initdata const struct mips_machine *mach; 29 static __initdata const void *mach_match_data; 30 31 void __init prom_init(void) 32 { 33 const struct mips_machine *check_mach; 34 const struct of_device_id *match; 35 36 if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) { 37 /* 38 * We booted using the UHI boot protocol, so we have been 39 * provided with the appropriate device tree for the board. 40 * Make use of it & search for any machine struct based upon 41 * the root compatible string. 42 */ 43 fdt = (void *)fw_arg1; 44 45 for_each_mips_machine(check_mach) { 46 match = mips_machine_is_compatible(check_mach, fdt); 47 if (match) { 48 mach = check_mach; 49 mach_match_data = match->data; 50 break; 51 } 52 } 53 } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) { 54 /* 55 * We weren't booted using the UHI boot protocol, but do 56 * support some number of boards with legacy boot protocols. 57 * Attempt to find the right one. 58 */ 59 for_each_mips_machine(check_mach) { 60 if (!check_mach->detect) 61 continue; 62 63 if (!check_mach->detect()) 64 continue; 65 66 mach = check_mach; 67 } 68 69 /* 70 * If we don't recognise the machine then we can't continue, so 71 * die here. 72 */ 73 BUG_ON(!mach); 74 75 /* Retrieve the machine's FDT */ 76 fdt = mach->fdt; 77 } 78 79 BUG_ON(!fdt); 80 } 81 82 void __init *plat_get_fdt(void) 83 { 84 return (void *)fdt; 85 } 86 87 void __init plat_mem_setup(void) 88 { 89 if (mach && mach->fixup_fdt) 90 fdt = mach->fixup_fdt(fdt, mach_match_data); 91 92 strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); 93 __dt_setup_arch((void *)fdt); 94 } 95 96 void __init device_tree_init(void) 97 { 98 int err; 99 100 unflatten_and_copy_device_tree(); 101 mips_cpc_probe(); 102 103 err = register_cps_smp_ops(); 104 if (err) 105 err = register_up_smp_ops(); 106 } 107 108 void __init plat_time_init(void) 109 { 110 struct device_node *np; 111 struct clk *clk; 112 113 of_clk_init(NULL); 114 115 if (!cpu_has_counter) { 116 mips_hpt_frequency = 0; 117 } else if (mach && mach->measure_hpt_freq) { 118 mips_hpt_frequency = mach->measure_hpt_freq(); 119 } else { 120 np = of_get_cpu_node(0, NULL); 121 if (!np) { 122 pr_err("Failed to get CPU node\n"); 123 return; 124 } 125 126 clk = of_clk_get(np, 0); 127 if (IS_ERR(clk)) { 128 pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); 129 return; 130 } 131 132 mips_hpt_frequency = clk_get_rate(clk); 133 clk_put(clk); 134 135 switch (boot_cpu_type()) { 136 case CPU_20KC: 137 case CPU_25KF: 138 /* The counter runs at the CPU clock rate */ 139 break; 140 default: 141 /* The counter runs at half the CPU clock rate */ 142 mips_hpt_frequency /= 2; 143 break; 144 } 145 } 146 147 clocksource_probe(); 148 } 149 150 void __init arch_init_irq(void) 151 { 152 struct device_node *intc_node; 153 154 intc_node = of_find_compatible_node(NULL, NULL, 155 "mti,cpu-interrupt-controller"); 156 if (!cpu_has_veic && !intc_node) 157 mips_cpu_irq_init(); 158 159 irqchip_init(); 160 } 161 162 static int __init publish_devices(void) 163 { 164 if (!of_have_populated_dt()) 165 panic("Device-tree not present"); 166 167 if (of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)) 168 panic("Failed to populate DT"); 169 170 return 0; 171 } 172 arch_initcall(publish_devices); 173 174 void __init prom_free_prom_memory(void) 175 { 176 } 177