blob: b8099116675459b933b290fd3fda5fd3cd3ecdb3 [file] [log] [blame]
Catalin Marinas9703d9d2012-03-05 11:49:27 +00001/*
2 * Based on arch/arm/kernel/setup.c
3 *
4 * Copyright (C) 1995-2001 Russell King
5 * Copyright (C) 2012 ARM Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/export.h>
21#include <linux/kernel.h>
22#include <linux/stddef.h>
23#include <linux/ioport.h>
24#include <linux/delay.h>
25#include <linux/utsname.h>
26#include <linux/initrd.h>
27#include <linux/console.h>
Catalin Marinasa41dc0e2014-04-03 17:48:54 +010028#include <linux/cache.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000029#include <linux/bootmem.h>
30#include <linux/seq_file.h>
31#include <linux/screen_info.h>
32#include <linux/init.h>
33#include <linux/kexec.h>
34#include <linux/crash_dump.h>
35#include <linux/root_dev.h>
Catalin Marinasde79a642013-02-08 12:18:15 +000036#include <linux/clk-provider.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000037#include <linux/cpu.h>
38#include <linux/interrupt.h>
39#include <linux/smp.h>
40#include <linux/fs.h>
41#include <linux/proc_fs.h>
42#include <linux/memblock.h>
43#include <linux/of_fdt.h>
Catalin Marinasd6bafb92012-12-07 17:47:17 +000044#include <linux/of_platform.h>
Mark Salterf84d0272014-04-15 21:59:30 -040045#include <linux/efi.h>
Mark Rutland44b82b72014-10-24 14:56:40 +010046#include <linux/personality.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000047
Mark Salterbf4b5582014-04-07 15:39:52 -070048#include <asm/fixmap.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010049#include <asm/cpu.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000050#include <asm/cputype.h>
51#include <asm/elf.h>
52#include <asm/cputable.h>
Andre Przywara930da092014-11-14 15:54:07 +000053#include <asm/cpufeature.h>
Mark Rutlande8765b22013-10-24 20:30:17 +010054#include <asm/cpu_ops.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000055#include <asm/sections.h>
56#include <asm/setup.h>
Javi Merino4c7aa002012-08-29 09:47:19 +010057#include <asm/smp_plat.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000058#include <asm/cacheflush.h>
59#include <asm/tlbflush.h>
60#include <asm/traps.h>
61#include <asm/memblock.h>
Will Deacone790f1d2012-12-18 17:53:14 +000062#include <asm/psci.h>
Mark Salterf84d0272014-04-15 21:59:30 -040063#include <asm/efi.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000064
65unsigned int processor_id;
66EXPORT_SYMBOL(processor_id);
67
Steve Capper25804e62013-09-18 16:14:28 +010068unsigned long elf_hwcap __read_mostly;
Catalin Marinas9703d9d2012-03-05 11:49:27 +000069EXPORT_SYMBOL_GPL(elf_hwcap);
70
Sudeep KarkadaNagesha46efe542013-08-13 15:57:53 +010071#ifdef CONFIG_COMPAT
72#define COMPAT_ELF_HWCAP_DEFAULT \
73 (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
74 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
75 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
76 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
Catalin Marinas7d575112014-11-17 10:37:40 +000077 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\
78 COMPAT_HWCAP_LPAE)
Sudeep KarkadaNagesha46efe542013-08-13 15:57:53 +010079unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
Ard Biesheuvel28964d32014-03-03 07:34:45 +000080unsigned int compat_elf_hwcap2 __read_mostly;
Sudeep KarkadaNagesha46efe542013-08-13 15:57:53 +010081#endif
82
Fabio Estevam06f9eb82014-12-04 01:17:01 +000083DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
Andre Przywara930da092014-11-14 15:54:07 +000084
Catalin Marinas9703d9d2012-03-05 11:49:27 +000085static const char *cpu_name;
Catalin Marinas9703d9d2012-03-05 11:49:27 +000086phys_addr_t __fdt_pointer __initdata;
87
88/*
89 * Standard memory resources
90 */
91static struct resource mem_res[] = {
92 {
93 .name = "Kernel code",
94 .start = 0,
95 .end = 0,
96 .flags = IORESOURCE_MEM
97 },
98 {
99 .name = "Kernel data",
100 .start = 0,
101 .end = 0,
102 .flags = IORESOURCE_MEM
103 }
104};
105
106#define kernel_code mem_res[0]
107#define kernel_data mem_res[1]
108
109void __init early_print(const char *str, ...)
110{
111 char buf[256];
112 va_list ap;
113
114 va_start(ap, str);
115 vsnprintf(buf, sizeof(buf), str, ap);
116 va_end(ap);
117
118 printk("%s", buf);
119}
120
Will Deacon71586272013-11-05 18:10:47 +0000121void __init smp_setup_processor_id(void)
122{
Mark Rutland80708672014-11-04 10:50:16 +0000123 u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
124 cpu_logical_map(0) = mpidr;
125
Will Deacon71586272013-11-05 18:10:47 +0000126 /*
127 * clear __my_cpu_offset on boot CPU to avoid hang caused by
128 * using percpu variable early, for example, lockdep will
129 * access percpu variable inside lock_release
130 */
131 set_my_cpu_offset(0);
Mark Rutland80708672014-11-04 10:50:16 +0000132 pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);
Will Deacon71586272013-11-05 18:10:47 +0000133}
134
Sudeep KarkadaNagesha6e15d0e2013-10-21 13:29:42 +0100135bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
136{
137 return phys_id == cpu_logical_map(cpu);
138}
139
Lorenzo Pieralisi976d7d32013-05-16 10:32:09 +0100140struct mpidr_hash mpidr_hash;
141#ifdef CONFIG_SMP
142/**
143 * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
144 * level in order to build a linear index from an
145 * MPIDR value. Resulting algorithm is a collision
146 * free hash carried out through shifting and ORing
147 */
148static void __init smp_build_mpidr_hash(void)
149{
150 u32 i, affinity, fs[4], bits[4], ls;
151 u64 mask = 0;
152 /*
153 * Pre-scan the list of MPIDRS and filter out bits that do
154 * not contribute to affinity levels, ie they never toggle.
155 */
156 for_each_possible_cpu(i)
157 mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
158 pr_debug("mask of set bits %#llx\n", mask);
159 /*
160 * Find and stash the last and first bit set at all affinity levels to
161 * check how many bits are required to represent them.
162 */
163 for (i = 0; i < 4; i++) {
164 affinity = MPIDR_AFFINITY_LEVEL(mask, i);
165 /*
166 * Find the MSB bit and LSB bits position
167 * to determine how many bits are required
168 * to express the affinity level.
169 */
170 ls = fls(affinity);
171 fs[i] = affinity ? ffs(affinity) - 1 : 0;
172 bits[i] = ls - fs[i];
173 }
174 /*
175 * An index can be created from the MPIDR_EL1 by isolating the
176 * significant bits at each affinity level and by shifting
177 * them in order to compress the 32 bits values space to a
178 * compressed set of values. This is equivalent to hashing
179 * the MPIDR_EL1 through shifting and ORing. It is a collision free
180 * hash though not minimal since some levels might contain a number
181 * of CPUs that is not an exact power of 2 and their bit
182 * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}.
183 */
184 mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0];
185 mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0];
186 mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] -
187 (bits[1] + bits[0]);
188 mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) +
189 fs[3] - (bits[2] + bits[1] + bits[0]);
190 mpidr_hash.mask = mask;
191 mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0];
192 pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n",
193 mpidr_hash.shift_aff[0],
194 mpidr_hash.shift_aff[1],
195 mpidr_hash.shift_aff[2],
196 mpidr_hash.shift_aff[3],
197 mpidr_hash.mask,
198 mpidr_hash.bits);
199 /*
200 * 4x is an arbitrary value used to warn on a hash table much bigger
201 * than expected on most systems.
202 */
203 if (mpidr_hash_size() > 4 * num_possible_cpus())
204 pr_warn("Large number of MPIDR hash buckets detected\n");
205 __flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash));
206}
207#endif
208
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000209static void __init setup_processor(void)
210{
211 struct cpu_info *cpu_info;
Steve Capper4bff28c2013-12-16 21:04:36 +0000212 u64 features, block;
Catalin Marinasa41dc0e2014-04-03 17:48:54 +0100213 u32 cwg;
214 int cls;
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000215
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000216 cpu_info = lookup_processor_type(read_cpuid_id());
217 if (!cpu_info) {
218 printk("CPU configuration botched (ID %08x), unable to continue.\n",
219 read_cpuid_id());
220 while (1);
221 }
222
223 cpu_name = cpu_info->cpu_name;
224
225 printk("CPU: %s [%08x] revision %d\n",
226 cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
227
Will Deacon94ed1f22013-10-11 14:52:11 +0100228 sprintf(init_utsname()->machine, ELF_PLATFORM);
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000229 elf_hwcap = 0;
Steve Capper4bff28c2013-12-16 21:04:36 +0000230
Mark Rutlanddf857412014-07-16 16:32:44 +0100231 cpuinfo_store_boot_cpu();
232
Steve Capper4bff28c2013-12-16 21:04:36 +0000233 /*
Catalin Marinasa41dc0e2014-04-03 17:48:54 +0100234 * Check for sane CTR_EL0.CWG value.
235 */
236 cwg = cache_type_cwg();
237 cls = cache_line_size();
238 if (!cwg)
239 pr_warn("No Cache Writeback Granule information, assuming cache line size %d\n",
240 cls);
241 if (L1_CACHE_BYTES < cls)
242 pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n",
243 L1_CACHE_BYTES, cls);
244
245 /*
Steve Capper4bff28c2013-12-16 21:04:36 +0000246 * ID_AA64ISAR0_EL1 contains 4-bit wide signed feature blocks.
247 * The blocks we test below represent incremental functionality
248 * for non-negative values. Negative values are reserved.
249 */
250 features = read_cpuid(ID_AA64ISAR0_EL1);
251 block = (features >> 4) & 0xf;
252 if (!(block & 0x8)) {
253 switch (block) {
254 default:
255 case 2:
256 elf_hwcap |= HWCAP_PMULL;
257 case 1:
258 elf_hwcap |= HWCAP_AES;
259 case 0:
260 break;
261 }
262 }
263
264 block = (features >> 8) & 0xf;
265 if (block && !(block & 0x8))
266 elf_hwcap |= HWCAP_SHA1;
267
268 block = (features >> 12) & 0xf;
269 if (block && !(block & 0x8))
270 elf_hwcap |= HWCAP_SHA2;
271
272 block = (features >> 16) & 0xf;
273 if (block && !(block & 0x8))
274 elf_hwcap |= HWCAP_CRC32;
Ard Biesheuvel4cf761c2014-03-03 07:34:46 +0000275
276#ifdef CONFIG_COMPAT
277 /*
278 * ID_ISAR5_EL1 carries similar information as above, but pertaining to
279 * the Aarch32 32-bit execution state.
280 */
281 features = read_cpuid(ID_ISAR5_EL1);
282 block = (features >> 4) & 0xf;
283 if (!(block & 0x8)) {
284 switch (block) {
285 default:
286 case 2:
287 compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL;
288 case 1:
289 compat_elf_hwcap2 |= COMPAT_HWCAP2_AES;
290 case 0:
291 break;
292 }
293 }
294
295 block = (features >> 8) & 0xf;
296 if (block && !(block & 0x8))
297 compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1;
298
299 block = (features >> 12) & 0xf;
300 if (block && !(block & 0x8))
301 compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2;
302
303 block = (features >> 16) & 0xf;
304 if (block && !(block & 0x8))
305 compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32;
306#endif
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000307}
308
309static void __init setup_machine_fdt(phys_addr_t dt_phys)
310{
Rob Herringd5189cc2013-08-26 10:14:32 -0500311 if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) {
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000312 early_print("\n"
313 "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
Rob Herringd5189cc2013-08-26 10:14:32 -0500314 "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000315 "\nPlease check your bootloader.\n",
Rob Herringd5189cc2013-08-26 10:14:32 -0500316 dt_phys, phys_to_virt(dt_phys));
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000317
318 while (true)
319 cpu_relax();
320 }
Will Deacon5e399772014-09-01 15:47:19 +0100321
Mark Rutland44b82b72014-10-24 14:56:40 +0100322 dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000323}
324
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000325/*
326 * Limit the memory size that was specified via FDT.
327 */
328static int __init early_mem(char *p)
329{
330 phys_addr_t limit;
331
332 if (!p)
333 return 1;
334
335 limit = memparse(p, &p) & PAGE_MASK;
336 pr_notice("Memory limited to %lldMB\n", limit >> 20);
337
338 memblock_enforce_memory_limit(limit);
339
340 return 0;
341}
342early_param("mem", early_mem);
343
344static void __init request_standard_resources(void)
345{
346 struct memblock_region *region;
347 struct resource *res;
348
349 kernel_code.start = virt_to_phys(_text);
350 kernel_code.end = virt_to_phys(_etext - 1);
351 kernel_data.start = virt_to_phys(_sdata);
352 kernel_data.end = virt_to_phys(_end - 1);
353
354 for_each_memblock(memory, region) {
355 res = alloc_bootmem_low(sizeof(*res));
356 res->name = "System RAM";
357 res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
358 res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
359 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
360
361 request_resource(&iomem_resource, res);
362
363 if (kernel_code.start >= res->start &&
364 kernel_code.end <= res->end)
365 request_resource(res, &kernel_code);
366 if (kernel_data.start >= res->start &&
367 kernel_data.end <= res->end)
368 request_resource(res, &kernel_data);
369 }
370}
371
Javi Merino4c7aa002012-08-29 09:47:19 +0100372u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
373
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000374void __init setup_arch(char **cmdline_p)
375{
376 setup_processor();
377
378 setup_machine_fdt(__fdt_pointer);
379
380 init_mm.start_code = (unsigned long) _text;
381 init_mm.end_code = (unsigned long) _etext;
382 init_mm.end_data = (unsigned long) _edata;
383 init_mm.brk = (unsigned long) _end;
384
385 *cmdline_p = boot_command_line;
386
Laura Abbottaf86e592014-11-21 21:50:42 +0000387 early_fixmap_init();
Mark Salterbf4b5582014-04-07 15:39:52 -0700388 early_ioremap_init();
Mark Salter0bf757c2014-04-07 15:39:51 -0700389
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000390 parse_early_param();
391
Jon Masters7a9c43b2014-08-26 21:23:38 +0100392 /*
393 * Unmask asynchronous aborts after bringing up possible earlycon.
394 * (Report possible System Errors once we can report this occurred)
395 */
396 local_async_enable();
397
Mark Salterf84d0272014-04-15 21:59:30 -0400398 efi_init();
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000399 arm64_memblock_init();
400
401 paging_init();
402 request_standard_resources();
403
Mark Salterf84d0272014-04-15 21:59:30 -0400404 efi_idmap_init();
405
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000406 unflatten_device_tree();
407
Will Deacone790f1d2012-12-18 17:53:14 +0000408 psci_init();
409
Mark Rutlande8765b22013-10-24 20:30:17 +0100410 cpu_read_bootcpu_ops();
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000411#ifdef CONFIG_SMP
412 smp_init_cpus();
Lorenzo Pieralisi976d7d32013-05-16 10:32:09 +0100413 smp_build_mpidr_hash();
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000414#endif
415
416#ifdef CONFIG_VT
417#if defined(CONFIG_VGA_CONSOLE)
418 conswitchp = &vga_con;
419#elif defined(CONFIG_DUMMY_CONSOLE)
420 conswitchp = &dummy_con;
421#endif
422#endif
423}
424
Catalin Marinasc560ecf2013-05-14 10:51:18 +0100425static int __init arm64_device_init(void)
Catalin Marinasde79a642013-02-08 12:18:15 +0000426{
Catalin Marinasc560ecf2013-05-14 10:51:18 +0100427 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
Catalin Marinasde79a642013-02-08 12:18:15 +0000428 return 0;
429}
Catalin Marinas6ecba8e2014-04-25 15:31:45 +0100430arch_initcall_sync(arm64_device_init);
Catalin Marinasde79a642013-02-08 12:18:15 +0000431
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000432static int __init topology_init(void)
433{
434 int i;
435
436 for_each_possible_cpu(i) {
Mark Rutlanddf857412014-07-16 16:32:44 +0100437 struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000438 cpu->hotpluggable = 1;
439 register_cpu(cpu, i);
440 }
441
442 return 0;
443}
444subsys_initcall(topology_init);
445
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000446static const char *hwcap_str[] = {
447 "fp",
448 "asimd",
Sudeep KarkadaNagesha46efe542013-08-13 15:57:53 +0100449 "evtstrm",
Steve Capper4bff28c2013-12-16 21:04:36 +0000450 "aes",
451 "pmull",
452 "sha1",
453 "sha2",
454 "crc32",
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000455 NULL
456};
457
Mark Rutland44b82b72014-10-24 14:56:40 +0100458#ifdef CONFIG_COMPAT
459static const char *compat_hwcap_str[] = {
460 "swp",
461 "half",
462 "thumb",
463 "26bit",
464 "fastmult",
465 "fpa",
466 "vfp",
467 "edsp",
468 "java",
469 "iwmmxt",
470 "crunch",
471 "thumbee",
472 "neon",
473 "vfpv3",
474 "vfpv3d16",
475 "tls",
476 "vfpv4",
477 "idiva",
478 "idivt",
479 "vfpd32",
480 "lpae",
481 "evtstrm"
482};
483
484static const char *compat_hwcap2_str[] = {
485 "aes",
486 "pmull",
487 "sha1",
488 "sha2",
489 "crc32",
490 NULL
491};
492#endif /* CONFIG_COMPAT */
493
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000494static int c_show(struct seq_file *m, void *v)
495{
Mark Rutland44b82b72014-10-24 14:56:40 +0100496 int i, j;
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000497
498 for_each_online_cpu(i) {
Mark Rutland44b82b72014-10-24 14:56:40 +0100499 struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
500 u32 midr = cpuinfo->reg_midr;
501
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000502 /*
503 * glibc reads /proc/cpuinfo to determine the number of
504 * online processors, looking for lines beginning with
505 * "processor". Give glibc what it expects.
506 */
507#ifdef CONFIG_SMP
508 seq_printf(m, "processor\t: %d\n", i);
509#endif
Mark Rutland44b82b72014-10-24 14:56:40 +0100510
511 /*
512 * Dump out the common processor features in a single line.
513 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
514 * rather than attempting to parse this, but there's a body of
515 * software which does already (at least for 32-bit).
516 */
517 seq_puts(m, "Features\t:");
518 if (personality(current->personality) == PER_LINUX32) {
519#ifdef CONFIG_COMPAT
520 for (j = 0; compat_hwcap_str[j]; j++)
521 if (compat_elf_hwcap & (1 << j))
522 seq_printf(m, " %s", compat_hwcap_str[j]);
523
524 for (j = 0; compat_hwcap2_str[j]; j++)
525 if (compat_elf_hwcap2 & (1 << j))
526 seq_printf(m, " %s", compat_hwcap2_str[j]);
527#endif /* CONFIG_COMPAT */
528 } else {
529 for (j = 0; hwcap_str[j]; j++)
530 if (elf_hwcap & (1 << j))
531 seq_printf(m, " %s", hwcap_str[j]);
532 }
533 seq_puts(m, "\n");
534
535 seq_printf(m, "CPU implementer\t: 0x%02x\n",
536 MIDR_IMPLEMENTOR(midr));
537 seq_printf(m, "CPU architecture: 8\n");
538 seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
539 seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
540 seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000541 }
542
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000543 return 0;
544}
545
546static void *c_start(struct seq_file *m, loff_t *pos)
547{
548 return *pos < 1 ? (void *)1 : NULL;
549}
550
551static void *c_next(struct seq_file *m, void *v, loff_t *pos)
552{
553 ++*pos;
554 return NULL;
555}
556
557static void c_stop(struct seq_file *m, void *v)
558{
559}
560
561const struct seq_operations cpuinfo_op = {
562 .start = c_start,
563 .next = c_next,
564 .stop = c_stop,
565 .show = c_show
566};