LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: 8xx spi completion sometime doesn't generate an interrupt
From: Wolfgang Denk @ 2006-06-03  0:51 UTC (permalink / raw)
  To: Antonio Di Bacco; +Cc: linuxppc-embedded
In-Reply-To: <200606030021.58892.antonio.dibacco@aruba.it>

In message <200606030021.58892.antonio.dibacco@aruba.it> you wrote:
>
> I lowered the SPI bus frequency, the interrupt is now always happening but I 
> have always problems.

Try reducing the CPM load. If you have a serial  console  on  a  SMC,
shut it off, etc. Then try again (usually it will be better).

> have to double check the writing procedure. But it is also worth to note that 
> changing the PM (prescaler module) and lowering the SPI clock even more the 
> writing problem is happening less frequently. 

Yeah. At a SPI clock of 0 no errors will happen. The problem is, that
this is not too much useful either ;-)

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Contrary to popular belief, thinking does not cause brain damage.

^ permalink raw reply

* Re: [PATCH] [2.6.18] U4 DART improvements
From: Olof Johansson @ 2006-06-03  3:28 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus
In-Reply-To: <1149295238.7972.12.camel@localhost.localdomain>

On Sat, Jun 03, 2006 at 10:40:38AM +1000, Benjamin Herrenschmidt wrote:

> In fact I doubt we need a barrier at all...

Yeah, I'm not sure what I was thinking. There's need for a barrier
before the invalidation to make sure that a stale entry doesn't get
re-entered into the TLB, and it's already done before the call. I have
no good explanation for why I added that one.

I'll respin, test and repost the patch tomorrow.


-Olof

^ permalink raw reply

* m25pe80 dataflash: put 50 usec between WREN and PW instructions
From: Antonio Di Bacco @ 2006-06-03  8:10 UTC (permalink / raw)
  To: linuxppc-embedded

I'm using a m25pe80 8Mbit spi dataflash. The PW (Page write) instruction is 
preceded by a WREN instruction but be careful to insert a delay between WREN 
and PW otherwise some page couldn't  be written. I hope could help someone.

Bye,
Antonio.

^ permalink raw reply

* Making Two ethernet interfaces up in Linux
From: Shantanu Nalage @ 2006-06-03 11:38 UTC (permalink / raw)
  To: linuxppc-embedded

Hi all,
         We are trying to port Linux on Xilinx Board XUPV2Pro which is
similar in most aspects to the Xilinx ML300 board. Linux is up and
running for the original board i.e. having only one ethrnet interface.
Now since we wanted to have the board working as router, we designed a
daughter board with two ethernet phy interfaces. The MACs required for
that are instantiated in Xilinx and corresponding Board support
Packages are also created in Xilinx.
        What all changes are required to make both the interfaces
visible in Linux?

Thank you in anticipation.

With regards,

Shantanu.

^ permalink raw reply

* Re: Making Two ethernet interfaces up in Linux
From: Antonio Di Bacco @ 2006-06-03 20:55 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Shantanu Nalage
In-Reply-To: <c91756f0606030438y62772d89ib43f613cd5373739@mail.gmail.com>

>          We are trying to port Linux on Xilinx Board XUPV2Pro which is
> similar in most aspects to the Xilinx ML300 board. Linux is up and
> running for the original board i.e. having only one ethrnet interface.
> Now since we wanted to have the board working as router, we designed a
> daughter board with two ethernet phy interfaces. The MACs required for
> that are instantiated in Xilinx ....

You have already the driver for the first MAC, then you should start from that 
modifying the init procedure for example and all the others. Your driver 
should initialize both the MACs and also create two devices calling 
init_etherdev tow times. If you post your driver I can suggest what to 
change. It is not so difficult. 

Bye,
Antonio.

^ permalink raw reply

* Re: [PATCH 2.6.16.16] sata_sil24: SII3124 sata driver endian problem
From: Alexey Dobriyan @ 2006-06-04 16:11 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Tejun Heo, linux-ide, linux-kernel, linuxppc-dev, jgarzik
In-Reply-To: <20060602163035.05ab7c71.akpm@osdl.org>

On Fri, Jun 02, 2006 at 04:30:35PM -0700, Andrew Morton wrote:
> > There is an endian issue in the sil24 driver.
> > The follwing pathc seems to fix it for me. (it is also attached in case
> > the mailer borks it for me)
> >
> > Signed-off-by: Rune Torgersen <runet@innovsys.com>
> >
> > Index: linux-innsys-2.6.16.16/drivers/scsi/sata_sil24.c
> > ===================================================================
> > --- linux-innsys-2.6.16.16/drivers/scsi/sata_sil24.c	(revision 101)
> > +++ linux-innsys-2.6.16.16/drivers/scsi/sata_sil24.c	(working copy)
> > @@ -446,7 +446,7 @@
> >  	 */
> >  	msleep(10);
> >
> > -	prb->ctrl = PRB_CTRL_SRST;
> > +	prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
> >  	prb->fis[1] = 0; /* no PM yet */
> >
> >  	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
> > @@ -537,9 +537,9 @@
> >
> >  		if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
> >  			if (qc->tf.flags & ATA_TFLAG_WRITE)
> > -				prb->ctrl = PRB_CTRL_PACKET_WRITE;
> > +				prb->ctrl =
> > cpu_to_le16(PRB_CTRL_PACKET_WRITE);
> >  			else
> > -				prb->ctrl = PRB_CTRL_PACKET_READ;
> > +				prb->ctrl =
> > cpu_to_le16(PRB_CTRL_PACKET_READ);

Are there some other fields that should be marked?

