init.c 4.6 KB

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