Subject: Pegasos 2 support patch ...

From: Sven Luther <[email-masked]>
Date: Tue, 29 Jun 2004 18:50:29 +0200

Hello,

Please find here attached a patch which adds support for the Pegasos 2
motherboard, and partial support for the Pegasos 1. I would like to have
some review of it, and if it is ok, see how it would be possible to have
it included in the main kernel. The patch is against 2.6.7.

The remaining problem for the pegasos 2 is with the via82cxxx ide
driver, which needs to support a different irq for both channels, thus
breakign when a device is present on the second ide channel. The
pegasos-via82cxxx.diff patches is a hcky soltuion for this, but is
naturally not fit for mainstream inclusion. I would welcome any hint on
how to solve this issue.

The pegasos1 support is not complete, but i believe this is due to some
brokeness in the OF. The main problem being that the translate function
is broken, and altough phys has the right value (0x00010000) before
calling it, it is 0 afterwards. I suppose the initial value is taken
from &_stext, so it should be feasible to detect that this is the
correct value before calling the translate OF method, or fixing it if we
detect a Pegasos 1 with the model OF property. Comments on this would
also be welcome. There may be some interrupt level thing left on pegasos
1 also, but i would need to check that.

Thanks for your comments,

Friendly,

Sven Luther
diff -urN kernel-source-2.6.7.orig/arch/ppc/platforms/chrp_pci.c kernel-source-2.6.7.peg2/arch/ppc/platforms/chrp_pci.c
--- kernel-source-2.6.7.orig/arch/ppc/platforms/chrp_pci.c	2004-06-16 07:20:26.000000000 +0200
+++ kernel-source-2.6.7.peg2/arch/ppc/platforms/chrp_pci.c	2004-06-29 18:10:43.951806408 +0200
@@ -97,8 +97,9 @@
 rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 		 int len, u32 *val)
 {
+	struct pci_controller *hose = bus->sysdata;
 	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
-		| ((bus->number & 0xff) << 16);
+		| (((bus->number - hose->first_busno) & 0xff) << 16) | (pci_domain_nr(bus) << 24);
         unsigned long ret = ~0UL;
 	int rval;

@@ -111,8 +112,9 @@
 rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 		  int len, u32 val)
 {
+	struct pci_controller *hose = bus->sysdata;
 	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
-		| ((bus->number & 0xff) << 16);
+		| (((bus->number - hose->first_busno) & 0xff) << 16) | (pci_domain_nr(bus) << 24);
 	int rval;

 	rval = call_rtas("write-pci-config", 3, 1, NULL, addr, len, val);
@@ -186,6 +188,26 @@
 	iounmap(reg);
 }

+/* Marvell Discovery II based Pegasos 2 */
+//#define PEGASOS_USE_PCI_DOMAINS
+
+static void __init
+setup_peg2(struct pci_controller *hose, struct device_node *dev)
+{
+	struct device_node *root = find_path_device("/");
+	struct device_node *rtas;
+
+	rtas = of_find_node_by_name (root, "rtas");
+	if (rtas) {
+		hose->ops = &rtas_pci_ops;
+	} else {
+		printk ("RTAS supporting Pegasos OF not found, please upgrade your firmware\n");
+	}
+#ifndef PEGASOS_USE_PCI_DOMAINS
+	pci_assign_all_busses = 1;
+#endif
+}
+
 void __init
 chrp_find_bridges(void)
 {
@@ -195,7 +217,7 @@
 	struct pci_controller *hose;
 	unsigned int *dma;
 	char *model, *machine;
-	int is_longtrail = 0, is_mot = 0;
+	int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
 	struct device_node *root = find_path_device("/");

 	/*
@@ -207,6 +229,8 @@
 	if (machine != NULL) {
 		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
 		is_mot = strncmp(machine, "MOT", 3) == 0;
+		if (strncmp(machine, "Pegasos2", 8) == 0) is_pegasos = 2;
+		else if (strncmp(machine, "Pegasos", 7) == 0) is_pegasos = 1;
 	}
 	for (dev = root->child; dev != NULL; dev = dev->sibling) {
 		if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
@@ -257,6 +281,10 @@
 			hose->cfg_data = (unsigned char *)
 				ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
 			gg2_pci_config_base = (unsigned long) hose->cfg_data;
+		} else if (is_pegasos == 1) {
+			setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc);
+		} else if (is_pegasos == 2) {
+			setup_peg2(hose, dev);
 		} else {
 			printk("No methods for %s (model %s), using RTAS\n",
 			       dev->full_name, model);
@@ -274,6 +302,9 @@
 			printk("pci_dram_offset = %lx\n", pci_dram_offset);
 		}
 	}
-
-	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
+
+	if (is_pegasos)
+		ppc_md.pcibios_fixup = NULL;
+	else
+		ppc_md.pcibios_fixup = chrp_pcibios_fixup;
 }
diff -urN kernel-source-2.6.7.orig/arch/ppc/platforms/chrp_setup.c kernel-source-2.6.7.peg2/arch/ppc/platforms/chrp_setup.c
--- kernel-source-2.6.7.orig/arch/ppc/platforms/chrp_setup.c	2004-06-16 07:19:52.000000000 +0200
+++ kernel-source-2.6.7.peg2/arch/ppc/platforms/chrp_setup.c	2004-06-29 18:10:44.191769928 +0200
@@ -214,6 +214,37 @@
 	}
 }

+void pegasos_set_l2cr(void)
+{
+	struct device_node *root = find_path_device("/");
+	char *machine;
+	struct device_node *np;
+	int l2cr_value;
+
+	/* On Pegasos, enable the l2 cache if needed, as the OF forgets it */
+	if (root == NULL)
+		return;
+	machine = get_property(root, "model", NULL);
+	if (machine == NULL)
+		return;
+	if (strncmp(machine, "Pegasos", 7) == 0) {
+		/* Enable L2 cache if needed */
+		np = find_type_devices("cpu");
+		if (np != NULL) {
+			unsigned int *l2cr = (unsigned int *)
+				get_property (np, "l2cr", NULL);
+			if (l2cr == NULL) {
+				printk ("Pegasos l2cr : no cpu l2cr property found\n");
+				return;
+			}
+			if (!((*l2cr) & 0x80000000)) {
+				printk ("Pegasos l2cr : L2 cache was not active, activating\n");
+				_set_L2CR(0);
+				_set_L2CR((*l2cr) | 0x80000000);
+			}
+		}
+	}
+}

 void __init
 chrp_setup_arch(void)
