setup.c 9.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  Maple (970 eval board) setup code
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11 12 13
 *
 *  (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org),
 *                     IBM Corp. 
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version
 *  2 of the License, or (at your option) any later version.
 *
 */

14
#undef DEBUG
L
Linus Torvalds 已提交
15 16 17 18 19

#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
20
#include <linux/export.h>
L
Linus Torvalds 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/initrd.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
#include <linux/pci.h>
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/pmu.h>
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/serial.h>
#include <linux/smp.h>
J
Jiri Slaby 已提交
43
#include <linux/bitops.h>
44
#include <linux/of_device.h>
Y
Yinghai Lu 已提交
45
#include <linux/memblock.h>
L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58

#include <asm/processor.h>
#include <asm/sections.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
#include <asm/machdep.h>
#include <asm/dma.h>
#include <asm/cputable.h>
#include <asm/time.h>
59
#include <asm/mpic.h>
60
#include <asm/rtas.h>
61
#include <asm/udbg.h>
N
Nathan Lynch 已提交
62
#include <asm/nvram.h>
L
Linus Torvalds 已提交
63

64 65
#include "maple.h"

L
Linus Torvalds 已提交
66 67 68 69 70 71
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
#else
#define DBG(fmt...)
#endif

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
static unsigned long maple_find_nvram_base(void)
{
	struct device_node *rtcs;
	unsigned long result = 0;

	/* find NVRAM device */
	rtcs = of_find_compatible_node(NULL, "nvram", "AMD8111");
	if (rtcs) {
		struct resource r;
		if (of_address_to_resource(rtcs, 0, &r)) {
			printk(KERN_EMERG "Maple: Unable to translate NVRAM"
			       " address\n");
			goto bail;
		}
		if (!(r.flags & IORESOURCE_IO)) {
			printk(KERN_EMERG "Maple: NVRAM address isn't PIO!\n");
			goto bail;
		}
		result = r.start;
	} else
		printk(KERN_EMERG "Maple: Unable to find NVRAM\n");
 bail:
	of_node_put(rtcs);
	return result;
}

L
Linus Torvalds 已提交
98 99
static void maple_restart(char *cmd)
{
D
David Gibson 已提交
100
	unsigned int maple_nvram_base;
101
	const unsigned int *maple_nvram_offset, *maple_nvram_command;
102
	struct device_node *sp;
D
David Gibson 已提交
103

104 105 106
	maple_nvram_base = maple_find_nvram_base();
	if (maple_nvram_base == 0)
		goto fail;
D
David Gibson 已提交
107 108

	/* find service processor device */
109 110
	sp = of_find_node_by_name(NULL, "service-processor");
	if (!sp) {
D
David Gibson 已提交
111
		printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
112
		goto fail;
D
David Gibson 已提交
113
	}
114 115
	maple_nvram_offset = of_get_property(sp, "restart-addr", NULL);
	maple_nvram_command = of_get_property(sp, "restart-value", NULL);
116
	of_node_put(sp);
D
David Gibson 已提交
117 118

	/* send command */
119
	outb_p(*maple_nvram_command, maple_nvram_base + *maple_nvram_offset);
D
David Gibson 已提交
120
	for (;;) ;
121 122
 fail:
	printk(KERN_EMERG "Maple: Manual Restart Required\n");
L
Linus Torvalds 已提交
123 124 125 126
}

static void maple_power_off(void)
{
D
David Gibson 已提交
127
	unsigned int maple_nvram_base;
128
	const unsigned int *maple_nvram_offset, *maple_nvram_command;
129
	struct device_node *sp;
D
David Gibson 已提交
130

131 132 133
	maple_nvram_base = maple_find_nvram_base();
	if (maple_nvram_base == 0)
		goto fail;
D
David Gibson 已提交
134 135

	/* find service processor device */
136 137
	sp = of_find_node_by_name(NULL, "service-processor");
	if (!sp) {
D
David Gibson 已提交
138
		printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
139
		goto fail;
D
David Gibson 已提交
140
	}
141 142
	maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL);
	maple_nvram_command = of_get_property(sp, "power-off-value", NULL);
143
	of_node_put(sp);
D
David Gibson 已提交
144 145

	/* send command */
146
	outb_p(*maple_nvram_command, maple_nvram_base + *maple_nvram_offset);
D
David Gibson 已提交
147
	for (;;) ;
148 149
 fail:
	printk(KERN_EMERG "Maple: Manual Power-Down Required\n");
L
Linus Torvalds 已提交
150 151 152 153
}

static void maple_halt(void)
{
D
David Gibson 已提交
154
	maple_power_off();
L
Linus Torvalds 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167
}

