linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
@ 2010-03-02  8:09 Albrecht Dreß
  2010-03-02  8:28 ` Wolfram Sang
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Albrecht Dreß @ 2010-03-02  8:09 UTC (permalink / raw)
  To: w.sang; +Cc: linuxppc-dev, devicetree-discuss

Hi Wolfram!

Thanks a lot for your comments!

[snip]
> > + * as the chip can be only either a 5200B or not. */
> > +static int is_mpc5200b =3D -1;
> > +
> > +
>=20
> One empty line too much. Maybe we can also get rid of the static later in
> the
> process, but first things first.

Ooops....

[snip]
> > +=09if (is_mpc5200b =3D=3D 1)
> > +=09=09return mpc5xxx_get_bus_frequency(p) * 4;
> > +=09else
> > +=09=09return mpc5xxx_get_bus_frequency(p) / 2;
>=20
> Isn't this wrong? You can also have /32 on the 5200B (the fallback).

Yes, but I do all /calculations/ with the /4 prescaler for higher accuracy.=
  If the divisor exceeds the available 16 bits of the counter reg, I round =
(divisor / 8) to use the /32 prescaler.  Think of a 19-bit counter value, w=
here I can choose to use either the lower or the higher 16 bits for the cou=
nter reg.  Remember also that using the higher 16 bits (/32 prescaler) is p=
robably the exceptional case - with an IPB frequency of 132 MHz this will h=
appen only for standard baud rates B300 and slower.

[snip]
> > +=09/* Check only once if we are running on a mpc5200b or not */
> > +=09if (is_mpc5200b =3D=3D -1) {
> > +=09=09struct device_node *np;
> > +
> > +=09=09np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5200b-immr");
>=20
> This should be handled using a new compatible-entry
> "fsl,mpc5200b-psc-uart".

I agree that this would be a lot cleaner, but it's also a lot more intrusiv=
e.  CC'ing the device tree discussion list here... comments, please!!

> > +=09=09if (np) {
> > +=09=09=09is_mpc5200b =3D 1;
> > +=09=09=09dev_dbg(&op->dev, "mpc5200b: using /4 prescaler\n");
>=20
> Does this message respect the fallback case?

See comment above...

> You could also have a set_divisor-function for 5200 and 5200B and set it
> here
> in the function struct (one reason less for the static ;))

Hmmm, but then I would need a 'static struct psc_ops mpc5200b_psc_ops', whe=
re only two functions differ from the generic 52xx struct as it is implemen=
ted now.  Using the static int needs less space.  However, in combination w=
ith the new compatible entry, it would of course make sense.

Again, any insight from the device tree gurus would be appreciated!

Thanks, Albrecht.

Tolle Dekollet=E9s oder scharfe Tatoos? Vote jetzt ... oder mach selbst mit=
 und zeige Deine Schokoladenseite
bei Topp oder Hopp von Arcor: http://www.arcor.de/rd/footer.toh

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-02  8:09 [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy) Albrecht Dreß
@ 2010-03-02  8:28 ` Wolfram Sang
  2010-03-02  8:56 ` Albrecht Dreß
  2010-03-02 20:06 ` Grant Likely
  2 siblings, 0 replies; 9+ messages in thread
From: Wolfram Sang @ 2010-03-02  8:28 UTC (permalink / raw)
  To: Albrecht Dre�; +Cc: linuxppc-dev, devicetree-discuss

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

> [snip]
> > > +	if (is_mpc5200b == 1)
> > > +		return mpc5xxx_get_bus_frequency(p) * 4;
> > > +	else
> > > +		return mpc5xxx_get_bus_frequency(p) / 2;
> > 
> > Isn't this wrong? You can also have /32 on the 5200B (the fallback).
> 
> Yes, but I do all /calculations/ with the /4 prescaler for higher accuracy.
> If the divisor exceeds the available 16 bits of the counter reg, I round
> (divisor / 8) to use the /32 prescaler.  Think of a 19-bit counter value,
> where I can choose to use either the lower or the higher 16 bits for the
> counter reg.

Okay, now I got it. (Maybe this is an indication for another comment above the
set divisor function?)

> Remember also that using the higher 16 bits (/32 prescaler) is
> probably the exceptional case - with an IPB frequency of 132 MHz this will
> happen only for standard baud rates B300 and slower.

