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/clk-provider.h>
   9#include <linux/clocksource.h>
  10#include <linux/init.h>
  11#include <linux/irqchip.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        if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_passed_dtb)) {
  43                /*
  44                 * We booted using the UHI boot protocol, so we have been
  45                 * provided with the appropriate device tree for the board.
  46                 * Make use of it & search for any machine struct based upon
  47                 * the root compatible string.
  48                 */
  49                fdt = (void *)fw_passed_dtb;
  50
  51                for_each_mips_machine(check_mach) {
  52                        match = mips_machine_is_compatible(check_mach, fdt);
  53                        if (match) {
  54                                mach = check_mach;
  55                                mach_match_data = match->data;
  56                                break;
  57                        }
  58                }
  59        } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) {
  60                /*
  61                 * We weren't booted using the UHI boot protocol, but do
  62                 * support some number of boards with legacy boot protocols.
  63                 * Attempt to find the right one.
  64                 */
  65                for_each_mips_machine(check_mach) {
  66                        if (!check_mach->detect)
  67                                continue;
  68
  69                        if (!check_mach->detect())
  70                                continue;
  71
  72                        mach = check_mach;
  73                }
  74
  75                /*
  76                 * If we don't recognise the machine then we can't continue, so
  77                 * die here.
  78                 */
  79                BUG_ON(!mach);
  80
  81                /* Retrieve the machine's FDT */
  82                fdt = mach->fdt;
  83        }
  84        return (void *)fdt;
  85}
  86
  87#ifdef CONFIG_RELOCATABLE
  88
  89void __init plat_fdt_relocated(void *new_location)
  90{
  91        /*
  92         * reset fdt as the cached value would point to the location
  93         * before relocations happened and update the location argument
  94         * if it was passed using UHI
  95         */
  96        fdt = NULL;
  97
  98        if (fw_arg0 == -2)
  99                fw_arg1 = (unsigned long)new_location;
 100}
 101
 102#endif /* CONFIG_RELOCATABLE */
 103
 104void __init plat_mem_setup(void)
 105{
 106        if (mach && mach->fixup_fdt)
 107                fdt = mach->fixup_fdt(fdt, mach_match_data);
 108
 109        strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
 110        __dt_setup_arch((void *)fdt);
 111}
 112
 113void __init device_tree_init(void)
 114{
 115        int err;
 116
 117        unflatten_and_copy_device_tree();
 118        mips_cpc_probe();
 119
 120        err = register_cps_smp_ops();
 121        if (err)
 122                err = register_up_smp_ops();
 123}
 124
 125int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size,
 126                                 const void *fdt_in,
 127                                 const struct mips_fdt_fixup *fixups)
 128{
 129        int err;
 130
 131        err = fdt_open_into(fdt_in, fdt_out, fdt_out_size);
 132        if (err) {
 133                pr_err("Failed to open FDT\n");
 134                return err;
 135        }
 136
 137        for (; fixups->apply; fixups++) {
 138                err = fixups->apply(fdt_out);
 139                if (err) {
 140                        pr_err("Failed to apply FDT fixup \"%s\"\n",
 141                               fixups->description);
 142                        return err;
 143                }
 144        }
 145
 146        err = fdt_pack(fdt_out);
 147        if (err)
 148                pr_err("Failed to pack FDT\n");
 149        return err;
 150}
 151
 152void __init plat_time_init(void)
 153{
 154        struct device_node *np;
 155        struct clk *clk;
 156
 157        of_clk_init(NULL);
 158
 159        if (!cpu_has_counter) {
 160                mips_hpt_frequency = 0;
 161        } else if (mach && mach->measure_hpt_freq) {
 162                mips_hpt_frequency = mach->measure_hpt_freq();
 163        } else {
 164                np = of_get_cpu_node(0, NULL);
 165                if (!np) {
 166                        pr_err("Failed to get CPU node\n");
 167                        return;
 168                }
 169
 170                clk = of_clk_get(np, 0);
 171                if (IS_ERR(clk)) {
 172                        pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
 173                        return;
 174                }
 175
 176                mips_hpt_frequency = clk_get_rate(clk);
 177                clk_put(clk);
 178
 179                switch (boot_cpu_type()) {
 180                case CPU_20KC:
 181                case CPU_25KF:
 182                        /* The counter runs at the CPU clock rate */
 183                        break;
 184                default:
 185                        /* The counter runs at half the CPU clock rate */
 186                        mips_hpt_frequency /= 2;
 187                        break;
 188                }
 189        }
 190
 191        timer_probe();
 192}
 193
 194void __init arch_init_irq(void)
 195{
 196        struct device_node *intc_node;
 197
 198        intc_node = of_find_compatible_node(NULL, NULL,
 199                                            "mti,cpu-interrupt-controller");
 200        if (!cpu_has_veic && !intc_node)
 201                mips_cpu_irq_init();
 202        of_node_put(intc_node);
 203
 204        irqchip_init();
 205}
 206
 207void __init prom_free_prom_memory(void)
 208{
 209}
 210