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