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