| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  *  linux/arch/h8300/kernel/setup.c | 
 |  * | 
 |  *  Copyright (C) 2001-2014 Yoshinori Sato <ysato@users.sourceforge.jp> | 
 |  */ | 
 |  | 
 | /* | 
 |  * This file handles the architecture-dependent parts of system setup | 
 |  */ | 
 |  | 
 | #include <linux/kernel.h> | 
 | #include <linux/sched.h> | 
 | #include <linux/delay.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/mm.h> | 
 | #include <linux/fs.h> | 
 | #include <linux/console.h> | 
 | #include <linux/errno.h> | 
 | #include <linux/string.h> | 
 | #include <linux/bootmem.h> | 
 | #include <linux/seq_file.h> | 
 | #include <linux/init.h> | 
 | #include <linux/of.h> | 
 | #include <linux/of_fdt.h> | 
 | #include <linux/of_address.h> | 
 | #include <linux/clk-provider.h> | 
 | #include <linux/memblock.h> | 
 | #include <linux/screen_info.h> | 
 | #include <linux/clocksource.h> | 
 |  | 
 | #include <asm/setup.h> | 
 | #include <asm/irq.h> | 
 | #include <asm/pgtable.h> | 
 | #include <asm/sections.h> | 
 | #include <asm/page.h> | 
 |  | 
 | #if defined(CONFIG_CPU_H8300H) | 
 | #define CPU "H8/300H" | 
 | #elif defined(CONFIG_CPU_H8S) | 
 | #define CPU "H8S" | 
 | #else | 
 | #define CPU "Unknown" | 
 | #endif | 
 |  | 
 | unsigned long memory_start; | 
 | unsigned long memory_end; | 
 | EXPORT_SYMBOL(memory_end); | 
 | static unsigned long freq; | 
 | extern char __dtb_start[]; | 
 |  | 
 | #ifdef CONFIG_VT | 
 | struct screen_info screen_info; | 
 | #endif | 
 |  | 
 | char __initdata command_line[COMMAND_LINE_SIZE]; | 
 |  | 
 | void sim_console_register(void); | 
 |  | 
 | void __init h8300_fdt_init(void *fdt, char *bootargs) | 
 | { | 
 | 	if (!fdt) | 
 | 		fdt = __dtb_start; | 
 | 	else | 
 | 		strcpy(command_line, bootargs); | 
 |  | 
 | 	early_init_dt_scan(fdt); | 
 | 	memblock_allow_resize(); | 
 | } | 
 |  | 
 | static void __init bootmem_init(void) | 
 | { | 
 | 	struct memblock_region *region; | 
 |  | 
 | 	memory_end = memory_start = 0; | 
 |  | 
 | 	/* Find main memory where is the kernel */ | 
 | 	for_each_memblock(memory, region) { | 
 | 		memory_start = region->base; | 
 | 		memory_end = region->base + region->size; | 
 | 	} | 
 |  | 
 | 	if (!memory_end) | 
 | 		panic("No memory!"); | 
 |  | 
 | 	/* setup bootmem globals (we use no_bootmem, but mm still depends on this) */ | 
 | 	min_low_pfn = PFN_UP(memory_start); | 
 | 	max_low_pfn = PFN_DOWN(memblock_end_of_DRAM()); | 
 | 	max_pfn = max_low_pfn; | 
 |  | 
 | 	memblock_reserve(__pa(_stext), _end - _stext); | 
 |  | 
 | 	early_init_fdt_reserve_self(); | 
 | 	early_init_fdt_scan_reserved_mem(); | 
 |  | 
 | 	memblock_dump_all(); | 
 | } | 
 |  | 
 | void __init setup_arch(char **cmdline_p) | 
 | { | 
 | 	unflatten_and_copy_device_tree(); | 
 |  | 
 | 	init_mm.start_code = (unsigned long) _stext; | 
 | 	init_mm.end_code = (unsigned long) _etext; | 
 | 	init_mm.end_data = (unsigned long) _edata; | 
 | 	init_mm.brk = (unsigned long) 0; | 
 |  | 
 | 	pr_notice("\r\n\nuClinux " CPU "\n"); | 
 | 	pr_notice("Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n"); | 
 |  | 
 | 	if (*command_line) | 
 | 		strcpy(boot_command_line, command_line); | 
 | 	*cmdline_p = boot_command_line; | 
 |  | 
 | 	parse_early_param(); | 
 |  | 
 | 	bootmem_init(); | 
 | 	/* | 
 | 	 * get kmalloc into gear | 
 | 	 */ | 
 | 	paging_init(); | 
 | } | 
 |  | 
 | /* | 
 |  *	Get CPU information for use by the procfs. | 
 |  */ | 
 |  | 
 | static int show_cpuinfo(struct seq_file *m, void *v) | 
 | { | 
 | 	char *cpu; | 
 |  | 
 | 	cpu = CPU; | 
 |  | 
 | 	seq_printf(m,  "CPU:\t\t%s\n" | 
 | 		   "Clock:\t\t%lu.%1luMHz\n" | 
 | 		   "BogoMips:\t%lu.%02lu\n" | 
 | 		   "Calibration:\t%lu loops\n", | 
 | 		   cpu, | 
 | 		   freq/1000, freq%1000, | 
 | 		   (loops_per_jiffy*HZ)/500000, | 
 | 		   ((loops_per_jiffy*HZ)/5000)%100, | 
 | 		   (loops_per_jiffy*HZ)); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void *c_start(struct seq_file *m, loff_t *pos) | 
 | { | 
 | 	return *pos < num_possible_cpus() ? | 
 | 		((void *) 0x12345678) : NULL; | 
 | } | 
 |  | 
 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | 
 | { | 
 | 	++*pos; | 
 | 	return c_start(m, pos); | 
 | } | 
 |  | 
 | static void c_stop(struct seq_file *m, void *v) | 
 | { | 
 | } | 
 |  | 
 | const struct seq_operations cpuinfo_op = { | 
 | 	.start	= c_start, | 
 | 	.next	= c_next, | 
 | 	.stop	= c_stop, | 
 | 	.show	= show_cpuinfo, | 
 | }; | 
 |  | 
 | #if defined(CONFIG_CPU_H8300H) | 
 | #define get_wait(base, addr) ({		\ | 
 | 	int baddr;			\ | 
 | 	baddr = ((addr) / 0x200000 * 2);			     \ | 
 | 	w *= (readw((base) + 2) & (3 << baddr)) + 1;		     \ | 
 | 	}) | 
 | #endif | 
 | #if defined(CONFIG_CPU_H8S) | 
 | #define get_wait(base, addr) ({		\ | 
 | 	int baddr;			\ | 
 | 	baddr = ((addr) / 0x200000 * 16);			     \ | 
 | 	w *= (readl((base) + 2) & (7 << baddr)) + 1;	\ | 
 | 	}) | 
 | #endif | 
 |  | 
 | static __init int access_timing(void) | 
 | { | 
 | 	struct device_node *bsc; | 
 | 	void __iomem *base; | 
 | 	unsigned long addr = (unsigned long)&__delay; | 
 | 	int bit = 1 << (addr / 0x200000); | 
 | 	int w; | 
 |  | 
 | 	bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc"); | 
 | 	base = of_iomap(bsc, 0); | 
 | 	w = (readb(base + 0) & bit)?2:1; | 
 | 	if (readb(base + 1) & bit) | 
 | 		w *= get_wait(base, addr); | 
 | 	else | 
 | 		w *= 2; | 
 | 	return w * 3 / 2; | 
 | } | 
 |  | 
 | void __init calibrate_delay(void) | 
 | { | 
 | 	struct device_node *cpu; | 
 | 	int freq; | 
 |  | 
 | 	cpu = of_find_compatible_node(NULL, NULL, "renesas,h8300"); | 
 | 	of_property_read_s32(cpu, "clock-frequency", &freq); | 
 | 	loops_per_jiffy = freq / HZ / (access_timing() * 2); | 
 | 	pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", | 
 | 		loops_per_jiffy / (500000 / HZ), | 
 | 		(loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy); | 
 | } | 
 |  | 
 |  | 
 | void __init time_init(void) | 
 | { | 
 | 	of_clk_init(NULL); | 
 | 	timer_probe(); | 
 | } |