board-ingenic.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Support for Ingenic SoCs
  4. *
  5. * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
  6. * Copyright (C) 2011, Maarten ter Huurne <maarten@treewalker.org>
  7. * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
  8. */
  9. #include <linux/clk.h>
  10. #include <linux/of.h>
  11. #include <linux/of_address.h>
  12. #include <linux/of_fdt.h>
  13. #include <linux/pm.h>
  14. #include <linux/sizes.h>
  15. #include <linux/suspend.h>
  16. #include <linux/types.h>
  17. #include <asm/bootinfo.h>
  18. #include <asm/io.h>
  19. #include <asm/machine.h>
  20. #include <asm/reboot.h>
  21. static __init char *ingenic_get_system_type(unsigned long machtype)
  22. {
  23. switch (machtype) {
  24. case MACH_INGENIC_X2100:
  25. return "X2100";
  26. case MACH_INGENIC_X2000H:
  27. return "X2000H";
  28. case MACH_INGENIC_X2000E:
  29. return "X2000E";
  30. case MACH_INGENIC_X2000:
  31. return "X2000";
  32. case MACH_INGENIC_X1830:
  33. return "X1830";
  34. case MACH_INGENIC_X1000E:
  35. return "X1000E";
  36. case MACH_INGENIC_X1000:
  37. return "X1000";
  38. case MACH_INGENIC_JZ4780:
  39. return "JZ4780";
  40. case MACH_INGENIC_JZ4775:
  41. return "JZ4775";
  42. case MACH_INGENIC_JZ4770:
  43. return "JZ4770";
  44. case MACH_INGENIC_JZ4760B:
  45. return "JZ4760B";
  46. case MACH_INGENIC_JZ4760:
  47. return "JZ4760";
  48. case MACH_INGENIC_JZ4755:
  49. return "JZ4755";
  50. case MACH_INGENIC_JZ4750:
  51. return "JZ4750";
  52. case MACH_INGENIC_JZ4725B:
  53. return "JZ4725B";
  54. case MACH_INGENIC_JZ4730:
  55. return "JZ4730";
  56. default:
  57. return "JZ4740";
  58. }
  59. }
  60. #define INGENIC_CGU_BASE 0x10000000
  61. #define JZ4750_CGU_CPCCR_ECS BIT(30)
  62. #define JZ4760_CGU_CPCCR_ECS BIT(31)
  63. static __init void ingenic_force_12M_ext(const void *fdt, unsigned int mask)
  64. {
  65. const __be32 *prop;
  66. unsigned int cpccr;
  67. void __iomem *cgu;
  68. bool use_div;
  69. int offset;
  70. offset = fdt_path_offset(fdt, "/ext");
  71. if (offset < 0)
  72. return;
  73. prop = fdt_getprop(fdt, offset, "clock-frequency", NULL);
  74. if (!prop)
  75. return;
  76. /*
  77. * If the external oscillator is 24 MHz, enable the /2 divider to
  78. * drive it down to 12 MHz, since this is what the hardware can work
  79. * with.
  80. * The 16 MHz cutoff value is arbitrary; setting it to 12 MHz would not
  81. * work as the crystal frequency (as reported in the Device Tree) might
  82. * be slightly above this value.
  83. */
  84. use_div = be32_to_cpup(prop) >= 16000000;
  85. cgu = ioremap(INGENIC_CGU_BASE, 0x4);
  86. if (!cgu)
  87. return;
  88. cpccr = ioread32(cgu);
  89. if (use_div)
  90. cpccr |= mask;
  91. else
  92. cpccr &= ~mask;
  93. iowrite32(cpccr, cgu);
  94. iounmap(cgu);
  95. }
  96. static __init const void *ingenic_fixup_fdt(const void *fdt, const void *match_data)
  97. {
  98. /*
  99. * Old devicetree files for the qi,lb60 board did not have a /memory
  100. * node. Hardcode the memory info here.
  101. */
  102. if (!fdt_node_check_compatible(fdt, 0, "qi,lb60") &&
  103. fdt_path_offset(fdt, "/memory") < 0)
  104. early_init_dt_add_memory_arch(0, SZ_32M);
  105. mips_machtype = (unsigned long)match_data;
  106. system_type = ingenic_get_system_type(mips_machtype);
  107. switch (mips_machtype) {
  108. case MACH_INGENIC_JZ4750:
  109. case MACH_INGENIC_JZ4755:
  110. ingenic_force_12M_ext(fdt, JZ4750_CGU_CPCCR_ECS);
  111. break;
  112. case MACH_INGENIC_JZ4760:
  113. ingenic_force_12M_ext(fdt, JZ4760_CGU_CPCCR_ECS);
  114. break;
  115. default:
  116. break;
  117. }
  118. return fdt;
  119. }
  120. static const struct of_device_id ingenic_of_match[] __initconst = {
  121. { .compatible = "ingenic,jz4730", .data = (void *)MACH_INGENIC_JZ4730 },
  122. { .compatible = "ingenic,jz4740", .data = (void *)MACH_INGENIC_JZ4740 },
  123. { .compatible = "ingenic,jz4725b", .data = (void *)MACH_INGENIC_JZ4725B },
  124. { .compatible = "ingenic,jz4750", .data = (void *)MACH_INGENIC_JZ4750 },
  125. { .compatible = "ingenic,jz4755", .data = (void *)MACH_INGENIC_JZ4755 },
  126. { .compatible = "ingenic,jz4760", .data = (void *)MACH_INGENIC_JZ4760 },
  127. { .compatible = "ingenic,jz4760b", .data = (void *)MACH_INGENIC_JZ4760B },
  128. { .compatible = "ingenic,jz4770", .data = (void *)MACH_INGENIC_JZ4770 },
  129. { .compatible = "ingenic,jz4775", .data = (void *)MACH_INGENIC_JZ4775 },
  130. { .compatible = "ingenic,jz4780", .data = (void *)MACH_INGENIC_JZ4780 },
  131. { .compatible = "ingenic,x1000", .data = (void *)MACH_INGENIC_X1000 },
  132. { .compatible = "ingenic,x1000e", .data = (void *)MACH_INGENIC_X1000E },
  133. { .compatible = "ingenic,x1830", .data = (void *)MACH_INGENIC_X1830 },
  134. { .compatible = "ingenic,x2000", .data = (void *)MACH_INGENIC_X2000 },
  135. { .compatible = "ingenic,x2000e", .data = (void *)MACH_INGENIC_X2000E },
  136. { .compatible = "ingenic,x2000h", .data = (void *)MACH_INGENIC_X2000H },
  137. { .compatible = "ingenic,x2100", .data = (void *)MACH_INGENIC_X2100 },
  138. {}
  139. };
  140. MIPS_MACHINE(ingenic) = {
  141. .matches = ingenic_of_match,
  142. .fixup_fdt = ingenic_fixup_fdt,
  143. };
  144. static void ingenic_wait_instr(void)
  145. {
  146. __asm__(".set push;\n"
  147. ".set mips3;\n"
  148. "wait;\n"
  149. ".set pop;\n"
  150. );
  151. }
  152. static void ingenic_halt(void)
  153. {
  154. for (;;)
  155. ingenic_wait_instr();
  156. }
  157. static int ingenic_pm_enter(suspend_state_t state)
  158. {
  159. ingenic_wait_instr();
  160. return 0;
  161. }
  162. static const struct platform_suspend_ops ingenic_pm_ops = {
  163. .valid = suspend_valid_only_mem,
  164. .enter = ingenic_pm_enter,
  165. };
  166. static int __init ingenic_pm_init(void)
  167. {
  168. if (boot_cpu_type() == CPU_XBURST) {
  169. if (IS_ENABLED(CONFIG_PM_SLEEP))
  170. suspend_set_ops(&ingenic_pm_ops);
  171. _machine_halt = ingenic_halt;
  172. }
  173. return 0;
  174. }
  175. late_initcall(ingenic_pm_init);