@@ -236,6 +267,9 @@
 	/* Lookup PCI host bridges */
 	chrp_find_bridges();

+	/* On pegasos, enable the L2 cache if not already done by OF */
+	pegasos_set_l2cr();
+
 #ifndef CONFIG_PPC64BRIDGE
 	/*
 	 *  Temporary fixes for PCI devices.
@@ -387,6 +421,8 @@
 #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
 	struct device_node *kbd;
 #endif
+	struct device_node *root = find_path_device ("/");
+	char *machine;

 	for (np = find_devices("pci"); np != NULL; np = np->next) {
 		unsigned int *addrp = (unsigned int *)
@@ -400,16 +436,20 @@
 	if (np == NULL)
 		printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n");

-	chrp_find_openpic();
-
-	prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
-	OpenPIC_InitSenses = init_senses;
-	OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
-
-	openpic_init(NUM_8259_INTERRUPTS);
-	/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
-	openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+	/* Pegasos doesn't have openpic */
+	machine = get_property(root, "model", NULL);
+	if (strncmp(machine, "Pegasos", 7) != 0) {
+		chrp_find_openpic();
+
+		prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
+		OpenPIC_InitSenses = init_senses;
+		OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
+
+		openpic_init(NUM_8259_INTERRUPTS);
+		/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+		openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
 			       i8259_irq);
+	}

 	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
@@ -450,6 +490,8 @@
 chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	  unsigned long r6, unsigned long r7)
 {
+	struct device_node *root = find_path_device ("/");
+	char *machine;
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* take care of initrd if we have one */
 	if ( r6 )
@@ -469,7 +511,11 @@
 	ppc_md.show_cpuinfo   = chrp_show_cpuinfo;
 	ppc_md.irq_canonicalize = chrp_irq_canonicalize;
 	ppc_md.init_IRQ       = chrp_init_IRQ;
-	ppc_md.get_irq        = openpic_get_irq;
+	machine = get_property(root, "model", NULL);
+	if (strncmp(machine, "Pegasos", 7) == 0)
+		ppc_md.get_irq        = i8259_irq;
+	else
+		ppc_md.get_irq        = openpic_get_irq;

 	ppc_md.init           = chrp_init2;

diff -urN kernel-source-2.6.7.orig/arch/ppc/platforms/chrp_time.c kernel-source-2.6.7.peg2/arch/ppc/platforms/chrp_time.c
--- kernel-source-2.6.7.orig/arch/ppc/platforms/chrp_time.c	2004-06-16 07:18:57.000000000 +0200
+++ kernel-source-2.6.7.peg2/arch/ppc/platforms/chrp_time.c	2004-06-29 18:10:44.032794096 +0200
@@ -41,6 +41,8 @@
 	int base;

 	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+	if (rtcs == NULL)
+		rtcs = find_compatible_devices("rtc", "ds1385-rtc");
 	if (rtcs == NULL || rtcs->addrs == NULL)
 		return 0;
 	base = rtcs->addrs[0].address;