Linux MIPS Architecture development
 help / color / mirror / Atom feed
* [PATCH 1/1] MIPS: Fix "max_mapnr" assignment bug
From: Williams, Victor L. @ 2008-08-13 19:21 UTC (permalink / raw)
  To: linux-mips

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

Fix "max_mapnr" assignment bug for high-memory enabled kernels running
on
platforms with no high memory

Currently, high memory enabled kernels always set "max_mapnr" equal to
"highend_pfn", but "highend_pfn" is only valid if high memory is
available on
the platform.  The proposed fix is to only use "highend_pfn" in the
assignment
when it is valid (non-zero).  In my particular case, this bug was
manifesting
itself via the "pfn_valid()" macro, with "CONFIG_FLATMEM" defined.

Signed-off-by: Victor Williams <williavi@cisco.com>
Signed-off-by: Sudharsan Vijayaraghavan <vijayas@cisco.com>
---

 init.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- old/arch/mips/mm/init.c     2008-08-06 11:19:01.000000000 -0500
+++ new/arch/mips/mm/init.c     2008-08-13 11:17:03.000000000 -0500
@@ -388,13 +388,13 @@
        unsigned long codesize, reservedpages, datasize, initsize;
        unsigned long tmp, ram;

+       max_mapnr = max_low_pfn;
 #ifdef CONFIG_HIGHMEM
 #ifdef CONFIG_DISCONTIGMEM
 #error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet"
 #endif
-       max_mapnr = highend_pfn;
-#else
-       max_mapnr = max_low_pfn;
+       if (highend_pfn)
+          max_mapnr = highend_pfn;
 #endif
        high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);





     - - - - -                              Cisco                            - - - - -
This e-mail and any attachments may contain information which is confidential,
proprietary, privileged or otherwise protected by law. The information is solely
intended for the named addressee (or a person responsible for delivering it to
the addressee). If you are not the intended recipient of this message, you are
not authorized to read, print, retain, copy or disseminate this message or any
part of it. If you have received this e-mail in error, please notify the sender
immediately by return e-mail and delete it from your computer.

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

^ permalink raw reply

* Re: Debugging the MIPS processor using GDB
From: Maciej W. Rozycki @ 2008-08-13 15:16 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-mips, Martin Gebert, TriKri
In-Reply-To: <200808131707.30570.brian.foster@innova-card.com>

On Wed, 13 Aug 2008, Brian Foster wrote:

>   What _might_ be an issue/cause is we're using our own
>  home-grown ‘gdb’ scripts (to init the memory, load the
>  kernel, etc.).  I didn't write them, but I have looked
>  them over, and they _look_ Ok to me.

 That should not matter.  For example you could boot your system in the
usual way provided by the firmware and attach to an already running
kernel.  The probe does not know or care about that.

>   I tried some “mdi cacheflush” at some plausible-seeming
>  points, all to no effect.  I also tried deleting the
>  breakpoint (after step 8), which was a disaster:  (From
>  memory) when I then ‘c’(ontinued), ‘gdb’ hung, and the
>  ‘sysnav’ went into an infinite loop of reporting a
>  breakpoint.  ;-(
> 
>  ( I seem to recall also having an issue with hardware
>   breakpoints, but cannot recall for certain ATM; tests
>   will have to wait until later ....  ;-\  )
> 
>   All ideas and suggestions are very welcome!

 Your situation looks pretty miserable -- you should definitely pester 
FS2.

  Maciej

^ permalink raw reply

* Re: Debugging the MIPS processor using GDB
From: Brian Foster @ 2008-08-13 15:12 UTC (permalink / raw)
  To: jfraser; +Cc: linux-mips, Maciej W. Rozycki, TriKri
In-Reply-To: <1218638494.21039.6.camel@chaos.ne.broadcom.com>

On Wednesday 13 August 2008 16:41:34 Jon Fraser wrote:
> I use the FS2 probe with sde-gdb on a nearly daily basis.
> Are you compiling your kernel with -g -O1 ?

Jon,

  ‘-g’, yes.  ‘-O1’?  Not sure, I will have to check when
 I get a chance.  (But I don't see how either would have
 the effect on breakpoints I'm suffering from?)

> You can also try 'hbreak' instead of 'break' in sde-gdb.

  I'll have to (re-)try that when I get a chance.  I did
 try it once, and have (very! vague!!) memories of some
 issue, but now cannot recall anything useful.  ;-\ 

cheers!
	-blf-

-- 
“How many surrealists does it take to   | Brian Foster
 change a lightbulb? Three. One calms   | somewhere in south of France
 the warthog, and two fill the bathtub  |   Stop E$$o (ExxonMobil)!
 with brightly-coloured machine tools.” |      http://www.stopesso.com

^ permalink raw reply

* Re: Debugging the MIPS processor using GDB
From: Brian Foster @ 2008-08-13 15:07 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: linux-mips, Martin Gebert, TriKri
In-Reply-To: <Pine.LNX.4.55.0808131441160.390@cliff.in.clinika.pl>

On Wednesday 13 August 2008 15:49:39 Maciej W. Rozycki wrote:
> On Wed, 13 Aug 2008, Brian Foster wrote:
> 
> >   Re the FS²:  [ ... ]  at least one thing doesn't work
> >  reliably for me [ ... ]:  Breakpoints in the Linux kernel.
> >  They do detonate.  Then, sometimes, I can ‘c’(ontinue) or
> >  ‘s’(tep) Ok.  But other times, when I ‘c’ or ‘s’, the
> >  breakpoint detonates again and I'm stuck.  [ ... ]
> 
>  Hmm, odd.  It looks like a cache coherence issue.

Maciej,

  That would be my guess also.

>  It could be a bug in your version of FS2 software -- did you raise the issue with them?  

  I've been trying to.  (I cannot say more on this ATM, sorry!)

  I'm using the most recent FS² (2.4.4) with the most recent
 SDE-Lite from MIPS (V6.06.01).  Older versions of FS²/SDE
 had the same(?) issue.  (This is with a 4KSd core, running
 Little Endian.)

  What _might_ be an issue/cause is we're using our own
 home-grown ‘gdb’ scripts (to init the memory, load the
 kernel, etc.).  I didn't write them, but I have looked
 them over, and they _look_ Ok to me.


> Anyway, as a workaround try setting "coherent=on" (quoting from memory)
> in fs2.ini (just an idea -- it may not work and you will lose some
> performance though) or use hardware breakpoints.

  As it turns out, I _have_ been running Coherent On!
 So I tried turning if Off, just to see what would happen.
 No difference.

  The behavior I saw was:

    1. gdb     b xxx_open
    2. target  cat /dev/xxx
    3. (breakpoint detonates)
    4. gdb     x/i $pc     (all is Ok)
    5. gdb     c           (Ok)
    6. target  cat /dev/xxx
    7. (breakpoint detonates)
    8. gdb     x/i $pc     (wrong! instruction is ‘sdbbp’.)

  I'm now stuck.  Any attempt to ‘c’ or ‘s’ just hits the
 breakpoint again.

  I tried some “mdi cacheflush” at some plausible-seeming
 points, all to no effect.  I also tried deleting the
 breakpoint (after step 8), which was a disaster:  (From
 memory) when I then ‘c’(ontinued), ‘gdb’ hung, and the
 ‘sysnav’ went into an infinite loop of reporting a
 breakpoint.  ;-(

 ( I seem to recall also having an issue with hardware
  breakpoints, but cannot recall for certain ATM; tests
  will have to wait until later ....  ;-\  )

  All ideas and suggestions are very welcome!

cheers!
	-blf-

-- 
“How many surrealists does it take to   | Brian Foster
 change a lightbulb? Three. One calms   | somewhere in south of France
 the warthog, and two fill the bathtub  |   Stop E$$o (ExxonMobil)!
 with brightly-coloured machine tools.” |      http://www.stopesso.com

^ permalink raw reply

* Re: Debugging the MIPS processor using GDB
From: Jon Fraser @ 2008-08-13 14:41 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-mips, Maciej W. Rozycki, Martin Gebert, TriKri
In-Reply-To: <200808130905.53671.brian.foster@innova-card.com>



FYI,

      I use the FS2 probe with sde-gdb on a nearly daily basis.
Are you compiling your kernel with -g -O1 ?

You can also try 'hbreak' instead of 'break' in sde-gdb.

Jon


On Wed, 2008-08-13 at 09:05 +0200, Brian Foster wrote:
> On Tuesday 12 August 2008 18:27:42 Maciej W. Rozycki wrote:
> > On Tue, 12 Aug 2008, Brian Foster wrote:
> > >   I'm using the commercial FS² (First Silicon Systems, now owned
> > >  by MIPS) EJTAG probe.  [ ... ]  There is no ‘gdbserver’ in this
> > >  setup per se, albeit I suppose the protocol between ‘gdb’ and
> > >  the FS² software [ ... ] might be similar/identical[?]
> > 
> >  Not really -- it uses a C API called MDI -- the spec is available from
> > MIPS Technologies.  I am happy to read somebody finds it useful. :) 
> > Debugging the Linux kernel with GDB and this piece of hardware is
> > certainly a lot of fun.
> 
> Maciej,
> 
>   Thanks for the clarification.  I didn't know if MDI
>  was related to the remote-‘gdbserver’ stuff or not.
> 
>   Re the FS²:  When it works, my (somewhat limited)
>  experience to-date is it works Ok.  And the use of
>  TCL on the Host workstation side allows some neat
>  tricks.  However, at least one thing doesn't work
>  reliably for me, albeit I've never investigated:
>  Breakpoints in the Linux kernel.  They do detonate.
>  Then, sometimes, I can ‘c’(ontinue) or ‘s’(tep) Ok.
>  But other times, when I ‘c’ or ‘s’, the breakpoint
>  detonates again and I'm stuck.  I cannot proceed.
>  (The same breakpoint might even work once or twice
>  and then fail.)   Any ideas?   AFAICR, this can also
>  happen if I try to use the ‘sysnav’ console instead
>  of ‘gdb’.
> 
>   I understand my predecessor in my job I gave up on
>  the FS² (very possibly because of this breakpoint
>  issue?) and used a competing (E?)JTAG probe.
> 
>   Weirdly, I've only seen this effect with the Linux
>  kernel — other kernel-mode software (e.g., the trivial
>  custom bootloader) — doesn't seem to suffer from these
>  “flakey FS² breakpoints”?
> 
> cheers!
> 	-blf-
> 

^ permalink raw reply

* Re: Debugging the MIPS processor using GDB
From: Maciej W. Rozycki @ 2008-08-13 13:49 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-mips, Martin Gebert, TriKri
In-Reply-To: <200808130905.53671.brian.foster@innova-card.com>

On Wed, 13 Aug 2008, Brian Foster wrote:

>   Re the FS²:  When it works, my (somewhat limited)
>  experience to-date is it works Ok.  And the use of
>  TCL on the Host workstation side allows some neat
>  tricks.  However, at least one thing doesn't work
>  reliably for me, albeit I've never investigated:
>  Breakpoints in the Linux kernel.  They do detonate.
>  Then, sometimes, I can ‘c’(ontinue) or ‘s’(tep) Ok.
>  But other times, when I ‘c’ or ‘s’, the breakpoint
>  detonates again and I'm stuck.  I cannot proceed.
>  (The same breakpoint might even work once or twice
>  and then fail.)   Any ideas?   AFAICR, this can also
>  happen if I try to use the ‘sysnav’ console instead
>  of ‘gdb’.

 Hmm, odd.  It looks like a cache coherence issue.  It could be a bug in
your version of FS2 software -- did you raise the issue with them?  
Anyway, as a workaround try setting "coherent=on" (quoting from memory) in
fs2.ini (just an idea -- it may not work and you will lose some
performance though) or use hardware breakpoints.

  Maciej

^ permalink raw reply

* Re: Cavium support
From: Ralf Baechle @ 2008-08-13 13:05 UTC (permalink / raw)
  To: James Perkins; +Cc: Fahim Ansari, linux-mips
In-Reply-To: <48A2298F.6020601@loowit.net>

On Tue, Aug 12, 2008 at 05:23:43PM -0700, James Perkins wrote:

> Fahim Ansari wrote:
>> I want to build a kernel that will boot on a cavium octeon board. Is 
>> the cavium octeon cpuset supported for the linux kernels available at  
>> linux-mips.org.
>> Or is such a kernel available at any other git repository?
>
> I'm not aware of any public git repositories tracking OCTEON at present. 
> The current linux-mips.org project has no support for Cavium Networks 
> OCTEON. There are commercial ports available: Cavium's SDK, and in 
> embedded Linux distributions from Wind River and Montavista. You may want 
> to try contacting Cavium at their website.

I got a Cavium board now so I hopefully can change that :-)

  Ralf

^ permalink raw reply

* "indy_volume_button" [sound/oss/hal2.ko] undefined
From: Martin Michlmayr @ 2008-08-13 12:59 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips

sound/oss/hal2.ko fails to build because indy_volume_button was
removed from the IP22 code.  Is sound/oss/hal2o going to be removed
before 2.6.27 is out?

-- 
Martin Michlmayr
http://www.cyrius.com/

^ permalink raw reply

* Re: [PATCH] Alchemy: modernize Pb1200 IRQ cascade handling code.
From: Manuel Lauss @ 2008-08-13 12:59 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: Ralf Baechle, Kevin Hickey, linux-mips
In-Reply-To: <48A2D4CB.1030901@ru.mvista.com>

On Wed, 13 Aug 2008 16:34:19 +0400
Sergei Shtylyov <sshtylyov@ru.mvista.com> wrote:



> > -inline void pb1200_enable_irq(unsigned int irq_nr)
> > +static void pb1200_unmask_irq(unsigned int irq_nr)
> >  {
> >  	bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
> >  	bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN);
> >  }
> >  
> > -inline void pb1200_disable_irq(unsigned int irq_nr)
> > +static void pb1200_maskack_irq(unsigned int irq_nr)
> >  {
> >  	bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
> >  	bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
> >   
> 
>    I wonder what's the difference between int{clr|set} and 
> int{clr|set}_mask registers...

The irq assertion equation in the CPLD is:

int_condition = inten & intmask & int_input_pin;

In theory, the ->startup() and ->shutdown() methods should fiddle with
the enable bits;  the ->mask()/->unmask() methods should modfiy the mask
bits.  In practice, at least on my DB1200, if not BOTH of the enable
and mask bits are cleared, the CPLD triggers tons of spurious
interrupts.  I read through the verilog sources but could not find a
reason for this...


> [...]
> > +	bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN);	/* ack */
> >   
> 
>    The above comment said that writing to this register has no effect on 
> the level-triggered interrupts, so this statement doesn't seem to make 
> sense since you're treating all interrupts as level-triggered below.

They _all_ behave level-triggered, even the ones that should be edge.
Again, looking at the verilog code, no edge detection or similar is
implemented; for instance the SD card insert/eject irqs should
be edge-triggered, but behave differently: the insert irq stays asserted
as long as a card is in the socket, the eject irq is asserted as long
as no card is present.  The PCMCIA carrdetect irqs exhibit identical
behaviour.


> > @@ -113,12 +77,9 @@ static struct irq_chip external_irq_type = {
> >  #ifdef CONFIG_MIPS_DB1200
> >  	.name = "Db1200 Ext",
> >  #endif
> > -	.startup  = pb1200_startup_irq,
> > -	.shutdown = pb1200_shutdown_irq,
> > -	.ack      = pb1200_disable_irq,
> > -	.mask     = pb1200_disable_irq,
> > -	.mask_ack = pb1200_disable_irq,
> > -	.unmask   = pb1200_enable_irq,
> > +	.mask		= pb1200_maskack_irq,
> > +	.mask_ack	= pb1200_maskack_irq,
> >   
> 
>    You can use the same function for the mask() and mask_ack() methods 
> but it only should be masking IRQ, as clearing it doesn't make sense...

It doesn't make a difference in practice, but I'll create a separate
->mask() method without the acking part of the supposedly-edge ints ;-)


> > +	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++)
> > +		set_irq_chip_and_handler_name(irq, &external_irq_type,
> > +					 handle_level_irq, "level");
> >   
> 
>    Are all those IRQs indeed level-triggered?

See above.

Thanks,
	Manuel Lauss

^ permalink raw reply

* Re: [PATCH] Alchemy: modernize Pb1200 IRQ cascade handling code.
From: Sergei Shtylyov @ 2008-08-13 12:34 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: Ralf Baechle, Kevin Hickey, linux-mips
In-Reply-To: <1218568881-3544-2-git-send-email-mano@roarinelk.homelinux.net>

Hello.

Manuel Lauss wrote:

> Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
>   
[...]
> diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
> index 2a505ad..7229f30 100644
> --- a/arch/mips/au1000/pb1200/irqmap.c
> +++ b/arch/mips/au1000/pb1200/irqmap.c
> @@ -48,62 +48,26 @@ int __initdata au1xxx_nr_irqs = ARRAY_SIZE(au1xxx_irq_map);
>  /*
>   * Support for External interrupts on the Pb1200 Development platform.
>   */
> -static volatile int pb1200_cascade_en;
>  
> -irqreturn_t pb1200_cascade_handler(int irq, void *dev_id)
> +static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *desc)
>  {
>  	unsigned short bisr = bcsr->int_status;
> -	int extirq_nr = 0;
> -
> -	/* Clear all the edge interrupts. This has no effect on level. */
>   

   Note this comment...

> -	bcsr->int_status = bisr;
> -	for ( ; bisr; bisr &= bisr - 1) {
> -		extirq_nr = PB1200_INT_BEGIN + __ffs(bisr);
> -		/* Ack and dispatch IRQ */
> -		do_IRQ(extirq_nr);
> -	}
>  
> -	return IRQ_RETVAL(1);
> +	for ( ; bisr; bisr &= bisr - 1)
> +		generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr));
>  }
>  
> -inline void pb1200_enable_irq(unsigned int irq_nr)
> +static void pb1200_unmask_irq(unsigned int irq_nr)
>  {
>  	bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
>  	bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN);
>  }
>  
> -inline void pb1200_disable_irq(unsigned int irq_nr)
> +static void pb1200_maskack_irq(unsigned int irq_nr)
>  {
>  	bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
>  	bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
>   

   I wonder what's the difference between int{clr|set} and 
int{clr|set}_mask registers...

[...]
> +	bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN);	/* ack */
>   

   The above comment said that writing to this register has no effect on 
the level-triggered interrupts, so this statement doesn't seem to make 
sense since you're treating all interrupts as level-triggered below.

> @@ -113,12 +77,9 @@ static struct irq_chip external_irq_type = {
>  #ifdef CONFIG_MIPS_DB1200
>  	.name = "Db1200 Ext",
>  #endif
> -	.startup  = pb1200_startup_irq,
> -	.shutdown = pb1200_shutdown_irq,
> -	.ack      = pb1200_disable_irq,
> -	.mask     = pb1200_disable_irq,
> -	.mask_ack = pb1200_disable_irq,
> -	.unmask   = pb1200_enable_irq,
> +	.mask		= pb1200_maskack_irq,
> +	.mask_ack	= pb1200_maskack_irq,
>   

   You can use the same function for the mask() and mask_ack() methods 
but it only should be masking IRQ, as clearing it doesn't make sense...

> @@ -147,14 +108,14 @@ void _board_init_irq(void)
>  	}
>  #endif
>  
> -	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++) {
> -		set_irq_chip_and_handler(irq, &external_irq_type,
> -					 handle_level_irq);
> -		pb1200_disable_irq(irq);
> -	}
> +	/* mask & disable & ack all */
> +	bcsr->intclr_mask = 0xffff;
> +	bcsr->intclr = 0xffff;
> +	bcsr->int_status = 0xffff;
> +
> +	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++)
> +		set_irq_chip_and_handler_name(irq, &external_irq_type,
> +					 handle_level_irq, "level");
>   

   Are all those IRQs indeed level-triggered?

WBR, Sergei

^ permalink raw reply

* Re: Debugging the MIPS processor using GDB
From: Brian Foster @ 2008-08-13  7:05 UTC (permalink / raw)
  To: linux-mips; +Cc: Maciej W. Rozycki, Martin Gebert, TriKri
In-Reply-To: <Pine.LNX.4.55.0808121720370.24222@cliff.in.clinika.pl>

On Tuesday 12 August 2008 18:27:42 Maciej W. Rozycki wrote:
> On Tue, 12 Aug 2008, Brian Foster wrote:
> >   I'm using the commercial FS² (First Silicon Systems, now owned
> >  by MIPS) EJTAG probe.  [ ... ]  There is no ‘gdbserver’ in this
> >  setup per se, albeit I suppose the protocol between ‘gdb’ and
> >  the FS² software [ ... ] might be similar/identical[?]
> 
>  Not really -- it uses a C API called MDI -- the spec is available from
> MIPS Technologies.  I am happy to read somebody finds it useful. :) 
> Debugging the Linux kernel with GDB and this piece of hardware is
> certainly a lot of fun.

Maciej,

  Thanks for the clarification.  I didn't know if MDI
 was related to the remote-‘gdbserver’ stuff or not.

  Re the FS²:  When it works, my (somewhat limited)
 experience to-date is it works Ok.  And the use of
 TCL on the Host workstation side allows some neat
 tricks.  However, at least one thing doesn't work
 reliably for me, albeit I've never investigated:
 Breakpoints in the Linux kernel.  They do detonate.
 Then, sometimes, I can ‘c’(ontinue) or ‘s’(tep) Ok.
 But other times, when I ‘c’ or ‘s’, the breakpoint
 detonates again and I'm stuck.  I cannot proceed.
 (The same breakpoint might even work once or twice
 and then fail.)   Any ideas?   AFAICR, this can also
 happen if I try to use the ‘sysnav’ console instead
 of ‘gdb’.

  I understand my predecessor in my job I gave up on
 the FS² (very possibly because of this breakpoint
 issue?) and used a competing (E?)JTAG probe.

  Weirdly, I've only seen this effect with the Linux
 kernel — other kernel-mode software (e.g., the trivial
 custom bootloader) — doesn't seem to suffer from these
 “flakey FS² breakpoints”?

cheers!
	-blf-

-- 
“How many surrealists does it take to   | Brian Foster
 change a lightbulb? Three. One calms   | somewhere in south of France
 the warthog, and two fill the bathtub  |   Stop E$$o (ExxonMobil)!
 with brightly-coloured machine tools.” |      http://www.stopesso.com

^ permalink raw reply

* Re: Cavium support
From: James Perkins @ 2008-08-13  0:23 UTC (permalink / raw)
  To: Fahim Ansari; +Cc: linux-mips
In-Reply-To: <48A22045.4060503@redback.com>

Fahim Ansari wrote:
> I want to build a kernel that will boot on a cavium octeon board. Is the 
> cavium octeon cpuset supported for the linux kernels available at 
> linux-mips.org.
> Or is such a kernel available at any other git repository?

I'm not aware of any public git repositories tracking OCTEON at present. The 
current linux-mips.org project has no support for Cavium Networks OCTEON. 
There are commercial ports available: Cavium's SDK, and in embedded Linux 
distributions from Wind River and Montavista. You may want to try contacting 
Cavium at their website.

Cheers,
James Perkins
james@loowit.net

^ permalink raw reply

* Cavium support
From: Fahim Ansari @ 2008-08-12 23:44 UTC (permalink / raw)
  To: linux-mips

I want to build a kernel that will boot on a cavium octeon board. Is the 
cavium octeon cpuset supported for the linux kernels available at 
linux-mips.org.
Or is such a kernel available at any other git repository?

Thanks,
Fahim

^ permalink raw reply

* [PATCH] add sparsemem howto document
From: Sundis @ 2008-08-12 20:02 UTC (permalink / raw)


---
 Documentation/sparsemem.txt |   95 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 95 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/sparsemem.txt

diff --git a/Documentation/sparsemem.txt b/Documentation/sparsemem.txt
new file mode 100644
index 0000000..a9ce4bc
--- /dev/null
+++ b/Documentation/sparsemem.txt
@@ -0,0 +1,95 @@
+Sparsemem divides up physical memory in your system into N section of M
+bytes. Page tables are created for only those sections that
+actually exist (as far as the sparsemem code is concerned). This allows
+for holes in the physical memory without having to waste space by
+creating page discriptors for those pages that do not exist.
+When page_to_pfn() or pfn_to_page() are called there is a bit of overhead to
+look up the proper memory section to get to the page_table, but this
+is small compared to the memory you are likely to save. So, it's not the
+default, but should be used if you have big holes in physical memory.
+
+Note that discontiguous memory is more closely related to NUMA machines
+and if you are a single CPU system use sparsemem and not discontig. 
+It's much simpler. 
+
+1) CALL MEMORY_PRESENT()
+Existing sections are recorded once the bootmem allocator is up and running by
+calling the sparsemem function "memory_present(node, pfn_start, pfn_end)" for each
+block of memory that exists in your physical address space. The
+memory_present() function records valid sections in a data structure called
+mem_section[].
+
+2) DETERMINE AND SET THE SIZE OF SECTIONS AND PHYSMEM
+The size of N and M above depend upon your architecture
+and your platform and are specified in the file:
+
+      include/asm-<your_arch>/sparsemem.h
+
+and you should create the following lines similar to below: 
+
+	#ifdef CONFIG_YOUR_PLATFORM
+	 #define SECTION_SIZE_BITS       27	/* 128 MiB */
+	#endif
+	#define MAX_PHYSMEM_BITS        31	/* 2 GiB   */
+
+if they don't already exist, where: 
+
+ * SECTION_SIZE_BITS            2^M: how big each section will be
+ * MAX_PHYSMEM_BITS             2^N: how much memory we can have in that
+                                     space
+
+3) INITIALIZE SPARSE MEMORY
+You should make sure that you initialize the sparse memory code by calling 
+
+	bootmem_init();
+  +	sparse_init();
+	paging_init();
+
+just before you call paging_init() and after the bootmem_allocator is
+turned on in your setup_arch() code.  
+
+4) ENABLE SPARSEMEM IN KCONFIG
+Add a line like this:
+
+	select ARCH_SPARSEMEM_ENABLE
+
+into the config for your platform in arch/<your_arch>/Kconfig. This will
+ensure that turning on sparsemem is enabled for your platform. 
+
+5) CONFIG
+Run make menuconfig or make gconfig, as you like, and turn on the sparsemem
+memory model under the "Kernel Type" --> "Memory Model" and then build your
+kernel.
+
+
+6) Gotchas
+
+One trick that I encountered when I was turning this on for MIPS was that there
+was some code in mem_init() that set the "reserved" flag for pages that were not
+valid RAM. This caused my kernel to crash when I enabled sparsemem since those
+pages (and page descriptors) didn't actually exist. I changed my code by adding
+lines like below:
+
+
+	for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
+		struct page *page = pfn_to_page(tmp);
+
+   +		if (!pfn_valid(tmp))
+   +			continue;
+   +
+		if (!page_is_ram(tmp)) {
+			SetPageReserved(page);
+			continue;
+		}
+		ClearPageReserved(page);
+		init_page_count(page);
+		__free_page(page);
+		physmem_record(PFN_PHYS(tmp), PAGE_SIZE, physmem_highmem);
+		totalhigh_pages++;
+	}
+
+
+Once I got that straight, it worked!!!! I saved 10MiB of memory.  
+
+
+
-- 
1.5.4.1


--------------010403040800010305090501--

^ permalink raw reply related

* [PATCH] support sparsemem for mips32
From: Sundis @ 2008-08-12 19:43 UTC (permalink / raw)


---
 arch/mips/kernel/setup.c     |   18 +++++++++++++++++-
 arch/mips/mm/init.c          |    3 +++
 include/asm-mips/sparsemem.h |    6 ++++++
 3 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index f8a535a..6ff0f72 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -405,7 +405,6 @@ static void __init bootmem_init(void)
 
 		/* Register lowmem ranges */
 		free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
-		memory_present(0, start, end);
 	}
 
 	/*
@@ -417,6 +416,23 @@ static void __init bootmem_init(void)
 	 * Reserve initrd memory if needed.
 	 */
 	finalize_initrd();
+
+	/* call memory present for all the ram */
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long start, end;
+
+		/*
+ * 		 * memory present only usable memory.
+ * 		 		 */
+		if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+			continue;
+
+		start = PFN_UP(boot_mem_map.map[i].addr);
+		end   = PFN_DOWN(boot_mem_map.map[i].addr
+				    + boot_mem_map.map[i].size);
+
+		memory_present(0, start, end);
+	}
 }
 
 #endif	/* CONFIG_SGI_IP27 */
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 480dec0..9bc6d35 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -417,6 +417,9 @@ void __init mem_init(void)
 	for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
 		struct page *page = pfn_to_page(tmp);
 
+		if (!pfn_valid(tmp))
+			continue;
+
 		if (!page_is_ram(tmp)) {
 			SetPageReserved(page);
 			continue;
diff --git a/include/asm-mips/sparsemem.h b/include/asm-mips/sparsemem.h
index 795ac6c..9faaf59 100644
--- a/include/asm-mips/sparsemem.h
+++ b/include/asm-mips/sparsemem.h
@@ -6,8 +6,14 @@
  * SECTION_SIZE_BITS		2^N: how big each section will be
  * MAX_PHYSMEM_BITS		2^N: how much memory we can have in that space
  */
+
+#ifndef CONFIG_64BIT
+#define SECTION_SIZE_BITS       27	/* 128 MiB */
+#define MAX_PHYSMEM_BITS        31	/* 2 GiB   */
+#else
 #define SECTION_SIZE_BITS       28
 #define MAX_PHYSMEM_BITS        35
+#endif
 
 #endif /* CONFIG_SPARSEMEM */
 #endif /* _MIPS_SPARSEMEM_H */
-- 
1.5.4.1

^ permalink raw reply related

* [PATCH] Alchemy: rework DBDMA init sequence.
From: Manuel Lauss @ 2008-08-12 19:21 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, linux-mips, Manuel Lauss

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/dbdma.c |   25 +++++++++----------------
 1 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index 601ee91..c1f0a3c 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -57,8 +57,6 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
 #define ALIGN_ADDR(x, a)	((((u32)(x)) + (a-1)) & ~(a-1))
 
 static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
-static int dbdma_initialized;
-static void au1xxx_dbdma_init(void);
 
 static dbdev_tab_t dbdev_tab[] = {
 #ifdef CONFIG_SOC_AU1550
@@ -239,15 +237,6 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
 	chan_tab_t	*ctp;
 	au1x_dma_chan_t *cp;
 
-	/*
-	 * We do the intialization on the first channel allocation.
-	 * We have to wait because of the interrupt handler initialization
-	 * which can't be done successfully during board set up.
-	 */
-	if (!dbdma_initialized)
-		au1xxx_dbdma_init();
-	dbdma_initialized = 1;
-
 	stp = find_dbdev_id(srcid);
 	if (stp == NULL)
 		return 0;
@@ -863,9 +852,9 @@ static irqreturn_t dbdma_interrupt(int irq, void *dev_id)
 	return IRQ_RETVAL(1);
 }
 
-static void au1xxx_dbdma_init(void)
+static int __init au1xxx_dbdma_init(void)
 {
-	int irq_nr;
+	int irq_nr, ret;
 
 	dbdma_gptr->ddma_config = 0;
 	dbdma_gptr->ddma_throttle = 0;
@@ -880,10 +869,14 @@ static void au1xxx_dbdma_init(void)
 	#error Unknown Au1x00 SOC
 #endif
 
-	if (request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED,
-			"Au1xxx dbdma", (void *)dbdma_gptr))
-		printk(KERN_ERR "Can't get 1550 dbdma irq");
+	ret = request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED,
+			"Au1xxx dbdma", (void *)dbdma_gptr);
+	if (ret)
+		printk(KERN_ERR "Au1xxx dbdma: cannot get IRQ\n");
+
+	return ret;
 }
+subsys_initcall(au1xxx_dbdma_init);
 
 void au1xxx_dbdma_dump(u32 chanid)
 {
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH] Alchemy: modernize Pb1200 IRQ cascade handling code.
From: Manuel Lauss @ 2008-08-12 19:21 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, linux-mips, Manuel Lauss

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/pb1200/irqmap.c |   75 +++++++++-----------------------------
 1 files changed, 18 insertions(+), 57 deletions(-)

diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
index 2a505ad..7229f30 100644
--- a/arch/mips/au1000/pb1200/irqmap.c
+++ b/arch/mips/au1000/pb1200/irqmap.c
@@ -48,62 +48,26 @@ int __initdata au1xxx_nr_irqs = ARRAY_SIZE(au1xxx_irq_map);
 /*
  * Support for External interrupts on the Pb1200 Development platform.
  */
-static volatile int pb1200_cascade_en;
 
-irqreturn_t pb1200_cascade_handler(int irq, void *dev_id)
+static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *desc)
 {
 	unsigned short bisr = bcsr->int_status;
-	int extirq_nr = 0;
-
-	/* Clear all the edge interrupts. This has no effect on level. */
-	bcsr->int_status = bisr;
-	for ( ; bisr; bisr &= bisr - 1) {
-		extirq_nr = PB1200_INT_BEGIN + __ffs(bisr);
-		/* Ack and dispatch IRQ */
-		do_IRQ(extirq_nr);
-	}
 
-	return IRQ_RETVAL(1);
+	for ( ; bisr; bisr &= bisr - 1)
+		generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr));
 }
 
-inline void pb1200_enable_irq(unsigned int irq_nr)
+static void pb1200_unmask_irq(unsigned int irq_nr)
 {
 	bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
 	bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN);
 }
 
-inline void pb1200_disable_irq(unsigned int irq_nr)
+static void pb1200_maskack_irq(unsigned int irq_nr)
 {
 	bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
 	bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
-}
-
-static unsigned int pb1200_setup_cascade(void)
-{
-	return request_irq(AU1000_GPIO_7, &pb1200_cascade_handler,
-			   0, "Pb1200 Cascade", &pb1200_cascade_handler);
-}
-
-static unsigned int pb1200_startup_irq(unsigned int irq)
-{
-	if (++pb1200_cascade_en == 1) {
-		int res;
-
-		res = pb1200_setup_cascade();
-		if (res)
-			return res;
-	}
-
-	pb1200_enable_irq(irq);
-
-	return 0;
-}
-
-static void pb1200_shutdown_irq(unsigned int irq)
-{
-	pb1200_disable_irq(irq);
-	if (--pb1200_cascade_en == 0)
-		free_irq(AU1000_GPIO_7, &pb1200_cascade_handler);
+	bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN);	/* ack */
 }
 
 static struct irq_chip external_irq_type = {
@@ -113,12 +77,9 @@ static struct irq_chip external_irq_type = {
 #ifdef CONFIG_MIPS_DB1200
 	.name = "Db1200 Ext",
 #endif
-	.startup  = pb1200_startup_irq,
-	.shutdown = pb1200_shutdown_irq,
-	.ack      = pb1200_disable_irq,
-	.mask     = pb1200_disable_irq,
-	.mask_ack = pb1200_disable_irq,
-	.unmask   = pb1200_enable_irq,
+	.mask		= pb1200_maskack_irq,
+	.mask_ack	= pb1200_maskack_irq,
+	.unmask		= pb1200_unmask_irq,
 };
 
 void _board_init_irq(void)
@@ -147,14 +108,14 @@ void _board_init_irq(void)
 	}
 #endif
 
-	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++) {
-		set_irq_chip_and_handler(irq, &external_irq_type,
-					 handle_level_irq);
-		pb1200_disable_irq(irq);
-	}
+	/* mask & disable & ack all */
+	bcsr->intclr_mask = 0xffff;
+	bcsr->intclr = 0xffff;
+	bcsr->int_status = 0xffff;
+
+	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++)
+		set_irq_chip_and_handler_name(irq, &external_irq_type,
+					 handle_level_irq, "level");
 
-	/*
-	 * GPIO_7 can not be hooked here, so it is hooked upon first
-	 * request of any source attached to the cascade.
-	 */
+	set_irq_chained_handler(AU1000_GPIO_7, pb1200_cascade_handler);
 }
-- 
1.5.6.4

^ permalink raw reply related

* Re: [PATCH 00/10] Alchemy updates v5
From: Kevin Hickey @ 2008-08-12 19:08 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: Ralf Baechle, Linux-MIPS
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

Ralf et al.,

On Tue, 2008-08-12 at 19:42 +0200, Manuel Lauss wrote:
> [Ralf: Please consider this series for 2.6.27 inclusion if it is still
>  possible to sneak them in]
I'd like to second this request.  I have some work that I would like to
do that depends on these patches.  I've tested them on my system and
they appear solid.  Feel free to add my Acked-By line to them:
Acked-by: Kevin Hickey <khickey@rmicorp.com>

Thanks.

> 
-- 
Kevin Hickey
Alchemy Solutions
RMI Corporation
khickey@RMICorp.com
P: 512.691.8044

^ permalink raw reply

* [PATCH 10/10] Alchemy: new demoboard userspace suspend interface.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

Replace the current sysctl-based suspend interface with a new sysfs-
based one which also uses the Linux-2.6 suspend model.

To configure wakeup sources, a subtree for the demoboards is created
under /sys/power/db1x:

sys/
`-- power
    `-- db1x
        |-- gpio0
        |-- gpio1
        |-- gpio2
        |-- gpio3
        |-- gpio4
        |-- gpio5
        |-- gpio6
        |-- gpio7
        |-- timer
        |-- timer_timeout
        |-- uptime
        |-- wakemsk
        `-- wakesrc

The nodes 'gpio[0-7]' and 'timer' configure the GPIO0..7 and M2
bits of the SYS_WAKEMSK (wakeup source enable) register.  Writing '1'
enables a wakesource, 0 disables it.

The 'timer_timeout' node holds the timeout in seconds after which the
TOYMATCH2 event should wake the system.

The 'wakesrc' node holds the SYS_WAKESRC register after wakeup (in hex),
the 'wakemsk' node can be used to get/set the wakeup mask directly.

'uptime' gives access to the TOY counter value; it can be used for example
to track total time in seconds since last kernel boot.

For example, to have the timer wake the system after 10 seconds of sleep,
the following must be done in userspace:

echo 10 > /sys/power/db1x/timer_timeout
echo 1 > /sys/power/db1x/timer
echo mem > /sys/power/sleep

This patch also removes the homebrew CPU frequency switching code.  I don't
understand how it could have ever worked reliably; it does not communicate
the clock changes to other devices tied to BCLK and does not adjust memory
controller timings (which is not a problem when the CPU is never clocked
higher than what was set by the bootloader).

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/irq.c         |   57 +----
 arch/mips/au1000/common/platform.c    |  423 ++++++++++++++-------------------
 include/asm-mips/mach-au1x00/au1000.h |    4 +
 3 files changed, 193 insertions(+), 291 deletions(-)

diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 40c6cec..f5489c3 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -44,8 +44,6 @@
 
 void (*board_init_irq)(void) __initdata = NULL;
 
-static DEFINE_SPINLOCK(irq_lock);
-
 #ifdef CONFIG_PM
 
 /*
@@ -130,7 +128,7 @@ void restore_au1xxx_intctl(void)
 #endif /* CONFIG_PM */
 
 
-inline void local_enable_irq(unsigned int irq_nr)
+static void local_enable_irq(unsigned int irq_nr)
 {
 	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
 
@@ -145,7 +143,7 @@ inline void local_enable_irq(unsigned int irq_nr)
 }
 
 
-inline void local_disable_irq(unsigned int irq_nr)
+static void local_disable_irq(unsigned int irq_nr)
 {
 	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
 
@@ -160,7 +158,7 @@ inline void local_disable_irq(unsigned int irq_nr)
 }
 
 
-static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr)
+static void mask_and_ack_rise_edge_irq(unsigned int irq_nr)
 {
 	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
 
@@ -175,7 +173,7 @@ static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr)
 }
 
 
-static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr)
+static void mask_and_ack_fall_edge_irq(unsigned int irq_nr)
 {
 	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
 
@@ -190,7 +188,7 @@ static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr)
 }
 
 
-static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr)
+static void mask_and_ack_either_edge_irq(unsigned int irq_nr)
 {
 	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
 
@@ -210,7 +208,7 @@ static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr)
 	au_sync();
 }
 
-static inline void mask_and_ack_level_irq(unsigned int irq_nr)
+static void mask_and_ack_level_irq(unsigned int irq_nr)
 {
 	local_disable_irq(irq_nr);
 	au_sync();
@@ -235,49 +233,6 @@ static void end_irq(unsigned int irq_nr)
 #endif
 }
 
-unsigned long save_local_and_disable(int controller)
-{
-	int i;
-	unsigned long flags, mask;
-
-	spin_lock_irqsave(&irq_lock, flags);
-	if (controller) {
-		mask = au_readl(IC1_MASKSET);
-		for (i = 32; i < 64; i++)
-			local_disable_irq(i);
-	} else {
-		mask = au_readl(IC0_MASKSET);
-		for (i = 0; i < 32; i++)
-			local_disable_irq(i);
-	}
-	spin_unlock_irqrestore(&irq_lock, flags);
-
-	return mask;
-}
-
-void restore_local_and_enable(int controller, unsigned long mask)
-{
-	int i;
-	unsigned long flags, new_mask;
-
-	spin_lock_irqsave(&irq_lock, flags);
-	for (i = 0; i < 32; i++)
-		if (mask & (1 << i)) {
-			if (controller)
-				local_enable_irq(i + 32);
-			else
-				local_enable_irq(i);
-		}
-
-	if (controller)
-		new_mask = au_readl(IC1_MASKSET);
-	else
-		new_mask = au_readl(IC0_MASKSET);
-
-	spin_unlock_irqrestore(&irq_lock, flags);
-}
-
-
 static struct irq_chip rise_edge_irq_type = {
 	.name		= "Au1000 Rise Edge",
 	.ack		= mask_and_ack_rise_edge_irq,
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index b5ff42a..e4c2c31 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -23,10 +23,6 @@
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/spinlock.h>
-#include <linux/sysctl.h>
-#include <linux/uaccess.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
 
@@ -336,269 +332,214 @@ arch_initcall(au1xxx_platform_init);
 
 #ifdef CONFIG_PM
 
-static DEFINE_SPINLOCK(pm_lock);
+/*
+ * Generic suspend for db1x.
+ * This codes exports a few sysfs nodes under /sys/power/db1x/
+ * which can be used by userspace to en/disable certain wakeup sources
+ * and configure the timeout after which the the TOYMATCH2 irq is to
+ * trigger a wakeup.
+ */
+
+#include <linux/kobject.h>
+#include <linux/suspend.h>
+#include <linux/sysfs.h>
 
-extern unsigned long save_local_and_disable(int controller);
-extern void restore_local_and_enable(int controller, unsigned long mask);
-extern void local_enable_irq(unsigned int irq_nr);
 extern void au_sleep(void);
 
-/*
- * Define this to cause the value you write to /proc/sys/pm/sleep to
- * set the TOY timer for the amount of time you want to sleep.
- * This is done mainly for testing, but may be useful in other cases.
- * The value is number of 32KHz ticks to sleep.
- */
-#define SLEEP_TEST_TIMEOUT 1
-#ifdef	SLEEP_TEST_TIMEOUT
-static int sleep_ticks;
-static void wakeup_counter0_set(int ticks)
-{
-	au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
-	au_sync();
-}
-#endif
+static unsigned long db1x_pm_sleep_secs;
+static unsigned long db1x_pm_wakemsk;
+static unsigned long db1x_pm_last_wakesrc;
 
-static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
-		       void __user *buffer, size_t *len, loff_t *ppos)
+static int db1x_pm_enter(suspend_state_t state)
 {
-	unsigned long wakeup, flags;
-#ifdef SLEEP_TEST_TIMEOUT
-#define TMPBUFLEN2 16
-	char buf[TMPBUFLEN2], *p;
-#endif
+	/* enable GPIO based wakeup */
+	au_writel(1, SYS_PININPUTEN);
+	au_sync();
 
-	spin_lock_irqsave(&pm_lock, flags);
+	/* clear and setup wake cause and source */
+	au_writel(0, SYS_WAKEMSK);
+	au_sync();
+	au_writel(0, SYS_WAKESRC);
+	au_sync();
 
-	if (!write) {
-		*len = 0;
-		spin_unlock_irqrestore(&pm_lock, flags);
-		return 0;
-	}
+	au_writel(db1x_pm_wakemsk, SYS_WAKEMSK);
+	au_sync();
 
-#ifdef SLEEP_TEST_TIMEOUT
-	if (*len > TMPBUFLEN2 - 1)
-		return -EFAULT;
-	if (copy_from_user(buf, buffer, *len))
-		return -EFAULT;
-	buf[*len] = 0;
-	p = buf;
-	sleep_ticks = simple_strtoul(p, &p, 0);
-#endif
+	/* setup 1Hz-timer-based wakeup */
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20)
+		asm volatile ("nop");
 
-	/**
-	 ** The code below is all system dependent and we should probably
-	 ** have a function call out of here to set this up.  You need
-	 ** to configure the GPIO or timer interrupts that will bring
-	 ** you out of sleep.
-	 ** For testing, the TOY counter wakeup is useful.
-	 **/
-#if 0
-	au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
-
-	/* GPIO 6 can cause a wake up event */
-	wakeup = au_readl(SYS_WAKEMSK);
-	wakeup &= ~(1 << 8);	/* turn off match20 wakeup */
-	wakeup |= 1 << 6;	/* turn on  GPIO  6 wakeup */
-#else
-	/* For testing, allow match20 to wake us up. */
-#ifdef SLEEP_TEST_TIMEOUT
-	wakeup_counter0_set(sleep_ticks);
-#endif
-	wakeup = 1 << 8;	/* turn on match20 wakeup   */
-#endif
-	au_writel(1, SYS_WAKESRC);	/* clear cause */
-	au_sync();
-	au_writel(wakeup, SYS_WAKEMSK);
+	au_writel(au_readl(SYS_TOYREAD) + db1x_pm_sleep_secs, SYS_TOYMATCH2);
 	au_sync();
 
-	au_sleep();
+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20)
+		asm volatile ("nop");
 
-	spin_unlock_irqrestore(&pm_lock, flags);
+	/* ...and now the sandman can come! */
+	au_sleep();
 
 	return 0;
 }
 
-#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
-/*
- * This is the number of bits of precision for the loops_per_jiffy.
- * Each bit takes on average 1.5/HZ seconds.  This (like the original)
- * is a little better than 1%.
- */
-#define LPS_PREC 8
-
-static void au1000_calibrate_delay(void)
+static int db1x_pm_begin(suspend_state_t state)
 {
-	unsigned long ticks, loopbit;
-	int lps_precision = LPS_PREC;
-
-	loops_per_jiffy = 1 << 12;
-
-	while (loops_per_jiffy <<= 1) {
-		/* Wait for "start of" clock tick */
-		ticks = jiffies;
-		while (ticks == jiffies)
-			/* nothing */ ;
-		/* Go ... */
-		ticks = jiffies;
-		__delay(loops_per_jiffy);
-		ticks = jiffies - ticks;
-		if (ticks)
-			break;
+	if (!db1x_pm_wakemsk) {
+		printk(KERN_ERR "db1x: no wakeup source activated!\n");
+		return -EINVAL;
 	}
 
-	/*
-	 * Do a binary approximation to get loops_per_jiffy set to be equal
-	 * one clock (up to lps_precision bits)
+	return 0;
+}
+
+static void db1x_pm_end(void)
+{
+	/* read and store wakeup source, the clear the register. To
+	 * be able to clear it, WAKEMSK must be cleared first.
 	 */
-	loops_per_jiffy >>= 1;
-	loopbit = loops_per_jiffy;
-	while (lps_precision-- && (loopbit >>= 1)) {
-		loops_per_jiffy |= loopbit;
-		ticks = jiffies;
-		while (ticks == jiffies);
-		ticks = jiffies;
-		__delay(loops_per_jiffy);
-		if (jiffies != ticks)	/* longer than 1 tick */
-			loops_per_jiffy &= ~loopbit;
-	}
+	db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC);
+
+	au_writel(0, SYS_WAKEMSK);
+	au_writel(0, SYS_WAKESRC);
+	au_sync();
+
 }
 
-static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
-		      void __user *buffer, size_t *len, loff_t *ppos)
+static struct platform_suspend_ops db1x_pm_ops = {
+	.valid		= suspend_valid_only_mem,
+	.begin		= db1x_pm_begin,
+	.enter		= db1x_pm_enter,
+	.end		= db1x_pm_end,
+};
+
+#define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))
+
+static ssize_t db1x_pmattr_show(struct kobject *kobj,
+				struct kobj_attribute *attr,
+				char *buf)
 {
-	int retval = 0, i;
-	unsigned long val, pll;
-#define TMPBUFLEN 64
-#define MAX_CPU_FREQ 396
-	char buf[TMPBUFLEN], *p;
-	unsigned long flags, intc0_mask, intc1_mask;
-	unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh;
-	unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
-	unsigned long baud_rate;
-
-	spin_lock_irqsave(&pm_lock, flags);
-	if (!write)
-		*len = 0;
-	else {
-		/* Parse the new frequency */
-		if (*len > TMPBUFLEN - 1) {
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-		if (copy_from_user(buf, buffer, *len)) {
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-		buf[*len] = 0;
-		p = buf;
-		val = simple_strtoul(p, &p, 0);
-		if (val > MAX_CPU_FREQ) {
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-
-		pll = val / 12;
-		if ((pll > 33) || (pll < 7)) {	/* 396 MHz max, 84 MHz min */
-			/* Revisit this for higher speed CPUs */
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-
-		old_baud_base = get_au1x00_uart_baud_base();
-		old_cpu_freq = get_au1x00_speed();
-
-		new_cpu_freq = pll * 12 * 1000000;
-	        new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)
-							    & 0x03) + 2) * 16));
-		set_au1x00_speed(new_cpu_freq);
-		set_au1x00_uart_baud_base(new_baud_base);
-
-		old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
-		new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) |
-			      (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
-
-		au_writel(pll, SYS_CPUPLL);
-		au_sync_delay(1);
-		au_writel(new_refresh, MEM_SDREFCFG);
-		au_sync_delay(1);
-
-		for (i = 0; i < 4; i++)
-			if (au_readl(UART_BASE + UART_MOD_CNTRL +
-				     i * 0x00100000) == 3) {
-				old_clk = au_readl(UART_BASE + UART_CLK +
-						   i * 0x00100000);
-				baud_rate = old_baud_base / old_clk;
-				/*
-				 * We won't get an exact baud rate and the error
-				 * could be significant enough that our new
-				 * calculation will result in a clock that will
-				 * give us a baud rate that's too far off from
-				 * what we really want.
-				 */
-				if (baud_rate > 100000)
-					baud_rate = 115200;
-				else if (baud_rate > 50000)
-					baud_rate = 57600;
-				else if (baud_rate > 30000)
-					baud_rate = 38400;
-				else if (baud_rate > 17000)
-					baud_rate = 19200;
-				else
-					baud_rate = 9600;
-				new_clk = new_baud_base / baud_rate;
-				au_writel(new_clk, UART_BASE + UART_CLK +
-					  i * 0x00100000);
-				au_sync_delay(10);
-			}
+	int idx;
+
+	if (ATTRCMP(timer_timeout))
+		return sprintf(buf, "%lu\n", db1x_pm_sleep_secs);
+
+	else if (ATTRCMP(timer))
+		return sprintf(buf, "%u\n",
+				!!(db1x_pm_wakemsk & SYS_WAKEMSK_M2));
+
+	else if (ATTRCMP(wakesrc))
+		return sprintf(buf, "%lu\n", db1x_pm_last_wakesrc);
+
+	else if (ATTRCMP(uptime))
+		return sprintf(buf, "%lu\n",
+				(unsigned long)au_readl(SYS_TOYREAD));
+
+	else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
+		 ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
+		 ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
+		idx = (attr->attr.name)[4] - '0';
+		return sprintf(buf, "%d\n",
+			!!(db1x_pm_wakemsk & SYS_WAKEMSK_GPIO(idx)));
+
+	} else if (ATTRCMP(wakemsk)) {
+		return sprintf(buf, "%08lx\n", db1x_pm_wakemsk);
 	}
 
-	/*
-	 * We don't want _any_ interrupts other than match20. Otherwise our
-	 * au1000_calibrate_delay() calculation will be off, potentially a lot.
-	 */
-	intc0_mask = save_local_and_disable(0);
-	intc1_mask = save_local_and_disable(1);
-	local_enable_irq(AU1000_TOY_MATCH2_INT);
-	spin_unlock_irqrestore(&pm_lock, flags);
-	au1000_calibrate_delay();
-	restore_local_and_enable(0, intc0_mask);
-	restore_local_and_enable(1, intc1_mask);
-
-	return retval;
+	return -ENOENT;
 }
-#endif
 
-static struct ctl_table pm_table[] = {
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "sleep",
-		.data		= NULL,
-		.maxlen		= 0,
-		.mode		= 0600,
-		.proc_handler	= &pm_do_sleep
-	},
-#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "freq",
-		.data		= NULL,
-		.maxlen		= 0,
-		.mode		= 0600,
-		.proc_handler	= &pm_do_freq
-	},
-#endif
-	{}
+static ssize_t db1x_pmattr_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *instr,
+				 size_t bytes)
+{
+	unsigned long l;
+	int tmp;
+
+	if (ATTRCMP(timer_timeout)) {
+		tmp = strict_strtoul(instr, 0, &l);
+		if (tmp)
+			return tmp;
+
+		db1x_pm_sleep_secs = l;
+
+	} else if (ATTRCMP(timer)) {
+		if (instr[0] != '0')
+			db1x_pm_wakemsk |= SYS_WAKEMSK_M2;
+		else
+			db1x_pm_wakemsk &= ~SYS_WAKEMSK_M2;
+
+	} else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
+		   ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
+		   ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
+		tmp = (attr->attr.name)[4] - '0';
+		if (instr[0] != '0')
+			db1x_pm_wakemsk |= SYS_WAKEMSK_GPIO(tmp);
+		else
+			db1x_pm_wakemsk &= ~SYS_WAKEMSK_GPIO(tmp);
+
+	} else if (ATTRCMP(uptime)) {
+		tmp = strict_strtoul(instr, 0, &l);
+		if (tmp)
+			return tmp;
+
+		while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S)
+			asm volatile ("nop");
+		au_writel(l, SYS_TOYWRITE);
+		au_sync();
+
+	} else if (ATTRCMP(wakemsk)) {
+		tmp = strict_strtoul(instr, 0, &l);
+		if (tmp)
+			return tmp;
+
+		db1x_pm_wakemsk = l & 0x0000003f;
+
+	} else
+		bytes = -ENOENT;
+
+	return bytes;
+}
+
+#define ATTR(x)							\
+	static struct kobj_attribute x##_attribute = 		\
+		__ATTR(x, 0664, db1x_pmattr_show,		\
+				db1x_pmattr_store);
+
+ATTR(gpio0)		/* GPIO-based wakeup enable */
+ATTR(gpio1)
+ATTR(gpio2)
+ATTR(gpio3)
+ATTR(gpio4)
+ATTR(gpio5)
+ATTR(gpio6)
+ATTR(gpio7)
+ATTR(timer)		/* TOYMATCH2-based wakeup enable */
+ATTR(timer_timeout)	/* timer-based wakeup timeout value, in seconds */
+ATTR(uptime)		/* contents of SYS_TOYREAD */
+ATTR(wakesrc)		/* contents of SYS_WAKESRC after last wakeup */
+ATTR(wakemsk)		/* direct access to SYS_WAKEMSK */
+
+#define ATTR_LIST(x)	& x ## _attribute.attr
+static struct attribute *db1x_pmattrs[] = {
+	ATTR_LIST(gpio0),
+	ATTR_LIST(gpio1),
+	ATTR_LIST(gpio2),
+	ATTR_LIST(gpio3),
+	ATTR_LIST(gpio4),
+	ATTR_LIST(gpio5),
+	ATTR_LIST(gpio6),
+	ATTR_LIST(gpio7),
+	ATTR_LIST(timer),
+	ATTR_LIST(timer_timeout),
+	ATTR_LIST(uptime),
+	ATTR_LIST(wakesrc),
+	ATTR_LIST(wakemsk),
+	NULL,		/* terminator */
 };
 
-static struct ctl_table pm_dir_table[] = {
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "pm",
-		.mode		= 0555,
-		.child		= pm_table
-	},
-	{}
+static struct attribute_group db1x_pmattr_group = {
+	.name	= "db1x",
+	.attrs	= db1x_pmattrs,
 };
 
 /*
@@ -615,14 +556,16 @@ static int __init pm_init(void)
 		au_sync();
 	}
 
+	db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC);
+
 	au_writel(0, SYS_WAKESRC);
 	au_sync();
 	au_writel(0, SYS_WAKEMSK);
 	au_sync();
 
-	register_sysctl_table(pm_dir_table);
+	suspend_set_ops(&db1x_pm_ops);
 
-	return 0;
+	return sysfs_create_group(power_kobj, &db1x_pmattr_group);
 }
 
 __initcall(pm_init);
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 7245960..639480e 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -1561,6 +1561,10 @@ enum soc_au1200_ints {
 #define SYS_SLPPWR		0xB1900078
 #define SYS_SLEEP		0xB190007C
 
+#define SYS_WAKEMSK_D2		(1 << 9)
+#define SYS_WAKEMSK_M2		(1 << 8)
+#define SYS_WAKEMSK_GPIO(x)	(1 << (x))
+
 /* Clock Controller */
 #define SYS_FREQCTRL0		0xB1900020
 #  define SYS_FC_FRDIV2_BIT	22
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 05/10] Alchemy: move calc_clock function.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

Now that nothing in time.c depends on calc_clock, it can
be moved to clocks.c where it belongs.
While at it, give it a better non-generic name and call it
as soon as possible in plat_mem_init.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/clocks.c |   54 ++++++++++++++++++++++++++++++++++++++
 arch/mips/au1000/common/setup.c  |    9 ++++++
 arch/mips/au1000/common/time.c   |   54 --------------------------------------
 3 files changed, 63 insertions(+), 54 deletions(-)

diff --git a/arch/mips/au1000/common/clocks.c b/arch/mips/au1000/common/clocks.c
index a8170fd..d899185 100644
--- a/arch/mips/au1000/common/clocks.c
+++ b/arch/mips/au1000/common/clocks.c
@@ -27,11 +27,21 @@
  */
 
 #include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/time.h>
 #include <asm/mach-au1x00/au1000.h>
 
+/*
+ * I haven't found anyone that doesn't use a 12 MHz source clock,
+ * but just in case.....
+ */
+#define AU1000_SRC_CLK	12000000
+
 static unsigned int au1x00_clock; /*  Hz */
 static unsigned long uart_baud_base;
 
+static DEFINE_SPINLOCK(time_lock);
+
 /*
  * Set the au1000_clock
  */
@@ -60,3 +70,47 @@ void set_au1x00_uart_baud_base(unsigned long new_baud_base)
 {
 	uart_baud_base = new_baud_base;
 }
+
+/*
+ * We read the real processor speed from the PLL.  This is important
+ * because it is more accurate than computing it from the 32 KHz
+ * counter, if it exists.  If we don't have an accurate processor
+ * speed, all of the peripherals that derive their clocks based on
+ * this advertised speed will introduce error and sometimes not work
+ * properly.  This function is futher convoluted to still allow configurations
+ * to do that in case they have really, really old silicon with a
+ * write-only PLL register.			-- Dan
+ */
+unsigned long au1xxx_calc_clock(void)
+{
+	unsigned long cpu_speed;
+	unsigned long flags;
+
+	spin_lock_irqsave(&time_lock, flags);
+
+	/*
+	 * On early Au1000, sys_cpupll was write-only. Since these
+	 * silicon versions of Au1000 are not sold by AMD, we don't bend
+	 * over backwards trying to determine the frequency.
+	 */
+	if (au1xxx_cpu_has_pll_wo())
+#ifdef CONFIG_SOC_AU1000_FREQUENCY
+		cpu_speed = CONFIG_SOC_AU1000_FREQUENCY;
+#else
+		cpu_speed = 396000000;
+#endif
+	else
+		cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
+
+	/* On Alchemy CPU:counter ratio is 1:1 */
+	mips_hpt_frequency = cpu_speed;
+	/* Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) */
+	set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)
+							  & 0x03) + 2) * 16));
+
+	spin_unlock_irqrestore(&time_lock, flags);
+
+	set_au1x00_speed(cpu_speed);
+
+	return cpu_speed;
+}
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index b6242c6..c5bd251 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -41,10 +41,19 @@ extern void __init board_setup(void);
 extern void au1000_restart(char *);
 extern void au1000_halt(void);
 extern void au1000_power_off(void);
+extern unsigned long au1xxx_calc_clock(void);
 
 void __init plat_mem_setup(void)
 {
 	char *argptr;
+	unsigned long est_freq;
+
+	/* determine core clock */
+	est_freq = au1xxx_calc_clock();
+	est_freq += 5000;    /* round */
+	est_freq -= est_freq % 10000;
+	printk(KERN_INFO "(PRId %08x) @ %lu.%02lu MHz\n", read_c0_prid(),
+	       est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
 
 	board_setup();  /* board specific setup */
 
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index fe859c1..0de9a43 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -47,53 +47,6 @@
 
 extern int allow_au1k_wait; /* default off for CP0 Counter */
 
-static DEFINE_SPINLOCK(time_lock);
-
-/*
- * I haven't found anyone that doesn't use a 12 MHz source clock,
- * but just in case.....
- */
-#define AU1000_SRC_CLK	12000000
-
-/*
- * We read the real processor speed from the PLL.  This is important
- * because it is more accurate than computing it from the 32 KHz
- * counter, if it exists.  If we don't have an accurate processor
- * speed, all of the peripherals that derive their clocks based on
- * this advertised speed will introduce error and sometimes not work
- * properly.  This function is futher convoluted to still allow configurations
- * to do that in case they have really, really old silicon with a
- * write-only PLL register.			-- Dan
- */
-unsigned long calc_clock(void)
-{
-	unsigned long cpu_speed;
-	unsigned long flags;
-
-	spin_lock_irqsave(&time_lock, flags);
-
-	/*
-	 * On early Au1000, sys_cpupll was write-only. Since these
-	 * silicon versions of Au1000 are not sold by AMD, we don't bend
-	 * over backwards trying to determine the frequency.
-	 */
-	if (au1xxx_cpu_has_pll_wo())
-#ifdef CONFIG_SOC_AU1000_FREQUENCY
-		cpu_speed = CONFIG_SOC_AU1000_FREQUENCY;
-#else
-		cpu_speed = 396000000;
-#endif
-	else
-		cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
-	/* On Alchemy CPU:counter ratio is 1:1 */
-	mips_hpt_frequency = cpu_speed;
-	/* Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) */
-	set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)
-							  & 0x03) + 2) * 16));
-	spin_unlock_irqrestore(&time_lock, flags);
-	return cpu_speed;
-}
-
 static cycle_t au1x_counter1_read(void)
 {
 	return au_readl(SYS_RTCREAD);
@@ -148,13 +101,6 @@ void __init plat_time_init(void)
 {
 	struct clock_event_device *cd = &au1x_rtcmatch2_clockdev;
 	unsigned long t;
-	unsigned int est_freq = calc_clock();
-
-	est_freq += 5000;    /* round */
-	est_freq -= est_freq%10000;
-	printk(KERN_INFO "(PRId %08x) @ %u.%02u MHz\n", read_c0_prid(),
-	       est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
-	set_au1x00_speed(est_freq);
 
 	/* Check if firmware (YAMON, ...) has enabled 32kHz and clock
 	 * has been detected.  If so install the rtcmatch2 clocksource,
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 09/10] Alchemy: dbdma suspend/resume support.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

Implement suspend/resume for DBDMA controller and its channels.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/dbdma.c |   65 +++++++++++++++++++++++++++++++++++++++
 arch/mips/au1000/common/power.c |   12 +++++++
 2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index 601ee91..3ab6d80 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -174,6 +174,11 @@ static dbdev_tab_t dbdev_tab[] = {
 
 #define DBDEV_TAB_SIZE	ARRAY_SIZE(dbdev_tab)
 
+#ifdef CONFIG_PM
+static u32 au1xxx_dbdma_pm_regs[NUM_DBDMA_CHANS + 1][8];
+#endif
+
+
 static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS];
 
 static dbdev_tab_t *find_dbdev_id(u32 id)
@@ -975,4 +980,64 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
 	return nbytes;
 }
 
+#ifdef CONFIG_PM
+void au1xxx_dbdma_suspend(void)
+{
+	int i;
+	u32 addr;
+
+	addr = DDMA_GLOBAL_BASE;
+	au1xxx_dbdma_pm_regs[0][0] = au_readl(addr + 0x00);
+	au1xxx_dbdma_pm_regs[0][1] = au_readl(addr + 0x04);
+	au1xxx_dbdma_pm_regs[0][2] = au_readl(addr + 0x08);
+	au1xxx_dbdma_pm_regs[0][3] = au_readl(addr + 0x0c);
+
+	/* save channel configurations */
+	for (i = 1, addr = DDMA_CHANNEL_BASE; i < NUM_DBDMA_CHANS; i++) {
+		au1xxx_dbdma_pm_regs[i][0] = au_readl(addr + 0x00);
+		au1xxx_dbdma_pm_regs[i][1] = au_readl(addr + 0x04);
+		au1xxx_dbdma_pm_regs[i][2] = au_readl(addr + 0x08);
+		au1xxx_dbdma_pm_regs[i][3] = au_readl(addr + 0x0c);
+		au1xxx_dbdma_pm_regs[i][4] = au_readl(addr + 0x10);
+		au1xxx_dbdma_pm_regs[i][5] = au_readl(addr + 0x14);
+		au1xxx_dbdma_pm_regs[i][6] = au_readl(addr + 0x18);
+
+		/* halt channel */
+		au_writel(au1xxx_dbdma_pm_regs[i][0] & ~1, addr + 0x00);
+		au_sync();
+		while (!(au_readl(addr + 0x14) & 1))
+			au_sync();
+
+		addr += 0x100;	/* next channel base */
+	}
+	/* disable channel interrupts */
+	au_writel(0, DDMA_GLOBAL_BASE + 0x0c);
+	au_sync();
+}
+
+void au1xxx_dbdma_resume(void)
+{
+	int i;
+	u32 addr;
+
+	addr = DDMA_GLOBAL_BASE;
+	au_writel(au1xxx_dbdma_pm_regs[0][0], addr + 0x00);
+	au_writel(au1xxx_dbdma_pm_regs[0][1], addr + 0x04);
+	au_writel(au1xxx_dbdma_pm_regs[0][2], addr + 0x08);
+	au_writel(au1xxx_dbdma_pm_regs[0][3], addr + 0x0c);
+
+	/* restore channel configurations */
+	for (i = 1, addr = DDMA_CHANNEL_BASE; i < NUM_DBDMA_CHANS; i++) {
+		au_writel(au1xxx_dbdma_pm_regs[i][0], addr + 0x00);
+		au_writel(au1xxx_dbdma_pm_regs[i][1], addr + 0x04);
+		au_writel(au1xxx_dbdma_pm_regs[i][2], addr + 0x08);
+		au_writel(au1xxx_dbdma_pm_regs[i][3], addr + 0x0c);
+		au_writel(au1xxx_dbdma_pm_regs[i][4], addr + 0x10);
+		au_writel(au1xxx_dbdma_pm_regs[i][5], addr + 0x14);
+		au_writel(au1xxx_dbdma_pm_regs[i][6], addr + 0x18);
+		au_sync();
+		addr += 0x100;	/* next channel base */
+	}
+}
+#endif	/* CONFIG_PM */
 #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index ba4c946..1057a73 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -33,6 +33,10 @@
 extern void save_and_sleep(void);
 extern void save_au1xxx_intctl(void);
 extern void restore_au1xxx_intctl(void);
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+extern void au1xxx_dbdma_suspend(void);
+extern void au1xxx_dbdma_resume(void);
+#endif
 
 /*
  * We need to save/restore a bunch of core registers that are
@@ -120,6 +124,10 @@ static void save_core_regs(void)
 	sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3);
 	sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3);
 	sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3);
+
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+	au1xxx_dbdma_suspend();
+#endif
 }
 
 static void restore_core_regs(void)
@@ -185,6 +193,10 @@ static void restore_core_regs(void)
 	}
 
 	restore_au1xxx_intctl();
+
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+	au1xxx_dbdma_resume();
+#endif
 }
 
 void au_sleep(void)
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 08/10] Alchemy: Fix PM code for Au1200/Au1550.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

Alchemy PM code doesn't compile on Au1200.
Copy the Au1200/Au1550 sleep code over from 2.4.

Tested on Au1200.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/platform.c |    5 +-
 arch/mips/au1000/common/power.c    |  111 +++++++++++++++++++++------------
 arch/mips/au1000/common/sleeper.S  |  121 ++++++++++++++++++++++--------------
 3 files changed, 150 insertions(+), 87 deletions(-)

diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index 8d0f05a..b5ff42a 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -419,6 +419,7 @@ static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
 	return 0;
 }
 
+#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
 /*
  * This is the number of bits of precision for the loops_per_jiffy.
  * Each bit takes on average 1.5/HZ seconds.  This (like the original)
@@ -566,7 +567,7 @@ static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
 
 	return retval;
 }
-
+#endif
 
 static struct ctl_table pm_table[] = {
 	{
@@ -577,6 +578,7 @@ static struct ctl_table pm_table[] = {
 		.mode		= 0600,
 		.proc_handler	= &pm_do_sleep
 	},
+#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
 	{
 		.ctl_name	= CTL_UNNUMBERED,
 		.procname	= "freq",
@@ -585,6 +587,7 @@ static struct ctl_table pm_table[] = {
 		.mode		= 0600,
 		.proc_handler	= &pm_do_freq
 	},
+#endif
 	{}
 };
 
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 4b0f6a1..ba4c946 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -26,13 +26,13 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
-#include <asm/cacheflush.h>
-#include <asm/mach-au1x00/au1000.h>
-
 #ifdef CONFIG_PM
 
+#include <asm/mach-au1x00/au1000.h>
+
 extern void save_and_sleep(void);
+extern void save_au1xxx_intctl(void);
+extern void restore_au1xxx_intctl(void);
 
 /*
  * We need to save/restore a bunch of core registers that are
@@ -44,23 +44,18 @@ extern void save_and_sleep(void);
  * We only have to save/restore registers that aren't otherwise
  * done as part of a driver pm_* function.
  */
-static unsigned int	sleep_aux_pll_cntrl;
-static unsigned int	sleep_cpu_pll_cntrl;
-static unsigned int	sleep_pin_function;
-static unsigned int	sleep_uart0_inten;
-static unsigned int	sleep_uart0_fifoctl;
-static unsigned int	sleep_uart0_linectl;
-static unsigned int	sleep_uart0_clkdiv;
-static unsigned int	sleep_uart0_enable;
-static unsigned int	sleep_usbhost_enable;
-static unsigned int	sleep_usbdev_enable;
-static unsigned int	sleep_static_memctlr[4][3];
+static unsigned int sleep_uart0_inten;
+static unsigned int sleep_uart0_fifoctl;
+static unsigned int sleep_uart0_linectl;
+static unsigned int sleep_uart0_clkdiv;
+static unsigned int sleep_uart0_enable;
+static unsigned int sleep_usb[2];
+static unsigned int sleep_sys_clocks[5];
+static unsigned int sleep_sys_pinfunc;
+static unsigned int sleep_static_memctlr[4][3];
 
 static void save_core_regs(void)
 {
-	extern void save_au1xxx_intctl(void);
-	extern void pm_eth0_shutdown(void);
-
 	/*
 	 * Do the serial ports.....these really should be a pm_*
 	 * registered function by the driver......but of course the
@@ -72,31 +67,45 @@ static void save_core_regs(void)
 	sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR);
 	sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK);
 	sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL);
+	au_sync();
 
+#ifndef CONFIG_SOC_AU1200
 	/* Shutdown USB host/device. */
-	sleep_usbhost_enable = au_readl(USB_HOST_CONFIG);
+	sleep_usb[0] = au_readl(USB_HOST_CONFIG);
 
 	/* There appears to be some undocumented reset register.... */
-	au_writel(0, 0xb0100004); au_sync();
-	au_writel(0, USB_HOST_CONFIG); au_sync();
+	au_writel(0, 0xb0100004);
+	au_sync();
+	au_writel(0, USB_HOST_CONFIG);
+	au_sync();
+
+	sleep_usb[1] = au_readl(USBD_ENABLE);
+	au_writel(0, USBD_ENABLE);
+	au_sync();
 
-	sleep_usbdev_enable = au_readl(USBD_ENABLE);
-	au_writel(0, USBD_ENABLE); au_sync();
+#else	/* AU1200 */
+
+	/* enable access to OTG mmio so we can save OTG CAP/MUX.
+	 * FIXME: write an OTG driver and move this stuff there!
+	 */
+	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
+	au_sync();
+	sleep_usb[0] = au_readl(0xb4020020);	/* OTG_CAP */
+	sleep_usb[1] = au_readl(0xb4020024);	/* OTG_MUX */
+#endif
 
 	/* Save interrupt controller state. */
 	save_au1xxx_intctl();
 
 	/* Clocks and PLLs. */
-	sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL);
-
-	/*
-	 * We don't really need to do this one, but unless we
-	 * write it again it won't have a valid value if we
-	 * happen to read it.
-	 */
-	sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL);
+	sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0);
+	sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1);
+	sleep_sys_clocks[2] = au_readl(SYS_CLKSRC);
+	sleep_sys_clocks[3] = au_readl(SYS_CPUPLL);
+	sleep_sys_clocks[4] = au_readl(SYS_AUXPLL);
 
-	sleep_pin_function = au_readl(SYS_PINFUNC);
+	/* pin mux config */
+	sleep_sys_pinfunc = au_readl(SYS_PINFUNC);
 
 	/* Save the static memory controller configuration. */
 	sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0);
@@ -115,12 +124,37 @@ static void save_core_regs(void)
 
 static void restore_core_regs(void)
 {
-	extern void restore_au1xxx_intctl(void);
-	extern void wakeup_counter0_adjust(void);
-
-	au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync();
-	au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync();
-	au_writel(sleep_pin_function, SYS_PINFUNC); au_sync();
+	/* restore clock configuration.  Writing CPUPLL last will
+	 * stall a bit and stabilize other clocks (unless this is
+	 * one of those Au1000 with a write-only PLL, where we dont
+	 * have a valid value)
+	 */
+	au_writel(sleep_sys_clocks[0], SYS_FREQCTRL0);
+	au_writel(sleep_sys_clocks[1], SYS_FREQCTRL1);
+	au_writel(sleep_sys_clocks[2], SYS_CLKSRC);
+	au_writel(sleep_sys_clocks[4], SYS_AUXPLL);
+	if (!au1xxx_cpu_has_pll_wo())
+		au_writel(sleep_sys_clocks[3], SYS_CPUPLL);
+	au_sync();
+
+	au_writel(sleep_sys_pinfunc, SYS_PINFUNC);
+	au_sync();
+
+#ifndef CONFIG_SOC_AU1200
+	au_writel(sleep_usb[0], USB_HOST_CONFIG);
+	au_writel(sleep_usb[1], USBD_ENABLE);
+	au_sync();
+#else
+	/* enable accces to OTG memory */
+	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
+	au_sync();
+
+	/* restore OTG caps and port mux. */
+	au_writel(sleep_usb[0], 0xb4020020 + 0);	/* OTG_CAP */
+	au_sync();
+	au_writel(sleep_usb[1], 0xb4020020 + 4);	/* OTG_MUX */
+	au_sync();
+#endif
 
 	/* Restore the static memory controller configuration. */
 	au_writel(sleep_static_memctlr[0][0], MEM_STCFG0);
@@ -156,7 +190,6 @@ static void restore_core_regs(void)
 void au_sleep(void)
 {
 	save_core_regs();
-	flush_cache_all();
 	save_and_sleep();
 	restore_core_regs();
 }
diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S
index 4b3cf02..76506aa 100644
--- a/arch/mips/au1000/common/sleeper.S
+++ b/arch/mips/au1000/common/sleeper.S
@@ -15,9 +15,11 @@
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 
+	.extern __flush_cache_all
+
 	.text
-	.set	macro
-	.set	noat
+	.set noreorder
+	.set noat
 	.align	5
 
 /* Save all of the processor general registers and go to sleep.
@@ -33,14 +35,6 @@ LEAF(save_and_sleep)
 	sw	$5, PT_R5(sp)
 	sw	$6, PT_R6(sp)
 	sw	$7, PT_R7(sp)
-	sw	$8, PT_R8(sp)
-	sw	$9, PT_R9(sp)
-	sw	$10, PT_R10(sp)
-	sw	$11, PT_R11(sp)
-	sw	$12, PT_R12(sp)
-	sw	$13, PT_R13(sp)
-	sw	$14, PT_R14(sp)
-	sw	$15, PT_R15(sp)
 	sw	$16, PT_R16(sp)
 	sw	$17, PT_R17(sp)
 	sw	$18, PT_R18(sp)
@@ -49,12 +43,9 @@ LEAF(save_and_sleep)
 	sw	$21, PT_R21(sp)
 	sw	$22, PT_R22(sp)
 	sw	$23, PT_R23(sp)
-	sw	$24, PT_R24(sp)
-	sw	$25, PT_R25(sp)
 	sw	$26, PT_R26(sp)
 	sw	$27, PT_R27(sp)
 	sw	$28, PT_R28(sp)
-	sw	$29, PT_R29(sp)
 	sw	$30, PT_R30(sp)
 	sw	$31, PT_R31(sp)
 	mfc0	k0, CP0_STATUS
@@ -66,44 +57,89 @@ LEAF(save_and_sleep)
 	mfc0	k0, CP0_CONFIG
 	sw	k0, 0x14(sp)
 
+	/* flush caches to make sure context is in memory */
+	la	t1, __flush_cache_all
+	lw	t0, 0(t1)
+	jal	t0
+	 nop
+
 	/* Now set up the scratch registers so the boot rom will
 	 * return to this point upon wakeup.
+	 * sys_scratch0 : SP
+	 * sys_scratch1 : RA
 	 */
-	la	k0, 1f
-	lui	k1, 0xb190
-	ori	k1, 0x18
-	sw	sp, 0(k1)
-	ori 	k1, 0x1c
-	sw	k0, 0(k1)
-
-/* Put SDRAM into self refresh.  Preload instructions into cache,
- * issue a precharge, then auto refresh, then sleep commands to it.
- */
- 	la	t0, sdsleep
+	li	t3, 0xb1900000		/* sys_xxx */
+	sw	sp, 0x0018(t3)
+	la	k0, resume_from_sleep
+	sw	k0, 0x001c(t3)
+
+	/* Put SDRAM into self refresh.  Preload instructions into cache,
+	 * issue a precharge, then auto refresh, then sleep commands to it.
+	 */
+	la	t0, sdsleep
 	.set	mips3
- 	cache	0x14, 0(t0)
- 	cache	0x14, 32(t0)
- 	cache	0x14, 64(t0)
- 	cache	0x14, 96(t0)
+	cache	0x14, 0(t0)
+	cache	0x14, 32(t0)
+	cache	0x14, 64(t0)
+	cache	0x14, 96(t0)
 	.set	mips0
 
 sdsleep:
-	lui 	k0, 0xb400
-	sw	zero, 0x001c(k0)	/* Precharge */
-	sw	zero, 0x0020(k0)	/* Auto refresh */
-	sw	zero, 0x0030(k0)	/* SDRAM sleep */
+	li 	a0, 0xb4000000		/* mem_xxx */
+#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100) ||	\
+    defined(CONFIG_SOC_AU1500)
+	sw	zero, 0x001c(a0) 	/* Precharge */
+	sync
+	sw	zero, 0x0020(a0)	/* Auto Refresh */
+	sync
+	sw	zero, 0x0030(a0)  	/* Sleep */
 	sync
+#endif
 
-	lui 	k1, 0xb190
-	sw	zero, 0x0078(k1)	/* get ready  to sleep */
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+	sw	zero, 0x08c0(a0) 	/* Precharge */
 	sync
-	sw	zero, 0x007c(k1)	/* Put processor to sleep */
+	sw	zero, 0x08d0(a0)	/* Self Refresh */
 	sync
 
+	/* wait for sdram to enter self-refresh mode */
+	li 	t0, 0x01000000
+sref_wait_loop:
+	lw 	t1, 0x0850(a0)		/* mem_sdstat */
+	and	t2, t1, t0
+	beq	t2, zero, sref_wait_loop
+	 nop
+
+	/* Disable SDRAM clocks */
+	li	t0, ~0x30000000
+	lw 	t1, 0x0840(a0)		/* mem_sdconfiga */
+	and 	t1, t0, t1		/* clear CE[1:0] */
+	sw 	t1, 0x0840(a0)		/* mem_sdconfiga */
+	sync
+#endif
+
+	/* put power supply and processor to sleep */
+	sw	zero, 0x0078(t3)	/* sys_slppwr */
+	sync
+	sw	zero, 0x007c(t3)	/* sys_sleep */
+	sync
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
 	/* This is where we return upon wakeup.
 	 * Reload all of the registers and return.
 	 */
-1:	nop
+resume_from_sleep:
+	nop
+	.set nomacro
+	.set noat
+
 	lw	k0, 0x20(sp)
 	mtc0	k0, CP0_STATUS
 	lw	k0, 0x1c(sp)
@@ -117,6 +153,7 @@ sdsleep:
 	 * the write-only Config[OD] bit and set it back to one...
 	 */
 	jal	au1x00_fixup_config_od
+	 nop
 	lw	$1, PT_R1(sp)
 	lw	$2, PT_R2(sp)
 	lw	$3, PT_R3(sp)
@@ -124,14 +161,6 @@ sdsleep:
 	lw	$5, PT_R5(sp)
 	lw	$6, PT_R6(sp)
 	lw	$7, PT_R7(sp)
-	lw	$8, PT_R8(sp)
-	lw	$9, PT_R9(sp)
-	lw	$10, PT_R10(sp)
-	lw	$11, PT_R11(sp)
-	lw	$12, PT_R12(sp)
-	lw	$13, PT_R13(sp)
-	lw	$14, PT_R14(sp)
-	lw	$15, PT_R15(sp)
 	lw	$16, PT_R16(sp)
 	lw	$17, PT_R17(sp)
 	lw	$18, PT_R18(sp)
@@ -140,15 +169,13 @@ sdsleep:
 	lw	$21, PT_R21(sp)
 	lw	$22, PT_R22(sp)
 	lw	$23, PT_R23(sp)
-	lw	$24, PT_R24(sp)
-	lw	$25, PT_R25(sp)
 	lw	$26, PT_R26(sp)
 	lw	$27, PT_R27(sp)
 	lw	$28, PT_R28(sp)
-	lw	$29, PT_R29(sp)
 	lw	$30, PT_R30(sp)
 	lw	$31, PT_R31(sp)
 	addiu	sp, PT_SIZE
 
 	jr	ra
+	 nop
 END(save_and_sleep)
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 07/10] Alchemy: split core PM code from sysctl parts.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

The Alchemy power.c file contains both core suspend/resume code, which
is processor specific, and leftovers of the 2.4 PM userspace interface
(sysctls).

This patch moves the userspace interface to the platform.c file and
leaves the core board-independent suspend/resume parts which should be
usable for all Alchemy-based systems intact.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/platform.c |  305 ++++++++++++++++++++++++++++++++++-
 arch/mips/au1000/common/power.c    |  318 +-----------------------------------
 2 files changed, 306 insertions(+), 317 deletions(-)

diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index 66d6770..8d0f05a 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -6,6 +6,9 @@
  * (C) Copyright Embedded Alley Solutions, Inc 2005
  * Author: Pantelis Antoniou <pantelis@embeddedalley.com>
  *
+ *  Some of the routines are right out of init/main.c, whose
+ *  copyrights apply here.
+ *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
@@ -19,7 +22,11 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
-#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <linux/uaccess.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
 
@@ -322,3 +329,299 @@ static int __init au1xxx_platform_init(void)
 }
 
 arch_initcall(au1xxx_platform_init);
+
+
+/*********************************************************************/
+
+
+#ifdef CONFIG_PM
+
+static DEFINE_SPINLOCK(pm_lock);
+
+extern unsigned long save_local_and_disable(int controller);
+extern void restore_local_and_enable(int controller, unsigned long mask);
+extern void local_enable_irq(unsigned int irq_nr);
+extern void au_sleep(void);
+
+/*
+ * Define this to cause the value you write to /proc/sys/pm/sleep to
+ * set the TOY timer for the amount of time you want to sleep.
+ * This is done mainly for testing, but may be useful in other cases.
+ * The value is number of 32KHz ticks to sleep.
+ */
+#define SLEEP_TEST_TIMEOUT 1
+#ifdef	SLEEP_TEST_TIMEOUT
+static int sleep_ticks;
+static void wakeup_counter0_set(int ticks)
+{
+	au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
+	au_sync();
+}
+#endif
+
+static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
+		       void __user *buffer, size_t *len, loff_t *ppos)
+{
+	unsigned long wakeup, flags;
+#ifdef SLEEP_TEST_TIMEOUT
+#define TMPBUFLEN2 16
+	char buf[TMPBUFLEN2], *p;
+#endif
+
+	spin_lock_irqsave(&pm_lock, flags);
+
+	if (!write) {
+		*len = 0;
+		spin_unlock_irqrestore(&pm_lock, flags);
+		return 0;
+	}
+
+#ifdef SLEEP_TEST_TIMEOUT
+	if (*len > TMPBUFLEN2 - 1)
+		return -EFAULT;
+	if (copy_from_user(buf, buffer, *len))
+		return -EFAULT;
+	buf[*len] = 0;
+	p = buf;
+	sleep_ticks = simple_strtoul(p, &p, 0);
+#endif
+
+	/**
+	 ** The code below is all system dependent and we should probably
+	 ** have a function call out of here to set this up.  You need
+	 ** to configure the GPIO or timer interrupts that will bring
+	 ** you out of sleep.
+	 ** For testing, the TOY counter wakeup is useful.
+	 **/
+#if 0
+	au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
+
+	/* GPIO 6 can cause a wake up event */
+	wakeup = au_readl(SYS_WAKEMSK);
+	wakeup &= ~(1 << 8);	/* turn off match20 wakeup */
+	wakeup |= 1 << 6;	/* turn on  GPIO  6 wakeup */
+#else
+	/* For testing, allow match20 to wake us up. */
+#ifdef SLEEP_TEST_TIMEOUT
+	wakeup_counter0_set(sleep_ticks);
+#endif
+	wakeup = 1 << 8;	/* turn on match20 wakeup   */
+#endif
+	au_writel(1, SYS_WAKESRC);	/* clear cause */
+	au_sync();
+	au_writel(wakeup, SYS_WAKEMSK);
+	au_sync();
+
+	au_sleep();
+
+	spin_unlock_irqrestore(&pm_lock, flags);
+
+	return 0;
+}
+
+/*
+ * This is the number of bits of precision for the loops_per_jiffy.
+ * Each bit takes on average 1.5/HZ seconds.  This (like the original)
+ * is a little better than 1%.
+ */
+#define LPS_PREC 8
+
+static void au1000_calibrate_delay(void)
+{
+	unsigned long ticks, loopbit;
+	int lps_precision = LPS_PREC;
+
+	loops_per_jiffy = 1 << 12;
+
+	while (loops_per_jiffy <<= 1) {
+		/* Wait for "start of" clock tick */
+		ticks = jiffies;
+		while (ticks == jiffies)
+			/* nothing */ ;
+		/* Go ... */
+		ticks = jiffies;
+		__delay(loops_per_jiffy);
+		ticks = jiffies - ticks;
+		if (ticks)
+			break;
+	}
+
+	/*
+	 * Do a binary approximation to get loops_per_jiffy set to be equal
+	 * one clock (up to lps_precision bits)
+	 */
+	loops_per_jiffy >>= 1;
+	loopbit = loops_per_jiffy;
+	while (lps_precision-- && (loopbit >>= 1)) {
+		loops_per_jiffy |= loopbit;
+		ticks = jiffies;
+		while (ticks == jiffies);
+		ticks = jiffies;
+		__delay(loops_per_jiffy);
+		if (jiffies != ticks)	/* longer than 1 tick */
+			loops_per_jiffy &= ~loopbit;
+	}
+}
+
+static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
+		      void __user *buffer, size_t *len, loff_t *ppos)
+{
+	int retval = 0, i;
+	unsigned long val, pll;
+#define TMPBUFLEN 64
+#define MAX_CPU_FREQ 396
+	char buf[TMPBUFLEN], *p;
+	unsigned long flags, intc0_mask, intc1_mask;
+	unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh;
+	unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
+	unsigned long baud_rate;
+
+	spin_lock_irqsave(&pm_lock, flags);
+	if (!write)
+		*len = 0;
+	else {
+		/* Parse the new frequency */
+		if (*len > TMPBUFLEN - 1) {
+			spin_unlock_irqrestore(&pm_lock, flags);
+			return -EFAULT;
+		}
+		if (copy_from_user(buf, buffer, *len)) {
+			spin_unlock_irqrestore(&pm_lock, flags);
+			return -EFAULT;
+		}
+		buf[*len] = 0;
+		p = buf;
+		val = simple_strtoul(p, &p, 0);
+		if (val > MAX_CPU_FREQ) {
+			spin_unlock_irqrestore(&pm_lock, flags);
+			return -EFAULT;
+		}
+
+		pll = val / 12;
+		if ((pll > 33) || (pll < 7)) {	/* 396 MHz max, 84 MHz min */
+			/* Revisit this for higher speed CPUs */
+			spin_unlock_irqrestore(&pm_lock, flags);
+			return -EFAULT;
+		}
+
+		old_baud_base = get_au1x00_uart_baud_base();
+		old_cpu_freq = get_au1x00_speed();
+
+		new_cpu_freq = pll * 12 * 1000000;
+	        new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)
+							    & 0x03) + 2) * 16));
+		set_au1x00_speed(new_cpu_freq);
+		set_au1x00_uart_baud_base(new_baud_base);
+
+		old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
+		new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) |
+			      (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
+
+		au_writel(pll, SYS_CPUPLL);
+		au_sync_delay(1);
+		au_writel(new_refresh, MEM_SDREFCFG);
+		au_sync_delay(1);
+
+		for (i = 0; i < 4; i++)
+			if (au_readl(UART_BASE + UART_MOD_CNTRL +
+				     i * 0x00100000) == 3) {
+				old_clk = au_readl(UART_BASE + UART_CLK +
+						   i * 0x00100000);
+				baud_rate = old_baud_base / old_clk;
+				/*
+				 * We won't get an exact baud rate and the error
+				 * could be significant enough that our new
+				 * calculation will result in a clock that will
+				 * give us a baud rate that's too far off from
+				 * what we really want.
+				 */
+				if (baud_rate > 100000)
+					baud_rate = 115200;
+				else if (baud_rate > 50000)
+					baud_rate = 57600;
+				else if (baud_rate > 30000)
+					baud_rate = 38400;
+				else if (baud_rate > 17000)
+					baud_rate = 19200;
+				else
+					baud_rate = 9600;
+				new_clk = new_baud_base / baud_rate;
+				au_writel(new_clk, UART_BASE + UART_CLK +
+					  i * 0x00100000);
+				au_sync_delay(10);
+			}
+	}
+
+	/*
+	 * We don't want _any_ interrupts other than match20. Otherwise our
+	 * au1000_calibrate_delay() calculation will be off, potentially a lot.
+	 */
+	intc0_mask = save_local_and_disable(0);
+	intc1_mask = save_local_and_disable(1);
+	local_enable_irq(AU1000_TOY_MATCH2_INT);
+	spin_unlock_irqrestore(&pm_lock, flags);
+	au1000_calibrate_delay();
+	restore_local_and_enable(0, intc0_mask);
+	restore_local_and_enable(1, intc1_mask);
+
+	return retval;
+}
+
+
+static struct ctl_table pm_table[] = {
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "sleep",
+		.data		= NULL,
+		.maxlen		= 0,
+		.mode		= 0600,
+		.proc_handler	= &pm_do_sleep
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "freq",
+		.data		= NULL,
+		.maxlen		= 0,
+		.mode		= 0600,
+		.proc_handler	= &pm_do_freq
+	},
+	{}
+};
+
+static struct ctl_table pm_dir_table[] = {
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "pm",
+		.mode		= 0555,
+		.child		= pm_table
+	},
+	{}
+};
+
+/*
+ * Initialize power interface
+ */
+static int __init pm_init(void)
+{
+	/* init TOY to tick at 1Hz. No need to wait for access bits
+	 * since there's plenty of time between here and the first
+	 * suspend cycle.
+	 */
+	if (au_readl(SYS_TOYTRIM) != 32767) {
+		au_writel(32767, SYS_TOYTRIM);
+		au_sync();
+	}
+
+	au_writel(0, SYS_WAKESRC);
+	au_sync();
+	au_writel(0, SYS_WAKEMSK);
+	au_sync();
+
+	register_sysctl_table(pm_dir_table);
+
+	return 0;
+}
+
+__initcall(pm_init);
+
+#endif	/* CONFIG_PM */
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 7812ebf..4b0f6a1 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -5,9 +5,6 @@
  * Copyright 2001, 2008 MontaVista Software Inc.
  * Author: MontaVista Software, Inc. <source@mvista.com>
  *
- *  Some of the routines are right out of init/main.c, whose
- *  copyrights apply here.
- *
  *  This program is free software; you can redistribute	 it and/or modify it
  *  under  the terms of	 the GNU General  Public License as published by the
  *  Free Software Foundation;  either version 2 of the	License, or (at your
@@ -30,30 +27,12 @@
  */
 
 #include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/sysctl.h>
-#include <linux/jiffies.h>
-
-#include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/mach-au1x00/au1000.h>
 
 #ifdef CONFIG_PM
 
-#define DEBUG 1
-#ifdef	DEBUG
-#define DPRINTK(fmt, args...)	printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-static void au1000_calibrate_delay(void);
-
-extern unsigned long save_local_and_disable(int controller);
-extern void restore_local_and_enable(int controller, unsigned long mask);
-extern void local_enable_irq(unsigned int irq_nr);
-
-static DEFINE_SPINLOCK(pm_lock);
+extern void save_and_sleep(void);
 
 /*
  * We need to save/restore a bunch of core registers that are
@@ -77,22 +56,6 @@ static unsigned int	sleep_usbhost_enable;
 static unsigned int	sleep_usbdev_enable;
 static unsigned int	sleep_static_memctlr[4][3];
 
-/*
- * Define this to cause the value you write to /proc/sys/pm/sleep to
- * set the TOY timer for the amount of time you want to sleep.
- * This is done mainly for testing, but may be useful in other cases.
- * The value is number of 32KHz ticks to sleep.
- */
-#define SLEEP_TEST_TIMEOUT 1
-#ifdef	SLEEP_TEST_TIMEOUT
-static int sleep_ticks;
-static void wakeup_counter0_set(int ticks)
-{
-	au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
-	au_sync();
-}
-#endif
-
 static void save_core_regs(void)
 {
 	extern void save_au1xxx_intctl(void);
@@ -190,288 +153,11 @@ static void restore_core_regs(void)
 	restore_au1xxx_intctl();
 }
 
-unsigned long suspend_mode;
-
-void wakeup_from_suspend(void)
-{
-	suspend_mode = 0;
-}
-
-int au_sleep(void)
+void au_sleep(void)
 {
-	unsigned long wakeup, flags;
-	extern void save_and_sleep(void);
-
-	spin_lock_irqsave(&pm_lock, flags);
-
 	save_core_regs();
-
 	flush_cache_all();
-
-	/**
-	 ** The code below is all system dependent and we should probably
-	 ** have a function call out of here to set this up.  You need
-	 ** to configure the GPIO or timer interrupts that will bring
-	 ** you out of sleep.
-	 ** For testing, the TOY counter wakeup is useful.
-	 **/
-#if 0
-	au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
-
-	/* GPIO 6 can cause a wake up event */
-	wakeup = au_readl(SYS_WAKEMSK);
-	wakeup &= ~(1 << 8);	/* turn off match20 wakeup */
-	wakeup |= 1 << 6;	/* turn on  GPIO  6 wakeup */
-#else
-	/* For testing, allow match20 to wake us up. */
-#ifdef SLEEP_TEST_TIMEOUT
-	wakeup_counter0_set(sleep_ticks);
-#endif
-	wakeup = 1 << 8;	/* turn on match20 wakeup   */
-	wakeup = 0;
-#endif
-	au_writel(1, SYS_WAKESRC);	/* clear cause */
-	au_sync();
-	au_writel(wakeup, SYS_WAKEMSK);
-	au_sync();
-
 	save_and_sleep();
-
-	/*
-	 * After a wakeup, the cpu vectors back to 0x1fc00000, so
-	 * it's up to the boot code to get us back here.
-	 */
 	restore_core_regs();
-	spin_unlock_irqrestore(&pm_lock, flags);
-	return 0;
-}
-
-static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
-		       void __user *buffer, size_t *len, loff_t *ppos)
-{
-#ifdef SLEEP_TEST_TIMEOUT
-#define TMPBUFLEN2 16
-	char buf[TMPBUFLEN2], *p;
-#endif
-
-	if (!write)
-		*len = 0;
-	else {
-#ifdef SLEEP_TEST_TIMEOUT
-		if (*len > TMPBUFLEN2 - 1)
-			return -EFAULT;
-		if (copy_from_user(buf, buffer, *len))
-			return -EFAULT;
-		buf[*len] = 0;
-		p = buf;
-		sleep_ticks = simple_strtoul(p, &p, 0);
-#endif
-
-		au_sleep();
-	}
-	return 0;
-}
-
-static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
-		      void __user *buffer, size_t *len, loff_t *ppos)
-{
-	int retval = 0, i;
-	unsigned long val, pll;
-#define TMPBUFLEN 64
-#define MAX_CPU_FREQ 396
-	char buf[TMPBUFLEN], *p;
-	unsigned long flags, intc0_mask, intc1_mask;
-	unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh;
-	unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
-	unsigned long baud_rate;
-
-	spin_lock_irqsave(&pm_lock, flags);
-	if (!write)
-		*len = 0;
-	else {
-		/* Parse the new frequency */
-		if (*len > TMPBUFLEN - 1) {
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-		if (copy_from_user(buf, buffer, *len)) {
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-		buf[*len] = 0;
-		p = buf;
-		val = simple_strtoul(p, &p, 0);
-		if (val > MAX_CPU_FREQ) {
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-
-		pll = val / 12;
-		if ((pll > 33) || (pll < 7)) {	/* 396 MHz max, 84 MHz min */
-			/* Revisit this for higher speed CPUs */
-			spin_unlock_irqrestore(&pm_lock, flags);
-			return -EFAULT;
-		}
-
-		old_baud_base = get_au1x00_uart_baud_base();
-		old_cpu_freq = get_au1x00_speed();
-
-		new_cpu_freq = pll * 12 * 1000000;
-	        new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)
-							    & 0x03) + 2) * 16));
-		set_au1x00_speed(new_cpu_freq);
-		set_au1x00_uart_baud_base(new_baud_base);
-
-		old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
-		new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) |
-			      (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
-
-		au_writel(pll, SYS_CPUPLL);
-		au_sync_delay(1);
-		au_writel(new_refresh, MEM_SDREFCFG);
-		au_sync_delay(1);
-
-		for (i = 0; i < 4; i++)
-			if (au_readl(UART_BASE + UART_MOD_CNTRL +
-				     i * 0x00100000) == 3) {
-				old_clk = au_readl(UART_BASE + UART_CLK +
-						   i * 0x00100000);
-				baud_rate = old_baud_base / old_clk;
-				/*
-				 * We won't get an exact baud rate and the error
-				 * could be significant enough that our new
-				 * calculation will result in a clock that will
-				 * give us a baud rate that's too far off from
-				 * what we really want.
-				 */
-				if (baud_rate > 100000)
-					baud_rate = 115200;
-				else if (baud_rate > 50000)
-					baud_rate = 57600;
-				else if (baud_rate > 30000)
-					baud_rate = 38400;
-				else if (baud_rate > 17000)
-					baud_rate = 19200;
-				else
-					baud_rate = 9600;
-				new_clk = new_baud_base / baud_rate;
-				au_writel(new_clk, UART_BASE + UART_CLK +
-					  i * 0x00100000);
-				au_sync_delay(10);
-			}
-	}
-
-	/*
-	 * We don't want _any_ interrupts other than match20. Otherwise our
-	 * au1000_calibrate_delay() calculation will be off, potentially a lot.
-	 */
-	intc0_mask = save_local_and_disable(0);
-	intc1_mask = save_local_and_disable(1);
-	local_enable_irq(AU1000_TOY_MATCH2_INT);
-	spin_unlock_irqrestore(&pm_lock, flags);
-	au1000_calibrate_delay();
-	restore_local_and_enable(0, intc0_mask);
-	restore_local_and_enable(1, intc1_mask);
-
-	return retval;
-}
-
-
-static struct ctl_table pm_table[] = {
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "sleep",
-		.data		= NULL,
-		.maxlen		= 0,
-		.mode		= 0600,
-		.proc_handler	= &pm_do_sleep
-	},
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "freq",
-		.data		= NULL,
-		.maxlen		= 0,
-		.mode		= 0600,
-		.proc_handler	= &pm_do_freq
-	},
-	{}
-};
-
-static struct ctl_table pm_dir_table[] = {
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "pm",
-		.mode		= 0555,
-		.child		= pm_table
-	},
-	{}
-};
-
-/*
- * Initialize power interface
- */
-static int __init pm_init(void)
-{
-	/* init TOY to tick at 1Hz. No need to wait for access bits
-	 * since there's plenty of time between here and the first
-	 * suspend cycle.
-	 */
-	if (au_readl(SYS_TOYTRIM) != 32767) {
-		au_writel(32767, SYS_TOYTRIM);
-		au_sync();
-	}
-
-	register_sysctl_table(pm_dir_table);
-	return 0;
-}
-
-__initcall(pm_init);
-
-/*
- * This is right out of init/main.c
- */
-
-/*
- * This is the number of bits of precision for the loops_per_jiffy.
- * Each bit takes on average 1.5/HZ seconds.  This (like the original)
- * is a little better than 1%.
- */
-#define LPS_PREC 8
-
-static void au1000_calibrate_delay(void)
-{
-	unsigned long ticks, loopbit;
-	int lps_precision = LPS_PREC;
-
-	loops_per_jiffy = 1 << 12;
-
-	while (loops_per_jiffy <<= 1) {
-		/* Wait for "start of" clock tick */
-		ticks = jiffies;
-		while (ticks == jiffies)
-			/* nothing */ ;
-		/* Go ... */
-		ticks = jiffies;
-		__delay(loops_per_jiffy);
-		ticks = jiffies - ticks;
-		if (ticks)
-			break;
-	}
-
-	/*
-	 * Do a binary approximation to get loops_per_jiffy set to be equal
-	 * one clock (up to lps_precision bits)
-	 */
-	loops_per_jiffy >>= 1;
-	loopbit = loops_per_jiffy;
-	while (lps_precision-- && (loopbit >>= 1)) {
-		loops_per_jiffy |= loopbit;
-		ticks = jiffies;
-		while (ticks == jiffies);
-		ticks = jiffies;
-		__delay(loops_per_jiffy);
-		if (jiffies != ticks)	/* longer than 1 tick */
-			loops_per_jiffy &= ~loopbit;
-	}
 }
 #endif	/* CONFIG_PM */
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 06/10] Alchemy: compile platform.c only when building for a demoboard.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

The platform.c registers devices not all boards might need/want,
and it makes adding platform data to drivers needlessly ugly and
complicated.

Most (all?) in-kernel users of Au1xxx are demoboards, and the file
in question somewhat reflects that.  Remove the platform.c from the
common Alchemy Makefile and add it to the Makefiles of the boards.
Existing behavior of all in-kernel boards is not changed in any way.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/Makefile   |    2 +-
 arch/mips/au1000/common/platform.c |    7 ++++++-
 arch/mips/au1000/db1x00/Makefile   |    1 +
 arch/mips/au1000/mtx-1/Makefile    |    2 +-
 arch/mips/au1000/pb1000/Makefile   |    1 +
 arch/mips/au1000/pb1100/Makefile   |    1 +
 arch/mips/au1000/pb1200/Makefile   |    2 +-
 arch/mips/au1000/pb1500/Makefile   |    1 +
 arch/mips/au1000/pb1550/Makefile   |    1 +
 arch/mips/au1000/xxs1500/Makefile  |    1 +
 10 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index 27bf73d..7265109 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -6,7 +6,7 @@
 #
 
 obj-y += prom.o irq.o puts.o time.o reset.o \
-	au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
+	au1xxx_irqmap.o clocks.o power.o setup.o \
 	sleeper.o dma.o dbdma.o gpio.o
 
 obj-$(CONFIG_PCI)		+= pci.o
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index dc8a67e..66d6770 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -1,5 +1,5 @@
 /*
- * Platform device support for Au1x00 SoCs.
+ * Common device support for Au1x00 demoboards.
  *
  * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
  *
@@ -9,6 +9,11 @@
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
+ *
+ * This file is intended to be included by all db1xxx/pb1xxx demoboards,
+ * and is currently used by all the in-tree ones.  If your system does
+ * not want/need all the devices registered in here (like mine) then
+ * simply don't include it in your Makefile ;-)
  */
 
 #include <linux/dma-mapping.h>
diff --git a/arch/mips/au1000/db1x00/Makefile b/arch/mips/au1000/db1x00/Makefile
index 274db3b..3bfec10 100644
--- a/arch/mips/au1000/db1x00/Makefile
+++ b/arch/mips/au1000/db1x00/Makefile
@@ -6,3 +6,4 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/mtx-1/Makefile b/arch/mips/au1000/mtx-1/Makefile
index 7c67b3d..ef98975 100644
--- a/arch/mips/au1000/mtx-1/Makefile
+++ b/arch/mips/au1000/mtx-1/Makefile
@@ -7,6 +7,6 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
-obj-y := platform.o
+obj-y := platform.o ../common/platform.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/au1000/pb1000/Makefile b/arch/mips/au1000/pb1000/Makefile
index 99bbec0..41a09be 100644
--- a/arch/mips/au1000/pb1000/Makefile
+++ b/arch/mips/au1000/pb1000/Makefile
@@ -6,3 +6,4 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/pb1100/Makefile b/arch/mips/au1000/pb1100/Makefile
index 793e97c..1a8cd71 100644
--- a/arch/mips/au1000/pb1100/Makefile
+++ b/arch/mips/au1000/pb1100/Makefile
@@ -6,3 +6,4 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile
index d678adf..7b9f2f5 100644
--- a/arch/mips/au1000/pb1200/Makefile
+++ b/arch/mips/au1000/pb1200/Makefile
@@ -3,6 +3,6 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
-obj-y += platform.o
+obj-y += platform.o ../common/platform.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/au1000/pb1500/Makefile b/arch/mips/au1000/pb1500/Makefile
index 602f38d..c12e1bd 100644
--- a/arch/mips/au1000/pb1500/Makefile
+++ b/arch/mips/au1000/pb1500/Makefile
@@ -6,3 +6,4 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/pb1550/Makefile b/arch/mips/au1000/pb1550/Makefile
index 7d8beca..8df0890 100644
--- a/arch/mips/au1000/pb1550/Makefile
+++ b/arch/mips/au1000/pb1550/Makefile
@@ -6,3 +6,4 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/xxs1500/Makefile b/arch/mips/au1000/xxs1500/Makefile
index db3c526..86db0f7 100644
--- a/arch/mips/au1000/xxs1500/Makefile
+++ b/arch/mips/au1000/xxs1500/Makefile
@@ -6,3 +6,4 @@
 #
 
 lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
-- 
1.5.6.4

^ permalink raw reply related

* [PATCH 02/10] Alchemy: remove cpu_table.
From: Manuel Lauss @ 2008-08-12 17:42 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Kevin Hickey, Linux-MIPS, Manuel Lauss
In-Reply-To: <cover.1218561745.git.mano@roarinelk.homelinux.net>

Remove the cpu_table:
- move detection of whether c0_config[OD] is read-only and should be set
  to fix various chip errata to au1000 headers.
- move detection of write-only sys_cpupll to au1000 headers.
- remove the BCLK switching code:  Activation of this features should be
  left to the boards using the chips since it also affects external devices
  tied to BCLK, and only the board designers know whether it is safe to
  enable.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
 arch/mips/au1000/common/Makefile      |    2 +-
 arch/mips/au1000/common/cputable.c    |   52 -----------------------------
 arch/mips/au1000/common/setup.c       |   26 +--------------
 arch/mips/au1000/common/time.c        |    4 +-
 include/asm-mips/mach-au1x00/au1000.h |   58 +++++++++++++++++++++-----------
 5 files changed, 42 insertions(+), 100 deletions(-)
 delete mode 100644 arch/mips/au1000/common/cputable.c

diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index df48fd6..27bf73d 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -7,7 +7,7 @@
 
 obj-y += prom.o irq.o puts.o time.o reset.o \
 	au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
-	sleeper.o cputable.o dma.o dbdma.o gpio.o
+	sleeper.o dma.o dbdma.o gpio.o
 
 obj-$(CONFIG_PCI)		+= pci.o
 
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c
deleted file mode 100644
index ba6430b..0000000
--- a/arch/mips/au1000/common/cputable.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  arch/mips/au1000/common/cputable.c
- *
- *  Copyright (C) 2004 Dan Malek (dan@embeddededge.com)
- *	Copied from PowerPC and updated for Alchemy Au1xxx processors.
- *
- *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- */
-
-#include <asm/mach-au1x00/au1000.h>
-
-struct cpu_spec *cur_cpu_spec[NR_CPUS];
-
-/* With some thought, we can probably use the mask to reduce the
- * size of the table.
- */
-struct cpu_spec cpu_specs[] = {
-	{ 0xffffffff, 0x00030100, "Au1000 DA", 1, 0, 1 },
-	{ 0xffffffff, 0x00030201, "Au1000 HA", 1, 0, 1 },
-	{ 0xffffffff, 0x00030202, "Au1000 HB", 1, 0, 1 },
-	{ 0xffffffff, 0x00030203, "Au1000 HC", 1, 1, 0 },
-	{ 0xffffffff, 0x00030204, "Au1000 HD", 1, 1, 0 },
-	{ 0xffffffff, 0x01030200, "Au1500 AB", 1, 1, 0 },
-	{ 0xffffffff, 0x01030201, "Au1500 AC", 0, 1, 0 },
-	{ 0xffffffff, 0x01030202, "Au1500 AD", 0, 1, 0 },
-	{ 0xffffffff, 0x02030200, "Au1100 AB", 1, 1, 0 },
-	{ 0xffffffff, 0x02030201, "Au1100 BA", 1, 1, 0 },
-	{ 0xffffffff, 0x02030202, "Au1100 BC", 1, 1, 0 },
-	{ 0xffffffff, 0x02030203, "Au1100 BD", 0, 1, 0 },
-	{ 0xffffffff, 0x02030204, "Au1100 BE", 0, 1, 0 },
-	{ 0xffffffff, 0x03030200, "Au1550 AA", 0, 1, 0 },
-	{ 0xffffffff, 0x04030200, "Au1200 AB", 0, 0, 0 },
-	{ 0xffffffff, 0x04030201, "Au1200 AC", 1, 0, 0 },
-	{ 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0, 0 }
-};
-
-void set_cpuspec(void)
-{
-	struct	cpu_spec *sp;
-	u32	prid;
-
-	prid = read_c0_prid();
-	sp = cpu_specs;
-	while ((prid & sp->prid_mask) != sp->prid_value)
-		sp++;
-	cur_cpu_spec[0] = sp;
-}
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 1ac6b06..8f06440 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -41,38 +41,14 @@ extern void __init board_setup(void);
 extern void au1000_restart(char *);
 extern void au1000_halt(void);
 extern void au1000_power_off(void);
-extern void set_cpuspec(void);
 
 void __init plat_mem_setup(void)
 {
-	struct	cpu_spec *sp;
 	char *argptr;
-	unsigned long prid, cpufreq, bclk;
-
-	set_cpuspec();
-	sp = cur_cpu_spec[0];
 
 	board_setup();  /* board specific setup */
 
-	prid = read_c0_prid();
-	if (sp->cpu_pll_wo)
-#ifdef CONFIG_SOC_AU1000_FREQUENCY
-		cpufreq = CONFIG_SOC_AU1000_FREQUENCY / 1000000;
-#else
-		cpufreq = 396;
-#endif
-	else
-		cpufreq = (au_readl(SYS_CPUPLL) & 0x3F) * 12;
-	printk(KERN_INFO "(PRID %08lx) @ %ld MHz\n", prid, cpufreq);
-
-	if (sp->cpu_bclk) {
-		/* Enable BCLK switching */
-		bclk = au_readl(SYS_POWERCTRL);
-		au_writel(bclk | 0x60, SYS_POWERCTRL);
-		printk(KERN_INFO "BCLK switching enabled!\n");
-	}
-
-	if (sp->cpu_od)
+	if (au1xxx_cpu_needs_config_od())
 		/* Various early Au1xx0 errata corrected by this */
 		set_c0_config(1 << 19); /* Set Config[OD] */
 	else
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index 68d7142..1518570 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -198,7 +198,7 @@ unsigned long calc_clock(void)
 	 * silicon versions of Au1000 are not sold by AMD, we don't bend
 	 * over backwards trying to determine the frequency.
 	 */
-	if (cur_cpu_spec[0]->cpu_pll_wo)
+	if (au1xxx_cpu_has_pll_wo())
 #ifdef CONFIG_SOC_AU1000_FREQUENCY
 		cpu_speed = CONFIG_SOC_AU1000_FREQUENCY;
 #else
@@ -221,7 +221,7 @@ void __init plat_time_init(void)
 
 	est_freq += 5000;    /* round */
 	est_freq -= est_freq%10000;
-	printk(KERN_INFO "CPU frequency %u.%02u MHz\n",
+	printk(KERN_INFO "(PRId %08x) @ %u.%02u MHz\n", read_c0_prid(),
 	       est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
 	set_au1x00_speed(est_freq);
 
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 8d2ced6..7245960 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -91,6 +91,44 @@ static inline u32 au_readl(unsigned long reg)
 	return *(volatile u32 *)reg;
 }
 
+/* Early Au1000 have a write-only SYS_CPUPLL register. */
+static inline int au1xxx_cpu_has_pll_wo(void)
+{
+	switch (read_c0_prid()) {
+	case 0x00030100:	/* Au1000 DA */
+	case 0x00030201:	/* Au1000 HA */
+	case 0x00030202:	/* Au1000 HB */
+		return 1;
+	}
+	return 0;
+}
+
+/* does CPU need CONFIG[OD] set to fix tons of errata? */
+static inline int au1xxx_cpu_needs_config_od(void)
+{
+	/*
+	 * c0_config.od (bit 19) was write only (and read as 0) on the
+	 * early revisions of Alchemy SOCs.  It disables the bus trans-
+	 * action overlapping and needs to be set to fix various errata.
+	 */
+	switch (read_c0_prid()) {
+	case 0x00030100: /* Au1000 DA */
+	case 0x00030201: /* Au1000 HA */
+	case 0x00030202: /* Au1000 HB */
+	case 0x01030200: /* Au1500 AB */
+	/*
+	 * Au1100/Au1200 errata actually keep silence about this bit,
+	 * so we set it just in case for those revisions that require
+	 * it to be set according to the (now gone) cpu_table.
+	 */
+	case 0x02030200: /* Au1100 AB */
+	case 0x02030201: /* Au1100 BA */
+	case 0x02030202: /* Au1100 BC */
+	case 0x04030201: /* Au1200 AC */
+		return 1;
+	}
+	return 0;
+}
 
 /* arch/mips/au1000/common/clocks.c */
 extern void set_au1x00_speed(unsigned int new_freq);
@@ -1747,24 +1785,4 @@ static AU1X00_SYS * const sys = (AU1X00_SYS *)SYS_BASE;
 
 #endif
 
-/*
- * Processor information based on PRID.
- * Copied from PowerPC.
- */
-#ifndef _LANGUAGE_ASSEMBLY
-struct cpu_spec {
-	/* CPU is matched via (PRID & prid_mask) == prid_value */
-	unsigned int	prid_mask;
-	unsigned int	prid_value;
-
-	char		*cpu_name;
-	unsigned char	cpu_od;		/* Set Config[OD] */
-	unsigned char	cpu_bclk;	/* Enable BCLK switching */
-	unsigned char	cpu_pll_wo;	/* sys_cpupll reg. write-only */
-};
-
-extern struct cpu_spec	cpu_specs[];
-extern struct cpu_spec	*cur_cpu_spec[];
-#endif
-
 #endif
-- 
1.5.6.4

^ 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