init.c 4.1 KB

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