[PATCH] sata_sil24: endian annotations

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 drivers/scsi/sata_sil24.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -37,7 +37,7 @@
  * Port request block (PRB) 32 bytes
  */
 struct sil24_prb {
-	u16	ctrl;
+	__le16	ctrl;
 	u16	prot;
 	u32	rx_cnt;
 	u8	fis[6 * 4];
@@ -47,9 +47,9 @@ struct sil24_prb {
  * Scatter gather entry (SGE) 16 bytes
  */
 struct sil24_sge {
-	u64	addr;
-	u32	cnt;
-	u32	flags;
+	__le64	addr;
+	__le32	cnt;
+	__le32	flags;
 };
 
 /*

^ permalink raw reply

* Re: [PATCH 2.6.16.16] sata_sil24: SII3124 sata driver endian problem
From: Tejun Heo @ 2006-06-04 20:24 UTC (permalink / raw)
  To: Alexey Dobriyan
  Cc: Andrew Morton, linux-ide, linux-kernel, linuxppc-dev, jgarzik
In-Reply-To: <20060604161124.GA7587@martell.zuzino.mipt.ru>

Alexey Dobriyan wrote:
> Are there some other fields that should be marked?

Yeap, prot and rx_cnt of sil24_prb should also be marked __le.  Also, 
all fields of sil24_port_multiplier

Thanks.

> [PATCH] sata_sil24: endian annotations
> 
> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
> ---
> 
>  drivers/scsi/sata_sil24.c |   14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> --- a/drivers/scsi/sata_sil24.c
> +++ b/drivers/scsi/sata_sil24.c
> @@ -37,7 +37,7 @@
>   * Port request block (PRB) 32 bytes
>   */
>  struct sil24_prb {
> -	u16	ctrl;
> +	__le16	ctrl;
>  	u16	prot;
>  	u32	rx_cnt;
>  	u8	fis[6 * 4];
> @@ -47,9 +47,9 @@ struct sil24_prb {
>   * Scatter gather entry (SGE) 16 bytes
>   */
>  struct sil24_sge {
> -	u64	addr;
> -	u32	cnt;
> -	u32	flags;
> +	__le64	addr;
> +	__le32	cnt;
> +	__le32	flags;
>  };
>  
>  /*

-- 
tejun

^ permalink raw reply

* Re: snd-aoa: using feature calls for GPIOs
From: Benjamin Herrenschmidt @ 2006-06-05  3:11 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev list
In-Reply-To: <1149187342.7875.9.camel@johannes>


> Anyway, I'm sure I'm doing something stupid in there and just can't find
> it, I even 'disassembled' all the platform functions I have to see what
> happens in them, and they also write 0 or 1 just like the code below...
> Maybe I got some offsets wrong?

The platform function write bit 0 of the register only afaik. Bit 0x4 is
"output enable" so if you clear it, your GPIOs won't do much :)

Also, bit 0x2 is the input data, though it's only useful if "output
enable" is cleared (or it will just reflect the state of the outputs).

Forget about what snd-powermac does, it's bogus anyway.

Ben.

> --- snd-aoa.orig/aoa.h	2006-06-01 20:29:56.252070199 +0200
> +++ snd-aoa/aoa.h	2006-06-01 20:31:03.972070199 +0200
> @@ -125,6 +125,7 @@ extern int aoa_snd_ctl_add(struct snd_kc
>  
>  /* GPIO stuff */
>  extern struct gpio_methods *pmf_gpio_methods;
> +extern struct gpio_methods *ftr_gpio_methods;
>  /* extern struct gpio_methods *map_gpio_methods; */
>  
>  #endif /* __AOA_H */
> --- snd-aoa.orig/core/Makefile	2006-06-01 20:29:56.252070199 +0200
> +++ snd-aoa/core/Makefile	2006-06-01 20:31:03.972070199 +0200
> @@ -1,4 +1,5 @@
>  obj-$(CONFIG_SND_AOA) += snd-aoa.o
>  snd-aoa-objs := snd-aoa-core.o \
>  		snd-aoa-alsa.o \
> -		snd-aoa-gpio-pmf.o
> +		snd-aoa-gpio-pmf.o \
> +		snd-aoa-gpio-feature.o
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ snd-aoa/core/snd-aoa-gpio-feature.c	2006-06-01 20:31:03.992070199 +0200
> @@ -0,0 +1,322 @@
> +/*
> + * Apple Onboard Audio feature call GPIO control
> + *
> + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
> + *
> + * GPL v2, can be found in COPYING.
> + */
> +
> +#include <asm/pmac_feature.h>
> +#include <linux/interrupt.h>
> +#include "../aoa.h"
> +
> +static int headphone_mute_gpio;
> +static int amp_mute_gpio;
> +static int lineout_mute_gpio;
> +static int hw_reset_gpio;
> +static int lineout_detect_gpio;
> +static int headphone_detect_gpio;
> +static int linein_detect_gpio;
> +
> +static int headphone_mute_gpio_activestate;
> +static int amp_mute_gpio_activestate;
> +static int lineout_mute_gpio_activestate;
> +static int hw_reset_gpio_activestate;
> +static int lineout_detect_gpio_activestate;
> +static int headphone_detect_gpio_activestate;
> +static int linein_detect_gpio_activestate;
> +
> +static int lineout_detect_irq;
> +static int linein_detect_irq;
> +static int headphone_detect_irq;
> +
> +static void get_gpio(char *name, int *gpioptr, int *gpioactiveptr)
> +{
> +	struct device_node *np;
> +	u32 *reg;
> +
> +	*gpioptr = -1;
> +
> +	np = of_find_node_by_name(NULL, name);
> +	if (!np)
> +		return;
> +
> +	reg = (u32 *)get_property(np, "reg", NULL);
> +	if (!reg)
> +		return;
> +
> +	*gpioptr = *reg;
> +
> +	/* this is a hack, usually the GPIOs 'reg' property
> +	 * should have the offset based from the GPIO space
> +	 * which is at 0x50, but apparently not always... */
> +	if (*gpioptr < 0x50)
> +		*gpioptr += 0x50;
> +
> +	reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
> +	if (!reg)
> +		*gpioactiveptr = 1;
> +	else
> +		*gpioactiveptr = *reg;
> +
> +	printk(KERN_DEBUG "gpio %s = %d (active = %d)\n", name, *gpioptr, *gpioactiveptr);
> +}
> +
> +static void get_irq(char *name, int *irqptr)
> +{
> +	struct device_node *np;
> +
> +	*irqptr = -1;
> +	np = of_find_node_by_name(NULL, name);
> +	if (!np)
> +		return;
> +	if (np->n_intrs != 1)
> +		return;
> +	*irqptr = np->intrs[0].line;
> +
> +	printk(KERN_DEBUG "got %s irq = %d\n", name, *irqptr);
> +}
> +
> +#define SWITCH_GPIO(name, on)					\
> +	((on)?(name##_gpio_activestate==0?0:1):(name##_gpio_activestate==0?1:0))
> +
> +#define FTR_GPIO(name, bit)					\
> +static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\
> +{								\
> +	if (unlikely(!rt)) return;				\
> +								\
> +	if (name##_mute_gpio < 0)				\
> +		return;						\
> +								\
> +	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,		\
> +			  name##_mute_gpio,			\
> +			  SWITCH_GPIO(name##_mute, on));	\
> +								\
> +	rt->implementation_private &= ~(1<<bit);		\
> +	rt->implementation_private |= (!!on << bit);		\
> +}								\
> +static int ftr_gpio_get_##name(struct gpio_runtime *rt)		\
> +{								\
> +	if (unlikely(!rt)) return 0;				\
> +	return (rt->implementation_private>>bit)&1;		\
> +}
> +
> +FTR_GPIO(headphone, 0);
> +FTR_GPIO(amp, 1);
> +FTR_GPIO(lineout, 2);
> +
> +static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
> +{
> +	if (unlikely(!rt)) return;
> +	if (hw_reset_gpio < 0)
> +		return;
> +
> +	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
> +			  hw_reset_gpio, SWITCH_GPIO(hw_reset, on));
> +}
> +
> +static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
> +{
> +	int saved;
> +
> +	if (unlikely(!rt)) return;
> +	saved = rt->implementation_private;
> +	ftr_gpio_set_headphone(rt, 0);
> +	ftr_gpio_set_amp(rt, 0);
> +	ftr_gpio_set_lineout(rt, 0);
> +	rt->implementation_private = saved;
> +}
> +
> +static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
> +{
> +	int s;
> +
> +	if (unlikely(!rt)) return;
> +	s = rt->implementation_private;
> +	ftr_gpio_set_headphone(rt, (s>>0)&1);
> +	ftr_gpio_set_amp(rt, (s>>1)&1);
> +	ftr_gpio_set_lineout(rt, (s>>2)&1);
> +}
> +
> +static void ftr_handle_notify(void *data)
> +{
> +	struct gpio_notification *notif = data;
> +
> +	mutex_lock(&notif->mutex);
> +	if (notif->notify)
> +		notif->notify(notif->data);
> +	mutex_unlock(&notif->mutex);
> +}
> +
> +static void ftr_gpio_init(struct gpio_runtime *rt)
> +{
> +	get_gpio("headphone-mute", &headphone_mute_gpio,
> +				   &headphone_mute_gpio_activestate);
> +	get_gpio("amp-mute", &amp_mute_gpio,
> +			     &amp_mute_gpio_activestate);
> +	get_gpio("lineout-mute", &lineout_mute_gpio,
> +				 &lineout_mute_gpio_activestate);
> +	get_gpio("hw-reset", &hw_reset_gpio,
> +			     &hw_reset_gpio_activestate);
> +	get_gpio("headphone-detect", &headphone_detect_gpio,
> +				     &headphone_detect_gpio_activestate);
> +	get_gpio("lineout-detect", &lineout_detect_gpio,
> +				   &lineout_detect_gpio_activestate);
> +	get_gpio("linein-detect", &linein_detect_gpio,
> +				  &linein_detect_gpio_activestate);
> +
> +	get_irq("headphone-detect", &headphone_detect_irq);
> +	get_irq("lineout-detect", &lineout_detect_irq);
> +	get_irq("linein-detect", &linein_detect_irq);
> +
> +	ftr_gpio_all_amps_off(rt);
> +	rt->implementation_private = 0;
> +	INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify, &rt->headphone_notify);
> +	INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify, &rt->line_in_notify);
> +	INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify, &rt->line_out_notify);
> +	mutex_init(&rt->headphone_notify.mutex);
> +	mutex_init(&rt->line_in_notify.mutex);
> +	mutex_init(&rt->line_out_notify.mutex);
> +}
> +
> +static void ftr_gpio_exit(struct gpio_runtime *rt)
> +{
> +	ftr_gpio_all_amps_off(rt);
> +	rt->implementation_private = 0;
> +	if (rt->headphone_notify.notify)
> +		free_irq(headphone_detect_irq, &rt->headphone_notify);
> +	if (rt->line_in_notify.gpio_private)
> +		free_irq(linein_detect_irq, &rt->line_in_notify);
> +	if (rt->line_out_notify.gpio_private)
> +		free_irq(lineout_detect_irq, &rt->line_out_notify);
> +	cancel_delayed_work(&rt->headphone_notify.work);
> +	cancel_delayed_work(&rt->line_in_notify.work);
> +	cancel_delayed_work(&rt->line_out_notify.work);
> +	flush_scheduled_work();
> +	mutex_destroy(&rt->headphone_notify.mutex);
> +	mutex_destroy(&rt->line_in_notify.mutex);
> +	mutex_destroy(&rt->line_out_notify.mutex);
> +}
> +
> +irqreturn_t ftr_handle_notify_irq(int xx, void *data, struct pt_regs *regs)
> +{
> +	struct gpio_notification *notif = data;
> +
> +	schedule_work(&notif->work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int ftr_set_notify(struct gpio_runtime *rt,
> +			  enum notify_type type,
> +			  notify_func_t notify,
> +			  void *data)
> +{
> +	struct gpio_notification *notif;
> +	notify_func_t old;
> +	int irq;
> +	char *name;
> +	int err = -EBUSY;
> +
> +	switch (type) {
> +	case AOA_NOTIFY_HEADPHONE:
> +		notif = &rt->headphone_notify;
> +		name = "headphone-detect";
> +		irq = headphone_detect_irq;
> +		break;
> +	case AOA_NOTIFY_LINE_IN:
> +		notif = &rt->line_in_notify;
> +		name = "linein-detect";
> +		irq = linein_detect_irq;
> +		break;
> +	case AOA_NOTIFY_LINE_OUT:
> +		notif = &rt->line_out_notify;
> +		name = "lineout-detect";
> +		irq = lineout_detect_irq;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (irq == -1)
> +		return -ENODEV;
> +
> +	mutex_lock(&notif->mutex);
> +
> +	old = notif->notify;
> +
> +	if (!old && !notify) {
> +		err = 0;
> +		goto out_unlock;
> +	}
> +
> +	if (old && notify) {
> +		if (old == notify && notif->data == data)
> +			err = 0;
> +		goto out_unlock;
> +	}
> +
> +	if (old && !notify) {
> +		free_irq(irq, notif);
> +	}
> +	if (!old && notify) {
> +		request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
> +	}
> +	notif->notify = notify;
> +	notif->data = data;
> +
> +	err = 0;
> + out_unlock:
> +	mutex_unlock(&notif->mutex);
> +	return err;
> +}
> +
> +static int ftr_get_detect(struct gpio_runtime *rt,
> +			  enum notify_type type)
> +{
> +	int gpio, ret, active;
> +
> +	switch (type) {
> +	case AOA_NOTIFY_HEADPHONE:
> +		gpio = headphone_detect_gpio;
> +		active = headphone_detect_gpio_activestate;
> +		break;
> +	case AOA_NOTIFY_LINE_IN:
> +		gpio = linein_detect_gpio;
> +		active = linein_detect_gpio_activestate;
> +		break;
> +	case AOA_NOTIFY_LINE_OUT:
> +		gpio = lineout_detect_gpio;
> +		active = lineout_detect_gpio_activestate;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (gpio == -1)
> +		return -ENODEV;
> +
> +	ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
> +	if (ret < 0)
> +		return ret;
> +	return ((ret >> 1) & 1) == active;
> +}
> +
> +static struct gpio_methods methods = {
> +	.init			= ftr_gpio_init,
> +	.exit			= ftr_gpio_exit,
> +	.all_amps_off		= ftr_gpio_all_amps_off,
> +	.all_amps_restore	= ftr_gpio_all_amps_restore,
> +	.set_headphone		= ftr_gpio_set_headphone,
> +	.set_speakers		= ftr_gpio_set_amp,
> +	.set_lineout		= ftr_gpio_set_lineout,
> +	.set_hw_reset		= ftr_gpio_set_hw_reset,
> +	.get_headphone		= ftr_gpio_get_headphone,
> +	.get_speakers		= ftr_gpio_get_amp,
> +	.get_lineout		= ftr_gpio_get_lineout,
> +	.set_notify		= ftr_set_notify,
> +	.get_detect		= ftr_get_detect,
> +};
> +
> +struct gpio_methods *ftr_gpio_methods = &methods;
> +EXPORT_SYMBOL_GPL(ftr_gpio_methods);
> 

^ permalink raw reply

* Re: [PATCH/2.6.17-rc4 8/10]  Add  tsi108 8250 serial support
From: Russell King @ 2006-06-05 10:04 UTC (permalink / raw)
  To: Zang Roy-r61911
  Cc: Alexandre.Bounine, linux-kernel, linuxppc-dev list,
	Paul Mackerras, linux-serial, Yang Xin-Xin-r48390
In-Reply-To: <9FCDBA58F226D911B202000BDBAD46730626DE5A@zch01exm40.ap.freescale.net>

On Thu, May 18, 2006 at 12:00:43PM +0800, Zang Roy-r61911 wrote:
> 
> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: 2006???5???17??? 21:26
> To: Zang Roy-r61911
> Cc: Paul Mackerras; linuxppc-dev list; Alexandre.Bounine@tundra.com; Yang Xin-Xin-r48390
> Subject: Re: [PATCH/2.6.17-rc4 8/10] Add tsi108 8250 serial support
> 
> 
> 
> On May 17, 2006, at 5:14 AM, Zang Roy-r61911 wrote:
> 
> > This patch contains changes to the serial device driver specific  
> > for integrated
> > serial port in Tsi108 Host Bridge.

There's no explaination about why this is required.  What is the problem?
Which changes relate directly to this problem and which changes are
related to fixing some other issue not related to the errata?

Plus, every patch line is prefixed by "> "... patch doesn't like that.

> >
> > Signed-off-by: Alexandre Bounine <alexandreb@tundra.com>
> > Signed-off-by: Roy Zang	<tie-fei.zang@freescale.com>
> >
> >> From nobody Mon Sep 17 00:00:00 2001
> > From: roy zang <tie-fei.zang@freescale.com>
> > Date: Tue May 16 15:26:02 2006 +0800
> > Subject: [PATCH] Add tsi108 serial support
> 
> This patch needs to go to Russell King as uart/8250 driver maintainer.
> 
> - kumar
> 
> >
> > ---
> >
> >  drivers/serial/8250.c |   17 +++++++++++++++++
> >  1 files changed, 17 insertions(+), 0 deletions(-)
> >
> > 6cb950357e9970afa671d59f172dbc4b03f11560
> > diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
> > index bbf78aa..c12f516 100644
> > --- a/drivers/serial/8250.c
> > +++ b/drivers/serial/8250.c
> > @@ -723,7 +723,9 @@ static int broken_efr(struct uart_8250_p
> >  static void autoconfig_16550a(struct uart_8250_port *up)
> >  {
> >  	unsigned char status1, status2;
> > +#ifndef CONFIG_TSI108_BRIDGE
> >  	unsigned int iersave;
> > +#endif
> >
> >  	up->port.type = PORT_16550A;
> >  	up->capabilities |= UART_CAP_FIFO;
> > @@ -833,6 +835,7 @@ static void autoconfig_16550a(struct uar
> >  	 * trying to write and read a 1 just to make sure it's not
> >  	 * already a 1 and maybe locked there before we even start start.
> >  	 */
> > +#ifndef CONFIG_TSI108_BRIDGE
> >  	iersave = serial_in(up, UART_IER);
> >  	serial_outp(up, UART_IER, iersave & ~UART_IER_UUE);
> >  	if (!(serial_in(up, UART_IER) & UART_IER_UUE)) {
> > @@ -859,6 +862,7 @@ static void autoconfig_16550a(struct uar
> >  		DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
> >  	}
> >  	serial_outp(up, UART_IER, iersave);
> > +#endif
> >  }
> >
> >  /*
> > @@ -1348,7 +1352,12 @@ static irqreturn_t serial8250_interrupt(
> >
> >  		up = list_entry(l, struct uart_8250_port, list);
> >
> > +#ifdef CONFIG_TSI108_BRIDGE /* for TSI108_REV_Z1 errata U2 */
> > +		/* read IIR as part of 32-bit word */
> > +		iir = (in_be32((u32 *)(up->port.membase + UART_RX)) >> 8) & 0xff;
> > +#else
> >  		iir = serial_in(up, UART_IIR);
> > +#endif
> >  		if (!(iir & UART_IIR_NO_INT)) {
> >  			serial8250_handle_port(up, regs);
> >
> > @@ -1529,7 +1538,9 @@ static int serial8250_startup(struct uar
> >  {
> >  	struct uart_8250_port *up = (struct uart_8250_port *)port;
> >  	unsigned long flags;
> > +#ifndef CONFIG_TSI108_BRIDGE
> >  	unsigned char lsr, iir;
> > +#endif
> >  	int retval;
> >
> >  	up->capabilities = uart_config[up->port.type].flags;
> > @@ -1567,7 +1578,9 @@ #endif
> >  	 */
> >  	(void) serial_inp(up, UART_LSR);
> >  	(void) serial_inp(up, UART_RX);
> > +#ifndef CONFIG_TSI108_BRIDGE /* for TSI108_REV_Z1 errata U2 */
> >  	(void) serial_inp(up, UART_IIR);
> > +#endif
> >  	(void) serial_inp(up, UART_MSR);
> >
> >  	/*
> > @@ -1634,6 +1647,7 @@ #endif
> >
> >  	serial8250_set_mctrl(&up->port, up->port.mctrl);
> >
> > +#ifndef CONFIG_TSI108_BRIDGE
> >  	/*
> >  	 * Do a quick test to see if we receive an
> >  	 * interrupt when we enable the TX irq.
> > @@ -1652,6 +1666,7 @@ #endif
> >  	} else {
> >  		up->bugs &= ~UART_BUG_TXEN;
> >  	}
> > +#endif
> >
> >  	spin_unlock_irqrestore(&up->port.lock, flags);
> >
> > @@ -1678,7 +1693,9 @@ #endif
> >  	 */
> >  	(void) serial_inp(up, UART_LSR);
> >  	(void) serial_inp(up, UART_RX);
> > +#ifndef CONFIG_TSI108_BRIDGE /* for TSI108_REV_Z1 errata U2 */
> >  	(void) serial_inp(up, UART_IIR);
> > +#endif
> >  	(void) serial_inp(up, UART_MSR);
> >
> >  	return 0;
> > -- 
> > 1.3.0
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-dev

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply

* Re: snd-aoa: using feature calls for GPIOs
From: Johannes Berg @ 2006-06-05 12:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1149477113.8543.1.camel@localhost.localdomain>

[-- Attachment #1: Type: text/plain, Size: 557 bytes --]

On Mon, 2006-06-05 at 13:11 +1000, Benjamin Herrenschmidt wrote:

> The platform function write bit 0 of the register only afaik. Bit 0x4 is
> "output enable" so if you clear it, your GPIOs won't do much :)

Aha! Yes, I had read the code wrongly, I figured the pmfs only wrote but
in fact there's a read/mask too. Thanks :)

> Also, bit 0x2 is the input data, though it's only useful if "output
> enable" is cleared (or it will just reflect the state of the outputs).

Yeah ok, I'll change/retest the patch during the week.

Thanks,
johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]

^ permalink raw reply

* Re: [HACK] add sandpoint + flattened dt support to arch/powerpc/boot
From: Matthew McClintock @ 2006-06-05 20:41 UTC (permalink / raw)
  To: Tom Rini; +Cc: linuxppc-dev
In-Reply-To: <20060522222227.GR32112@smtp.west.cox.net>

On Mon, 2006-05-22 at 15:22 -0700, Tom Rini wrote:
> And on all architectures (practically) the zlib inflate code is shared
> between kernel and bootstuff.  So it's not unprecidented to do the
> ugly
> define abstractions to let you easily share code as needed. 

Could you point me at the code you are referring too?

Thanks,
Matthew

^ permalink raw reply

* Re: [HACK] add sandpoint + flattened dt support to arch/powerpc/boot
From: Tom Rini @ 2006-06-05 21:04 UTC (permalink / raw)
  To: Matthew McClintock; +Cc: linuxppc-dev
In-Reply-To: <1149540113.8317.93.camel@localhost.localdomain>

On Mon, Jun 05, 2006 at 03:41:53PM -0500, Matthew McClintock wrote:
> On Mon, 2006-05-22 at 15:22 -0700, Tom Rini wrote:
> > And on all architectures (practically) the zlib inflate code is shared
> > between kernel and bootstuff.  So it's not unprecidented to do the
> > ugly
> > define abstractions to let you easily share code as needed. 
> 
> Could you point me at the code you are referring too?

arch/powerpc/boot/Makefile
arch/ppc/boot/lib/Makefile
arch/xtensa/boot/lib/Makefile

And I could have sworn there were other arches (maybe in patches in
-mm?) that switched from lib/inflate.c to lib/zlib_inflate/

-- 
Tom Rini

^ permalink raw reply

* [PATCH] reorg RTAS delay code
From: John Rose @ 2006-06-05 21:31 UTC (permalink / raw)
  To: Nathan Lynch; +Cc: Paul Mackerras, External List
In-Reply-To: <20060602213308.GP8934@localdomain>

This patch attempts to handle RTAS "busy" return codes in a more simple
and consistent manner.  Typical callers of RTAS shouldn't have to
manage wait times and delay calls.

This patch also changes the kernel to use msleep() rather than udelay()
when a runtime delay is necessary.  This will avoid CPU soft lockups
for extended delay conditions.

Signed-off-by: John Rose <johnrose@austin.ibm.com>

---

Resend - added the suggested might_sleep() and braces.

Thanks-
John

 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c   |   30 +++----
 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c       |   85 ++++++++------------
 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c |   25 -----
 2_6_linus-johnrose/include/asm-powerpc/rtas.h       |    8 -
 4 files changed, 57 insertions(+), 91 deletions(-)

diff -puN arch/powerpc/kernel/rtas.c~rtas_delay_reorg arch/powerpc/kernel/rtas.c
--- 2_6_linus/arch/powerpc/kernel/rtas.c~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
+++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c	2006-06-05 15:00:03.000000000 -0500
@@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int 
 	return ret;
 }
 
-/* Given an RTAS status code of 990n compute the hinted delay of 10^n
- * (last digit) milliseconds.  For now we bound at n=5 (100 sec).
+/* For RTAS_BUSY (-2), delay for 1 millisecond.  For an extended busy status
+ * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
  */
-unsigned int rtas_extended_busy_delay_time(int status)
+unsigned int rtas_busy_delay_time(int status)
 {
-	int order = status - 9900;
-	unsigned long ms;
+	int order;
+	unsigned int ms = 0;
 
-	if (order < 0)
-		order = 0;	/* RTC depends on this for -2 clock busy */
-	else if (order > 5)
-		order = 5;	/* bound */
+	if (status == RTAS_BUSY) {
+		ms = 1;
+	} else if (status >= 9900 && status <= 9905) {
+		order = status - 9900;
+		for (ms = 1; order > 0; order--)
+			ms *= 10;
+	}
+
+	return ms;
+}
+
+/* For an RTAS busy status code, perform the hinted delay. */
+unsigned int rtas_busy_delay(int status)
+{
+	unsigned int ms;
 
-	/* Use microseconds for reasonable accuracy */
-	for (ms = 1; order > 0; order--)
-		ms *= 10;
+	might_sleep();
+	ms = rtas_busy_delay_time(status);
+	if (ms)
+		msleep(ms);
 
-	return ms; 
+	return ms;
 }
 
 int rtas_error_rc(int rtas_rc)
@@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain
 int rtas_set_power_level(int powerdomain, int level, int *setlevel)
 {
 	int token = rtas_token("set-power-level");
-	unsigned int wait_time;
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -ENOENT;
 
-	while (1) {
+	do {
 		rc = rtas_call(token, 2, 2, setlevel, powerdomain, level);
-		if (rc == RTAS_BUSY)
-			udelay(1);
-		else if (rtas_is_extended_busy(rc)) {
-			wait_time = rtas_extended_busy_delay_time(rc);
-			udelay(wait_time * 1000);
-		} else
-			break;
-	}
+	} while (rtas_busy_delay(rc));
 
 	if (rc < 0)
 		return rtas_error_rc(rc);
@@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain
 int rtas_get_sensor(int sensor, int index, int *state)
 {
 	int token = rtas_token("get-sensor-state");
-	unsigned int wait_time;
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -ENOENT;
 
-	while (1) {
+	do {
 		rc = rtas_call(token, 2, 2, state, sensor, index);
-		if (rc == RTAS_BUSY)
-			udelay(1);
-		else if (rtas_is_extended_busy(rc)) {
-			wait_time = rtas_extended_busy_delay_time(rc);
-			udelay(wait_time * 1000);
-		} else
-			break;
-	}
+	} while (rtas_busy_delay(rc));
 
 	if (rc < 0)
 		return rtas_error_rc(rc);
@@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int inde
 int rtas_set_indicator(int indicator, int index, int new_value)
 {
 	int token = rtas_token("set-indicator");
-	unsigned int wait_time;
 	int rc;
 
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -ENOENT;
 
-	while (1) {
+	do {
 		rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
-		if (rc == RTAS_BUSY)
-			udelay(1);
-		else if (rtas_is_extended_busy(rc)) {
-			wait_time = rtas_extended_busy_delay_time(rc);
-			udelay(wait_time * 1000);
-		}
-		else
-			break;
-	}
+	} while (rtas_busy_delay(rc));
 
 	if (rc < 0)
 		return rtas_error_rc(rc);
@@ -555,13 +542,11 @@ void rtas_os_term(char *str)
 	do {
 		status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL,
 				   __pa(rtas_os_term_buf));
+	} while (rtas_busy_delay(status));
 
-		if (status == RTAS_BUSY)
-			udelay(1);
-		else if (status != 0)
-			printk(KERN_EMERG "ibm,os-term call failed %d\n",
+	if (status != 0)
+		printk(KERN_EMERG "ibm,os-term call failed %d\n",
 			       status);
-	} while (status == RTAS_BUSY);
 }
 
 static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
@@ -789,7 +774,7 @@ EXPORT_SYMBOL(rtas_token);
 EXPORT_SYMBOL(rtas_call);
 EXPORT_SYMBOL(rtas_data_buf);
 EXPORT_SYMBOL(rtas_data_buf_lock);
-EXPORT_SYMBOL(rtas_extended_busy_delay_time);
+EXPORT_SYMBOL(rtas_busy_delay_time);
 EXPORT_SYMBOL(rtas_get_sensor);
 EXPORT_SYMBOL(rtas_get_power_level);
 EXPORT_SYMBOL(rtas_set_power_level);
diff -puN arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg arch/powerpc/kernel/rtas-rtc.c
--- 2_6_linus/arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
+++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c	2006-06-02 15:09:43.000000000 -0500
@@ -14,19 +14,20 @@
 unsigned long __init rtas_get_boot_time(void)
 {
 	int ret[8];
-	int error, wait_time;
+	int error;
+	unsigned int wait_time;
 	u64 max_wait_tb;
 
 	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
 	do {
 		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
-		if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
-			wait_time = rtas_extended_busy_delay_time(error);
+
+		wait_time = rtas_busy_delay_time(error);
+		if (wait_time) {
 			/* This is boot time so we spin. */
 			udelay(wait_time*1000);
-			error = RTAS_CLOCK_BUSY;
 		}
-	} while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+	} while (wait_time && (get_tb() < max_wait_tb));
 
 	if (error != 0 && printk_ratelimit()) {
 		printk(KERN_WARNING "error: reading the clock failed (%d)\n",
@@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time(
 void rtas_get_rtc_time(struct rtc_time *rtc_tm)
 {
         int ret[8];
-	int error, wait_time;
+	int error;
+	unsigned int wait_time;
 	u64 max_wait_tb;
 
 	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
 	do {
 		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
-		if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+
+		wait_time = rtas_busy_delay_time(error);
+		if (wait_time) {
 			if (in_interrupt() && printk_ratelimit()) {
 				memset(rtc_tm, 0, sizeof(struct rtc_time));
 				printk(KERN_WARNING "error: reading clock"
 				       " would delay interrupt\n");
 				return;	/* delay not allowed */
 			}
-			wait_time = rtas_extended_busy_delay_time(error);
 			msleep(wait_time);
-			error = RTAS_CLOCK_BUSY;
 		}
-	} while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+	} while (wait_time && (get_tb() < max_wait_tb));
 
         if (error != 0 && printk_ratelimit()) {
                 printk(KERN_WARNING "error: reading the clock failed (%d)\n",
@@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *t
 				  tm->tm_year + 1900, tm->tm_mon + 1,
 				  tm->tm_mday, tm->tm_hour, tm->tm_min,
 				  tm->tm_sec, 0);
-		if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+
+		wait_time = rtas_busy_delay_time(error);
+		if (wait_time) {
 			if (in_interrupt())
 				return 1;	/* probably decrementer */
-			wait_time = rtas_extended_busy_delay_time(error);
 			msleep(wait_time);
-			error = RTAS_CLOCK_BUSY;
 		}
-	} while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+	} while (wait_time && (get_tb() < max_wait_tb));
 
         if (error != 0 && printk_ratelimit())
                 printk(KERN_WARNING "error: setting the clock failed (%d)\n",
diff -puN include/asm-powerpc/rtas.h~rtas_delay_reorg include/asm-powerpc/rtas.h
--- 2_6_linus/include/asm-powerpc/rtas.h~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
+++ 2_6_linus-johnrose/include/asm-powerpc/rtas.h	2006-06-02 15:09:43.000000000 -0500
@@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time(
 extern void rtas_get_rtc_time(struct rtc_time *rtc_time);
 extern int rtas_set_rtc_time(struct rtc_time *rtc_time);
 
-/* Given an RTAS status code of 9900..9905 compute the hinted delay */
-unsigned int rtas_extended_busy_delay_time(int status);
-static inline int rtas_is_extended_busy(int status)
-{
-	return status >= 9900 && status <= 9909;
-}
+extern unsigned int rtas_busy_delay_time(int status);
+extern unsigned int rtas_busy_delay(int status);
 
 extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
 
diff -puN arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg arch/powerpc/kernel/rtas_flash.c
--- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
+++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c	2006-06-05 15:00:44.000000000 -0500
@@ -365,20 +365,12 @@ static int rtas_excl_release(struct inod
 
 static void manage_flash(struct rtas_manage_flash_t *args_buf)
 {
-	unsigned int wait_time;
 	s32 rc;
 
-	while (1) {
+	do {
 		rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 
 			       1, NULL, args_buf->op);
-		if (rc == RTAS_RC_BUSY)
-			udelay(1);
-		else if (rtas_is_extended_busy(rc)) {
-			wait_time = rtas_extended_busy_delay_time(rc);
-			udelay(wait_time * 1000);
-		} else
-			break;
-	}
+	} while (rtas_busy_delay(rc));
 
 	args_buf->status = rc;
 }
@@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct
 static void validate_flash(struct rtas_validate_flash_t *args_buf)
 {
 	int token = rtas_token("ibm,validate-flash-image");
-	unsigned int wait_time;
 	int update_results;
 	s32 rc;	
 
 	rc = 0;
-	while(1) {
+	do {
 		spin_lock(&rtas_data_buf_lock);
 		memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE);
 		rc = rtas_call(token, 2, 2, &update_results, 
 			       (u32) __pa(rtas_data_buf), args_buf->buf_size);
 		memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE);
 		spin_unlock(&rtas_data_buf_lock);
-			
-		if (rc == RTAS_RC_BUSY)
-			udelay(1);
-		else if (rtas_is_extended_busy(rc)) {
-			wait_time = rtas_extended_busy_delay_time(rc);
-			udelay(wait_time * 1000);
-		} else
-			break;
-	}
+	} while (rtas_busy_delay(rc));
 
 	args_buf->status = rc;
 	args_buf->update_results = update_results;

_

^ permalink raw reply

* RE: MPC85xx PCI transfer disconnect
From: Liu Dave-r63238 @ 2006-06-05 10:33 UTC (permalink / raw)
  To: 'Martin, Tim', linuxppc-embedded

 
> After scaning more logic analyzer captures, I noticed that 
> occasionally the MPC85xx inserts additional wait states (by 
> deasserting TRDY#) after only 32 bytes have been transferred. 
>  So it definitely appears that (the way I have things 
> configured now) there's a 20-80ns delay after 1 cache line is 
> read, and the MPC85xx disconnects transfers that are larger 
> than 2 cache lines.
> 

There is one description about MRM cmd in the MPC85xx user manual.
[Memory read multiple] 
Similar to the memory-read command, but also causes a
prefetch of the next cache line (32 bytes).

How many masters in your PCI system? 
Maybe, you can tune the master latency timer of Tsi148 to get more bandwidth.
The latecy timer is locate at configuration space of your master.

Dave

^ permalink raw reply

* Re: [PATCH] reorg RTAS delay code
From: Nathan Lynch @ 2006-06-05 21:54 UTC (permalink / raw)
  To: John Rose; +Cc: Paul Mackerras, External List
In-Reply-To: <1149543108.17307.6.camel@sinatra.austin.ibm.com>

John Rose wrote:
> This patch attempts to handle RTAS "busy" return codes in a more simple
> and consistent manner.  Typical callers of RTAS shouldn't have to
> manage wait times and delay calls.
> 
> This patch also changes the kernel to use msleep() rather than udelay()
> when a runtime delay is necessary.  This will avoid CPU soft lockups
> for extended delay conditions.
> 
> Signed-off-by: John Rose <johnrose@austin.ibm.com>
> 
> ---
> 
> Resend - added the suggested might_sleep() and braces.

FWIW:

Acked-by: Nathan Lynch <ntl@pobox.com>

>  2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c   |   30 +++----
>  2_6_linus-johnrose/arch/powerpc/kernel/rtas.c       |   85 ++++++++------------
>  2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c |   25 -----
>  2_6_linus-johnrose/include/asm-powerpc/rtas.h       |    8 -
>  4 files changed, 57 insertions(+), 91 deletions(-)
> 
> diff -puN arch/powerpc/kernel/rtas.c~rtas_delay_reorg arch/powerpc/kernel/rtas.c
> --- 2_6_linus/arch/powerpc/kernel/rtas.c~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
> +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c	2006-06-05 15:00:03.000000000 -0500
> @@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int 
>  	return ret;
>  }
>  
> -/* Given an RTAS status code of 990n compute the hinted delay of 10^n
> - * (last digit) milliseconds.  For now we bound at n=5 (100 sec).
> +/* For RTAS_BUSY (-2), delay for 1 millisecond.  For an extended busy status
> + * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
>   */
> -unsigned int rtas_extended_busy_delay_time(int status)
> +unsigned int rtas_busy_delay_time(int status)
>  {
> -	int order = status - 9900;
> -	unsigned long ms;
> +	int order;
> +	unsigned int ms = 0;
>  
> -	if (order < 0)
> -		order = 0;	/* RTC depends on this for -2 clock busy */
> -	else if (order > 5)
> -		order = 5;	/* bound */
> +	if (status == RTAS_BUSY) {
> +		ms = 1;
> +	} else if (status >= 9900 && status <= 9905) {
> +		order = status - 9900;
> +		for (ms = 1; order > 0; order--)
> +			ms *= 10;
> +	}
> +
> +	return ms;
> +}
> +
> +/* For an RTAS busy status code, perform the hinted delay. */
> +unsigned int rtas_busy_delay(int status)
> +{
> +	unsigned int ms;
>  
> -	/* Use microseconds for reasonable accuracy */
> -	for (ms = 1; order > 0; order--)
> -		ms *= 10;
> +	might_sleep();
> +	ms = rtas_busy_delay_time(status);
> +	if (ms)
> +		msleep(ms);
>  
> -	return ms; 
> +	return ms;
>  }
>  
>  int rtas_error_rc(int rtas_rc)
> @@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain
>  int rtas_set_power_level(int powerdomain, int level, int *setlevel)
>  {
>  	int token = rtas_token("set-power-level");
> -	unsigned int wait_time;
>  	int rc;
>  
>  	if (token == RTAS_UNKNOWN_SERVICE)
>  		return -ENOENT;
>  
> -	while (1) {
> +	do {
>  		rc = rtas_call(token, 2, 2, setlevel, powerdomain, level);
> -		if (rc == RTAS_BUSY)
> -			udelay(1);
> -		else if (rtas_is_extended_busy(rc)) {
> -			wait_time = rtas_extended_busy_delay_time(rc);
> -			udelay(wait_time * 1000);
> -		} else
> -			break;
> -	}
> +	} while (rtas_busy_delay(rc));
>  
>  	if (rc < 0)
>  		return rtas_error_rc(rc);
> @@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain
>  int rtas_get_sensor(int sensor, int index, int *state)
>  {
>  	int token = rtas_token("get-sensor-state");
> -	unsigned int wait_time;
>  	int rc;
>  
>  	if (token == RTAS_UNKNOWN_SERVICE)
>  		return -ENOENT;
>  
> -	while (1) {
> +	do {
>  		rc = rtas_call(token, 2, 2, state, sensor, index);
> -		if (rc == RTAS_BUSY)
> -			udelay(1);
> -		else if (rtas_is_extended_busy(rc)) {
> -			wait_time = rtas_extended_busy_delay_time(rc);
> -			udelay(wait_time * 1000);
> -		} else
> -			break;
> -	}
> +	} while (rtas_busy_delay(rc));
>  
>  	if (rc < 0)
>  		return rtas_error_rc(rc);
> @@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int inde
>  int rtas_set_indicator(int indicator, int index, int new_value)
>  {
>  	int token = rtas_token("set-indicator");
> -	unsigned int wait_time;
>  	int rc;
>  
>  	if (token == RTAS_UNKNOWN_SERVICE)
>  		return -ENOENT;
>  
> -	while (1) {
> +	do {
>  		rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
> -		if (rc == RTAS_BUSY)
> -			udelay(1);
> -		else if (rtas_is_extended_busy(rc)) {
> -			wait_time = rtas_extended_busy_delay_time(rc);
> -			udelay(wait_time * 1000);
> -		}
> -		else
> -			break;
> -	}
> +	} while (rtas_busy_delay(rc));
>  
>  	if (rc < 0)
>  		return rtas_error_rc(rc);
> @@ -555,13 +542,11 @@ void rtas_os_term(char *str)
>  	do {
>  		status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL,
>  				   __pa(rtas_os_term_buf));
> +	} while (rtas_busy_delay(status));
>  
> -		if (status == RTAS_BUSY)
> -			udelay(1);
> -		else if (status != 0)
> -			printk(KERN_EMERG "ibm,os-term call failed %d\n",
> +	if (status != 0)
> +		printk(KERN_EMERG "ibm,os-term call failed %d\n",
>  			       status);
> -	} while (status == RTAS_BUSY);
>  }
>  
>  static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
> @@ -789,7 +774,7 @@ EXPORT_SYMBOL(rtas_token);
>  EXPORT_SYMBOL(rtas_call);
>  EXPORT_SYMBOL(rtas_data_buf);
>  EXPORT_SYMBOL(rtas_data_buf_lock);
> -EXPORT_SYMBOL(rtas_extended_busy_delay_time);
> +EXPORT_SYMBOL(rtas_busy_delay_time);
>  EXPORT_SYMBOL(rtas_get_sensor);
>  EXPORT_SYMBOL(rtas_get_power_level);
>  EXPORT_SYMBOL(rtas_set_power_level);
> diff -puN arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg arch/powerpc/kernel/rtas-rtc.c
> --- 2_6_linus/arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
> +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c	2006-06-02 15:09:43.000000000 -0500
> @@ -14,19 +14,20 @@
>  unsigned long __init rtas_get_boot_time(void)
>  {
>  	int ret[8];
> -	int error, wait_time;
> +	int error;
> +	unsigned int wait_time;
>  	u64 max_wait_tb;
>  
>  	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
>  	do {
>  		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
> -		if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
> -			wait_time = rtas_extended_busy_delay_time(error);
> +
> +		wait_time = rtas_busy_delay_time(error);
> +		if (wait_time) {
>  			/* This is boot time so we spin. */
>  			udelay(wait_time*1000);
> -			error = RTAS_CLOCK_BUSY;
>  		}
> -	} while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
> +	} while (wait_time && (get_tb() < max_wait_tb));
>  
>  	if (error != 0 && printk_ratelimit()) {
>  		printk(KERN_WARNING "error: reading the clock failed (%d)\n",
> @@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time(
>  void rtas_get_rtc_time(struct rtc_time *rtc_tm)
>  {
>          int ret[8];
> -	int error, wait_time;
> +	int error;
> +	unsigned int wait_time;
>  	u64 max_wait_tb;
>  
>  	max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
>  	do {
>  		error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
> -		if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
> +
> +		wait_time = rtas_busy_delay_time(error);
> +		if (wait_time) {
>  			if (in_interrupt() && printk_ratelimit()) {











>  				memset(rtc_tm, 0, sizeof(struct rtc_time));
>  				printk(KERN_WARNING "error: reading clock"
>  				       " would delay interrupt\n");
>  				return;	/* delay not allowed */
>  			}
> -			wait_time = rtas_extended_busy_delay_time(error);
>  			msleep(wait_time);
> -			error = RTAS_CLOCK_BUSY;
>  		}
> -	} while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
> +	} while (wait_time && (get_tb() < max_wait_tb));
>  
>          if (error != 0 && printk_ratelimit()) {
>                  printk(KERN_WARNING "error: reading the clock failed (%d)\n",
> @@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *t
>  				  tm->tm_year + 1900, tm->tm_mon + 1,
>  				  tm->tm_mday, tm->tm_hour, tm->tm_min,
>  				  tm->tm_sec, 0);
> -		if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
> +
> +		wait_time = rtas_busy_delay_time(error);
> +		if (wait_time) {
>  			if (in_interrupt())
>  				return 1;	/* probably decrementer */
> -			wait_time = rtas_extended_busy_delay_time(error);
>  			msleep(wait_time);
> -			error = RTAS_CLOCK_BUSY;
>  		}
> -	} while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
> +	} while (wait_time && (get_tb() < max_wait_tb));
>  
>          if (error != 0 && printk_ratelimit())
>                  printk(KERN_WARNING "error: setting the clock failed (%d)\n",
> diff -puN include/asm-powerpc/rtas.h~rtas_delay_reorg include/asm-powerpc/rtas.h
> --- 2_6_linus/include/asm-powerpc/rtas.h~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
> +++ 2_6_linus-johnrose/include/asm-powerpc/rtas.h	2006-06-02 15:09:43.000000000 -0500
> @@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time(
>  extern void rtas_get_rtc_time(struct rtc_time *rtc_time);
>  extern int rtas_set_rtc_time(struct rtc_time *rtc_time);
>  
> -/* Given an RTAS status code of 9900..9905 compute the hinted delay */
> -unsigned int rtas_extended_busy_delay_time(int status);
> -static inline int rtas_is_extended_busy(int status)
> -{
> -	return status >= 9900 && status <= 9909;
> -}
> +extern unsigned int rtas_busy_delay_time(int status);
> +extern unsigned int rtas_busy_delay(int status);
>  
>  extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
>  
> diff -puN arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg arch/powerpc/kernel/rtas_flash.c
> --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg	2006-06-02 15:09:43.000000000 -0500
> +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c	2006-06-05 15:00:44.000000000 -0500
> @@ -365,20 +365,12 @@ static int rtas_excl_release(struct inod
>  
>  static void manage_flash(struct rtas_manage_flash_t *args_buf)
>  {
> -	unsigned int wait_time;
>  	s32 rc;
>  
> -	while (1) {
> +	do {
>  		rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 
>  			       1, NULL, args_buf->op);
> -		if (rc == RTAS_RC_BUSY)
> -			udelay(1);
> -		else if (rtas_is_extended_busy(rc)) {
> -			wait_time = rtas_extended_busy_delay_time(rc);
> -			udelay(wait_time * 1000);
> -		} else
> -			break;
> -	}
> +	} while (rtas_busy_delay(rc));
>  
>  	args_buf->status = rc;
>  }
> @@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct
>  static void validate_flash(struct rtas_validate_flash_t *args_buf)
>  {
>  	int token = rtas_token("ibm,validate-flash-image");
> -	unsigned int wait_time;
>  	int update_results;
>  	s32 rc;	
>  
>  	rc = 0;
> -	while(1) {
> +	do {
>  		spin_lock(&rtas_data_buf_lock);
>  		memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE);
>  		rc = rtas_call(token, 2, 2, &update_results, 
>  			       (u32) __pa(rtas_data_buf), args_buf->buf_size);
>  		memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE);
>  		spin_unlock(&rtas_data_buf_lock);
> -			
> -		if (rc == RTAS_RC_BUSY)
> -			udelay(1);
> -		else if (rtas_is_extended_busy(rc)) {
> -			wait_time = rtas_extended_busy_delay_time(rc);
> -			udelay(wait_time * 1000);
> -		} else
> -			break;
> -	}
> +	} while (rtas_busy_delay(rc));
>  
>  	args_buf->status = rc;
>  	args_buf->update_results = update_results;
> 
> _
> 
> 

^ permalink raw reply

* FW: process starvation with 2.6 scheduler
From: Kallol Biswas @ 2006-06-05 22:08 UTC (permalink / raw)
  To: linuxppc-dev



-----Original Message-----
From: Kallol Biswas 
Sent: Monday, June 05, 2006 2:30 PM
To: Kallol Biswas; linux-kernel@vger.kernel.org
Subject: RE: process starvation with 2.6 scheduler

I have checked the per processor run queue data structure (we have only one).

The active process is the in the queue list 118 of the of array[0] and the
starved process is the queue list 120 of the array[0]. The pointer, active points to array[0] and expired points to array[1].

-----Original Message-----
From: linux-kernel-owner@vger.kernel.org [mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of Kallol Biswas
Sent: Monday, June 05, 2006 1:47 PM
To: linux-kernel@vger.kernel.org
Subject: process starvation with 2.6 scheduler


From: Kallol Biswas 
Sent: Monday, June 05, 2006 12:49 PM
To: 'linux-kernel@vger.kernel.org'
Subject: process starvation with 2.6 scheduler

Hello,
       We have a process starvation problem with our 2.6.11 kernel running on a ppc-440 based system.

We have a storage SOC based on PPC-440. The SOC is emulated on a system emulator called Palladium. It is from Cadence. The system runs at 400KHz speed. It has three Ethernet ports; they are connected to outside lab network with a speed bridge.

The netperf server netserver runs on the emulated system (2.6.11 kernel on Palladium). There are netperf linux clients running on a x86 box.

If netperf request response (TCP_RR) traffic is run on all three ports; after sometime only one port remains active, the application (netperf client) on other two ports wait for a long time and eventually time out.

The netserver code has been instrumented. For one of the starved netserver processes it has been found that the TCP_RR request from the netperf client on linux x86 box has been received by the server, it has issued send() call to send back reply but send() never returns.

With an ICE connected to the Palladium (emulator) I have dumped the kernel data structures of the starved process and the active process. 


For Active  Process:
  Time_slice 84
  Policy : SCHED_NORMAL
  Dynamic priority: 118
  Static priority: 120
  Preempt_count: 0x20100
  Flags = 0
  State = 0 (TASK_RUNNING)

For Starved Process:
  Time slice: 77
  Policy: SCHED_NORMAL
  Dynamic priority: 120
  Static priority: 120
  Preempt_count: 0x10000000 (PREEMPT_ACTIVE is set)
  Flags = 0 
  State = 0 (TASK_RUNNING)



CONFIG_PREEMPT is not set.
The system has single CPU.


Any help to debug the problem is welcome. 

Kallol

^ permalink raw reply

* RE: process starvation with 2.6 scheduler
From: Kallol Biswas @ 2006-06-05 23:05 UTC (permalink / raw)
  To: linuxppc-dev

Some more information:

For the active process:
            Last_ran 0x190458787
            Timestamp: 0x190458787
For the starved process:
            Last_ran: 0x14dc18cfd
            Timestamp: 0x14dc18cfd

-----Original Message-----
From: Kallol Biswas 
Sent: Monday, June 05, 2006 3:09 PM
To: 'linuxppc-dev@ozlabs.org'
Subject: FW: process starvation with 2.6 scheduler



-----Original Message-----
From: Kallol Biswas 
Sent: Monday, June 05, 2006 2:30 PM
To: Kallol Biswas; linux-kernel@vger.kernel.org
Subject: RE: process starvation with 2.6 scheduler

I have checked the per processor run queue data structure (we have only one).

The active process is the in the queue list 118 of the of array[0] and the
starved process is the queue list 120 of the array[0]. The pointer, active points to array[0] and expired points to array[1].

-----Original Message-----
From: linux-kernel-owner@vger.kernel.org [mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of Kallol Biswas
Sent: Monday, June 05, 2006 1:47 PM
To: linux-kernel@vger.kernel.org
Subject: process starvation with 2.6 scheduler


From: Kallol Biswas 
Sent: Monday, June 05, 2006 12:49 PM
To: 'linux-kernel@vger.kernel.org'
Subject: process starvation with 2.6 scheduler

Hello,
       We have a process starvation problem with our 2.6.11 kernel running on a ppc-440 based system.

We have a storage SOC based on PPC-440. The SOC is emulated on a system emulator called Palladium. It is from Cadence. The system runs at 400KHz speed. It has three Ethernet ports; they are connected to outside lab network with a speed bridge.

The netperf server netserver runs on the emulated system (2.6.11 kernel on Palladium). There are netperf linux clients running on a x86 box.

If netperf request response (TCP_RR) traffic is run on all three ports; after sometime only one port remains active, the application (netperf client) on other two ports wait for a long time and eventually time out.

The netserver code has been instrumented. For one of the starved netserver processes it has been found that the TCP_RR request from the netperf client on linux x86 box has been received by the server, it has issued send() call to send back reply but send() never returns.

With an ICE connected to the Palladium (emulator) I have dumped the kernel data structures of the starved process and the active process. 


For Active  Process:
  Time_slice 84
  Policy : SCHED_NORMAL
  Dynamic priority: 118
  Static priority: 120
  Preempt_count: 0x20100
  Thread_info->flags = 0
  State = 0 (TASK_RUNNING)

For Starved Process:
  Time slice: 77
  Policy: SCHED_NORMAL
  Dynamic priority: 120
  Static priority: 120
  Preempt_count: 0x10000000 (PREEMPT_ACTIVE is set)
  Thread_info->flags = 0 
  State = 0 (TASK_RUNNING)



CONFIG_PREEMPT is not set.
The system has single CPU.


Any help to debug the problem is welcome. 

Kallol

^ permalink raw reply

* ppc85xx DMA
From: Naru Sundar @ 2006-06-06  0:55 UTC (permalink / raw)
  To: linuxppc-embedded

Dear sirs,

I am trying to add a DMA transfer component to my driver on linux 2.6 on a
ppc 8541.  Following the steps listed in the reference manual, I write the
SAR, SATR, DAR, DATR and BCR registers before cycling the bit in the MR
register to start the transfer.

The SR register though indicates a transfer error as soon as I write the
DAR register.  Clearly I've gotten the mapping wrong. I know what the
address I am trying to write to in kernel space is, what is unclear is
what address the DAR register is expecting.

Any help would be appreciated

-naru

^ permalink raw reply

* RE: ppc85xx DMA
From: Liu Dave-r63238 @ 2006-06-06  1:39 UTC (permalink / raw)
  To: 'Naru Sundar', linuxppc-embedded

> Dear sirs,
> 
> I am trying to add a DMA transfer component to my driver on 
> linux 2.6 on a ppc 8541.  Following the steps listed in the 
> reference manual, I write the SAR, SATR, DAR, DATR and BCR 
> registers before cycling the bit in the MR register to start 
> the transfer.
> 
What is the DMA transfer mode? Is direct or chaining mode?

> The SR register though indicates a transfer error as soon as 
> I write the DAR register.  Clearly I've gotten the mapping 
> wrong. I know what the address I am trying to write to in 
> kernel space is, what is unclear is what address the DAR 
> register is expecting.
> 

Did you ioremap the DMA register space?
The DAR register need the physical address

Dave

^ permalink raw reply

* Re: Making Two ethernet interfaces up in Linux
From: Andy Fleming @ 2006-06-05 15:12 UTC (permalink / raw)
  To: Antonio Di Bacco; +Cc: Shantanu Nalage, linuxppc-embedded
In-Reply-To: <200606032255.05997.antonio.dibacco@aruba.it>


On Jun 3, 2006, at 15:55, Antonio Di Bacco wrote:

>>          We are trying to port Linux on Xilinx Board XUPV2Pro  
>> which is
>> similar in most aspects to the Xilinx ML300 board. Linux is up and
>> running for the original board i.e. having only one ethrnet  
>> interface.
>> Now since we wanted to have the board working as router, we  
>> designed a
>> daughter board with two ethernet phy interfaces. The MACs required  
>> for
>> that are instantiated in Xilinx ....
>
> You have already the driver for the first MAC, then you should  
> start from that
> modifying the init procedure for example and all the others. Your  
> driver
> should initialize both the MACs and also create two devices calling
> init_etherdev tow times. If you post your driver I can suggest what to
> change. It is not so difficult.


Generally, it's better to modify the driver so it can be used to  
control any number of instances of the same ethernet hardware.  Then  
instantiate 2 (or how many you like) instances of the device, using  
the device layer (typically done in the board-specific code).

^ permalink raw reply

* Re: snd-aoa: using feature calls for GPIOs
From: Johannes Berg @ 2006-06-06  7:24 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1149477113.8543.1.camel@localhost.localdomain>

Here's a new patch. This one works for me if I invert the polarity of
the hw_reset GPIO, but that doesn't seem right to me. But maybe it
doesn't matter because the mini comes with explicit polarity indicators
in the device tree and we can see what happens there? I'll implement the
toonie codec in a bit.

johannes

--- snd-aoa.orig/aoa.h	2006-06-06 09:21:44.341828919 +0200
+++ snd-aoa/aoa.h	2006-06-06 09:22:08.341828919 +0200
@@ -125,6 +125,7 @@ extern int aoa_snd_ctl_add(struct snd_kc
 
 /* GPIO stuff */
 extern struct gpio_methods *pmf_gpio_methods;
+extern struct gpio_methods *ftr_gpio_methods;
 /* extern struct gpio_methods *map_gpio_methods; */
 
 #endif /* __AOA_H */
--- snd-aoa.orig/core/Makefile	2006-06-06 09:21:44.481828919 +0200
+++ snd-aoa/core/Makefile	2006-06-06 09:22:08.541828919 +0200
@@ -1,4 +1,5 @@
 obj-$(CONFIG_SND_AOA) += snd-aoa.o
 snd-aoa-objs := snd-aoa-core.o \
 		snd-aoa-alsa.o \
-		snd-aoa-gpio-pmf.o
+		snd-aoa-gpio-pmf.o \
+		snd-aoa-gpio-feature.o
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ snd-aoa/core/snd-aoa-gpio-feature.c	2006-06-06 09:22:08.581828919 +0200
@@ -0,0 +1,339 @@
+/*
+ * Apple Onboard Audio feature call GPIO control
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/pmac_feature.h>
+#include <linux/interrupt.h>
+#include "../aoa.h"
+
+static int headphone_mute_gpio;
+static int amp_mute_gpio;
+static int lineout_mute_gpio;
+static int hw_reset_gpio;
+static int lineout_detect_gpio;
+static int headphone_detect_gpio;
+static int linein_detect_gpio;
+
+static int headphone_mute_gpio_activestate;
+static int amp_mute_gpio_activestate;
+static int lineout_mute_gpio_activestate;
+static int hw_reset_gpio_activestate;
+static int lineout_detect_gpio_activestate;
+static int headphone_detect_gpio_activestate;
+static int linein_detect_gpio_activestate;
+
+static int lineout_detect_irq;
+static int linein_detect_irq;
+static int headphone_detect_irq;
+
+static void get_gpio(char *name, int *gpioptr, int *gpioactiveptr)
+{
+	struct device_node *np;
+	u32 *reg;
+
+	*gpioptr = -1;
+
+	np = of_find_node_by_name(NULL, name);
+	if (!np)
+		return;
+
+	reg = (u32 *)get_property(np, "reg", NULL);
+	if (!reg)
+		return;
+
+	*gpioptr = *reg;
+
+	/* this is a hack, usually the GPIOs 'reg' property
+	 * should have the offset based from the GPIO space
+	 * which is at 0x50, but apparently not always... */
+	if (*gpioptr < 0x50)
+		*gpioptr += 0x50;
+
+	reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+	if (!reg)
+		*gpioactiveptr = 1;
+	else
+		*gpioactiveptr = *reg;
+
+	printk(KERN_DEBUG "gpio %s = %d (active = %d)\n", name, *gpioptr, *gpioactiveptr);
+}
+
+static void get_irq(char *name, int *irqptr)
+{
+	struct device_node *np;
+
+	*irqptr = -1;
+	np = of_find_node_by_name(NULL, name);
+	if (!np)
+		return;
+	if (np->n_intrs != 1)
+		return;
+	*irqptr = np->intrs[0].line;
+
+	printk(KERN_DEBUG "got %s irq = %d\n", name, *irqptr);
+}
+
+#define SWITCH_GPIO(name, v, on)	\
+	(((v)&~1) | ((on)?(name##_gpio_activestate==0?4:5):(name##_gpio_activestate==0?5:4)))
+
+#define FTR_GPIO(name, bit)					\
+static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\
+{								\
+	int v;							\
+								\
+	if (unlikely(!rt)) return;				\
+								\
+	if (name##_mute_gpio < 0)				\
+		return;						\
+								\
+	v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,		\
+			  name##_mute_gpio,			\
+			  0);					\
+	printk(KERN_DEBUG "gpio " #name " is %x\n", v);		\
+								\
+	v = SWITCH_GPIO(name##_mute, v, on);			\
+	printk(KERN_DEBUG "writing %x to " #name " gpio\n", v);	\
+								\
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,		\
+			  name##_mute_gpio,			\
+			  SWITCH_GPIO(name##_mute, v, on));	\
+								\
+	rt->implementation_private &= ~(1<<bit);		\
+	rt->implementation_private |= (!!on << bit);		\
+}								\
+static int ftr_gpio_get_##name(struct gpio_runtime *rt)		\
+{								\
+	if (unlikely(!rt)) return 0;				\
+	return (rt->implementation_private>>bit)&1;		\
+}
+
+FTR_GPIO(headphone, 0);
+FTR_GPIO(amp, 1);
+FTR_GPIO(lineout, 2);
+
+static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
+{
+	int v;
+
+	if (unlikely(!rt)) return;
+	if (hw_reset_gpio < 0)
+		return;
+
+	v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,
+			  hw_reset_gpio, 0);
+	printk(KERN_DEBUG "hw_reset gpio is %x\n", v);
+	v = SWITCH_GPIO(hw_reset, v, on);
+	printk(KERN_DEBUG "writing %x to hw_reset gpio\n", v);
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
+			  hw_reset_gpio, v);
+}
+
+static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
+{
+	int saved;
+
+	if (unlikely(!rt)) return;
+	saved = rt->implementation_private;
+	ftr_gpio_set_headphone(rt, 0);
+	ftr_gpio_set_amp(rt, 0);
+	ftr_gpio_set_lineout(rt, 0);
+	rt->implementation_private = saved;
+}
+
+static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
+{
+	int s;
+
+	if (unlikely(!rt)) return;
+	s = rt->implementation_private;
+	ftr_gpio_set_headphone(rt, (s>>0)&1);
+	ftr_gpio_set_amp(rt, (s>>1)&1);
+	ftr_gpio_set_lineout(rt, (s>>2)&1);
+}
+
+static void ftr_handle_notify(void *data)
+{
+	struct gpio_notification *notif = data;
+
+	mutex_lock(&notif->mutex);
+	if (notif->notify)
+		notif->notify(notif->data);
+	mutex_unlock(&notif->mutex);
+}
+
+static void ftr_gpio_init(struct gpio_runtime *rt)
+{
+	get_gpio("headphone-mute", &headphone_mute_gpio,
+				   &headphone_mute_gpio_activestate);
+	get_gpio("amp-mute", &amp_mute_gpio,
+			     &amp_mute_gpio_activestate);
+	get_gpio("lineout-mute", &lineout_mute_gpio,
+				 &lineout_mute_gpio_activestate);
+	get_gpio("hw-reset", &hw_reset_gpio,
+			     &hw_reset_gpio_activestate);
+	get_gpio("headphone-detect", &headphone_detect_gpio,
+				     &headphone_detect_gpio_activestate);
+	get_gpio("lineout-detect", &lineout_detect_gpio,
+				   &lineout_detect_gpio_activestate);
+	get_gpio("linein-detect", &linein_detect_gpio,
+				  &linein_detect_gpio_activestate);
+
+	get_irq("headphone-detect", &headphone_detect_irq);
+	get_irq("lineout-detect", &lineout_detect_irq);
+	get_irq("linein-detect", &linein_detect_irq);
+
+	ftr_gpio_all_amps_off(rt);
+	rt->implementation_private = 0;
+	INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify, &rt->headphone_notify);
+	INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify, &rt->line_in_notify);
+	INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify, &rt->line_out_notify);
+	mutex_init(&rt->headphone_notify.mutex);
+	mutex_init(&rt->line_in_notify.mutex);
+	mutex_init(&rt->line_out_notify.mutex);
+}
+
+static void ftr_gpio_exit(struct gpio_runtime *rt)
+{
+	ftr_gpio_all_amps_off(rt);
+	rt->implementation_private = 0;
+	if (rt->headphone_notify.notify)
+		free_irq(headphone_detect_irq, &rt->headphone_notify);
+	if (rt->line_in_notify.gpio_private)
+		free_irq(linein_detect_irq, &rt->line_in_notify);
+	if (rt->line_out_notify.gpio_private)
+		free_irq(lineout_detect_irq, &rt->line_out_notify);
+	cancel_delayed_work(&rt->headphone_notify.work);
+	cancel_delayed_work(&rt->line_in_notify.work);
+	cancel_delayed_work(&rt->line_out_notify.work);
+	flush_scheduled_work();
+	mutex_destroy(&rt->headphone_notify.mutex);
+	mutex_destroy(&rt->line_in_notify.mutex);
+	mutex_destroy(&rt->line_out_notify.mutex);
+}
+
+irqreturn_t ftr_handle_notify_irq(int xx, void *data, struct pt_regs *regs)
+{
+	struct gpio_notification *notif = data;
+
+	schedule_work(&notif->work);
+
+	return IRQ_HANDLED;
+}
+
+static int ftr_set_notify(struct gpio_runtime *rt,
+			  enum notify_type type,
+			  notify_func_t notify,
+			  void *data)
+{
+	struct gpio_notification *notif;
+	notify_func_t old;
+	int irq;
+	char *name;
+	int err = -EBUSY;
+
+	switch (type) {
+	case AOA_NOTIFY_HEADPHONE:
+		notif = &rt->headphone_notify;
+		name = "headphone-detect";
+		irq = headphone_detect_irq;
+		break;
+	case AOA_NOTIFY_LINE_IN:
+		notif = &rt->line_in_notify;
+		name = "linein-detect";
+		irq = linein_detect_irq;
+		break;
+	case AOA_NOTIFY_LINE_OUT:
+		notif = &rt->line_out_notify;
+		name = "lineout-detect";
+		irq = lineout_detect_irq;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (irq == -1)
+		return -ENODEV;
+
+	mutex_lock(&notif->mutex);
+
+	old = notif->notify;
+
+	if (!old && !notify) {
+		err = 0;
+		goto out_unlock;
+	}
+
+	if (old && notify) {
+		if (old == notify && notif->data == data)
+			err = 0;
+		goto out_unlock;
+	}
+
+	if (old && !notify) {
+		free_irq(irq, notif);
+	}
+	if (!old && notify) {
+		request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
+	}
+	notif->notify = notify;
+	notif->data = data;
+
+	err = 0;
+ out_unlock:
+	mutex_unlock(&notif->mutex);
+	return err;
+}
+
+static int ftr_get_detect(struct gpio_runtime *rt,
+			  enum notify_type type)
+{
+	int gpio, ret, active;
+
+	switch (type) {
+	case AOA_NOTIFY_HEADPHONE:
+		gpio = headphone_detect_gpio;
+		active = headphone_detect_gpio_activestate;
+		break;
+	case AOA_NOTIFY_LINE_IN:
+		gpio = linein_detect_gpio;
+		active = linein_detect_gpio_activestate;
+		break;
+	case AOA_NOTIFY_LINE_OUT:
+		gpio = lineout_detect_gpio;
+		active = lineout_detect_gpio_activestate;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (gpio == -1)
+		return -ENODEV;
+
+	ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
+	if (ret < 0)
+		return ret;
+	return ((ret >> 1) & 1) == active;
+}
+
+static struct gpio_methods methods = {
+	.init			= ftr_gpio_init,
+	.exit			= ftr_gpio_exit,
+	.all_amps_off		= ftr_gpio_all_amps_off,
+	.all_amps_restore	= ftr_gpio_all_amps_restore,
+	.set_headphone		= ftr_gpio_set_headphone,
+	.set_speakers		= ftr_gpio_set_amp,
+	.set_lineout		= ftr_gpio_set_lineout,
+	.set_hw_reset		= ftr_gpio_set_hw_reset,
+	.get_headphone		= ftr_gpio_get_headphone,
+	.get_speakers		= ftr_gpio_get_amp,
+	.get_lineout		= ftr_gpio_get_lineout,
+	.set_notify		= ftr_set_notify,
+	.get_detect		= ftr_get_detect,
+};
+
+struct gpio_methods *ftr_gpio_methods = &methods;
+EXPORT_SYMBOL_GPL(ftr_gpio_methods);
--- snd-aoa.orig/fabrics/snd-aoa-fabric-layout.c	2006-06-06 09:22:13.251828919 +0200
+++ snd-aoa/fabrics/snd-aoa-fabric-layout.c	2006-06-06 09:22:17.051828919 +0200
@@ -749,7 +749,11 @@ static int aoa_fabric_layout_probe(struc
 	ldev->sound = sound;
 	ldev->layout = layout;
 	ldev->gpio.node = sound->parent;
-	ldev->gpio.methods = pmf_gpio_methods;
+	if (layout->layout_id == 58)
+		/* only on the Mac Mini ... */
+		ldev->gpio.methods = ftr_gpio_methods;
+	else
+		ldev->gpio.methods = pmf_gpio_methods;
 	ldev->selfptr_headphone.ptr = ldev;
 	ldev->selfptr_lineout.ptr = ldev;
 	sdev->ofdev.dev.driver_data = ldev;

^ permalink raw reply

* eth0: tx queue full
From: salvatore cusenza @ 2006-06-06  8:13 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 1238 bytes --]

At runtime during the usual life of my board (MPC852 and linux-2.4.20 Denk's
distribution)
 I have experienced the following crash:


eth0: tx queue full!.
eth0: tx queue full!.
eth0: tx queue full!.

Oops: kernel access of bad area, sig: 11
NIP: C000D440 XER: 00000000 LR: C00BB040 SP: C0C9BC10 REGS: c0c9bb60 TRAP:
0300    Tainted: P
MSR: 00009032 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11
DAR: 00001F9D, DSISR: 000000E4
TASK = c0c9a000[145] 'L5421' Last syscall: 4
last math 00000000 last altivec 00000000
GPR00: 00000000 C0C9BC10 C0C9A000 C0F56D70 00001F99 0000003C C0F56D6C
00000007
GPR08: 00000001 0000003C 00000000 C0F56DB0 C0D83C3C 10071D28 00000000
C3120000
GPR16: C311CB04 C311C8D8 C311C754 C0170000 C3120000 C311CB30 00000001
C0169DA0
GPR24: F0000E00 00001F9D C0F58400 0000003C 00000040 C2080100 C0F58200
C0F501B0
Call backtrace:
C00BAF8C C00BABC8 C0005848 C3119448 C31194C0 C31194F8 C00066F8
C0011A48 C00BA8FC C00CADD8 C00C3F00 C0016B50 C00AFE4C C00B4B94
C00B5EF4 C003571C C000457C 0FFD5E4C 0FEDB8DC 0FEDB284 1003B5B8
1003D558 1003A88C 0FED34A4 0FED32D0 0FFCFEE4 0FD5F590
Kernel panic: Aiee, killing interrupt handler!
In interrupt handler - not syncing
 <0>Rebooting in 180 seconds..


Could you suggest me something to investigate?

[-- Attachment #2: Type: text/html, Size: 1394 bytes --]

^ permalink raw reply

* Using RS232 Terminal as input device
From: hbruegge @ 2006-06-06  8:08 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 1104 bytes --]

Hi all


I am using the kernel (2.6.15) in an ppc-based embedded system through a 
serial console on ttyS0 with no problems.

Now I attached a graphic card to the system, which is correctly 
recognized and initialised by the Kernel. If I add "console=tty0 
console=ttyS0,57600" to the bootargs, I have the boot messages of the 
kernel on the screen and a login on the ttyS0.

What I now want to do is to disable the serial console and use the 
graphic card as output and the raw character data (ASCII) coming in from 
the terminal connected to the rs232 as input.

I have a login on the screen, if I delete the line console=ttyS0,57600 
from the bootargs, but unfortunately no input if a key is pressed on the 
terminal keyboard.


So my problem and question is, apart from not totally understanding the 
input device system of 2.6.x ;-)
Has anyone ever done that?
Is it just a kernel configuration problem? If so what modules have to be 
compiled in?
Are there any good documentaion about the new input device system ?

Basically I am totally confused ;-), so any ideas are appreciated.

Cheers

Harald

[-- Attachment #2: Type: text/html, Size: 1411 bytes --]

^ permalink raw reply

* Re: snd-aoa: using feature calls for GPIOs
From: Benjamin Herrenschmidt @ 2006-06-06  9:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev list
In-Reply-To: <1149578692.5928.6.camel@johannes.berg>

On Tue, 2006-06-06 at 09:24 +0200, Johannes Berg wrote:
> Here's a new patch. This one works for me if I invert the polarity of
> the hw_reset GPIO, but that doesn't seem right to me. But maybe it
> doesn't matter because the mini comes with explicit polarity indicators
> in the device tree and we can see what happens there? I'll implement the
> toonie codec in a bit.

I would say don't expect polarities to be any use when pmf are
available. That's why you get those explicit polarity infos on earlier
models. It's generally expected for a reset line to be active low (you
"assert" a reset by pulling it low to 0 and it's normally an open
collector with a pull-up to 5v. That's also why in general, reset lines
are never set to "1" but to "tristate" (or input mode for a GPIO) when
"released" but just do what darwin does there.

Ben.


> johannes
> 
> --- snd-aoa.orig/aoa.h	2006-06-06 09:21:44.341828919 +0200
> +++ snd-aoa/aoa.h	2006-06-06 09:22:08.341828919 +0200
> @@ -125,6 +125,7 @@ extern int aoa_snd_ctl_add(struct snd_kc
>  
>  /* GPIO stuff */
>  extern struct gpio_methods *pmf_gpio_methods;
> +extern struct gpio_methods *ftr_gpio_methods;
>  /* extern struct gpio_methods *map_gpio_methods; */
>  
>  #endif /* __AOA_H */
> --- snd-aoa.orig/core/Makefile	2006-06-06 09:21:44.481828919 +0200
> +++ snd-aoa/core/Makefile	2006-06-06 09:22:08.541828919 +0200
> @@ -1,4 +1,5 @@
>  obj-$(CONFIG_SND_AOA) += snd-aoa.o
>  snd-aoa-objs := snd-aoa-core.o \
>  		snd-aoa-alsa.o \
> -		snd-aoa-gpio-pmf.o
> +		snd-aoa-gpio-pmf.o \
> +		snd-aoa-gpio-feature.o
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ snd-aoa/core/snd-aoa-gpio-feature.c	2006-06-06 09:22:08.581828919 +0200
> @@ -0,0 +1,339 @@
> +/*
> + * Apple Onboard Audio feature call GPIO control
> + *
> + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
> + *
> + * GPL v2, can be found in COPYING.
> + */
> +
> +#include <asm/pmac_feature.h>
> +#include <linux/interrupt.h>
> +#include "../aoa.h"
> +
> +static int headphone_mute_gpio;
> +static int amp_mute_gpio;
> +static int lineout_mute_gpio;
> +static int hw_reset_gpio;
> +static int lineout_detect_gpio;
> +static int headphone_detect_gpio;
> +static int linein_detect_gpio;
> +
> +static int headphone_mute_gpio_activestate;
> +static int amp_mute_gpio_activestate;
> +static int lineout_mute_gpio_activestate;
> +static int hw_reset_gpio_activestate;
> +static int lineout_detect_gpio_activestate;
> +static int headphone_detect_gpio_activestate;
> +static int linein_detect_gpio_activestate;
> +
> +static int lineout_detect_irq;
> +static int linein_detect_irq;
> +static int headphone_detect_irq;
> +
> +static void get_gpio(char *name, int *gpioptr, int *gpioactiveptr)
> +{
> +	struct device_node *np;
> +	u32 *reg;
> +
> +	*gpioptr = -1;
> +
> +	np = of_find_node_by_name(NULL, name);
> +	if (!np)
> +		return;
> +
> +	reg = (u32 *)get_property(np, "reg", NULL);
> +	if (!reg)
> +		return;
> +
> +	*gpioptr = *reg;
> +
> +	/* this is a hack, usually the GPIOs 'reg' property
> +	 * should have the offset based from the GPIO space
> +	 * which is at 0x50, but apparently not always... */
> +	if (*gpioptr < 0x50)
> +		*gpioptr += 0x50;
> +
> +	reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
> +	if (!reg)
> +		*gpioactiveptr = 1;
> +	else
> +		*gpioactiveptr = *reg;
> +
> +	printk(KERN_DEBUG "gpio %s = %d (active = %d)\n", name, *gpioptr, *gpioactiveptr);
> +}
> +
> +static void get_irq(char *name, int *irqptr)
> +{
> +	struct device_node *np;
> +
> +	*irqptr = -1;
> +	np = of_find_node_by_name(NULL, name);
> +	if (!np)
> +		return;
> +	if (np->n_intrs != 1)
> +		return;
> +	*irqptr = np->intrs[0].line;
> +
> +	printk(KERN_DEBUG "got %s irq = %d\n", name, *irqptr);
> +}
> +
> +#define SWITCH_GPIO(name, v, on)	\
> +	(((v)&~1) | ((on)?(name##_gpio_activestate==0?4:5):(name##_gpio_activestate==0?5:4)))
> +
> +#define FTR_GPIO(name, bit)					\
> +static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\
> +{								\
> +	int v;							\
> +								\
> +	if (unlikely(!rt)) return;				\
> +								\
> +	if (name##_mute_gpio < 0)				\
> +		return;						\
> +								\
> +	v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,		\
> +			  name##_mute_gpio,			\
> +			  0);					\
> +	printk(KERN_DEBUG "gpio " #name " is %x\n", v);		\
> +								\
> +	v = SWITCH_GPIO(name##_mute, v, on);			\
> +	printk(KERN_DEBUG "writing %x to " #name " gpio\n", v);	\
> +								\
> +	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,		\
> +			  name##_mute_gpio,			\
> +			  SWITCH_GPIO(name##_mute, v, on));	\
> +								\
> +	rt->implementation_private &= ~(1<<bit);		\
> +	rt->implementation_private |= (!!on << bit);		\
> +}								\
> +static int ftr_gpio_get_##name(struct gpio_runtime *rt)		\
> +{								\
> +	if (unlikely(!rt)) return 0;				\
> +	return (rt->implementation_private>>bit)&1;		\
> +}
> +
> +FTR_GPIO(headphone, 0);
> +FTR_GPIO(amp, 1);
> +FTR_GPIO(lineout, 2);
> +
> +static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
> +{
> +	int v;
> +
> +	if (unlikely(!rt)) return;
> +	if (hw_reset_gpio < 0)
> +		return;
> +
> +	v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,
> +			  hw_reset_gpio, 0);
> +	printk(KERN_DEBUG "hw_reset gpio is %x\n", v);
> +	v = SWITCH_GPIO(hw_reset, v, on);
> +	printk(KERN_DEBUG "writing %x to hw_reset gpio\n", v);
> +	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
> +			  hw_reset_gpio, v);
> +}
> +
> +static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
> +{
> +	int saved;
> +
> +	if (unlikely(!rt)) return;
> +	saved = rt->implementation_private;
> +	ftr_gpio_set_headphone(rt, 0);
> +	ftr_gpio_set_amp(rt, 0);
> +	ftr_gpio_set_lineout(rt, 0);
> +	rt->implementation_private = saved;
> +}
> +
> +static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
> +{
> +	int s;
> +
> +	if (unlikely(!rt)) return;
> +	s = rt->implementation_private;
> +	ftr_gpio_set_headphone(rt, (s>>0)&1);
> +	ftr_gpio_set_amp(rt, (s>>1)&1);
> +	ftr_gpio_set_lineout(rt, (s>>2)&1);
> +}
> +
> +static void ftr_handle_notify(void *data)
> +{
> +	struct gpio_notification *notif = data;
> +
> +	mutex_lock(&notif->mutex);
> +	if (notif->notify)
> +		notif->notify(notif->data);
> +	mutex_unlock(&notif->mutex);
> +}
> +
> +static void ftr_gpio_init(struct gpio_runtime *rt)
> +{
> +	get_gpio("headphone-mute", &headphone_mute_gpio,
> +				   &headphone_mute_gpio_activestate);
> +	get_gpio("amp-mute", &amp_mute_gpio,
> +			     &amp_mute_gpio_activestate);
> +	get_gpio("lineout-mute", &lineout_mute_gpio,
> +				 &lineout_mute_gpio_activestate);
> +	get_gpio("hw-reset", &hw_reset_gpio,
> +			     &hw_reset_gpio_activestate);
> +	get_gpio("headphone-detect", &headphone_detect_gpio,
> +				     &headphone_detect_gpio_activestate);
> +	get_gpio("lineout-detect", &lineout_detect_gpio,
> +				   &lineout_detect_gpio_activestate);
> +	get_gpio("linein-detect", &linein_detect_gpio,
> +				  &linein_detect_gpio_activestate);
> +
> +	get_irq("headphone-detect", &headphone_detect_irq);
> +	get_irq("lineout-detect", &lineout_detect_irq);
> +	get_irq("linein-detect", &linein_detect_irq);
> +
> +	ftr_gpio_all_amps_off(rt);
> +	rt->implementation_private = 0;
> +	INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify, &rt->headphone_notify);
> +	INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify, &rt->line_in_notify);
> +	INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify, &rt->line_out_notify);
> +	mutex_init(&rt->headphone_notify.mutex);
> +	mutex_init(&rt->line_in_notify.mutex);
> +	mutex_init(&rt->line_out_notify.mutex);
> +}
> +
> +static void ftr_gpio_exit(struct gpio_runtime *rt)
> +{
> +	ftr_gpio_all_amps_off(rt);
> +	rt->implementation_private = 0;
> +	if (rt->headphone_notify.notify)
> +		free_irq(headphone_detect_irq, &rt->headphone_notify);
> +	if (rt->line_in_notify.gpio_private)
> +		free_irq(linein_detect_irq, &rt->line_in_notify);
> +	if (rt->line_out_notify.gpio_private)
> +		free_irq(lineout_detect_irq, &rt->line_out_notify);
> +	cancel_delayed_work(&rt->headphone_notify.work);
> +	cancel_delayed_work(&rt->line_in_notify.work);
> +	cancel_delayed_work(&rt->line_out_notify.work);
> +	flush_scheduled_work();
> +	mutex_destroy(&rt->headphone_notify.mutex);
> +	mutex_destroy(&rt->line_in_notify.mutex);
> +	mutex_destroy(&rt->line_out_notify.mutex);
> +}
> +
> +irqreturn_t ftr_handle_notify_irq(int xx, void *data, struct pt_regs *regs)
> +{
> +	struct gpio_notification *notif = data;
> +
> +	schedule_work(&notif->work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int ftr_set_notify(struct gpio_runtime *rt,
> +			  enum notify_type type,
> +			  notify_func_t notify,
> +			  void *data)
> +{
> +	struct gpio_notification *notif;
> +	notify_func_t old;
> +	int irq;
> +	char *name;
> +	int err = -EBUSY;
> +
> +	switch (type) {
> +	case AOA_NOTIFY_HEADPHONE:
> +		notif = &rt->headphone_notify;
> +		name = "headphone-detect";
> +		irq = headphone_detect_irq;
> +		break;
> +	case AOA_NOTIFY_LINE_IN:
> +		notif = &rt->line_in_notify;
> +		name = "linein-detect";
> +		irq = linein_detect_irq;
> +		break;
> +	case AOA_NOTIFY_LINE_OUT:
> +		notif = &rt->line_out_notify;
> +		name = "lineout-detect";
> +		irq = lineout_detect_irq;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (irq == -1)
> +		return -ENODEV;
> +
> +	mutex_lock(&notif->mutex);
> +
> +	old = notif->notify;
> +
> +	if (!old && !notify) {
> +		err = 0;
> +		goto out_unlock;
> +	}
> +
> +	if (old && notify) {
> +		if (old == notify && notif->data == data)
> +			err = 0;
> +		goto out_unlock;
> +	}
> +
> +	if (old && !notify) {
> +		free_irq(irq, notif);
> +	}
> +	if (!old && notify) {
> +		request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
> +	}
> +	notif->notify = notify;
> +	notif->data = data;
> +
> +	err = 0;
> + out_unlock:
> +	mutex_unlock(&notif->mutex);
> +	return err;
> +}
> +
> +static int ftr_get_detect(struct gpio_runtime *rt,
> +			  enum notify_type type)
> +{
> +	int gpio, ret, active;
> +
> +	switch (type) {
> +	case AOA_NOTIFY_HEADPHONE:
> +		gpio = headphone_detect_gpio;
> +		active = headphone_detect_gpio_activestate;
> +		break;
> +	case AOA_NOTIFY_LINE_IN:
> +		gpio = linein_detect_gpio;
> +		active = linein_detect_gpio_activestate;
> +		break;
> +	case AOA_NOTIFY_LINE_OUT:
> +		gpio = lineout_detect_gpio;
> +		active = lineout_detect_gpio_activestate;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (gpio == -1)
> +		return -ENODEV;
> +
> +	ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
> +	if (ret < 0)
> +		return ret;
> +	return ((ret >> 1) & 1) == active;
> +}
> +
> +static struct gpio_methods methods = {
> +	.init			= ftr_gpio_init,
> +	.exit			= ftr_gpio_exit,
> +	.all_amps_off		= ftr_gpio_all_amps_off,
> +	.all_amps_restore	= ftr_gpio_all_amps_restore,
> +	.set_headphone		= ftr_gpio_set_headphone,
> +	.set_speakers		= ftr_gpio_set_amp,
> +	.set_lineout		= ftr_gpio_set_lineout,
> +	.set_hw_reset		= ftr_gpio_set_hw_reset,
> +	.get_headphone		= ftr_gpio_get_headphone,
> +	.get_speakers		= ftr_gpio_get_amp,
> +	.get_lineout		= ftr_gpio_get_lineout,
> +	.set_notify		= ftr_set_notify,
> +	.get_detect		= ftr_get_detect,
> +};
> +
> +struct gpio_methods *ftr_gpio_methods = &methods;
> +EXPORT_SYMBOL_GPL(ftr_gpio_methods);
> --- snd-aoa.orig/fabrics/snd-aoa-fabric-layout.c	2006-06-06 09:22:13.251828919 +0200
> +++ snd-aoa/fabrics/snd-aoa-fabric-layout.c	2006-06-06 09:22:17.051828919 +0200
> @@ -749,7 +749,11 @@ static int aoa_fabric_layout_probe(struc
>  	ldev->sound = sound;
>  	ldev->layout = layout;
>  	ldev->gpio.node = sound->parent;
> -	ldev->gpio.methods = pmf_gpio_methods;
> +	if (layout->layout_id == 58)
> +		/* only on the Mac Mini ... */
> +		ldev->gpio.methods = ftr_gpio_methods;
> +	else
> +		ldev->gpio.methods = pmf_gpio_methods;
>  	ldev->selfptr_headphone.ptr = ldev;
>  	ldev->selfptr_lineout.ptr = ldev;
>  	sdev->ofdev.dev.driver_data = ldev;
> 

^ permalink raw reply

* RE: [PATCH/2.6.17-rc4 4/10]Powerpc:  Add tsi108 pic support
From: Zang Roy-r61911 @ 2006-06-06  9:43 UTC (permalink / raw)
  To: Alexandre Bounine, Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Paul Mackerras, Yang Xin-Xin-r48390

> The items 1 and 2 not needed. I moved them from the 
> tsi108_pic.c but really they have been leftovers from the old 
> code there. Originally code ppc/syslib/open_pic.c was used as 
> a template, which was good fit for the blocking output mode 
> of the tsi108 PIC (plus some extra tweaks). In that mode EOI 
> has to be signaled to PIC to deactivate interrupt line to the 
> CPU before it re-enables local interrupts. This is why we 
> have got ack routine. We changed mode later and removed most 
> of workarounds except these two.
> 
> I removed code for 1 and 2 and will send a patch to Roy after 
> retesting (probably this weekend with some other stuff).
> 
> Alex.
>               
> 
> On Thu, 2006-06-01 at 16:45 -0400, Alexandre Bounine wrote:
> > All differences in the Tsi108/109 PIC code from the 
> standard MPIC are caused by the HW behavior. The Tsi108/109 
> PIC looks like standard OpenPIC but, in fact, is different in 
> registers mapping and behavior. Its logic is close but not 
> exactly as MPIC.  
> > 
> > Here are replies on comments to the code:
> > 
> > 1.Why do you have to check if its a LEVEL irq?
> > 
> > Check for LEVEL irqs is required in the ack/end pair to 
> enable nested 
> > interrupt servicing and does not hang when core (local) 
> interrupts are 
> > re-enabled in the ISR. Otherwise we have to use 
> SA_INTERRUPT flag for all level signaled interrupts.
> 
> Can you be more precise about what exactly happens and why ? 
> Unless you EOI handling is broken of course, there should be 
> no need to do anything other than a single eoi in end(), period.
> 
> > 2. if the PIC works like other openpic's you dont need an 'ack' we 
> > handle it via 'end'
> > 
> > Tsi108/109 needs it.
> 
> What for ? Please, give the low level details.
> 
> > 3. why the changes to where we do mpic_eoi for TSI108?
> > The Tsi108 PIC requires EOI for spurious interrupt (as all 
> other interrupt sources).
> 
> Ok, that is acceptable.
> 
> > The do_IRQ() does not call end routine for spurious interrupts.  
> > 
> > The MPIC code patch for Tsi108/109 demonstrates HW 
> differences and why we originally considered having separate 
> code for Tsi108 pic.
> 
> Please tell me more about the HW differences :)
> 
> Ben.


Update Tsi108 implementation of MPIC.
Any comment? 

Integrate Tundra Semiconductor tsi108 host bridge interrupt controller 
to mpic arch.

Signed-off-by: Alexandre Bounine <alexandreb@tundra.com>
Signed-off-by: Roy Zang		<tie-fei.zang@freescale.com>

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 7e4d38e..d8a9add 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -408,7 +408,8 @@ config U3_DART
 	default n
 
 config MPIC
-	depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP
+	depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP \
+			       || MPC7448HPC2
 	bool
 	default y
 
diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig
index 28c7c8b..15a50f4 100644
--- a/arch/powerpc/configs/mpc7448_hpc2_defconfig
+++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.17-rc4
-# Tue May 23 11:29:48 2006
+# Sat May 27 18:45:55 2006
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -110,6 +110,7 @@ # CONFIG_PPC_MULTIPLATFORM is not set
 # CONFIG_PPC_ISERIES is not set
 CONFIG_EMBEDDED6xx=y
 # CONFIG_APUS is not set
+CONFIG_MPIC=y
 # CONFIG_PPC_RTAS is not set
 # CONFIG_MMIO_NVRAM is not set
 # CONFIG_PPC_MPC106 is not set
@@ -899,6 +900,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_FS is not set
 # CONFIG_UNWIND_INFO is not set
 # CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
 # CONFIG_PPC_EARLY_DEBUG_LPAR is not set
 # CONFIG_PPC_EARLY_DEBUG_G5 is not set
 # CONFIG_PPC_EARLY_DEBUG_RTAS is not set
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index e125ec6..2b78196 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -79,6 +79,7 @@ config MPC7448HPC2
 	select TSI108_BRIDGE
 	select DEFAULT_UIMAGE
 	select PPC_UDBG_16550
+	select MPIC
 	help
 	  Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
 	  platform
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index db5dc10..458f70d 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -43,7 +43,16 @@ #include <asm/pci-bridge.h>
 #include <asm/reg.h>
 #include <mm/mmu_decl.h>
 #include "mpc7448_hpc2.h"
-#include <asm/tsi108_pic.h>
+#include <asm/tsi108_irq.h>
+#include <asm/mpic.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
 
 #ifndef CONFIG_PCI
 isa_io_base = MPC7448_HPC2_ISA_IO_BASE;
@@ -53,20 +62,8 @@ #endif
 
 extern int add_bridge(struct device_node *dev);
 extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
-
-#ifdef TSI108_ETH
-hw_info hw_info_table[TSI108_ETH_MAX_PORTS + 1] = {
-	{TSI108_CSR_ADDR_PHYS + TSI108_ETH_OFFSET,
-	 TSI108_CSR_ADDR_PHYS + TSI108_ETH_OFFSET,
-	 TSI108_PHY0_ADDR, IRQ_TSI108_GIGE0},
-
-	{TSI108_CSR_ADDR_PHYS + TSI108_ETH_OFFSET + 0x400,
-	 TSI108_CSR_ADDR_PHYS + TSI108_ETH_OFFSET,
-	 TSI108_PHY1_ADDR, IRQ_TSI108_GIGE1},
-
-	{TBL_END, TBL_END, TBL_END, TBL_END}
-};
-#endif
+extern void tsi108_pci_int_init(void);
+extern int tsi108_irq_cascade(struct pt_regs *regs, void *unused);
 
 /*
  * Define all of the IRQ senses and polarities.  Taken from the
@@ -76,10 +73,32 @@ #endif
  */
 
 static u_char mpc7448_hpc2_pic_initsenses[] __initdata = {
+	/* External on-board sources */
 	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* INT[0] XINT0 from FPGA */
 	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* INT[1] XINT1 from FPGA */
 	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* INT[2] PHY_INT from both GIGE */
 	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* INT[3] RESERVED */
+	/* Internal Tsi108/109 interrupt sources */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Reserved IRQ */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Reserved IRQ */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Reserved IRQ */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Reserved IRQ */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* DMA0 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* DMA1 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* DMA2 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* DMA3 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* UART0 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* UART1 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* I2C */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* GPIO */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* GIGE0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* GIGE1 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Reserved IRQ */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* HLP */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* SDC */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Processor IF */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* Reserved IRQ */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* PCI/X block */
 };
 
 /*
@@ -196,18 +215,44 @@ #endif
  */
 static void __init mpc7448_hpc2_init_IRQ(void)
 {
+	struct mpic *mpic;
+	phys_addr_t mpic_paddr = 0;
+	struct device_node *tsi_pic;
+
+	tsi_pic = of_find_node_by_type(NULL, "open-pic");
+	if (tsi_pic) {
+		unsigned int size;
+		void *prop = get_property(tsi_pic, "reg", &size);
+		mpic_paddr = of_translate_address(tsi_pic, prop);
+	}
 
-	tsi108_pic_init(mpc7448_hpc2_pic_initsenses);
+	if (mpic_paddr == 0) {
+		printk("%s: No tsi108 PIC found !\n", __FUNCTION__);
+		return;
+	}
 
-	/* Configure MPIC outputs to CPU0 */
-	tsi108_pic_set_output(0, IRQ_SENSE_EDGE, IRQ_POLARITY_NEGATIVE);
-}
+	DBG("%s: tsi108pic phys_addr = 0x%x\n", __FUNCTION__,
+	    (u32) mpic_paddr);
 
-static void __init mpc7448_hpc2_map_io(void)
-{
-	/* Tsi108 CSR mapping */
-	io_block_mapping(TSI108_CSR_ADDR_VIRT, TSI108_CSR_ADDR_PHYS,
-			 0x100000, _PAGE_IO);
+	mpic = mpic_alloc(mpic_paddr,
+			MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+			MPIC_SPV_EOI | MPIC_CASC_NOEOI | 
+			MPIC_MOD_ID(MPIC_ID_TSI108),
+			0, /* num_sources used */
+			TSI108_IRQ_BASE,
+			0, /* num_sources used */
+			NR_IRQS - 4 /* XXXX */,
+			mpc7448_hpc2_pic_initsenses,
+			sizeof(mpc7448_hpc2_pic_initsenses), "Tsi108_PIC");
+
+	BUG_ON(mpic == NULL); /* XXXX */
+
+	mpic_init(mpic);
+	mpic_setup_cascade(IRQ_TSI108_PCI, tsi108_irq_cascade, mpic);
+	tsi108_pci_int_init();
+
+	/* Configure MPIC outputs to CPU0 */
+	tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
 }
 
 void mpc7448_hpc2_show_cpuinfo(struct seq_file *m)
@@ -269,10 +314,9 @@ define_machine(mpc7448_hpc2){
 	.setup_arch 		= mpc7448_hpc2_setup_arch,
 	.init_IRQ 		= mpc7448_hpc2_init_IRQ,
 	.show_cpuinfo 		= mpc7448_hpc2_show_cpuinfo,
-	.get_irq 		= tsi108_pic_get_irq,
+	.get_irq 		= mpic_get_irq,
 	.restart 		= mpc7448_hpc2_restart,
 	.calibrate_decr 	= generic_calibrate_decr,
-	.setup_io_mappings 	= mpc7448_hpc2_map_io,
 	.machine_check_exception= mpc7448_machine_check_exception,
 	.progress 		= udbg_progress,
 };
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 8c0afb7..048e1f6 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -8,4 +8,4 @@ obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_PPC_83xx)		+= ipic.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
-obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_common.o tsi108_pic.o
+obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_common.o tsi108_pci_int.o
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 7dcdfcb..09cb0eb 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -55,6 +55,78 @@ #define distribute_irqs	(0)
 #endif
 #endif
 
+static struct mpic_info mpic_infos[] = {
+	[0] = {	/* Original OpenPIC compatible MPIC */
+	.greg_base	= MPIC_GREG_BASE,
+	.greg_frr0	= MPIC_GREG_FEATURE_0,
+	.greg_config0	= MPIC_GREG_GLOBAL_CONF_0,
+	.greg_vendor_id	= MPIC_GREG_VENDOR_ID,
+	.greg_ipi_vp0	= MPIC_GREG_IPI_VECTOR_PRI_0,
+	.greg_ipi_stride	= MPIC_GREG_IPI_STRIDE,
+	.greg_spurious	= MPIC_GREG_SPURIOUS,
+	.greg_tfrr	= MPIC_GREG_TIMER_FREQ,
+
+	.timer_base	= MPIC_TIMER_BASE,
+	.timer_stride	= MPIC_TIMER_STRIDE,
+	.timer_ccr	= MPIC_TIMER_CURRENT_CNT,
+	.timer_bcr	= MPIC_TIMER_BASE_CNT,
+	.timer_vpr	= MPIC_TIMER_VECTOR_PRI,
+	.timer_dest	= MPIC_TIMER_DESTINATION,
+
+	.cpu_base	= MPIC_CPU_BASE,
+	.cpu_stride	= MPIC_CPU_STRIDE,
+	.cpu_ipi_disp0	= MPIC_CPU_IPI_DISPATCH_0,
+	.cpu_ipi_disp_stride	= MPIC_CPU_IPI_DISPATCH_STRIDE,
+	.cpu_task_pri	= MPIC_CPU_CURRENT_TASK_PRI,
+	.cpu_whoami	= MPIC_CPU_WHOAMI,
+	.cpu_intack	= MPIC_CPU_INTACK,
+	.cpu_eoi	= MPIC_CPU_EOI,
+
+	.irq_base	= MPIC_IRQ_BASE,
+	.irq_stride	= MPIC_IRQ_STRIDE,
+	.irq_vpr	= MPIC_IRQ_VECTOR_PRI,
+	.irq_vpr_vector	= MPIC_VECPRI_VECTOR_MASK,
+	.irq_vpr_polpos	= MPIC_VECPRI_POLARITY_POSITIVE,
+	.irq_vpr_senlvl	= MPIC_VECPRI_SENSE_LEVEL,
+	.irq_dest	= MPIC_IRQ_DESTINATION,
+	},
+
+	[1] = {	/* Tsi108/109 PIC */
+	.greg_base	= TSI108_GREG_BASE,
+	.greg_frr0	= TSI108_GREG_FEATURE_0,
+	.greg_config0	= TSI108_GREG_GLOBAL_CONF_0,
+	.greg_vendor_id	= TSI108_GREG_VENDOR_ID,
+	.greg_ipi_vp0	= TSI108_GREG_IPI_VECTOR_PRI_0,
+	.greg_ipi_stride	= TSI108_GREG_IPI_STRIDE,
+	.greg_spurious	= TSI108_GREG_SPURIOUS,
+	.greg_tfrr	= TSI108_GREG_TIMER_FREQ,
+
+	.timer_base	= TSI108_TIMER_BASE,
+	.timer_stride	= TSI108_TIMER_STRIDE,
+	.timer_ccr	= TSI108_TIMER_CURRENT_CNT,
+	.timer_bcr	= TSI108_TIMER_BASE_CNT,
+	.timer_vpr	= TSI108_TIMER_VECTOR_PRI,
+	.timer_dest	= TSI108_TIMER_DESTINATION,
+
+	.cpu_base	= TSI108_CPU_BASE,
+	.cpu_stride	= TSI108_CPU_STRIDE,
+	.cpu_ipi_disp0	= TSI108_CPU_IPI_DISPATCH_0,
+	.cpu_ipi_disp_stride	= TSI108_CPU_IPI_DISPATCH_STRIDE,
+	.cpu_task_pri	= TSI108_CPU_CURRENT_TASK_PRI,
+	.cpu_whoami	= 0xFFFFFFFF,
+	.cpu_intack	= TSI108_CPU_INTACK,
+	.cpu_eoi	= TSI108_CPU_EOI,
+
+	.irq_base	= TSI108_IRQ_REG_BASE,
+	.irq_stride	= TSI108_IRQ_STRIDE,
+	.irq_vpr	= TSI108_IRQ_VECTOR_PRI,
+	.irq_vpr_vector = TSI108_VECPRI_VECTOR_MASK,
+	.irq_vpr_polpos = TSI108_VECPRI_POLARITY_POSITIVE,
+	.irq_vpr_senlvl = TSI108_VECPRI_SENSE_LEVEL,
+	.irq_dest	= TSI108_IRQ_DESTINATION,
+	},
+};
+
 /*
  * Register accessor functions
  */
@@ -81,7 +153,8 @@ static inline void _mpic_write(unsigned 
 static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
 {
 	unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0;
-	unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+	unsigned int offset = mpic->hw_set->greg_ipi_vp0 +
+			      (ipi * mpic->hw_set->greg_ipi_stride);
 
 	if (mpic->flags & MPIC_BROKEN_IPI)
 		be = !be;
@@ -90,7 +163,8 @@ static inline u32 _mpic_ipi_read(struct 
 
 static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value)
 {
-	unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+	unsigned int offset = mpic->hw_set->greg_ipi_vp0 +
+			      (ipi * mpic->hw_set->greg_ipi_stride);
 
 	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value);
 }
@@ -121,7 +195,7 @@ static inline u32 _mpic_irq_read(struct 
 	unsigned int	idx = src_no & mpic->isu_mask;
 
 	return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
-			  reg + (idx * MPIC_IRQ_STRIDE));
+			  reg + (idx * mpic->hw_set->irq_stride));
 }
 
 static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
@@ -131,7 +205,7 @@ static inline void _mpic_irq_write(struc
 	unsigned int	idx = src_no & mpic->isu_mask;
 
 	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
-		    reg + (idx * MPIC_IRQ_STRIDE), value);
+		    reg + (idx * mpic->hw_set->irq_stride), value);
 }
 
 #define mpic_read(b,r)		_mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r))
@@ -157,8 +231,8 @@ static void __init mpic_test_broken_ipi(
 {
 	u32 r;
 
-	mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK);
-	r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0);
+	mpic_write(mpic->gregs, mpic->hw_set->greg_ipi_vp0, MPIC_VECPRI_MASK);
+	r = mpic_read(mpic->gregs, mpic->hw_set->greg_ipi_vp0);
 
 	if (r == le32_to_cpu(MPIC_VECPRI_MASK)) {
 		printk(KERN_INFO "mpic: Detected reversed IPI registers\n");
@@ -392,8 +466,8 @@ static inline struct mpic * mpic_from_ir
 /* Send an EOI */
 static inline void mpic_eoi(struct mpic *mpic)
 {
-	mpic_cpu_write(MPIC_CPU_EOI, 0);
-	(void)mpic_cpu_read(MPIC_CPU_WHOAMI);
+	mpic_cpu_write(mpic->hw_set->cpu_eoi, 0);
+	(void)mpic_cpu_read(mpic->hw_set->cpu_task_pri);
 }
 
 #ifdef CONFIG_SMP
@@ -419,8 +493,8 @@ static void mpic_enable_irq(unsigned int
 
 	DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 
-	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
-		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
+	mpic_irq_write(src, mpic->hw_set->irq_vpr,
+		       mpic_irq_read(src, mpic->hw_set->irq_vpr) &
 		       ~MPIC_VECPRI_MASK);
 
 	/* make sure mask gets to controller before we return to user */
@@ -429,7 +503,7 @@ static void mpic_enable_irq(unsigned int
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			break;
 		}
-	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);	
+	} while(mpic_irq_read(src, mpic->hw_set->irq_vpr) & MPIC_VECPRI_MASK);	
 
 #ifdef CONFIG_MPIC_BROKEN_U3
 	if (mpic->flags & MPIC_BROKEN_U3) {
@@ -466,8 +540,8 @@ static void mpic_disable_irq(unsigned in
 
 	DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
 
-	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
-		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
+	mpic_irq_write(src, mpic->hw_set->irq_vpr,
+		       mpic_irq_read(src, mpic->hw_set->irq_vpr) |
 		       MPIC_VECPRI_MASK);
 
 	/* make sure mask gets to controller before we return to user */
@@ -476,7 +550,7 @@ static void mpic_disable_irq(unsigned in
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			break;
 		}
-	} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
+	} while(!(mpic_irq_read(src, mpic->hw_set->irq_vpr) & MPIC_VECPRI_MASK));
 }
 
 static void mpic_shutdown_irq(unsigned int irq)
@@ -557,7 +631,7 @@ static void mpic_set_affinity(unsigned i
 
 	cpus_and(tmp, cpumask, cpu_online_map);
 
-	mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION,
+	mpic_irq_write(irq - mpic->irq_offset, mpic->hw_set->irq_dest,
 		       mpic_physmask(cpus_addr(tmp)[0]));	
 }
 
@@ -613,18 +687,20 @@ #endif /* CONFIG_SMP */
 	mpic->num_sources = 0; /* so far */
 	mpic->senses = senses;
 	mpic->senses_count = senses_count;
+	mpic->hw_set = &mpic_infos[MPIC_GET_MOD_ID(flags)];
 
 	/* Map the global registers */
-	mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000);
-	mpic->tmregs = mpic->gregs + ((MPIC_TIMER_BASE - MPIC_GREG_BASE) >> 2);
+	mpic->gregs = ioremap(phys_addr + mpic->hw_set->greg_base, 0x1000);
+	mpic->tmregs = mpic->gregs +
+		       ((mpic->hw_set->timer_base - mpic->hw_set->greg_base) >> 2);
 	BUG_ON(mpic->gregs == NULL);
 
 	/* Reset */
 	if (flags & MPIC_WANTS_RESET) {
-		mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
-			   mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+		mpic_write(mpic->gregs, mpic->hw_set->greg_config0,
+			   mpic_read(mpic->gregs, mpic->hw_set->greg_config0)
 			   | MPIC_GREG_GCONF_RESET);
-		while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+		while( mpic_read(mpic->gregs, mpic->hw_set->greg_config0)
 		       & MPIC_GREG_GCONF_RESET)
 			mb();
 	}
@@ -633,7 +709,7 @@ #endif /* CONFIG_SMP */
 	 * MPICs, num sources as well. On ISU MPICs, sources are counted
 	 * as ISUs are added
 	 */
-	reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0);
+	reg = mpic_read(mpic->gregs, mpic->hw_set->greg_frr0);
 	mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK)
 			  >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
 	if (isu_size == 0)
@@ -642,16 +718,16 @@ #endif /* CONFIG_SMP */
 
 	/* Map the per-CPU registers */
 	for (i = 0; i < mpic->num_cpus; i++) {
-		mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE +
-					   i * MPIC_CPU_STRIDE, 0x1000);
+		mpic->cpuregs[i] = ioremap(phys_addr + mpic->hw_set->cpu_base +
+					   i * mpic->hw_set->cpu_stride, 0x1000);
 		BUG_ON(mpic->cpuregs[i] == NULL);
 	}
 
 	/* Initialize main ISU if none provided */
 	if (mpic->isu_size == 0) {
 		mpic->isu_size = mpic->num_sources;
-		mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE,
-					MPIC_IRQ_STRIDE * mpic->isu_size);
+		mpic->isus[0] = ioremap(phys_addr + mpic->hw_set->irq_base,
+					mpic->hw_set->irq_stride * mpic->isu_size);
 		BUG_ON(mpic->isus[0] == NULL);
 	}
 	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
@@ -693,7 +769,8 @@ void __init mpic_assign_isu(struct mpic 
 
 	BUG_ON(isu_num >= MPIC_MAX_ISU);
 
-	mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE * mpic->isu_size);
+	mpic->isus[isu_num] = ioremap(phys_addr,
+				      mpic->hw_set->irq_stride * mpic->isu_size);
 	if ((isu_first + mpic->isu_size) > mpic->num_sources)
 		mpic->num_sources = isu_first + mpic->isu_size;
 }
@@ -729,14 +806,15 @@ void __init mpic_init(struct mpic *mpic)
 	printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources);
 
 	/* Set current processor priority to max */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+	mpic_cpu_write(mpic->hw_set->cpu_task_pri, 0xf);
 
 	/* Initialize timers: just disable them all */
 	for (i = 0; i < 4; i++) {
 		mpic_write(mpic->tmregs,
-			   i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0);
+			   i * mpic->hw_set->timer_stride +
+			   mpic->hw_set->timer_dest, 0);
 		mpic_write(mpic->tmregs,
-			   i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI,
+			   i * mpic->hw_set->timer_stride + mpic->hw_set->timer_vpr,
 			   MPIC_VECPRI_MASK |
 			   (MPIC_VEC_TIMER_0 + i));
 	}
@@ -780,14 +858,14 @@ #endif /* CONFIG_MPIC_BROKEN_U3 */
 		/* do senses munging */
 		if (mpic->senses && i < mpic->senses_count) {
 			if (mpic->senses[i] & IRQ_SENSE_LEVEL)
-				vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+				vecpri |= mpic->hw_set->irq_vpr_senlvl;
 			if (mpic->senses[i] & IRQ_POLARITY_POSITIVE)
-				vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+				vecpri |= mpic->hw_set->irq_vpr_polpos;
 		} else
-			vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+			vecpri |= mpic->hw_set->irq_vpr_senlvl;
 
 		/* remember if it was a level interrupts */
-		level = (vecpri & MPIC_VECPRI_SENSE_LEVEL);
+		level = (vecpri & mpic->hw_set->irq_vpr_senlvl);
 
 		/* deal with broken U3 */
 		if (mpic->flags & MPIC_BROKEN_U3) {
@@ -795,7 +873,7 @@ #ifdef CONFIG_MPIC_BROKEN_U3
 			if (mpic_is_ht_interrupt(mpic, i)) {
 				vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
 					    MPIC_VECPRI_POLARITY_MASK);
-				vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+				vecpri |= mpic->hw_set->irq_vpr_polpos;
 			}
 #else
 			printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n");
@@ -806,8 +884,8 @@ #endif
 		    (level != 0));
 
 		/* init hw */
-		mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
-		mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+		mpic_irq_write(i, mpic->hw_set->irq_vpr, vecpri);
+		mpic_irq_write(i, mpic->hw_set->irq_dest,
 			       1 << hard_smp_processor_id());
 
 		/* init linux descriptors */
@@ -818,15 +896,16 @@ #endif
 	}
 	
 	/* Init spurrious vector */
-	mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS);
+	mpic_write(mpic->gregs, mpic->hw_set->greg_spurious, MPIC_VEC_SPURRIOUS);
 
-	/* Disable 8259 passthrough */
-	mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
-		   mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
-		   | MPIC_GREG_GCONF_8259_PTHROU_DIS);
+	/* Disable 8259 passthrough, if supported */
+	if (MPIC_GET_MOD_ID(mpic->flags) != MPIC_ID_TSI108)
+		mpic_write(mpic->gregs, mpic->hw_set->greg_config0,
+			   mpic_read(mpic->gregs, mpic->hw_set->greg_config0)
+			   | MPIC_GREG_GCONF_8259_PTHROU_DIS);
 
 	/* Set current processor priority to 0 */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+	mpic_cpu_write(mpic->hw_set->cpu_task_pri, 0);
 }
 
 
@@ -845,9 +924,9 @@ void mpic_irq_set_priority(unsigned int 
 		mpic_ipi_write(irq - mpic->ipi_offset,
 			       reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
 	} else {
-		reg = mpic_irq_read(irq - mpic->irq_offset,MPIC_IRQ_VECTOR_PRI)
+		reg = mpic_irq_read(irq - mpic->irq_offset,mpic->hw_set->irq_vpr)
 			& ~MPIC_VECPRI_PRIORITY_MASK;
-		mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI,
+		mpic_irq_write(irq - mpic->irq_offset, mpic->hw_set->irq_vpr,
 			       reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
 	}
 	spin_unlock_irqrestore(&mpic_lock, flags);
@@ -864,7 +943,7 @@ unsigned int mpic_irq_get_priority(unsig
 	if (is_ipi)
 		reg = mpic_ipi_read(irq - mpic->ipi_offset);
 	else
-		reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI);
+		reg = mpic_irq_read(irq - mpic->irq_offset, mpic->hw_set->irq_vpr);
 	spin_unlock_irqrestore(&mpic_lock, flags);
 	return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT;
 }
@@ -890,12 +969,12 @@ #ifdef CONFIG_SMP
  	 */
 	if (distribute_irqs) {
 	 	for (i = 0; i < mpic->num_sources ; i++)
-			mpic_irq_write(i, MPIC_IRQ_DESTINATION,
-				mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk);
+			mpic_irq_write(i, mpic->hw_set->irq_dest,
+				mpic_irq_read(i, mpic->hw_set->irq_dest) | msk);
 	}
 
 	/* Set current processor priority to 0 */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+	mpic_cpu_write(mpic->hw_set->cpu_task_pri, 0);
 
 	spin_unlock_irqrestore(&mpic_lock, flags);
 #endif /* CONFIG_SMP */
@@ -905,7 +984,7 @@ int mpic_cpu_get_priority(void)
 {
 	struct mpic *mpic = mpic_primary;
 
-	return mpic_cpu_read(MPIC_CPU_CURRENT_TASK_PRI);
+	return mpic_cpu_read(mpic->hw_set->cpu_task_pri);
 }
 
 void mpic_cpu_set_priority(int prio)
@@ -913,7 +992,7 @@ void mpic_cpu_set_priority(int prio)
 	struct mpic *mpic = mpic_primary;
 
 	prio &= MPIC_CPU_TASKPRI_MASK;
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, prio);
+	mpic_cpu_write(mpic->hw_set->cpu_task_pri, prio);
 }
 
 /*
@@ -935,11 +1014,11 @@ void mpic_teardown_this_cpu(int secondar
 
 	/* let the mpic know we don't want intrs.  */
 	for (i = 0; i < mpic->num_sources ; i++)
-		mpic_irq_write(i, MPIC_IRQ_DESTINATION,
-			mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk);
+		mpic_irq_write(i, mpic->hw_set->irq_dest,
+			mpic_irq_read(i, mpic->hw_set->irq_dest) & ~msk);
 
 	/* Set current processor priority to max */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+	mpic_cpu_write(mpic->hw_set->cpu_task_pri, 0xf);
 
 	spin_unlock_irqrestore(&mpic_lock, flags);
 }
@@ -955,7 +1034,8 @@ #ifdef DEBUG_IPI
 	DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
 #endif
 
-	mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
+	mpic_cpu_write(mpic->hw_set->cpu_ipi_disp0 +
+		       ipi_no * mpic->hw_set->cpu_ipi_disp_stride,
 		       mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
 }
 
@@ -963,7 +1043,7 @@ int mpic_get_one_irq(struct mpic *mpic, 
 {
 	u32 irq;
 
-	irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+	irq = mpic_cpu_read(mpic->hw_set->cpu_intack) & mpic->hw_set->irq_vpr_vector;
 #ifdef DEBUG_LOW
 	DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
 #endif
@@ -972,11 +1052,18 @@ #ifdef DEBUG_LOW
 		DBG("%s: cascading ...\n", mpic->name);
 #endif
 		irq = mpic->cascade(regs, mpic->cascade_data);
-		mpic_eoi(mpic);
+#ifdef DEBUG_LOW
+		DBG("%s: cascaded irq: %d\n", mpic->name, irq);
+#endif
+		if (!(mpic->flags & MPIC_CASC_NOEOI))
+			mpic_eoi(mpic);
 		return irq;
 	}
-	if (unlikely(irq == MPIC_VEC_SPURRIOUS))
+	if (unlikely(irq == MPIC_VEC_SPURRIOUS)) {
+		if (mpic->flags & MPIC_SPV_EOI)
+			mpic_eoi(mpic);
 		return -1;
+	}
 	if (irq < MPIC_VEC_IPI_0) {
 #ifdef DEBUG_IRQ
 		DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index 6b9e781..6fa3427 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -37,6 +37,7 @@ #define MPIC_GREG_IPI_VECTOR_PRI_0	0x000
 #define MPIC_GREG_IPI_VECTOR_PRI_1	0x000b0
 #define MPIC_GREG_IPI_VECTOR_PRI_2	0x000c0
 #define MPIC_GREG_IPI_VECTOR_PRI_3	0x000d0
+#define MPIC_GREG_IPI_STRIDE		0x10
 #define MPIC_GREG_SPURIOUS		0x000e0
 #define MPIC_GREG_TIMER_FREQ		0x000f0
 
@@ -64,6 +65,7 @@ #define MPIC_CPU_IPI_DISPATCH_0		0x00040
 #define MPIC_CPU_IPI_DISPATCH_1		0x00050
 #define MPIC_CPU_IPI_DISPATCH_2		0x00060
 #define MPIC_CPU_IPI_DISPATCH_3		0x00070
+#define MPIC_CPU_IPI_DISPATCH_STRIDE	0x00010
 #define MPIC_CPU_CURRENT_TASK_PRI	0x00080
 #define 	MPIC_CPU_TASKPRI_MASK			0x0000000f
 #define MPIC_CPU_WHOAMI			0x00090
@@ -91,6 +93,55 @@ #define 	MPIC_VECPRI_SENSE_EDGE			0x0000
 #define 	MPIC_VECPRI_SENSE_MASK			0x00400000
 #define MPIC_IRQ_DESTINATION		0x00010
 
+/******************************************************************************
+ * Tsi108 implementation of MPIC has many differences form the original one
+ */
+
+/*
+ * Global registers
+ */
+
+#define TSI108_GREG_BASE		0x00000
+#define TSI108_GREG_FEATURE_0		0x00000
+#define TSI108_GREG_GLOBAL_CONF_0	0x00004
+#define TSI108_GREG_VENDOR_ID		0x0000c
+#define TSI108_GREG_IPI_VECTOR_PRI_0	0x00204		/* Doorbell 0 */
+#define TSI108_GREG_IPI_STRIDE		0x0c
+#define TSI108_GREG_SPURIOUS		0x00010
+#define TSI108_GREG_TIMER_FREQ		0x00014
+
+/*
+ * Timer registers
+ */
+#define TSI108_TIMER_BASE		0x0030
+#define TSI108_TIMER_STRIDE		0x10
+#define TSI108_TIMER_CURRENT_CNT	0x00000
+#define TSI108_TIMER_BASE_CNT		0x00004
+#define TSI108_TIMER_VECTOR_PRI		0x00008
+#define TSI108_TIMER_DESTINATION	0x0000c
+
+/*
+ * Per-Processor registers
+ */
+#define TSI108_CPU_BASE			0x00300
+#define TSI108_CPU_STRIDE		0x00040
+#define TSI108_CPU_IPI_DISPATCH_0	0x00200
+#define TSI108_CPU_IPI_DISPATCH_STRIDE	0x00000
+#define TSI108_CPU_CURRENT_TASK_PRI	0x00000
+#define TSI108_CPU_INTACK		0x00004
+#define TSI108_CPU_EOI			0x00008
+
+/*
+ * Per-source registers
+ */
+#define TSI108_IRQ_REG_BASE		0x00100
+#define TSI108_IRQ_STRIDE		0x00008
+#define TSI108_IRQ_VECTOR_PRI		0x00000
+#define 	TSI108_VECPRI_VECTOR_MASK		0x000000ff
+#define 	TSI108_VECPRI_POLARITY_POSITIVE		0x01000000
+#define 	TSI108_VECPRI_SENSE_LEVEL		0x02000000
+#define TSI108_IRQ_DESTINATION		0x00004
+
 #define MPIC_MAX_IRQ_SOURCES	2048
 #define MPIC_MAX_CPUS		32
 #define MPIC_MAX_ISU		32
@@ -124,6 +175,40 @@ struct mpic_irq_fixup
 };
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
+struct mpic_info {
+	u32	greg_base;	/* offset of global registers from MPIC base */
+	u32	greg_frr0;	/* FRR0 offset from base */
+	u32	greg_config0;	/* Global Config register offset from base */
+	u32	greg_vendor_id;	/* VID register offset from base */
+	u32	greg_ipi_vp0;	/* IPI Vector/Priority Registers */
+	u32	greg_ipi_stride; /* IPI Vector/Priority Registers spacing */
+	u32	greg_spurious;	/* Spurious Vector Register */
+	u32	greg_tfrr;	/* Global Timer Frequency Reporting Register */
+
+	u32	timer_base;	/* Global Timer Registers base */
+	u32	timer_stride;	/* Global Timer Registers spacing */
+	u32	timer_ccr;	/* Global Timer Current Count Register */
+	u32	timer_bcr;	/* Global Timer Base Count Register */
+	u32	timer_vpr;	/* Global Timer Vector/Priority Register */
+	u32	timer_dest;	/* Global Timer Destination Register */
+
+	u32	cpu_base;	/* Global Timer Destination Register */
+	u32	cpu_stride;	/* Global Timer Destination Register */
+	u32	cpu_ipi_disp0;	/* IPI 0 Dispatch Command Register */
+	u32	cpu_ipi_disp_stride;	/* IPI Dispatch spacing */
+	u32	cpu_task_pri;	/* Processor Current Task Priority Register */
+	u32	cpu_whoami;	/* Who Am I Register */
+	u32	cpu_intack;	/* Interrupt Acknowledge Register */
+	u32	cpu_eoi;	/* End of Interrupt Register */
+
+	u32	irq_base;	/* Interrupt registers base */
+	u32	irq_stride;	/* Interrupt registers spacing */
+	u32	irq_vpr;	/* Interrupt Vector/Priority Register */
+	u32	irq_vpr_vector;	/* Interrupt Vector Mask */
+	u32	irq_vpr_polpos;	/* Interrupt Positive Polarity bit */
+	u32	irq_vpr_senlvl;	/* Interrupt Level Sense bit */
+	u32	irq_dest;	/* Interrupt Destination Register */
+};
 
 /* The instance data of a given MPIC */
 struct mpic
@@ -168,6 +253,8 @@ #endif
 	volatile u32 __iomem	*tmregs;
 	volatile u32 __iomem	*cpuregs[MPIC_MAX_CPUS];
 	volatile u32 __iomem	*isus[MPIC_MAX_ISU];
+	/* Pointer to HW info structure */
+	struct mpic_info	*hw_set;
 
 	/* link */
 	struct mpic		*next;
@@ -186,6 +273,16 @@ #define MPIC_BROKEN_U3			0x00000004
 #define MPIC_BROKEN_IPI			0x00000008
 /* MPIC wants a reset */
 #define MPIC_WANTS_RESET		0x00000010
+/* Spurious vector requires EOI */
+#define MPIC_SPV_EOI			0x00000020
+/* No EOI for cascaded interrupt */
+#define MPIC_CASC_NOEOI			0x00000040
+/* MPIC HW modification ID */
+#define MPIC_MOD_ID_MASK		0x00000f00
+#define MPIC_MOD_ID(val)		(((val) << 8) & MPIC_MOD_ID_MASK)
+#define MPIC_GET_MOD_ID(flags)		(((flags) & MPIC_MOD_ID_MASK) >> 8)
+#define		MPIC_ID_MPIC		0	/* Original MPIC */
+#define		MPIC_ID_TSI108		1	/* Tsi108/109 PIC */
 
 /* Allocate the controller structure and setup the linux irq descs
  * for the range if interrupts passed in. No HW initialization is

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox