Merge tag 'arc-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
[linux-2.6-microblaze.git] / arch / mips / generic / board-ingenic.c
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
10 #include <linux/clk.h>
11 #include <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/of_fdt.h>
14 #include <linux/pm.h>
15 #include <linux/sizes.h>
16 #include <linux/suspend.h>
17 #include <linux/types.h>
18
19 #include <asm/bootinfo.h>
20 #include <asm/machine.h>
21 #include <asm/reboot.h>
22
23 static __init char *ingenic_get_system_type(unsigned long machtype)
24 {
25         switch (machtype) {
26         case MACH_INGENIC_X2100:
27                 return "X2100";
28         case MACH_INGENIC_X2000H:
29                 return "X2000H";
30         case MACH_INGENIC_X2000E:
31                 return "X2000E";
32         case MACH_INGENIC_X2000:
33                 return "X2000";
34         case MACH_INGENIC_X1830:
35                 return "X1830";
36         case MACH_INGENIC_X1000E:
37                 return "X1000E";
38         case MACH_INGENIC_X1000:
39                 return "X1000";
40         case MACH_INGENIC_JZ4780:
41                 return "JZ4780";
42         case MACH_INGENIC_JZ4775:
43                 return "JZ4775";
44         case MACH_INGENIC_JZ4770:
45                 return "JZ4770";
46         case MACH_INGENIC_JZ4760B:
47                 return "JZ4760B";
48         case MACH_INGENIC_JZ4760:
49                 return "JZ4760";
50         case MACH_INGENIC_JZ4755:
51                 return "JZ4755";
52         case MACH_INGENIC_JZ4750:
53                 return "JZ4750";
54         case MACH_INGENIC_JZ4725B:
55                 return "JZ4725B";
56         case MACH_INGENIC_JZ4730:
57                 return "JZ4730";
58         default:
59                 return "JZ4740";
60         }
61 }
62
63 static __init const void *ingenic_fixup_fdt(const void *fdt, const void *match_data)
64 {
65         /*
66          * Old devicetree files for the qi,lb60 board did not have a /memory
67          * node. Hardcode the memory info here.
68          */
69         if (!fdt_node_check_compatible(fdt, 0, "qi,lb60") &&
70             fdt_path_offset(fdt, "/memory") < 0)
71                 early_init_dt_add_memory_arch(0, SZ_32M);
72
73         mips_machtype = (unsigned long)match_data;
74         system_type = ingenic_get_system_type(mips_machtype);
75
76         return fdt;
77 }
78
79 static const struct of_device_id ingenic_of_match[] __initconst = {
80         { .compatible = "ingenic,jz4730", .data = (void *)MACH_INGENIC_JZ4730 },
81         { .compatible = "ingenic,jz4740", .data = (void *)MACH_INGENIC_JZ4740 },
82         { .compatible = "ingenic,jz4725b", .data = (void *)MACH_INGENIC_JZ4725B },
83         { .compatible = "ingenic,jz4750", .data = (void *)MACH_INGENIC_JZ4750 },
84         { .compatible = "ingenic,jz4755", .data = (void *)MACH_INGENIC_JZ4755 },
85         { .compatible = "ingenic,jz4760", .data = (void *)MACH_INGENIC_JZ4760 },
86         { .compatible = "ingenic,jz4760b", .data = (void *)MACH_INGENIC_JZ4760B },
87         { .compatible = "ingenic,jz4770", .data = (void *)MACH_INGENIC_JZ4770 },
88         { .compatible = "ingenic,jz4775", .data = (void *)MACH_INGENIC_JZ4775 },
89         { .compatible = "ingenic,jz4780", .data = (void *)MACH_INGENIC_JZ4780 },
90         { .compatible = "ingenic,x1000", .data = (void *)MACH_INGENIC_X1000 },
91         { .compatible = "ingenic,x1000e", .data = (void *)MACH_INGENIC_X1000E },
92         { .compatible = "ingenic,x1830", .data = (void *)MACH_INGENIC_X1830 },
93         { .compatible = "ingenic,x2000", .data = (void *)MACH_INGENIC_X2000 },
94         { .compatible = "ingenic,x2000e", .data = (void *)MACH_INGENIC_X2000E },
95         { .compatible = "ingenic,x2000h", .data = (void *)MACH_INGENIC_X2000H },
96         { .compatible = "ingenic,x2100", .data = (void *)MACH_INGENIC_X2100 },
97         {}
98 };
99
100 MIPS_MACHINE(ingenic) = {
101         .matches = ingenic_of_match,
102         .fixup_fdt = ingenic_fixup_fdt,
103 };
104
105 static void ingenic_wait_instr(void)
106 {
107         __asm__(".set push;\n"
108                 ".set mips3;\n"
109                 "wait;\n"
110                 ".set pop;\n"
111         );
112 }
113
114 static void ingenic_halt(void)
115 {
116         for (;;)
117                 ingenic_wait_instr();
118 }
119
120 static int __maybe_unused ingenic_pm_enter(suspend_state_t state)
121 {
122         ingenic_wait_instr();
123
124         return 0;
125 }
126
127 static const struct platform_suspend_ops ingenic_pm_ops __maybe_unused = {
128         .valid = suspend_valid_only_mem,
129         .enter = ingenic_pm_enter,
130 };
131
132 static int __init ingenic_pm_init(void)
133 {
134         struct device_node *cpu_node;
135         struct clk *cpu0_clk;
136         int ret;
137
138         if (boot_cpu_type() == CPU_XBURST) {
139                 if (IS_ENABLED(CONFIG_PM_SLEEP))
140                         suspend_set_ops(&ingenic_pm_ops);
141                 _machine_halt = ingenic_halt;
142
143                 /*
144                  * Unconditionally enable the clock for the first CPU.
145                  * This makes sure that the PLL that feeds the CPU won't be
146                  * stopped while the kernel is running.
147                  */
148                 cpu_node = of_get_cpu_node(0, NULL);
149                 if (!cpu_node) {
150                         pr_err("Unable to get CPU node\n");
151                 } else {
152                         cpu0_clk = of_clk_get(cpu_node, 0);
153                         if (IS_ERR(cpu0_clk)) {
154                                 pr_err("Unable to get CPU0 clock\n");
155                                 return PTR_ERR(cpu0_clk);
156                         }
157
158                         ret = clk_prepare_enable(cpu0_clk);
159                         if (ret) {
160                                 pr_err("Unable to enable CPU0 clock\n");
161                                 return ret;
162                         }
163                 }
164         }
165
166         return 0;
167
168 }
169 late_initcall(ingenic_pm_init);