#ifdef CONFIG_SMP
struct smp_ops_t maple_smp_ops = {
	.probe		= smp_mpic_probe,
	.message_pass	= smp_mpic_message_pass,
	.kick_cpu	= smp_generic_kick_cpu,
	.setup_cpu	= smp_mpic_setup_cpu,
	.give_timebase	= smp_generic_give_timebase,
	.take_timebase	= smp_generic_take_timebase,
};
#endif /* CONFIG_SMP */

168 169 170 171 172 173 174 175 176 177
static void __init maple_use_rtas_reboot_and_halt_if_present(void)
{
	if (rtas_service_present("system-reboot") &&
	    rtas_service_present("power-off")) {
		ppc_md.restart = rtas_restart;
		ppc_md.power_off = rtas_power_off;
		ppc_md.halt = rtas_halt;
	}
}

L
Linus Torvalds 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
void __init maple_setup_arch(void)
{
	/* init to some ~sane value until calibrate_delay() runs */
	loops_per_jiffy = 50000000;

	/* Setup SMP callback */
#ifdef CONFIG_SMP
	smp_ops = &maple_smp_ops;
#endif
	/* Lookup PCI hosts */
       	maple_pci_init();

#ifdef CONFIG_DUMMY_CONSOLE
	conswitchp = &dummy_con;
#endif
193
	maple_use_rtas_reboot_and_halt_if_present();
194

195
	printk(KERN_DEBUG "Using native/NAP idle loop\n");
N
Nathan Lynch 已提交
196 197

	mmio_nvram_init();
L
Linus Torvalds 已提交
198 199 200 201 202 203 204 205 206
}

/* 
 * Early initialization.
 */
static void __init maple_init_early(void)
{
	DBG(" -> maple_init_early\n");

207
	iommu_init_early_dart();
L
Linus Torvalds 已提交
208 209 210 211

	DBG(" <- maple_init_early\n");
}

212 213 214 215 216 217
/*
 * This is almost identical to pSeries and CHRP. We need to make that
 * code generic at one point, with appropriate bits in the device-tree to
 * identify the presence of an HT APIC
 */
static void __init maple_init_IRQ(void)
L
Linus Torvalds 已提交
218
{
219
	struct device_node *root, *np, *mpic_node = NULL;
220
	const unsigned int *opprop;
221 222
	unsigned long openpic_addr = 0;
	int naddr, n, i, opplen, has_isus = 0;
L
Linus Torvalds 已提交
223
	struct mpic *mpic;
224
	unsigned int flags = 0;
L
Linus Torvalds 已提交
225

226 227 228 229
	/* Locate MPIC in the device-tree. Note that there is a bug
	 * in Maple device-tree where the type of the controller is
	 * open-pic and not interrupt-controller
	 */
230 231

	for_each_node_by_type(np, "interrupt-controller")
232
		if (of_device_is_compatible(np, "open-pic")) {
233 234 235 236 237 238 239 240
			mpic_node = np;
			break;
		}
	if (mpic_node == NULL)
		for_each_node_by_type(np, "open-pic") {
			mpic_node = np;
			break;
		}
241 242 243 244 245
	if (mpic_node == NULL) {
		printk(KERN_ERR
		       "Failed to locate the MPIC interrupt controller\n");
		return;
	}
L
Linus Torvalds 已提交
246

247
	/* Find address list in /platform-open-pic */
L
Linus Torvalds 已提交
248
	root = of_find_node_by_path("/");
249
	naddr = of_n_addr_cells(root);
250
	opprop = of_get_property(root, "platform-open-pic", &opplen);
251 252 253 254 255 256
	if (opprop != 0) {
		openpic_addr = of_read_number(opprop, naddr);
		has_isus = (opplen > naddr);
		printk(KERN_DEBUG "OpenPIC addr: %lx, has ISUs: %d\n",
		       openpic_addr, has_isus);
	}
L
Linus Torvalds 已提交
257

258
	BUG_ON(openpic_addr == 0);
L
Linus Torvalds 已提交
259

260
	/* Check for a big endian MPIC */
261
	if (of_get_property(np, "big-endian", NULL) != NULL)
262 263 264
		flags |= MPIC_BIG_ENDIAN;

	/* XXX Maple specific bits */
265
	flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
266 267
	/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
	flags |= MPIC_BIG_ENDIAN;
268 269 270 271 272 273 274

	/* Setup the openpic driver. More device-tree junks, we hard code no
	 * ISUs for now. I'll have to revisit some stuffs with the folks doing
	 * the firmware for those
	 */
	mpic = mpic_alloc(mpic_node, openpic_addr, flags,
			  /*has_isus ? 16 :*/ 0, 0, " MPIC     ");
L
Linus Torvalds 已提交
275 276
	BUG_ON(mpic == NULL);

277 278 279 280 281 282 283 284 285 286 287 288
	/* Add ISUs */
	opplen /= sizeof(u32);
	for (n = 0, i = naddr; i < opplen; i += naddr, n++) {
		unsigned long isuaddr = of_read_number(opprop + i, naddr);
		mpic_assign_isu(mpic, n, isuaddr);
	}

	/* All ISUs are setup, complete initialization */
	mpic_init(mpic);
	ppc_md.get_irq = mpic_get_irq;
	of_node_put(mpic_node);
	of_node_put(root);
L
Linus Torvalds 已提交
289 290 291 292 293 294 295 296 297 298 299
}