Even the rare cases have to be correct ;)

> [snip]
> > > +	/* Check only once if we are running on a mpc5200b or not */
> > > +	if (is_mpc5200b == -1) {
> > > +		struct device_node *np;
> > > +
> > > +		np = of_find_compatible_node(NULL, NULL, "fsl,mpc5200b-immr");
> > 
> > This should be handled using a new compatible-entry
> > "fsl,mpc5200b-psc-uart".
> 

> I agree that this would be a lot cleaner, but it's also a lot more intrusive.
> CC'ing the device tree discussion list here... comments, please!!

Why intrusive? Maybe I miss something?

> > You could also have a set_divisor-function for 5200 and 5200B and set it
> > here in the function struct (one reason less for the static ;))
> 
> Hmmm, but then I would need a 'static struct psc_ops mpc5200b_psc_ops', where
> only two functions differ from the generic 52xx struct as it is implemented
> now.  Using the static int needs less space.  However, in combination with
> the new compatible entry, it would of course make sense.

Leave those two function pointers empty and fill them during probe (probe has
access to the compatible-property it was matched against, see its arguments).
So it should be a matter of:

if (matched_property == 5200b)
	ops->func = this_one;
else
	ops->func = that_one;

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-02  8:09 [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy) Albrecht Dreß
  2010-03-02  8:28 ` Wolfram Sang
@ 2010-03-02  8:56 ` Albrecht Dreß
  2010-03-02 15:27   ` Wolfram Sang
  2010-03-02 20:12   ` Grant Likely
  2010-03-02 20:06 ` Grant Likely
  2 siblings, 2 replies; 9+ messages in thread
From: Albrecht Dreß @ 2010-03-02  8:56 UTC (permalink / raw)
  To: w.sang; +Cc: linuxppc-dev, devicetree-discuss

Hi Wolfram:

[snip]
> > Yes, but I do all /calculations/ with the /4 prescaler for higher
> accuracy.
> > If the divisor exceeds the available 16 bits of the counter reg, I roun=
d
> > (divisor / 8) to use the /32 prescaler.  Think of a 19-bit counter valu=
e,
> > where I can choose to use either the lower or the higher 16 bits for th=
e
> > counter reg.
>=20
> Okay, now I got it. (Maybe this is an indication for another comment abov=
e
> the
> set divisor function?)

O.k., I will add that comment...

> > Remember also that using the higher 16 bits (/32 prescaler) is
> > probably the exceptional case - with an IPB frequency of 132 MHz this
> will
> > happen only for standard baud rates B300 and slower.
>=20
> Even the rare cases have to be correct ;)

I agree - will make the debug output and comments clearer...

[snip]
> > > This should be handled using a new compatible-entry
> > > "fsl,mpc5200b-psc-uart".
> >=20
>=20
> > I agree that this would be a lot cleaner, but it's also a lot more
> intrusive.
> > CC'ing the device tree discussion list here... comments, please!!
>=20
> Why intrusive? Maybe I miss something?

Not for the source file, but for all the dts files, if they want to benefit=
 from the detection of the '5200B.  Basically, *all* files have to be check=
ed and touched if necessary.  Again, I agree that this would be the clean a=
pproach, but I wanted to avoid that effort.  Grant???

[snip]
> Leave those two function pointers empty and fill them during probe (probe
> has
> access to the compatible-property it was matched against, see its
> arguments).
> So it should be a matter of:
>=20
> if (matched_property =3D=3D 5200b)
> =09ops->func =3D this_one;
> else
> =09ops->func =3D that_one;

Umm, yes, that's true of course.  Will pick it up.

Thanks, Albrecht.

Tolle Dekollet=E9s oder scharfe Tatoos? Vote jetzt ... oder mach selbst mit=
 und zeige Deine Schokoladenseite
bei Topp oder Hopp von Arcor: http://www.arcor.de/rd/footer.toh

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-02  8:56 ` Albrecht Dreß
@ 2010-03-02 15:27   ` Wolfram Sang
  2010-03-02 20:12   ` Grant Likely
  1 sibling, 0 replies; 9+ messages in thread
From: Wolfram Sang @ 2010-03-02 15:27 UTC (permalink / raw)
  To: Albrecht Dre�; +Cc: linuxppc-dev, devicetree-discuss

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


> > > > This should be handled using a new compatible-entry
> > > > "fsl,mpc5200b-psc-uart".
> > > 
> > 
> > > I agree that this would be a lot cleaner, but it's also a lot more
> > intrusive.
> > > CC'ing the device tree discussion list here... comments, please!!
> > 
> > Why intrusive? Maybe I miss something?
> 
> Not for the source file, but for all the dts files, if they want to benefit
> from the detection of the '5200B.  Basically, *all* files have to be checked
> and touched if necessary.  Again, I agree that this would be the clean
> approach, but I wanted to avoid that effort.  Grant???

Please check the current 5200b-dts files. They already have the property,
exactly for the case that a specific driver may be added in the future. And
even if not, the behaviour of the driver would not change by missing your
driver improvement, so there is also no regression.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-02  8:09 [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy) Albrecht Dreß
  2010-03-02  8:28 ` Wolfram Sang
  2010-03-02  8:56 ` Albrecht Dreß
@ 2010-03-02 20:06 ` Grant Likely
  2 siblings, 0 replies; 9+ messages in thread
From: Grant Likely @ 2010-03-02 20:06 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: linuxppc-dev, devicetree-discuss

On Tue, Mar 2, 2010 at 1:09 AM, Albrecht Dre=DF <albrecht.dress@arcor.de> w=
rote:
>> > + =A0 /* Check only once if we are running on a mpc5200b or not */
>> > + =A0 if (is_mpc5200b =3D=3D -1) {
>> > + =A0 =A0 =A0 =A0 =A0 struct device_node *np;
>> > +
>> > + =A0 =A0 =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,=
mpc5200b-immr");
>>
>> This should be handled using a new compatible-entry
>> "fsl,mpc5200b-psc-uart".
>
> I agree that this would be a lot cleaner, but it's also a lot more intrus=
ive. =A0CC'ing the device tree discussion list here... comments, please!!

fsl,mpc5200b-psc-uart is already in the compatible list for all
MPC500b boards currently in the kernel tree.

>> > + =A0 =A0 =A0 =A0 =A0 if (np) {
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 is_mpc5200b =3D 1;
>> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(&op->dev, "mpc5200b: usi=
ng /4 prescaler\n");
>>
>> Does this message respect the fallback case?
>
> See comment above...
>
>> You could also have a set_divisor-function for 5200 and 5200B and set it
>> here
>> in the function struct (one reason less for the static ;))
>
> Hmmm, but then I would need a 'static struct psc_ops mpc5200b_psc_ops', w=
here only two functions differ from the generic 52xx struct as it is implem=
ented now. =A0Using the static int needs less space. =A0However, in combina=
tion with the new compatible entry, it would of course make sense.
>
> Again, any insight from the device tree gurus would be appreciated!

Wolfram is correct, you should set the correct divisor function in the
ops structure.  Much clearer code that way.

g.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-02  8:56 ` Albrecht Dreß
  2010-03-02 15:27   ` Wolfram Sang
@ 2010-03-02 20:12   ` Grant Likely
  1 sibling, 0 replies; 9+ messages in thread
From: Grant Likely @ 2010-03-02 20:12 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: linuxppc-dev, devicetree-discuss

On Tue, Mar 2, 2010 at 1:56 AM, Albrecht Dre=DF <albrecht.dress@arcor.de> w=
rote:
> Hi Wolfram:
>
> [snip]
>> > Yes, but I do all /calculations/ with the /4 prescaler for higher
>> accuracy.
>> > If the divisor exceeds the available 16 bits of the counter reg, I rou=
nd
>> > (divisor / 8) to use the /32 prescaler. =A0Think of a 19-bit counter v=
alue,
>> > where I can choose to use either the lower or the higher 16 bits for t=
he
>> > counter reg.
>>
>> Okay, now I got it. (Maybe this is an indication for another comment abo=
ve
>> the
>> set divisor function?)
>
> O.k., I will add that comment...
>

Yes, please document your calculation approach thoroughly.

>> > > This should be handled using a new compatible-entry
>> > > "fsl,mpc5200b-psc-uart".
>> >
>>
>> > I agree that this would be a lot cleaner, but it's also a lot more
>> intrusive.
>> > CC'ing the device tree discussion list here... comments, please!!
>>
>> Why intrusive? Maybe I miss something?
>
> Not for the source file, but for all the dts files, if they want to benef=
it from the detection of the '5200B. =A0Basically, *all* files have to be c=
hecked and touched if necessary. =A0Again, I agree that this would be the c=
lean approach, but I wanted to avoid that effort. =A0Grant???

Already there on mainlined .dts files, and it won't break boards that
don't have it.

> [snip]
>> Leave those two function pointers empty and fill them during probe (prob=
e
>> has
>> access to the compatible-property it was matched against, see its
>> arguments).
>> So it should be a matter of:
>>
>> if (matched_property =3D=3D 5200b)
>> =A0 =A0 =A0 ops->func =3D this_one;
>> else
>> =A0 =A0 =A0 ops->func =3D that_one;
>
> Umm, yes, that's true of course. =A0Will pick it up.

When it comes to code clarity, I'd prefer you had separate mpc5200 and
mpc5200b ops structures.  I'm not worried about an extra 64 bytes
added to the kernel size for this (minus the # of bytes needed to test
and set the new op).

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-01 18:11 Albrecht Dreß
  2010-03-02  0:32 ` Wolfram Sang
@ 2010-03-02 20:22 ` Grant Likely
  1 sibling, 0 replies; 9+ messages in thread
From: Grant Likely @ 2010-03-02 20:22 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: Linux PPC Development

Hi Albrecht,

Thanks for this work, comment below...

On Mon, Mar 1, 2010 at 11:11 AM, Albrecht Dre=DF <albrecht.dress@arcor.de> =
wrote:
> On the MPC5200B, select the baud rate prescaler as /4 by default to make =
very
> high baud rates (e.g. 3 MBaud) accessible and to achieve a higher precisi=
on
> for high baud rates in general. For baud rates below ~500 Baud, the code =
will
> automatically fall back to the /32 prescaler. =A0The original MPC5200 doe=
s only
> have a /32 prescaler which is detected only once and stored in a global. =
=A0A
> new chip-dependent method is used to set the divisor.
>
> Tested on a custom 5200B based board, with up to 3 MBaud.
>
> Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
>
> ---
>
> --- linux-2.6.33/drivers/serial/mpc52xx_uart.c.orig =A0 =A0 2010-02-24 19=
:52:17.000000000 +0100
> +++ linux-2.6.33/drivers/serial/mpc52xx_uart.c =A02010-02-26 21:12:51.000=
000000 +0100
> =A0/* Search for bus-frequency property in this node or a parent */
> =A0static unsigned long mpc52xx_getuartclk(void *p)
> =A0{
> =A0 =A0 =A0 =A0/*
> - =A0 =A0 =A0 =A0* 5200 UARTs have a / 32 prescaler
> - =A0 =A0 =A0 =A0* but the generic serial code assumes 16
> - =A0 =A0 =A0 =A0* so return ipb freq / 2
> + =A0 =A0 =A0 =A0* The 5200 has only /32 prescalers.
> + =A0 =A0 =A0 =A0* 5200B UARTs have a /4 or a /32 prescaler. =A0For highe=
r accuracy, we
> + =A0 =A0 =A0 =A0* do all calculations using the /4 prescaler for this ch=
ip.
> + =A0 =A0 =A0 =A0* The generic serial code assumes /16 so return ipb freq=
 / 2 (5200)
> + =A0 =A0 =A0 =A0* or ipb freq * 4 (5200B).
> =A0 =A0 =A0 =A0 */
> - =A0 =A0 =A0 return mpc5xxx_get_bus_frequency(p) / 2;
> + =A0 =A0 =A0 if (is_mpc5200b =3D=3D 1)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return mpc5xxx_get_bus_frequency(p) * 4;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return mpc5xxx_get_bus_frequency(p) / 2;
> =A0}

Remove this function entirely and the associated .getuartclk() hook
from the psc_ops structure.  Callers can just call
mpc5xxx_get_bus_frequency() directly.  mpc5121 already just passes
back the return value unmodified, and current mpc52xx code uses a /2,
but that would be eliminated if the new set_divisor hook took that
into account.  That way all the chip-specific clock setup calculation
is consolidated into a single function.  I like patches that make
things simpler.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
  2010-03-01 18:11 Albrecht Dreß
@ 2010-03-02  0:32 ` Wolfram Sang
  2010-03-02 20:22 ` Grant Likely
  1 sibling, 0 replies; 9+ messages in thread
From: Wolfram Sang @ 2010-03-02  0:32 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: Linux PPC Development

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

Hi Albrecht,

On Mon, Mar 01, 2010 at 07:11:54PM +0100, Albrecht Dreß wrote:
> On the MPC5200B, select the baud rate prescaler as /4 by default to make very
> high baud rates (e.g. 3 MBaud) accessible and to achieve a higher precision
> for high baud rates in general. For baud rates below ~500 Baud, the code will
> automatically fall back to the /32 prescaler.  The original MPC5200 does only
> have a /32 prescaler which is detected only once and stored in a global.  A
> new chip-dependent method is used to set the divisor.
> 
> Tested on a custom 5200B based board, with up to 3 MBaud.
> 
> Signed-off-by: Albrecht Dreß <albrecht.dress@arcor.de>
> 
> ---
> 
> --- linux-2.6.33/drivers/serial/mpc52xx_uart.c.orig	2010-02-24 19:52:17.000000000 +0100
> +++ linux-2.6.33/drivers/serial/mpc52xx_uart.c	2010-02-26 21:12:51.000000000 +0100
> @@ -144,9 +144,17 @@ struct psc_ops {
>  	unsigned char	(*read_char)(struct uart_port *port);
>  	void		(*cw_disable_ints)(struct uart_port *port);
>  	void		(*cw_restore_ints)(struct uart_port *port);
> +	void		(*set_divisor)(struct uart_port *port,
> +				       unsigned int divisor);
>  	unsigned long	(*getuartclk)(void *p);
>  };
>  
> +/* We need to distinguish between the MPC5200 which has only a /32 prescaler,
> + * and the MPC5200B which has a /32 and a /4 prescaler.  The global is fine,
> + * as the chip can be only either a 5200B or not. */
> +static int is_mpc5200b = -1;
> +
> +

One empty line too much. Maybe we can also get rid of the static later in the
process, but first things first.

>  #ifdef CONFIG_PPC_MPC52xx
>  #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
>  static void mpc52xx_psc_fifo_init(struct uart_port *port)
> @@ -154,9 +162,6 @@ static void mpc52xx_psc_fifo_init(struct
>  	struct mpc52xx_psc __iomem *psc = PSC(port);
>  	struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
>  
> -	/* /32 prescaler */
> -	out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
> -
>  	out_8(&fifo->rfcntl, 0x00);
>  	out_be16(&fifo->rfalarm, 0x1ff);
>  	out_8(&fifo->tfcntl, 0x07);
> @@ -245,15 +250,40 @@ static void mpc52xx_psc_cw_restore_ints(
>  	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
>  }
>  
> +static void mpc52xx_psc_set_divisor(struct uart_port *port,
> +				    unsigned int divisor)
> +{
> +	struct mpc52xx_psc __iomem *psc = PSC(port);
> +
> +	/* prescaler */
> +	if (is_mpc5200b != 1)
> +		out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /32 */
> +	else if (divisor > 0xffff) {
> +		out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /32 */
> +		divisor = (divisor + 4) / 8;
> +	} else
> +		out_be16(&psc->mpc52xx_psc_clock_select, 0xff00); /* /4 */
> +
> +	/* ctr */
> +	divisor &= 0xffff;
> +	out_8(&psc->ctur, divisor >> 8);
> +	out_8(&psc->ctlr, divisor & 0xff);
> +}
> +
>  /* Search for bus-frequency property in this node or a parent */
>  static unsigned long mpc52xx_getuartclk(void *p)
>  {
>  	/*
> -	 * 5200 UARTs have a / 32 prescaler
> -	 * but the generic serial code assumes 16
> -	 * so return ipb freq / 2
> +	 * The 5200 has only /32 prescalers.
> +	 * 5200B UARTs have a /4 or a /32 prescaler.  For higher accuracy, we
> +	 * do all calculations using the /4 prescaler for this chip.
> +	 * The generic serial code assumes /16 so return ipb freq / 2 (5200)
> +	 * or ipb freq * 4 (5200B).
>  	 */
> -	return mpc5xxx_get_bus_frequency(p) / 2;
> +	if (is_mpc5200b == 1)
> +		return mpc5xxx_get_bus_frequency(p) * 4;
> +	else
> +		return mpc5xxx_get_bus_frequency(p) / 2;

Isn't this wrong? You can also have /32 on the 5200B (the fallback).

>  }
>  
>  static struct psc_ops mpc52xx_psc_ops = {
> @@ -272,6 +302,7 @@ static struct psc_ops mpc52xx_psc_ops = 
>  	.read_char = mpc52xx_psc_read_char,
>  	.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
>  	.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
> +	.set_divisor = mpc52xx_psc_set_divisor,
>  	.getuartclk = mpc52xx_getuartclk,
>  };
>  
> @@ -388,6 +419,16 @@ static void mpc512x_psc_cw_restore_ints(
>  	out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
>  }
>  
> +static void mpc512x_psc_set_divisor(struct uart_port *port,
> +				    unsigned int divisor)
> +{
> +	struct mpc52xx_psc __iomem *psc = PSC(port);
> +
> +	divisor &= 0xffff;
> +	out_8(&psc->ctur, divisor >> 8);
> +	out_8(&psc->ctlr, divisor & 0xff);
> +}
> +
>  static unsigned long mpc512x_getuartclk(void *p)
>  {
>  	return mpc5xxx_get_bus_frequency(p);
> @@ -409,6 +450,7 @@ static struct psc_ops mpc512x_psc_ops = 
>  	.read_char = mpc512x_psc_read_char,
>  	.cw_disable_ints = mpc512x_psc_cw_disable_ints,
>  	.cw_restore_ints = mpc512x_psc_cw_restore_ints,
> +	.set_divisor = mpc512x_psc_set_divisor,
>  	.getuartclk = mpc512x_getuartclk,
>  };
>  #endif
> @@ -564,7 +606,6 @@ mpc52xx_uart_set_termios(struct uart_por
>  	struct mpc52xx_psc __iomem *psc = PSC(port);
>  	unsigned long flags;
>  	unsigned char mr1, mr2;
> -	unsigned short ctr;
>  	unsigned int j, baud, quot;
>  
>  	/* Prepare what we're gonna write */
> @@ -604,7 +645,6 @@ mpc52xx_uart_set_termios(struct uart_por
>  
>  	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
>  	quot = uart_get_divisor(port, baud);
> -	ctr = quot & 0xffff;
>  
>  	/* Get the lock */
>  	spin_lock_irqsave(&port->lock, flags);
> @@ -635,8 +675,7 @@ mpc52xx_uart_set_termios(struct uart_por
>  	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
>  	out_8(&psc->mode, mr1);
>  	out_8(&psc->mode, mr2);
> -	out_8(&psc->ctur, ctr >> 8);
> -	out_8(&psc->ctlr, ctr & 0xff);
> +	psc_ops->set_divisor(port, quot);
>  
>  	if (UART_ENABLE_MS(port, new->c_cflag))
>  		mpc52xx_uart_enable_ms(port);
> @@ -1113,6 +1152,19 @@ mpc52xx_uart_of_probe(struct of_device *
>  
>  	dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
>  
> +	/* Check only once if we are running on a mpc5200b or not */
> +	if (is_mpc5200b == -1) {
> +		struct device_node *np;
> +
> +		np = of_find_compatible_node(NULL, NULL, "fsl,mpc5200b-immr");

This should be handled using a new compatible-entry "fsl,mpc5200b-psc-uart".

> +		if (np) {
> +			is_mpc5200b = 1;
> +			dev_dbg(&op->dev, "mpc5200b: using /4 prescaler\n");

Does this message respect the fallback case?

You could also have a set_divisor-function for 5200 and 5200B and set it here
in the function struct (one reason less for the static ;))

> +			of_node_put(np);
> +		} else
> +			is_mpc5200b = 0;
> +	}
> +
>  	/* Check validity & presence */
>  	for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
>  		if (mpc52xx_uart_nodes[idx] == op->node)
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
@ 2010-03-01 18:11 Albrecht Dreß
  2010-03-02  0:32 ` Wolfram Sang
  2010-03-02 20:22 ` Grant Likely
  0 siblings, 2 replies; 9+ messages in thread
From: Albrecht Dreß @ 2010-03-01 18:11 UTC (permalink / raw)
  To: Linux PPC Development, Likely, Grant

On the MPC5200B, select the baud rate prescaler as /4 by default to make ve=
ry
high baud rates (e.g. 3 MBaud) accessible and to achieve a higher precision
for high baud rates in general. For baud rates below ~500 Baud, the code wi=
ll
automatically fall back to the /32 prescaler.  The original MPC5200 does on=
ly
have a /32 prescaler which is detected only once and stored in a global.  A
new chip-dependent method is used to set the divisor.

Tested on a custom 5200B based board, with up to 3 MBaud.

Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>

---

--- linux-2.6.33/drivers/serial/mpc52xx_uart.c.orig	2010-02-24 19:52:17.000=
000000 +0100
+++ linux-2.6.33/drivers/serial/mpc52xx_uart.c	2010-02-26 21:12:51.00000000=
0 +0100
@@ -144,9 +144,17 @@ struct psc_ops {
 	unsigned char	(*read_char)(struct uart_port *port);
 	void		(*cw_disable_ints)(struct uart_port *port);
 	void		(*cw_restore_ints)(struct uart_port *port);
+	void		(*set_divisor)(struct uart_port *port,
+				       unsigned int divisor);
 	unsigned long	(*getuartclk)(void *p);
 };
=20
+/* We need to distinguish between the MPC5200 which has only a /32 prescal=
er,
+ * and the MPC5200B which has a /32 and a /4 prescaler.  The global is fin=
e,
+ * as the chip can be only either a 5200B or not. */
+static int is_mpc5200b =3D -1;
+
+
 #ifdef CONFIG_PPC_MPC52xx
 #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
 static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -154,9 +162,6 @@ static void mpc52xx_psc_fifo_init(struct
 	struct mpc52xx_psc __iomem *psc =3D PSC(port);
 	struct mpc52xx_psc_fifo __iomem *fifo =3D FIFO_52xx(port);
=20
-	/* /32 prescaler */
-	out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
-
 	out_8(&fifo->rfcntl, 0x00);
 	out_be16(&fifo->rfalarm, 0x1ff);
 	out_8(&fifo->tfcntl, 0x07);
@@ -245,15 +250,40 @@ static void mpc52xx_psc_cw_restore_ints(
 	out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
 }
=20
+static void mpc52xx_psc_set_divisor(struct uart_port *port,
+				    unsigned int divisor)
+{
+	struct mpc52xx_psc __iomem *psc =3D PSC(port);
+
+	/* prescaler */
+	if (is_mpc5200b !=3D 1)
+		out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /32 */
+	else if (divisor > 0xffff) {
+		out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /32 */
+		divisor =3D (divisor + 4) / 8;
+	} else
+		out_be16(&psc->mpc52xx_psc_clock_select, 0xff00); /* /4 */
+
+	/* ctr */
+	divisor &=3D 0xffff;
+	out_8(&psc->ctur, divisor >> 8);
+	out_8(&psc->ctlr, divisor & 0xff);
+}
+
 /* Search for bus-frequency property in this node or a parent */
 static unsigned long mpc52xx_getuartclk(void *p)
 {
 	/*
-	 * 5200 UARTs have a / 32 prescaler
-	 * but the generic serial code assumes 16
-	 * so return ipb freq / 2
+	 * The 5200 has only /32 prescalers.
+	 * 5200B UARTs have a /4 or a /32 prescaler.  For higher accuracy, we
+	 * do all calculations using the /4 prescaler for this chip.
+	 * The generic serial code assumes /16 so return ipb freq / 2 (5200)
+	 * or ipb freq * 4 (5200B).
 	 */
-	return mpc5xxx_get_bus_frequency(p) / 2;
+	if (is_mpc5200b =3D=3D 1)
+		return mpc5xxx_get_bus_frequency(p) * 4;
+	else
+		return mpc5xxx_get_bus_frequency(p) / 2;
 }
=20
 static struct psc_ops mpc52xx_psc_ops =3D {
@@ -272,6 +302,7 @@ static struct psc_ops mpc52xx_psc_ops =3D=20
 	.read_char =3D mpc52xx_psc_read_char,
 	.cw_disable_ints =3D mpc52xx_psc_cw_disable_ints,
 	.cw_restore_ints =3D mpc52xx_psc_cw_restore_ints,
+	.set_divisor =3D mpc52xx_psc_set_divisor,
 	.getuartclk =3D mpc52xx_getuartclk,
 };
=20
@@ -388,6 +419,16 @@ static void mpc512x_psc_cw_restore_ints(
 	out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
 }
=20
+static void mpc512x_psc_set_divisor(struct uart_port *port,
+				    unsigned int divisor)
+{
+	struct mpc52xx_psc __iomem *psc =3D PSC(port);
+
+	divisor &=3D 0xffff;
+	out_8(&psc->ctur, divisor >> 8);
+	out_8(&psc->ctlr, divisor & 0xff);
+}
+
 static unsigned long mpc512x_getuartclk(void *p)
 {
 	return mpc5xxx_get_bus_frequency(p);
@@ -409,6 +450,7 @@ static struct psc_ops mpc512x_psc_ops =3D=20
 	.read_char =3D mpc512x_psc_read_char,
 	.cw_disable_ints =3D mpc512x_psc_cw_disable_ints,
 	.cw_restore_ints =3D mpc512x_psc_cw_restore_ints,
+	.set_divisor =3D mpc512x_psc_set_divisor,
 	.getuartclk =3D mpc512x_getuartclk,
 };
 #endif
@@ -564,7 +606,6 @@ mpc52xx_uart_set_termios(struct uart_por
 	struct mpc52xx_psc __iomem *psc =3D PSC(port);
 	unsigned long flags;
 	unsigned char mr1, mr2;
-	unsigned short ctr;
 	unsigned int j, baud, quot;
=20
 	/* Prepare what we're gonna write */
@@ -604,7 +645,6 @@ mpc52xx_uart_set_termios(struct uart_por
=20
 	baud =3D uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
 	quot =3D uart_get_divisor(port, baud);
-	ctr =3D quot & 0xffff;
=20
 	/* Get the lock */
 	spin_lock_irqsave(&port->lock, flags);
@@ -635,8 +675,7 @@ mpc52xx_uart_set_termios(struct uart_por
 	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
 	out_8(&psc->mode, mr1);
 	out_8(&psc->mode, mr2);
-	out_8(&psc->ctur, ctr >> 8);
-	out_8(&psc->ctlr, ctr & 0xff);
+	psc_ops->set_divisor(port, quot);
=20
 	if (UART_ENABLE_MS(port, new->c_cflag))
 		mpc52xx_uart_enable_ms(port);
@@ -1113,6 +1152,19 @@ mpc52xx_uart_of_probe(struct of_device *
=20
 	dev_dbg(&op->dev, "mpc52xx_uart_probe(op=3D%p, match=3D%p)\n", op, match)=
;
=20
+	/* Check only once if we are running on a mpc5200b or not */
+	if (is_mpc5200b =3D=3D -1) {
+		struct device_node *np;
+
+		np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5200b-immr");
+		if (np) {
+			is_mpc5200b =3D 1;
+			dev_dbg(&op->dev, "mpc5200b: using /4 prescaler\n");
+			of_node_put(np);
+		} else
+			is_mpc5200b =3D 0;
+	}
+
 	/* Check validity & presence */
 	for (idx =3D 0; idx < MPC52xx_PSC_MAXNUM; idx++)
 		if (mpc52xx_uart_nodes[idx] =3D=3D op->node)

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2010-03-02 20:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-02  8:09 [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy) Albrecht Dreß
2010-03-02  8:28 ` Wolfram Sang
2010-03-02  8:56 ` Albrecht Dreß
2010-03-02 15:27   ` Wolfram Sang
2010-03-02 20:12   ` Grant Likely
2010-03-02 20:06 ` Grant Likely
  -- strict thread matches above, loose matches on Subject: below --
2010-03-01 18:11 Albrecht Dreß
2010-03-02  0:32 ` Wolfram Sang
2010-03-02 20:22 ` Grant Likely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).