~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/generic/board-ingenic.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php