mpc85xx_cds.c 8.48 KB
Newer Older
Andy Fleming's avatar
Andy Fleming committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * MPC85xx setup and early boot code plus other random bits.
 *
 * Maintained by Kumar Gala (see MAINTAINERS for contact information)
 *
 * Copyright 2005 Freescale Semiconductor Inc.
 *
 * 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.
 */

#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/initrd.h>
#include <linux/module.h>
27
#include <linux/interrupt.h>
Andy Fleming's avatar
Andy Fleming committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#include <linux/fsl_devices.h>

#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/atomic.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/ipic.h>
#include <asm/pci-bridge.h>
#include <asm/mpc85xx.h>
#include <asm/irq.h>
#include <mm/mmu_decl.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/i8259.h>

#include <sysdev/fsl_soc.h>
48
#include <sysdev/fsl_pci.h>
Andy Fleming's avatar
Andy Fleming committed
49 50 51 52 53 54 55 56 57

static int cds_pci_slot = 2;
static volatile u8 *cadmus;

#ifdef CONFIG_PCI

#define ARCADIA_HOST_BRIDGE_IDSEL	17
#define ARCADIA_2ND_BRIDGE_IDSEL	3

58 59
static int mpc85xx_exclude_device(struct pci_controller *hose,
				  u_char bus, u_char devfn)
Andy Fleming's avatar
Andy Fleming committed
60 61 62 63 64 65 66 67 68 69
{
	/* We explicitly do not go past the Tundra 320 Bridge */
	if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
		return PCIBIOS_DEVICE_NOT_FOUND;
	if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
		return PCIBIOS_DEVICE_NOT_FOUND;
	else
		return PCIBIOS_SUCCESSFUL;
}

70 71 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 void mpc85xx_cds_restart(char *cmd)
{
	struct pci_dev *dev;
	u_char tmp;

	if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686,
					NULL))) {

		/* Use the VIA Super Southbridge to force a PCI reset */
		pci_read_config_byte(dev, 0x47, &tmp);
		pci_write_config_byte(dev, 0x47, tmp | 1);

		/* Flush the outbound PCI write queues */
		pci_read_config_byte(dev, 0x47, &tmp);

		/*
		 *  At this point, the harware reset should have triggered.
		 *  However, if it doesn't work for some mysterious reason,
		 *  just fall through to the default reset below.
		 */

		pci_dev_put(dev);
	}

	/*
	 *  If we can't find the VIA chip (maybe the P2P bridge is disabled)
	 *  or the VIA chip reset didn't work, just use the default reset.
	 */
98
	fsl_rstcr_restart(NULL);
99 100
}

101
static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev)
Andy Fleming's avatar
Andy Fleming committed
102
{
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	u_char c;
	if (dev->vendor == PCI_VENDOR_ID_VIA) {
		switch (dev->device) {
		case PCI_DEVICE_ID_VIA_82C586_1:
			/*
			 * U-Boot does not set the enable bits
			 * for the IDE device. Force them on here.
			 */
			pci_read_config_byte(dev, 0x40, &c);
			c |= 0x03; /* IDE: Chip Enable Bits */
			pci_write_config_byte(dev, 0x40, c);

			/*
			 * Since only primary interface works, force the
			 * IDE function to standard primary IDE interrupt
			 * w/ 8259 offset
			 */
			dev->irq = 14;
			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
			break;
Andy Fleming's avatar
Andy Fleming committed
123
		/*
124
		 * Force legacy USB interrupt routing
Andy Fleming's avatar
Andy Fleming committed
125
		 */
126 127 128
		case PCI_DEVICE_ID_VIA_82C586_2:
		/* There are two USB controllers.
		 * Identify them by functon number
Andy Fleming's avatar
Andy Fleming committed
129
		 */
130
			if (PCI_FUNC(dev->devfn) == 3)
131 132 133 134 135 136 137
				dev->irq = 11;
			else
				dev->irq = 10;
			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
		default:
			break;
		}
Andy Fleming's avatar
Andy Fleming committed
138
	}
139 140
}

141 142 143 144 145 146 147 148 149 150
static void __devinit skip_fake_bridge(struct pci_dev *dev)
{
	/* Make it an error to skip the fake bridge
	 * in pci_setup_device() in probe.c */
	dev->hdr_type = 0x7f;
}
DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge);
DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);
DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge);

151
#ifdef CONFIG_PPC_I8259
152 153
static void mpc85xx_8259_cascade_handler(unsigned int irq,
					 struct irq_desc *desc)
154
{
155
	unsigned int cascade_irq = i8259_irq();
156 157

	if (cascade_irq != NO_IRQ)
158
		/* handle an interrupt from the 8259 */
159
		generic_handle_irq(cascade_irq);
160

161 162
	/* check for any interrupts from the shared IRQ line */
	handle_fasteoi_irq(irq, desc);
Andy Fleming's avatar
Andy Fleming committed
163
}
164 165 166 167 168 169 170 171 172 173 174 175

static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id)
{
	return IRQ_HANDLED;
}

static struct irqaction mpc85xxcds_8259_irqaction = {
	.handler = mpc85xx_8259_cascade_action,
	.flags = IRQF_SHARED,
	.mask = CPU_MASK_NONE,
	.name = "8259 cascade",
};
176
#endif /* PPC_I8259 */
Andy Fleming's avatar
Andy Fleming committed
177 178
#endif /* CONFIG_PCI */

179
static void __init mpc85xx_cds_pic_init(void)
Andy Fleming's avatar
Andy Fleming committed
180
{
181 182 183
	struct mpic *mpic;
	struct resource r;
	struct device_node *np = NULL;
Andy Fleming's avatar
Andy Fleming committed
184

185 186 187 188 189 190
	np = of_find_node_by_type(np, "open-pic");

	if (np == NULL) {
		printk(KERN_ERR "Could not find open-pic node\n");
		return;
	}
Andy Fleming's avatar
Andy Fleming committed
191

192 193 194 195 196 197 198
	if (of_address_to_resource(np, 0, &r)) {
		printk(KERN_ERR "Failed to map mpic register space\n");
		of_node_put(np);
		return;
	}

	mpic = mpic_alloc(np, r.start,
Andy Fleming's avatar
Andy Fleming committed
199
			MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
200
			0, 256, " OpenPIC  ");
201 202 203 204 205 206
	BUG_ON(mpic == NULL);

	/* Return the mpic node */
	of_node_put(np);

	mpic_init(mpic);
207
}
208

209
#if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI)
210 211 212 213 214 215 216 217 218 219
static int mpc85xx_cds_8259_attach(void)
{
	int ret;
	struct device_node *np = NULL;
	struct device_node *cascade_node = NULL;
	int cascade_irq;

	if (!machine_is(mpc85xx_cds))
		return 0;

220 221
	/* Initialize the i8259 controller */
	for_each_node_by_type(np, "interrupt-controller")
222
		if (of_device_is_compatible(np, "chrp,iic")) {
223 224 225 226 227 228
			cascade_node = np;
			break;
		}

	if (cascade_node == NULL) {
		printk(KERN_DEBUG "Could not find i8259 PIC\n");
229
		return -ENODEV;
230
	}
Andy Fleming's avatar
Andy Fleming committed
231

232 233 234
	cascade_irq = irq_of_parse_and_map(cascade_node, 0);
	if (cascade_irq == NO_IRQ) {
		printk(KERN_ERR "Failed to map cascade interrupt\n");
235
		return -ENXIO;
236
	}
Andy Fleming's avatar
Andy Fleming committed
237

238 239 240
	i8259_init(cascade_node, 0);
	of_node_put(cascade_node);

241 242 243 244 245 246
	/*
	 *  Hook the interrupt to make sure desc->action is never NULL.
	 *  This is required to ensure that the interrupt does not get
	 *  disabled when the last user of the shared IRQ line frees their
	 *  interrupt.
	 */
247
	if ((ret = setup_irq(cascade_irq, &mpc85xxcds_8259_irqaction))) {
248
		printk(KERN_ERR "Failed to setup cascade interrupt\n");
249 250 251 252 253 254 255
		return ret;
	}

	/* Success. Connect our low-level cascade handler. */
	set_irq_handler(cascade_irq, mpc85xx_8259_cascade_handler);

	return 0;
Andy Fleming's avatar
Andy Fleming committed
256 257
}

258 259 260 261
device_initcall(mpc85xx_cds_8259_attach);

#endif /* CONFIG_PPC_I8259 */

Andy Fleming's avatar
Andy Fleming committed
262 263 264
/*
 * Setup the architecture
 */
265
static void __init mpc85xx_cds_setup_arch(void)
Andy Fleming's avatar
Andy Fleming committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
{
#ifdef CONFIG_PCI
	struct device_node *np;
#endif

	if (ppc_md.progress)
		ppc_md.progress("mpc85xx_cds_setup_arch()", 0);

	cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE);
	cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;

	if (ppc_md.progress) {
		char buf[40];
		snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n",
				cadmus[CM_VER], cds_pci_slot);
		ppc_md.progress(buf, 0);
	}

#ifdef CONFIG_PCI
285 286 287 288 289 290 291 292 293 294
	for_each_node_by_type(np, "pci") {
		if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
		    of_device_is_compatible(np, "fsl,mpc8548-pcie")) {
			struct resource rsrc;
			of_address_to_resource(np, 0, &rsrc);
			if ((rsrc.start & 0xfffff) == 0x8000)
				fsl_add_bridge(np, 1);
			else
				fsl_add_bridge(np, 0);
		}
295
	}
296

297
	ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup;
Andy Fleming's avatar
Andy Fleming committed
298 299 300 301
	ppc_md.pci_exclude_device = mpc85xx_exclude_device;
#endif
}

302
static void mpc85xx_cds_show_cpuinfo(struct seq_file *m)
Andy Fleming's avatar
Andy Fleming committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
{
	uint pvid, svid, phid1;
	uint memsize = total_memory;

	pvid = mfspr(SPRN_PVR);
	svid = mfspr(SPRN_SVR);

	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
	seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]);
	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
	seq_printf(m, "SVR\t\t: 0x%x\n", svid);

	/* Display cpu Pll setting */
	phid1 = mfspr(SPRN_HID1);
	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));

	/* Display the amount of memory */
	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
}


/*
 * Called very early, device-tree isn't unflattened
 */
static int __init mpc85xx_cds_probe(void)
{
329 330 331
        unsigned long root = of_get_flat_dt_root();

        return of_flat_dt_is_compatible(root, "MPC85xxCDS");
Andy Fleming's avatar
Andy Fleming committed
332 333 334 335 336 337 338 339 340
}

define_machine(mpc85xx_cds) {
	.name		= "MPC85xx CDS",
	.probe		= mpc85xx_cds_probe,
	.setup_arch	= mpc85xx_cds_setup_arch,
	.init_IRQ	= mpc85xx_cds_pic_init,
	.show_cpuinfo	= mpc85xx_cds_show_cpuinfo,
	.get_irq	= mpic_get_irq,
341 342
#ifdef CONFIG_PCI
	.restart	= mpc85xx_cds_restart,
343
	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
344
#else
345
	.restart	= fsl_rstcr_restart,
346
#endif
Andy Fleming's avatar
Andy Fleming committed
347 348 349
	.calibrate_decr = generic_calibrate_decr,
	.progress	= udbg_progress,
};