linux/arch/mips/generic/init.c
<<
>>
Prefs
   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}
 204