static void __init maple_progress(char *s, unsigned short hex)
{
	printk("*** %04x : %s\n", hex, s ? s : "");
}


/*
 * Called very early, MMU is off, device-tree isn't unflattened
 */
300
static int __init maple_probe(void)
L
Linus Torvalds 已提交
301
{
302
	unsigned long root = of_get_flat_dt_root();
303 304 305

	if (!of_flat_dt_is_compatible(root, "Momentum,Maple") &&
	    !of_flat_dt_is_compatible(root, "Momentum,Apache"))
L
Linus Torvalds 已提交
306 307 308 309 310 311 312
		return 0;
	/*
	 * On U3, the DART (iommu) must be allocated now since it
	 * has an impact on htab_initialize (due to the large page it
	 * occupies having to be broken up so the DART itself is not
	 * part of the cacheable linar mapping
	 */
313
	alloc_dart_table();
L
Linus Torvalds 已提交
314

315 316
	hpte_init_native();

L
Linus Torvalds 已提交
317 318 319
	return 1;
}

320
define_machine(maple) {
321
	.name			= "Maple",
L
Linus Torvalds 已提交
322 323 324 325
	.probe			= maple_probe,
	.setup_arch		= maple_setup_arch,
	.init_early		= maple_init_early,
	.init_IRQ		= maple_init_IRQ,
326
	.pci_irq_fixup		= maple_pci_irq_fixup,
L
Linus Torvalds 已提交
327 328 329 330 331 332 333
	.pci_get_legacy_ide_irq	= maple_pci_get_legacy_ide_irq,
	.restart		= maple_restart,
	.power_off		= maple_power_off,
	.halt			= maple_halt,
       	.get_boot_time		= maple_get_boot_time,
       	.set_rtc_time		= maple_set_rtc_time,
       	.get_rtc_time		= maple_get_rtc_time,
334
      	.calibrate_decr		= generic_calibrate_decr,
L
Linus Torvalds 已提交
335
	.progress		= maple_progress,
336
	.power_save		= power4_idle,
L
Linus Torvalds 已提交
337
};
338 339 340 341

#ifdef CONFIG_EDAC
/*
 * Register a platform device for CPC925 memory controller on
342
 * all boards with U3H (CPC925) bridge.
343 344 345 346 347 348 349
 */
static int __init maple_cpc925_edac_setup(void)
{
	struct platform_device *pdev;
	struct device_node *np = NULL;
	struct resource r;
	int ret;
350 351
	volatile void __iomem *mem;
	u32 rev;
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

	np = of_find_node_by_type(NULL, "memory-controller");
	if (!np) {
		printk(KERN_ERR "%s: Unable to find memory-controller node\n",
			__func__);
		return -ENODEV;
	}

	ret = of_address_to_resource(np, 0, &r);
	of_node_put(np);

	if (ret < 0) {
		printk(KERN_ERR "%s: Unable to get memory-controller reg\n",
			__func__);
		return -ENODEV;
	}

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	mem = ioremap(r.start, resource_size(&r));
	if (!mem) {
		printk(KERN_ERR "%s: Unable to map memory-controller memory\n",
				__func__);
		return -ENOMEM;
	}

	rev = __raw_readl(mem);
	iounmap(mem);

	if (rev < 0x34 || rev > 0x3f) { /* U3H */
		printk(KERN_ERR "%s: Non-CPC925(U3H) bridge revision: %02x\n",
			__func__, rev);
		return 0;
	}

385 386 387 388 389 390 391 392 393 394
	pdev = platform_device_register_simple("cpc925_edac", 0, &r, 1);
	if (IS_ERR(pdev))
		return PTR_ERR(pdev);

	printk(KERN_INFO "%s: CPC925 platform device created\n", __func__);

	return 0;
}
machine_device_initcall(maple, maple_cpc925_edac_setup);
#endif