* Re: [PATCH 1/3] add default device trees for MPC837x MDS board
From: Grant Likely @ 2008-01-08 17:53 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Li Yang, paulus
In-Reply-To: <20080108173845.GA5188@loki.buserror.net>
On 1/8/08, Scott Wood <scottwood@freescale.com> wrote:
> On Tue, Jan 08, 2008 at 08:58:17AM -0700, Grant Likely wrote:
> > On 1/7/08, Li Yang <leoli@freescale.com> wrote:
> > > + phy_type = "utmi_wide";
> >
> > fsl,phy_type please.
>
> Again, code will break. Can we stop ambushing people submitting board
> support with complaints against existing, non-board-specific code/device
> trees? Fix that first, then complain if new code reintroduces the crud.
I disagree (about bringing up these comments). New board port is the
time to bring these issue up. It keeps the issue in the forefront so
it actually gets fixed.
>
> Also, if we're going to change the property name, we should also change the
> underscore to a dash.
Good point, I missed that
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 2/4] nand base: Give drivers a chance to do late initialization.
From: Scott Wood @ 2008-01-08 17:48 UTC (permalink / raw)
To: David Woodhouse; +Cc: linuxppc-dev, linux-mtd
In-Reply-To: <1199779069.4111.379.camel@shinybook.infradead.org>
On Tue, Jan 08, 2008 at 07:57:49AM +0000, David Woodhouse wrote:
>
> On Thu, 2007-12-13 at 11:15 -0600, Scott Wood wrote:
> > Some nand controllers, such as the Freescale enhanced local bus controller,
> > need to do late initialization based on details of the chip that has been
> > probed, such as chip size, large/small pages, etc. A late_init() callback
> > method is added to allow this.
>
> Do you really need this so late? Can't it be done between
> nand_scan_ident() and nand_scan_tail()? That's why we split nand_scan()
> into two in the first place...
Yeah, that'd work. I'll send an updated driver soon.
-Scott
^ permalink raw reply
* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Jon Loeliger @ 2008-01-08 17:44 UTC (permalink / raw)
To: Olof Johansson; +Cc: linuxppc-dev, John Rigby
In-Reply-To: <20080108174038.GA20819@lixom.net>
So, like, the other day Olof Johansson mumbled:
>
> > @@ -0,0 +1,90 @@
> > +#include <asm/system.h>
> > +#include <asm/atomic.h>
> > +#include <asm/machdep.h>
> > +#include <asm/ipic.h>
> > +#include <asm/prom.h>
> > +#include <asm/time.h>
> > +#include <asm/of_platform.h>
>
> Stephen will tell you to include linux/of_platform.h instead. :-)
Yeah, watch me outright NAK it too. :-)
jdl
^ permalink raw reply
* Re: [PATCH 1/3] add default device trees for MPC837x MDS board
From: Scott Wood @ 2008-01-08 17:38 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, Li Yang, paulus
In-Reply-To: <fa686aa40801080758o35dce96ej5db45576769561a5@mail.gmail.com>
On Tue, Jan 08, 2008 at 08:58:17AM -0700, Grant Likely wrote:
> On 1/7/08, Li Yang <leoli@freescale.com> wrote:
> > + soc@e0000000 {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + device_type = "soc";
>
> I recommend dropping device_type and adding 'compatible = "fsl,mpc8377-immr";'
I recommend fixing the code that looks for this device_type before
recommending that people drop it. :-)
> > + wdt@200 {
> > + compatible = "mpc83xx_wdt";
>
> "fsl,mpc8377_wdt", "fsl,mpc83xx_wdt" as per generic names recommended practice.
Speaking of generic names, can we change the node name to "watchdog"?
> > + /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */
> > + usb@23000 {
> > + compatible = "fsl-usb2-dr";
> > + reg = <23000 1000>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + interrupt-parent = < &ipic >;
> > + interrupts = <26 8>;
> > + phy_type = "utmi_wide";
>
> fsl,phy_type please.
Again, code will break. Can we stop ambushing people submitting board
support with complaints against existing, non-board-specific code/device
trees? Fix that first, then complain if new code reintroduces the crud.
Also, if we're going to change the property name, we should also change the
underscore to a dash.
> > + enet0: ethernet@24000 {
> > + cell-index = <0>;
> > + device_type = "network";
> > + model = "eTSEC";
>
> Drop model property
Fix the code that checks for it.
-Scott
^ permalink raw reply
* error : array type has incomplete element type
From: Rami @ 2008-01-08 17:02 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 2927 bytes --]
Hi all,
I am trying to compile a kernel for the ppc405 embedded on the virtex 4 and
I am obtaining the compiling errors listed below(at the end of this mail).
my compiler is the crosstool latest one.
I tried to compile each the following kernel versions :
2.6.23.8
2.6.17
with the following versions of gcc and glibc of the crosscompiler
gcc-4.0.2-glibc-2.3.5
gcc-4.1.0-glibc-2.3.6
gcc-4.1.1-glibc-2.3.6
the result is always the same (array type has incomplete element type)
moreover I searched all the files and I replaced
(struct ocp_def core_ocp[]) with (struct ocp_def
core_ocp[2])
because my architectur contains only one UART, the result is always
the same (same error).
any help is appreciated,
Rami
arch/ppc/syslib/virtex_devices.c:23: error: array type has incomplete
element type
arch/ppc/syslib/virtex_devices.c:25: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:25: error: (near initialization for
'core_ocp')
arch/ppc/syslib/virtex_devices.c:26: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:26: error: (near initialization for
'core_ocp')
arch/ppc/syslib/virtex_devices.c:27: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:27: error: (near initialization for
'core_ocp')
arch/ppc/syslib/virtex_devices.c:28: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:28: error: (near initialization for
'core_ocp')
arch/ppc/syslib/virtex_devices.c:29: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:29: error: (near initialization for
'core_ocp')
arch/ppc/syslib/virtex_devices.c:30: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:30: error: (near initialization for
'core_ocp')
arch/ppc/syslib/virtex_devices.c:30: error: 'OCP_CPM_NA' undeclared here
(not in a function)
arch/ppc/syslib/virtex_devices.c:63: error: field name not in record or
union initializer
arch/ppc/syslib/virtex_devices.c:63: error: (near initialization for
'core_ocp')
CONFIDENTIALITE : Ce message et les éventuelles pièces attachées sont
confidentiels. Si vous n'êtes pas dans la liste des destinataires, veuillez
informer l'expéditeur immédiatement et ne pas divulguer le contenu à une
tierce personne, ne pas l'utiliser pour quelque raison que ce soit, ne pas
stocker ou copier l'information qu'il contient sur un quelconque support.
CONFIDENTIALITY : This e-mail and any attachments are confidential and may
be privileged. If you are not a named recipient, please notify the sender
immediately and do not disclose the contents to another person, use it for
any purpose or store or copy the information in any medium.
[-- Attachment #1.2: Type: text/html, Size: 8111 bytes --]
[-- Attachment #2: wt2007bottom_RWE.gif --]
[-- Type: image/gif, Size: 9139 bytes --]
[-- Attachment #3: arbre-logo.gif --]
[-- Type: image/gif, Size: 2808 bytes --]
^ permalink raw reply
* Re: [PATCH 7/7] Add MPC512x PSC serial driver
From: Grant Likely @ 2008-01-08 17:32 UTC (permalink / raw)
To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-8-git-send-email-jrigby@freescale.com>
Exactly *how* different is the 5121 PSC from the 5200 PSC? If it is
really different, then it makes sense to clone. In fact; I'd
duplicate the mpc52xx_psc.h file also to avoid any crossover.
However, if the differences are manegable, I'd rather see a single
driver that can drive either type of PSC. In fact, can you post a
diff between this driver and the original PSC driver?
Cheers,
g.
On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> mpc512x_uart.c is based on mpc52xx_uart.c with
> names changed
> arch/ppc support removed
> 512x psc fifo support added
> shares mpc52xx_psc.h with 52xx driver
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> ---
> drivers/serial/Kconfig | 18 +
> drivers/serial/Makefile | 1 +
> drivers/serial/mpc512x_uart.c | 969 +++++++++++++++++++++++++++++++++++++
> include/asm-powerpc/mpc52xx_psc.h | 47 ++
> 4 files changed, 1035 insertions(+), 0 deletions(-)
> create mode 100644 drivers/serial/mpc512x_uart.c
>
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index d7e1996..643b84a 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -1113,6 +1113,24 @@ config SERIAL_SGI_L1_CONSOLE
> controller serial port as your console (you want this!),
> say Y. Otherwise, say N.
>
> +config SERIAL_MPC512x
> + tristate "Freescale MPC512x family PSC serial support"
> + depends on PPC_512x
> + select SERIAL_CORE
> + help
> + This drivers support the MPC512x PSC serial ports. If you would
> + like to use them, you must answer Y or M to this option. Not that
> + for use as console, it must be included in kernel and not as a
> + module.
> +
> +config SERIAL_MPC512x_CONSOLE
> + bool "Console on a Freescale MPC512x family PSC serial port"
> + depends on SERIAL_MPC512x=y
> + select SERIAL_CORE_CONSOLE
> + help
> + Select this options if you'd like to use one of the PSC serial port
> + of the Freescale MPC52xx family as a console.
> +
> config SERIAL_MPC52xx
> tristate "Freescale MPC52xx family PSC serial support"
> depends on PPC_MPC52xx
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index af6377d..13e8176 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
> obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
> obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
> obj-$(CONFIG_SERIAL_IMX) += imx.o
> +obj-$(CONFIG_SERIAL_MPC512x) += mpc512x_uart.o
> obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
> obj-$(CONFIG_SERIAL_ICOM) += icom.o
> obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
> diff --git a/drivers/serial/mpc512x_uart.c b/drivers/serial/mpc512x_uart.c
> new file mode 100644
> index 0000000..e2ff0b8
> --- /dev/null
> +++ b/drivers/serial/mpc512x_uart.c
> @@ -0,0 +1,969 @@
> +/*
> + * Driver for the PSC of the Freescale MPC512x PSCs configured as UARTs.
> + *
> + * Copyright (C) 2007 Freescale Semiconductor Inc
> + * John Rigby <jrigby@freescale.com>
> + *
> + * Fork of mpc512x_uart.c:
> + *
> + * Copyright (C) 2006 Secret Lab Technologies Ltd.
> + * Grant Likely <grant.likely@secretlab.ca>
> + * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
> + * Copyright (C) 2003 MontaVista, Software, Inc.
> + * Dale Farnsworth <dfarnsworth@mvista.com>.
> + *
> + * 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.
> + */
> +
> +/*
> + * The 512x PSCs are almost identical to those on 52xx. The most notable
> + * difference is that the FIFOs have been separated out. This file
> + * still uses the mpc52xx_psc.h which has had the fifo differences added.
> + *
> + * TODO (maybe) abstract out the fifo differences and merge this back
> + * into mpc512x_serial.c
> + */
> +
> +/* OF Platform device Usage :
> + *
> + * This driver is only used for PSCs configured in uart mode. The device
> + * tree will have a node for each PSC in uart mode w/ device_type = "serial"
> + * and "mpc52xx-psc-uart" in the compatible string
> + *
> + * By default, PSC devices are enumerated in the order they are found. However
> + * a particular PSC number can be forced by adding 'device_no = <port#>'
> + * to the device node.
> + *
> + * The driver init all necessary registers to place the PSC in uart mode without
> + * DCD. However, the pin multiplexing aren't changed and should be set either
> + * by the bootloader or in the platform init code.
> + */
> +
> +#undef DEBUG
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/tty.h>
> +#include <linux/serial.h>
> +#include <linux/sysrq.h>
> +#include <linux/console.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +
> +#include <asm/of_platform.h>
> +#include <asm/mpc52xx_psc.h>
> +#include <asm/mpc512x.h>
> +
> +#if defined(CONFIG_SERIAL_MPC512x_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/serial_core.h>
> +
> +/* We've been assigned a range on the "Low-density serial ports" major */
> +#define SERIAL_PSC_MAJOR 204
> +#define SERIAL_PSC_MINOR 148
> +
> +#define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */
> +
> +static struct uart_port mpc512x_uart_ports[MPC52xx_PSC_MAXNUM];
> +
> +/* lookup table for matching device nodes to index numbers */
> +static struct device_node *mpc512x_uart_nodes[MPC52xx_PSC_MAXNUM];
> +
> +static void mpc512x_uart_of_enumerate(void);
> +
> +static unsigned long getuartclk(void *p)
> +{
> + return mpc512x_find_ips_freq(p);
> +}
> +
> +#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
> +#define FIFO(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
> +
> +/* Forward declaration of the interruption handling routine */
> +static irqreturn_t mpc512x_uart_int(int irq, void *dev_id);
> +
> +/* Simple macro to test if a port is console or not. This one is taken
> + * for serial_core.c and maybe should be moved to serial_core.h ? */
> +#ifdef CONFIG_SERIAL_CORE_CONSOLE
> +#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
> +#else
> +#define uart_console(port) (0)
> +#endif
> +
> +static struct of_device_id mpc512x_uart_of_match[] = {
> + {.type = "serial", .compatible = "mpc512x-psc-uart",},
> + {},
> +};
> +
> +/* ======================================================================== */
> +/* UART operations */
> +/* ======================================================================== */
> +
> +static unsigned int mpc512x_uart_tx_empty(struct uart_port *port)
> +{
> + int status;
> +
> + status = in_be32(&FIFO(port)->txsr);
> + return (status & MPC512x_PSC_FIFO_EMPTY) ? TIOCSER_TEMT : 0;
> +}
> +
> +static void mpc512x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> + /* Not implemented */
> +}
> +
> +static unsigned int mpc512x_uart_get_mctrl(struct uart_port *port)
> +{
> + /* Not implemented */
> + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
> +}
> +
> +static void mpc512x_uart_stop_tx(struct uart_port *port)
> +{
> + /* port->lock taken by caller */
> + unsigned long tx_fifo_imr;
> +
> + tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> + tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
> + out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> +}
> +
> +static void mpc512x_uart_start_tx(struct uart_port *port)
> +{
> + /* port->lock taken by caller */
> + unsigned long tx_fifo_imr;
> +
> + tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> + tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
> + out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> +}
> +
> +static void mpc512x_uart_send_xchar(struct uart_port *port, char ch)
> +{
> + unsigned long flags;
> + spin_lock_irqsave(&port->lock, flags);
> +
> + port->x_char = ch;
> + if (ch) {
> + /* Make sure tx interrupts are on */
> + /* Truly necessary ??? They should be anyway */
> + unsigned long tx_fifo_imr;
> +
> + tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> + tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
> + out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> + }
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void mpc512x_uart_stop_rx(struct uart_port *port)
> +{
> + /* port->lock taken by caller */
> + unsigned long rx_fifo_imr;
> +
> + rx_fifo_imr = in_be32(&FIFO(port)->rximr);
> + rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
> + out_be32(&FIFO(port)->rximr, rx_fifo_imr);
> +}
> +
> +static void mpc512x_uart_enable_ms(struct uart_port *port)
> +{
> + /* Not implemented */
> +}
> +
> +static void mpc512x_uart_break_ctl(struct uart_port *port, int ctl)
> +{
> + unsigned long flags;
> + spin_lock_irqsave(&port->lock, flags);
> +
> + if (ctl == -1)
> + out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
> + else
> + out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void mpc512x_uart_fifo_init(struct mpc52xx_psc *psc)
> +{
> + struct mpc512x_psc_fifo *fifo;
> +
> + /* fifo is right after the psc */
> + fifo = (struct mpc512x_psc_fifo *)(psc + 1);
> +
> + out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
> + out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
> + out_be32(&fifo->txalarm, 1);
> + out_be32(&fifo->tximr, 0);
> +
> + out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
> + out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
> + out_be32(&fifo->rxalarm, 1);
> + out_be32(&fifo->rximr, 0);
> +}
> +
> +static int mpc512x_uart_startup(struct uart_port *port)
> +{
> + struct mpc52xx_psc __iomem *psc = PSC(port);
> + int ret;
> +
> + /* Request IRQ */
> + ret = request_irq(port->irq, mpc512x_uart_int,
> + IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
> + "mpc512x_psc_uart", port);
> + if (ret)
> + return ret;
> +
> + /* Reset/activate the port, clear and enable interrupts */
> + out_8(&psc->command, MPC52xx_PSC_RST_RX);
> + out_8(&psc->command, MPC52xx_PSC_RST_TX);
> +
> + out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
> +
> + mpc512x_uart_fifo_init(psc);
> +
> + out_be32(&FIFO(port)->tximr, MPC512x_PSC_FIFO_ALARM);
> + out_be32(&FIFO(port)->rximr, MPC512x_PSC_FIFO_ALARM);
> +
> + out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
> + out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
> +
> + return 0;
> +}
> +
> +static void mpc512x_uart_shutdown(struct uart_port *port)
> +{
> + struct mpc52xx_psc __iomem *psc = PSC(port);
> +
> + /* Shut down the port. Leave TX active if on a console port */
> + out_8(&psc->command, MPC52xx_PSC_RST_RX);
> + if (!uart_console(port))
> + out_8(&psc->command, MPC52xx_PSC_RST_TX);
> +
> + out_be32(&FIFO(port)->tximr, 0);
> + out_be32(&FIFO(port)->rximr, 0);
> +
> + /* Release interrupt */
> + free_irq(port->irq, port);
> +}
> +
> +static void
> +mpc512x_uart_set_termios(struct uart_port *port, struct ktermios *new,
> + struct ktermios *old)
> +{
> + struct mpc52xx_psc __iomem *psc = PSC(port);
> + unsigned long flags;
> + unsigned char mr1, mr2;
> + unsigned short ctr;
> + unsigned int j, baud, quot;
> + struct mpc512x_psc_fifo *fifo = FIFO(port);
> +
> + /* Prepare what we're gonna write */
> + mr1 = 0;
> +
> + switch (new->c_cflag & CSIZE) {
> + case CS5:
> + mr1 |= MPC52xx_PSC_MODE_5_BITS;
> + break;
> + case CS6:
> + mr1 |= MPC52xx_PSC_MODE_6_BITS;
> + break;
> + case CS7:
> + mr1 |= MPC52xx_PSC_MODE_7_BITS;
> + break;
> + case CS8:
> + default:
> + mr1 |= MPC52xx_PSC_MODE_8_BITS;
> + }
> +
> + if (new->c_cflag & PARENB) {
> + mr1 |= (new->c_cflag & PARODD) ?
> + MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
> + } else
> + mr1 |= MPC52xx_PSC_MODE_PARNONE;
> +
> + mr2 = 0;
> +
> + if (new->c_cflag & CSTOPB)
> + mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
> + else
> + mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
> + MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
> + MPC52xx_PSC_MODE_ONE_STOP;
> +
> + 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);
> +
> + /* Update the per-port timeout */
> + uart_update_timeout(port, new->c_cflag, baud);
> +
> + /* Do our best to flush TX & RX, so we don't loose anything */
> + /* But we don't wait indefinitly ! */
> + j = 5000000; /* Maximum wait */
> + /* FIXME Can't receive chars since set_termios might be called at early
> + * boot for the console, all stuff is not yet ready to receive at that
> + * time and that just makes the kernel oops */
> + /* while (j-- && mpc512x_uart_int_rx_chars(port)); */
> + while (!(in_be32(&fifo->txsr) & MPC512x_PSC_FIFO_EMPTY) && --j)
> + udelay(1);
> +
> + if (!j)
> + printk(KERN_ERR "mpc512x_uart.c: "
> + "Unable to flush RX & TX fifos in-time in set_termios."
> + "Some chars may have been lost.\n");
> +
> + /* Reset the TX & RX */
> + out_8(&psc->command, MPC52xx_PSC_RST_RX);
> + out_8(&psc->command, MPC52xx_PSC_RST_TX);
> +
> + /* Send new mode settings */
> + 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);
> +
> + /* Reenable TX & RX */
> + out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
> + out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
> +
> + /* We're all set, release the lock */
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *mpc512x_uart_type(struct uart_port *port)
> +{
> + return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
> +}
> +
> +static void mpc512x_uart_release_port(struct uart_port *port)
> +{
> + /* remapped by us ? */
> + if (port->flags & UPF_IOREMAP) {
> + iounmap(port->membase);
> + port->membase = NULL;
> + }
> +
> + release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
> +}
> +
> +static int mpc512x_uart_request_port(struct uart_port *port)
> +{
> + int err;
> +
> + if (port->flags & UPF_IOREMAP) /* Need to remap ? */
> + port->membase = ioremap(port->mapbase,
> + sizeof(struct mpc52xx_psc));
> +
> + if (!port->membase)
> + return -EINVAL;
> +
> + err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
> + "mpc512x_psc_uart") != NULL ? 0 : -EBUSY;
> +
> + if (err && (port->flags & UPF_IOREMAP)) {
> + iounmap(port->membase);
> + port->membase = NULL;
> + }
> +
> + return err;
> +}
> +
> +static void mpc512x_uart_config_port(struct uart_port *port, int flags)
> +{
> + if ((flags & UART_CONFIG_TYPE) &&
> + (mpc512x_uart_request_port(port) == 0))
> + port->type = PORT_MPC52xx;
> +}
> +
> +static int
> +mpc512x_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
> + return -EINVAL;
> +
> + if ((ser->irq != port->irq) ||
> + (ser->io_type != SERIAL_IO_MEM) ||
> + (ser->baud_base != port->uartclk) ||
> + (ser->iomem_base != (void *)port->mapbase) || (ser->hub6 != 0))
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static struct uart_ops mpc512x_uart_ops = {
> + .tx_empty = mpc512x_uart_tx_empty,
> + .set_mctrl = mpc512x_uart_set_mctrl,
> + .get_mctrl = mpc512x_uart_get_mctrl,
> + .stop_tx = mpc512x_uart_stop_tx,
> + .start_tx = mpc512x_uart_start_tx,
> + .send_xchar = mpc512x_uart_send_xchar,
> + .stop_rx = mpc512x_uart_stop_rx,
> + .enable_ms = mpc512x_uart_enable_ms,
> + .break_ctl = mpc512x_uart_break_ctl,
> + .startup = mpc512x_uart_startup,
> + .shutdown = mpc512x_uart_shutdown,
> + .set_termios = mpc512x_uart_set_termios,
> +/* .pm = mpc512x_uart_pm, Not supported yet */
> +/* .set_wake = mpc512x_uart_set_wake, Not supported yet */
> + .type = mpc512x_uart_type,
> + .release_port = mpc512x_uart_release_port,
> + .request_port = mpc512x_uart_request_port,
> + .config_port = mpc512x_uart_config_port,
> + .verify_port = mpc512x_uart_verify_port
> +};
> +
> +/* ======================================================================== */
> +/* Interrupt handling */
> +/* ======================================================================== */
> +
> +static inline int mpc512x_uart_int_rx_chars(struct uart_port *port)
> +{
> + struct tty_struct *tty = port->info->tty;
> + unsigned char ch, flag;
> + unsigned short status;
> + unsigned long fifostatus;
> + struct mpc52xx_psc __iomem *psc = PSC(port);
> + struct mpc512x_psc_fifo __iomem *fifo = FIFO(port);
> +
> + /* While we can read, do so ! */
> + while (1) {
> + fifostatus = in_be32(&fifo->rxsr);
> +
> + if (fifostatus & MPC512x_PSC_FIFO_EMPTY)
> + break;
> +
> + status = in_be16(&psc->mpc52xx_psc_status);
> +
> + /* Get the char */
> + ch = in_8(&fifo->rxdata_8);
> +
> + /* Handle sysreq char */
> +#ifdef SUPPORT_SYSRQ
> + if (uart_handle_sysrq_char(port, ch)) {
> + port->sysrq = 0;
> + continue;
> + }
> +#endif
> +
> + /* Store it */
> +
> + flag = TTY_NORMAL;
> + port->icount.rx++;
> +
> + if (status & (MPC52xx_PSC_SR_PE |
> + MPC52xx_PSC_SR_FE | MPC52xx_PSC_SR_RB)) {
> +
> + if (status & MPC52xx_PSC_SR_RB) {
> + flag = TTY_BREAK;
> + uart_handle_break(port);
> + } else if (status & MPC52xx_PSC_SR_PE)
> + flag = TTY_PARITY;
> + else if (status & MPC52xx_PSC_SR_FE)
> + flag = TTY_FRAME;
> +
> + /* Clear error condition */
> + out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
> +
> + }
> + tty_insert_flip_char(tty, ch, flag);
> + if (status & MPC52xx_PSC_SR_OE) {
> + /*
> + * Overrun is special, since it's
> + * reported immediately, and doesn't
> + * affect the current character
> + */
> + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> + }
> + }
> +
> + tty_flip_buffer_push(tty);
> +
> + fifostatus = in_be32(&fifo->rxsr);
> + return !(fifostatus & MPC512x_PSC_FIFO_EMPTY);
> +}
> +
> +static inline int mpc512x_uart_int_tx_chars(struct uart_port *port)
> +{
> + struct circ_buf *xmit = &port->info->xmit;
> + struct mpc512x_psc_fifo *fifo = FIFO(port);
> +
> + /* Process out of band chars */
> + if (port->x_char) {
> + out_8(&fifo->txdata_8, port->x_char);
> + port->icount.tx++;
> + port->x_char = 0;
> + return 1;
> + }
> +
> + /* Nothing to do ? */
> + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
> + mpc512x_uart_stop_tx(port);
> + return 0;
> + }
> +
> + /* Send chars */
> + while (!(in_be32(&fifo->txsr) & MPC512x_PSC_FIFO_FULL)) {
> + out_8(&fifo->txdata_8, xmit->buf[xmit->tail]);
> + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> + port->icount.tx++;
> + if (uart_circ_empty(xmit))
> + break;
> + }
> +
> + /* Wake up */
> + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> + uart_write_wakeup(port);
> +
> + /* Maybe we're done after all */
> + if (uart_circ_empty(xmit)) {
> + mpc512x_uart_stop_tx(port);
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static irqreturn_t mpc512x_uart_int(int irq, void *dev_id)
> +{
> + struct uart_port *port = dev_id;
> + unsigned long pass = ISR_PASS_LIMIT;
> + unsigned int keepgoing;
> + unsigned long rx_fifo_status;
> + unsigned long tx_fifo_status;
> +
> + spin_lock(&port->lock);
> +
> + /* While we have stuff to do, we continue */
> + do {
> + /* If we don't find anything to do, we stop */
> + keepgoing = 0;
> +
> + /* clear any pending interrupts */
> + out_be32(&FIFO(port)->rxisr, in_be32(&FIFO(port)->rxisr));
> +
> + rx_fifo_status = in_be32(&FIFO(port)->rxsr);
> + out_be32(&FIFO(port)->rxisr, rx_fifo_status);
> + rx_fifo_status &= in_be32(&FIFO(port)->rximr);
> +
> + if (rx_fifo_status & MPC512x_PSC_FIFO_ALARM)
> + keepgoing |= mpc512x_uart_int_rx_chars(port);
> +
> + /* clear any pending interrupts */
> + out_be32(&FIFO(port)->txisr, in_be32(&FIFO(port)->txisr));
> +
> + tx_fifo_status = in_be32(&FIFO(port)->txsr);
> + out_be32(&FIFO(port)->txisr, tx_fifo_status);
> + tx_fifo_status &= in_be32(&FIFO(port)->tximr);
> +
> + if (tx_fifo_status & MPC512x_PSC_FIFO_ALARM)
> + keepgoing |= mpc512x_uart_int_tx_chars(port);
> +
> + /* Limit number of iteration */
> + if (!(--pass))
> + keepgoing = 0;
> +
> + } while (keepgoing);
> +
> + spin_unlock(&port->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/* ======================================================================== */
> +/* Console ( if applicable ) */
> +/* ======================================================================== */
> +
> +#ifdef CONFIG_SERIAL_MPC512x_CONSOLE
> +
> +static void __init
> +mpc512x_console_get_options(struct uart_port *port,
> + int *baud, int *parity, int *bits, int *flow)
> +{
> + struct mpc52xx_psc __iomem *psc = PSC(port);
> + unsigned char mr1;
> +
> + pr_debug("mpc512x_console_get_options(port=%p)\n", port);
> +
> + /* Read the mode registers */
> + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
> + mr1 = in_8(&psc->mode);
> +
> + /* CT{U,L}R are write-only ! */
> + *baud = 115200;
> + /* Parse them */
> + switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
> + case MPC52xx_PSC_MODE_5_BITS:
> + *bits = 5;
> + break;
> + case MPC52xx_PSC_MODE_6_BITS:
> + *bits = 6;
> + break;
> + case MPC52xx_PSC_MODE_7_BITS:
> + *bits = 7;
> + break;
> + case MPC52xx_PSC_MODE_8_BITS:
> + default:
> + *bits = 8;
> + }
> +
> + if (mr1 & MPC52xx_PSC_MODE_PARNONE)
> + *parity = 'n';
> + else
> + *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
> +}
> +
> +static void
> +mpc512x_console_write(struct console *co, const char *s, unsigned int count)
> +{
> + struct uart_port *port = &mpc512x_uart_ports[co->index];
> + unsigned int i, j;
> + unsigned long rx_fifo_imr, tx_fifo_imr;
> +
> + /* Disable interrupts */
> + tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> + out_be32(&FIFO(port)->tximr, 0);
> + rx_fifo_imr = in_be32(&FIFO(port)->rximr);
> + out_be32(&FIFO(port)->rximr, 0);
> +
> + /* Wait the TX buffer to be empty */
> + j = 5000000; /* Maximum wait */
> + while (!(in_be32(&FIFO(port)->txsr) & MPC512x_PSC_FIFO_EMPTY) && --j)
> + udelay(1);
> + /* Write all the chars */
> + for (i = 0; i < count; i++, s++) {
> + /* Line return handling */
> + if (*s == '\n')
> + out_8(&FIFO(port)->txdata_8, '\r');
> +
> + /* Send the char */
> + out_8(&FIFO(port)->txdata_8, *s);
> +
> + /* Wait the TX buffer to be empty */
> + j = 20000; /* Maximum wait */
> + while (!(in_be32(&FIFO(port)->txsr) & MPC512x_PSC_FIFO_EMPTY)
> + && --j)
> + udelay(1);
> + }
> +
> + /* Restore interrupt state */
> + out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> + out_be32(&FIFO(port)->rximr, rx_fifo_imr);
> +}
> +
> +static int __init mpc512x_console_setup(struct console *co, char *options)
> +{
> + struct uart_port *port = &mpc512x_uart_ports[co->index];
> + struct device_node *np = mpc512x_uart_nodes[co->index];
> + struct resource res;
> +
> + int baud = 115200;
> + int bits = 8;
> + int parity = 'n';
> + int flow = 'n';
> +
> + pr_debug("mpc512x_console_setup co=%p, co->index=%i, options=%s\n",
> + co, co->index, options);
> +
> + if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) {
> + pr_debug("PSC%x out of range\n", co->index);
> + return -EINVAL;
> + }
> +
> + if (!np) {
> + pr_debug("PSC%x not found in device tree\n", co->index);
> + return -EINVAL;
> + }
> +
> + pr_debug("Console on ttyPSC%x is %s\n",
> + co->index, mpc512x_uart_nodes[co->index]->full_name);
> +
> + /* Fetch register locations */
> + if (of_address_to_resource(np, 0, &res)) {
> + pr_debug("Could not get resources for PSC%x\n", co->index);
> + return -EINVAL;
> + }
> +
> + /* Basic port init. Needed since we use some uart_??? func before
> + * real init for early access */
> + spin_lock_init(&port->lock);
> + port->uartclk = getuartclk(np);
> + port->ops = &mpc512x_uart_ops;
> + port->mapbase = res.start;
> + port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
> + port->irq = irq_of_parse_and_map(np, 0);
> +
> + if (port->membase == NULL)
> + return -EINVAL;
> +
> + pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
> + (void *)port->mapbase, port->membase, port->irq,
> + port->uartclk);
> +
> + /* Setup the port parameters accoding to options */
> + if (options)
> + uart_parse_options(options, &baud, &parity, &bits, &flow);
> + else
> + mpc512x_console_get_options(port, &baud, &parity, &bits, &flow);
> +
> + pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
> + baud, bits, parity, flow);
> +
> + return uart_set_options(port, co, baud, parity, bits, flow);
> +}
> +
> +static struct uart_driver mpc512x_uart_driver;
> +
> +static struct console mpc512x_console = {
> + .name = "ttyPSC",
> + .write = mpc512x_console_write,
> + .device = uart_console_device,
> + .setup = mpc512x_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1,
> + .data = &mpc512x_uart_driver,
> +};
> +
> +static int __init mpc512x_console_init(void)
> +{
> + mpc512x_uart_of_enumerate();
> + register_console(&mpc512x_console);
> + return 0;
> +}
> +
> +console_initcall(mpc512x_console_init);
> +
> +#define MPC52xx_PSC_CONSOLE &mpc512x_console
> +#else
> +#define MPC52xx_PSC_CONSOLE NULL
> +#endif
> +
> +/* ======================================================================== */
> +/* UART Driver */
> +/* ======================================================================== */
> +
> +static struct uart_driver mpc512x_uart_driver = {
> + .owner = THIS_MODULE,
> + .driver_name = "mpc512x_psc_uart",
> + .dev_name = "ttyPSC",
> + .major = SERIAL_PSC_MAJOR,
> + .minor = SERIAL_PSC_MINOR,
> + .nr = MPC52xx_PSC_MAXNUM,
> + .cons = MPC52xx_PSC_CONSOLE,
> +};
> +
> +/* ======================================================================== */
> +/* OF Platform Driver */
> +/* ======================================================================== */
> +
> +static int __devinit
> +mpc512x_uart_of_probe(struct of_device *op, const struct of_device_id *match)
> +{
> + int idx = -1;
> + struct uart_port *port = NULL;
> + struct resource res;
> + int ret;
> +
> + dev_dbg(&op->dev, "mpc512x_uart_probe(op=%p, match=%p)\n", op, match);
> +
> + /* Check validity & presence */
> + for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
> + if (mpc512x_uart_nodes[idx] == op->node)
> + break;
> + if (idx >= MPC52xx_PSC_MAXNUM)
> + return -EINVAL;
> + pr_debug("Found %s assigned to ttyPSC%x\n",
> + mpc512x_uart_nodes[idx]->full_name, idx);
> +
> + /* Init the port structure */
> + port = &mpc512x_uart_ports[idx];
> +
> + spin_lock_init(&port->lock);
> + port->uartclk = getuartclk(op->node);
> + port->fifosize = 512;
> + port->iotype = UPIO_MEM;
> + port->flags = UPF_BOOT_AUTOCONF |
> + (uart_console(port) ? 0 : UPF_IOREMAP);
> + port->line = idx;
> + port->ops = &mpc512x_uart_ops;
> + port->dev = &op->dev;
> +
> + /* Search for IRQ and mapbase */
> + if (of_address_to_resource(op->node, 0, &res))
> + return -EINVAL;
> +
> + port->mapbase = res.start;
> + port->irq = irq_of_parse_and_map(op->node, 0);
> +
> + dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
> + (void *)port->mapbase, port->irq, port->uartclk);
> +
> + if ((port->irq == NO_IRQ) || !port->mapbase) {
> + printk(KERN_ERR "Could not allocate resources for PSC\n");
> + return -EINVAL;
> + }
> +
> + /* Add the port to the uart sub-system */
> + ret = uart_add_one_port(&mpc512x_uart_driver, port);
> + if (!ret)
> + dev_set_drvdata(&op->dev, (void *)port);
> +
> + return ret;
> +}
> +
> +static int mpc512x_uart_of_remove(struct of_device *op)
> +{
> + struct uart_port *port = dev_get_drvdata(&op->dev);
> + dev_set_drvdata(&op->dev, NULL);
> +
> + if (port) {
> + uart_remove_one_port(&mpc512x_uart_driver, port);
> + irq_dispose_mapping(port->irq);
> + }
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int mpc512x_uart_of_suspend(struct of_device *op, pm_message_t state)
> +{
> + struct uart_port *port = (struct uart_port *)dev_get_drvdata(&op->dev);
> +
> + if (port)
> + uart_suspend_port(&mpc512x_uart_driver, port);
> +
> + return 0;
> +}
> +
> +static int mpc512x_uart_of_resume(struct of_device *op)
> +{
> + struct uart_port *port = (struct uart_port *)dev_get_drvdata(&op->dev);
> +
> + if (port)
> + uart_resume_port(&mpc512x_uart_driver, port);
> +
> + return 0;
> +}
> +#endif
> +
> +static void mpc512x_uart_of_assign(struct device_node *np, int idx)
> +{
> + int free_idx = -1;
> + int i;
> +
> + /* Find the first free node */
> + for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
> + if (mpc512x_uart_nodes[i] == NULL) {
> + free_idx = i;
> + break;
> + }
> + }
> +
> + if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
> + idx = free_idx;
> +
> + if (idx < 0)
> + return; /* No free slot; abort */
> +
> + /* If the slot is already occupied, then swap slots */
> + if (mpc512x_uart_nodes[idx] && (free_idx != -1))
> + mpc512x_uart_nodes[free_idx] = mpc512x_uart_nodes[idx];
> + mpc512x_uart_nodes[idx] = np;
> +}
> +
> +static void mpc512x_uart_of_enumerate(void)
> +{
> + static int enum_done;
> + struct device_node *np;
> + const unsigned int *devno;
> + int i;
> +
> + if (enum_done)
> + return;
> +
> + for_each_node_by_type(np, "serial") {
> + if (!of_match_node(mpc512x_uart_of_match, np))
> + continue;
> +
> + /* Is a particular device number requested? */
> + devno = of_get_property(np, "port-number", NULL);
> + mpc512x_uart_of_assign(of_node_get(np), devno ? *devno : -1);
> + }
> +
> + enum_done = 1;
> +
> + for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
> + if (mpc512x_uart_nodes[i])
> + pr_debug("%s assigned to ttyPSC%x\n",
> + mpc512x_uart_nodes[i]->full_name, i);
> + }
> +}
> +
> +MODULE_DEVICE_TABLE(of, mpc512x_uart_of_match);
> +
> +static struct of_platform_driver mpc512x_uart_of_driver = {
> + .owner = THIS_MODULE,
> + .name = "mpc52xx-psc-uart",
> + .match_table = mpc512x_uart_of_match,
> + .probe = mpc512x_uart_of_probe,
> + .remove = mpc512x_uart_of_remove,
> +#ifdef CONFIG_PM
> + .suspend = mpc512x_uart_of_suspend,
> + .resume = mpc512x_uart_of_resume,
> +#endif
> + .driver = {
> + .name = "mpc52xx-psc-uart",
> + },
> +};
> +
> +/* ======================================================================== */
> +/* Module */
> +/* ======================================================================== */
> +
> +static int __init mpc512x_uart_init(void)
> +{
> + int ret;
> +
> + printk(KERN_INFO "Serial: MPC512x PSC UART driver\n");
> +
> + ret = uart_register_driver(&mpc512x_uart_driver);
> + if (ret) {
> + printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
> + __FILE__, ret);
> + return ret;
> + }
> +
> + mpc512x_uart_of_enumerate();
> +
> + ret = of_register_platform_driver(&mpc512x_uart_of_driver);
> + if (ret) {
> + printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
> + __FILE__, ret);
> + uart_unregister_driver(&mpc512x_uart_driver);
> + return ret;
> + }
> + return 0;
> +}
> +
> +static void __exit mpc512x_uart_exit(void)
> +{
> + of_unregister_platform_driver(&mpc512x_uart_of_driver);
> + uart_unregister_driver(&mpc512x_uart_driver);
> +}
> +
> +module_init(mpc512x_uart_init);
> +module_exit(mpc512x_uart_exit);
> +
> +MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
> +MODULE_DESCRIPTION("Freescale MPC512x PSC UART");
> +MODULE_LICENSE("GPL");
> diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h
> index bea42b9..6841868 100644
> --- a/include/asm-powerpc/mpc52xx_psc.h
> +++ b/include/asm-powerpc/mpc52xx_psc.h
> @@ -190,5 +190,52 @@ struct mpc52xx_psc_fifo {
> u16 tflwfptr; /* PSC + 0x9e */
> };
>
> +#define MPC512x_PSC_FIFO_RESET_SLICE 0x80
> +#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01
> +
> +#define MPC512x_PSC_FIFO_EMPTY 0x1
> +#define MPC512x_PSC_FIFO_FULL 0x2
> +#define MPC512x_PSC_FIFO_ALARM 0x4
> +#define MPC512x_PSC_FIFO_URERR 0x8
> +#define MPC512x_PSC_FIFO_ORERR 0x01
> +#define MPC512x_PSC_FIFO_MEMERROR 0x02
> +
> +struct mpc512x_psc_fifo {
> + u32 reserved1[10];
> + u32 txcmd; /* PSC + 0x80 */
> + u32 txalarm; /* PSC + 0x84 */
> + u32 txsr; /* PSC + 0x88 */
> + u32 txisr; /* PSC + 0x8c */
> + u32 tximr; /* PSC + 0x90 */
> + u32 txcnt; /* PSC + 0x94 */
> + u32 txptr; /* PSC + 0x98 */
> + u32 txsz; /* PSC + 0x9c */
> + u32 reserved2[7];
> + union {
> + u8 txdata_8;
> + u16 txdata_16;
> + u32 txdata_32;
> + } txdata; /* PSC + 0xbc */
> +#define txdata_8 txdata.txdata_8
> +#define txdata_16 txdata.txdata_16
> +#define txdata_32 txdata.txdata_32
> + u32 rxcmd; /* PSC + 0xc0 */
> + u32 rxalarm; /* PSC + 0xc4 */
> + u32 rxsr; /* PSC + 0xc8 */
> + u32 rxisr; /* PSC + 0xcc */
> + u32 rximr; /* PSC + 0xd0 */
> + u32 rxcnt; /* PSC + 0xd4 */
> + u32 rxptr; /* PSC + 0xd8 */
> + u32 rxsz; /* PSC + 0xdc */
> + u32 reserved3[7];
> + union {
> + u8 rxdata_8;
> + u16 rxdata_16;
> + u32 rxdata_32;
> + } rxdata; /* PSC + 0xfc */
> +#define rxdata_8 rxdata.rxdata_8
> +#define rxdata_16 rxdata.rxdata_16
> +#define rxdata_32 rxdata.rxdata_32
> +};
>
> #endif /* __ASM_MPC52xx_PSC_H__ */
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Olof Johansson @ 2008-01-08 17:40 UTC (permalink / raw)
To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-4-git-send-email-jrigby@freescale.com>
Hi,
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 66a3d8c..81c3f05 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -470,7 +470,7 @@ config PCI
> bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
> || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
> || PPC_PS3
> - default y if !40x && !CPM2 && !8xx && !PPC_83xx \
> + default y if !40x && !CPM2 && !8xx && !PPC_512x && !PPC_83xx \
> && !PPC_85xx && !PPC_86xx
This is getting out of control. Not a comment to this specific patch,
but it's getting silly.
Btw, why no PCI by default on this platform when it seemingly is default
on 5200? I thought they were fairly similar.
> diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
> new file mode 100644
> index 0000000..399d279
> --- /dev/null
> +++ b/arch/powerpc/platforms/512x/Kconfig
> @@ -0,0 +1,20 @@
> +menu "Platform support"
> + depends on PPC_512x
> +
> +choice
> + prompt "Machine Type"
> + default MPC5121_ADS
> +
> +config MPC5121_ADS
> + bool "Freescale MPC5121E ADS"
> + select DEFAULT_UIMAGE
> + help
> + This option enables support for the MPC5121E ADS board.
> +
> +endchoice
For new platforms it makes more sense to make it possible to build
multiplatform kernels instead of using 'choice'.
I know some embedded board guys prefer to build a custom kernel for just
their board (since it means extra revenue for them to spin a kernel
for every customer), but it's still convenient to be able to build
multiplatform kernels. Especially since there's some companies out there
with intent to make end-user products with this cpu.
> @@ -0,0 +1,90 @@
> +#include <asm/system.h>
> +#include <asm/atomic.h>
> +#include <asm/machdep.h>
> +#include <asm/ipic.h>
> +#include <asm/prom.h>
> +#include <asm/time.h>
> +#include <asm/of_platform.h>
Stephen will tell you to include linux/of_platform.h instead. :-)
> @@ -229,7 +229,7 @@ config NR_CPUS
>
> config NOT_COHERENT_CACHE
> bool
> - depends on 4xx || 8xx || E200
> + depends on 4xx || 8xx || E200 || PPC_512x
> default y
Why do you need this, when 5200 doesn't?
-Olof
^ permalink raw reply
* Re: [PATCH 6/7] Add mpc512x_find_ips_freq
From: Grant Likely @ 2008-01-08 17:27 UTC (permalink / raw)
To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-7-git-send-email-jrigby@freescale.com>
Looks good to me; but I'd just merge this one with the earlier patch
that adds 5121 board support.
Cheers,
g.
On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> Added mpc512x_find_ips_freq needed by the following
> serial driver patch. It is basically a renamed
> mpc512x_find_ipd_freq from 52xx.
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> ---
> arch/powerpc/platforms/512x/mpc5121_ads.c | 28 ++++++++++++++++++++++++++++
> include/asm-powerpc/mpc512x.h | 22 ++++++++++++++++++++++
> 2 files changed, 50 insertions(+), 0 deletions(-)
> create mode 100644 include/asm-powerpc/mpc512x.h
>
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
> index a860bf0..2f4cfee 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
> @@ -36,6 +36,34 @@
> #include <asm/time.h>
> #include <asm/of_platform.h>
>
> +/**
> + * mpc512x_find_ips_freq - Find the IPB bus frequency for a device
> + * @node: device node
> + *
> + * Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
> + */
> +unsigned long
> +mpc512x_find_ips_freq(struct device_node *node)
> +{
> + struct device_node *np;
> + const unsigned int *p_ips_freq = NULL;
> +
> + of_node_get(node);
> + while (node) {
> + p_ips_freq = of_get_property(node, "bus-frequency", NULL);
> + if (p_ips_freq)
> + break;
> +
> + np = of_get_parent(node);
> + of_node_put(node);
> + node = np;
> + }
> + if (node)
> + of_node_put(node);
> +
> + return p_ips_freq ? *p_ips_freq : 0;
> +}
> +
> static void __init mpc5121_ads_setup_arch(void)
> {
> if (ppc_md.progress)
> diff --git a/include/asm-powerpc/mpc512x.h b/include/asm-powerpc/mpc512x.h
> new file mode 100644
> index 0000000..c48a165
> --- /dev/null
> +++ b/include/asm-powerpc/mpc512x.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * Author: John Rigby, <jrigby@freescale.com>, Friday Apr 13 2007
> + *
> + * Description:
> + * MPC5121 Prototypes and definitions
> + *
> + * This 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.
> + *
> + */
> +
> +#ifndef __ASM_POWERPC_MPC512x_H__
> +#define __ASM_POWERPC_MPC512x_H__
> +
> +extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
> +
> +#endif /* __ASM_POWERPC_MPC512x_H__ */
> +
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: Generic MMC-over-SPI binding?
From: Arnd Bergmann @ 2008-01-08 17:27 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linuxppc-embedded
In-Reply-To: <47838708.5050008@hogyros.de>
On Tuesday 08 January 2008, Simon Richter wrote:
> in an embedded system similar to the lite5200 board, there is an MMC
> card socket connected to one of the PSCs. Ideally, I'd like to express
> this fact via the device tree and have the kernel bind the mmc-spi
> driver to the SPI interface, but I cannot find any place where to insert
> this code that I feel comfortable with.
> ...
> Any ideas?
>
One way you could do it would be to have an spi_board_info in the
way that mpc832x_spi_init does it, but that would not make use of the
device tree.
What would probably be a better way is to call spi_new_device()
from the mpc52xx_psc_spi driver, with an spi_board_info you generate
on the fly for each child of the spi controller.
The important part where this connects to the mmc-spi driver is that
you need to set spi_board_info->modalias to "mmc-spi", if the
device node can be identified as an mmc card.
We'd have to define a list of valid identifications of SPI devices
in the device tree, and teach the SPI drivers how they relate to
linux device drivers like mmc-spi.
Since that part of the code would be used by all device tree based
SPI master drivers, it should be in a separate module, which can
consist of a single exported function, like (paraphrased):
void spi_of_scan_master(struct spi_master *master)
{
struct device_node *child;
of_dev_for_each_child(master->dev->node, child) {
struct spi_board_info *info;
info = kzalloc(sizeof (*info), GFP_KERNEL);
if (of_device_is_compatible(child, "spi,mmc"))
strcpy(info->modalias, "mmc-spi");
else if (of_device_is_compatible(child, "spi,foo"))
strcpy(info->modalias, "foo");
else
strcpy(info->modalias, "");
info->irq = irq_of_parse_and_map(child);
spi_new_device(master, child);
}
}
Then you call that function after registering the master, from
mpc52xx_psc_spi_of_probe.
Arnd <><
^ permalink raw reply
* Re: [PATCH 5/7] Separate MPC52xx PSC FIFO registers from rest of PSC
From: Grant Likely @ 2008-01-08 17:26 UTC (permalink / raw)
To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-6-git-send-email-jrigby@freescale.com>
On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> This is in preparation for the addition of MPC512x
> PSC support. The main difference in the 512x is
> in the fifo registers.
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
Looks good, I'll pick this one up.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> drivers/serial/mpc52xx_uart.c | 10 ++++++----
> include/asm-powerpc/mpc52xx_psc.h | 3 +++
> include/asm-ppc/mpc52xx_psc.h | 3 +++
> 3 files changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
> index ec36ad7..25a91c9 100644
> --- a/drivers/serial/mpc52xx_uart.c
> +++ b/drivers/serial/mpc52xx_uart.c
> @@ -111,6 +111,7 @@ static void mpc52xx_uart_of_enumerate(void);
> #endif
>
> #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
> +#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
>
>
> /* Forward declaration of the interruption handling routine */
> @@ -222,6 +223,7 @@ static int
> mpc52xx_uart_startup(struct uart_port *port)
> {
> struct mpc52xx_psc __iomem *psc = PSC(port);
> + struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
> int ret;
>
> /* Request IRQ */
> @@ -238,10 +240,10 @@ mpc52xx_uart_startup(struct uart_port *port)
>
> out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
>
> - out_8(&psc->rfcntl, 0x00);
> - out_be16(&psc->rfalarm, 0x1ff);
> - out_8(&psc->tfcntl, 0x07);
> - out_be16(&psc->tfalarm, 0x80);
> + out_8(&fifo->rfcntl, 0x00);
> + out_be16(&fifo->rfalarm, 0x1ff);
> + out_8(&fifo->tfcntl, 0x07);
> + out_be16(&fifo->tfalarm, 0x80);
>
> port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
> out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
> diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h
> index 26690d2..bea42b9 100644
> --- a/include/asm-powerpc/mpc52xx_psc.h
> +++ b/include/asm-powerpc/mpc52xx_psc.h
> @@ -153,6 +153,9 @@ struct mpc52xx_psc {
> u8 reserved16[3];
> u8 irfdr; /* PSC + 0x54 */
> u8 reserved17[3];
> +};
> +
> +struct mpc52xx_psc_fifo {
> u16 rfnum; /* PSC + 0x58 */
> u16 reserved18;
> u16 tfnum; /* PSC + 0x5c */
> diff --git a/include/asm-ppc/mpc52xx_psc.h b/include/asm-ppc/mpc52xx_psc.h
> index c82b8d4..39fcd02 100644
> --- a/include/asm-ppc/mpc52xx_psc.h
> +++ b/include/asm-ppc/mpc52xx_psc.h
> @@ -159,6 +159,9 @@ struct mpc52xx_psc {
> u8 reserved16[3];
> u8 irfdr; /* PSC + 0x54 */
> u8 reserved17[3];
> +};
> +
> +struct mpc52xx_psc_fifo {
> u16 rfnum; /* PSC + 0x58 */
> u16 reserved18;
> u16 tfnum; /* PSC + 0x5c */
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 4/7] Device tree for MPC5121 ADS
From: Grant Likely @ 2008-01-08 17:25 UTC (permalink / raw)
To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-5-git-send-email-jrigby@freescale.com>
Comments below.
On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> Bare minimum tree containing only
> what is currently supported.
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> ---
> arch/powerpc/boot/dts/mpc5121ads.dts | 102 ++++++++++++++++++++++++++++++++++
> 1 files changed, 102 insertions(+), 0 deletions(-)
> create mode 100644 arch/powerpc/boot/dts/mpc5121ads.dts
>
> diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
> new file mode 100644
> index 0000000..26471ff
> --- /dev/null
> +++ b/arch/powerpc/boot/dts/mpc5121ads.dts
> @@ -0,0 +1,102 @@
> +/*
> + * MPC5121E MDS Device Tree Source
> + *
> + * Copyright 2007 Freescale Semiconductor Inc.
> + *
> + * 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.
> + */
> +
> +/ {
> + model = "MPC5121ADS";
> + compatible = "MPC5121ADS";
"fsl, mpc5121ads" (drop the caps and use the fsl, prefix)
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + cpus {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + PowerPC,5121@0 {
> + device_type = "cpu";
> + reg = <0>;
> + d-cache-line-size = <20>; // 32 bytes
> + i-cache-line-size = <20>; // 32 bytes
> + d-cache-size = <8000>; // L1, 32K
> + i-cache-size = <8000>; // L1, 32K
> + ref-frequency = <3ef1480>; // 66MHz ref clock
> + timebase-frequency = <2f34f60>; // 49.5MHz (396MHz/8) makes time tick correctly
> + bus-frequency = <bcd3d80>; // 198MHz csb bus
> + clock-frequency = <179a7b00>; // 396MHz ppc core ??
> + 32-bit;
> + };
> + };
> +
> + memory {
> + device_type = "memory";
> + reg = <00000000 10000000>; // 256MB at 0
> + };
> +
> + cpld@82000000 {
> + device_type = "board-control";
> + reg = <82000000 8000>;
> + };
> +
> + soc5121@80000000 {
soc@80000000
"soc<cpu>@<addr>" is no longer recommended.
> + #address-cells = <1>;
> + #size-cells = <1>;
> + #interrupt-cells = <2>;
> + device_type = "soc";
- Drop device_type property
- add: compatible = "fsl,mpc5121-immr";
> + ranges = <0 80000000 400000>;
> + reg = <80000000 400000>;
> + ref-frequency = <3ef1480>; // 66MHz ref
> + bus-frequency = <5e69ec0>; // 99MHz ips ref
> +
> + // IPIC
> + // interrupts cell = <intr #, sense>
> + // sense values match linux IORESOURCE_IRQ_* defines:
> + // sense == 8: Level, low assertion
> + // sense == 2: Edge, high-to-low change
> + //
> + ipic: pic@c00 {
> + interrupt-controller;
> + #address-cells = <0>;
> + #interrupt-cells = <2>;
> + reg = <c00 100>;
> + built-in;
> + device_type = "ipic";
> + };
> +
> + // 512x PSCs are not 52xx PSCs compatible
> + // PSC3 serial port A aka ttyPSC0
> + serial@11300 {
> + device_type = "serial";
> + compatible = "mpc512x-psc-uart";
Specify the *exact* version in compatible first. You can add generic
forms after that if you like, but the first entry should always be
exact (as per the generic names recommended practice). It should be:
compatible = "fsl,mpc5121-psc-uart".
Also, make sure all compatible properties have the 'fsl,' prefix.
> + port-number = <0>; // Logical port assignment
> + cell-index = <3>;
> + reg = <11300 100>;
> + interrupts = <28 8>; // actually the fifo irq
> + interrupt-parent = < &ipic >;
> + };
> +
> + // PSC4 serial port B aka ttyPSC1
> + serial@11400 {
> + device_type = "serial";
> + compatible = "mpc512x-psc-uart";
> + port-number = <1>; // Logical port assignment
Drop port-number. Aliases will be used instead.
> + cell-index = <4>;
> + reg = <11400 100>;
> + interrupts = <28 8>; // actually the fifo irq
> + interrupt-parent = < &ipic >;
> + };
> +
> + pscsfifo@11f00 {
> + compatible = "mpc512x-pscsfifo";
> + reg = <11f00 100>;
> + interrupts = <28 8>;
> + interrupt-parent = < &ipic >;
> + };
> + };
> +};
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Grant Likely @ 2008-01-08 17:19 UTC (permalink / raw)
To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-4-git-send-email-jrigby@freescale.com>
Looks pretty good; major comment is that it should be multiplatform enabled.
Cheers,
g.
On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> 512x is very similar to 83xx and most
> of this is patterned after code from 83xx
>
> New platform:
> changed:
> arch/powerpc/Kconfig
> arch/powerpc/platforms/Kconfig
> arch/powerpc/platforms/Kconfig.cputype
> arch/powerpc/platforms/Makefile
> new:
> arch/powerpc/platforms/512x/*
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> ---
> arch/powerpc/Kconfig | 2 +-
> arch/powerpc/platforms/512x/Kconfig | 20 ++++++
> arch/powerpc/platforms/512x/Makefile | 4 +
> arch/powerpc/platforms/512x/mpc5121_ads.c | 90 +++++++++++++++++++++++++++++
> arch/powerpc/platforms/Kconfig | 8 +++
> arch/powerpc/platforms/Kconfig.cputype | 6 +-
> arch/powerpc/platforms/Makefile | 1 +
> 7 files changed, 127 insertions(+), 4 deletions(-)
> create mode 100644 arch/powerpc/platforms/512x/Kconfig
> create mode 100644 arch/powerpc/platforms/512x/Makefile
> create mode 100644 arch/powerpc/platforms/512x/mpc5121_ads.c
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 66a3d8c..81c3f05 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -470,7 +470,7 @@ config PCI
> bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
> || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
> || PPC_PS3
> - default y if !40x && !CPM2 && !8xx && !PPC_83xx \
> + default y if !40x && !CPM2 && !8xx && !PPC_512x && !PPC_83xx \
> && !PPC_85xx && !PPC_86xx
> default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
> default PCI_QSPAN if !4xx && !CPM2 && 8xx
> diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
> new file mode 100644
> index 0000000..399d279
> --- /dev/null
> +++ b/arch/powerpc/platforms/512x/Kconfig
> @@ -0,0 +1,20 @@
> +menu "Platform support"
> + depends on PPC_512x
> +
> +choice
> + prompt "Machine Type"
> + default MPC5121_ADS
You should drop this choice and make mpc512x support multiplatform instead.
You might also want to consider renaming platforms/52xx to
platforms/5xxx and putting the 512x boards there instead.
> +
> +config MPC5121_ADS
> + bool "Freescale MPC5121E ADS"
> + select DEFAULT_UIMAGE
> + help
> + This option enables support for the MPC5121E ADS board.
Make this depend on PPC_MULTIPLATFORM and PPC32
> +
> +endchoice
> +
> +config MPC5121
> + bool
> + default y if MPC5121_ADS
Drop the default and make the MPC5121_ADS select MPC5121.
Also I recommend change this to PPC_MPC5121 instead of MPC5121 (better
namespace)
> +
> +endmenu
> diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
> new file mode 100644
> index 0000000..232c89f
> --- /dev/null
> +++ b/arch/powerpc/platforms/512x/Makefile
> @@ -0,0 +1,4 @@
> +#
> +# Makefile for the Freescale PowerPC 512x linux kernel.
> +#
> +obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
> new file mode 100644
> index 0000000..a860bf0
> --- /dev/null
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
> @@ -0,0 +1,90 @@
> +/*
> + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007
> + *
> + * Description:
> + * MPC5121 ADS board setup
> + *
> + * This 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 <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/reboot.h>
> +#include <linux/kdev_t.h>
> +#include <linux/major.h>
> +#include <linux/console.h>
> +#include <linux/delay.h>
> +#include <linux/seq_file.h>
> +#include <linux/root_dev.h>
> +#include <linux/time.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +
> +#include <asm/system.h>
> +#include <asm/atomic.h>
> +#include <asm/machdep.h>
> +#include <asm/ipic.h>
> +#include <asm/prom.h>
> +#include <asm/time.h>
> +#include <asm/of_platform.h>
> +
> +static void __init mpc5121_ads_setup_arch(void)
> +{
> + if (ppc_md.progress)
> + ppc_md.progress("mpc5121_ads_setup_arch()", 0);
> +
> + printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n");
> +}
This function doesn't do anything; just drop it
> +
> +static void __init mpc5121_ads_declare_of_platform_devices(void)
> +{
> + /* Find every child of the SOC node and add it to of_platform */
> + if (of_platform_bus_probe(NULL, NULL, NULL))
> + printk(KERN_ERR __FILE__ ": "
> + "Error while probing of_platform bus\n");
> +}
> +
> +static void __init mpc5121_ads_init_IRQ(void)
> +{
> + struct device_node *np;
> +
> + np = of_find_node_by_type(NULL, "ipic");
> + if (!np)
> + return;
> +
> + ipic_init(np, 0);
> +
> + /*
> + * Initialize the default interrupt mapping priorities,
> + * in case the boot rom changed something on us.
> + */
> + ipic_set_default_priority();
> +}
> +
> +/*
> + * Called very early, MMU is off, device-tree isn't unflattened
> + */
> +static int __init mpc5121_ads_probe(void)
> +{
> + unsigned long root = of_get_flat_dt_root();
> +
> + return of_flat_dt_is_compatible(root, "MPC5121ADS");
Use "fsl,mpc5121ads" instead.
> +}
> +
> +define_machine(mpc5121_ads) {
> + .name = "MPC5121 ADS",
> + .probe = mpc5121_ads_probe,
> + .setup_arch = mpc5121_ads_setup_arch,
> + .init = mpc5121_ads_declare_of_platform_devices,
> + .init_IRQ = mpc5121_ads_init_IRQ,
> + .get_irq = ipic_get_irq,
> + .calibrate_decr = generic_calibrate_decr,
> +};
> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
> index ad9b1c0..1daf47f 100644
> --- a/arch/powerpc/platforms/Kconfig
> +++ b/arch/powerpc/platforms/Kconfig
> @@ -25,6 +25,13 @@ config PPC_83xx
> select IPIC
> select WANT_DEVICE_TREE
>
> +config PPC_512x
> + bool "Freescale 512x"
> + depends on 6xx
> + select FSL_SOC
> + select IPIC
> + select WANT_DEVICE_TREE
> +
Drop this entry so that 512x can be multiplatform instead.
> config PPC_86xx
> bool "Freescale 86xx"
> depends on 6xx
> @@ -41,6 +48,7 @@ config CLASSIC32
> source "arch/powerpc/platforms/pseries/Kconfig"
> source "arch/powerpc/platforms/iseries/Kconfig"
> source "arch/powerpc/platforms/chrp/Kconfig"
> +source "arch/powerpc/platforms/512x/Kconfig"
> source "arch/powerpc/platforms/52xx/Kconfig"
> source "arch/powerpc/platforms/powermac/Kconfig"
> source "arch/powerpc/platforms/prep/Kconfig"
> diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
> index c3ee0b5..e21ffa5 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -14,7 +14,7 @@ choice
> There are five families of 32 bit PowerPC chips supported.
> The most common ones are the desktop and server CPUs (601, 603,
> 604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
> - embedded 52xx/82xx/83xx/86xx counterparts.
> + embedded 512x/52xx/82xx/83xx/86xx counterparts.
> The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
> (85xx) each form a family of their own that is not compatible
> with the others.
> @@ -22,7 +22,7 @@ choice
> If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
>
> config 6xx
> - bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
> + bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
5xxx maybe?
> select PPC_FPU
>
> config PPC_85xx
> @@ -229,7 +229,7 @@ config NR_CPUS
>
> config NOT_COHERENT_CACHE
> bool
> - depends on 4xx || 8xx || E200
> + depends on 4xx || 8xx || E200 || PPC_512x
> default y
>
> config CHECK_CACHE_COHERENCY
> diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
> index 6d9079d..633a599 100644
> --- a/arch/powerpc/platforms/Makefile
> +++ b/arch/powerpc/platforms/Makefile
> @@ -11,6 +11,7 @@ endif
> obj-$(CONFIG_PPC_CHRP) += chrp/
> obj-$(CONFIG_40x) += 40x/
> obj-$(CONFIG_44x) += 44x/
> +obj-$(CONFIG_PPC_512x) += 512x/
> obj-$(CONFIG_PPC_MPC52xx) += 52xx/
> obj-$(CONFIG_PPC_8xx) += 8xx/
> obj-$(CONFIG_PPC_82xx) += 82xx/
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* kernel panic after upgrading to 2.6.22
From: raul.moreno @ 2008-01-08 16:33 UTC (permalink / raw)
To: linuxppc-embedded
Hello everybody!
I have upgraded from 2.6.15 to 2.6.22 with a mpc866 processor. I haven=
't
got any idea what is happening in the system, but I got a kernel panic.=
The
direction of the kernel panic points to the "get_index( )" call into
"prio_tree_insert( )".
I don't think the problem is caused by the uart cpm, but it's also a
possibility.
Here is the console message:
Linux version 2.6.22.14-ELinOS-453 (sermb@pt-330039) (gcc version 3.4.4=
(ELinOS 4.2 3.4.4-38 2007-11-23)) #93 PREEMPT Tue Jan 8 16:8
Zone PFN ranges:
DMA 0 -> 32768
Normal 32768 -> 32768
early_node_map[1] active PFN ranges
0: 0 -> 32768
Built 1 zonelists. Total pages: 32512
Kernel command line:
PID hash table entries: 512 (order: 9, 2048 bytes)
Decrementer Frequency =3D 375000000/60
cpm_uart: console: compat mode
CPM uart[-]:init portdesc
CPM uart[0]:allocbuf
CPM uart[0]:initbd
CPM uart[0]:init_smc
CPM uart[0]:set_termios
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 125824k available (1424k kernel code, 288k data, 2192k init, 0k=
highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
JFFS2 version 2.2. (NAND) =C2=A9 2001-2006 Red Hat, Inc.
io scheduler noop registered (default)
io scheduler anticipatory registered
Serial: CPM driver $Revision: 0.02 $
cpm_uart: WARNING: no UART devices found on platform bus!
cpm_uart: the driver will guess configuration, but this mode is no long=
er
supported.
CPM uart[0]:config_port
CPM uart[0]:request port
CPM uart[0]:uart_type
ttyCPM0 at MMIO 0xff000a80 (irq =3D 20) is a CPM UART
CPM uart[1]:config_port
CPM uart[1]:request port
CPM uart[1]:allocbuf
CPM uart[1]:initbd
CPM uart[1]:init_smc
CPM uart[1]:uart_type
ttyCPM1 at MMIO 0xff000a90 (irq =3D 19) is a CPM UART
TCP cubic registered
NET: Registered protocol family 1
Freeing unused kernel memory: 2192k init
CPM uart[0]:startup
CPM uart[0]:set_termios
Oops: kernel access of bad area, sig: 11 [#1]
PREEMPT
NIP: c00c9cdc LR: c00c9f2c CTR: 00000000
REGS: c0529cd0 TRAP: 0300 Not tainted (2.6.22.14-ELinOS-453)
MSR: 00009032 <EE,ME,IR,DR> CR: 35093059 XER: a0007a00
DAR: ff801005, DSISR: c0000000
TASK =3D c0524ae0[1] 'init' THREAD: c0528000
GPR00: c00c9f2c c0529d80 c0524ae0 ff800fff c03be29c c0529d98 c0529d9c
c03be278
GPR08: 00000000 00000000 c03be278 00000000 35093059 00000008 30027ff0
10001c3c
GPR16: 0ffd8000 00000129 00000000 c7c84578 00000000 c7c8458c 35093053
95053053
GPR24: 00000000 c03be278 c03be29c c7c8458c c03be29c c03be278 c03be56c
c03be320
Call Trace:
[c0529d80] [c03be2cc] (unreliable)
[c0529d90] [c00c9f2c]
[c0529dd0] [c0047b3c]
[c0529df0] [c004e1a8]
[c0529e50] [c004f234]
[c0529e70] [c004f324]
[c0529eb0] [c004f720]
[c0529f10] [c000633c]
[c0529f40] [c0002a80]
Instruction dump:
7c8803a6 4e800021 38000001 7c030378 80010014 38210010 7c0803a6 4e800020=
7c0802a6 9421fff0 3944ffdc 90010014 <a0030006> 2f800000 419e0048 812a00=
44
Kernel panic - not syncing: Attempted to kill init!
Rebooting in 180 seconds..
Does anyone know what the problem could be?
Ra=FAl Moreno=
^ permalink raw reply
* Re: [PATCH] i2c-ibm_iic driver - new patch
From: Scott Wood @ 2008-01-08 16:40 UTC (permalink / raw)
To: Sean MacLennan
Cc: Stephen Rothwell, Stefan Roese, Arnd Bergmann, linuxppc-dev
In-Reply-To: <4783108B.6070308@pikatech.com>
On Tue, Jan 08, 2008 at 12:56:27AM -0500, Sean MacLennan wrote:
> Stephen Rothwell wrote:
> > On Mon, 07 Jan 2008 21:03:12 -0500 Sean MacLennan <smaclennan@pikatech.com> wrote:
> >> +static int __devinit iic_probe(struct of_device *ofdev,
> >> + const struct of_device_id *match)
> >>
> >
> > Indenting could be better.
> >
> Sorry. Since this kernel is in a "work" directory and not in
> /usr/src/linux* my rules for deciding on the tab size didn't work :( I
> tried to correct the tabbing.
Better to tab to the semantic indentation level (in this case there is
none), and then use spaces to align -- that way it looks right regardless of
what the tab size is set to.
-Scott
^ permalink raw reply
* Re: How to write a device driver in such a fashion .????
From: Scott Wood @ 2008-01-08 16:42 UTC (permalink / raw)
To: Misbah khan; +Cc: linuxppc-dev
In-Reply-To: <14682271.post@talk.nabble.com>
On Mon, Jan 07, 2008 at 08:31:10PM -0800, Misbah khan wrote:
>
> using mmap() in application to access the h/w is only possible if the device
> memory is mapped in the kernel virtual memory how come we directly map to
> the physical memory to virtual from user space ???
No, /dev/mem takes physical addresses, not kernel virtual.
-Scott
^ permalink raw reply
* [PATCH v7] qe: add ability to upload QE firmware
From: Timur Tabi @ 2008-01-08 16:30 UTC (permalink / raw)
To: galak, linuxppc-dev, sfr; +Cc: Timur Tabi
Define the layout of a binary blob that contains a QE firmware and instructions
on how to upload it. Add function qe_upload_firmware() to parse the blob
and perform the actual upload. Fully define 'struct rsp' in immap_qe.h to
include the actual RISC Special Registers. Added description of a new
QE firmware node to booting-without-of.txt.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
Updated w.r.t. comments from Stephen R.
This patch is for Kumar's for-2.6.25 branch. This code is necessary for
my QE UART driver.
Documentation/powerpc/00-INDEX | 3 +
Documentation/powerpc/booting-without-of.txt | 33 +++-
Documentation/powerpc/qe_firmware.txt | 295 ++++++++++++++++++++++++++
arch/powerpc/platforms/Kconfig | 1 +
arch/powerpc/sysdev/qe_lib/qe.c | 247 +++++++++++++++++++++
include/asm-powerpc/immap_qe.h | 34 +++-
include/asm-powerpc/qe.h | 61 ++++++
7 files changed, 670 insertions(+), 4 deletions(-)
create mode 100644 Documentation/powerpc/qe_firmware.txt
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index 94a3c57..3be84aa 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -28,3 +28,6 @@ sound.txt
- info on sound support under Linux/PPC
zImage_layout.txt
- info on the kernel images for Linux/PPC
+qe_firmware.txt
+ - describes the layout of firmware binaries for the Freescale QUICC
+ Engine and the code that parses and uploads the microcode therein.
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index ee0209a..53c2295 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -52,7 +52,10 @@ Table of Contents
i) Freescale QUICC Engine module (QE)
j) CFI or JEDEC memory-mapped NOR flash
k) Global Utilities Block
- l) Xilinx IP cores
+ l) Freescale Communications Processor Module
+ m) Chipselect/Local Bus
+ n) 4xx/Axon EMAC ethernet nodes
+ o) Xilinx IP cores
VII - Specifying interrupt information for devices
1) interrupts property
@@ -1788,6 +1791,32 @@ platforms are moved over to use the flattened-device-tree model.
};
};
+ viii) Uploaded QE firmware
+
+ If a new firwmare has been uploaded to the QE (usually by the
+ boot loader), then a 'firmware' child node should be added to the QE
+ node. This node provides information on the uploaded firmware that
+ device drivers may need.
+
+ Required properties:
+ - id: The string name of the firmware. This is taken from the 'id'
+ member of the qe_firmware structure of the uploaded firmware.
+ Device drivers can search this string to determine if the
+ firmware they want is already present.
+ - extended-modes: The Extended Modes bitfield, taken from the
+ firmware binary. It is a 64-bit number represented
+ as an array of two 32-bit numbers.
+ - virtual-traps: The virtual traps, taken from the firmware binary.
+ It is an array of 8 32-bit numbers.
+
+ Example:
+
+ firmware {
+ id = "Soft-UART";
+ extended-modes = <0 0>;
+ virtual-traps = <0 0 0 0 0 0 0 0>;
+ }
+
j) CFI or JEDEC memory-mapped NOR flash
Flash chips (Memory Technology Devices) are often used for solid state
@@ -2270,7 +2299,7 @@ platforms are moved over to use the flattened-device-tree model.
available.
For Axon: 0x0000012a
- l) Xilinx IP cores
+ o) Xilinx IP cores
The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
in Xilinx Spartan and Virtex FPGAs. The devices cover the whole range
diff --git a/Documentation/powerpc/qe_firmware.txt b/Documentation/powerpc/qe_firmware.txt
new file mode 100644
index 0000000..8962664
--- /dev/null
+++ b/Documentation/powerpc/qe_firmware.txt
@@ -0,0 +1,295 @@
+ Freescale QUICC Engine Firmware Uploading
+ -----------------------------------------
+
+(c) 2007 Timur Tabi <timur at freescale.com>,
+ Freescale Semiconductor
+
+Table of Contents
+=================
+
+ I - Software License for Firmware
+
+ II - Microcode Availability
+
+ III - Description and Terminology
+
+ IV - Microcode Programming Details
+
+ V - Firmware Structure Layout
+
+ VI - Sample Code for Creating Firmware Files
+
+Revision Information
+====================
+
+November 30, 2007: Rev 1.0 - Initial version
+
+I - Software License for Firmware
+=================================
+
+Each firmware file comes with its own software license. For information on
+the particular license, please see the license text that is distributed with
+the firmware.
+
+II - Microcode Availability
+===========================
+
+Firmware files are distributed through various channels. Some are available on
+http://opensource.freescale.com. For other firmware files, please contact
+your Freescale representative or your operating system vendor.
+
+III - Description and Terminology
+================================
+
+In this document, the term 'microcode' refers to the sequence of 32-bit
+integers that compose the actual QE microcode.
+
+The term 'firmware' refers to a binary blob that contains the microcode as
+well as other data that
+
+ 1) describes the microcode's purpose
+ 2) describes how and where to upload the microcode
+ 3) specifies the values of various registers
+ 4) includes additional data for use by specific device drivers
+
+Firmware files are binary files that contain only a firmware.
+
+IV - Microcode Programming Details
+===================================
+
+The QE architecture allows for only one microcode present in I-RAM for each
+RISC processor. To replace any current microcode, a full QE reset (which
+disables the microcode) must be performed first.
+
+QE microcode is uploaded using the following procedure:
+
+1) The microcode is placed into I-RAM at a specific location, using the
+ IRAM.IADD and IRAM.IDATA registers.
+
+2) The CERCR.CIR bit is set to 0 or 1, depending on whether the firmware
+ needs split I-RAM. Split I-RAM is only meaningful for SOCs that have
+ QEs with multiple RISC processors, such as the 8360. Splitting the I-RAM
+ allows each processor to run a different microcode, effectively creating an
+ asymmetric multiprocessing (AMP) system.
+
+3) The TIBCR trap registers are loaded with the addresses of the trap handlers
+ in the microcode.
+
+4) The RSP.ECCR register is programmed with the value provided.
+
+5) If necessary, device drivers that need the virtual traps and extended mode
+ data will use them.
+
+Virtual Microcode Traps
+
+These virtual traps are conditional branches in the microcode. These are
+"soft" provisional introduced in the ROMcode in order to enable higher
+flexibility and save h/w traps If new features are activated or an issue is
+being fixed in the RAM package utilizing they should be activated. This data
+structure signals the microcode which of these virtual traps is active.
+
+This structure contains 6 words that the application should copy to some
+specific been defined. This table describes the structure.
+
+ ---------------------------------------------------------------
+ | Offset in | | Destination Offset | Size of |
+ | array | Protocol | within PRAM | Operand |
+ --------------------------------------------------------------|
+ | 0 | Ethernet | 0xF8 | 4 bytes |
+ | | interworking | | |
+ ---------------------------------------------------------------
+ | 4 | ATM | 0xF8 | 4 bytes |
+ | | interworking | | |
+ ---------------------------------------------------------------
+ | 8 | PPP | 0xF8 | 4 bytes |
+ | | interworking | | |
+ ---------------------------------------------------------------
+ | 12 | Ethernet RX | 0x22 | 1 byte |
+ | | Distributor Page | | |
+ ---------------------------------------------------------------
+ | 16 | ATM Globtal | 0x28 | 1 byte |
+ | | Params Table | | |
+ ---------------------------------------------------------------
+ | 20 | Insert Frame | 0xF8 | 4 bytes |
+ ---------------------------------------------------------------
+
+
+Extended Modes
+
+This is a double word bit array (64 bits) that defines special functionality
+which has an impact on the softwarew drivers. Each bit has its own impact
+and has special instructions for the s/w associated with it. This structure is
+described in this table:
+
+ -----------------------------------------------------------------------
+ | Bit # | Name | Description |
+ -----------------------------------------------------------------------
+ | 0 | General | Indicates that prior to each host command |
+ | | push command | given by the application, the software must |
+ | | | assert a special host command (push command)|
+ | | | CECDR = 0x00800000. |
+ | | | CECR = 0x01c1000f. |
+ -----------------------------------------------------------------------
+ | 1 | UCC ATM | Indicates that after issuing ATM RX INIT |
+ | | RX INIT | command, the host must issue another special|
+ | | push command | command (push command) and immediately |
+ | | | following that re-issue the ATM RX INIT |
+ | | | command. (This makes the sequence of |
+ | | | initializing the ATM receiver a sequence of |
+ | | | three host commands) |
+ | | | CECDR = 0x00800000. |
+ | | | CECR = 0x01c1000f. |
+ -----------------------------------------------------------------------
+ | 2 | Add/remove | Indicates that following the specific host |
+ | | command | command: "Add/Remove entry in Hash Lookup |
+ | | validation | Table" used in Interworking setup, the user |
+ | | | must issue another command. |
+ | | | CECDR = 0xce000003. |
+ | | | CECR = 0x01c10f58. |
+ -----------------------------------------------------------------------
+ | 3 | General push | Indicates that the s/w has to initialize |
+ | | command | some pointers in the Ethernet thread pages |
+ | | | which are used when Header Compression is |
+ | | | activated. The full details of these |
+ | | | pointers is located in the software drivers.|
+ -----------------------------------------------------------------------
+ | 4 | General push | Indicates that after issuing Ethernet TX |
+ | | command | INIT command, user must issue this command |
+ | | | for each SNUM of Ethernet TX thread. |
+ | | | CECDR = 0x00800003. |
+ | | | CECR = 0x7'b{0}, 8'b{Enet TX thread SNUM}, |
+ | | | 1'b{1}, 12'b{0}, 4'b{1} |
+ -----------------------------------------------------------------------
+ | 5 - 31 | N/A | Reserved, set to zero. |
+ -----------------------------------------------------------------------
+
+V - Firmware Structure Layout
+==============================
+
+QE microcode from Freescale is typically provided as a header file. This
+header file contains macros that define the microcode binary itself as well as
+some other data used in uploading that microcode. The format of these files
+do not lend themselves to simple inclusion into other code. Hence,
+the need for a more portable format. This section defines that format.
+
+Instead of distributing a header file, the microcode and related data are
+embedded into a binary blob. This blob is passed to the qe_upload_firmware()
+function, which parses the blob and performs everything necessary to upload
+the microcode.
+
+All integers are big-endian. See the comments for function
+qe_upload_firmware() for up-to-date implementation information.
+
+This structure supports versioning, where the version of the structure is
+embedded into the structure itself. To ensure forward and backwards
+compatibility, all versions of the structure must use the same 'qe_header'
+structure at the beginning.
+
+'header' (type: struct qe_header):
+ The 'length' field is the size, in bytes, of the entire structure,
+ including all the microcode embedded in it, as well as the CRC (if
+ present).
+
+ The 'magic' field is an array of three bytes that contains the letters
+ 'Q', 'E', and 'F'. This is an identifier that indicates that this
+ structure is a QE Firmware structure.
+
+ The 'version' field is a single byte that indicates the version of this
+ structure. If the layout of the structure should ever need to be
+ changed to add support for additional types of microcode, then the
+ version number should also be changed.
+
+The 'id' field is a null-terminated string(suitable for printing) that
+identifies the firmware.
+
+The 'count' field indicates the number of 'microcode' structures. There
+must be one and only one 'microcode' structure for each RISC processor.
+Therefore, this field also represents the number of RISC processors for this
+SOC.
+
+The 'soc' structure contains the SOC numbers and revisions used to match
+the microcode to the SOC itself. Normally, the microcode loader should
+check the data in this structure with the SOC number and revisions, and
+only upload the microcode if there's a match. However, this check is not
+made on all platforms.
+
+Although it is not recommended, you can specify '0' in the soc.model
+field to skip matching SOCs altogether.
+
+The 'model' field is a 16-bit number that matches the actual SOC. The
+'major' and 'minor' fields are the major and minor revision numbrs,
+respectively, of the SOC.
+
+For example, to match the 8323, revision 1.0:
+ soc.model = 8323
+ soc.major = 1
+ soc.minor = 0
+
+'padding' is neccessary for structure alignment. This field ensures that the
+'extended_modes' field is aligned on a 64-bit boundary.
+
+'extended_modes' is a bitfield that defines special functionality which has an
+impact on the device drivers. Each bit has its own impact and has special
+instructions for the driver associated with it. This field is stored in
+the QE library and available to any driver that calles qe_get_firmware_info().
+
+'vtraps' is an array of 8 words that contain virtual trap values for each
+virtual traps. As with 'extended_modes', this field is stored in the QE
+library and available to any driver that calles qe_get_firmware_info().
+
+'microcode' (type: struct qe_microcode):
+ For each RISC processor there is one 'microcode' structure. The first
+ 'microcode' structure is for the first RISC, and so on.
+
+ The 'id' field is a null-terminated string suitable for printing that
+ identifies this particular microcode.
+
+ 'traps' is an array of 16 words that contain hardware trap values
+ for each of the 16 traps. If trap[i] is 0, then this particular
+ trap is to be ignored (i.e. not written to TIBCR[i]). The entire value
+ is written as-is to the TIBCR[i] register, so be sure to set the EN
+ and T_IBP bits if necessary.
+
+ 'eccr' is the value to program into the ECCR register.
+
+ 'iram_offset' is the offset into IRAM to start writing the
+ microcode.
+
+ 'count' is the number of 32-bit words in the microcode.
+
+ 'code_offset' is the offset, in bytes, from the beginning of this
+ structure where the microcode itself can be found. The first
+ microcode binary should be located immediately after the 'microcode'
+ array.
+
+ 'major', 'minor', and 'revision' are the major, minor, and revision
+ version numbers, respectively, of the microcode. If all values are 0,
+ then these fields are ignored.
+
+ 'reserved' is necessary for structure alignment. Since 'microcode'
+ is an array, the 64-bit 'extended_modes' field needs to be aligned
+ on a 64-bit boundary, and this can only happen if the size of
+ 'microcode' is a multiple of 8 bytes. To ensure that, we add
+ 'reserved'.
+
+After the last microcode is a 32-bit CRC. It can be calculated using
+this algorithm:
+
+u32 crc32(const u8 *p, unsigned int len)
+{
+ unsigned int i;
+ u32 crc = 0;
+
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+ }
+ return crc;
+}
+
+VI - Sample Code for Creating Firmware Files
+============================================
+
+A Python program that creates firmware binaries from the header files normally
+distributed by Freescale can be found on http://opensource.freescale.com.
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index ea22cad..18f101b 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -265,6 +265,7 @@ config TAU_AVERAGE
config QUICC_ENGINE
bool
select PPC_LIB_RHEAP
+ select CRC32
help
The QUICC Engine (QE) is a new generation of communications
coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 21e0106..3925eae 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <linux/crc32.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -394,3 +395,249 @@ void *qe_muram_addr(unsigned long offset)
return (void *)&qe_immr->muram[offset];
}
EXPORT_SYMBOL(qe_muram_addr);
+
+/* The maximum number of RISCs we support */
+#define MAX_QE_RISC 2
+
+/* Firmware information stored here for qe_get_firmware_info() */
+static struct qe_firmware_info qe_firmware_info;
+
+/*
+ * Set to 1 if QE firmware has been uploaded, and therefore
+ * qe_firmware_info contains valid data.
+ */
+static int qe_firmware_uploaded;
+
+/*
+ * Upload a QE microcode
+ *
+ * This function is a worker function for qe_upload_firmware(). It does
+ * the actual uploading of the microcode.
+ */
+static void qe_upload_microcode(const void *base,
+ const struct qe_microcode *ucode)
+{
+ const __be32 *code = base + be32_to_cpu(ucode->code_offset);
+ unsigned int i;
+
+ if (ucode->major || ucode->minor || ucode->revision)
+ printk(KERN_INFO "qe-firmware: "
+ "uploading microcode '%s' version %u.%u.%u\n",
+ ucode->id, ucode->major, ucode->minor, ucode->revision);
+ else
+ printk(KERN_INFO "qe-firmware: "
+ "uploading microcode '%s'\n", ucode->id);
+
+ /* Use auto-increment */
+ out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
+ QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
+
+ for (i = 0; i < be32_to_cpu(ucode->count); i++)
+ out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
+}
+
+/*
+ * Upload a microcode to the I-RAM at a specific address.
+ *
+ * See Documentation/powerpc/qe-firmware.txt for information on QE microcode
+ * uploading.
+ *
+ * Currently, only version 1 is supported, so the 'version' field must be
+ * set to 1.
+ *
+ * The SOC model and revision are not validated, they are only displayed for
+ * informational purposes.
+ *
+ * 'calc_size' is the calculated size, in bytes, of the firmware structure and
+ * all of the microcode structures, minus the CRC.
+ *
+ * 'length' is the size that the structure says it is, including the CRC.
+ */
+int qe_upload_firmware(const struct qe_firmware *firmware)
+{
+ unsigned int i;
+ unsigned int j;
+ u32 crc;
+ size_t calc_size = sizeof(struct qe_firmware);
+ size_t length;
+ const struct qe_header *hdr;
+
+ if (!firmware) {
+ printk(KERN_ERR "qe-firmware: invalid pointer\n");
+ return -EINVAL;
+ }
+
+ hdr = &firmware->header;
+ length = be32_to_cpu(hdr->length);
+
+ /* Check the magic */
+ if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+ (hdr->magic[2] != 'F')) {
+ printk(KERN_ERR "qe-firmware: not a microcode\n");
+ return -EPERM;
+ }
+
+ /* Check the version */
+ if (hdr->version != 1) {
+ printk(KERN_ERR "qe-firmware: unsupported version\n");
+ return -EPERM;
+ }
+
+ /* Validate some of the fields */
+ if ((firmware->count < 1) || (firmware->count >= MAX_QE_RISC)) {
+ printk(KERN_ERR "qe-firmware: invalid data\n");
+ return -EINVAL;
+ }
+
+ /* Validate the length and check if there's a CRC */
+ calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
+
+ for (i = 0; i < firmware->count; i++)
+ /*
+ * For situations where the second RISC uses the same microcode
+ * as the first, the 'code_offset' and 'count' fields will be
+ * zero, so it's okay to add those.
+ */
+ calc_size += sizeof(__be32) *
+ be32_to_cpu(firmware->microcode[i].count);
+
+ /* Validate the length */
+ if (length != calc_size + sizeof(__be32)) {
+ printk(KERN_ERR "qe-firmware: invalid length\n");
+ return -EPERM;
+ }
+
+ /* Validate the CRC */
+ crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size));
+ if (crc != crc32(0, firmware, calc_size)) {
+ printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n");
+ return -EIO;
+ }
+
+ /*
+ * If the microcode calls for it, split the I-RAM.
+ */
+ if (!firmware->split)
+ setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR);
+
+ if (firmware->soc.model)
+ printk(KERN_INFO
+ "qe-firmware: firmware '%s' for %u V%u.%u\n",
+ firmware->id, be16_to_cpu(firmware->soc.model),
+ firmware->soc.major, firmware->soc.minor);
+ else
+ printk(KERN_INFO "qe-firmware: firmware '%s'\n",
+ firmware->id);
+
+ /*
+ * The QE only supports one microcode per RISC, so clear out all the
+ * saved microcode information and put in the new.
+ */
+ memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
+ strcpy(qe_firmware_info.id, firmware->id);
+ qe_firmware_info.extended_modes = firmware->extended_modes;
+ memcpy(qe_firmware_info.vtraps, firmware->vtraps,
+ sizeof(firmware->vtraps));
+
+ /* Loop through each microcode. */
+ for (i = 0; i < firmware->count; i++) {
+ const struct qe_microcode *ucode = &firmware->microcode[i];
+
+ /* Upload a microcode if it's present */
+ if (ucode->code_offset)
+ qe_upload_microcode(firmware, ucode);
+
+ /* Program the traps for this processor */
+ for (j = 0; j < 16; j++) {
+ u32 trap = be32_to_cpu(ucode->traps[j]);
+
+ if (trap)
+ out_be32(&qe_immr->rsp[i].tibcr[j], trap);
+ }
+
+ /* Enable traps */
+ out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
+ }
+
+ qe_firmware_uploaded = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(qe_upload_firmware);
+
+/*
+ * Get info on the currently-loaded firmware
+ *
+ * This function also checks the device tree to see if the boot loader has
+ * uploaded a firmware already.
+ */
+struct qe_firmware_info *qe_get_firmware_info(void)
+{
+ static int initialized;
+ struct property *prop;
+ struct device_node *qe;
+ struct device_node *fw = NULL;
+ const char *sprop;
+ unsigned int i;
+
+ /*
+ * If we haven't checked yet, and a driver hasn't uploaded a firmware
+ * yet, then check the device tree for information.
+ */
+ if (initialized || qe_firmware_uploaded)
+ return NULL;
+
+ initialized = 1;
+
+ /*
+ * Newer device trees have an "fsl,qe" compatible property for the QE
+ * node, but we still need to support older device trees.
+ */
+ qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!qe) {
+ qe = of_find_node_by_type(NULL, "qe");
+ if (!qe)
+ return NULL;
+ }
+
+ /* Find the 'firmware' child node */
+ for_each_child_of_node(qe, fw) {
+ if (strcmp(fw->name, "firmware") == 0)
+ break;
+ }
+
+ of_node_put(qe);
+
+ /* Did we find the 'firmware' node? */
+ if (!fw)
+ return NULL;
+
+ qe_firmware_uploaded = 1;
+
+ /* Copy the data into qe_firmware_info*/
+ sprop = of_get_property(fw, "id", NULL);
+ if (sprop)
+ strncpy(qe_firmware_info.id, sprop,
+ sizeof(qe_firmware_info.id) - 1);
+
+ prop = of_find_property(fw, "extended-modes", NULL);
+ if (prop && (prop->length == sizeof(u64))) {
+ const u64 *iprop = prop->value;
+
+ qe_firmware_info.extended_modes = *iprop;
+ }
+
+ prop = of_find_property(fw, "virtual-traps", NULL);
+ if (prop && (prop->length == 32)) {
+ const u32 *iprop = prop->value;
+
+ for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++)
+ qe_firmware_info.vtraps[i] = iprop[i];
+ }
+
+ of_node_put(fw);
+
+ return &qe_firmware_info;
+}
+EXPORT_SYMBOL(qe_get_firmware_info);
+
diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h
index aba9806..82a4526 100644
--- a/include/asm-powerpc/immap_qe.h
+++ b/include/asm-powerpc/immap_qe.h
@@ -393,9 +393,39 @@ struct dbg {
u8 res2[0x48];
} __attribute__ ((packed));
-/* RISC Special Registers (Trap and Breakpoint) */
+/*
+ * RISC Special Registers (Trap and Breakpoint). These are described in
+ * the QE Developer's Handbook.
+ */
struct rsp {
- u32 reg[0x40]; /* 64 32-bit registers */
+ __be32 tibcr[16]; /* Trap/instruction breakpoint control regs */
+ u8 res0[64];
+ __be32 ibcr0;
+ __be32 ibs0;
+ __be32 ibcnr0;
+ u8 res1[4];
+ __be32 ibcr1;
+ __be32 ibs1;
+ __be32 ibcnr1;
+ __be32 npcr;
+ __be32 dbcr;
+ __be32 dbar;
+ __be32 dbamr;
+ __be32 dbsr;
+ __be32 dbcnr;
+ u8 res2[12];
+ __be32 dbdr_h;
+ __be32 dbdr_l;
+ __be32 dbdmr_h;
+ __be32 dbdmr_l;
+ __be32 bsr;
+ __be32 bor;
+ __be32 bior;
+ u8 res3[4];
+ __be32 iatr[4];
+ __be32 eccr; /* Exception control configuration register */
+ __be32 eicr;
+ u8 res4[0x100-0xf8];
} __attribute__ ((packed));
struct qe_immap {
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index a24b7b1..430dc77 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -94,6 +94,58 @@ unsigned long qe_muram_alloc_fixed(unsigned long offset, int size);
void qe_muram_dump(void);
void *qe_muram_addr(unsigned long offset);
+/* Structure that defines QE firmware binary files.
+ *
+ * See Documentation/powerpc/qe-firmware.txt for a description of these
+ * fields.
+ */
+struct qe_firmware {
+ struct qe_header {
+ __be32 length; /* Length of the entire structure, in bytes */
+ u8 magic[3]; /* Set to { 'Q', 'E', 'F' } */
+ u8 version; /* Version of this layout. First ver is '1' */
+ } header;
+ u8 id[62]; /* Null-terminated identifier string */
+ u8 split; /* 0 = shared I-RAM, 1 = split I-RAM */
+ u8 count; /* Number of microcode[] structures */
+ struct {
+ __be16 model; /* The SOC model */
+ u8 major; /* The SOC revision major */
+ u8 minor; /* The SOC revision minor */
+ } __attribute__ ((packed)) soc;
+ u8 padding[4]; /* Reserved, for alignment */
+ __be64 extended_modes; /* Extended modes */
+ __be32 vtraps[8]; /* Virtual trap addresses */
+ u8 reserved[4]; /* Reserved, for future expansion */
+ struct qe_microcode {
+ u8 id[32]; /* Null-terminated identifier */
+ __be32 traps[16]; /* Trap addresses, 0 == ignore */
+ __be32 eccr; /* The value for the ECCR register */
+ __be32 iram_offset; /* Offset into I-RAM for the code */
+ __be32 count; /* Number of 32-bit words of the code */
+ __be32 code_offset; /* Offset of the actual microcode */
+ u8 major; /* The microcode version major */
+ u8 minor; /* The microcode version minor */
+ u8 revision; /* The microcode version revision */
+ u8 padding; /* Reserved, for alignment */
+ u8 reserved[4]; /* Reserved, for future expansion */
+ } __attribute__ ((packed)) microcode[1];
+ /* All microcode binaries should be located here */
+ /* CRC32 should be located here, after the microcode binaries */
+} __attribute__ ((packed));
+
+struct qe_firmware_info {
+ char id[64]; /* Firmware name */
+ u32 vtraps[8]; /* Virtual trap addresses */
+ u64 extended_modes; /* Extended modes */
+};
+
+/* Upload a firmware to the QE */
+int qe_upload_firmware(const struct qe_firmware *firmware);
+
+/* Obtain information on the uploaded firmware */
+struct qe_firmware_info *qe_get_firmware_info(void);
+
/* Buffer descriptors */
struct qe_bd {
__be16 status;
@@ -329,6 +381,15 @@ enum comm_dir {
#define QE_SDEBCR_BA_MASK 0x01FFFFFF
+/* Communication Processor */
+#define QE_CP_CERCR_MEE 0x8000 /* Multi-user RAM ECC enable */
+#define QE_CP_CERCR_IEE 0x4000 /* Instruction RAM ECC enable */
+#define QE_CP_CERCR_CIR 0x0800 /* Common instruction RAM */
+
+/* I-RAM */
+#define QE_IRAM_IADD_AIE 0x80000000 /* Auto Increment Enable */
+#define QE_IRAM_IADD_BADDR 0x00080000 /* Base Address */
+
/* UPC */
#define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */
#define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */
--
1.5.2.4
^ permalink raw reply related
* Re: Generic MMC-over-SPI binding?
From: Simon Richter @ 2008-01-08 16:29 UTC (permalink / raw)
To: Robert Schwebel; +Cc: linuxppc-dev, linuxppc-embedded
In-Reply-To: <20080108161120.GC3177@pengutronix.de>
Hi,
Robert Schwebel wrote:
> Or is your question how to express this in the device tree?
This. As far as I can see, using the device tree for this is currently
unsupported, and everyone who uses the mmc-spi driver just creates a
platform device in the board startup code, which strikes me as somewhat
redundant, so I think it might be good to move it into the device tree
(after all, it is still a hardware device).
Simon
^ permalink raw reply
* Re: [PATCH v2] [ALSA] Add ASoC drivers for the Freescale MPC8610 SoC
From: Liam Girdwood @ 2008-01-08 16:20 UTC (permalink / raw)
To: Takashi Iwai; +Cc: linuxppc-dev, alsa-devel, Timur Tabi
In-Reply-To: <11997322053652-git-send-email-timur@freescale.com>
On Mon, 2008-01-07 at 12:56 -0600, Timur Tabi wrote:
> Add the ASoC drivers for the Freescale MPC8610 SoC and the MPC8610 HPCD
> reference board.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
Acked-by: Liam Girdwood <lg@opensource.wolfsonmicro.com>
^ permalink raw reply
* Re: Generic MMC-over-SPI binding?
From: Robert Schwebel @ 2008-01-08 16:11 UTC (permalink / raw)
To: Simon Richter; +Cc: linuxppc-dev, linuxppc-embedded
In-Reply-To: <47838708.5050008@hogyros.de>
On Tue, Jan 08, 2008 at 03:22:00PM +0100, Simon Richter wrote:
> in an embedded system similar to the lite5200 board, there is an MMC
> card socket connected to one of the PSCs. Ideally, I'd like to express
> this fact via the device tree and have the kernel bind the mmc-spi
> driver to the SPI interface, but I cannot find any place where to insert
> this code that I feel comfortable with.
>
> - It is not a board-specific thing, because any board can just use any
> SPI bus for MMC.
>
> - The mmc-spi driver appears to be platform independent, so I'm not
> sure OF bindings should be added to it.
>
> - The generic device tree scanning does not contain any special cases
> yet, so I don't want to add one.
>
> My current thought is to create a new driver that just handles MMC on
> PSCs in SPI mode by gluing all the relevant drivers together, but that
> doesn't seem optimal to me either.
You know this driver?
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=drivers/mmc/host/mmc_spi.c;h=365024b83d3da9df9b6e4f7a9d4cf6d216ba523d;hb=HEAD
Or is your question how to express this in the device tree?
Robert
--
Dipl.-Ing. Robert Schwebel | http://www.pengutronix.de
Pengutronix - Linux Solutions for Science and Industry
Handelsregister: Amtsgericht Hildesheim, HRA 2686
Hannoversche Str. 2, 31134 Hildesheim, Germany
Phone: +49-5121-206917-0 | Fax: +49-5121-206917-9
^ permalink raw reply
* Re: [PATCH] enable built-in networking for Sequoia defconfig
From: Josh Boyer @ 2008-01-08 16:09 UTC (permalink / raw)
To: Hollis Blanchard; +Cc: linuxppc-dev
In-Reply-To: <1199489214.9673.18.camel@basalt>
On Fri, 04 Jan 2008 17:26:54 -0600
Hollis Blanchard <hollisb@us.ibm.com> wrote:
> Enable EMAC driver for Sequoia (and while we're in there, disable
> Macintosh drivers for Sequoia and Bamboo).
>
> Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
applied, thanks.
josh
^ permalink raw reply
* [PATCH 7/7] Add MPC512x PSC serial driver
From: John Rigby @ 2008-01-08 16:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1199808093-15929-7-git-send-email-jrigby@freescale.com>
mpc512x_uart.c is based on mpc52xx_uart.c with
names changed
arch/ppc support removed
512x psc fifo support added
shares mpc52xx_psc.h with 52xx driver
Signed-off-by: John Rigby <jrigby@freescale.com>
---
drivers/serial/Kconfig | 18 +
drivers/serial/Makefile | 1 +
drivers/serial/mpc512x_uart.c | 969 +++++++++++++++++++++++++++++++++++++
include/asm-powerpc/mpc52xx_psc.h | 47 ++
4 files changed, 1035 insertions(+), 0 deletions(-)
create mode 100644 drivers/serial/mpc512x_uart.c
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d7e1996..643b84a 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1113,6 +1113,24 @@ config SERIAL_SGI_L1_CONSOLE
controller serial port as your console (you want this!),
say Y. Otherwise, say N.
+config SERIAL_MPC512x
+ tristate "Freescale MPC512x family PSC serial support"
+ depends on PPC_512x
+ select SERIAL_CORE
+ help
+ This drivers support the MPC512x PSC serial ports. If you would
+ like to use them, you must answer Y or M to this option. Not that
+ for use as console, it must be included in kernel and not as a
+ module.
+
+config SERIAL_MPC512x_CONSOLE
+ bool "Console on a Freescale MPC512x family PSC serial port"
+ depends on SERIAL_MPC512x=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Select this options if you'd like to use one of the PSC serial port
+ of the Freescale MPC52xx family as a console.
+
config SERIAL_MPC52xx
tristate "Freescale MPC52xx family PSC serial support"
depends on PPC_MPC52xx
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index af6377d..13e8176 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
obj-$(CONFIG_SERIAL_IMX) += imx.o
+obj-$(CONFIG_SERIAL_MPC512x) += mpc512x_uart.o
obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
obj-$(CONFIG_SERIAL_ICOM) += icom.o
obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
diff --git a/drivers/serial/mpc512x_uart.c b/drivers/serial/mpc512x_uart.c
new file mode 100644
index 0000000..e2ff0b8
--- /dev/null
+++ b/drivers/serial/mpc512x_uart.c
@@ -0,0 +1,969 @@
+/*
+ * Driver for the PSC of the Freescale MPC512x PSCs configured as UARTs.
+ *
+ * Copyright (C) 2007 Freescale Semiconductor Inc
+ * John Rigby <jrigby@freescale.com>
+ *
+ * Fork of mpc512x_uart.c:
+ *
+ * Copyright (C) 2006 Secret Lab Technologies Ltd.
+ * Grant Likely <grant.likely@secretlab.ca>
+ * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 MontaVista, Software, Inc.
+ * Dale Farnsworth <dfarnsworth@mvista.com>.
+ *
+ * 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.
+ */
+
+/*
+ * The 512x PSCs are almost identical to those on 52xx. The most notable
+ * difference is that the FIFOs have been separated out. This file
+ * still uses the mpc52xx_psc.h which has had the fifo differences added.
+ *
+ * TODO (maybe) abstract out the fifo differences and merge this back
+ * into mpc512x_serial.c
+ */
+
+/* OF Platform device Usage :
+ *
+ * This driver is only used for PSCs configured in uart mode. The device
+ * tree will have a node for each PSC in uart mode w/ device_type = "serial"
+ * and "mpc52xx-psc-uart" in the compatible string
+ *
+ * By default, PSC devices are enumerated in the order they are found. However
+ * a particular PSC number can be forced by adding 'device_no = <port#>'
+ * to the device node.
+ *
+ * The driver init all necessary registers to place the PSC in uart mode without
+ * DCD. However, the pin multiplexing aren't changed and should be set either
+ * by the bootloader or in the platform init code.
+ */
+
+#undef DEBUG
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/of_platform.h>
+#include <asm/mpc52xx_psc.h>
+#include <asm/mpc512x.h>
+
+#if defined(CONFIG_SERIAL_MPC512x_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_PSC_MAJOR 204
+#define SERIAL_PSC_MINOR 148
+
+#define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */
+
+static struct uart_port mpc512x_uart_ports[MPC52xx_PSC_MAXNUM];
+
+/* lookup table for matching device nodes to index numbers */
+static struct device_node *mpc512x_uart_nodes[MPC52xx_PSC_MAXNUM];
+
+static void mpc512x_uart_of_enumerate(void);
+
+static unsigned long getuartclk(void *p)
+{
+ return mpc512x_find_ips_freq(p);
+}
+
+#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
+#define FIFO(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
+
+/* Forward declaration of the interruption handling routine */
+static irqreturn_t mpc512x_uart_int(int irq, void *dev_id);
+
+/* Simple macro to test if a port is console or not. This one is taken
+ * for serial_core.c and maybe should be moved to serial_core.h ? */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port) (0)
+#endif
+
+static struct of_device_id mpc512x_uart_of_match[] = {
+ {.type = "serial", .compatible = "mpc512x-psc-uart",},
+ {},
+};
+
+/* ======================================================================== */
+/* UART operations */
+/* ======================================================================== */
+
+static unsigned int mpc512x_uart_tx_empty(struct uart_port *port)
+{
+ int status;
+
+ status = in_be32(&FIFO(port)->txsr);
+ return (status & MPC512x_PSC_FIFO_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static void mpc512x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* Not implemented */
+}
+
+static unsigned int mpc512x_uart_get_mctrl(struct uart_port *port)
+{
+ /* Not implemented */
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void mpc512x_uart_stop_tx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+ unsigned long tx_fifo_imr;
+
+ tx_fifo_imr = in_be32(&FIFO(port)->tximr);
+ tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_uart_start_tx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+ unsigned long tx_fifo_imr;
+
+ tx_fifo_imr = in_be32(&FIFO(port)->tximr);
+ tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc512x_uart_send_xchar(struct uart_port *port, char ch)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->x_char = ch;
+ if (ch) {
+ /* Make sure tx interrupts are on */
+ /* Truly necessary ??? They should be anyway */
+ unsigned long tx_fifo_imr;
+
+ tx_fifo_imr = in_be32(&FIFO(port)->tximr);
+ tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO(port)->tximr, tx_fifo_imr);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void mpc512x_uart_stop_rx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+ unsigned long rx_fifo_imr;
+
+ rx_fifo_imr = in_be32(&FIFO(port)->rximr);
+ rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO(port)->rximr, rx_fifo_imr);
+}
+
+static void mpc512x_uart_enable_ms(struct uart_port *port)
+{
+ /* Not implemented */
+}
+
+static void mpc512x_uart_break_ctl(struct uart_port *port, int ctl)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (ctl == -1)
+ out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
+ else
+ out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void mpc512x_uart_fifo_init(struct mpc52xx_psc *psc)
+{
+ struct mpc512x_psc_fifo *fifo;
+
+ /* fifo is right after the psc */
+ fifo = (struct mpc512x_psc_fifo *)(psc + 1);
+
+ out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+ out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+ out_be32(&fifo->txalarm, 1);
+ out_be32(&fifo->tximr, 0);
+
+ out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+ out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+ out_be32(&fifo->rxalarm, 1);
+ out_be32(&fifo->rximr, 0);
+}
+
+static int mpc512x_uart_startup(struct uart_port *port)
+{
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+ int ret;
+
+ /* Request IRQ */
+ ret = request_irq(port->irq, mpc512x_uart_int,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ "mpc512x_psc_uart", port);
+ if (ret)
+ return ret;
+
+ /* Reset/activate the port, clear and enable interrupts */
+ out_8(&psc->command, MPC52xx_PSC_RST_RX);
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+ out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
+
+ mpc512x_uart_fifo_init(psc);
+
+ out_be32(&FIFO(port)->tximr, MPC512x_PSC_FIFO_ALARM);
+ out_be32(&FIFO(port)->rximr, MPC512x_PSC_FIFO_ALARM);
+
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+ out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+
+ return 0;
+}
+
+static void mpc512x_uart_shutdown(struct uart_port *port)
+{
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+
+ /* Shut down the port. Leave TX active if on a console port */
+ out_8(&psc->command, MPC52xx_PSC_RST_RX);
+ if (!uart_console(port))
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+ out_be32(&FIFO(port)->tximr, 0);
+ out_be32(&FIFO(port)->rximr, 0);
+
+ /* Release interrupt */
+ free_irq(port->irq, port);
+}
+
+static void
+mpc512x_uart_set_termios(struct uart_port *port, struct ktermios *new,
+ struct ktermios *old)
+{
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+ unsigned long flags;
+ unsigned char mr1, mr2;
+ unsigned short ctr;
+ unsigned int j, baud, quot;
+ struct mpc512x_psc_fifo *fifo = FIFO(port);
+
+ /* Prepare what we're gonna write */
+ mr1 = 0;
+
+ switch (new->c_cflag & CSIZE) {
+ case CS5:
+ mr1 |= MPC52xx_PSC_MODE_5_BITS;
+ break;
+ case CS6:
+ mr1 |= MPC52xx_PSC_MODE_6_BITS;
+ break;
+ case CS7:
+ mr1 |= MPC52xx_PSC_MODE_7_BITS;
+ break;
+ case CS8:
+ default:
+ mr1 |= MPC52xx_PSC_MODE_8_BITS;
+ }
+
+ if (new->c_cflag & PARENB) {
+ mr1 |= (new->c_cflag & PARODD) ?
+ MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
+ } else
+ mr1 |= MPC52xx_PSC_MODE_PARNONE;
+
+ mr2 = 0;
+
+ if (new->c_cflag & CSTOPB)
+ mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
+ else
+ mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
+ MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
+ MPC52xx_PSC_MODE_ONE_STOP;
+
+ 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);
+
+ /* Update the per-port timeout */
+ uart_update_timeout(port, new->c_cflag, baud);
+
+ /* Do our best to flush TX & RX, so we don't loose anything */
+ /* But we don't wait indefinitly ! */
+ j = 5000000; /* Maximum wait */
+ /* FIXME Can't receive chars since set_termios might be called at early
+ * boot for the console, all stuff is not yet ready to receive at that
+ * time and that just makes the kernel oops */
+ /* while (j-- && mpc512x_uart_int_rx_chars(port)); */
+ while (!(in_be32(&fifo->txsr) & MPC512x_PSC_FIFO_EMPTY) && --j)
+ udelay(1);
+
+ if (!j)
+ printk(KERN_ERR "mpc512x_uart.c: "
+ "Unable to flush RX & TX fifos in-time in set_termios."
+ "Some chars may have been lost.\n");
+
+ /* Reset the TX & RX */
+ out_8(&psc->command, MPC52xx_PSC_RST_RX);
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+ /* Send new mode settings */
+ 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);
+
+ /* Reenable TX & RX */
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+ out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+
+ /* We're all set, release the lock */
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *mpc512x_uart_type(struct uart_port *port)
+{
+ return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
+}
+
+static void mpc512x_uart_release_port(struct uart_port *port)
+{
+ /* remapped by us ? */
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+}
+
+static int mpc512x_uart_request_port(struct uart_port *port)
+{
+ int err;
+
+ if (port->flags & UPF_IOREMAP) /* Need to remap ? */
+ port->membase = ioremap(port->mapbase,
+ sizeof(struct mpc52xx_psc));
+
+ if (!port->membase)
+ return -EINVAL;
+
+ err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
+ "mpc512x_psc_uart") != NULL ? 0 : -EBUSY;
+
+ if (err && (port->flags & UPF_IOREMAP)) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ return err;
+}
+
+static void mpc512x_uart_config_port(struct uart_port *port, int flags)
+{
+ if ((flags & UART_CONFIG_TYPE) &&
+ (mpc512x_uart_request_port(port) == 0))
+ port->type = PORT_MPC52xx;
+}
+
+static int
+mpc512x_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
+ return -EINVAL;
+
+ if ((ser->irq != port->irq) ||
+ (ser->io_type != SERIAL_IO_MEM) ||
+ (ser->baud_base != port->uartclk) ||
+ (ser->iomem_base != (void *)port->mapbase) || (ser->hub6 != 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct uart_ops mpc512x_uart_ops = {
+ .tx_empty = mpc512x_uart_tx_empty,
+ .set_mctrl = mpc512x_uart_set_mctrl,
+ .get_mctrl = mpc512x_uart_get_mctrl,
+ .stop_tx = mpc512x_uart_stop_tx,
+ .start_tx = mpc512x_uart_start_tx,
+ .send_xchar = mpc512x_uart_send_xchar,
+ .stop_rx = mpc512x_uart_stop_rx,
+ .enable_ms = mpc512x_uart_enable_ms,
+ .break_ctl = mpc512x_uart_break_ctl,
+ .startup = mpc512x_uart_startup,
+ .shutdown = mpc512x_uart_shutdown,
+ .set_termios = mpc512x_uart_set_termios,
+/* .pm = mpc512x_uart_pm, Not supported yet */
+/* .set_wake = mpc512x_uart_set_wake, Not supported yet */
+ .type = mpc512x_uart_type,
+ .release_port = mpc512x_uart_release_port,
+ .request_port = mpc512x_uart_request_port,
+ .config_port = mpc512x_uart_config_port,
+ .verify_port = mpc512x_uart_verify_port
+};
+
+/* ======================================================================== */
+/* Interrupt handling */
+/* ======================================================================== */
+
+static inline int mpc512x_uart_int_rx_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned char ch, flag;
+ unsigned short status;
+ unsigned long fifostatus;
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+ struct mpc512x_psc_fifo __iomem *fifo = FIFO(port);
+
+ /* While we can read, do so ! */
+ while (1) {
+ fifostatus = in_be32(&fifo->rxsr);
+
+ if (fifostatus & MPC512x_PSC_FIFO_EMPTY)
+ break;
+
+ status = in_be16(&psc->mpc52xx_psc_status);
+
+ /* Get the char */
+ ch = in_8(&fifo->rxdata_8);
+
+ /* Handle sysreq char */
+#ifdef SUPPORT_SYSRQ
+ if (uart_handle_sysrq_char(port, ch)) {
+ port->sysrq = 0;
+ continue;
+ }
+#endif
+
+ /* Store it */
+
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & (MPC52xx_PSC_SR_PE |
+ MPC52xx_PSC_SR_FE | MPC52xx_PSC_SR_RB)) {
+
+ if (status & MPC52xx_PSC_SR_RB) {
+ flag = TTY_BREAK;
+ uart_handle_break(port);
+ } else if (status & MPC52xx_PSC_SR_PE)
+ flag = TTY_PARITY;
+ else if (status & MPC52xx_PSC_SR_FE)
+ flag = TTY_FRAME;
+
+ /* Clear error condition */
+ out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
+
+ }
+ tty_insert_flip_char(tty, ch, flag);
+ if (status & MPC52xx_PSC_SR_OE) {
+ /*
+ * Overrun is special, since it's
+ * reported immediately, and doesn't
+ * affect the current character
+ */
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ }
+
+ tty_flip_buffer_push(tty);
+
+ fifostatus = in_be32(&fifo->rxsr);
+ return !(fifostatus & MPC512x_PSC_FIFO_EMPTY);
+}
+
+static inline int mpc512x_uart_int_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+ struct mpc512x_psc_fifo *fifo = FIFO(port);
+
+ /* Process out of band chars */
+ if (port->x_char) {
+ out_8(&fifo->txdata_8, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return 1;
+ }
+
+ /* Nothing to do ? */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ mpc512x_uart_stop_tx(port);
+ return 0;
+ }
+
+ /* Send chars */
+ while (!(in_be32(&fifo->txsr) & MPC512x_PSC_FIFO_FULL)) {
+ out_8(&fifo->txdata_8, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ /* Wake up */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ /* Maybe we're done after all */
+ if (uart_circ_empty(xmit)) {
+ mpc512x_uart_stop_tx(port);
+ return 0;
+ }
+
+ return 1;
+}
+
+static irqreturn_t mpc512x_uart_int(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ unsigned long pass = ISR_PASS_LIMIT;
+ unsigned int keepgoing;
+ unsigned long rx_fifo_status;
+ unsigned long tx_fifo_status;
+
+ spin_lock(&port->lock);
+
+ /* While we have stuff to do, we continue */
+ do {
+ /* If we don't find anything to do, we stop */
+ keepgoing = 0;
+
+ /* clear any pending interrupts */
+ out_be32(&FIFO(port)->rxisr, in_be32(&FIFO(port)->rxisr));
+
+ rx_fifo_status = in_be32(&FIFO(port)->rxsr);
+ out_be32(&FIFO(port)->rxisr, rx_fifo_status);
+ rx_fifo_status &= in_be32(&FIFO(port)->rximr);
+
+ if (rx_fifo_status & MPC512x_PSC_FIFO_ALARM)
+ keepgoing |= mpc512x_uart_int_rx_chars(port);
+
+ /* clear any pending interrupts */
+ out_be32(&FIFO(port)->txisr, in_be32(&FIFO(port)->txisr));
+
+ tx_fifo_status = in_be32(&FIFO(port)->txsr);
+ out_be32(&FIFO(port)->txisr, tx_fifo_status);
+ tx_fifo_status &= in_be32(&FIFO(port)->tximr);
+
+ if (tx_fifo_status & MPC512x_PSC_FIFO_ALARM)
+ keepgoing |= mpc512x_uart_int_tx_chars(port);
+
+ /* Limit number of iteration */
+ if (!(--pass))
+ keepgoing = 0;
+
+ } while (keepgoing);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* ======================================================================== */
+/* Console ( if applicable ) */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_MPC512x_CONSOLE
+
+static void __init
+mpc512x_console_get_options(struct uart_port *port,
+ int *baud, int *parity, int *bits, int *flow)
+{
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+ unsigned char mr1;
+
+ pr_debug("mpc512x_console_get_options(port=%p)\n", port);
+
+ /* Read the mode registers */
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ mr1 = in_8(&psc->mode);
+
+ /* CT{U,L}R are write-only ! */
+ *baud = 115200;
+ /* Parse them */
+ switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
+ case MPC52xx_PSC_MODE_5_BITS:
+ *bits = 5;
+ break;
+ case MPC52xx_PSC_MODE_6_BITS:
+ *bits = 6;
+ break;
+ case MPC52xx_PSC_MODE_7_BITS:
+ *bits = 7;
+ break;
+ case MPC52xx_PSC_MODE_8_BITS:
+ default:
+ *bits = 8;
+ }
+
+ if (mr1 & MPC52xx_PSC_MODE_PARNONE)
+ *parity = 'n';
+ else
+ *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
+}
+
+static void
+mpc512x_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &mpc512x_uart_ports[co->index];
+ unsigned int i, j;
+ unsigned long rx_fifo_imr, tx_fifo_imr;
+
+ /* Disable interrupts */
+ tx_fifo_imr = in_be32(&FIFO(port)->tximr);
+ out_be32(&FIFO(port)->tximr, 0);
+ rx_fifo_imr = in_be32(&FIFO(port)->rximr);
+ out_be32(&FIFO(port)->rximr, 0);
+
+ /* Wait the TX buffer to be empty */
+ j = 5000000; /* Maximum wait */
+ while (!(in_be32(&FIFO(port)->txsr) & MPC512x_PSC_FIFO_EMPTY) && --j)
+ udelay(1);
+ /* Write all the chars */
+ for (i = 0; i < count; i++, s++) {
+ /* Line return handling */
+ if (*s == '\n')
+ out_8(&FIFO(port)->txdata_8, '\r');
+
+ /* Send the char */
+ out_8(&FIFO(port)->txdata_8, *s);
+
+ /* Wait the TX buffer to be empty */
+ j = 20000; /* Maximum wait */
+ while (!(in_be32(&FIFO(port)->txsr) & MPC512x_PSC_FIFO_EMPTY)
+ && --j)
+ udelay(1);
+ }
+
+ /* Restore interrupt state */
+ out_be32(&FIFO(port)->tximr, tx_fifo_imr);
+ out_be32(&FIFO(port)->rximr, rx_fifo_imr);
+}
+
+static int __init mpc512x_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port = &mpc512x_uart_ports[co->index];
+ struct device_node *np = mpc512x_uart_nodes[co->index];
+ struct resource res;
+
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ pr_debug("mpc512x_console_setup co=%p, co->index=%i, options=%s\n",
+ co, co->index, options);
+
+ if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) {
+ pr_debug("PSC%x out of range\n", co->index);
+ return -EINVAL;
+ }
+
+ if (!np) {
+ pr_debug("PSC%x not found in device tree\n", co->index);
+ return -EINVAL;
+ }
+
+ pr_debug("Console on ttyPSC%x is %s\n",
+ co->index, mpc512x_uart_nodes[co->index]->full_name);
+
+ /* Fetch register locations */
+ if (of_address_to_resource(np, 0, &res)) {
+ pr_debug("Could not get resources for PSC%x\n", co->index);
+ return -EINVAL;
+ }
+
+ /* Basic port init. Needed since we use some uart_??? func before
+ * real init for early access */
+ spin_lock_init(&port->lock);
+ port->uartclk = getuartclk(np);
+ port->ops = &mpc512x_uart_ops;
+ port->mapbase = res.start;
+ port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
+ port->irq = irq_of_parse_and_map(np, 0);
+
+ if (port->membase == NULL)
+ return -EINVAL;
+
+ pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
+ (void *)port->mapbase, port->membase, port->irq,
+ port->uartclk);
+
+ /* Setup the port parameters accoding to options */
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ mpc512x_console_get_options(port, &baud, &parity, &bits, &flow);
+
+ pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
+ baud, bits, parity, flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mpc512x_uart_driver;
+
+static struct console mpc512x_console = {
+ .name = "ttyPSC",
+ .write = mpc512x_console_write,
+ .device = uart_console_device,
+ .setup = mpc512x_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mpc512x_uart_driver,
+};
+
+static int __init mpc512x_console_init(void)
+{
+ mpc512x_uart_of_enumerate();
+ register_console(&mpc512x_console);
+ return 0;
+}
+
+console_initcall(mpc512x_console_init);
+
+#define MPC52xx_PSC_CONSOLE &mpc512x_console
+#else
+#define MPC52xx_PSC_CONSOLE NULL
+#endif
+
+/* ======================================================================== */
+/* UART Driver */
+/* ======================================================================== */
+
+static struct uart_driver mpc512x_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "mpc512x_psc_uart",
+ .dev_name = "ttyPSC",
+ .major = SERIAL_PSC_MAJOR,
+ .minor = SERIAL_PSC_MINOR,
+ .nr = MPC52xx_PSC_MAXNUM,
+ .cons = MPC52xx_PSC_CONSOLE,
+};
+
+/* ======================================================================== */
+/* OF Platform Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc512x_uart_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ int idx = -1;
+ struct uart_port *port = NULL;
+ struct resource res;
+ int ret;
+
+ dev_dbg(&op->dev, "mpc512x_uart_probe(op=%p, match=%p)\n", op, match);
+
+ /* Check validity & presence */
+ for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
+ if (mpc512x_uart_nodes[idx] == op->node)
+ break;
+ if (idx >= MPC52xx_PSC_MAXNUM)
+ return -EINVAL;
+ pr_debug("Found %s assigned to ttyPSC%x\n",
+ mpc512x_uart_nodes[idx]->full_name, idx);
+
+ /* Init the port structure */
+ port = &mpc512x_uart_ports[idx];
+
+ spin_lock_init(&port->lock);
+ port->uartclk = getuartclk(op->node);
+ port->fifosize = 512;
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF |
+ (uart_console(port) ? 0 : UPF_IOREMAP);
+ port->line = idx;
+ port->ops = &mpc512x_uart_ops;
+ port->dev = &op->dev;
+
+ /* Search for IRQ and mapbase */
+ if (of_address_to_resource(op->node, 0, &res))
+ return -EINVAL;
+
+ port->mapbase = res.start;
+ port->irq = irq_of_parse_and_map(op->node, 0);
+
+ dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
+ (void *)port->mapbase, port->irq, port->uartclk);
+
+ if ((port->irq == NO_IRQ) || !port->mapbase) {
+ printk(KERN_ERR "Could not allocate resources for PSC\n");
+ return -EINVAL;
+ }
+
+ /* Add the port to the uart sub-system */
+ ret = uart_add_one_port(&mpc512x_uart_driver, port);
+ if (!ret)
+ dev_set_drvdata(&op->dev, (void *)port);
+
+ return ret;
+}
+
+static int mpc512x_uart_of_remove(struct of_device *op)
+{
+ struct uart_port *port = dev_get_drvdata(&op->dev);
+ dev_set_drvdata(&op->dev, NULL);
+
+ if (port) {
+ uart_remove_one_port(&mpc512x_uart_driver, port);
+ irq_dispose_mapping(port->irq);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mpc512x_uart_of_suspend(struct of_device *op, pm_message_t state)
+{
+ struct uart_port *port = (struct uart_port *)dev_get_drvdata(&op->dev);
+
+ if (port)
+ uart_suspend_port(&mpc512x_uart_driver, port);
+
+ return 0;
+}
+
+static int mpc512x_uart_of_resume(struct of_device *op)
+{
+ struct uart_port *port = (struct uart_port *)dev_get_drvdata(&op->dev);
+
+ if (port)
+ uart_resume_port(&mpc512x_uart_driver, port);
+
+ return 0;
+}
+#endif
+
+static void mpc512x_uart_of_assign(struct device_node *np, int idx)
+{
+ int free_idx = -1;
+ int i;
+
+ /* Find the first free node */
+ for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
+ if (mpc512x_uart_nodes[i] == NULL) {
+ free_idx = i;
+ break;
+ }
+ }
+
+ if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
+ idx = free_idx;
+
+ if (idx < 0)
+ return; /* No free slot; abort */
+
+ /* If the slot is already occupied, then swap slots */
+ if (mpc512x_uart_nodes[idx] && (free_idx != -1))
+ mpc512x_uart_nodes[free_idx] = mpc512x_uart_nodes[idx];
+ mpc512x_uart_nodes[idx] = np;
+}
+
+static void mpc512x_uart_of_enumerate(void)
+{
+ static int enum_done;
+ struct device_node *np;
+ const unsigned int *devno;
+ int i;
+
+ if (enum_done)
+ return;
+
+ for_each_node_by_type(np, "serial") {
+ if (!of_match_node(mpc512x_uart_of_match, np))
+ continue;
+
+ /* Is a particular device number requested? */
+ devno = of_get_property(np, "port-number", NULL);
+ mpc512x_uart_of_assign(of_node_get(np), devno ? *devno : -1);
+ }
+
+ enum_done = 1;
+
+ for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
+ if (mpc512x_uart_nodes[i])
+ pr_debug("%s assigned to ttyPSC%x\n",
+ mpc512x_uart_nodes[i]->full_name, i);
+ }
+}
+
+MODULE_DEVICE_TABLE(of, mpc512x_uart_of_match);
+
+static struct of_platform_driver mpc512x_uart_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc52xx-psc-uart",
+ .match_table = mpc512x_uart_of_match,
+ .probe = mpc512x_uart_of_probe,
+ .remove = mpc512x_uart_of_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc512x_uart_of_suspend,
+ .resume = mpc512x_uart_of_resume,
+#endif
+ .driver = {
+ .name = "mpc52xx-psc-uart",
+ },
+};
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init mpc512x_uart_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: MPC512x PSC UART driver\n");
+
+ ret = uart_register_driver(&mpc512x_uart_driver);
+ if (ret) {
+ printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
+ __FILE__, ret);
+ return ret;
+ }
+
+ mpc512x_uart_of_enumerate();
+
+ ret = of_register_platform_driver(&mpc512x_uart_of_driver);
+ if (ret) {
+ printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
+ __FILE__, ret);
+ uart_unregister_driver(&mpc512x_uart_driver);
+ return ret;
+ }
+ return 0;
+}
+
+static void __exit mpc512x_uart_exit(void)
+{
+ of_unregister_platform_driver(&mpc512x_uart_of_driver);
+ uart_unregister_driver(&mpc512x_uart_driver);
+}
+
+module_init(mpc512x_uart_init);
+module_exit(mpc512x_uart_exit);
+
+MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
+MODULE_DESCRIPTION("Freescale MPC512x PSC UART");
+MODULE_LICENSE("GPL");
diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h
index bea42b9..6841868 100644
--- a/include/asm-powerpc/mpc52xx_psc.h
+++ b/include/asm-powerpc/mpc52xx_psc.h
@@ -190,5 +190,52 @@ struct mpc52xx_psc_fifo {
u16 tflwfptr; /* PSC + 0x9e */
};
+#define MPC512x_PSC_FIFO_RESET_SLICE 0x80
+#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01
+
+#define MPC512x_PSC_FIFO_EMPTY 0x1
+#define MPC512x_PSC_FIFO_FULL 0x2
+#define MPC512x_PSC_FIFO_ALARM 0x4
+#define MPC512x_PSC_FIFO_URERR 0x8
+#define MPC512x_PSC_FIFO_ORERR 0x01
+#define MPC512x_PSC_FIFO_MEMERROR 0x02
+
+struct mpc512x_psc_fifo {
+ u32 reserved1[10];
+ u32 txcmd; /* PSC + 0x80 */
+ u32 txalarm; /* PSC + 0x84 */
+ u32 txsr; /* PSC + 0x88 */
+ u32 txisr; /* PSC + 0x8c */
+ u32 tximr; /* PSC + 0x90 */
+ u32 txcnt; /* PSC + 0x94 */
+ u32 txptr; /* PSC + 0x98 */
+ u32 txsz; /* PSC + 0x9c */
+ u32 reserved2[7];
+ union {
+ u8 txdata_8;
+ u16 txdata_16;
+ u32 txdata_32;
+ } txdata; /* PSC + 0xbc */
+#define txdata_8 txdata.txdata_8
+#define txdata_16 txdata.txdata_16
+#define txdata_32 txdata.txdata_32
+ u32 rxcmd; /* PSC + 0xc0 */
+ u32 rxalarm; /* PSC + 0xc4 */
+ u32 rxsr; /* PSC + 0xc8 */
+ u32 rxisr; /* PSC + 0xcc */
+ u32 rximr; /* PSC + 0xd0 */
+ u32 rxcnt; /* PSC + 0xd4 */
+ u32 rxptr; /* PSC + 0xd8 */
+ u32 rxsz; /* PSC + 0xdc */
+ u32 reserved3[7];
+ union {
+ u8 rxdata_8;
+ u16 rxdata_16;
+ u32 rxdata_32;
+ } rxdata; /* PSC + 0xfc */
+#define rxdata_8 rxdata.rxdata_8
+#define rxdata_16 rxdata.rxdata_16
+#define rxdata_32 rxdata.rxdata_32
+};
#endif /* __ASM_MPC52xx_PSC_H__ */
--
1.5.3.5.726.g41a7a
^ permalink raw reply related
* [PATCH 6/7] Add mpc512x_find_ips_freq
From: John Rigby @ 2008-01-08 16:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1199808093-15929-6-git-send-email-jrigby@freescale.com>
Added mpc512x_find_ips_freq needed by the following
serial driver patch. It is basically a renamed
mpc512x_find_ipd_freq from 52xx.
Signed-off-by: John Rigby <jrigby@freescale.com>
---
arch/powerpc/platforms/512x/mpc5121_ads.c | 28 ++++++++++++++++++++++++++++
include/asm-powerpc/mpc512x.h | 22 ++++++++++++++++++++++
2 files changed, 50 insertions(+), 0 deletions(-)
create mode 100644 include/asm-powerpc/mpc512x.h
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index a860bf0..2f4cfee 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -36,6 +36,34 @@
#include <asm/time.h>
#include <asm/of_platform.h>
+/**
+ * mpc512x_find_ips_freq - Find the IPB bus frequency for a device
+ * @node: device node
+ *
+ * Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
+ */
+unsigned long
+mpc512x_find_ips_freq(struct device_node *node)
+{
+ struct device_node *np;
+ const unsigned int *p_ips_freq = NULL;
+
+ of_node_get(node);
+ while (node) {
+ p_ips_freq = of_get_property(node, "bus-frequency", NULL);
+ if (p_ips_freq)
+ break;
+
+ np = of_get_parent(node);
+ of_node_put(node);
+ node = np;
+ }
+ if (node)
+ of_node_put(node);
+
+ return p_ips_freq ? *p_ips_freq : 0;
+}
+
static void __init mpc5121_ads_setup_arch(void)
{
if (ppc_md.progress)
diff --git a/include/asm-powerpc/mpc512x.h b/include/asm-powerpc/mpc512x.h
new file mode 100644
index 0000000..c48a165
--- /dev/null
+++ b/include/asm-powerpc/mpc512x.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>, Friday Apr 13 2007
+ *
+ * Description:
+ * MPC5121 Prototypes and definitions
+ *
+ * This 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.
+ *
+ */
+
+#ifndef __ASM_POWERPC_MPC512x_H__
+#define __ASM_POWERPC_MPC512x_H__
+
+extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
+
+#endif /* __ASM_POWERPC_MPC512x_H__ */
+
--
1.5.3.5.726.g41a7a
^ permalink raw reply related
* [PATCH 4/7] Device tree for MPC5121 ADS
From: John Rigby @ 2008-01-08 16:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1199808093-15929-4-git-send-email-jrigby@freescale.com>
Bare minimum tree containing only
what is currently supported.
Signed-off-by: John Rigby <jrigby@freescale.com>
---
arch/powerpc/boot/dts/mpc5121ads.dts | 102 ++++++++++++++++++++++++++++++++++
1 files changed, 102 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/boot/dts/mpc5121ads.dts
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
new file mode 100644
index 0000000..26471ff
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -0,0 +1,102 @@
+/*
+ * MPC5121E MDS Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+/ {
+ model = "MPC5121ADS";
+ compatible = "MPC5121ADS";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,5121@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <8000>; // L1, 32K
+ i-cache-size = <8000>; // L1, 32K
+ ref-frequency = <3ef1480>; // 66MHz ref clock
+ timebase-frequency = <2f34f60>; // 49.5MHz (396MHz/8) makes time tick correctly
+ bus-frequency = <bcd3d80>; // 198MHz csb bus
+ clock-frequency = <179a7b00>; // 396MHz ppc core ??
+ 32-bit;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <00000000 10000000>; // 256MB at 0
+ };
+
+ cpld@82000000 {
+ device_type = "board-control";
+ reg = <82000000 8000>;
+ };
+
+ soc5121@80000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 80000000 400000>;
+ reg = <80000000 400000>;
+ ref-frequency = <3ef1480>; // 66MHz ref
+ bus-frequency = <5e69ec0>; // 99MHz ips ref
+
+ // IPIC
+ // interrupts cell = <intr #, sense>
+ // sense values match linux IORESOURCE_IRQ_* defines:
+ // sense == 8: Level, low assertion
+ // sense == 2: Edge, high-to-low change
+ //
+ ipic: pic@c00 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <c00 100>;
+ built-in;
+ device_type = "ipic";
+ };
+
+ // 512x PSCs are not 52xx PSCs compatible
+ // PSC3 serial port A aka ttyPSC0
+ serial@11300 {
+ device_type = "serial";
+ compatible = "mpc512x-psc-uart";
+ port-number = <0>; // Logical port assignment
+ cell-index = <3>;
+ reg = <11300 100>;
+ interrupts = <28 8>; // actually the fifo irq
+ interrupt-parent = < &ipic >;
+ };
+
+ // PSC4 serial port B aka ttyPSC1
+ serial@11400 {
+ device_type = "serial";
+ compatible = "mpc512x-psc-uart";
+ port-number = <1>; // Logical port assignment
+ cell-index = <4>;
+ reg = <11400 100>;
+ interrupts = <28 8>; // actually the fifo irq
+ interrupt-parent = < &ipic >;
+ };
+
+ pscsfifo@11f00 {
+ compatible = "mpc512x-pscsfifo";
+ reg = <11f00 100>;
+ interrupts = <28 8>;
+ interrupt-parent = < &ipic >;
+ };
+ };
+};
--
1.5.3.5.726.g41a7a
^ permalink raw reply related
* [PATCH 5/7] Separate MPC52xx PSC FIFO registers from rest of PSC
From: John Rigby @ 2008-01-08 16:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1199808093-15929-5-git-send-email-jrigby@freescale.com>
This is in preparation for the addition of MPC512x
PSC support. The main difference in the 512x is
in the fifo registers.
Signed-off-by: John Rigby <jrigby@freescale.com>
---
drivers/serial/mpc52xx_uart.c | 10 ++++++----
include/asm-powerpc/mpc52xx_psc.h | 3 +++
include/asm-ppc/mpc52xx_psc.h | 3 +++
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index ec36ad7..25a91c9 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -111,6 +111,7 @@ static void mpc52xx_uart_of_enumerate(void);
#endif
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
+#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
/* Forward declaration of the interruption handling routine */
@@ -222,6 +223,7 @@ static int
mpc52xx_uart_startup(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
+ struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
int ret;
/* Request IRQ */
@@ -238,10 +240,10 @@ mpc52xx_uart_startup(struct uart_port *port)
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
- out_8(&psc->rfcntl, 0x00);
- out_be16(&psc->rfalarm, 0x1ff);
- out_8(&psc->tfcntl, 0x07);
- out_be16(&psc->tfalarm, 0x80);
+ out_8(&fifo->rfcntl, 0x00);
+ out_be16(&fifo->rfalarm, 0x1ff);
+ out_8(&fifo->tfcntl, 0x07);
+ out_be16(&fifo->tfalarm, 0x80);
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h
index 26690d2..bea42b9 100644
--- a/include/asm-powerpc/mpc52xx_psc.h
+++ b/include/asm-powerpc/mpc52xx_psc.h
@@ -153,6 +153,9 @@ struct mpc52xx_psc {
u8 reserved16[3];
u8 irfdr; /* PSC + 0x54 */
u8 reserved17[3];
+};
+
+struct mpc52xx_psc_fifo {
u16 rfnum; /* PSC + 0x58 */
u16 reserved18;
u16 tfnum; /* PSC + 0x5c */
diff --git a/include/asm-ppc/mpc52xx_psc.h b/include/asm-ppc/mpc52xx_psc.h
index c82b8d4..39fcd02 100644
--- a/include/asm-ppc/mpc52xx_psc.h
+++ b/include/asm-ppc/mpc52xx_psc.h
@@ -159,6 +159,9 @@ struct mpc52xx_psc {
u8 reserved16[3];
u8 irfdr; /* PSC + 0x54 */
u8 reserved17[3];
+};
+
+struct mpc52xx_psc_fifo {
u16 rfnum; /* PSC + 0x58 */
u16 reserved18;
u16 tfnum; /* PSC + 0x5c */
--
1.5.3.5.726.g41a7a
^ permalink raw reply related
* [PATCH 3/7] Basic Freescale MPC512x support
From: John Rigby @ 2008-01-08 16:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1199808093-15929-3-git-send-email-jrigby@freescale.com>
512x is very similar to 83xx and most
of this is patterned after code from 83xx
New platform:
changed:
arch/powerpc/Kconfig
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/Makefile
new:
arch/powerpc/platforms/512x/*
Signed-off-by: John Rigby <jrigby@freescale.com>
---
arch/powerpc/Kconfig | 2 +-
arch/powerpc/platforms/512x/Kconfig | 20 ++++++
arch/powerpc/platforms/512x/Makefile | 4 +
arch/powerpc/platforms/512x/mpc5121_ads.c | 90 +++++++++++++++++++++++++++++
arch/powerpc/platforms/Kconfig | 8 +++
arch/powerpc/platforms/Kconfig.cputype | 6 +-
arch/powerpc/platforms/Makefile | 1 +
7 files changed, 127 insertions(+), 4 deletions(-)
create mode 100644 arch/powerpc/platforms/512x/Kconfig
create mode 100644 arch/powerpc/platforms/512x/Makefile
create mode 100644 arch/powerpc/platforms/512x/mpc5121_ads.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 66a3d8c..81c3f05 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -470,7 +470,7 @@ config PCI
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
|| PPC_PS3
- default y if !40x && !CPM2 && !8xx && !PPC_83xx \
+ default y if !40x && !CPM2 && !8xx && !PPC_512x && !PPC_83xx \
&& !PPC_85xx && !PPC_86xx
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
default PCI_QSPAN if !4xx && !CPM2 && 8xx
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
new file mode 100644
index 0000000..399d279
--- /dev/null
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -0,0 +1,20 @@
+menu "Platform support"
+ depends on PPC_512x
+
+choice
+ prompt "Machine Type"
+ default MPC5121_ADS
+
+config MPC5121_ADS
+ bool "Freescale MPC5121E ADS"
+ select DEFAULT_UIMAGE
+ help
+ This option enables support for the MPC5121E ADS board.
+
+endchoice
+
+config MPC5121
+ bool
+ default y if MPC5121_ADS
+
+endmenu
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
new file mode 100644
index 0000000..232c89f
--- /dev/null
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for the Freescale PowerPC 512x linux kernel.
+#
+obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
new file mode 100644
index 0000000..a860bf0
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007
+ *
+ * Description:
+ * MPC5121 ADS board setup
+ *
+ * This 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 <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/of_platform.h>
+
+static void __init mpc5121_ads_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("mpc5121_ads_setup_arch()", 0);
+
+ printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n");
+}
+
+static void __init mpc5121_ads_declare_of_platform_devices(void)
+{
+ /* Find every child of the SOC node and add it to of_platform */
+ if (of_platform_bus_probe(NULL, NULL, NULL))
+ printk(KERN_ERR __FILE__ ": "
+ "Error while probing of_platform bus\n");
+}
+
+static void __init mpc5121_ads_init_IRQ(void)
+{
+ struct device_node *np;
+
+ np = of_find_node_by_type(NULL, "ipic");
+ if (!np)
+ return;
+
+ ipic_init(np, 0);
+
+ /*
+ * Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ ipic_set_default_priority();
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc5121_ads_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "MPC5121ADS");
+}
+
+define_machine(mpc5121_ads) {
+ .name = "MPC5121 ADS",
+ .probe = mpc5121_ads_probe,
+ .setup_arch = mpc5121_ads_setup_arch,
+ .init = mpc5121_ads_declare_of_platform_devices,
+ .init_IRQ = mpc5121_ads_init_IRQ,
+ .get_irq = ipic_get_irq,
+ .calibrate_decr = generic_calibrate_decr,
+};
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index ad9b1c0..1daf47f 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -25,6 +25,13 @@ config PPC_83xx
select IPIC
select WANT_DEVICE_TREE
+config PPC_512x
+ bool "Freescale 512x"
+ depends on 6xx
+ select FSL_SOC
+ select IPIC
+ select WANT_DEVICE_TREE
+
config PPC_86xx
bool "Freescale 86xx"
depends on 6xx
@@ -41,6 +48,7 @@ config CLASSIC32
source "arch/powerpc/platforms/pseries/Kconfig"
source "arch/powerpc/platforms/iseries/Kconfig"
source "arch/powerpc/platforms/chrp/Kconfig"
+source "arch/powerpc/platforms/512x/Kconfig"
source "arch/powerpc/platforms/52xx/Kconfig"
source "arch/powerpc/platforms/powermac/Kconfig"
source "arch/powerpc/platforms/prep/Kconfig"
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index c3ee0b5..e21ffa5 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -14,7 +14,7 @@ choice
There are five families of 32 bit PowerPC chips supported.
The most common ones are the desktop and server CPUs (601, 603,
604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
- embedded 52xx/82xx/83xx/86xx counterparts.
+ embedded 512x/52xx/82xx/83xx/86xx counterparts.
The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
(85xx) each form a family of their own that is not compatible
with the others.
@@ -22,7 +22,7 @@ choice
If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
config 6xx
- bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
+ bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
select PPC_FPU
config PPC_85xx
@@ -229,7 +229,7 @@ config NR_CPUS
config NOT_COHERENT_CACHE
bool
- depends on 4xx || 8xx || E200
+ depends on 4xx || 8xx || E200 || PPC_512x
default y
config CHECK_CACHE_COHERENCY
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 6d9079d..633a599 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -11,6 +11,7 @@ endif
obj-$(CONFIG_PPC_CHRP) += chrp/
obj-$(CONFIG_40x) += 40x/
obj-$(CONFIG_44x) += 44x/
+obj-$(CONFIG_PPC_512x) += 512x/
obj-$(CONFIG_PPC_MPC52xx) += 52xx/
obj-$(CONFIG_PPC_8xx) += 8xx/
obj-$(CONFIG_PPC_82xx) += 82xx/
--
1.5.3.5.726.g41a7a
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox