xref: /OK3568_Linux_fs/kernel/arch/mips/sgi-ip30/ip30-setup.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SGI IP30 miscellaneous setup bits.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2004-2007 Stanislaw Skowronek <skylark@unaligned.org>
6*4882a593Smuzhiyun  *               2007 Joshua Kinard <kumba@gentoo.org>
7*4882a593Smuzhiyun  *               2009 Johannes Dickgreber <tanzy@gmx.de>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/io.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/types.h>
14*4882a593Smuzhiyun #include <linux/percpu.h>
15*4882a593Smuzhiyun #include <linux/memblock.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <asm/smp-ops.h>
18*4882a593Smuzhiyun #include <asm/sgialib.h>
19*4882a593Smuzhiyun #include <asm/time.h>
20*4882a593Smuzhiyun #include <asm/sgi/heart.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "ip30-common.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* Structure of accessible HEART registers located in XKPHYS space. */
25*4882a593Smuzhiyun struct ip30_heart_regs __iomem *heart_regs = HEART_XKPHYS_BASE;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * ARCS will report up to the first 1GB of
29*4882a593Smuzhiyun  * memory if queried.  Anything beyond that
30*4882a593Smuzhiyun  * is marked as reserved.
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun #define IP30_MAX_PROM_MEMORY	_AC(0x40000000, UL)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun  * Memory in the Octane starts at 512MB
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun #define IP30_MEMORY_BASE	_AC(0x20000000, UL)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun  * If using ARCS to probe for memory, then
41*4882a593Smuzhiyun  * remaining memory will start at this offset.
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun #define IP30_REAL_MEMORY_START  (IP30_MEMORY_BASE + IP30_MAX_PROM_MEMORY)
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define MEM_SHIFT(x) ((x) >> 20)
46*4882a593Smuzhiyun 
ip30_mem_init(void)47*4882a593Smuzhiyun static void __init ip30_mem_init(void)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	unsigned long total_mem;
50*4882a593Smuzhiyun 	phys_addr_t addr;
51*4882a593Smuzhiyun 	phys_addr_t size;
52*4882a593Smuzhiyun 	u32 memcfg;
53*4882a593Smuzhiyun 	int i;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	total_mem = 0;
56*4882a593Smuzhiyun 	for (i = 0; i < HEART_MEMORY_BANKS; i++) {
57*4882a593Smuzhiyun 		memcfg = __raw_readl(&heart_regs->mem_cfg.l[i]);
58*4882a593Smuzhiyun 		if (!(memcfg & HEART_MEMCFG_VALID))
59*4882a593Smuzhiyun 			continue;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 		addr = memcfg & HEART_MEMCFG_ADDR_MASK;
62*4882a593Smuzhiyun 		addr <<= HEART_MEMCFG_UNIT_SHIFT;
63*4882a593Smuzhiyun 		addr += IP30_MEMORY_BASE;
64*4882a593Smuzhiyun 		size = memcfg & HEART_MEMCFG_SIZE_MASK;
65*4882a593Smuzhiyun 		size >>= HEART_MEMCFG_SIZE_SHIFT;
66*4882a593Smuzhiyun 		size += 1;
67*4882a593Smuzhiyun 		size <<= HEART_MEMCFG_UNIT_SHIFT;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 		total_mem += size;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		if (addr >= IP30_REAL_MEMORY_START)
72*4882a593Smuzhiyun 			memblock_free(addr, size);
73*4882a593Smuzhiyun 		else if ((addr + size) > IP30_REAL_MEMORY_START)
74*4882a593Smuzhiyun 			memblock_free(IP30_REAL_MEMORY_START,
75*4882a593Smuzhiyun 				     size - IP30_MAX_PROM_MEMORY);
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun 	pr_info("Detected %luMB of physical memory.\n", MEM_SHIFT(total_mem));
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /**
81*4882a593Smuzhiyun  * ip30_cpu_time_init - platform time initialization.
82*4882a593Smuzhiyun  */
ip30_cpu_time_init(void)83*4882a593Smuzhiyun static void __init ip30_cpu_time_init(void)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	int cpu = smp_processor_id();
86*4882a593Smuzhiyun 	u64 heart_compare;
87*4882a593Smuzhiyun 	unsigned int start, end;
88*4882a593Smuzhiyun 	int time_diff;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	heart_compare = (heart_read(&heart_regs->count) +
91*4882a593Smuzhiyun 			 (HEART_CYCLES_PER_SEC / 10));
92*4882a593Smuzhiyun 	start = read_c0_count();
93*4882a593Smuzhiyun 	while ((heart_read(&heart_regs->count) - heart_compare) & 0x800000)
94*4882a593Smuzhiyun 		cpu_relax();
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	end = read_c0_count();
97*4882a593Smuzhiyun 	time_diff = (int)end - (int)start;
98*4882a593Smuzhiyun 	mips_hpt_frequency = time_diff * 10;
99*4882a593Smuzhiyun 	pr_info("IP30: CPU%d: %d MHz CPU detected.\n", cpu,
100*4882a593Smuzhiyun 		(mips_hpt_frequency * 2) / 1000000);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
ip30_per_cpu_init(void)103*4882a593Smuzhiyun void __init ip30_per_cpu_init(void)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	/* Disable all interrupts. */
106*4882a593Smuzhiyun 	clear_c0_status(ST0_IM);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	ip30_cpu_time_init();
109*4882a593Smuzhiyun #ifdef CONFIG_SMP
110*4882a593Smuzhiyun 	ip30_install_ipi();
111*4882a593Smuzhiyun #endif
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	enable_percpu_irq(IP30_HEART_L0_IRQ, IRQ_TYPE_NONE);
114*4882a593Smuzhiyun 	enable_percpu_irq(IP30_HEART_L1_IRQ, IRQ_TYPE_NONE);
115*4882a593Smuzhiyun 	enable_percpu_irq(IP30_HEART_L2_IRQ, IRQ_TYPE_NONE);
116*4882a593Smuzhiyun 	enable_percpu_irq(IP30_HEART_ERR_IRQ, IRQ_TYPE_NONE);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /**
120*4882a593Smuzhiyun  * plat_mem_setup - despite the name, misc setup happens here.
121*4882a593Smuzhiyun  */
plat_mem_setup(void)122*4882a593Smuzhiyun void __init plat_mem_setup(void)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	ip30_mem_init();
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	/* XXX: Hard lock on /sbin/init if this flag isn't specified. */
127*4882a593Smuzhiyun 	prom_flags |= PROM_FLAG_DONT_FREE_TEMP;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun #ifdef CONFIG_SMP
130*4882a593Smuzhiyun 	register_smp_ops(&ip30_smp_ops);
131*4882a593Smuzhiyun #else
132*4882a593Smuzhiyun 	ip30_per_cpu_init();
133*4882a593Smuzhiyun #endif
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	ioport_resource.start = 0;
136*4882a593Smuzhiyun 	ioport_resource.end = ~0UL;
137*4882a593Smuzhiyun 	set_io_port_base(IO_BASE);
138*4882a593Smuzhiyun }
139