* [PATCH] General CHRP/MPC5K2 platform support patch
@ 2006-10-25 19:05 Nicolas DET
2006-10-25 21:59 ` Paul Mackerras
` (3 more replies)
0 siblings, 4 replies; 40+ messages in thread
From: Nicolas DET @ 2006-10-25 19:05 UTC (permalink / raw)
To: linuxppc-dev, sl, akpm, Benjamin Herrenschmidt, Sylvain Munaut,
grant.likely, linuxppc-embedded, sha
[-- Attachment #1: Type: text/plain, Size: 2084 bytes --]
This patch add support for MPC52xx/CHRP/OFW platform.
It contains the minimal changes required: platform/chrp/ and the
interrupt controller code.
This one is slightly different than the one I submitted previously.
http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027133.html
* /proc/ppc64/rtas/ I left it for now. It's not really the concern of
this patch.
* mpc5k2_bestcomm.c (& helpers): I've been in contact with others people
using bestcomm and please to see the development was still active. I'm
already using latest code on my board but this is not include in this
patch. Indeed, it needs some changes for ARCH=powerpc. Moreover, we have
a different approach for the tasks. I'll be pleased to work with the
bestcomm folks.
* mpc5k2.c: As far as I understood, using of_platform_device will allow
'smart' of tree parsing. I did not implement it yet.
* mpc5k2_pic.c : The thingy ;-). I moved it into arch/powerpc/sysdev as
suggested. This code is 99% copy/paste from the ARCH=ppc. I added an
irq_host with the appropriate xlate and co. However, I have not done
more as this code has been written by others. I think we should work
together to move to new Linux style irq. I stay ready to test or code
upcoming revision/
* arch/powerpc/platform/*. Here, only small changes has been made. I
added _CHRP_E5K2 (in asm/processor.h), an entry in chrp_names() and the
correct detection in arch/powerpc/platform/setup.c / chrp_setup_arch().
in chrp_init_IRQ(), I set ppc_md.get_irq to mpc52xx_get_irq and call
mpc52xx_init_irq().
* fec driver: I did not wrote it and just made small modification to
make it works with our bestcomm API. However, we will soon you the same.
I think this is out of topic for his patch.
* serial stuff / IBP Freq. As this frequency is MPC52xx specific. I
think it would make sense to add a new func mpc52xx_getipbfreq(void).
The way it would be implemented may depend of the architecture. Our
firmware contains an 'ipb-freq' property in '/builtin/'.
Signed-off-by: Nicolas DET <nd@bplan-gmbh.de>
Signed-off-by: Sven Luther <sl@bplan-gmbh.de>
[-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --]
[-- Type: text/plain, Size: 15074 bytes --]
diff -uprN a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
--- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200
+++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:10:18.000000000 +0200
@@ -51,6 +51,7 @@
#include <asm/mpic.h>
#include <asm/rtas.h>
#include <asm/xmon.h>
+#include <asm/mpc52xx.h>
#include "chrp.h"
@@ -101,7 +102,8 @@ static const char *chrp_names[] = {
"Motorola",
"IBM or Longtrail",
"Genesi Pegasos",
- "Total Impact Briq"
+ "Total Impact Briq",
+ "bPlan Efika"
};
void chrp_show_cpuinfo(struct seq_file *m)
@@ -260,6 +262,8 @@ void __init chrp_setup_arch(void)
machine = get_property(root, "model", NULL);
if (machine && strncmp(machine, "Pegasos", 7) == 0) {
_chrp_type = _CHRP_Pegasos;
+ } else if (machine && strncmp(machine, "EFIKA5K2", 8) == 0) {
+ _chrp_type =_CHRP_E5K2;
} else if (machine && strncmp(machine, "IBM", 3) == 0) {
_chrp_type = _CHRP_IBM;
} else if (machine && strncmp(machine, "MOT", 3) == 0) {
@@ -494,6 +498,12 @@ void __init chrp_init_IRQ(void)
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
struct device_node *kbd;
#endif
+ if (_chrp_type == _CHRP_E5K2) {
+ ppc_md.get_irq = mpc52xx_get_irq;
+ mpc52xx_init_irq();
+ return;
+ }
+
chrp_find_openpic();
chrp_find_8259();
@@ -530,6 +540,9 @@ chrp_init2(void)
chrp_nvram_init();
#endif
+ if (_chrp_type == _CHRP_E5K2)
+ return;
+
request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
request_region(0x00,0x20,"dma1");
diff -uprN a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
--- a/include/asm-powerpc/processor.h 2006-10-25 19:07:48.000000000 +0200
+++ b/include/asm-powerpc/processor.h 2006-10-25 19:11:54.000000000 +0200
@@ -33,6 +33,7 @@
#define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */
#define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */
#define _CHRP_briq 0x07 /* TotalImpact's briQ */
+#define _CHRP_E5K2 0x08 /* bPlan's Efika 5k2*/
#if defined(__KERNEL__) && defined(CONFIG_PPC32)
diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
--- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200
+++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200
@@ -119,7 +119,7 @@ enum ppc_sys_devices {
#define MPC52xx_SDMA_IRQ_NUM 17
#define MPC52xx_PERP_IRQ_NUM 23
-#define MPC52xx_CRIT_IRQ_BASE 1
+#define MPC52xx_CRIT_IRQ_BASE 0
#define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM)
#define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM)
#define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)
@@ -415,7 +415,7 @@ struct mpc52xx_cdm {
#ifndef __ASSEMBLY__
extern void mpc52xx_init_irq(void);
-extern int mpc52xx_get_irq(void);
+extern unsigned int mpc52xx_get_irq(void);
extern unsigned long mpc52xx_find_end_of_memory(void);
extern void mpc52xx_set_bat(void);
--- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100
+++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-25 19:17:48.000000000 +0200
@@ -0,0 +1,375 @@
+/*
+ * arch/powerpc/platforms/mpc5k2_pic.c
+ *
+ * Programmable Interrupt Controller functions for the Freescale MPC52xx
+ * embedded CPU.
+ * Modified for CHRP Efika 5K2
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Based on (well, mostly copied from) the code from the 2.4 kernel by
+ * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Montavista Software, Inc
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+//#define DEBUG
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#include <asm/mpc52xx.h>
+
+static struct mpc52xx_intr __iomem *intr;
+static struct mpc52xx_sdma __iomem *sdma;
+
+
+static struct irq_host *mpc52xx_irqhost = NULL;
+
+static void
+mpc52xx_ic_disable(unsigned int virq)
+{
+ u32 val;
+ int irq;
+
+ irq = irq_map[virq].hwirq;
+
+ pr_debug("%s: irq=%d\n", __func__, irq);
+
+ if (irq == MPC52xx_IRQ0) {
+ val = in_be32(&intr->ctrl);
+ val &= ~(1 << 11);
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC52xx_IRQ1) {
+ BUG();
+ } else if (irq <= MPC52xx_IRQ3) {
+ val = in_be32(&intr->ctrl);
+ val &= ~(1 << (10 - (irq - MPC52xx_IRQ1)));
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC52xx_SDMA_IRQ_BASE) {
+ val = in_be32(&intr->main_mask);
+ val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE));
+ out_be32(&intr->main_mask, val);
+ } else if (irq < MPC52xx_PERP_IRQ_BASE) {
+ val = in_be32(&sdma->IntMask);
+ val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE);
+ out_be32(&sdma->IntMask, val);
+ } else {
+ val = in_be32(&intr->per_mask);
+ val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
+ out_be32(&intr->per_mask, val);
+ }
+}
+
+static void
+mpc52xx_ic_enable(unsigned int virq)
+{
+ u32 val;
+ int irq;
+
+ irq = irq_map[virq].hwirq;
+
+ pr_debug("%s: irq=%d\n", __func__, irq);
+
+ if (irq == MPC52xx_IRQ0) {
+ val = in_be32(&intr->ctrl);
+ val |= 1 << 11;
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC52xx_IRQ1) {
+ BUG();
+ } else if (irq <= MPC52xx_IRQ3) {
+ val = in_be32(&intr->ctrl);
+ val |= 1 << (10 - (irq - MPC52xx_IRQ1));
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC52xx_SDMA_IRQ_BASE) {
+ val = in_be32(&intr->main_mask);
+ val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)));
+ out_be32(&intr->main_mask, val);
+ } else if (irq < MPC52xx_PERP_IRQ_BASE) {
+ val = in_be32(&sdma->IntMask);
+ val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE));
+ out_be32(&sdma->IntMask, val);
+ } else {
+ val = in_be32(&intr->per_mask);
+ val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
+ out_be32(&intr->per_mask, val);
+ }
+}
+
+static void
+mpc52xx_ic_ack(unsigned int virq)
+{
+ u32 val;
+ int irq;
+
+ irq = irq_map[virq].hwirq;
+
+ pr_debug("%s: irq=%d\n", __func__, irq);
+
+ /*
+ * Only some irqs are reset here, others in interrupting hardware.
+ */
+
+ switch (irq) {
+ case MPC52xx_IRQ0:
+ val = in_be32(&intr->ctrl);
+ val |= 0x08000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ case MPC52xx_CCS_IRQ:
+ val = in_be32(&intr->enc_status);
+ val |= 0x00000400;
+ out_be32(&intr->enc_status, val);
+ break;
+ case MPC52xx_IRQ1:
+ val = in_be32(&intr->ctrl);
+ val |= 0x04000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ case MPC52xx_IRQ2:
+ val = in_be32(&intr->ctrl);
+ val |= 0x02000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ case MPC52xx_IRQ3:
+ val = in_be32(&intr->ctrl);
+ val |= 0x01000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ default:
+ if (irq >= MPC52xx_SDMA_IRQ_BASE
+ && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) {
+ out_be32(&sdma->IntPend,
+ 1 << (irq - MPC52xx_SDMA_IRQ_BASE));
+ }
+
+ break;
+ }
+
+}
+
+static void
+mpc52xx_ic_disable_and_ack(unsigned int irq)
+{
+ mpc52xx_ic_disable(irq);
+ mpc52xx_ic_ack(irq);
+}
+
+static void
+mpc52xx_ic_end(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ mpc52xx_ic_enable(irq);
+}
+
+static struct irq_chip mpc52xx_irqchip = {
+ .name = " MPC52xx ",
+ .enable = mpc52xx_ic_enable,
+ .disable = mpc52xx_ic_disable,
+ .ack = mpc52xx_ic_disable_and_ack,
+ .end = mpc52xx_ic_end,
+};
+
+static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node)
+{
+ pr_debug("%s: node=%p\n", __func__, node);
+
+ if ( device_is_compatible(node, "mpc52xx-pic") )
+ return 1;
+
+ return device_is_compatible(node, "mpc5200-pic");
+}
+
+
+static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
+ u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+ static unsigned char map_senses[4] = {
+ IRQ_TYPE_LEVEL_HIGH,
+ IRQ_TYPE_EDGE_FALLING,
+ IRQ_TYPE_EDGE_RISING,
+ IRQ_TYPE_LEVEL_LOW,
+ };
+
+ int intrvect_l1;
+ int intrvect_l2;
+ int intrvect_type;
+ int intrvect_linux;
+
+ pr_debug("%s:\n", __func__);
+
+ if (intsize!=3)
+ return -1;
+
+ intrvect_l1 = (int) intspec[0];
+ intrvect_l2 = (int) intspec[1];
+ intrvect_type = (int) intspec[2];
+
+ pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, intrvect_type );
+
+ switch(intrvect_l1) {
+ case 0: /* Critical */
+ intrvect_linux = MPC52xx_CRIT_IRQ_BASE;
+ break;
+
+ case 1: /* Main */
+ intrvect_linux = MPC52xx_MAIN_IRQ_BASE;
+ break;
+
+ case 2: /* Periph */
+ intrvect_linux = MPC52xx_PERP_IRQ_BASE;
+ break;
+
+ case 3: /* Bestcomm */
+ intrvect_linux = MPC52xx_SDMA_IRQ_BASE;
+ break;
+
+ default:
+ if ( printk_ratelimit() )
+ printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", intrvect_l1);
+
+ return -1;
+ }
+
+ intrvect_linux += intrvect_l2;
+
+ pr_debug("return %d\n", intrvect_linux);
+
+ *out_hwirq = intrvect_linux;
+ *out_flags = map_senses[intrvect_type];
+
+ return 0;
+
+}
+
+int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw)
+{
+ pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int) hw);
+
+ return 0;
+}
+
+void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq)
+{
+ pr_debug("%s: v=%d\n", __func__, virq);
+}
+
+static struct irq_host_ops mpc52xx_irqhost_ops = {
+ .match = mpc52xx_irqhost_match,
+ .xlate = mpc52xx_irqhost_xlate,
+ .map = mpc52xx_irqhost_map,
+ .unmap = mpc52xx_irqhost_unmap,
+};
+
+void __init
+mpc52xx_init_irq(void)
+{
+ int i;
+ u32 intr_ctrl;
+
+
+ /* Remap the necessary zones */
+ intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
+ sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
+
+ if ((intr==NULL) || (sdma==NULL))
+ panic("Can't ioremap PIC/SDMA register or init_irq !");
+
+ /* Disable all interrupt sources. */
+ out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
+ out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
+ out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
+ out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
+ intr_ctrl = in_be32(&intr->ctrl);
+ intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */
+ intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
+ 0x00001000 | /* MEE master external enable */
+ 0x00000000 | /* 0 means disable IRQ 0-3 */
+ 0x00000001; /* CEb route critical normally */
+ out_be32(&intr->ctrl, intr_ctrl);
+
+ /* Zero a bunch of the priority settings. */
+ out_be32(&intr->per_pri1, 0);
+ out_be32(&intr->per_pri2, 0);
+ out_be32(&intr->per_pri3, 0);
+ out_be32(&intr->main_pri1, 0);
+ out_be32(&intr->main_pri2, 0);
+ /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].chip = &mpc52xx_irqchip;
+ irq_desc[i].status = IRQ_LEVEL;
+
+ }
+
+#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03)
+ for (i=0 ; i<4 ; i++) {
+ int mode;
+ mode = IRQn_MODE(intr_ctrl,i);
+ if ((mode == 0x1) || (mode == 0x2))
+ irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0;
+ }
+
+ /*
+ * As last step, add an irq host to translate the real
+ * hw irq information provided by the ofw to linux virq
+ */
+
+ mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 0, &mpc52xx_irqhost_ops, -1);
+ pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost );
+}
+
+unsigned int
+mpc52xx_get_irq(void)
+{
+ u32 status;
+ int virq;
+ int irq = NO_IRQ_IGNORE;
+
+ status = in_be32(&intr->enc_status);
+ if (status & 0x00000400)
+ { /* critical */
+ irq = (status >> 8) & 0x3;
+ if (irq == 2) /* high priority peripheral */
+ goto peripheral;
+ irq += MPC52xx_CRIT_IRQ_BASE;
+ } else if (status & 0x00200000)
+ { /* main */
+ irq = (status >> 16) & 0x1f;
+ if (irq == 4) /* low priority peripheral */
+ goto peripheral;
+ irq += MPC52xx_MAIN_IRQ_BASE;
+ } else if (status & 0x20000000)
+ { /* peripheral */
+peripheral:
+ irq = (status >> 24) & 0x1f;
+ if (irq == 0) { /* bestcomm */
+ status = in_be32(&sdma->IntPend);
+ irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1;
+ } else
+ irq += MPC52xx_PERP_IRQ_BASE;
+
+ }
+
+ virq = irq_linear_revmap(mpc52xx_irqhost, irq);
+ pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq);
+
+ return virq;
+}
+
--- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200
+++ b/arch/powerpc/sysdev/Makefile 2006-10-25 20:33:32.000000000 +0200
@@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_PPC_TODC) += todc.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
+obj-$(CONFIG_PPC_CHRP) += mpc52xx_pic.o
ifeq ($(CONFIG_PPC_MERGE),y)
obj-$(CONFIG_PPC_I8259) += i8259.o
[-- Attachment #3: nd.vcf --]
[-- Type: text/x-vcard, Size: 249 bytes --]
begin:vcard
fn:Nicolas DET ( bplan GmbH )
n:DET;Nicolas
org:bplan GmbH
adr:;;;;;;Germany
email;internet:nd@bplan-gmbh.de
title:Software Entwicklung
tel;work:+49 6171 9187 - 31
x-mozilla-html:FALSE
url:http://www.bplan-gmbh.de
version:2.1
end:vcard
^ permalink raw reply [flat|nested] 40+ messages in thread* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 19:05 [PATCH] General CHRP/MPC5K2 platform support patch Nicolas DET @ 2006-10-25 21:59 ` Paul Mackerras 2006-10-25 22:41 ` Grant Likely 2006-10-25 22:53 ` Benjamin Herrenschmidt ` (2 subsequent siblings) 3 siblings, 1 reply; 40+ messages in thread From: Paul Mackerras @ 2006-10-25 21:59 UTC (permalink / raw) To: Nicolas DET Cc: akpm, Sylvain Munaut, sl, linuxppc-dev, linuxppc-embedded, sha Nicolas DET writes: > if (machine && strncmp(machine, "Pegasos", 7) == 0) { > _chrp_type = _CHRP_Pegasos; > + } else if (machine && strncmp(machine, "EFIKA5K2", 8) == 0) { > + _chrp_type =_CHRP_E5K2; This whole _chrp_type thing, and having to do different things based on the root-node model property, is really only a workaround for older machines with inadequate device trees. Decisions about things like which interrupt controller driver(s) to instantiate should be taken based on properties in the appropriate device-tree nodes, for instance the model and compatible properties in the node(s) for the interrupt controller(s). In fact I'd like to get rid of _chrp_type completely. > diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h > --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 > +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 > @@ -119,7 +119,7 @@ enum ppc_sys_devices { > #define MPC52xx_SDMA_IRQ_NUM 17 > #define MPC52xx_PERP_IRQ_NUM 23 > > -#define MPC52xx_CRIT_IRQ_BASE 1 > +#define MPC52xx_CRIT_IRQ_BASE 0 What is this going to do to other 52xx users? Paul. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 21:59 ` Paul Mackerras @ 2006-10-25 22:41 ` Grant Likely 2006-10-25 22:59 ` Benjamin Herrenschmidt 2006-10-26 11:17 ` Nicolas DET 0 siblings, 2 replies; 40+ messages in thread From: Grant Likely @ 2006-10-25 22:41 UTC (permalink / raw) To: Paul Mackerras; +Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, sha On 10/25/06, Paul Mackerras <paulus@samba.org> wrote: > Nicolas DET writes: > > > if (machine && strncmp(machine, "Pegasos", 7) == 0) { > > _chrp_type = _CHRP_Pegasos; > > + } else if (machine && strncmp(machine, "EFIKA5K2", 8) == 0) { > > + _chrp_type =_CHRP_E5K2; > > This whole _chrp_type thing, and having to do different things based > on the root-node model property, is really only a workaround for > older machines with inadequate device trees. Decisions about things > like which interrupt controller driver(s) to instantiate should be > taken based on properties in the appropriate device-tree nodes, for > instance the model and compatible properties in the node(s) for the > interrupt controller(s). In fact I'd like to get rid of _chrp_type > completely. What are the implications anyway for the bplan board being CHRP vs the way the rest of the embedded ppcs are set up? Will having this setup as a CHRP system conflict w/ non-CHRP embedded boards? (I'm assuming that CHRP requires more capable firmware than u-boot passing in a fdt) > > > diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h > > --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 > > +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 > > @@ -119,7 +119,7 @@ enum ppc_sys_devices { > > #define MPC52xx_SDMA_IRQ_NUM 17 > > #define MPC52xx_PERP_IRQ_NUM 23 > > > > -#define MPC52xx_CRIT_IRQ_BASE 1 > > +#define MPC52xx_CRIT_IRQ_BASE 0 > > What is this going to do to other 52xx users? Shouldn't be a big deal if all drivers use the macros; but as you pointed out on IRC, the interrupt stuff needs to be reworked for the interrupt mapping interface anyway g. -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. grant.likely@secretlab.ca (403) 399-0195 ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 22:41 ` Grant Likely @ 2006-10-25 22:59 ` Benjamin Herrenschmidt 2006-10-26 11:09 ` Nicolas DET 2006-10-26 11:17 ` Nicolas DET 1 sibling, 1 reply; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-25 22:59 UTC (permalink / raw) To: Grant Likely Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, Paul Mackerras, sha > What are the implications anyway for the bplan board being CHRP vs the > way the rest of the embedded ppcs are set up? Will having this setup > as a CHRP system conflict w/ non-CHRP embedded boards? (I'm assuming > that CHRP requires more capable firmware than u-boot passing in a fdt) Not really :) The main thing they "buy" by going CHRP is that they use RTAS for PCI config space access and thus don't have to write the host bridge code. Since their firmware initializes everything properly, there is little need for non-generic platform code and that sort of generic platform code is what CHRP provides. With the device-tree thingy done properly nowadays, there should be little difference between platforms unless you end up dealing with really special things. There should be no conflict with non-CHRP boards using the MPC5200 chip provided they do things right which is what I've been advocating so far. That includes making sure everybody agrees on the format of the MPC5200 specific bits in the device-tree: - Format of the interrupt cells (they have come up upon my suggestion to a 3-cell based format (could probably be compressed a bit but heh) and that should be documented publically) - Binding (set of required properties and their definitions) for on chip devices, and more specifically, for representing the bestcomm and the links between devices and associated bestcomm tasks. If the above is properly agreed upon, then the code for dealing with MPC5200 specific devices will purely rely on those bits, and thus should be useable from whatever platform it's included in, wether it's CHRP, or something else. Unfortunately, at this point, Nicolas seems to be unwilling to open up his device-tree publically. Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 22:59 ` Benjamin Herrenschmidt @ 2006-10-26 11:09 ` Nicolas DET 0 siblings, 0 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-26 11:09 UTC (permalink / raw) To: Benjamin Herrenschmidt Cc: akpm, sl, linuxppc-dev, Paul Mackerras, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 734 bytes --] Benjamin Herrenschmidt wrote: > - Format of the interrupt cells (they have come up upon my suggestion > to a 3-cell based format (could probably be compressed a bit but heh) > and that should be documented publically) > It's some kind of 'documented' in mpc52xx_pic.c/xlate() > - Binding (set of required properties and their definitions) for on > chip devices, and more specifically, for representing the bestcomm and > the links between devices and associated bestcomm tasks. Bestcomm is something a bit 'weird'. I think we are the only to use this approach (task code loaded by the OFW and not by the OS). As said earlier, I've been in contact with an bestcomm coders and I think we would work together on this subject. [-- Attachment #2: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 22:41 ` Grant Likely 2006-10-25 22:59 ` Benjamin Herrenschmidt @ 2006-10-26 11:17 ` Nicolas DET 1 sibling, 0 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-26 11:17 UTC (permalink / raw) To: Grant Likely Cc: akpm, sl, linuxppc-dev, Paul Mackerras, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 1603 bytes --] Paul Mackerras wrote: > Nicolas DET writes: > >> if (machine && strncmp(machine, "Pegasos", 7) == 0) { >> _chrp_type = _CHRP_Pegasos; >> + } else if (machine && strncmp(machine, "EFIKA5K2", 8) == 0) { >> + _chrp_type =_CHRP_E5K2; > > This whole _chrp_type thing, and having to do different things based > on the root-node model property, is really only a workaround for > older machines with inadequate device trees. Decisions about things > like which interrupt controller driver(s) to instantiate should be > taken based on properties in the appropriate device-tree nodes, for > instance the model and compatible properties in the node(s) for the > interrupt controller(s). In fact I'd like to get rid of _chrp_type > completely. > I remove this part of the patch which is only cosmetic (good CHRP name). >> diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h >> --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 >> +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 >> @@ -119,7 +119,7 @@ enum ppc_sys_devices { >> #define MPC52xx_SDMA_IRQ_NUM 17 >> #define MPC52xx_PERP_IRQ_NUM 23 >> >> -#define MPC52xx_CRIT_IRQ_BASE 1 >> +#define MPC52xx_CRIT_IRQ_BASE 0 > > What is this going to do to other 52xx users? > IRQ 0 may cause issue in earlier kernel as far as I understood. New one, using the new IRQ stuff, just works (at least works great here). This is a revert change from: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e21b9f2e9a580ce7375ec58953c1bb19aabe0db4 Regards, [-- Attachment #2: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 19:05 [PATCH] General CHRP/MPC5K2 platform support patch Nicolas DET 2006-10-25 21:59 ` Paul Mackerras @ 2006-10-25 22:53 ` Benjamin Herrenschmidt 2006-10-26 11:09 ` Nicolas DET 2006-10-25 23:01 ` Grant Likely 2006-10-26 17:17 ` John Rigby 3 siblings, 1 reply; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-25 22:53 UTC (permalink / raw) To: Nicolas DET Cc: akpm, Sylvain Munaut, sl, linuxppc-dev, linuxppc-embedded, sha On Wed, 2006-10-25 at 21:05 +0200, Nicolas DET wrote: In addition to various whitespace damage in the patch... > + if (_chrp_type == _CHRP_E5K2) { > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return; > + } As I wrote, the above should be unnecessary. > chrp_find_openpic(); > chrp_find_8259(); Just add a chrp_find_mpc5200pic(); Which will set itself as the default controller and set ppc_md.get_irq if none have done it before. > @@ -530,6 +540,9 @@ chrp_init2(void) > chrp_nvram_init(); > #endif > > + if (_chrp_type == _CHRP_E5K2) > + return; Why that ? Not that we really need those request_region() anyway, but it's highly recommended that your firmware doesn't allocate anything in that "legacy" portion of the IO space anyway, so requesting those regions will do no harm. > request_region(0x20,0x20,"pic1"); > request_region(0xa0,0x20,"pic2"); > request_region(0x00,0x20,"dma1"); > +static void > +mpc52xx_ic_disable(unsigned int virq) > +{ > + u32 val; > + int irq; > + > + irq = irq_map[virq].hwirq; You should test if the result is valid just in case you were called with a bogus irq number > + pr_debug("%s: irq=%d\n", __func__, irq); > + > + if (irq == MPC52xx_IRQ0) { > + val = in_be32(&intr->ctrl); > + val &= ~(1 << 11); > + out_be32(&intr->ctrl, val); > + } else if (irq < MPC52xx_IRQ1) { > + BUG(); > + } else if (irq <= MPC52xx_IRQ3) { > + val = in_be32(&intr->ctrl); > + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); > + out_be32(&intr->ctrl, val); > + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { > + val = in_be32(&intr->main_mask); > + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); > + out_be32(&intr->main_mask, val); > + } else if (irq < MPC52xx_PERP_IRQ_BASE) { > + val = in_be32(&sdma->IntMask); > + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); > + out_be32(&sdma->IntMask, val); > + } else { > + val = in_be32(&intr->per_mask); > + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); > + out_be32(&intr->per_mask, val); > + } > +} You may want to chose a different encoding for your HW irqs to make the above less horrible. For example, have an irq category in some top bits and the actual bit mask pre-mashed in the bottom bits. And same comments for enable(). > +static void > +mpc52xx_ic_disable_and_ack(unsigned int irq) > +{ > + mpc52xx_ic_disable(irq); > + mpc52xx_ic_ack(irq); > +} You don't need the above. It will be done for you by the core code once you properly adapt to genirq. > +static void > +mpc52xx_ic_end(unsigned int irq) > +{ > + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) > + mpc52xx_ic_enable(irq); > +} The above is not necessary anymore, you need to properly adapt to genirq which you haven't done yet. > +static struct irq_chip mpc52xx_irqchip = { > + .name = " MPC52xx ", > + .enable = mpc52xx_ic_enable, > + .disable = mpc52xx_ic_disable, > + .ack = mpc52xx_ic_disable_and_ack, > + .end = mpc52xx_ic_end, > +}; As I said, you haven't properly adapted to genirq. That is enable -> unmask disable -> mask ack stays and doesn't do disable end is gone You also need to call set_irq_chip_and_handler(), possibly in your host map() function to set the right flow handler for your interrupts. > +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) > +{ > + pr_debug("%s: node=%p\n", __func__, node); > + > + if ( device_is_compatible(node, "mpc52xx-pic") ) > + return 1; > + > + return device_is_compatible(node, "mpc5200-pic"); > +} You probably need only one of the above statements. It depends on how the device-tree binding is defined for the MPC52xx which, for the 10000th time, should be done PUBLICALLY > +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) > +{ > + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int) hw); > + > + return 0; > +} As I said earlier, the above needs to at least set a flow handler. Also, if you intend to have different flow handlers for edge and level irqs, then you'll also probably need to implement set_irq_type(). You may want to look at the IPI driver for that (and beware of the lock problem with set_irq_type() vs. set_irq_handler(), see the IPIC patch that went on the list recently) > + /* Zero a bunch of the priority settings. */ > + out_be32(&intr->per_pri1, 0); > + out_be32(&intr->per_pri2, 0); > + out_be32(&intr->per_pri3, 0); > + out_be32(&intr->main_pri1, 0); > + out_be32(&intr->main_pri2, 0); > + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ > + for (i = 0; i < NR_IRQS; i++) { > + irq_desc[i].chip = &mpc52xx_irqchip; > + irq_desc[i].status = IRQ_LEVEL; > + > + } The above should go. With the port to genirq, you get descriptors as irqs get mapped, from your map callback, which is where you set the chip and flow handler. You should also never completley override status like that. Just or-in the bits you need. Look at what other PICs in arch/powerpc do. > +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) > + for (i=0 ; i<4 ; i++) { > + int mode; > + mode = IRQn_MODE(intr_ctrl,i); > + if ((mode == 0x1) || (mode == 0x2)) > + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; > + } What is the above about ? > + /* > + * As last step, add an irq host to translate the real > + * hw irq information provided by the ofw to linux virq > + */ > + > + mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 0, &mpc52xx_irqhost_ops, -1); > + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost ); > +} Ususally we do that first but heh, it doesn't really matter. However: passing a count of 0 when creating a linear revmap is totally bogus (in fact, I'm surprised your code works). Also, as far as the invalid irq is concerned, you should probably define it using a symbolic constant (properly typed) so you can use it elsewhere in the code to test the result of the revmap functions among others. > +unsigned int > +mpc52xx_get_irq(void) > +{ > + u32 status; > + int virq; > + int irq = NO_IRQ_IGNORE; > + > + status = in_be32(&intr->enc_status); > + if (status & 0x00000400) > + { /* critical */ > + irq = (status >> 8) & 0x3; > + if (irq == 2) /* high priority peripheral */ > + goto peripheral; > + irq += MPC52xx_CRIT_IRQ_BASE; > + } else if (status & 0x00200000) > + { /* main */ > + irq = (status >> 16) & 0x1f; > + if (irq == 4) /* low priority peripheral */ > + goto peripheral; > + irq += MPC52xx_MAIN_IRQ_BASE; > + } else if (status & 0x20000000) > + { /* peripheral */ > +peripheral: > + irq = (status >> 24) & 0x1f; > + if (irq == 0) { /* bestcomm */ > + status = in_be32(&sdma->IntPend); > + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; > + } else > + irq += MPC52xx_PERP_IRQ_BASE; > + > + } > + > + virq = irq_linear_revmap(mpc52xx_irqhost, irq); > + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); > + > + return virq; > +} I'm surprised the revmap is working at all... considering the issues you have above. You are lucky but things should be fixed anyway. > --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 > +++ b/arch/powerpc/sysdev/Makefile 2006-10-25 20:33:32.000000000 +0200 > @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o > obj-$(CONFIG_PPC_TODC) += todc.o > obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o > obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ > +obj-$(CONFIG_PPC_CHRP) += mpc52xx_pic.o That's not the proper way to do it. Instead, define an invisible CONFIG_MPC52xx_PIC and have the chrp platform select it. > ifeq ($(CONFIG_PPC_MERGE),y) > obj-$(CONFIG_PPC_I8259) += i8259.o Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 22:53 ` Benjamin Herrenschmidt @ 2006-10-26 11:09 ` Nicolas DET 2006-10-26 12:49 ` Benjamin Herrenschmidt 0 siblings, 1 reply; 40+ messages in thread From: Nicolas DET @ 2006-10-26 11:09 UTC (permalink / raw) To: Benjamin Herrenschmidt Cc: akpm, Sylvain Munaut, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 1742 bytes --] Benjamin Herrenschmidt wrote: > On Wed, 2006-10-25 at 21:05 +0200, Nicolas DET wrote: > > In addition to various whitespace damage in the patch... > >> + if (_chrp_type == _CHRP_E5K2) { >> + ppc_md.get_irq = mpc52xx_get_irq; >> + mpc52xx_init_irq(); >> + return; >> + } > > As I wrote, the above should be unnecessary. > >> chrp_find_openpic(); >> chrp_find_8259(); > > Just add a > > chrp_find_mpc5200pic(); > > Which will set itself as the default controller and set ppc_md.get_irq > if none have done it before. > >> @@ -530,6 +540,9 @@ chrp_init2(void) >> chrp_nvram_init(); >> #endif >> >> + if (_chrp_type == _CHRP_E5K2) >> + return; > Done. >> +static void >> +mpc52xx_ic_disable(unsigned int virq) >> +{ >> + u32 val; >> + int irq; >> + >> + irq = irq_map[virq].hwirq; > > You should test if the result is valid just in case you were called with > [...] > I'm surprised the revmap is working at all... considering the issues you > have above. You are lucky but things should be fixed anyway. > As said in the mail. I'm waiting for the opinion of the original authors and the mainteners. What's why I did not made much change in this file. In the current patch, I know do: mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, -1); Which should be ok. >> --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 >> +++ b/arch/powerpc/sysdev/Makefile 2006-10-25 20:33:32.000000000 +0200 >> @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o >> obj-$(CONFIG_PPC_TODC) += todc.o >> obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o >> obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ >> +obj-$(CONFIG_PPC_CHRP) += mpc52xx_pic.o > Done. Regards [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 15111 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 10:55:44.000000000 +0200 @@ -0,0 +1,371 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * Modified for CHRP Efika 5K2 + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +//#define DEBUG + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> + +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; + +static struct irq_host *mpc52xx_irqhost = NULL; + +static void +mpc52xx_ic_disable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_enable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + + break; + } + +} + +static void +mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void +mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .name = " MPC52xx ", + .enable = mpc52xx_ic_enable, + .disable = mpc52xx_ic_disable, + .ack = mpc52xx_ic_disable_and_ack, + .end = mpc52xx_ic_end, +}; + + +extern struct device_node *find_mpc52xx_pic(void); +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); + return find_mpc52xx_pic() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + pr_debug("%s:\n", __func__); + + if (intsize!=3) + return -1; + + intrvect_l1 = (int) intspec[0]; + intrvect_l2 = (int) intspec[1]; + intrvect_type = (int) intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, intrvect_type ); + + switch(intrvect_l1) { + case 0: /* Critical */ + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; + break; + + case 1: /* Main */ + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; + break; + + case 2: /* Periph */ + intrvect_linux = MPC52xx_PERP_IRQ_BASE; + break; + + case 3: /* Bestcomm */ + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; + break; + + default: + if ( printk_ratelimit() ) + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", intrvect_l1); + + return -1; + } + + intrvect_linux += intrvect_l2; + + pr_debug("return %d\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) +{ + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int) hw); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%d\n", __func__, virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init +mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr==NULL) || (sdma==NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i=0 ; i<4 ; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl,i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, -1); + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost ); +} + +unsigned int +mpc52xx_get_irq(void) +{ + u32 status; + int virq; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) + { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } else if (status & 0x00200000) + { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } else if (status & 0x20000000) + { /* peripheral */ +peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; + } else + irq += MPC52xx_PERP_IRQ_BASE; + + } + + virq = irq_linear_revmap(mpc52xx_irqhost, irq); + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); + + return virq; +} + --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-26 11:32:54.000000000 +0200 @@ -384,6 +384,12 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool + depends on PPC_CHRP default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 10:59:39.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = }; #endif + +struct device_node *find_mpc52xx_pic(void) +{ + struct device_node *dev; + const char *piccompatible_list[] = + { + "mpc5200-interrupt-controller", + "mpc52xx-interrupt-controller", + "mpc52xx-pic", + "mpc5200-pic", + "5200-interrupt-controller", + "52xx-interrupt-controller", + "52xx-pic", + "5200-pic", + NULL + }; + + /* Look for an MPC52xx interrupt controller */ + for_each_node_by_type(dev, "interrupt-controller") + { + const char **piccompatible_entry = piccompatible_list; + + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) + { + if (device_is_compatible(dev, *piccompatible_entry )) + return dev; + } + } + + return NULL; +} + +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_pic()) + { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -494,8 +540,12 @@ void __init chrp_init_IRQ(void) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif - chrp_find_openpic(); - chrp_find_8259(); + + if ( chrp_find_mpc52xx_pic() < 0) + { + chrp_find_openpic(); + chrp_find_8259(); + } #ifdef CONFIG_SMP /* Pegasos has no MPIC, those ops would make it crash. It might be an diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 @@ -119,7 +119,7 @@ enum ppc_sys_devices { #define MPC52xx_SDMA_IRQ_NUM 17 #define MPC52xx_PERP_IRQ_NUM 23 -#define MPC52xx_CRIT_IRQ_BASE 1 +#define MPC52xx_CRIT_IRQ_BASE 0 #define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM) #define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM) #define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM) @@ -415,7 +415,7 @@ struct mpc52xx_cdm { #ifndef __ASSEMBLY__ extern void mpc52xx_init_irq(void); -extern int mpc52xx_get_irq(void); +extern unsigned int mpc52xx_get_irq(void); extern unsigned long mpc52xx_find_end_of_memory(void); extern void mpc52xx_set_bat(void); [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 11:09 ` Nicolas DET @ 2006-10-26 12:49 ` Benjamin Herrenschmidt 2006-10-26 12:59 ` Nicolas DET 0 siblings, 1 reply; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-26 12:49 UTC (permalink / raw) To: Nicolas DET Cc: akpm, Sylvain Munaut, sl, linuxppc-dev, linuxppc-embedded, sha > rent patch, I know do: > mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, > &mpc52xx_irqhost_ops, -1); > > Which should be ok. NR_IRQ, it's a bit violent :) It's also the max number of virtual IRQs and thus has nothing to do with your HW numbers. Use the max number of HW IRQs here. Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 12:49 ` Benjamin Herrenschmidt @ 2006-10-26 12:59 ` Nicolas DET 2006-10-26 16:02 ` Grant Likely 0 siblings, 1 reply; 40+ messages in thread From: Nicolas DET @ 2006-10-26 12:59 UTC (permalink / raw) To: Benjamin Herrenschmidt Cc: akpm, Sylvain Munaut, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 364 bytes --] Benjamin Herrenschmidt wrote: >> rent patch, I know do: >> mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, >> &mpc52xx_irqhost_ops, -1); >> >> Which should be ok. > > NR_IRQ, it's a bit violent :) It's also the max number of virtual IRQs > and thus has nothing to do with your HW numbers. Use the max number of > HW IRQs here. > > Ben. > > > [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 15122 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 10:55:44.000000000 +0200 @@ -0,0 +1,371 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * Modified for CHRP Efika 5K2 + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +//#define DEBUG + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> + +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; + +static struct irq_host *mpc52xx_irqhost = NULL; + +static void +mpc52xx_ic_disable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_enable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + + break; + } + +} + +static void +mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void +mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .name = " MPC52xx ", + .enable = mpc52xx_ic_enable, + .disable = mpc52xx_ic_disable, + .ack = mpc52xx_ic_disable_and_ack, + .end = mpc52xx_ic_end, +}; + + +extern struct device_node *find_mpc52xx_pic(void); +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); + return find_mpc52xx_pic() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + pr_debug("%s:\n", __func__); + + if (intsize!=3) + return -1; + + intrvect_l1 = (int) intspec[0]; + intrvect_l2 = (int) intspec[1]; + intrvect_type = (int) intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, intrvect_type ); + + switch(intrvect_l1) { + case 0: /* Critical */ + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; + break; + + case 1: /* Main */ + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; + break; + + case 2: /* Periph */ + intrvect_linux = MPC52xx_PERP_IRQ_BASE; + break; + + case 3: /* Bestcomm */ + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; + break; + + default: + if ( printk_ratelimit() ) + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", intrvect_l1); + + return -1; + } + + intrvect_linux += intrvect_l2; + + pr_debug("return %d\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) +{ + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int) hw); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%d\n", __func__, virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init +mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr==NULL) || (sdma==NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i=0 ; i<4 ; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl,i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, MPC52xx_BDLC_IRQ+1, &mpc52xx_irqhost_ops, -1); + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost ); +} + +unsigned int +mpc52xx_get_irq(void) +{ + u32 status; + int virq; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) + { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } else if (status & 0x00200000) + { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } else if (status & 0x20000000) + { /* peripheral */ +peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; + } else + irq += MPC52xx_PERP_IRQ_BASE; + + } + + virq = irq_linear_revmap(mpc52xx_irqhost, irq); + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); + + return virq; +} + --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-26 11:32:54.000000000 +0200 @@ -384,6 +384,12 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool + depends on PPC_CHRP default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 10:59:39.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = }; #endif + +struct device_node *find_mpc52xx_pic(void) +{ + struct device_node *dev; + const char *piccompatible_list[] = + { + "mpc5200-interrupt-controller", + "mpc52xx-interrupt-controller", + "mpc52xx-pic", + "mpc5200-pic", + "5200-interrupt-controller", + "52xx-interrupt-controller", + "52xx-pic", + "5200-pic", + NULL + }; + + /* Look for an MPC52xx interrupt controller */ + for_each_node_by_type(dev, "interrupt-controller") + { + const char **piccompatible_entry = piccompatible_list; + + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) + { + if (device_is_compatible(dev, *piccompatible_entry )) + return dev; + } + } + + return NULL; +} + +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_pic()) + { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -494,8 +540,12 @@ void __init chrp_init_IRQ(void) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif - chrp_find_openpic(); - chrp_find_8259(); + + if ( chrp_find_mpc52xx_pic() < 0) + { + chrp_find_openpic(); + chrp_find_8259(); + } #ifdef CONFIG_SMP /* Pegasos has no MPIC, those ops would make it crash. It might be an diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 @@ -119,7 +119,7 @@ enum ppc_sys_devices { #define MPC52xx_SDMA_IRQ_NUM 17 #define MPC52xx_PERP_IRQ_NUM 23 -#define MPC52xx_CRIT_IRQ_BASE 1 +#define MPC52xx_CRIT_IRQ_BASE 0 #define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM) #define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM) #define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM) @@ -415,7 +415,7 @@ struct mpc52xx_cdm { #ifndef __ASSEMBLY__ extern void mpc52xx_init_irq(void); -extern int mpc52xx_get_irq(void); +extern unsigned int mpc52xx_get_irq(void); extern unsigned long mpc52xx_find_end_of_memory(void); extern void mpc52xx_set_bat(void); [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 12:59 ` Nicolas DET @ 2006-10-26 16:02 ` Grant Likely 2006-10-26 16:09 ` Grant Likely ` (2 more replies) 0 siblings, 3 replies; 40+ messages in thread From: Grant Likely @ 2006-10-26 16:02 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha (minor) Whitespace is still inconsistent; mostly spaces used where they should be tabs and a few lines longer than 80 chars. Running the source through scripts/Lindent will help. On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: > --- a/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-25 19:07:24.000000000 +0200 > +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 10:55:44.000000000 +0200 > @@ -0,0 +1,371 @@ > +/* > + * arch/powerpc/sysdev/mpc52xx_pic.c > + * > + * Programmable Interrupt Controller functions for the Freescale MPC52xx > + * embedded CPU. > + * Modified for CHRP Efika 5K2 Don't really need to add the "Modified for.." line; That's what git is for. Besides this code is modified for more than just the Efika now. :) > + * > + * Maintainer : Sylvain Munaut <tnt@246tNt.com> > + * > + * Based on (well, mostly copied from) the code from the 2.4 kernel by > + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. Ditto for this; but I know you didn't add it. :) Although this kind of comment is more justified because it captures information not maintained in git. (Namely where the original file came from.) > + * > + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> > + * Copyright (C) 2003 Montavista Software, Inc You should add a bplan copyright line too. > + * > + * This file is licensed under the terms of the GNU General Public License > + * version 2. This program is licensed "as is" without any warranty of any > + * kind, whether express or implied. > + */ > + > +//#define DEBUG C++ style comment bad. :) > + > +#include <linux/stddef.h> > +#include <linux/init.h> > +#include <linux/sched.h> > +#include <linux/signal.h> > +#include <linux/stddef.h> > +#include <linux/delay.h> > +#include <linux/irq.h> > + > +#include <asm/io.h> > +#include <asm/processor.h> > +#include <asm/system.h> > +#include <asm/irq.h> > +#include <asm/prom.h> > + > +#include <asm/mpc52xx.h> > + > +static struct mpc52xx_intr __iomem *intr; > +static struct mpc52xx_sdma __iomem *sdma; > + > +static struct irq_host *mpc52xx_irqhost = NULL; > + (snip) > --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/Kconfig 2006-10-26 11:32:54.000000000 +0200 > @@ -384,6 +384,12 @@ config PPC_CHRP > select PPC_RTAS > select PPC_MPC106 > select PPC_UDBG_16550 > + select PPC_MPC52xx_PIC > + default y > + > +config PPC_MPC52xx_PIC > + bool > + depends on PPC_CHRP > default y This isn't good for embedded 52xx boards. Anything u-boot based cannot be CHRP. Please drop the "depends on" line > --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 10:59:39.000000000 +0200 > @@ -51,6 +51,7 @@ > #include <asm/mpic.h> > #include <asm/rtas.h> > #include <asm/xmon.h> > +#include <asm/mpc52xx.h> > > #include "chrp.h" > > @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = > }; > #endif > > + > +struct device_node *find_mpc52xx_pic(void) > +{ > + struct device_node *dev; > + const char *piccompatible_list[] = > + { > + "mpc5200-interrupt-controller", > + "mpc52xx-interrupt-controller", > + "mpc52xx-pic", > + "mpc5200-pic", > + "5200-interrupt-controller", > + "52xx-interrupt-controller", > + "52xx-pic", > + "5200-pic", > + NULL > + }; Considering Efika is the *only* CHRP 52xx board out there at the moment, and only a handful of embedded folks trying to move it to arch/powerpc, surely we can come to an agreement now on what this thing is named. :) Seriously, just recommend a name to use and everyone will use it. Providing a list of names means that every name in your list will be used. > + > + /* Look for an MPC52xx interrupt controller */ > + for_each_node_by_type(dev, "interrupt-controller") > + { > + const char **piccompatible_entry = piccompatible_list; > + > + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) > + { > + if (device_is_compatible(dev, *piccompatible_entry )) > + return dev; > + } > + } > + > + return NULL; > +} > + > +static int __init chrp_find_mpc52xx_pic(void) > +{ > + if (find_mpc52xx_pic()) > + { > + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return 0; > + } > + > + return -ENODEV; > +} > + > static void __init chrp_find_8259(void) > { > struct device_node *np, *pic = NULL; > @@ -494,8 +540,12 @@ void __init chrp_init_IRQ(void) > #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) > struct device_node *kbd; > #endif > - chrp_find_openpic(); > - chrp_find_8259(); > + > + if ( chrp_find_mpc52xx_pic() < 0) > + { > + chrp_find_openpic(); > + chrp_find_8259(); > + } Why? Why not just add the call to chrp_find_mpc52xx_pic() before or after the other two chrp_find_ calls? Will calling them cause things to break? Keep the code simple. Cheers, g. -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. grant.likely@secretlab.ca (403) 399-0195 ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 16:02 ` Grant Likely @ 2006-10-26 16:09 ` Grant Likely 2006-10-26 17:06 ` Nicolas DET 2006-10-26 16:45 ` Sven Luther 2006-10-26 19:50 ` Nicolas DET 2 siblings, 1 reply; 40+ messages in thread From: Grant Likely @ 2006-10-26 16:09 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha On 10/26/06, Grant Likely <grant.likely@secretlab.ca> wrote: > On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: > > - chrp_find_openpic(); > > - chrp_find_8259(); > > + > > + if ( chrp_find_mpc52xx_pic() < 0) > > + { > > + chrp_find_openpic(); > > + chrp_find_8259(); > > + } > > Why? Why not just add the call to chrp_find_mpc52xx_pic() before or > after the other two chrp_find_ calls? Will calling them cause things > to break? > > Keep the code simple. ... as possible; but no simpler. :) g. -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. grant.likely@secretlab.ca (403) 399-0195 ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 16:09 ` Grant Likely @ 2006-10-26 17:06 ` Nicolas DET 2006-10-26 17:54 ` Sylvain Munaut ` (2 more replies) 0 siblings, 3 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-26 17:06 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 631 bytes --] Grant Likely wrote: > On 10/26/06, Grant Likely <grant.likely@secretlab.ca> wrote: >> On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: >> > - chrp_find_openpic(); >> > - chrp_find_8259(); >> > + >> > + if ( chrp_find_mpc52xx_pic() < 0) >> > + { >> > + chrp_find_openpic(); >> > + chrp_find_8259(); >> > + } >> >> Why? Why not just add the call to chrp_find_mpc52xx_pic() before or >> after the other two chrp_find_ calls? Will calling them cause things >> to break? >> As decided on the IRC channel. a patch which remove the check but fix chrp_find_8259(). Regards, [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 15259 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 18:55:04.000000000 +0200 @@ -0,0 +1,368 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> + +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; + +static struct irq_host *mpc52xx_irqhost = NULL; + +static void +mpc52xx_ic_disable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_enable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + + break; + } + +} + +static void +mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void +mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .name = " MPC52xx ", + .enable = mpc52xx_ic_enable, + .disable = mpc52xx_ic_disable, + .ack = mpc52xx_ic_disable_and_ack, + .end = mpc52xx_ic_end, +}; + + +extern struct device_node *find_mpc52xx_pic(void); +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); + return find_mpc52xx_pic() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + pr_debug("%s:\n", __func__); + + if (intsize!=3) + return -1; + + intrvect_l1 = (int) intspec[0]; + intrvect_l2 = (int) intspec[1]; + intrvect_type = (int) intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, intrvect_type ); + + switch(intrvect_l1) { + case 0: /* Critical */ + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; + break; + + case 1: /* Main */ + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; + break; + + case 2: /* Periph */ + intrvect_linux = MPC52xx_PERP_IRQ_BASE; + break; + + case 3: /* Bestcomm */ + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; + break; + + default: + if ( printk_ratelimit() ) + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", intrvect_l1); + + return -1; + } + + intrvect_linux += intrvect_l2; + + pr_debug("return %d\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) +{ + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int) hw); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%d\n", __func__, virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init +mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr==NULL) || (sdma==NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i=0 ; i<4 ; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl,i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, -1); + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost ); +} + +unsigned int +mpc52xx_get_irq(void) +{ + u32 status; + int virq; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) + { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } else if (status & 0x00200000) + { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } else if (status & 0x20000000) + { /* peripheral */ +peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; + } else + irq += MPC52xx_PERP_IRQ_BASE; + + } + + virq = irq_linear_revmap(mpc52xx_irqhost, irq); + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); + + return virq; +} + --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 @@ -384,6 +384,11 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 18:56:34.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = }; #endif + +struct device_node *find_mpc52xx_pic(void) +{ + struct device_node *dev; + const char *piccompatible_list[] = + { + "mpc5200-interrupt-controller", + "mpc52xx-interrupt-controller", + "mpc52xx-pic", + "mpc5200-pic", + "5200-interrupt-controller", + "52xx-interrupt-controller", + "52xx-pic", + "5200-pic", + NULL + }; + + /* Look for an MPC52xx interrupt controller */ + for_each_node_by_type(dev, "interrupt-controller") + { + const char **piccompatible_entry = piccompatible_list; + + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) + { + if (device_is_compatible(dev, *piccompatible_entry )) + return dev; + } + } + + return NULL; +} + +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_pic()) + { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -473,8 +519,11 @@ static void __init chrp_find_8259(void) break; } if (np == NULL) - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" - " address, polling\n"); + { + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" + " Fix your tree!\n"); + return; + } i8259_init(pic, chrp_int_ack); if (ppc_md.get_irq == NULL) @@ -494,6 +543,8 @@ void __init chrp_init_IRQ(void) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif + + chrp_find_mpc52xx_pic(); chrp_find_openpic(); chrp_find_8259(); diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 @@ -119,7 +119,7 @@ enum ppc_sys_devices { #define MPC52xx_SDMA_IRQ_NUM 17 #define MPC52xx_PERP_IRQ_NUM 23 -#define MPC52xx_CRIT_IRQ_BASE 1 +#define MPC52xx_CRIT_IRQ_BASE 0 #define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM) #define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM) #define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM) @@ -415,7 +415,7 @@ struct mpc52xx_cdm { #ifndef __ASSEMBLY__ extern void mpc52xx_init_irq(void); -extern int mpc52xx_get_irq(void); +extern unsigned int mpc52xx_get_irq(void); extern unsigned long mpc52xx_find_end_of_memory(void); extern void mpc52xx_set_bat(void); [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:06 ` Nicolas DET @ 2006-10-26 17:54 ` Sylvain Munaut 2006-10-27 3:08 ` Benjamin Herrenschmidt 2006-10-26 19:14 ` Grant Likely 2006-10-27 2:49 ` Benjamin Herrenschmidt 2 siblings, 1 reply; 40+ messages in thread From: Sylvain Munaut @ 2006-10-26 17:54 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha Hi Nicolas, I don't have much to add to what's already been posted, so here's a couple of details, mainly compatibility concerns with the legacy arch/ppc tree. > > diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h > --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 > +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 > @@ -119,7 +119,7 @@ enum ppc_sys_devices { > #define MPC52xx_SDMA_IRQ_NUM 17 > #define MPC52xx_PERP_IRQ_NUM 23 > > -#define MPC52xx_CRIT_IRQ_BASE 1 > +#define MPC52xx_CRIT_IRQ_BASE 0 As explained in IRC, I'm not sure about this. I was previously talked into applying this to avoid using interrupt number 0. In the LITE5200 IRQ0 is used for PCI. It's interrupt number is equal to MPC52xx_CRIT_IRQ_BASE and if it's 0 some drivers just don't work. That's when using the arch/ppc code. Apparently this is no longer an issue in arch/powerpc (someone to confirm and explain me why ? I would guess the irq_linear_revmap thingie ), but can a "standard" lite5200 be booted in a arch/powerpc kernel ? So if no critical, I would postpone that change until it's confirmed a lite5200 can boot ... > -extern int mpc52xx_get_irq(void); > +extern unsigned int mpc52xx_get_irq(void); Mmmh, the one in arch/ppc is not unsigned but I guess the warning is fine. Finally, some triviality : The patch adds some space on empty lines. Also, the indentation is sometimes done with space and sometimes with space ... Sylvain ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:54 ` Sylvain Munaut @ 2006-10-27 3:08 ` Benjamin Herrenschmidt 0 siblings, 0 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-27 3:08 UTC (permalink / raw) To: Sylvain Munaut; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha On Thu, 2006-10-26 at 19:54 +0200, Sylvain Munaut wrote: > Hi Nicolas, > > > I don't have much to add to what's already been posted, so here's a > couple of details, > mainly compatibility concerns with the legacy arch/ppc tree. I'd rather not clobber the code to be compatible with arch/ppc... once 52xx is ported over, I'm happy to completely drop support for arch/ppc 52xx. If we want to keep dual support for a while and we are changing APIs too much, we can just fork the drivers for a kernel version of two until we are confident enough to drop the arch/ppc version. > > diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h > > --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 > > +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 > > @@ -119,7 +119,7 @@ enum ppc_sys_devices { > > #define MPC52xx_SDMA_IRQ_NUM 17 > > #define MPC52xx_PERP_IRQ_NUM 23 > > > > -#define MPC52xx_CRIT_IRQ_BASE 1 > > +#define MPC52xx_CRIT_IRQ_BASE 0 > As explained in IRC, I'm not sure about this. > I was previously talked into applying this to avoid using interrupt > number 0. In the LITE5200 IRQ0 is used for PCI. It's interrupt number > is equal to MPC52xx_CRIT_IRQ_BASE and if it's 0 some drivers just don't > work. arch/powerpc has completely virtualized interrupt numbering. The "hardware" numbers supported by a given interrupt controller are generally not visible to a driver and can have any value including 0. The system will assign virtual numbers when interrupts are "mapped" and those will never be 0. > That's when using the arch/ppc code. Apparently this is no longer an > issue in arch/powerpc (someone to confirm and explain me why ? I would guess > the irq_linear_revmap thingie ), but can a "standard" lite5200 be booted > in a arch/powerpc kernel ? Once the code has been ported over :-) > So if no critical, I would postpone that change until it's confirmed > a lite5200 can boot ... It's not been ported yet I presume. Anyway, as I said, we shouldn't bother too much about what is in arch/ppc. If we think we are changing things in a conflicting way, then we should fork the drivers and includes (you can have the same include in both asm-ppc and asm-powerpc, the one matching you building ARCH will be used and they can have different definitions). > > -extern int mpc52xx_get_irq(void); > > +extern unsigned int mpc52xx_get_irq(void); > Mmmh, the one in arch/ppc is not unsigned but I guess the warning is fine. We should instead create a new mpc52xx.h in include/asm-powerpc and leave arch/ppc alone > Finally, some triviality : The patch adds some space on empty lines. Also, > the indentation is sometimes done with space and sometimes with space ... Yeah, I've noticed that the patch is fairly whitespace damaged. It's also incorrect in many ways concerning the hooking to genirq, I'm surprised it works at all in fact. It might be useful if somebody got me one of those boards (either efika or lite5200b) so I can do some proper rework of that stuff. Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:06 ` Nicolas DET 2006-10-26 17:54 ` Sylvain Munaut @ 2006-10-26 19:14 ` Grant Likely 2006-10-26 19:21 ` Nicolas DET 2006-10-27 2:49 ` Benjamin Herrenschmidt 2 siblings, 1 reply; 40+ messages in thread From: Grant Likely @ 2006-10-26 19:14 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha I've already made these comments on IRC; but I'll repeat them here for posterity. :) General: - Run this code through Lindent; fixes up spacing and line endings On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: > --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 18:56:34.000000000 +0200 > @@ -51,6 +51,7 @@ > #include <asm/mpic.h> > #include <asm/rtas.h> > #include <asm/xmon.h> > +#include <asm/mpc52xx.h> > > #include "chrp.h" > > @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = > }; > #endif > > + > +struct device_node *find_mpc52xx_pic(void) > +{ > + struct device_node *dev; > + const char *piccompatible_list[] = > + { > + "mpc5200-interrupt-controller", > + "mpc52xx-interrupt-controller", > + "mpc52xx-pic", > + "mpc5200-pic", > + "5200-interrupt-controller", > + "52xx-interrupt-controller", > + "52xx-pic", > + "5200-pic", > + NULL > + }; As you mentioned on IRC that benh suggested "mpc52xx-pic"; Just call it mpc52xx-pic and be done with it. Don't need to loop over this table. If incompatible variants appear in the future; this can change. > + > + /* Look for an MPC52xx interrupt controller */ > + for_each_node_by_type(dev, "interrupt-controller") > + { > + const char **piccompatible_entry = piccompatible_list; > + > + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) > + { > + if (device_is_compatible(dev, *piccompatible_entry )) > + return dev; > + } > + } > + > + return NULL; > +} > + > +static int __init chrp_find_mpc52xx_pic(void) > +{ > + if (find_mpc52xx_pic()) > + { > + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return 0; > + } > + > + return -ENODEV; > +} > + > static void __init chrp_find_8259(void) > { > struct device_node *np, *pic = NULL; > @@ -473,8 +519,11 @@ static void __init chrp_find_8259(void) > break; > } > if (np == NULL) > - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" > - " address, polling\n"); > + { > + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" > + " Fix your tree!\n"); > + return; > + } > > i8259_init(pic, chrp_int_ack); > if (ppc_md.get_irq == NULL) Missing the fixup to prevent i8258 from clobbering the 52xx-pic. You do need to have that change in this patch; or have this patch dependent on another patch that fixes it. Otherwise, as you know, this patch is worthless! :) And on the other side of this coin; I don't think that the message change in chrp_find_8259 has anything to do with adding mpc52xx. :) (Unfortunately, I have tendencies towards perfectionism) And on the flip side, I would (* > @@ -494,6 +543,8 @@ void __init chrp_init_IRQ(void) > #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) > struct device_node *kbd; > #endif > + > + chrp_find_mpc52xx_pic(); > chrp_find_openpic(); > chrp_find_8259(); > > diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h > --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 > +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 > @@ -119,7 +119,7 @@ enum ppc_sys_devices { > #define MPC52xx_SDMA_IRQ_NUM 17 > #define MPC52xx_PERP_IRQ_NUM 23 > > -#define MPC52xx_CRIT_IRQ_BASE 1 > +#define MPC52xx_CRIT_IRQ_BASE 0 Is this *strictly* necessary for adding mpc52xx-pic support to arch/powerpc? If not, then move it to a separate patch. > #define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM) > #define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM) > #define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM) > @@ -415,7 +415,7 @@ struct mpc52xx_cdm { > #ifndef __ASSEMBLY__ > > extern void mpc52xx_init_irq(void); > -extern int mpc52xx_get_irq(void); > +extern unsigned int mpc52xx_get_irq(void); Yeah, you really shouldn't do this without fixing the arch/ppc side too. g. -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. grant.likely@secretlab.ca (403) 399-0195 ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 19:14 ` Grant Likely @ 2006-10-26 19:21 ` Nicolas DET 2006-10-26 19:32 ` Nicolas DET 0 siblings, 1 reply; 40+ messages in thread From: Nicolas DET @ 2006-10-26 19:21 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 611 bytes --] Grant Likely wrote: >> >> diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h >> --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 >> +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 >> @@ -119,7 +119,7 @@ enum ppc_sys_devices { >> #define MPC52xx_SDMA_IRQ_NUM 17 >> #define MPC52xx_PERP_IRQ_NUM 23 >> >> -#define MPC52xx_CRIT_IRQ_BASE 1 >> +#define MPC52xx_CRIT_IRQ_BASE 0 > > Is this *strictly* necessary for adding mpc52xx-pic support to > arch/powerpc? If not, then move it to a separate patch. Removed as it does not hurt ARCH=powerpc. Bye [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 14370 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 18:55:04.000000000 +0200 @@ -0,0 +1,368 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> + +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; + +static struct irq_host *mpc52xx_irqhost = NULL; + +static void +mpc52xx_ic_disable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_enable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + + break; + } + +} + +static void +mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void +mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .name = " MPC52xx ", + .enable = mpc52xx_ic_enable, + .disable = mpc52xx_ic_disable, + .ack = mpc52xx_ic_disable_and_ack, + .end = mpc52xx_ic_end, +}; + + +extern struct device_node *find_mpc52xx_pic(void); +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); + return find_mpc52xx_pic() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + pr_debug("%s:\n", __func__); + + if (intsize!=3) + return -1; + + intrvect_l1 = (int) intspec[0]; + intrvect_l2 = (int) intspec[1]; + intrvect_type = (int) intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, intrvect_type ); + + switch(intrvect_l1) { + case 0: /* Critical */ + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; + break; + + case 1: /* Main */ + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; + break; + + case 2: /* Periph */ + intrvect_linux = MPC52xx_PERP_IRQ_BASE; + break; + + case 3: /* Bestcomm */ + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; + break; + + default: + if ( printk_ratelimit() ) + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", intrvect_l1); + + return -1; + } + + intrvect_linux += intrvect_l2; + + pr_debug("return %d\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) +{ + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int) hw); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%d\n", __func__, virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init +mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr==NULL) || (sdma==NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i=0 ; i<4 ; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl,i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0; + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, -1); + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost ); +} + +unsigned int +mpc52xx_get_irq(void) +{ + u32 status; + int virq; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) + { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } else if (status & 0x00200000) + { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } else if (status & 0x20000000) + { /* peripheral */ +peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; + } else + irq += MPC52xx_PERP_IRQ_BASE; + + } + + virq = irq_linear_revmap(mpc52xx_irqhost, irq); + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); + + return virq; +} + --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 @@ -384,6 +384,11 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 18:56:34.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = }; #endif + +struct device_node *find_mpc52xx_pic(void) +{ + struct device_node *dev; + const char *piccompatible_list[] = + { + "mpc5200-interrupt-controller", + "mpc52xx-interrupt-controller", + "mpc52xx-pic", + "mpc5200-pic", + "5200-interrupt-controller", + "52xx-interrupt-controller", + "52xx-pic", + "5200-pic", + NULL + }; + + /* Look for an MPC52xx interrupt controller */ + for_each_node_by_type(dev, "interrupt-controller") + { + const char **piccompatible_entry = piccompatible_list; + + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) + { + if (device_is_compatible(dev, *piccompatible_entry )) + return dev; + } + } + + return NULL; +} + +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_pic()) + { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -473,8 +519,11 @@ static void __init chrp_find_8259(void) break; } if (np == NULL) - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" - " address, polling\n"); + { + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" + " Fix your tree!\n"); + return; + } i8259_init(pic, chrp_int_ack); if (ppc_md.get_irq == NULL) @@ -494,6 +543,8 @@ void __init chrp_init_IRQ(void) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif + + chrp_find_mpc52xx_pic(); chrp_find_openpic(); chrp_find_8259(); [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 19:21 ` Nicolas DET @ 2006-10-26 19:32 ` Nicolas DET 0 siblings, 0 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-26 19:32 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 659 bytes --] Nicolas DET wrote: > Grant Likely wrote: > >>> >>> diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h >>> --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 >>> +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 >>> @@ -119,7 +119,7 @@ enum ppc_sys_devices { >>> #define MPC52xx_SDMA_IRQ_NUM 17 >>> #define MPC52xx_PERP_IRQ_NUM 23 >>> >>> -#define MPC52xx_CRIT_IRQ_BASE 1 >>> +#define MPC52xx_CRIT_IRQ_BASE 0 >> >> Is this *strictly* necessary for adding mpc52xx-pic support to >> arch/powerpc? If not, then move it to a separate patch. > > > Removed as it does not hurt ARCH=powerpc. Lindent... [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 12346 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 21:32:05.000000000 +0200 @@ -0,0 +1,363 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * Modified for CHRP Efika 5K2 + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> + +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; + +static struct irq_host *mpc52xx_irqhost = NULL; + +static void mpc52xx_ic_disable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void mpc52xx_ic_enable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + + break; + } + +} + +static void mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .name = " MPC52xx ", + .enable = mpc52xx_ic_enable, + .disable = mpc52xx_ic_disable, + .ack = mpc52xx_ic_disable_and_ack, + .end = mpc52xx_ic_end, +}; + +extern struct device_node *find_mpc52xx_pic(void); +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); + return find_mpc52xx_pic() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 * intspec, unsigned int intsize, + irq_hw_number_t * out_hwirq, + unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + pr_debug("%s:\n", __func__); + + if (intsize != 3) + return -1; + + intrvect_l1 = (int)intspec[0]; + intrvect_l2 = (int)intspec[1]; + intrvect_type = (int)intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, + intrvect_type); + + switch (intrvect_l1) { + case 0: /* Critical */ + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; + break; + + case 1: /* Main */ + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; + break; + + case 2: /* Periph */ + intrvect_linux = MPC52xx_PERP_IRQ_BASE; + break; + + case 3: /* Bestcomm */ + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; + break; + + default: + if (printk_ratelimit()) + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", + intrvect_l1); + + return -1; + } + + intrvect_linux += intrvect_l2; + + pr_debug("return %d\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int)hw); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%d\n", __func__, virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr == NULL) || (sdma == NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i = 0; i < 4; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl, i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i ? MPC52xx_IRQ1 + i - + 1 : MPC52xx_IRQ0].status = 0; + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, + -1); + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost); +} + +unsigned int mpc52xx_get_irq(void) +{ + u32 status; + int virq; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } else if (status & 0x00200000) { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } else if (status & 0x20000000) { /* peripheral */ + peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE - 1; + } else + irq += MPC52xx_PERP_IRQ_BASE; + + } + + virq = irq_linear_revmap(mpc52xx_irqhost, irq); + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); + + return virq; +} --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 @@ -384,6 +384,11 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 18:56:34.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,51 @@ static struct irqaction xmon_irqaction = }; #endif + +struct device_node *find_mpc52xx_pic(void) +{ + struct device_node *dev; + const char *piccompatible_list[] = + { + "mpc5200-interrupt-controller", + "mpc52xx-interrupt-controller", + "mpc52xx-pic", + "mpc5200-pic", + "5200-interrupt-controller", + "52xx-interrupt-controller", + "52xx-pic", + "5200-pic", + NULL + }; + + /* Look for an MPC52xx interrupt controller */ + for_each_node_by_type(dev, "interrupt-controller") + { + const char **piccompatible_entry = piccompatible_list; + + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) + { + if (device_is_compatible(dev, *piccompatible_entry )) + return dev; + } + } + + return NULL; +} + +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_pic()) + { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -473,8 +519,11 @@ static void __init chrp_find_8259(void) break; } if (np == NULL) - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" - " address, polling\n"); + { + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" + " Fix your tree!\n"); + return; + } i8259_init(pic, chrp_int_ack); if (ppc_md.get_irq == NULL) @@ -494,6 +543,8 @@ void __init chrp_init_IRQ(void) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif + + chrp_find_mpc52xx_pic(); chrp_find_openpic(); chrp_find_8259(); [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:06 ` Nicolas DET 2006-10-26 17:54 ` Sylvain Munaut 2006-10-26 19:14 ` Grant Likely @ 2006-10-27 2:49 ` Benjamin Herrenschmidt 2 siblings, 0 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-27 2:49 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha Any reason why this is not static nor __init ? : > +struct device_node *find_mpc52xx_pic(void) > +{ > + struct device_node *dev; > + const char *piccompatible_list[] = > + { > + "mpc5200-interrupt-controller", > + "mpc52xx-interrupt-controller", > + "mpc52xx-pic", > + "mpc5200-pic", > + "5200-interrupt-controller", > + "52xx-interrupt-controller", > + "52xx-pic", > + "5200-pic", > + NULL > + }; > + > + /* Look for an MPC52xx interrupt controller */ > + for_each_node_by_type(dev, "interrupt-controller") > + { > + const char **piccompatible_entry = piccompatible_list; > + > + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) > + { > + if (device_is_compatible(dev, *piccompatible_entry )) > + return dev; > + } > + } > + > + return NULL; > +} > + > +static int __init chrp_find_mpc52xx_pic(void) > +{ > + if (find_mpc52xx_pic()) > + { > + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return 0; > + } > + > + return -ENODEV; > +} I'm not sure I see any point in splitting in two functions like that > static void __init chrp_find_8259(void) > { > struct device_node *np, *pic = NULL; > @@ -473,8 +519,11 @@ static void __init chrp_find_8259(void) > break; > } > if (np == NULL) > - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" > - " address, polling\n"); > + { > + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" > + " Fix your tree!\n"); > + return; > + } Unrelated changes/fix, should probably be in a separate patch. Cheers, Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 16:02 ` Grant Likely 2006-10-26 16:09 ` Grant Likely @ 2006-10-26 16:45 ` Sven Luther 2006-10-26 19:50 ` Nicolas DET 2 siblings, 0 replies; 40+ messages in thread From: Sven Luther @ 2006-10-26 16:45 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, sven, sha On Thu, Oct 26, 2006 at 10:02:00AM -0600, Grant Likely wrote: > >+config PPC_MPC52xx_PIC > >+ bool > >+ depends on PPC_CHRP > > default y > > This isn't good for embedded 52xx boards. Anything u-boot based > cannot be CHRP. Please drop the "depends on" line This was a direct suggestion from benh, ppc_chrp should not be dropped, but ored with whatever you are using, or somethiung like it. Friendly, Sven Luther ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 16:02 ` Grant Likely 2006-10-26 16:09 ` Grant Likely 2006-10-26 16:45 ` Sven Luther @ 2006-10-26 19:50 ` Nicolas DET 2006-10-26 20:00 ` Grant Likely 2 siblings, 1 reply; 40+ messages in thread From: Nicolas DET @ 2006-10-26 19:50 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 781 bytes --] Grant Likely wrote: >> + >> +struct device_node *find_mpc52xx_pic(void) >> +{ >> + struct device_node *dev; >> + const char *piccompatible_list[] = >> + { >> + "mpc5200-interrupt-controller", >> + "mpc52xx-interrupt-controller", >> + "mpc52xx-pic", >> + "mpc5200-pic", >> + "5200-interrupt-controller", >> + "52xx-interrupt-controller", >> + "52xx-pic", >> + "5200-pic", >> + NULL >> + }; > > Considering Efika is the *only* CHRP 52xx board out there at the > moment, and only a handful of embedded folks trying to move it to > arch/powerpc, surely we can come to an agreement now on what this > thing is named. :) > > Done [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 12164 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 21:32:05.000000000 +0200 @@ -0,0 +1,363 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * Modified for CHRP Efika 5K2 + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> + +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; + +static struct irq_host *mpc52xx_irqhost = NULL; + +static void mpc52xx_ic_disable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void mpc52xx_ic_enable(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_IRQ1) { + BUG(); + } else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + + irq = irq_map[virq].hwirq; + + pr_debug("%s: irq=%d\n", __func__, irq); + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + + break; + } + +} + +static void mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .name = " MPC52xx ", + .enable = mpc52xx_ic_enable, + .disable = mpc52xx_ic_disable, + .ack = mpc52xx_ic_disable_and_ack, + .end = mpc52xx_ic_end, +}; + +extern struct device_node *find_mpc52xx_pic(void); +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); + return find_mpc52xx_pic() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 * intspec, unsigned int intsize, + irq_hw_number_t * out_hwirq, + unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + pr_debug("%s:\n", __func__); + + if (intsize != 3) + return -1; + + intrvect_l1 = (int)intspec[0]; + intrvect_l2 = (int)intspec[1]; + intrvect_type = (int)intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, + intrvect_type); + + switch (intrvect_l1) { + case 0: /* Critical */ + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; + break; + + case 1: /* Main */ + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; + break; + + case 2: /* Periph */ + intrvect_linux = MPC52xx_PERP_IRQ_BASE; + break; + + case 3: /* Bestcomm */ + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; + break; + + default: + if (printk_ratelimit()) + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", + intrvect_l1); + + return -1; + } + + intrvect_linux += intrvect_l2; + + pr_debug("return %d\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int)hw); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%d\n", __func__, virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr == NULL) || (sdma == NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) + for (i = 0; i < 4; i++) { + int mode; + mode = IRQn_MODE(intr_ctrl, i); + if ((mode == 0x1) || (mode == 0x2)) + irq_desc[i ? MPC52xx_IRQ1 + i - + 1 : MPC52xx_IRQ0].status = 0; + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, + -1); + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost); +} + +unsigned int mpc52xx_get_irq(void) +{ + u32 status; + int virq; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } else if (status & 0x00200000) { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } else if (status & 0x20000000) { /* peripheral */ + peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE - 1; + } else + irq += MPC52xx_PERP_IRQ_BASE; + + } + + virq = irq_linear_revmap(mpc52xx_irqhost, irq); + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); + + return virq; +} --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 @@ -384,6 +384,11 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 21:47:29.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,44 @@ static struct irqaction xmon_irqaction = }; #endif + +struct device_node *find_mpc52xx_pic(void) +{ + struct device_node *dev; + const char *piccompatible_list[] = + { + "mpc5200-pic", + NULL + }; + + /* Look for an MPC52xx interrupt controller */ + for_each_node_by_type(dev, "interrupt-controller") + { + const char **piccompatible_entry = piccompatible_list; + + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) + { + if (device_is_compatible(dev, *piccompatible_entry )) + return dev; + } + } + + return NULL; +} + +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_pic()) + { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -473,8 +512,11 @@ static void __init chrp_find_8259(void) break; } if (np == NULL) - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" - " address, polling\n"); + { + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" + " Fix your tree!\n"); + return; + } i8259_init(pic, chrp_int_ack); if (ppc_md.get_irq == NULL) @@ -494,6 +536,8 @@ void __init chrp_init_IRQ(void) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif + + chrp_find_mpc52xx_pic(); chrp_find_openpic(); chrp_find_8259(); [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 19:50 ` Nicolas DET @ 2006-10-26 20:00 ` Grant Likely 2006-10-26 20:51 ` Sylvain Munaut 2006-10-27 3:28 ` Benjamin Herrenschmidt 0 siblings, 2 replies; 40+ messages in thread From: Grant Likely @ 2006-10-26 20:00 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha My comments are satisfied Acked-by: Grant Likely <grant.likely@secretlab.ca> On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: > Grant Likely wrote: > > >> + > >> +struct device_node *find_mpc52xx_pic(void) > >> +{ > >> + struct device_node *dev; > >> + const char *piccompatible_list[] = > >> + { > >> + "mpc5200-interrupt-controller", > >> + "mpc52xx-interrupt-controller", > >> + "mpc52xx-pic", > >> + "mpc5200-pic", > >> + "5200-interrupt-controller", > >> + "52xx-interrupt-controller", > >> + "52xx-pic", > >> + "5200-pic", > >> + NULL > >> + }; > > > > Considering Efika is the *only* CHRP 52xx board out there at the > > moment, and only a handful of embedded folks trying to move it to > > arch/powerpc, surely we can come to an agreement now on what this > > thing is named. :) > > > > > > Done > > > > > --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 > +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 > @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o > obj-$(CONFIG_PPC_TODC) += todc.o > obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o > obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ > +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o > > ifeq ($(CONFIG_PPC_MERGE),y) > obj-$(CONFIG_PPC_I8259) += i8259.o > --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 > +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 21:32:05.000000000 +0200 > @@ -0,0 +1,363 @@ > +/* > + * arch/powerpc/sysdev/mpc52xx_pic.c > + * > + * Programmable Interrupt Controller functions for the Freescale MPC52xx > + * embedded CPU. > + * Modified for CHRP Efika 5K2 > + * > + * Maintainer : Sylvain Munaut <tnt@246tNt.com> > + * > + * Based on (well, mostly copied from) the code from the 2.4 kernel by > + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. > + * > + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> > + * Copyright (C) 2003 Montavista Software, Inc > + * > + * This file is licensed under the terms of the GNU General Public License > + * version 2. This program is licensed "as is" without any warranty of any > + * kind, whether express or implied. > + */ > + > +#include <linux/stddef.h> > +#include <linux/init.h> > +#include <linux/sched.h> > +#include <linux/signal.h> > +#include <linux/stddef.h> > +#include <linux/delay.h> > +#include <linux/irq.h> > + > +#include <asm/io.h> > +#include <asm/processor.h> > +#include <asm/system.h> > +#include <asm/irq.h> > +#include <asm/prom.h> > + > +#include <asm/mpc52xx.h> > + > +static struct mpc52xx_intr __iomem *intr; > +static struct mpc52xx_sdma __iomem *sdma; > + > +static struct irq_host *mpc52xx_irqhost = NULL; > + > +static void mpc52xx_ic_disable(unsigned int virq) > +{ > + u32 val; > + int irq; > + > + irq = irq_map[virq].hwirq; > + > + pr_debug("%s: irq=%d\n", __func__, irq); > + > + if (irq == MPC52xx_IRQ0) { > + val = in_be32(&intr->ctrl); > + val &= ~(1 << 11); > + out_be32(&intr->ctrl, val); > + } else if (irq < MPC52xx_IRQ1) { > + BUG(); > + } else if (irq <= MPC52xx_IRQ3) { > + val = in_be32(&intr->ctrl); > + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); > + out_be32(&intr->ctrl, val); > + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { > + val = in_be32(&intr->main_mask); > + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); > + out_be32(&intr->main_mask, val); > + } else if (irq < MPC52xx_PERP_IRQ_BASE) { > + val = in_be32(&sdma->IntMask); > + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); > + out_be32(&sdma->IntMask, val); > + } else { > + val = in_be32(&intr->per_mask); > + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); > + out_be32(&intr->per_mask, val); > + } > +} > + > +static void mpc52xx_ic_enable(unsigned int virq) > +{ > + u32 val; > + int irq; > + > + irq = irq_map[virq].hwirq; > + > + pr_debug("%s: irq=%d\n", __func__, irq); > + > + if (irq == MPC52xx_IRQ0) { > + val = in_be32(&intr->ctrl); > + val |= 1 << 11; > + out_be32(&intr->ctrl, val); > + } else if (irq < MPC52xx_IRQ1) { > + BUG(); > + } else if (irq <= MPC52xx_IRQ3) { > + val = in_be32(&intr->ctrl); > + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); > + out_be32(&intr->ctrl, val); > + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { > + val = in_be32(&intr->main_mask); > + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); > + out_be32(&intr->main_mask, val); > + } else if (irq < MPC52xx_PERP_IRQ_BASE) { > + val = in_be32(&sdma->IntMask); > + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); > + out_be32(&sdma->IntMask, val); > + } else { > + val = in_be32(&intr->per_mask); > + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); > + out_be32(&intr->per_mask, val); > + } > +} > + > +static void mpc52xx_ic_ack(unsigned int virq) > +{ > + u32 val; > + int irq; > + > + irq = irq_map[virq].hwirq; > + > + pr_debug("%s: irq=%d\n", __func__, irq); > + > + /* > + * Only some irqs are reset here, others in interrupting hardware. > + */ > + > + switch (irq) { > + case MPC52xx_IRQ0: > + val = in_be32(&intr->ctrl); > + val |= 0x08000000; > + out_be32(&intr->ctrl, val); > + break; > + case MPC52xx_CCS_IRQ: > + val = in_be32(&intr->enc_status); > + val |= 0x00000400; > + out_be32(&intr->enc_status, val); > + break; > + case MPC52xx_IRQ1: > + val = in_be32(&intr->ctrl); > + val |= 0x04000000; > + out_be32(&intr->ctrl, val); > + break; > + case MPC52xx_IRQ2: > + val = in_be32(&intr->ctrl); > + val |= 0x02000000; > + out_be32(&intr->ctrl, val); > + break; > + case MPC52xx_IRQ3: > + val = in_be32(&intr->ctrl); > + val |= 0x01000000; > + out_be32(&intr->ctrl, val); > + break; > + default: > + if (irq >= MPC52xx_SDMA_IRQ_BASE > + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { > + out_be32(&sdma->IntPend, > + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); > + } > + > + break; > + } > + > +} > + > +static void mpc52xx_ic_disable_and_ack(unsigned int irq) > +{ > + mpc52xx_ic_disable(irq); > + mpc52xx_ic_ack(irq); > +} > + > +static void mpc52xx_ic_end(unsigned int irq) > +{ > + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) > + mpc52xx_ic_enable(irq); > +} > + > +static struct irq_chip mpc52xx_irqchip = { > + .name = " MPC52xx ", > + .enable = mpc52xx_ic_enable, > + .disable = mpc52xx_ic_disable, > + .ack = mpc52xx_ic_disable_and_ack, > + .end = mpc52xx_ic_end, > +}; > + > +extern struct device_node *find_mpc52xx_pic(void); > +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) > +{ > + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); > + return find_mpc52xx_pic() == node; > +} > + > +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, > + u32 * intspec, unsigned int intsize, > + irq_hw_number_t * out_hwirq, > + unsigned int *out_flags) > +{ > + static unsigned char map_senses[4] = { > + IRQ_TYPE_LEVEL_HIGH, > + IRQ_TYPE_EDGE_FALLING, > + IRQ_TYPE_EDGE_RISING, > + IRQ_TYPE_LEVEL_LOW, > + }; > + > + int intrvect_l1; > + int intrvect_l2; > + int intrvect_type; > + int intrvect_linux; > + > + pr_debug("%s:\n", __func__); > + > + if (intsize != 3) > + return -1; > + > + intrvect_l1 = (int)intspec[0]; > + intrvect_l2 = (int)intspec[1]; > + intrvect_type = (int)intspec[2]; > + > + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, > + intrvect_type); > + > + switch (intrvect_l1) { > + case 0: /* Critical */ > + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; > + break; > + > + case 1: /* Main */ > + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; > + break; > + > + case 2: /* Periph */ > + intrvect_linux = MPC52xx_PERP_IRQ_BASE; > + break; > + > + case 3: /* Bestcomm */ > + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; > + break; > + > + default: > + if (printk_ratelimit()) > + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", > + intrvect_l1); > + > + return -1; > + } > + > + intrvect_linux += intrvect_l2; > + > + pr_debug("return %d\n", intrvect_linux); > + > + *out_hwirq = intrvect_linux; > + *out_flags = map_senses[intrvect_type]; > + > + return 0; > + > +} > + > +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, > + irq_hw_number_t hw) > +{ > + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int)hw); > + > + return 0; > +} > + > +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) > +{ > + pr_debug("%s: v=%d\n", __func__, virq); > +} > + > +static struct irq_host_ops mpc52xx_irqhost_ops = { > + .match = mpc52xx_irqhost_match, > + .xlate = mpc52xx_irqhost_xlate, > + .map = mpc52xx_irqhost_map, > + .unmap = mpc52xx_irqhost_unmap, > +}; > + > +void __init mpc52xx_init_irq(void) > +{ > + int i; > + u32 intr_ctrl; > + > + /* Remap the necessary zones */ > + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); > + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); > + > + if ((intr == NULL) || (sdma == NULL)) > + panic("Can't ioremap PIC/SDMA register or init_irq !"); > + > + /* Disable all interrupt sources. */ > + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ > + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ > + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ > + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ > + intr_ctrl = in_be32(&intr->ctrl); > + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ > + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ > + 0x00001000 | /* MEE master external enable */ > + 0x00000000 | /* 0 means disable IRQ 0-3 */ > + 0x00000001; /* CEb route critical normally */ > + out_be32(&intr->ctrl, intr_ctrl); > + > + /* Zero a bunch of the priority settings. */ > + out_be32(&intr->per_pri1, 0); > + out_be32(&intr->per_pri2, 0); > + out_be32(&intr->per_pri3, 0); > + out_be32(&intr->main_pri1, 0); > + out_be32(&intr->main_pri2, 0); > + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ > + for (i = 0; i < NR_IRQS; i++) { > + irq_desc[i].chip = &mpc52xx_irqchip; > + irq_desc[i].status = IRQ_LEVEL; > + > + } > + > +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) > + for (i = 0; i < 4; i++) { > + int mode; > + mode = IRQn_MODE(intr_ctrl, i); > + if ((mode == 0x1) || (mode == 0x2)) > + irq_desc[i ? MPC52xx_IRQ1 + i - > + 1 : MPC52xx_IRQ0].status = 0; > + } > + > + /* > + * As last step, add an irq host to translate the real > + * hw irq information provided by the ofw to linux virq > + */ > + > + mpc52xx_irqhost = > + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, > + -1); > + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost); > +} > + > +unsigned int mpc52xx_get_irq(void) > +{ > + u32 status; > + int virq; > + int irq = NO_IRQ_IGNORE; > + > + status = in_be32(&intr->enc_status); > + if (status & 0x00000400) { /* critical */ > + irq = (status >> 8) & 0x3; > + if (irq == 2) /* high priority peripheral */ > + goto peripheral; > + irq += MPC52xx_CRIT_IRQ_BASE; > + } else if (status & 0x00200000) { /* main */ > + irq = (status >> 16) & 0x1f; > + if (irq == 4) /* low priority peripheral */ > + goto peripheral; > + irq += MPC52xx_MAIN_IRQ_BASE; > + } else if (status & 0x20000000) { /* peripheral */ > + peripheral: > + irq = (status >> 24) & 0x1f; > + if (irq == 0) { /* bestcomm */ > + status = in_be32(&sdma->IntPend); > + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE - 1; > + } else > + irq += MPC52xx_PERP_IRQ_BASE; > + > + } > + > + virq = irq_linear_revmap(mpc52xx_irqhost, irq); > + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); > + > + return virq; > +} > --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 > @@ -384,6 +384,11 @@ config PPC_CHRP > select PPC_RTAS > select PPC_MPC106 > select PPC_UDBG_16550 > + select PPC_MPC52xx_PIC > + default y > + > +config PPC_MPC52xx_PIC > + bool > default y > > config PPC_PMAC > --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 21:47:29.000000000 +0200 > @@ -51,6 +51,7 @@ > #include <asm/mpic.h> > #include <asm/rtas.h> > #include <asm/xmon.h> > +#include <asm/mpc52xx.h> > > #include "chrp.h" > > @@ -435,6 +436,44 @@ static struct irqaction xmon_irqaction = > }; > #endif > > + > +struct device_node *find_mpc52xx_pic(void) > +{ > + struct device_node *dev; > + const char *piccompatible_list[] = > + { > + "mpc5200-pic", > + NULL > + }; > + > + /* Look for an MPC52xx interrupt controller */ > + for_each_node_by_type(dev, "interrupt-controller") > + { > + const char **piccompatible_entry = piccompatible_list; > + > + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) > + { > + if (device_is_compatible(dev, *piccompatible_entry )) > + return dev; > + } > + } > + > + return NULL; > +} > + > +static int __init chrp_find_mpc52xx_pic(void) > +{ > + if (find_mpc52xx_pic()) > + { > + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return 0; > + } > + > + return -ENODEV; > +} > + > static void __init chrp_find_8259(void) > { > struct device_node *np, *pic = NULL; > @@ -473,8 +512,11 @@ static void __init chrp_find_8259(void) > break; > } > if (np == NULL) > - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" > - " address, polling\n"); > + { > + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" > + " Fix your tree!\n"); > + return; > + } > > i8259_init(pic, chrp_int_ack); > if (ppc_md.get_irq == NULL) > @@ -494,6 +536,8 @@ void __init chrp_init_IRQ(void) > #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) > struct device_node *kbd; > #endif > + > + chrp_find_mpc52xx_pic(); > chrp_find_openpic(); > chrp_find_8259(); > > > > > -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. grant.likely@secretlab.ca (403) 399-0195 ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 20:00 ` Grant Likely @ 2006-10-26 20:51 ` Sylvain Munaut 2006-10-27 3:28 ` Benjamin Herrenschmidt 1 sibling, 0 replies; 40+ messages in thread From: Sylvain Munaut @ 2006-10-26 20:51 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha FWIW, Looks good to me too. Acked-by: Sylvain Munaut <tnt@246tNt.com> It will need some changes when we'll get rid of the need to stay compatible with arch/ppc. This will hopefully be soon and getting this in should help get things moving imho. Sylvain Grant Likely wrote: > My comments are satisfied > > Acked-by: Grant Likely <grant.likely@secretlab.ca> > > On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: >> Grant Likely wrote: >> >> >> + >> >> +struct device_node *find_mpc52xx_pic(void) >> >> +{ >> >> + struct device_node *dev; >> >> + const char *piccompatible_list[] = >> >> + { >> >> + "mpc5200-interrupt-controller", >> >> + "mpc52xx-interrupt-controller", >> >> + "mpc52xx-pic", >> >> + "mpc5200-pic", >> >> + "5200-interrupt-controller", >> >> + "52xx-interrupt-controller", >> >> + "52xx-pic", >> >> + "5200-pic", >> >> + NULL >> >> + }; >> > >> > Considering Efika is the *only* CHRP 52xx board out there at the >> > moment, and only a handful of embedded folks trying to move it to >> > arch/powerpc, surely we can come to an agreement now on what this >> > thing is named. :) >> > >> > >> >> Done >> >> >> >> >> --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 >> +0200 >> +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 >> +0200 >> @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o >> obj-$(CONFIG_PPC_TODC) += todc.o >> obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o >> obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ >> +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o >> >> ifeq ($(CONFIG_PPC_MERGE),y) >> obj-$(CONFIG_PPC_I8259) += i8259.o >> --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 >> +0100 >> +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 21:32:05.000000000 >> +0200 >> @@ -0,0 +1,363 @@ >> +/* >> + * arch/powerpc/sysdev/mpc52xx_pic.c >> + * >> + * Programmable Interrupt Controller functions for the Freescale >> MPC52xx >> + * embedded CPU. >> + * Modified for CHRP Efika 5K2 >> + * >> + * Maintainer : Sylvain Munaut <tnt@246tNt.com> >> + * >> + * Based on (well, mostly copied from) the code from the 2.4 kernel by >> + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. >> + * >> + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> >> + * Copyright (C) 2003 Montavista Software, Inc >> + * >> + * This file is licensed under the terms of the GNU General Public >> License >> + * version 2. This program is licensed "as is" without any warranty >> of any >> + * kind, whether express or implied. >> + */ >> + >> +#include <linux/stddef.h> >> +#include <linux/init.h> >> +#include <linux/sched.h> >> +#include <linux/signal.h> >> +#include <linux/stddef.h> >> +#include <linux/delay.h> >> +#include <linux/irq.h> >> + >> +#include <asm/io.h> >> +#include <asm/processor.h> >> +#include <asm/system.h> >> +#include <asm/irq.h> >> +#include <asm/prom.h> >> + >> +#include <asm/mpc52xx.h> >> + >> +static struct mpc52xx_intr __iomem *intr; >> +static struct mpc52xx_sdma __iomem *sdma; >> + >> +static struct irq_host *mpc52xx_irqhost = NULL; >> + >> +static void mpc52xx_ic_disable(unsigned int virq) >> +{ >> + u32 val; >> + int irq; >> + >> + irq = irq_map[virq].hwirq; >> + >> + pr_debug("%s: irq=%d\n", __func__, irq); >> + >> + if (irq == MPC52xx_IRQ0) { >> + val = in_be32(&intr->ctrl); >> + val &= ~(1 << 11); >> + out_be32(&intr->ctrl, val); >> + } else if (irq < MPC52xx_IRQ1) { >> + BUG(); >> + } else if (irq <= MPC52xx_IRQ3) { >> + val = in_be32(&intr->ctrl); >> + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); >> + out_be32(&intr->ctrl, val); >> + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { >> + val = in_be32(&intr->main_mask); >> + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); >> + out_be32(&intr->main_mask, val); >> + } else if (irq < MPC52xx_PERP_IRQ_BASE) { >> + val = in_be32(&sdma->IntMask); >> + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); >> + out_be32(&sdma->IntMask, val); >> + } else { >> + val = in_be32(&intr->per_mask); >> + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); >> + out_be32(&intr->per_mask, val); >> + } >> +} >> + >> +static void mpc52xx_ic_enable(unsigned int virq) >> +{ >> + u32 val; >> + int irq; >> + >> + irq = irq_map[virq].hwirq; >> + >> + pr_debug("%s: irq=%d\n", __func__, irq); >> + >> + if (irq == MPC52xx_IRQ0) { >> + val = in_be32(&intr->ctrl); >> + val |= 1 << 11; >> + out_be32(&intr->ctrl, val); >> + } else if (irq < MPC52xx_IRQ1) { >> + BUG(); >> + } else if (irq <= MPC52xx_IRQ3) { >> + val = in_be32(&intr->ctrl); >> + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); >> + out_be32(&intr->ctrl, val); >> + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { >> + val = in_be32(&intr->main_mask); >> + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); >> + out_be32(&intr->main_mask, val); >> + } else if (irq < MPC52xx_PERP_IRQ_BASE) { >> + val = in_be32(&sdma->IntMask); >> + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); >> + out_be32(&sdma->IntMask, val); >> + } else { >> + val = in_be32(&intr->per_mask); >> + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); >> + out_be32(&intr->per_mask, val); >> + } >> +} >> + >> +static void mpc52xx_ic_ack(unsigned int virq) >> +{ >> + u32 val; >> + int irq; >> + >> + irq = irq_map[virq].hwirq; >> + >> + pr_debug("%s: irq=%d\n", __func__, irq); >> + >> + /* >> + * Only some irqs are reset here, others in interrupting >> hardware. >> + */ >> + >> + switch (irq) { >> + case MPC52xx_IRQ0: >> + val = in_be32(&intr->ctrl); >> + val |= 0x08000000; >> + out_be32(&intr->ctrl, val); >> + break; >> + case MPC52xx_CCS_IRQ: >> + val = in_be32(&intr->enc_status); >> + val |= 0x00000400; >> + out_be32(&intr->enc_status, val); >> + break; >> + case MPC52xx_IRQ1: >> + val = in_be32(&intr->ctrl); >> + val |= 0x04000000; >> + out_be32(&intr->ctrl, val); >> + break; >> + case MPC52xx_IRQ2: >> + val = in_be32(&intr->ctrl); >> + val |= 0x02000000; >> + out_be32(&intr->ctrl, val); >> + break; >> + case MPC52xx_IRQ3: >> + val = in_be32(&intr->ctrl); >> + val |= 0x01000000; >> + out_be32(&intr->ctrl, val); >> + break; >> + default: >> + if (irq >= MPC52xx_SDMA_IRQ_BASE >> + && irq < (MPC52xx_SDMA_IRQ_BASE + >> MPC52xx_SDMA_IRQ_NUM)) { >> + out_be32(&sdma->IntPend, >> + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); >> + } >> + >> + break; >> + } >> + >> +} >> + >> +static void mpc52xx_ic_disable_and_ack(unsigned int irq) >> +{ >> + mpc52xx_ic_disable(irq); >> + mpc52xx_ic_ack(irq); >> +} >> + >> +static void mpc52xx_ic_end(unsigned int irq) >> +{ >> + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) >> + mpc52xx_ic_enable(irq); >> +} >> + >> +static struct irq_chip mpc52xx_irqchip = { >> + .name = " MPC52xx ", >> + .enable = mpc52xx_ic_enable, >> + .disable = mpc52xx_ic_disable, >> + .ack = mpc52xx_ic_disable_and_ack, >> + .end = mpc52xx_ic_end, >> +}; >> + >> +extern struct device_node *find_mpc52xx_pic(void); >> +static int mpc52xx_irqhost_match(struct irq_host *h, struct >> device_node *node) >> +{ >> + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); >> + return find_mpc52xx_pic() == node; >> +} >> + >> +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct >> device_node *ct, >> + u32 * intspec, unsigned int intsize, >> + irq_hw_number_t * out_hwirq, >> + unsigned int *out_flags) >> +{ >> + static unsigned char map_senses[4] = { >> + IRQ_TYPE_LEVEL_HIGH, >> + IRQ_TYPE_EDGE_FALLING, >> + IRQ_TYPE_EDGE_RISING, >> + IRQ_TYPE_LEVEL_LOW, >> + }; >> + >> + int intrvect_l1; >> + int intrvect_l2; >> + int intrvect_type; >> + int intrvect_linux; >> + >> + pr_debug("%s:\n", __func__); >> + >> + if (intsize != 3) >> + return -1; >> + >> + intrvect_l1 = (int)intspec[0]; >> + intrvect_l2 = (int)intspec[1]; >> + intrvect_type = (int)intspec[2]; >> + >> + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, >> + intrvect_type); >> + >> + switch (intrvect_l1) { >> + case 0: /* Critical */ >> + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; >> + break; >> + >> + case 1: /* Main */ >> + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; >> + break; >> + >> + case 2: /* Periph */ >> + intrvect_linux = MPC52xx_PERP_IRQ_BASE; >> + break; >> + >> + case 3: /* Bestcomm */ >> + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; >> + break; >> + >> + default: >> + if (printk_ratelimit()) >> + printk(KERN_ERR "Wrong L1 interrupt vector >> (%d)\n", >> + intrvect_l1); >> + >> + return -1; >> + } >> + >> + intrvect_linux += intrvect_l2; >> + >> + pr_debug("return %d\n", intrvect_linux); >> + >> + *out_hwirq = intrvect_linux; >> + *out_flags = map_senses[intrvect_type]; >> + >> + return 0; >> + >> +} >> + >> +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, >> + irq_hw_number_t hw) >> +{ >> + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int)hw); >> + >> + return 0; >> +} >> + >> +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) >> +{ >> + pr_debug("%s: v=%d\n", __func__, virq); >> +} >> + >> +static struct irq_host_ops mpc52xx_irqhost_ops = { >> + .match = mpc52xx_irqhost_match, >> + .xlate = mpc52xx_irqhost_xlate, >> + .map = mpc52xx_irqhost_map, >> + .unmap = mpc52xx_irqhost_unmap, >> +}; >> + >> +void __init mpc52xx_init_irq(void) >> +{ >> + int i; >> + u32 intr_ctrl; >> + >> + /* Remap the necessary zones */ >> + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), >> MPC52xx_INTR_SIZE); >> + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), >> MPC52xx_SDMA_SIZE); >> + >> + if ((intr == NULL) || (sdma == NULL)) >> + panic("Can't ioremap PIC/SDMA register or init_irq !"); >> + >> + /* Disable all interrupt sources. */ >> + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear >> pending */ >> + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ >> + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ >> + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ >> + intr_ctrl = in_be32(&intr->ctrl); >> + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ >> + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ >> + 0x00001000 | /* MEE master external enable */ >> + 0x00000000 | /* 0 means disable IRQ 0-3 */ >> + 0x00000001; /* CEb route critical normally */ >> + out_be32(&intr->ctrl, intr_ctrl); >> + >> + /* Zero a bunch of the priority settings. */ >> + out_be32(&intr->per_pri1, 0); >> + out_be32(&intr->per_pri2, 0); >> + out_be32(&intr->per_pri3, 0); >> + out_be32(&intr->main_pri1, 0); >> + out_be32(&intr->main_pri2, 0); >> + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ >> + for (i = 0; i < NR_IRQS; i++) { >> + irq_desc[i].chip = &mpc52xx_irqchip; >> + irq_desc[i].status = IRQ_LEVEL; >> + >> + } >> + >> +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) >> + for (i = 0; i < 4; i++) { >> + int mode; >> + mode = IRQn_MODE(intr_ctrl, i); >> + if ((mode == 0x1) || (mode == 0x2)) >> + irq_desc[i ? MPC52xx_IRQ1 + i - >> + 1 : MPC52xx_IRQ0].status = 0; >> + } >> + >> + /* >> + * As last step, add an irq host to translate the real >> + * hw irq information provided by the ofw to linux virq >> + */ >> + >> + mpc52xx_irqhost = >> + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, >> &mpc52xx_irqhost_ops, >> + -1); >> + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, >> mpc52xx_irqhost); >> +} >> + >> +unsigned int mpc52xx_get_irq(void) >> +{ >> + u32 status; >> + int virq; >> + int irq = NO_IRQ_IGNORE; >> + >> + status = in_be32(&intr->enc_status); >> + if (status & 0x00000400) { /* critical */ >> + irq = (status >> 8) & 0x3; >> + if (irq == 2) /* high priority peripheral */ >> + goto peripheral; >> + irq += MPC52xx_CRIT_IRQ_BASE; >> + } else if (status & 0x00200000) { /* main */ >> + irq = (status >> 16) & 0x1f; >> + if (irq == 4) /* low priority peripheral */ >> + goto peripheral; >> + irq += MPC52xx_MAIN_IRQ_BASE; >> + } else if (status & 0x20000000) { /* peripheral */ >> + peripheral: >> + irq = (status >> 24) & 0x1f; >> + if (irq == 0) { /* bestcomm */ >> + status = in_be32(&sdma->IntPend); >> + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE - 1; >> + } else >> + irq += MPC52xx_PERP_IRQ_BASE; >> + >> + } >> + >> + virq = irq_linear_revmap(mpc52xx_irqhost, irq); >> + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); >> + >> + return virq; >> +} >> --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 >> +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 >> @@ -384,6 +384,11 @@ config PPC_CHRP >> select PPC_RTAS >> select PPC_MPC106 >> select PPC_UDBG_16550 >> + select PPC_MPC52xx_PIC >> + default y >> + >> +config PPC_MPC52xx_PIC >> + bool >> default y >> >> config PPC_PMAC >> --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 >> 19:07:23.000000000 +0200 >> +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 >> 21:47:29.000000000 +0200 >> @@ -51,6 +51,7 @@ >> #include <asm/mpic.h> >> #include <asm/rtas.h> >> #include <asm/xmon.h> >> +#include <asm/mpc52xx.h> >> >> #include "chrp.h" >> >> @@ -435,6 +436,44 @@ static struct irqaction xmon_irqaction = >> }; >> #endif >> >> + >> +struct device_node *find_mpc52xx_pic(void) >> +{ >> + struct device_node *dev; >> + const char *piccompatible_list[] = >> + { >> + "mpc5200-pic", >> + NULL >> + }; >> + >> + /* Look for an MPC52xx interrupt controller */ >> + for_each_node_by_type(dev, "interrupt-controller") >> + { >> + const char **piccompatible_entry = piccompatible_list; >> + >> + for(piccompatible_entry = piccompatible_list; >> *piccompatible_entry; piccompatible_entry++ ) >> + { >> + if (device_is_compatible(dev, >> *piccompatible_entry )) >> + return dev; >> + } >> + } >> + >> + return NULL; >> +} >> + >> +static int __init chrp_find_mpc52xx_pic(void) >> +{ >> + if (find_mpc52xx_pic()) >> + { >> + printk(KERN_INFO "Found MPC52xx Interrupt >> Controller\n"); >> + ppc_md.get_irq = mpc52xx_get_irq; >> + mpc52xx_init_irq(); >> + return 0; >> + } >> + >> + return -ENODEV; >> +} >> + >> static void __init chrp_find_8259(void) >> { >> struct device_node *np, *pic = NULL; >> @@ -473,8 +512,11 @@ static void __init chrp_find_8259(void) >> break; >> } >> if (np == NULL) >> - printk(KERN_WARNING "Cannot find PCI interrupt >> acknowledge" >> - " address, polling\n"); >> + { >> + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt >> acknowledge" >> + " Fix your tree!\n"); >> + return; >> + } >> >> i8259_init(pic, chrp_int_ack); >> if (ppc_md.get_irq == NULL) >> @@ -494,6 +536,8 @@ void __init chrp_init_IRQ(void) >> #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) >> struct device_node *kbd; >> #endif >> + >> + chrp_find_mpc52xx_pic(); >> chrp_find_openpic(); >> chrp_find_8259(); >> >> >> >> >> > > ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 20:00 ` Grant Likely 2006-10-26 20:51 ` Sylvain Munaut @ 2006-10-27 3:28 ` Benjamin Herrenschmidt 2006-10-27 14:52 ` Nicolas DET 1 sibling, 1 reply; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-27 3:28 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha On Thu, 2006-10-26 at 14:00 -0600, Grant Likely wrote: > My comments are satisfied > > Acked-by: Grant Likely <grant.likely@secretlab.ca> Nack. The irq code doesn't properly use the genirq infrastructure. It's not setting flow handlers, not implementing set_irq_type, not using the new mask/unmask instead of the toplevel enable/disable... Ben. > On 10/26/06, Nicolas DET <nd@bplan-gmbh.de> wrote: > > Grant Likely wrote: > > > > >> + > > >> +struct device_node *find_mpc52xx_pic(void) > > >> +{ > > >> + struct device_node *dev; > > >> + const char *piccompatible_list[] = > > >> + { > > >> + "mpc5200-interrupt-controller", > > >> + "mpc52xx-interrupt-controller", > > >> + "mpc52xx-pic", > > >> + "mpc5200-pic", > > >> + "5200-interrupt-controller", > > >> + "52xx-interrupt-controller", > > >> + "52xx-pic", > > >> + "5200-pic", > > >> + NULL > > >> + }; > > > > > > Considering Efika is the *only* CHRP 52xx board out there at the > > > moment, and only a handful of embedded folks trying to move it to > > > arch/powerpc, surely we can come to an agreement now on what this > > > thing is named. :) > > > > > > > > > > Done > > > > > > > > > > --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 > > +++ b/arch/powerpc/sysdev/Makefile 2006-10-26 11:38:02.000000000 +0200 > > @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o > > obj-$(CONFIG_PPC_TODC) += todc.o > > obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o > > obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ > > +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o > > > > ifeq ($(CONFIG_PPC_MERGE),y) > > obj-$(CONFIG_PPC_I8259) += i8259.o > > --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 > > +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-26 21:32:05.000000000 +0200 > > @@ -0,0 +1,363 @@ > > +/* > > + * arch/powerpc/sysdev/mpc52xx_pic.c > > + * > > + * Programmable Interrupt Controller functions for the Freescale MPC52xx > > + * embedded CPU. > > + * Modified for CHRP Efika 5K2 > > + * > > + * Maintainer : Sylvain Munaut <tnt@246tNt.com> > > + * > > + * Based on (well, mostly copied from) the code from the 2.4 kernel by > > + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. > > + * > > + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> > > + * Copyright (C) 2003 Montavista Software, Inc > > + * > > + * This file is licensed under the terms of the GNU General Public License > > + * version 2. This program is licensed "as is" without any warranty of any > > + * kind, whether express or implied. > > + */ > > + > > +#include <linux/stddef.h> > > +#include <linux/init.h> > > +#include <linux/sched.h> > > +#include <linux/signal.h> > > +#include <linux/stddef.h> > > +#include <linux/delay.h> > > +#include <linux/irq.h> > > + > > +#include <asm/io.h> > > +#include <asm/processor.h> > > +#include <asm/system.h> > > +#include <asm/irq.h> > > +#include <asm/prom.h> > > + > > +#include <asm/mpc52xx.h> > > + > > +static struct mpc52xx_intr __iomem *intr; > > +static struct mpc52xx_sdma __iomem *sdma; > > + > > +static struct irq_host *mpc52xx_irqhost = NULL; > > + > > +static void mpc52xx_ic_disable(unsigned int virq) > > +{ > > + u32 val; > > + int irq; > > + > > + irq = irq_map[virq].hwirq; > > + > > + pr_debug("%s: irq=%d\n", __func__, irq); > > + > > + if (irq == MPC52xx_IRQ0) { > > + val = in_be32(&intr->ctrl); > > + val &= ~(1 << 11); > > + out_be32(&intr->ctrl, val); > > + } else if (irq < MPC52xx_IRQ1) { > > + BUG(); > > + } else if (irq <= MPC52xx_IRQ3) { > > + val = in_be32(&intr->ctrl); > > + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); > > + out_be32(&intr->ctrl, val); > > + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { > > + val = in_be32(&intr->main_mask); > > + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); > > + out_be32(&intr->main_mask, val); > > + } else if (irq < MPC52xx_PERP_IRQ_BASE) { > > + val = in_be32(&sdma->IntMask); > > + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); > > + out_be32(&sdma->IntMask, val); > > + } else { > > + val = in_be32(&intr->per_mask); > > + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); > > + out_be32(&intr->per_mask, val); > > + } > > +} > > + > > +static void mpc52xx_ic_enable(unsigned int virq) > > +{ > > + u32 val; > > + int irq; > > + > > + irq = irq_map[virq].hwirq; > > + > > + pr_debug("%s: irq=%d\n", __func__, irq); > > + > > + if (irq == MPC52xx_IRQ0) { > > + val = in_be32(&intr->ctrl); > > + val |= 1 << 11; > > + out_be32(&intr->ctrl, val); > > + } else if (irq < MPC52xx_IRQ1) { > > + BUG(); > > + } else if (irq <= MPC52xx_IRQ3) { > > + val = in_be32(&intr->ctrl); > > + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); > > + out_be32(&intr->ctrl, val); > > + } else if (irq < MPC52xx_SDMA_IRQ_BASE) { > > + val = in_be32(&intr->main_mask); > > + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); > > + out_be32(&intr->main_mask, val); > > + } else if (irq < MPC52xx_PERP_IRQ_BASE) { > > + val = in_be32(&sdma->IntMask); > > + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); > > + out_be32(&sdma->IntMask, val); > > + } else { > > + val = in_be32(&intr->per_mask); > > + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); > > + out_be32(&intr->per_mask, val); > > + } > > +} > > + > > +static void mpc52xx_ic_ack(unsigned int virq) > > +{ > > + u32 val; > > + int irq; > > + > > + irq = irq_map[virq].hwirq; > > + > > + pr_debug("%s: irq=%d\n", __func__, irq); > > + > > + /* > > + * Only some irqs are reset here, others in interrupting hardware. > > + */ > > + > > + switch (irq) { > > + case MPC52xx_IRQ0: > > + val = in_be32(&intr->ctrl); > > + val |= 0x08000000; > > + out_be32(&intr->ctrl, val); > > + break; > > + case MPC52xx_CCS_IRQ: > > + val = in_be32(&intr->enc_status); > > + val |= 0x00000400; > > + out_be32(&intr->enc_status, val); > > + break; > > + case MPC52xx_IRQ1: > > + val = in_be32(&intr->ctrl); > > + val |= 0x04000000; > > + out_be32(&intr->ctrl, val); > > + break; > > + case MPC52xx_IRQ2: > > + val = in_be32(&intr->ctrl); > > + val |= 0x02000000; > > + out_be32(&intr->ctrl, val); > > + break; > > + case MPC52xx_IRQ3: > > + val = in_be32(&intr->ctrl); > > + val |= 0x01000000; > > + out_be32(&intr->ctrl, val); > > + break; > > + default: > > + if (irq >= MPC52xx_SDMA_IRQ_BASE > > + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { > > + out_be32(&sdma->IntPend, > > + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); > > + } > > + > > + break; > > + } > > + > > +} > > + > > +static void mpc52xx_ic_disable_and_ack(unsigned int irq) > > +{ > > + mpc52xx_ic_disable(irq); > > + mpc52xx_ic_ack(irq); > > +} > > + > > +static void mpc52xx_ic_end(unsigned int irq) > > +{ > > + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) > > + mpc52xx_ic_enable(irq); > > +} > > + > > +static struct irq_chip mpc52xx_irqchip = { > > + .name = " MPC52xx ", > > + .enable = mpc52xx_ic_enable, > > + .disable = mpc52xx_ic_disable, > > + .ack = mpc52xx_ic_disable_and_ack, > > + .end = mpc52xx_ic_end, > > +}; > > + > > +extern struct device_node *find_mpc52xx_pic(void); > > +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) > > +{ > > + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_pic(), node); > > + return find_mpc52xx_pic() == node; > > +} > > + > > +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, > > + u32 * intspec, unsigned int intsize, > > + irq_hw_number_t * out_hwirq, > > + unsigned int *out_flags) > > +{ > > + static unsigned char map_senses[4] = { > > + IRQ_TYPE_LEVEL_HIGH, > > + IRQ_TYPE_EDGE_FALLING, > > + IRQ_TYPE_EDGE_RISING, > > + IRQ_TYPE_LEVEL_LOW, > > + }; > > + > > + int intrvect_l1; > > + int intrvect_l2; > > + int intrvect_type; > > + int intrvect_linux; > > + > > + pr_debug("%s:\n", __func__); > > + > > + if (intsize != 3) > > + return -1; > > + > > + intrvect_l1 = (int)intspec[0]; > > + intrvect_l2 = (int)intspec[1]; > > + intrvect_type = (int)intspec[2]; > > + > > + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, > > + intrvect_type); > > + > > + switch (intrvect_l1) { > > + case 0: /* Critical */ > > + intrvect_linux = MPC52xx_CRIT_IRQ_BASE; > > + break; > > + > > + case 1: /* Main */ > > + intrvect_linux = MPC52xx_MAIN_IRQ_BASE; > > + break; > > + > > + case 2: /* Periph */ > > + intrvect_linux = MPC52xx_PERP_IRQ_BASE; > > + break; > > + > > + case 3: /* Bestcomm */ > > + intrvect_linux = MPC52xx_SDMA_IRQ_BASE; > > + break; > > + > > + default: > > + if (printk_ratelimit()) > > + printk(KERN_ERR "Wrong L1 interrupt vector (%d)\n", > > + intrvect_l1); > > + > > + return -1; > > + } > > + > > + intrvect_linux += intrvect_l2; > > + > > + pr_debug("return %d\n", intrvect_linux); > > + > > + *out_hwirq = intrvect_linux; > > + *out_flags = map_senses[intrvect_type]; > > + > > + return 0; > > + > > +} > > + > > +int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, > > + irq_hw_number_t hw) > > +{ > > + pr_debug("%s: v=%d, hw=%d\n", __func__, virq, (int)hw); > > + > > + return 0; > > +} > > + > > +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) > > +{ > > + pr_debug("%s: v=%d\n", __func__, virq); > > +} > > + > > +static struct irq_host_ops mpc52xx_irqhost_ops = { > > + .match = mpc52xx_irqhost_match, > > + .xlate = mpc52xx_irqhost_xlate, > > + .map = mpc52xx_irqhost_map, > > + .unmap = mpc52xx_irqhost_unmap, > > +}; > > + > > +void __init mpc52xx_init_irq(void) > > +{ > > + int i; > > + u32 intr_ctrl; > > + > > + /* Remap the necessary zones */ > > + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); > > + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); > > + > > + if ((intr == NULL) || (sdma == NULL)) > > + panic("Can't ioremap PIC/SDMA register or init_irq !"); > > + > > + /* Disable all interrupt sources. */ > > + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ > > + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ > > + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ > > + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ > > + intr_ctrl = in_be32(&intr->ctrl); > > + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ > > + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ > > + 0x00001000 | /* MEE master external enable */ > > + 0x00000000 | /* 0 means disable IRQ 0-3 */ > > + 0x00000001; /* CEb route critical normally */ > > + out_be32(&intr->ctrl, intr_ctrl); > > + > > + /* Zero a bunch of the priority settings. */ > > + out_be32(&intr->per_pri1, 0); > > + out_be32(&intr->per_pri2, 0); > > + out_be32(&intr->per_pri3, 0); > > + out_be32(&intr->main_pri1, 0); > > + out_be32(&intr->main_pri2, 0); > > + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ > > + for (i = 0; i < NR_IRQS; i++) { > > + irq_desc[i].chip = &mpc52xx_irqchip; > > + irq_desc[i].status = IRQ_LEVEL; > > + > > + } > > + > > +#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03) > > + for (i = 0; i < 4; i++) { > > + int mode; > > + mode = IRQn_MODE(intr_ctrl, i); > > + if ((mode == 0x1) || (mode == 0x2)) > > + irq_desc[i ? MPC52xx_IRQ1 + i - > > + 1 : MPC52xx_IRQ0].status = 0; > > + } > > + > > + /* > > + * As last step, add an irq host to translate the real > > + * hw irq information provided by the ofw to linux virq > > + */ > > + > > + mpc52xx_irqhost = > > + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, > > + -1); > > + pr_debug("%s: mpc52xx_irqhost =%p\n", __func__, mpc52xx_irqhost); > > +} > > + > > +unsigned int mpc52xx_get_irq(void) > > +{ > > + u32 status; > > + int virq; > > + int irq = NO_IRQ_IGNORE; > > + > > + status = in_be32(&intr->enc_status); > > + if (status & 0x00000400) { /* critical */ > > + irq = (status >> 8) & 0x3; > > + if (irq == 2) /* high priority peripheral */ > > + goto peripheral; > > + irq += MPC52xx_CRIT_IRQ_BASE; > > + } else if (status & 0x00200000) { /* main */ > > + irq = (status >> 16) & 0x1f; > > + if (irq == 4) /* low priority peripheral */ > > + goto peripheral; > > + irq += MPC52xx_MAIN_IRQ_BASE; > > + } else if (status & 0x20000000) { /* peripheral */ > > + peripheral: > > + irq = (status >> 24) & 0x1f; > > + if (irq == 0) { /* bestcomm */ > > + status = in_be32(&sdma->IntPend); > > + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE - 1; > > + } else > > + irq += MPC52xx_PERP_IRQ_BASE; > > + > > + } > > + > > + virq = irq_linear_revmap(mpc52xx_irqhost, irq); > > + pr_debug("%s: irq=%d -> %d\n", __func__, irq, virq); > > + > > + return virq; > > +} > > --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 > > +++ b/arch/powerpc/Kconfig 2006-10-26 18:55:58.000000000 +0200 > > @@ -384,6 +384,11 @@ config PPC_CHRP > > select PPC_RTAS > > select PPC_MPC106 > > select PPC_UDBG_16550 > > + select PPC_MPC52xx_PIC > > + default y > > + > > +config PPC_MPC52xx_PIC > > + bool > > default y > > > > config PPC_PMAC > > --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 > > +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-26 21:47:29.000000000 +0200 > > @@ -51,6 +51,7 @@ > > #include <asm/mpic.h> > > #include <asm/rtas.h> > > #include <asm/xmon.h> > > +#include <asm/mpc52xx.h> > > > > #include "chrp.h" > > > > @@ -435,6 +436,44 @@ static struct irqaction xmon_irqaction = > > }; > > #endif > > > > + > > +struct device_node *find_mpc52xx_pic(void) > > +{ > > + struct device_node *dev; > > + const char *piccompatible_list[] = > > + { > > + "mpc5200-pic", > > + NULL > > + }; > > + > > + /* Look for an MPC52xx interrupt controller */ > > + for_each_node_by_type(dev, "interrupt-controller") > > + { > > + const char **piccompatible_entry = piccompatible_list; > > + > > + for(piccompatible_entry = piccompatible_list; *piccompatible_entry; piccompatible_entry++ ) > > + { > > + if (device_is_compatible(dev, *piccompatible_entry )) > > + return dev; > > + } > > + } > > + > > + return NULL; > > +} > > + > > +static int __init chrp_find_mpc52xx_pic(void) > > +{ > > + if (find_mpc52xx_pic()) > > + { > > + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); > > + ppc_md.get_irq = mpc52xx_get_irq; > > + mpc52xx_init_irq(); > > + return 0; > > + } > > + > > + return -ENODEV; > > +} > > + > > static void __init chrp_find_8259(void) > > { > > struct device_node *np, *pic = NULL; > > @@ -473,8 +512,11 @@ static void __init chrp_find_8259(void) > > break; > > } > > if (np == NULL) > > - printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" > > - " address, polling\n"); > > + { > > + printk(KERN_WARNING "Cannot find PCI/i8259 interrupt acknowledge" > > + " Fix your tree!\n"); > > + return; > > + } > > > > i8259_init(pic, chrp_int_ack); > > if (ppc_md.get_irq == NULL) > > @@ -494,6 +536,8 @@ void __init chrp_init_IRQ(void) > > #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) > > struct device_node *kbd; > > #endif > > + > > + chrp_find_mpc52xx_pic(); > > chrp_find_openpic(); > > chrp_find_8259(); > > > > > > > > > > > > ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-27 3:28 ` Benjamin Herrenschmidt @ 2006-10-27 14:52 ` Nicolas DET 2006-10-27 15:04 ` Nicolas DET 2006-10-27 22:05 ` Sylvain Munaut 0 siblings, 2 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-27 14:52 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 771 bytes --] Benjamin Herrenschmidt wrote: > On Thu, 2006-10-26 at 14:00 -0600, Grant Likely wrote: >> My comments are satisfied >> >> Acked-by: Grant Likely <grant.likely@secretlab.ca> > > Nack. > > The irq code doesn't properly use the genirq infrastructure. It's not > setting flow handlers, not implementing set_irq_type, not using the new > mask/unmask instead of the toplevel enable/disable... > > Done. We agree on IRC last night to postpone this implementation later on. However, here it is. This patch compiles fine when applied to the kernel 2.6.19-rc3. I also tested gcc 3.3.5 and 4.1.2. I made some tests and did not found any issue. However, more testing/stressing/torturing and also with on others platforms is required to fully validate the driver. Regards [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 24917 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-27 15:31:41.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-27 15:58:29.000000000 +0200 @@ -0,0 +1,414 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#undef DEBUG + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/hardirq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; +static struct irq_host *mpc52xx_irqhost = NULL; + +static void mpc52xx_ic_mask(unsigned int virq) +{ + u32 val; + int irq; + int l1irq; + int l2irq; + + irq = irq_map[virq].hwirq; + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + break; + + case MPC52xx_IRQ_L1_MAIN: + if ( (l2irq >= 1) && (l2irq <= 3) ) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (11 - l2irq)); + out_be32(&intr->ctrl, val); + } else { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - l2irq); + out_be32(&intr->main_mask, val); + } + break; + + case MPC52xx_IRQ_L1_PERP: + val = in_be32(&intr->per_mask); + val |= 1 << (31 - l2irq); + out_be32(&intr->per_mask, val); + break; + + case MPC52xx_IRQ_L1_SDMA: + val = in_be32(&sdma->IntMask); + val |= 1 << l2irq; + out_be32(&sdma->IntMask, val); + break; + + default: + printk(KERN_ERR "MPC52xx PIC: Wrong interrupt\n"); + } +} + +static void mpc52xx_ic_unmask(unsigned int virq) +{ + u32 val; + int irq; + int l1irq; + int l2irq; + + irq = irq_map[virq].hwirq; + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + break; + + case MPC52xx_IRQ_L1_MAIN: + if ( (l2irq >= 1) && (l2irq <= 3) ) { + val = in_be32(&intr->ctrl); + val |= 1 << (11 - l2irq); + out_be32(&intr->ctrl, val); + } else { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - l2irq)); + out_be32(&intr->main_mask, val); + } + break; + + case MPC52xx_IRQ_L1_PERP: + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - l2irq)); + out_be32(&intr->per_mask, val); + break; + + case MPC52xx_IRQ_L1_SDMA: + val = in_be32(&sdma->IntMask); + val &= ~(1 << l2irq); + out_be32(&sdma->IntMask, val); + break; + + default: + printk(KERN_ERR "MPC52xx PIC: Wrong interrupt\n"); + } +} + +static void mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + int l1irq; + int l2irq; + + irq = irq_map[virq].hwirq; + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + + case MPC52xx_IRQ_L1_MAIN: + if ( (l2irq >= 1) && (l2irq <= 3) ) { + val = in_be32(&intr->ctrl); + val |= 0x08000000 >> l2irq; + out_be32(&intr->ctrl, val); + } + break; + + case MPC52xx_IRQ_L1_PERP: + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - l2irq)); + out_be32(&intr->per_mask, val); + break; + + case MPC52xx_IRQ_L1_SDMA: + out_be32(&sdma->IntPend, 1 << l2irq); + break; + + default: + printk(KERN_ERR "MPC52xx PIC: Wrong interrupt\n"); + } +} + +static void mpc52xx_ic_mask_and_ack(unsigned int irq) +{ + mpc52xx_ic_mask(irq); + mpc52xx_ic_ack(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .typename = " MPC52xx ", + .mask = mpc52xx_ic_mask, + .unmask = mpc52xx_ic_unmask, + .mask_ack = mpc52xx_ic_mask_and_ack, +}; + +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_picnode(), node); + return find_mpc52xx_picnode() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 * intspec, unsigned int intsize, + irq_hw_number_t * out_hwirq, + unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + if (intsize != 3) + return -1; + + intrvect_l1 = (int)intspec[0]; + intrvect_l2 = (int)intspec[1]; + intrvect_type = (int)intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, + intrvect_type); + + intrvect_linux = + (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; + intrvect_linux |= + (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; + + pr_debug("return %x\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +static int mpc52xx_islevel(int num) +{ + u32 ictl_req; + int ictl_type; + + ictl_req = in_be32(&intr->ctrl); + ictl_type = (ictl_req >> 16) & 0x3; + + switch (ictl_type) { + case 0: + case 3: + return 1; + } + + return 0; +} + +static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t irq) +{ + int l1irq; + int l2irq; + unsigned int status; + + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + status = get_irq_desc(virq)->status; + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + if (mpc52xx_islevel(0)) + status |= IRQ_LEVEL; + break; + + case MPC52xx_IRQ_L1_MAIN: + if (mpc52xx_islevel(l2irq)) + status |= IRQ_LEVEL; + break; + + default: + status |= IRQ_LEVEL; + } + + get_irq_desc(virq)->status = status; + set_irq_chip_and_handler(virq, &mpc52xx_irqchip, + (status & IRQ_LEVEL) ? handle_level_irq : + handle_edge_irq); + + pr_debug("%s: virq=%x, hw=%x. desc status=%x\n", __func__, virq, + (int)irq, status); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%x\n", __func__, virq); + + mpc52xx_ic_mask(virq); + set_irq_chip_and_handler(virq, NULL, NULL); + synchronize_irq(virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr == NULL) || (sdma == NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, + -1); +} + +unsigned int mpc52xx_get_irq(void) +{ + u32 status; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq |= + (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + } else if (status & 0x00200000) { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq |= + (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + } else if (status & 0x20000000) { /* peripheral */ + peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) - 1; + irq |= + (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + } else + irq |= + (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + + } + + pr_debug("%s: irq=%x. virq=%d\n", __func__, irq, + irq_linear_revmap(mpc52xx_irqhost, irq)); + + return irq_linear_revmap(mpc52xx_irqhost, irq); +} --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-27 15:50:21.000000000 +0200 @@ -384,6 +384,11 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-27 16:08:03.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,18 @@ static struct irqaction xmon_irqaction = }; #endif +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_picnode()) { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -496,6 +509,7 @@ void __init chrp_init_IRQ(void) #endif chrp_find_openpic(); chrp_find_8259(); + chrp_find_mpc52xx_pic(); #ifdef CONFIG_SMP /* Pegasos has no MPIC, those ops would make it crash. It might be an diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 @@ -0,0 +1,414 @@ +/* + * include/asm-ppc/mpc52xx.h + * + * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips + * May need to be cleaned as the port goes on ... + * + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> + * for the 2.4 kernel. + * + * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __ASM_POWERPC_MPC52xx_H__ +#define __ASM_POWERPC_MPC52xx_H__ + +#ifndef __ASSEMBLY__ +#include <asm/types.h> +#include <asm/prom.h> + +#endif /* __ASSEMBLY__ */ + + +#ifdef CONFIG_PCI +#define _IO_BASE isa_io_base +#define _ISA_MEM_BASE isa_mem_base +#define PCI_DRAM_OFFSET pci_dram_offset +#else +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 +#endif + + +/* ======================================================================== */ +/* PPC Sys devices definition */ +/* ======================================================================== */ + +enum ppc_sys_devices { + MPC52xx_MSCAN1, + MPC52xx_MSCAN2, + MPC52xx_SPI, + MPC52xx_USB, + MPC52xx_BDLC, + MPC52xx_PSC1, + MPC52xx_PSC2, + MPC52xx_PSC3, + MPC52xx_PSC4, + MPC52xx_PSC5, + MPC52xx_PSC6, + MPC52xx_FEC, + MPC52xx_ATA, + MPC52xx_I2C1, + MPC52xx_I2C2, + NUM_PPC_SYS_DEVS, +}; + + +/* ======================================================================== */ +/* Main registers/struct addresses */ +/* ======================================================================== */ + +/* MBAR position */ +#define MPC52xx_MBAR 0xf0000000 /* Phys address */ +#define MPC52xx_MBAR_VIRT 0xf0000000 /* Virt address */ +#define MPC52xx_MBAR_SIZE 0x00010000 + +#define MPC52xx_PA(x) ((phys_addr_t)(MPC52xx_MBAR + (x))) +#define MPC52xx_VA(x) ((void __iomem *)(MPC52xx_MBAR_VIRT + (x))) + +/* Registers zone offset/size */ +#define MPC52xx_MMAP_CTL_OFFSET 0x0000 +#define MPC52xx_MMAP_CTL_SIZE 0x068 +#define MPC52xx_SDRAM_OFFSET 0x0100 +#define MPC52xx_SDRAM_SIZE 0x010 +#define MPC52xx_CDM_OFFSET 0x0200 +#define MPC52xx_CDM_SIZE 0x038 +#define MPC52xx_INTR_OFFSET 0x0500 +#define MPC52xx_INTR_SIZE 0x04c +#define MPC52xx_GPTx_OFFSET(x) (0x0600 + ((x)<<4)) +#define MPC52xx_GPT_SIZE 0x010 +#define MPC52xx_RTC_OFFSET 0x0800 +#define MPC52xx_RTC_SIZE 0x024 +#define MPC52xx_GPIO_OFFSET 0x0b00 +#define MPC52xx_GPIO_SIZE 0x040 +#define MPC52xx_GPIO_WKUP_OFFSET 0x0c00 +#define MPC52xx_GPIO_WKUP_SIZE 0x028 +#define MPC52xx_PCI_OFFSET 0x0d00 +#define MPC52xx_PCI_SIZE 0x100 +#define MPC52xx_SDMA_OFFSET 0x1200 +#define MPC52xx_SDMA_SIZE 0x100 +#define MPC52xx_XLB_OFFSET 0x1f00 +#define MPC52xx_XLB_SIZE 0x100 +#define MPC52xx_PSCx_OFFSET(x) (((x)!=6)?(0x1e00+((x)<<9)):0x2c00) +#define MPC52xx_PSC_SIZE 0x0a0 + +/* SRAM used for SDMA */ +#define MPC52xx_SRAM_OFFSET 0x8000 +#define MPC52xx_SRAM_SIZE 0x4000 + + +/* ======================================================================== */ +/* IRQ mapping */ +/* ======================================================================== */ + +#define MPC52xx_IRQ_L1_CRIT 0 +#define MPC52xx_IRQ_L1_MAIN 1 +#define MPC52xx_IRQ_L1_PERP 2 +#define MPC52xx_IRQ_L1_SDMA 3 + +#define MPC52xx_IRQ_L1_OFFSET (6) +#define MPC52xx_IRQ_L1_MASK (0xc0) + +#define MPC52xx_IRQ_L2_OFFSET (0) +#define MPC52xx_IRQ_L2_MASK (0x3f) + + +/* ======================================================================== */ +/* Structures mapping of some unit register set */ +/* ======================================================================== */ + +#ifndef __ASSEMBLY__ + +/* Memory Mapping Control */ +struct mpc52xx_mmap_ctl { + u32 mbar; /* MMAP_CTRL + 0x00 */ + + u32 cs0_start; /* MMAP_CTRL + 0x04 */ + u32 cs0_stop; /* MMAP_CTRL + 0x08 */ + u32 cs1_start; /* MMAP_CTRL + 0x0c */ + u32 cs1_stop; /* MMAP_CTRL + 0x10 */ + u32 cs2_start; /* MMAP_CTRL + 0x14 */ + u32 cs2_stop; /* MMAP_CTRL + 0x18 */ + u32 cs3_start; /* MMAP_CTRL + 0x1c */ + u32 cs3_stop; /* MMAP_CTRL + 0x20 */ + u32 cs4_start; /* MMAP_CTRL + 0x24 */ + u32 cs4_stop; /* MMAP_CTRL + 0x28 */ + u32 cs5_start; /* MMAP_CTRL + 0x2c */ + u32 cs5_stop; /* MMAP_CTRL + 0x30 */ + + u32 sdram0; /* MMAP_CTRL + 0x34 */ + u32 sdram1; /* MMAP_CTRL + 0X38 */ + + u32 reserved[4]; /* MMAP_CTRL + 0x3c .. 0x48 */ + + u32 boot_start; /* MMAP_CTRL + 0x4c */ + u32 boot_stop; /* MMAP_CTRL + 0x50 */ + + u32 ipbi_ws_ctrl; /* MMAP_CTRL + 0x54 */ + + u32 cs6_start; /* MMAP_CTRL + 0x58 */ + u32 cs6_stop; /* MMAP_CTRL + 0x5c */ + u32 cs7_start; /* MMAP_CTRL + 0x60 */ + u32 cs7_stop; /* MMAP_CTRL + 0x64 */ +}; + +/* SDRAM control */ +struct mpc52xx_sdram { + u32 mode; /* SDRAM + 0x00 */ + u32 ctrl; /* SDRAM + 0x04 */ + u32 config1; /* SDRAM + 0x08 */ + u32 config2; /* SDRAM + 0x0c */ +}; + +/* Interrupt controller */ +struct mpc52xx_intr { + u32 per_mask; /* INTR + 0x00 */ + u32 per_pri1; /* INTR + 0x04 */ + u32 per_pri2; /* INTR + 0x08 */ + u32 per_pri3; /* INTR + 0x0c */ + u32 ctrl; /* INTR + 0x10 */ + u32 main_mask; /* INTR + 0x14 */ + u32 main_pri1; /* INTR + 0x18 */ + u32 main_pri2; /* INTR + 0x1c */ + u32 reserved1; /* INTR + 0x20 */ + u32 enc_status; /* INTR + 0x24 */ + u32 crit_status; /* INTR + 0x28 */ + u32 main_status; /* INTR + 0x2c */ + u32 per_status; /* INTR + 0x30 */ + u32 reserved2; /* INTR + 0x34 */ + u32 per_error; /* INTR + 0x38 */ +}; + +/* SDMA */ +struct mpc52xx_sdma { + u32 taskBar; /* SDMA + 0x00 */ + u32 currentPointer; /* SDMA + 0x04 */ + u32 endPointer; /* SDMA + 0x08 */ + u32 variablePointer;/* SDMA + 0x0c */ + + u8 IntVect1; /* SDMA + 0x10 */ + u8 IntVect2; /* SDMA + 0x11 */ + u16 PtdCntrl; /* SDMA + 0x12 */ + + u32 IntPend; /* SDMA + 0x14 */ + u32 IntMask; /* SDMA + 0x18 */ + + u16 tcr[16]; /* SDMA + 0x1c .. 0x3a */ + + u8 ipr[32]; /* SDMA + 0x3c .. 0x5b */ + + u32 cReqSelect; /* SDMA + 0x5c */ + u32 task_size0; /* SDMA + 0x60 */ + u32 task_size1; /* SDMA + 0x64 */ + u32 MDEDebug; /* SDMA + 0x68 */ + u32 ADSDebug; /* SDMA + 0x6c */ + u32 Value1; /* SDMA + 0x70 */ + u32 Value2; /* SDMA + 0x74 */ + u32 Control; /* SDMA + 0x78 */ + u32 Status; /* SDMA + 0x7c */ + u32 PTDDebug; /* SDMA + 0x80 */ +}; + +/* GPT */ +struct mpc52xx_gpt { + u32 mode; /* GPTx + 0x00 */ + u32 count; /* GPTx + 0x04 */ + u32 pwm; /* GPTx + 0x08 */ + u32 status; /* GPTx + 0X0c */ +}; + +/* RTC */ +struct mpc52xx_rtc { + u32 time_set; /* RTC + 0x00 */ + u32 date_set; /* RTC + 0x04 */ + u32 stopwatch; /* RTC + 0x08 */ + u32 int_enable; /* RTC + 0x0c */ + u32 time; /* RTC + 0x10 */ + u32 date; /* RTC + 0x14 */ + u32 stopwatch_intr; /* RTC + 0x18 */ + u32 bus_error; /* RTC + 0x1c */ + u32 dividers; /* RTC + 0x20 */ +}; + +/* GPIO */ +struct mpc52xx_gpio { + u32 port_config; /* GPIO + 0x00 */ + u32 simple_gpioe; /* GPIO + 0x04 */ + u32 simple_ode; /* GPIO + 0x08 */ + u32 simple_ddr; /* GPIO + 0x0c */ + u32 simple_dvo; /* GPIO + 0x10 */ + u32 simple_ival; /* GPIO + 0x14 */ + u8 outo_gpioe; /* GPIO + 0x18 */ + u8 reserved1[3]; /* GPIO + 0x19 */ + u8 outo_dvo; /* GPIO + 0x1c */ + u8 reserved2[3]; /* GPIO + 0x1d */ + u8 sint_gpioe; /* GPIO + 0x20 */ + u8 reserved3[3]; /* GPIO + 0x21 */ + u8 sint_ode; /* GPIO + 0x24 */ + u8 reserved4[3]; /* GPIO + 0x25 */ + u8 sint_ddr; /* GPIO + 0x28 */ + u8 reserved5[3]; /* GPIO + 0x29 */ + u8 sint_dvo; /* GPIO + 0x2c */ + u8 reserved6[3]; /* GPIO + 0x2d */ + u8 sint_inten; /* GPIO + 0x30 */ + u8 reserved7[3]; /* GPIO + 0x31 */ + u16 sint_itype; /* GPIO + 0x34 */ + u16 reserved8; /* GPIO + 0x36 */ + u8 gpio_control; /* GPIO + 0x38 */ + u8 reserved9[3]; /* GPIO + 0x39 */ + u8 sint_istat; /* GPIO + 0x3c */ + u8 sint_ival; /* GPIO + 0x3d */ + u8 bus_errs; /* GPIO + 0x3e */ + u8 reserved10; /* GPIO + 0x3f */ +}; + +#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD 4 +#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD 5 +#define MPC52xx_GPIO_PCI_DIS (1<<15) + +/* GPIO with WakeUp*/ +struct mpc52xx_gpio_wkup { + u8 wkup_gpioe; /* GPIO_WKUP + 0x00 */ + u8 reserved1[3]; /* GPIO_WKUP + 0x03 */ + u8 wkup_ode; /* GPIO_WKUP + 0x04 */ + u8 reserved2[3]; /* GPIO_WKUP + 0x05 */ + u8 wkup_ddr; /* GPIO_WKUP + 0x08 */ + u8 reserved3[3]; /* GPIO_WKUP + 0x09 */ + u8 wkup_dvo; /* GPIO_WKUP + 0x0C */ + u8 reserved4[3]; /* GPIO_WKUP + 0x0D */ + u8 wkup_inten; /* GPIO_WKUP + 0x10 */ + u8 reserved5[3]; /* GPIO_WKUP + 0x11 */ + u8 wkup_iinten; /* GPIO_WKUP + 0x14 */ + u8 reserved6[3]; /* GPIO_WKUP + 0x15 */ + u16 wkup_itype; /* GPIO_WKUP + 0x18 */ + u8 reserved7[2]; /* GPIO_WKUP + 0x1A */ + u8 wkup_maste; /* GPIO_WKUP + 0x1C */ + u8 reserved8[3]; /* GPIO_WKUP + 0x1D */ + u8 wkup_ival; /* GPIO_WKUP + 0x20 */ + u8 reserved9[3]; /* GPIO_WKUP + 0x21 */ + u8 wkup_istat; /* GPIO_WKUP + 0x24 */ + u8 reserved10[3]; /* GPIO_WKUP + 0x25 */ +}; + +/* XLB Bus control */ +struct mpc52xx_xlb { + u8 reserved[0x40]; + u32 config; /* XLB + 0x40 */ + u32 version; /* XLB + 0x44 */ + u32 status; /* XLB + 0x48 */ + u32 int_enable; /* XLB + 0x4c */ + u32 addr_capture; /* XLB + 0x50 */ + u32 bus_sig_capture; /* XLB + 0x54 */ + u32 addr_timeout; /* XLB + 0x58 */ + u32 data_timeout; /* XLB + 0x5c */ + u32 bus_act_timeout; /* XLB + 0x60 */ + u32 master_pri_enable; /* XLB + 0x64 */ + u32 master_priority; /* XLB + 0x68 */ + u32 base_address; /* XLB + 0x6c */ + u32 snoop_window; /* XLB + 0x70 */ +}; + +#define MPC52xx_XLB_CFG_PLDIS (1 << 31) +#define MPC52xx_XLB_CFG_SNOOP (1 << 15) + +/* Clock Distribution control */ +struct mpc52xx_cdm { + u32 jtag_id; /* CDM + 0x00 reg0 read only */ + u32 rstcfg; /* CDM + 0x04 reg1 read only */ + u32 breadcrumb; /* CDM + 0x08 reg2 */ + + u8 mem_clk_sel; /* CDM + 0x0c reg3 byte0 */ + u8 xlb_clk_sel; /* CDM + 0x0d reg3 byte1 read only */ + u8 ipb_clk_sel; /* CDM + 0x0e reg3 byte2 */ + u8 pci_clk_sel; /* CDM + 0x0f reg3 byte3 */ + + u8 ext_48mhz_en; /* CDM + 0x10 reg4 byte0 */ + u8 fd_enable; /* CDM + 0x11 reg4 byte1 */ + u16 fd_counters; /* CDM + 0x12 reg4 byte2,3 */ + + u32 clk_enables; /* CDM + 0x14 reg5 */ + + u8 osc_disable; /* CDM + 0x18 reg6 byte0 */ + u8 reserved0[3]; /* CDM + 0x19 reg6 byte1,2,3 */ + + u8 ccs_sleep_enable; /* CDM + 0x1c reg7 byte0 */ + u8 osc_sleep_enable; /* CDM + 0x1d reg7 byte1 */ + u8 reserved1; /* CDM + 0x1e reg7 byte2 */ + u8 ccs_qreq_test; /* CDM + 0x1f reg7 byte3 */ + + u8 soft_reset; /* CDM + 0x20 u8 byte0 */ + u8 no_ckstp; /* CDM + 0x21 u8 byte0 */ + u8 reserved2[2]; /* CDM + 0x22 u8 byte1,2,3 */ + + u8 pll_lock; /* CDM + 0x24 reg9 byte0 */ + u8 pll_looselock; /* CDM + 0x25 reg9 byte1 */ + u8 pll_sm_lockwin; /* CDM + 0x26 reg9 byte2 */ + u8 reserved3; /* CDM + 0x27 reg9 byte3 */ + + u16 reserved4; /* CDM + 0x28 reg10 byte0,1 */ + u16 mclken_div_psc1; /* CDM + 0x2a reg10 byte2,3 */ + + u16 reserved5; /* CDM + 0x2c reg11 byte0,1 */ + u16 mclken_div_psc2; /* CDM + 0x2e reg11 byte2,3 */ + + u16 reserved6; /* CDM + 0x30 reg12 byte0,1 */ + u16 mclken_div_psc3; /* CDM + 0x32 reg12 byte2,3 */ + + u16 reserved7; /* CDM + 0x34 reg13 byte0,1 */ + u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ +}; + +#endif /* __ASSEMBLY__ */ + + +/* ========================================================================= */ +/* Prototypes for MPC52xx syslib */ +/* ========================================================================= */ + +#ifndef __ASSEMBLY__ + +extern void mpc52xx_init_irq(void); +extern unsigned int mpc52xx_get_irq(void); + +extern unsigned long mpc52xx_find_end_of_memory(void); +extern void mpc52xx_set_bat(void); +extern void mpc52xx_map_io(void); +extern void mpc52xx_restart(char *cmd); +extern void mpc52xx_halt(void); +extern void mpc52xx_power_off(void); +extern void mpc52xx_progress(char *s, unsigned short hex); +extern void mpc52xx_calibrate_decr(void); + +extern void mpc52xx_find_bridges(void); + +extern void mpc52xx_setup_cpu(void); + +static inline struct device_node * +find_mpc52xx_picnode(void) +{ + return of_find_compatible_node(NULL, "interrupt-controller", "mpc5200-pic"); +} + + /* Matching of PSC function */ +struct mpc52xx_psc_func { + int id; + char *func; +}; + +extern int mpc52xx_match_psc_function(int psc_idx, const char *func); +extern struct mpc52xx_psc_func mpc52xx_psc_functions[]; + /* This array is to be defined in platform file */ + +#endif /* __ASSEMBLY__ */ + + +#endif /* _ASM_POWERPC_MPC52xx_H__ */ [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-27 14:52 ` Nicolas DET @ 2006-10-27 15:04 ` Nicolas DET 2006-10-27 17:08 ` Jon Loeliger 2006-10-27 22:34 ` Benjamin Herrenschmidt 2006-10-27 22:05 ` Sylvain Munaut 1 sibling, 2 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-27 15:04 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 2074 bytes --] Nicolas DET wrote: > Benjamin Herrenschmidt wrote: >> On Thu, 2006-10-26 at 14:00 -0600, Grant Likely wrote: >>> My comments are satisfied >>> >>> Acked-by: Grant Likely <grant.likely@secretlab.ca> >> >> Nack. >> >> The irq code doesn't properly use the genirq infrastructure. It's not >> setting flow handlers, not implementing set_irq_type, not using the new >> mask/unmask instead of the toplevel enable/disable... >> >> > > Done. > > We agree on IRC last night to postpone this implementation later on. > However, here it is. > > This patch compiles fine when applied to the kernel 2.6.19-rc3. I also > tested gcc 3.3.5 and 4.1.2. > > I made some tests and did not found any issue. However, more > testing/stressing/torturing and also with on others platforms is > required to fully validate the driver. > > > /* Pegasos has no MPIC, those ops would make it crash. It might be an > diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h > --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 > +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 > @@ -0,0 +1,414 @@ > +/* > + * include/asm-ppc/mpc52xx.h > + * Fixed to powerpc > +#endif /* __ASSEMBLY__ */ > + > + > +#ifdef CONFIG_PCI > +#define _IO_BASE isa_io_base > +#define _ISA_MEM_BASE isa_mem_base > +#define PCI_DRAM_OFFSET pci_dram_offset > +#else > +#define _IO_BASE 0 > +#define _ISA_MEM_BASE 0 > +#define PCI_DRAM_OFFSET 0 > +#endif > + > + > +/* ======================================================================== */ > +/* PPC Sys devices definition */ > +/* ======================================================================== */ > + > +enum ppc_sys_devices { > + MPC52xx_MSCAN1, > + MPC52xx_MSCAN2, > + MPC52xx_SPI, > + MPC52xx_USB, > + MPC52xx_BDLC, > + MPC52xx_PSC1, > + MPC52xx_PSC2, > + MPC52xx_PSC3, > + MPC52xx_PSC4, > + MPC52xx_PSC5, > + MPC52xx_PSC6, > + MPC52xx_FEC, > + MPC52xx_ATA, > + MPC52xx_I2C1, > + MPC52xx_I2C2, > + NUM_PPC_SYS_DEVS, > +}; > + > + Removed [-- Attachment #2: chrpmpc52xx_2.6.19-rc3.patch --] [-- Type: text/plain, Size: 24385 bytes --] --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 +++ b/arch/powerpc/sysdev/Makefile 2006-10-27 15:31:41.000000000 +0200 @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_PPC_TODC) += todc.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ +obj-$(CONFIG_PPC_MPC52xx_PIC) += mpc52xx_pic.o ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-27 15:58:29.000000000 +0200 @@ -0,0 +1,414 @@ +/* + * arch/powerpc/sysdev/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#undef DEBUG + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/hardirq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/prom.h> +#include <asm/mpc52xx.h> + +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_sdma __iomem *sdma; +static struct irq_host *mpc52xx_irqhost = NULL; + +static void mpc52xx_ic_mask(unsigned int virq) +{ + u32 val; + int irq; + int l1irq; + int l2irq; + + irq = irq_map[virq].hwirq; + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + break; + + case MPC52xx_IRQ_L1_MAIN: + if ( (l2irq >= 1) && (l2irq <= 3) ) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (11 - l2irq)); + out_be32(&intr->ctrl, val); + } else { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - l2irq); + out_be32(&intr->main_mask, val); + } + break; + + case MPC52xx_IRQ_L1_PERP: + val = in_be32(&intr->per_mask); + val |= 1 << (31 - l2irq); + out_be32(&intr->per_mask, val); + break; + + case MPC52xx_IRQ_L1_SDMA: + val = in_be32(&sdma->IntMask); + val |= 1 << l2irq; + out_be32(&sdma->IntMask, val); + break; + + default: + printk(KERN_ERR "MPC52xx PIC: Wrong interrupt\n"); + } +} + +static void mpc52xx_ic_unmask(unsigned int virq) +{ + u32 val; + int irq; + int l1irq; + int l2irq; + + irq = irq_map[virq].hwirq; + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + break; + + case MPC52xx_IRQ_L1_MAIN: + if ( (l2irq >= 1) && (l2irq <= 3) ) { + val = in_be32(&intr->ctrl); + val |= 1 << (11 - l2irq); + out_be32(&intr->ctrl, val); + } else { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - l2irq)); + out_be32(&intr->main_mask, val); + } + break; + + case MPC52xx_IRQ_L1_PERP: + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - l2irq)); + out_be32(&intr->per_mask, val); + break; + + case MPC52xx_IRQ_L1_SDMA: + val = in_be32(&sdma->IntMask); + val &= ~(1 << l2irq); + out_be32(&sdma->IntMask, val); + break; + + default: + printk(KERN_ERR "MPC52xx PIC: Wrong interrupt\n"); + } +} + +static void mpc52xx_ic_ack(unsigned int virq) +{ + u32 val; + int irq; + int l1irq; + int l2irq; + + irq = irq_map[virq].hwirq; + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + + case MPC52xx_IRQ_L1_MAIN: + if ( (l2irq >= 1) && (l2irq <= 3) ) { + val = in_be32(&intr->ctrl); + val |= 0x08000000 >> l2irq; + out_be32(&intr->ctrl, val); + } + break; + + case MPC52xx_IRQ_L1_PERP: + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - l2irq)); + out_be32(&intr->per_mask, val); + break; + + case MPC52xx_IRQ_L1_SDMA: + out_be32(&sdma->IntPend, 1 << l2irq); + break; + + default: + printk(KERN_ERR "MPC52xx PIC: Wrong interrupt\n"); + } +} + +static void mpc52xx_ic_mask_and_ack(unsigned int irq) +{ + mpc52xx_ic_mask(irq); + mpc52xx_ic_ack(irq); +} + +static struct irq_chip mpc52xx_irqchip = { + .typename = " MPC52xx ", + .mask = mpc52xx_ic_mask, + .unmask = mpc52xx_ic_unmask, + .mask_ack = mpc52xx_ic_mask_and_ack, +}; + +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) +{ + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_picnode(), node); + return find_mpc52xx_picnode() == node; +} + +static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, + u32 * intspec, unsigned int intsize, + irq_hw_number_t * out_hwirq, + unsigned int *out_flags) +{ + static unsigned char map_senses[4] = { + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + }; + + int intrvect_l1; + int intrvect_l2; + int intrvect_type; + int intrvect_linux; + + if (intsize != 3) + return -1; + + intrvect_l1 = (int)intspec[0]; + intrvect_l2 = (int)intspec[1]; + intrvect_type = (int)intspec[2]; + + pr_debug("l1=%d, l2=%d, type=%d\n", intrvect_l1, intrvect_l2, + intrvect_type); + + intrvect_linux = + (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; + intrvect_linux |= + (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; + + pr_debug("return %x\n", intrvect_linux); + + *out_hwirq = intrvect_linux; + *out_flags = map_senses[intrvect_type]; + + return 0; + +} + +static int mpc52xx_islevel(int num) +{ + u32 ictl_req; + int ictl_type; + + ictl_req = in_be32(&intr->ctrl); + ictl_type = (ictl_req >> 16) & 0x3; + + switch (ictl_type) { + case 0: + case 3: + return 1; + } + + return 0; +} + +static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t irq) +{ + int l1irq; + int l2irq; + unsigned int status; + + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; + + status = get_irq_desc(virq)->status; + + switch (l1irq) { + case MPC52xx_IRQ_L1_CRIT: + if (l2irq != 0) + BUG(); + if (mpc52xx_islevel(0)) + status |= IRQ_LEVEL; + break; + + case MPC52xx_IRQ_L1_MAIN: + if (mpc52xx_islevel(l2irq)) + status |= IRQ_LEVEL; + break; + + default: + status |= IRQ_LEVEL; + } + + get_irq_desc(virq)->status = status; + set_irq_chip_and_handler(virq, &mpc52xx_irqchip, + (status & IRQ_LEVEL) ? handle_level_irq : + handle_edge_irq); + + pr_debug("%s: virq=%x, hw=%x. desc status=%x\n", __func__, virq, + (int)irq, status); + + return 0; +} + +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) +{ + pr_debug("%s: v=%x\n", __func__, virq); + + mpc52xx_ic_mask(virq); + set_irq_chip_and_handler(virq, NULL, NULL); + synchronize_irq(virq); +} + +static struct irq_host_ops mpc52xx_irqhost_ops = { + .match = mpc52xx_irqhost_match, + .xlate = mpc52xx_irqhost_xlate, + .map = mpc52xx_irqhost_map, + .unmap = mpc52xx_irqhost_unmap, +}; + +void __init mpc52xx_init_irq(void) +{ + int i; + u32 intr_ctrl; + + /* Remap the necessary zones */ + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); + + if ((intr == NULL) || (sdma == NULL)) + panic("Can't ioremap PIC/SDMA register or init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + intr_ctrl = in_be32(&intr->ctrl); + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001; /* CEb route critical normally */ + out_be32(&intr->ctrl, intr_ctrl); + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].chip = &mpc52xx_irqchip; + irq_desc[i].status = IRQ_LEVEL; + + } + + /* + * As last step, add an irq host to translate the real + * hw irq information provided by the ofw to linux virq + */ + + mpc52xx_irqhost = + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, + -1); +} + +unsigned int mpc52xx_get_irq(void) +{ + u32 status; + int irq = NO_IRQ_IGNORE; + + status = in_be32(&intr->enc_status); + if (status & 0x00000400) { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq |= + (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + } else if (status & 0x00200000) { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq |= + (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + } else if (status & 0x20000000) { /* peripheral */ + peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) - 1; + irq |= + (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + } else + irq |= + (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & + MPC52xx_IRQ_L1_MASK; + + } + + pr_debug("%s: irq=%x. virq=%d\n", __func__, irq, + irq_linear_revmap(mpc52xx_irqhost, irq)); + + return irq_linear_revmap(mpc52xx_irqhost, irq); +} --- a/arch/powerpc/Kconfig 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/Kconfig 2006-10-27 15:50:21.000000000 +0200 @@ -384,6 +384,11 @@ config PPC_CHRP select PPC_RTAS select PPC_MPC106 select PPC_UDBG_16550 + select PPC_MPC52xx_PIC + default y + +config PPC_MPC52xx_PIC + bool default y config PPC_PMAC --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-27 16:08:03.000000000 +0200 @@ -51,6 +51,7 @@ #include <asm/mpic.h> #include <asm/rtas.h> #include <asm/xmon.h> +#include <asm/mpc52xx.h> #include "chrp.h" @@ -435,6 +436,18 @@ static struct irqaction xmon_irqaction = }; #endif +static int __init chrp_find_mpc52xx_pic(void) +{ + if (find_mpc52xx_picnode()) { + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); + ppc_md.get_irq = mpc52xx_get_irq; + mpc52xx_init_irq(); + return 0; + } + + return -ENODEV; +} + static void __init chrp_find_8259(void) { struct device_node *np, *pic = NULL; @@ -496,6 +509,7 @@ void __init chrp_init_IRQ(void) #endif chrp_find_openpic(); chrp_find_8259(); + chrp_find_mpc52xx_pic(); #ifdef CONFIG_SMP /* Pegasos has no MPIC, those ops would make it crash. It might be an diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 @@ -0,0 +1,414 @@ +/* + * include/asm-powerpc/mpc52xx.h + * + * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips + * May need to be cleaned as the port goes on ... + * + * + * Maintainer : Sylvain Munaut <tnt@246tNt.com> + * + * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> + * for the 2.4 kernel. + * + * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com> + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __ASM_POWERPC_MPC52xx_H__ +#define __ASM_POWERPC_MPC52xx_H__ + +#ifndef __ASSEMBLY__ +#include <asm/types.h> +#include <asm/prom.h> + +#endif /* __ASSEMBLY__ */ + + +#ifdef CONFIG_PCI +#define _IO_BASE isa_io_base +#define _ISA_MEM_BASE isa_mem_base +#define PCI_DRAM_OFFSET pci_dram_offset +#else +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 +#endif + +/* ======================================================================== */ +/* Main registers/struct addresses */ +/* ======================================================================== */ + +/* MBAR position */ +#define MPC52xx_MBAR 0xf0000000 /* Phys address */ +#define MPC52xx_MBAR_VIRT 0xf0000000 /* Virt address */ +#define MPC52xx_MBAR_SIZE 0x00010000 + +#define MPC52xx_PA(x) ((phys_addr_t)(MPC52xx_MBAR + (x))) +#define MPC52xx_VA(x) ((void __iomem *)(MPC52xx_MBAR_VIRT + (x))) + +/* Registers zone offset/size */ +#define MPC52xx_MMAP_CTL_OFFSET 0x0000 +#define MPC52xx_MMAP_CTL_SIZE 0x068 +#define MPC52xx_SDRAM_OFFSET 0x0100 +#define MPC52xx_SDRAM_SIZE 0x010 +#define MPC52xx_CDM_OFFSET 0x0200 +#define MPC52xx_CDM_SIZE 0x038 +#define MPC52xx_INTR_OFFSET 0x0500 +#define MPC52xx_INTR_SIZE 0x04c +#define MPC52xx_GPTx_OFFSET(x) (0x0600 + ((x)<<4)) +#define MPC52xx_GPT_SIZE 0x010 +#define MPC52xx_RTC_OFFSET 0x0800 +#define MPC52xx_RTC_SIZE 0x024 +#define MPC52xx_GPIO_OFFSET 0x0b00 +#define MPC52xx_GPIO_SIZE 0x040 +#define MPC52xx_GPIO_WKUP_OFFSET 0x0c00 +#define MPC52xx_GPIO_WKUP_SIZE 0x028 +#define MPC52xx_PCI_OFFSET 0x0d00 +#define MPC52xx_PCI_SIZE 0x100 +#define MPC52xx_SDMA_OFFSET 0x1200 +#define MPC52xx_SDMA_SIZE 0x100 +#define MPC52xx_XLB_OFFSET 0x1f00 +#define MPC52xx_XLB_SIZE 0x100 +#define MPC52xx_PSCx_OFFSET(x) (((x)!=6)?(0x1e00+((x)<<9)):0x2c00) +#define MPC52xx_PSC_SIZE 0x0a0 + +/* SRAM used for SDMA */ +#define MPC52xx_SRAM_OFFSET 0x8000 +#define MPC52xx_SRAM_SIZE 0x4000 + + +/* ======================================================================== */ +/* IRQ mapping */ +/* ======================================================================== */ + +#define MPC52xx_IRQ_L1_CRIT 0 +#define MPC52xx_IRQ_L1_MAIN 1 +#define MPC52xx_IRQ_L1_PERP 2 +#define MPC52xx_IRQ_L1_SDMA 3 + +#define MPC52xx_IRQ_L1_OFFSET (6) +#define MPC52xx_IRQ_L1_MASK (0xc0) + +#define MPC52xx_IRQ_L2_OFFSET (0) +#define MPC52xx_IRQ_L2_MASK (0x3f) + + +/* ======================================================================== */ +/* Structures mapping of some unit register set */ +/* ======================================================================== */ + +#ifndef __ASSEMBLY__ + +/* Memory Mapping Control */ +struct mpc52xx_mmap_ctl { + u32 mbar; /* MMAP_CTRL + 0x00 */ + + u32 cs0_start; /* MMAP_CTRL + 0x04 */ + u32 cs0_stop; /* MMAP_CTRL + 0x08 */ + u32 cs1_start; /* MMAP_CTRL + 0x0c */ + u32 cs1_stop; /* MMAP_CTRL + 0x10 */ + u32 cs2_start; /* MMAP_CTRL + 0x14 */ + u32 cs2_stop; /* MMAP_CTRL + 0x18 */ + u32 cs3_start; /* MMAP_CTRL + 0x1c */ + u32 cs3_stop; /* MMAP_CTRL + 0x20 */ + u32 cs4_start; /* MMAP_CTRL + 0x24 */ + u32 cs4_stop; /* MMAP_CTRL + 0x28 */ + u32 cs5_start; /* MMAP_CTRL + 0x2c */ + u32 cs5_stop; /* MMAP_CTRL + 0x30 */ + + u32 sdram0; /* MMAP_CTRL + 0x34 */ + u32 sdram1; /* MMAP_CTRL + 0X38 */ + + u32 reserved[4]; /* MMAP_CTRL + 0x3c .. 0x48 */ + + u32 boot_start; /* MMAP_CTRL + 0x4c */ + u32 boot_stop; /* MMAP_CTRL + 0x50 */ + + u32 ipbi_ws_ctrl; /* MMAP_CTRL + 0x54 */ + + u32 cs6_start; /* MMAP_CTRL + 0x58 */ + u32 cs6_stop; /* MMAP_CTRL + 0x5c */ + u32 cs7_start; /* MMAP_CTRL + 0x60 */ + u32 cs7_stop; /* MMAP_CTRL + 0x64 */ +}; + +/* SDRAM control */ +struct mpc52xx_sdram { + u32 mode; /* SDRAM + 0x00 */ + u32 ctrl; /* SDRAM + 0x04 */ + u32 config1; /* SDRAM + 0x08 */ + u32 config2; /* SDRAM + 0x0c */ +}; + +/* Interrupt controller */ +struct mpc52xx_intr { + u32 per_mask; /* INTR + 0x00 */ + u32 per_pri1; /* INTR + 0x04 */ + u32 per_pri2; /* INTR + 0x08 */ + u32 per_pri3; /* INTR + 0x0c */ + u32 ctrl; /* INTR + 0x10 */ + u32 main_mask; /* INTR + 0x14 */ + u32 main_pri1; /* INTR + 0x18 */ + u32 main_pri2; /* INTR + 0x1c */ + u32 reserved1; /* INTR + 0x20 */ + u32 enc_status; /* INTR + 0x24 */ + u32 crit_status; /* INTR + 0x28 */ + u32 main_status; /* INTR + 0x2c */ + u32 per_status; /* INTR + 0x30 */ + u32 reserved2; /* INTR + 0x34 */ + u32 per_error; /* INTR + 0x38 */ +}; + +/* SDMA */ +struct mpc52xx_sdma { + u32 taskBar; /* SDMA + 0x00 */ + u32 currentPointer; /* SDMA + 0x04 */ + u32 endPointer; /* SDMA + 0x08 */ + u32 variablePointer;/* SDMA + 0x0c */ + + u8 IntVect1; /* SDMA + 0x10 */ + u8 IntVect2; /* SDMA + 0x11 */ + u16 PtdCntrl; /* SDMA + 0x12 */ + + u32 IntPend; /* SDMA + 0x14 */ + u32 IntMask; /* SDMA + 0x18 */ + + u16 tcr[16]; /* SDMA + 0x1c .. 0x3a */ + + u8 ipr[32]; /* SDMA + 0x3c .. 0x5b */ + + u32 cReqSelect; /* SDMA + 0x5c */ + u32 task_size0; /* SDMA + 0x60 */ + u32 task_size1; /* SDMA + 0x64 */ + u32 MDEDebug; /* SDMA + 0x68 */ + u32 ADSDebug; /* SDMA + 0x6c */ + u32 Value1; /* SDMA + 0x70 */ + u32 Value2; /* SDMA + 0x74 */ + u32 Control; /* SDMA + 0x78 */ + u32 Status; /* SDMA + 0x7c */ + u32 PTDDebug; /* SDMA + 0x80 */ +}; + +/* GPT */ +struct mpc52xx_gpt { + u32 mode; /* GPTx + 0x00 */ + u32 count; /* GPTx + 0x04 */ + u32 pwm; /* GPTx + 0x08 */ + u32 status; /* GPTx + 0X0c */ +}; + +/* RTC */ +struct mpc52xx_rtc { + u32 time_set; /* RTC + 0x00 */ + u32 date_set; /* RTC + 0x04 */ + u32 stopwatch; /* RTC + 0x08 */ + u32 int_enable; /* RTC + 0x0c */ + u32 time; /* RTC + 0x10 */ + u32 date; /* RTC + 0x14 */ + u32 stopwatch_intr; /* RTC + 0x18 */ + u32 bus_error; /* RTC + 0x1c */ + u32 dividers; /* RTC + 0x20 */ +}; + +/* GPIO */ +struct mpc52xx_gpio { + u32 port_config; /* GPIO + 0x00 */ + u32 simple_gpioe; /* GPIO + 0x04 */ + u32 simple_ode; /* GPIO + 0x08 */ + u32 simple_ddr; /* GPIO + 0x0c */ + u32 simple_dvo; /* GPIO + 0x10 */ + u32 simple_ival; /* GPIO + 0x14 */ + u8 outo_gpioe; /* GPIO + 0x18 */ + u8 reserved1[3]; /* GPIO + 0x19 */ + u8 outo_dvo; /* GPIO + 0x1c */ + u8 reserved2[3]; /* GPIO + 0x1d */ + u8 sint_gpioe; /* GPIO + 0x20 */ + u8 reserved3[3]; /* GPIO + 0x21 */ + u8 sint_ode; /* GPIO + 0x24 */ + u8 reserved4[3]; /* GPIO + 0x25 */ + u8 sint_ddr; /* GPIO + 0x28 */ + u8 reserved5[3]; /* GPIO + 0x29 */ + u8 sint_dvo; /* GPIO + 0x2c */ + u8 reserved6[3]; /* GPIO + 0x2d */ + u8 sint_inten; /* GPIO + 0x30 */ + u8 reserved7[3]; /* GPIO + 0x31 */ + u16 sint_itype; /* GPIO + 0x34 */ + u16 reserved8; /* GPIO + 0x36 */ + u8 gpio_control; /* GPIO + 0x38 */ + u8 reserved9[3]; /* GPIO + 0x39 */ + u8 sint_istat; /* GPIO + 0x3c */ + u8 sint_ival; /* GPIO + 0x3d */ + u8 bus_errs; /* GPIO + 0x3e */ + u8 reserved10; /* GPIO + 0x3f */ +}; + +#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD 4 +#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD 5 +#define MPC52xx_GPIO_PCI_DIS (1<<15) + +/* GPIO with WakeUp*/ +struct mpc52xx_gpio_wkup { + u8 wkup_gpioe; /* GPIO_WKUP + 0x00 */ + u8 reserved1[3]; /* GPIO_WKUP + 0x03 */ + u8 wkup_ode; /* GPIO_WKUP + 0x04 */ + u8 reserved2[3]; /* GPIO_WKUP + 0x05 */ + u8 wkup_ddr; /* GPIO_WKUP + 0x08 */ + u8 reserved3[3]; /* GPIO_WKUP + 0x09 */ + u8 wkup_dvo; /* GPIO_WKUP + 0x0C */ + u8 reserved4[3]; /* GPIO_WKUP + 0x0D */ + u8 wkup_inten; /* GPIO_WKUP + 0x10 */ + u8 reserved5[3]; /* GPIO_WKUP + 0x11 */ + u8 wkup_iinten; /* GPIO_WKUP + 0x14 */ + u8 reserved6[3]; /* GPIO_WKUP + 0x15 */ + u16 wkup_itype; /* GPIO_WKUP + 0x18 */ + u8 reserved7[2]; /* GPIO_WKUP + 0x1A */ + u8 wkup_maste; /* GPIO_WKUP + 0x1C */ + u8 reserved8[3]; /* GPIO_WKUP + 0x1D */ + u8 wkup_ival; /* GPIO_WKUP + 0x20 */ + u8 reserved9[3]; /* GPIO_WKUP + 0x21 */ + u8 wkup_istat; /* GPIO_WKUP + 0x24 */ + u8 reserved10[3]; /* GPIO_WKUP + 0x25 */ +}; + +/* XLB Bus control */ +struct mpc52xx_xlb { + u8 reserved[0x40]; + u32 config; /* XLB + 0x40 */ + u32 version; /* XLB + 0x44 */ + u32 status; /* XLB + 0x48 */ + u32 int_enable; /* XLB + 0x4c */ + u32 addr_capture; /* XLB + 0x50 */ + u32 bus_sig_capture; /* XLB + 0x54 */ + u32 addr_timeout; /* XLB + 0x58 */ + u32 data_timeout; /* XLB + 0x5c */ + u32 bus_act_timeout; /* XLB + 0x60 */ + u32 master_pri_enable; /* XLB + 0x64 */ + u32 master_priority; /* XLB + 0x68 */ + u32 base_address; /* XLB + 0x6c */ + u32 snoop_window; /* XLB + 0x70 */ +}; + +#define MPC52xx_XLB_CFG_PLDIS (1 << 31) +#define MPC52xx_XLB_CFG_SNOOP (1 << 15) + +/* Clock Distribution control */ +struct mpc52xx_cdm { + u32 jtag_id; /* CDM + 0x00 reg0 read only */ + u32 rstcfg; /* CDM + 0x04 reg1 read only */ + u32 breadcrumb; /* CDM + 0x08 reg2 */ + + u8 mem_clk_sel; /* CDM + 0x0c reg3 byte0 */ + u8 xlb_clk_sel; /* CDM + 0x0d reg3 byte1 read only */ + u8 ipb_clk_sel; /* CDM + 0x0e reg3 byte2 */ + u8 pci_clk_sel; /* CDM + 0x0f reg3 byte3 */ + + u8 ext_48mhz_en; /* CDM + 0x10 reg4 byte0 */ + u8 fd_enable; /* CDM + 0x11 reg4 byte1 */ + u16 fd_counters; /* CDM + 0x12 reg4 byte2,3 */ + + u32 clk_enables; /* CDM + 0x14 reg5 */ + + u8 osc_disable; /* CDM + 0x18 reg6 byte0 */ + u8 reserved0[3]; /* CDM + 0x19 reg6 byte1,2,3 */ + + u8 ccs_sleep_enable; /* CDM + 0x1c reg7 byte0 */ + u8 osc_sleep_enable; /* CDM + 0x1d reg7 byte1 */ + u8 reserved1; /* CDM + 0x1e reg7 byte2 */ + u8 ccs_qreq_test; /* CDM + 0x1f reg7 byte3 */ + + u8 soft_reset; /* CDM + 0x20 u8 byte0 */ + u8 no_ckstp; /* CDM + 0x21 u8 byte0 */ + u8 reserved2[2]; /* CDM + 0x22 u8 byte1,2,3 */ + + u8 pll_lock; /* CDM + 0x24 reg9 byte0 */ + u8 pll_looselock; /* CDM + 0x25 reg9 byte1 */ + u8 pll_sm_lockwin; /* CDM + 0x26 reg9 byte2 */ + u8 reserved3; /* CDM + 0x27 reg9 byte3 */ + + u16 reserved4; /* CDM + 0x28 reg10 byte0,1 */ + u16 mclken_div_psc1; /* CDM + 0x2a reg10 byte2,3 */ + + u16 reserved5; /* CDM + 0x2c reg11 byte0,1 */ + u16 mclken_div_psc2; /* CDM + 0x2e reg11 byte2,3 */ + + u16 reserved6; /* CDM + 0x30 reg12 byte0,1 */ + u16 mclken_div_psc3; /* CDM + 0x32 reg12 byte2,3 */ + + u16 reserved7; /* CDM + 0x34 reg13 byte0,1 */ + u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ +}; + +#endif /* __ASSEMBLY__ */ + + +/* ========================================================================= */ +/* Prototypes for MPC52xx syslib */ +/* ========================================================================= */ + +#ifndef __ASSEMBLY__ + +extern void mpc52xx_init_irq(void); +extern unsigned int mpc52xx_get_irq(void); + +extern unsigned long mpc52xx_find_end_of_memory(void); +extern void mpc52xx_set_bat(void); +extern void mpc52xx_map_io(void); +extern void mpc52xx_restart(char *cmd); +extern void mpc52xx_halt(void); +extern void mpc52xx_power_off(void); +extern void mpc52xx_progress(char *s, unsigned short hex); +extern void mpc52xx_calibrate_decr(void); + +extern void mpc52xx_find_bridges(void); + +extern void mpc52xx_setup_cpu(void); + +static inline struct device_node * +find_mpc52xx_picnode(void) +{ + return of_find_compatible_node(NULL, "interrupt-controller", "mpc5200-pic"); +} + + /* Matching of PSC function */ +struct mpc52xx_psc_func { + int id; + char *func; +}; + +extern int mpc52xx_match_psc_function(int psc_idx, const char *func); +extern struct mpc52xx_psc_func mpc52xx_psc_functions[]; + /* This array is to be defined in platform file */ + +#endif /* __ASSEMBLY__ */ + + +#endif /* _ASM_POWERPC_MPC52xx_H__ */ [-- Attachment #3: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-27 15:04 ` Nicolas DET @ 2006-10-27 17:08 ` Jon Loeliger 2006-10-28 0:27 ` Stephen Rothwell 2006-10-27 22:34 ` Benjamin Herrenschmidt 1 sibling, 1 reply; 40+ messages in thread From: Jon Loeliger @ 2006-10-27 17:08 UTC (permalink / raw) To: Nicolas DET Cc: akpm, linuxppc-dev@ozlabs.org, sl, sha, linuxppc-embedded@ozlabs.org On Fri, 2006-10-27 at 10:04, Nicolas DET wrote: > > diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h > > --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 > > +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 > > @@ -0,0 +1,414 @@ > > +/* > > + * include/asm-ppc/mpc52xx.h > > + * > > > Fixed to powerpc I thought we were removing the names of files from within the file itself, right? Thanks, jdl ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-27 17:08 ` Jon Loeliger @ 2006-10-28 0:27 ` Stephen Rothwell 0 siblings, 0 replies; 40+ messages in thread From: Stephen Rothwell @ 2006-10-28 0:27 UTC (permalink / raw) To: Jon Loeliger Cc: akpm, sl, linuxppc-dev@ozlabs.org, linuxppc-embedded@ozlabs.org, sha [-- Attachment #1: Type: text/plain, Size: 707 bytes --] On Fri, 27 Oct 2006 12:08:46 -0500 Jon Loeliger <jdl@freescale.com> wrote: > > On Fri, 2006-10-27 at 10:04, Nicolas DET wrote: > > > > diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h > > > --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 > > > +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 > > > @@ -0,0 +1,414 @@ > > > +/* > > > + * include/asm-ppc/mpc52xx.h > > > + * > > > > Fixed to powerpc > > I thought we were removing the names of files from > within the file itself, right? Correct. They add nothing and become stale. -- Cheers, Stephen Rothwell sfr@canb.auug.org.au http://www.canb.auug.org.au/~sfr/ [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-27 15:04 ` Nicolas DET 2006-10-27 17:08 ` Jon Loeliger @ 2006-10-27 22:34 ` Benjamin Herrenschmidt 1 sibling, 0 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-27 22:34 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, linuxppc-dev, sl, sha, linuxppc-embedded On Fri, 2006-10-27 at 17:04 +0200, Nicolas DET wrote: > +static void mpc52xx_ic_mask(unsigned int virq) > +{ > + u32 val; > + int irq; > + int l1irq; > + int l2irq; > + > + irq = irq_map[virq].hwirq; > + l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; > + l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; > + > + pr_debug("%s: irq=%x. l1=%d, l2=%d\n", __func__, irq, l1irq, l2irq); > + > + switch (l1irq) { > + case MPC52xx_IRQ_L1_CRIT: > + if (l2irq != 0) > + BUG(); > + > + val = in_be32(&intr->ctrl); > + val &= ~(1 << 11); > + out_be32(&intr->ctrl, val); > + break; > + > + case MPC52xx_IRQ_L1_MAIN: > + if ( (l2irq >= 1) && (l2irq <= 3) ) { > + val = in_be32(&intr->ctrl); > + val &= ~(1 << (11 - l2irq)); > + out_be32(&intr->ctrl, val); > + } else { > + val = in_be32(&intr->main_mask); > + val |= 1 << (16 - l2irq); > + out_be32(&intr->main_mask, val); > + } > + break; Any reason why you do the above instead o defining two diferent levels instead. Also, L1_CRIT would fit in the L1_MAIN case too... I don't see the point of having also XXX-l2, just put a bit number in L2 and be done with it. The idea is to streamling the code, such that you can index an array with l1irq to get the register, and build a mask. No test, no switch case, etc... Actually... the most performant way of doing all this is to have a different irq_chip (with a different set of ask,mask,unmask) for each "L1" so that they get right to the point. But I would settle for an array indexed by L1. > +static void mpc52xx_ic_mask_and_ack(unsigned int irq) > +{ > + mpc52xx_ic_mask(irq); > + mpc52xx_ic_ack(irq); > +} The above is unnuecessary. The core will call mask and ack. > +static struct irq_chip mpc52xx_irqchip = { > + .typename = " MPC52xx ", > + .mask = mpc52xx_ic_mask, > + .unmask = mpc52xx_ic_unmask, > + .mask_ack = mpc52xx_ic_mask_and_ack, > +}; In the above, you need to provide ack. > +static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) > +{ > + pr_debug("%s: %p vs %p\n", __func__, find_mpc52xx_picnode(), node); > + return find_mpc52xx_picnode() == node; > +} Don't redo the whole find all the time. Put the node in your irq_host->host_data at init time and compare it there. That way, also, find_mpc53xx_picnode() thingy can just stay static to chrp/setup.c. The way you did it would be a problem if we had more than one platform using 52xx built in the same kernel. > +static int mpc52xx_islevel(int num) > +{ > + u32 ictl_req; > + int ictl_type; > + > + ictl_req = in_be32(&intr->ctrl); > + ictl_type = (ictl_req >> 16) & 0x3; > + > + switch (ictl_type) { > + case 0: > + case 3: > + return 1; > + } > + > + return 0; > +} You only have level/edge settings, not polarity ? Also, you aren't giving the user or device-tree the option to set the type manually.... Ideally, you should use the bits in IRQ_TYPE_SENSE_MASK to fully define the irq type/polarity and provide a set_irq_type() callback. Also, beware that you cannot call set_irq_chip_and_handler() from within set_irq_type() due to a spinlock recursion issue. There is a patch floating on the list for IPIC fixing an issue of that sort, you may want to have a look. In general, look at what others are doing, notably mpic and ipic. You can also keep IRQ_LEVEL in "sync" with the other polarity bits, it's really only useful to display the polarity in /proc/interrupts. Note that your map code would always OR the bit, never clear it. It should have probably cleared it before the switch/case. > +void mpc52xx_irqhost_unmap(struct irq_host *h, unsigned int virq) > +{ > + pr_debug("%s: v=%x\n", __func__, virq); > + > + mpc52xx_ic_mask(virq); > + set_irq_chip_and_handler(virq, NULL, NULL); > + synchronize_irq(virq); > +} The common code will do all of the above. Your unmap can be empty. (Or just don't do an unmap). > +static struct irq_host_ops mpc52xx_irqhost_ops = { > + .match = mpc52xx_irqhost_match, > + .xlate = mpc52xx_irqhost_xlate, > + .map = mpc52xx_irqhost_map, > + .unmap = mpc52xx_irqhost_unmap, > +}; > + > +void __init mpc52xx_init_irq(void) > +{ > + int i; > + u32 intr_ctrl; > + > + /* Remap the necessary zones */ > + intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); > + sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE); > + > + if ((intr == NULL) || (sdma == NULL)) > + panic("Can't ioremap PIC/SDMA register or init_irq !"); > + > + /* Disable all interrupt sources. */ > + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ > + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ > + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ > + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ > + intr_ctrl = in_be32(&intr->ctrl); > + intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ > + intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ > + 0x00001000 | /* MEE master external enable */ > + 0x00000000 | /* 0 means disable IRQ 0-3 */ > + 0x00000001; /* CEb route critical normally */ > + out_be32(&intr->ctrl, intr_ctrl); > + > + /* Zero a bunch of the priority settings. */ > + out_be32(&intr->per_pri1, 0); > + out_be32(&intr->per_pri2, 0); > + out_be32(&intr->per_pri3, 0); > + out_be32(&intr->main_pri1, 0); > + out_be32(&intr->main_pri2, 0); > + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ > + for (i = 0; i < NR_IRQS; i++) { > + irq_desc[i].chip = &mpc52xx_irqchip; > + irq_desc[i].status = IRQ_LEVEL; > + > + } The above is completely bogus and should be just removed. You should not touch the irq_desc array. You should only ever modify irq_desc's that have been assigned to you by your host->map callback. > + /* > + * As last step, add an irq host to translate the real > + * hw irq information provided by the ofw to linux virq > + */ > + > + mpc52xx_irqhost = > + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, > + -1); > +} As I said before, NR_IRQ is a poor choice for the size of the revmap. You should have a constant somewhere defining what is your max HW irq number. and use that +1, or a hw irq count. > --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-27 16:08:03.000000000 +0200 > @@ -51,6 +51,7 @@ > #include <asm/mpic.h> > #include <asm/rtas.h> > #include <asm/xmon.h> > +#include <asm/mpc52xx.h> > > #include "chrp.h" > > @@ -435,6 +436,18 @@ static struct irqaction xmon_irqaction = > }; > #endif > > +static int __init chrp_find_mpc52xx_pic(void) > +{ > + if (find_mpc52xx_picnode()) { > + printk(KERN_INFO "Found MPC52xx Interrupt Controller\n"); > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return 0; > + } > + > + return -ENODEV; > +} Just get rif of find_mpic53xx_picnode. Do it locally and pass the device node to mpc52xx_init_irq(). > static void __init chrp_find_8259(void) > { > struct device_node *np, *pic = NULL; > @@ -496,6 +509,7 @@ void __init chrp_init_IRQ(void) > #endif > chrp_find_openpic(); > chrp_find_8259(); > + chrp_find_mpc52xx_pic(); > > #ifdef CONFIG_SMP > /* Pegasos has no MPIC, those ops would make it crash. It might be an > diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h > --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 > +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 > @@ -0,0 +1,414 @@ > +/* > + * include/asm-powerpc/mpc52xx.h > + * > + * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips > + * May need to be cleaned as the port goes on ... > + * > + * > + * Maintainer : Sylvain Munaut <tnt@246tNt.com> > + * > + * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> > + * for the 2.4 kernel. > + * > + * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com> > + * Copyright (C) 2003 MontaVista, Software, Inc. > + * > + * This file is licensed under the terms of the GNU General Public License > + * version 2. This program is licensed "as is" without any warranty of any > + * kind, whether express or implied. > + */ > + > +#ifndef __ASM_POWERPC_MPC52xx_H__ > +#define __ASM_POWERPC_MPC52xx_H__ > + > +#ifndef __ASSEMBLY__ > +#include <asm/types.h> > +#include <asm/prom.h> > + > +#endif /* __ASSEMBLY__ */ > + > + > +#ifdef CONFIG_PCI > +#define _IO_BASE isa_io_base > +#define _ISA_MEM_BASE isa_mem_base > +#define PCI_DRAM_OFFSET pci_dram_offset > +#else > +#define _IO_BASE 0 > +#define _ISA_MEM_BASE 0 > +#define PCI_DRAM_OFFSET 0 > +#endif Remove all of the above, it's bogus. You don't want to touch those things when CONFIG_MULTIPLATFORM. (That is, they are variables set programmatically, you can't just go #define them and common code already takes care of defining them anyway). Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-27 14:52 ` Nicolas DET 2006-10-27 15:04 ` Nicolas DET @ 2006-10-27 22:05 ` Sylvain Munaut 1 sibling, 0 replies; 40+ messages in thread From: Sylvain Munaut @ 2006-10-27 22:05 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha Hi Nicolas, Here is a few comments. I'm not very familiar with the new irq stuff so others might have more insights. Sylvain > --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 > +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-27 15:58:29.000000000 +0200 > @@ -0,0 +1,414 @@ > +/* > + * arch/powerpc/sysdev/mpc52xx_pic.c > Looks like jdl is right, we apparently don't do that any more ... So let's not ;) > + * Based on (well, mostly copied from) the code from the 2.4 kernel by > + * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. > That can be removed ... We can't blame Dale anymore if it doesn't work ;) > + > +static void mpc52xx_ic_mask_and_ack(unsigned int irq) > +{ > + mpc52xx_ic_mask(irq); > + mpc52xx_ic_ack(irq); > +} > >From kernel/irq/chip.c that's done automatically if mask_and_ack is NULL. > + > +static struct irq_chip mpc52xx_irqchip = { > + .typename = " MPC52xx ", > + .mask = mpc52xx_ic_mask, > + .unmask = mpc52xx_ic_unmask, > + .mask_ack = mpc52xx_ic_mask_and_ack, > +}; Is it useful to implement set_type for IRQ[0-3] ? (Just asking ...) > + for (i = 0; i < NR_IRQS; i++) { > + irq_desc[i].chip = &mpc52xx_irqchip; > + irq_desc[i].status = IRQ_LEVEL; > + > + } > All LEVEL ? > + > + /* > + * As last step, add an irq host to translate the real > + * hw irq information provided by the ofw to linux virq > + */ > + > + mpc52xx_irqhost = > + irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IRQS, &mpc52xx_irqhost_ops, > + -1); > +} > NR_IRQS ? Might be time to do something better. > diff -uprN a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h > --- a/include/asm-powerpc/mpc52xx.h 1970-01-01 01:00:00.000000000 +0100 > +++ b/include/asm-powerpc/mpc52xx.h 2006-10-27 15:51:55.000000000 +0200 > @@ -0,0 +1,414 @@ > +/* > + * include/asm-ppc/mpc52xx.h > + * > + * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips > + * May need to be cleaned as the port goes on ... > + * > + * > + * Maintainer : Sylvain Munaut <tnt@246tNt.com> > + * > + * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> > + * for the 2.4 kernel. > Again, remove all that (just leave the first line of the description) > + > +/* ======================================================================== */ > +/* IRQ mapping */ > +/* ======================================================================== */ > + > +#define MPC52xx_IRQ_L1_CRIT 0 > +#define MPC52xx_IRQ_L1_MAIN 1 > +#define MPC52xx_IRQ_L1_PERP 2 > +#define MPC52xx_IRQ_L1_SDMA 3 > + > +#define MPC52xx_IRQ_L1_OFFSET (6) > +#define MPC52xx_IRQ_L1_MASK (0xc0) > + > +#define MPC52xx_IRQ_L2_OFFSET (0) > +#define MPC52xx_IRQ_L2_MASK (0x3f) > As benh suggested on IRC, a L1 offset of 8 might be better for readability of the hw irq numbers. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 19:05 [PATCH] General CHRP/MPC5K2 platform support patch Nicolas DET 2006-10-25 21:59 ` Paul Mackerras 2006-10-25 22:53 ` Benjamin Herrenschmidt @ 2006-10-25 23:01 ` Grant Likely 2006-10-25 23:06 ` Benjamin Herrenschmidt 2006-10-26 17:17 ` John Rigby 3 siblings, 1 reply; 40+ messages in thread From: Grant Likely @ 2006-10-25 23:01 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha Thanks Nicolas, I'll dig through the PIC code tonight. I'm really not sure about the implications of this being a CHRP board vs. the Lite5200 using u-boot. ie. Should the Lite5200 also be a CHRP platform? Does u-boot provide enough capability (this is where my ignorance about CHRP shines through) Cheers, g. On 10/25/06, Nicolas DET <nd@bplan-gmbh.de> wrote: > * mpc5k2.c: As far as I understood, using of_platform_device will allow > 'smart' of tree parsing. I did not implement it yet. > > * mpc5k2_pic.c : The thingy ;-). I moved it into arch/powerpc/sysdev as > suggested. This code is 99% copy/paste from the ARCH=ppc. I added an > irq_host with the appropriate xlate and co. However, I have not done > more as this code has been written by others. I think we should work > together to move to new Linux style irq. I stay ready to test or code > upcoming revision/ Why change the naming scheme from mpc52xx to mpc5k3? All other freescale supports follow the mpcXXxxx scheme. > > * arch/powerpc/platform/*. Here, only small changes has been made. I > added _CHRP_E5K2 (in asm/processor.h), an entry in chrp_names() and the > correct detection in arch/powerpc/platform/setup.c / chrp_setup_arch(). > in chrp_init_IRQ(), I set ppc_md.get_irq to mpc52xx_get_irq and call > mpc52xx_init_irq(). > > * serial stuff / IBP Freq. As this frequency is MPC52xx specific. I > think it would make sense to add a new func mpc52xx_getipbfreq(void). > The way it would be implemented may depend of the architecture. Our > firmware contains an 'ipb-freq' property in '/builtin/'. > > diff -uprN a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c > --- a/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:07:23.000000000 +0200 > +++ b/arch/powerpc/platforms/chrp/setup.c 2006-10-25 19:10:18.000000000 +0200 > @@ -101,7 +102,8 @@ static const char *chrp_names[] = { > "Motorola", > "IBM or Longtrail", > "Genesi Pegasos", > - "Total Impact Briq" > + "Total Impact Briq", > + "bPlan Efika" > }; I agree w/ Paul... the chrp_type stuff is stinky. :) > @@ -494,6 +498,12 @@ void __init chrp_init_IRQ(void) > #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) > struct device_node *kbd; > #endif > + if (_chrp_type == _CHRP_E5K2) { > + ppc_md.get_irq = mpc52xx_get_irq; > + mpc52xx_init_irq(); > + return; > + } > + > chrp_find_openpic(); > chrp_find_8259(); Also, this only covers one 52xx board and does not match the convention in this function. Shouldn't this instead call a new function "chrp_find_mpc52xx_pic()? > > @@ -530,6 +540,9 @@ chrp_init2(void) > chrp_nvram_init(); > #endif > > + if (_chrp_type == _CHRP_E5K2) > + return; > + > request_region(0x20,0x20,"pic1"); > request_region(0xa0,0x20,"pic2"); > request_region(0x00,0x20,"dma1"); There's got to be a better way to go about this. If all the request_regions are not required by all CHRP platforms, then they should be enclosed by an if{} block. Just bailing from the function does not seem to be a good idea to me. For example, at the end of chrp_init2() there is a progress method called (if enabled). Bailing out prevents that progress message. (not a big issue, but I'm looking a convention consistency here) > diff -uprN a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h > --- a/include/asm-powerpc/processor.h 2006-10-25 19:07:48.000000000 +0200 > +++ b/include/asm-powerpc/processor.h 2006-10-25 19:11:54.000000000 +0200 > @@ -33,6 +33,7 @@ > #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ > #define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */ > #define _CHRP_briq 0x07 /* TotalImpact's briQ */ > +#define _CHRP_E5K2 0x08 /* bPlan's Efika 5k2*/ Ick. :) > diff -uprN a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h > --- a/include/asm-ppc/mpc52xx.h 2006-10-25 19:07:48.000000000 +0200 > +++ b/include/asm-ppc/mpc52xx.h 2006-10-25 19:11:55.000000000 +0200 > @@ -119,7 +119,7 @@ enum ppc_sys_devices { > #define MPC52xx_SDMA_IRQ_NUM 17 > #define MPC52xx_PERP_IRQ_NUM 23 > > -#define MPC52xx_CRIT_IRQ_BASE 1 > +#define MPC52xx_CRIT_IRQ_BASE 0 > #define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM) > #define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM) > #define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM) Just curious... why? > --- a/arch/powerpc/sysdev/mpc52xx_pic.c 1970-01-01 01:00:00.000000000 +0100 > +++ b/arch/powerpc/sysdev/mpc52xx_pic.c 2006-10-25 19:17:48.000000000 +0200 I'll skip commenting on PIC stuff as I'm still working through how it all works myself. It still needs to be worked out if we go to a two level interrupt # table in the device tree (interrupt_cells=3) and where they will be mapped back into Linux IRQ numbers. > --- a/arch/powerpc/sysdev/Makefile 2006-10-25 19:07:24.000000000 +0200 > +++ b/arch/powerpc/sysdev/Makefile 2006-10-25 20:33:32.000000000 +0200 > @@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o > obj-$(CONFIG_PPC_TODC) += todc.o > obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o > obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ > +obj-$(CONFIG_PPC_CHRP) += mpc52xx_pic.o > > ifeq ($(CONFIG_PPC_MERGE),y) > obj-$(CONFIG_PPC_I8259) += i8259.o > > > > -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. grant.likely@secretlab.ca (403) 399-0195 ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 23:01 ` Grant Likely @ 2006-10-25 23:06 ` Benjamin Herrenschmidt 2006-10-25 23:13 ` Sven Luther 2006-10-26 12:09 ` Nicolas DET 0 siblings, 2 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-25 23:06 UTC (permalink / raw) To: Grant Likely; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha On Wed, 2006-10-25 at 17:01 -0600, Grant Likely wrote: > Thanks Nicolas, I'll dig through the PIC code tonight. I'm really not > sure about the implications of this being a CHRP board vs. the > Lite5200 using u-boot. ie. Should the Lite5200 also be a CHRP > platform? Does u-boot provide enough capability (this is where my > ignorance about CHRP shines through) Bah, if you have no RTAS, don't bother being CHRP. > > * serial stuff / IBP Freq. As this frequency is MPC52xx specific. I > > think it would make sense to add a new func mpc52xx_getipbfreq(void). > > The way it would be implemented may depend of the architecture. Our > > firmware contains an 'ipb-freq' property in '/builtin/'. BTW. I forgot to comment on the above in my previous mail... As I said, there should be no such thing. Instead, the IPB freq should be in the device-tree. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 23:06 ` Benjamin Herrenschmidt @ 2006-10-25 23:13 ` Sven Luther 2006-10-26 12:09 ` Nicolas DET 1 sibling, 0 replies; 40+ messages in thread From: Sven Luther @ 2006-10-25 23:13 UTC (permalink / raw) To: Benjamin Herrenschmidt Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, sven, sha On Thu, Oct 26, 2006 at 09:06:16AM +1000, Benjamin Herrenschmidt wrote: > > > * serial stuff / IBP Freq. As this frequency is MPC52xx specific. I > > > think it would make sense to add a new func mpc52xx_getipbfreq(void). > > > The way it would be implemented may depend of the architecture. Our > > > firmware contains an 'ipb-freq' property in '/builtin/'. > > BTW. I forgot to comment on the above in my previous mail... As I said, > there should be no such thing. Instead, the IPB freq should be in the > device-tree. Euh, how is this different from having our "firmware contains an 'ipb-freq' property in '/builtin/'". There is no an ipb-freq property in the device tree, so you need a function to be able to get it from the the device tree, which i believe what is proposed here. Friendly, Sven Luther ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 23:06 ` Benjamin Herrenschmidt 2006-10-25 23:13 ` Sven Luther @ 2006-10-26 12:09 ` Nicolas DET 2006-10-26 12:51 ` Benjamin Herrenschmidt 1 sibling, 1 reply; 40+ messages in thread From: Nicolas DET @ 2006-10-26 12:09 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 586 bytes --] Benjamin Herrenschmidt wrote: >>> * serial stuff / IBP Freq. As this frequency is MPC52xx specific. I >>> think it would make sense to add a new func mpc52xx_getipbfreq(void). >>> The way it would be implemented may depend of the architecture. Our >>> firmware contains an 'ipb-freq' property in '/builtin/'. > > BTW. I forgot to comment on the above in my previous mail... As I said, > there should be no such thing. Instead, the IPB freq should be in the > device-tree. > > > What do you mean exactly by 'the IPB freq should be in the device-tree'? It is as property. Regards [-- Attachment #2: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 12:09 ` Nicolas DET @ 2006-10-26 12:51 ` Benjamin Herrenschmidt 0 siblings, 0 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-26 12:51 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha On Thu, 2006-10-26 at 14:09 +0200, Nicolas DET wrote: > What do you mean exactly by 'the IPB freq should be in the device-tree'? > It is as property. Yeah, just that drivers should pick it up from there Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-25 19:05 [PATCH] General CHRP/MPC5K2 platform support patch Nicolas DET ` (2 preceding siblings ...) 2006-10-25 23:01 ` Grant Likely @ 2006-10-26 17:17 ` John Rigby 2006-10-26 17:23 ` Nicolas DET ` (2 more replies) 3 siblings, 3 replies; 40+ messages in thread From: John Rigby @ 2006-10-26 17:17 UTC (permalink / raw) To: Nicolas DET; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha > > * mpc5k2_bestcomm.c (& helpers): I've been in contact with others people > using bestcomm and please to see the development was still active. I'm > already using latest code on my board but this is not include in this > patch. Indeed, it needs some changes for ARCH=powerpc. Moreover, we have > a different approach for the tasks. I'll be pleased to work with the > bestcomm folks. > So you preload the bestcomm task code in your boot loader? Do those of us using other bootloaders still have the option of loading the task code later in linux? What api are you using? Sylvain's proposed one based on Dale's with some additions from me? Or have you come up with your own? ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:17 ` John Rigby @ 2006-10-26 17:23 ` Nicolas DET 2006-10-26 17:33 ` Sylvain Munaut 2006-10-27 2:57 ` Benjamin Herrenschmidt 2 siblings, 0 replies; 40+ messages in thread From: Nicolas DET @ 2006-10-26 17:23 UTC (permalink / raw) To: John Rigby; +Cc: akpm, sl, linuxppc-dev, linuxppc-embedded, sha [-- Attachment #1: Type: text/plain, Size: 934 bytes --] John Rigby wrote: >> >> * mpc5k2_bestcomm.c (& helpers): I've been in contact with others people >> using bestcomm and please to see the development was still active. I'm >> already using latest code on my board but this is not include in this >> patch. Indeed, it needs some changes for ARCH=powerpc. Moreover, we have >> a different approach for the tasks. I'll be pleased to work with the >> bestcomm folks. >> > > So you preload the bestcomm task code in your boot loader? Yes. >Do those > of us using other bootloaders still have the option of loading the > task code later in linux? Well, just reading the phy address from 0xf008000 to 0xf00c0000 (if I remenber correctly) should be enough to get the tasks code. > What api are you using? Sylvain's proposed one based on Dale's with > some additions from me? Or have you come up with your own? > We implemented our own yet. However, we could moved to any. Regards, [-- Attachment #2: nd.vcf --] [-- Type: text/x-vcard, Size: 249 bytes --] begin:vcard fn:Nicolas DET ( bplan GmbH ) n:DET;Nicolas org:bplan GmbH adr:;;;;;;Germany email;internet:nd@bplan-gmbh.de title:Software Entwicklung tel;work:+49 6171 9187 - 31 x-mozilla-html:FALSE url:http://www.bplan-gmbh.de version:2.1 end:vcard ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:17 ` John Rigby 2006-10-26 17:23 ` Nicolas DET @ 2006-10-26 17:33 ` Sylvain Munaut 2006-10-27 3:03 ` Benjamin Herrenschmidt 2006-10-27 2:57 ` Benjamin Herrenschmidt 2 siblings, 1 reply; 40+ messages in thread From: Sylvain Munaut @ 2006-10-26 17:33 UTC (permalink / raw) To: John Rigby; +Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, sha John Rigby wrote: >> >> * mpc5k2_bestcomm.c (& helpers): I've been in contact with others people >> using bestcomm and please to see the development was still active. I'm >> already using latest code on my board but this is not include in this >> patch. Indeed, it needs some changes for ARCH=powerpc. Moreover, we have >> a different approach for the tasks. I'll be pleased to work with the >> bestcomm folks. >> > > So you preload the bestcomm task code in your boot loader? Do those > of us using other bootloaders still have the option of loading the > task code later in linux? > > What api are you using? Sylvain's proposed one based on Dale's with > some additions from me? Or have you come up with your own? > Hi John, I've sent him the latest API you describe. As for task preloading, I'm not too sure what Nicolas' plan is. I'm waiting to see what he's proposing. Since the bestcomm init is in a module, a different module could be implemented, (like bestcomm-chrp5k2.ko) that instead of clearing SRAM and doing everything from scrtch, would rely on the bootloader more. This would allow "custom" tasks to be marked as "don't touch". So if the bootloader want to load something that will not be altered by the linux driver (for whatever reason ...) However, for the tasks like FEC and ATA and everything supported in the kernel natively, I would still recommend reload the task code (anyway the driver is gonna reset the task and everything ...) Trying to reuse the microcode loaded by the bootloader is not a great idea IMHO. (Imagine, the fec driver is changed to use the latest microcode, but the bootloader is not ... both have to be in perfect sync ...) We would still have to compare the internal FDT and the preloaded one though since they have to match ... Sylvain ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:33 ` Sylvain Munaut @ 2006-10-27 3:03 ` Benjamin Herrenschmidt 0 siblings, 0 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-27 3:03 UTC (permalink / raw) To: Sylvain Munaut; +Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, sha > Since the bestcomm init is in a module, a different module could be > implemented, > (like bestcomm-chrp5k2.ko) that instead of clearing SRAM and doing > everything > from scrtch, would rely on the bootloader more. This would allow > "custom" tasks > to be marked as "don't touch". So if the bootloader want to load > something that > will not be altered by the linux driver (for whatever reason ...) I don't think we should have two different modules. We are talking here about arch/powerpc where the presence of a device-tree is mandatory. Thus, we should rely on that and define something based on that. In any case, I strongly think a single module with a single API should be able to deal with all the cases we need to define for loading the tasks. As I defined in a separate email, that includes wether the tasks are preloaded, provided as a blob in the device-tree (possibly via the zImage wrapper, and thus still in the kernel tree), or hard coded in the kernel driver (I don't like that solution though). It's mostly a matter on how the thing initializes anyway. Once it's up and running, the code path should be identical. > However, for the tasks like FEC and ATA and everything supported in the > kernel > natively, I would still recommend reload the task code (anyway the > driver is gonna > reset the task and everything ...) Trying to reuse the microcode loaded > by the > bootloader is not a great idea IMHO. (Imagine, the fec driver is changed > to use > the latest microcode, but the bootloader is not ... both have to be in > perfect sync ...) Is there some versionning available with the microcode ? I'm afraid there might not be (since that whole bestcomm business seems to be immune to good ideas from whoever design the whole chip), but that would be useful. I agree that having the task code coming from the firmware might not be the best idea if there is no versionning, but it nicely solves some of the problems related to distributing "binary blobs" ... I'm sure debian would have issues with bestcomm code shipped with the kernel.... If no versionning is available we might want to create one ourselves, via a wiki possibly and one person (you ?) responsible for distributing the "releases" and assigning them versions... At which point, the device-tree can contain version information along with the task code or pointers to the code in sram. > We would still have to compare the internal FDT and the preloaded one > though since > they have to match ... Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH] General CHRP/MPC5K2 platform support patch 2006-10-26 17:17 ` John Rigby 2006-10-26 17:23 ` Nicolas DET 2006-10-26 17:33 ` Sylvain Munaut @ 2006-10-27 2:57 ` Benjamin Herrenschmidt 2 siblings, 0 replies; 40+ messages in thread From: Benjamin Herrenschmidt @ 2006-10-27 2:57 UTC (permalink / raw) To: John Rigby; +Cc: akpm, linuxppc-embedded, sl, linuxppc-dev, sha On Thu, 2006-10-26 at 11:17 -0600, John Rigby wrote: > > > > * mpc5k2_bestcomm.c (& helpers): I've been in contact with others people > > using bestcomm and please to see the development was still active. I'm > > already using latest code on my board but this is not include in this > > patch. Indeed, it needs some changes for ARCH=powerpc. Moreover, we have > > a different approach for the tasks. I'll be pleased to work with the > > bestcomm folks. > > > > So you preload the bestcomm task code in your boot loader? Do those > of us using other bootloaders still have the option of loading the > task code later in linux? > > What api are you using? Sylvain's proposed one based on Dale's with > some additions from me? Or have you come up with your own? I think we need to look into 3 options for the bestcomm task code: - Preloaded by the firmware - In the device-tree but not preloaded - In the kernel Though we might want to completely dismiss the 3rd option and decide that it has to be in the device-tree, wether it's provided by the zImage wrapper, or by the firmware. Do you see any other case ? So we need to define the content of the various device nodes for those 3 cases. The 3rd case is easy: probably nothing to put there, purely an in-kernel thing, unless the bestcomm task IDs related to a given cell are always the same. The two first ones are similar, with the exception that the "blob" is in one case preloaded (thus we provide a property telling where it is in the sram) and in the other case, the blob is in the DT itself, thus we have a bit of "bootstrap" code that loads it. In both cases, tasks IDs are known and thus the device-tree might contain the necessary binding informations. Now, in any case, the "drivers" need a way to link to their respective "tasks". That is, the function drivers (FEC, ...) need to use functions provided by the "bestcomm" driver to setup and use tasks. In order to do that the function drivers need to provide enough information of course to allow the bestcomm to properly find out the tasks. That's why my idea is that we associate to "known" bestcomm tasks a name (a string), for example, "fec-tx" and "fec-rx" and the function drivers pass their device-node to the bestcomm drivers. The Bestcomm "driver" can then look into the device-tree node for a property "bestcomm-task-% s" where %s is the task "name", containing the task informations (ID, position in a table, whatever, I don't remember the details, it's up to you guys to define something). That property can then be in the device own node, in the bestcomm node, or absent in the case where the whole bestcom ucode is embedded in the kernel itself, in which case the driver has an internal table to resolve that, but I wonder if we shouldn't make madantory to at least have it in the device-tree and thus ignore that case 3... Ben. ^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2006-10-28 0:27 UTC | newest] Thread overview: 40+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-10-25 19:05 [PATCH] General CHRP/MPC5K2 platform support patch Nicolas DET 2006-10-25 21:59 ` Paul Mackerras 2006-10-25 22:41 ` Grant Likely 2006-10-25 22:59 ` Benjamin Herrenschmidt 2006-10-26 11:09 ` Nicolas DET 2006-10-26 11:17 ` Nicolas DET 2006-10-25 22:53 ` Benjamin Herrenschmidt 2006-10-26 11:09 ` Nicolas DET 2006-10-26 12:49 ` Benjamin Herrenschmidt 2006-10-26 12:59 ` Nicolas DET 2006-10-26 16:02 ` Grant Likely 2006-10-26 16:09 ` Grant Likely 2006-10-26 17:06 ` Nicolas DET 2006-10-26 17:54 ` Sylvain Munaut 2006-10-27 3:08 ` Benjamin Herrenschmidt 2006-10-26 19:14 ` Grant Likely 2006-10-26 19:21 ` Nicolas DET 2006-10-26 19:32 ` Nicolas DET 2006-10-27 2:49 ` Benjamin Herrenschmidt 2006-10-26 16:45 ` Sven Luther 2006-10-26 19:50 ` Nicolas DET 2006-10-26 20:00 ` Grant Likely 2006-10-26 20:51 ` Sylvain Munaut 2006-10-27 3:28 ` Benjamin Herrenschmidt 2006-10-27 14:52 ` Nicolas DET 2006-10-27 15:04 ` Nicolas DET 2006-10-27 17:08 ` Jon Loeliger 2006-10-28 0:27 ` Stephen Rothwell 2006-10-27 22:34 ` Benjamin Herrenschmidt 2006-10-27 22:05 ` Sylvain Munaut 2006-10-25 23:01 ` Grant Likely 2006-10-25 23:06 ` Benjamin Herrenschmidt 2006-10-25 23:13 ` Sven Luther 2006-10-26 12:09 ` Nicolas DET 2006-10-26 12:51 ` Benjamin Herrenschmidt 2006-10-26 17:17 ` John Rigby 2006-10-26 17:23 ` Nicolas DET 2006-10-26 17:33 ` Sylvain Munaut 2006-10-27 3:03 ` Benjamin Herrenschmidt 2006-10-27 2:57 ` Benjamin Herrenschmidt
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).