LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Questions on interrupt vector assignment on MPC8641D
From: Michael Ellerman @ 2010-10-13  1:10 UTC (permalink / raw)
  To: david.hagood; +Cc: Scott Wood, tiejun.chen, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <8f62561e16a507967978112d03fe5867.squirrel@localhost>

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

On Mon, 2010-10-11 at 09:44 -0500, david.hagood@gmail.com wrote:
> > You should define MSI device nodes on your target dts. And you can refer
> > to the
> > file, mpc8572ds.dts.
> 
> I see nothing in that file that defines any MSIs. I see code that looks
> like it maps ROOT COMPLEX MODE interrupts on regular PCI interfaces, which
> IS NOT WHAT I AM DOING.
> 
> Since it seems I have been unclear, let me state this as clearly as possible.
> 
> I AM DOING ENDPOINT MODE.

Shouting is not going to make you any friends.

cheers



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

^ permalink raw reply

* Re: Questions on interrupt vector assignment on MPC8641D
From: tiejun.chen @ 2010-10-13  1:17 UTC (permalink / raw)
  To: Scott Wood; +Cc: david.hagood, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20101012162152.5246744a@udp111988uds.am.freescale.net>

Scott Wood wrote:
> On Tue, 12 Oct 2010 15:55:28 -0500
> <david.hagood@gmail.com> wrote:
> 
>> I wonder about the next lines:
>>
>>
>> 	mpic_assign_isu(mpic1, 0, res.start + 0x10000);
>>
>> 	/* 48 Internal Interrupts */
>> 	mpic_assign_isu(mpic1, 1, res.start + 0x10200);
>> 	mpic_assign_isu(mpic1, 2, res.start + 0x10400);
>> 	mpic_assign_isu(mpic1, 3, res.start + 0x10600);
>>
>> 	/* 16 External interrupts
>> 	 * Moving them from [0 - 15] to [64 - 79]
>> 	 */
>> 	mpic_assign_isu(mpic1, 4, res.start + 0x10000);
> 
> No mainline 86xx boards do that, even in 2.6.26.  I suspect you need to
> either get rid of the isu stuff altogether, or add a mapping for the
> MSI interrupts.
> 
>> Looking at the code, and where it appears to be faulting, it looks like
>> its in kernel/irq/chip.c:
>>
>>
>> int set_irq_type(unsigned int irq, unsigned int type)
>> {
>> 	struct irq_desc *desc;
>> 	unsigned long flags;
>> 	int ret = -ENXIO;
>>
>> 	if (irq >= NR_IRQS) {
>> 		printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
>> 		return -ENODEV;
>> 	}
>>
>> 	desc = irq_desc + irq;
>> ------------------------
>> 	if (desc->chip->set_type) {
>> 		spin_lock_irqsave(&desc->lock, flags);
>> 		ret = desc->chip->set_type(irq, type);
>> ------------------------
>>
>>
>> 		spin_unlock_irqrestore(&desc->lock, flags);
>> 	}
>> 	return ret;
>> }
>>
>> My conjecture is that desc->chip isn't set. Is mpic_assign_isu the
>> function that does that?
> 
> That happens in set_irq_chip_and_handler(), called from mpic_host_map()
> -- just a few lines before calling set_irq_type().
> 
> The crash is happening somewhere in mpic_set_irq_type():

Agreed. That is just where I pointed out on my email replied for OOPS. To enable
DBG to figure out 'src' and 'mpic->irq_count' from the file,
arch/powerpc/sysdev/mpic.c,    .
======
int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
{
	......
	if (src >= mpic->irq_count)
		return -EINVAL;
			^
			I think this OOPS may be from here.


Tiejun

>> NIP [c0016540] mpic_set_irq_type+0x188/0x1c4
> 
> -Scott
> 
> 

^ permalink raw reply

* Re: MSI-X vector allocation failure in upstream kernel
From: Michael Ellerman @ 2010-10-13  1:51 UTC (permalink / raw)
  To: Anirban Chakraborty; +Cc: linuxppc-dev@lists.ozlabs.org, Ameen Rahman
In-Reply-To: <9101728E-3FFC-457E-AF5B-87B2037FEC32@qlogic.com>

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

On Tue, 2010-10-05 at 10:18 -0700, Anirban Chakraborty wrote:
> Hi All,
> 
> I am trying to test qlcnic driver (for 10Gb QLogic network adapter) on a Power 6 system 
> (IBM P 520, System type 8203) with upstream kernel and I do see that the kernel is 
> not able to allocate any MSI-X vectors. The driver requests for 4 vectors in pci_enable_msix,
> which returns 2.

OK, that's the platform code saying it can only support 2, that seems
low, but it's possible.

>  The driver again attempts, this time for 2 vectors but the kernel can't allocate 
> and it returns a value of 0xfffffffd. 

OK, that's odd. That is -3, which AFAICS we don't return from the linux
code. So it must be coming from firmware? In which case it would be
"parameter error".

> I upgraded the system FW to 01EL350 (from 01EL340) just to make sure
> if MSI-X is enabled in the system.

Is that the latest FW version?

Adding #define DEBUG at the top of arch/powerpc/platforms/pseries/msi.c
will give us lots of useful info.

Or you can enable CONFIG_DYNAMIC_DEBUG, and enable it that way.

cheers

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

^ permalink raw reply

* Re: ppc405 + MCP23S17
From: tiejun.chen @ 2010-10-13  3:09 UTC (permalink / raw)
  To: WANG YiFei; +Cc: linuxppc-dev
In-Reply-To: <BAY158-ds7DB18D88ED851794F4E19F5540@phx.gbl>

WANG YiFei wrote:
> Hi,
> 
>  
> 
> I'm a newbie for linux device driver development.
> 
> We have a custom ppc405 board which has MCP23S17
> 
> (16-Bit I/O Expander with SPI Interface) on it.
> 
> I noticed that current kernel has MCP23S08 driver
> 
> support, I'd like to know:
> 
> 1. if passing platform data to MCP23S08 driver, can it make
> 
>    MCP23S17 work?
> 

These chips should be same vendor product so I think 16-bit mcp23s17 may be
compatible to 8-bit modes. But you have to check the data sheet to confirm this
and track how to configure that as 8-bit mode. After that it's possible to run
mcp23s17 with mcp23s08.c.

> 2. Generally, I'd like to know how to pass platform data to
> 
>    a particular device driver. In my mind, platform data should
> 
>    not be in driver code, right? However, I don't know where is

Firstly you should define this on your dts. Then parse that to register
corresponding of_platform_device or platform_device when you setup your target
on <your target>.c.

When spi_register_driver prober successfully, you can get the platform_data from
associated spi device.

> 
>    the suitable place to pass platform data to driver.
> 
> 3. How to describe this in dts file?
> 

You can get more from the file, Documentation/powerpc/dts-bindings/spi-bus.txt.
Or refer to those existed spi nodes on other platform dts.

Tiejun

>  
> 
> Thanks in advance,
> 
> YiFei
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* Re: RTC rtc-cmos.c : Fix warning on PowerPC
From: Michael Neuling @ 2010-10-13  3:24 UTC (permalink / raw)
  To: srikanth krishnakar; +Cc: linuxppc-dev, Linuxppc-embedded
In-Reply-To: <AANLkTikVdVkej7LNKXjrcNH2t2rJL=O=NhBDnw3j6N1v@mail.gmail.com>

> I noticed a compilation warning of RTC for powerpc. Found the fix existing
> for MIPS & not for available for PowerPC.

Can you please add the waring text here.

> [1. text/x-patch; 0001-RTC-rtc-cmos.c-Fix-warning-on-PowerPC.patch]...

Please inline the patch rather than using an attachment.

Mikey

^ permalink raw reply

* Re: [PATCH v4 1/5] spi/mpc8xxx: rename spi_mpc8xxx.c to spi_fsl_spi.c
From: Grant Likely @ 2010-10-13  3:40 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general
In-Reply-To: <1286878714-13090-2-git-send-email-Mingkai.hu@freescale.com>

On Tue, Oct 12, 2010 at 06:18:30PM +0800, Mingkai Hu wrote:
> This will pave the way to refactor out the common code which can be used
> by the eSPI controller driver, and rename the SPI controller dirver to the
> file spi_fsl_spi.c.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>

Applied, thanks.

g.

> ---
> v4:
>  - Updated to latest kernel base(Linux 2.6.36-rc7).
> 
>  drivers/spi/Kconfig       |    9 +-
>  drivers/spi/Makefile      |    2 +-
>  drivers/spi/spi_fsl_spi.c | 1425 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_mpc8xxx.c | 1425 ---------------------------------------------
>  4 files changed, 1431 insertions(+), 1430 deletions(-)
>  create mode 100644 drivers/spi/spi_fsl_spi.c
>  delete mode 100644 drivers/spi/spi_mpc8xxx.c
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 91c2f4f..6af34c6 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -182,12 +182,13 @@ config SPI_MPC512x_PSC
>  	  This enables using the Freescale MPC5121 Programmable Serial
>  	  Controller in SPI master mode.
>  
> -config SPI_MPC8xxx
> -	tristate "Freescale MPC8xxx SPI controller"
> +config SPI_FSL_SPI
> +	tristate "Freescale SPI controller"
>  	depends on FSL_SOC
>  	help
> -	  This enables using the Freescale MPC8xxx SPI controllers in master
> -	  mode.
> +	  This enables using the Freescale SPI controllers in master mode.
> +	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
> +	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
>  
>  config SPI_OMAP_UWIRE
>  	tristate "OMAP1 MicroWire"
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index e9cbd18..770817c 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -34,7 +34,7 @@ obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
>  obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
> -obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
> +obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
>  obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
>  obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
>  obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx_hw.o
> diff --git a/drivers/spi/spi_fsl_spi.c b/drivers/spi/spi_fsl_spi.c
> new file mode 100644
> index 0000000..1dd86b8
> --- /dev/null
> +++ b/drivers/spi/spi_fsl_spi.c
> @@ -0,0 +1,1425 @@
> +/*
> + * MPC8xxx SPI controller driver.
> + *
> + * Maintainer: Kumar Gala
> + *
> + * Copyright (C) 2006 Polycom, Inc.
> + *
> + * CPM SPI and QE buffer descriptors mode support:
> + * Copyright (c) 2009  MontaVista Software, Inc.
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/bug.h>
> +#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/completion.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/device.h>
> +#include <linux/spi/spi.h>
> +#include <linux/spi/spi_bitbang.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/mm.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +#include <linux/slab.h>
> +
> +#include <sysdev/fsl_soc.h>
> +#include <asm/cpm.h>
> +#include <asm/qe.h>
> +#include <asm/irq.h>
> +
> +/* CPM1 and CPM2 are mutually exclusive. */
> +#ifdef CONFIG_CPM1
> +#include <asm/cpm1.h>
> +#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
> +#else
> +#include <asm/cpm2.h>
> +#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
> +#endif
> +
> +/* SPI Controller registers */
> +struct mpc8xxx_spi_reg {
> +	u8 res1[0x20];
> +	__be32 mode;
> +	__be32 event;
> +	__be32 mask;
> +	__be32 command;
> +	__be32 transmit;
> +	__be32 receive;
> +};
> +
> +/* SPI Controller mode register definitions */
> +#define	SPMODE_LOOP		(1 << 30)
> +#define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
> +#define	SPMODE_CP_BEGIN_EDGECLK	(1 << 28)
> +#define	SPMODE_DIV16		(1 << 27)
> +#define	SPMODE_REV		(1 << 26)
> +#define	SPMODE_MS		(1 << 25)
> +#define	SPMODE_ENABLE		(1 << 24)
> +#define	SPMODE_LEN(x)		((x) << 20)
> +#define	SPMODE_PM(x)		((x) << 16)
> +#define	SPMODE_OP		(1 << 14)
> +#define	SPMODE_CG(x)		((x) << 7)
> +
> +/*
> + * Default for SPI Mode:
> + * 	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
> + */
> +#define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
> +			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
> +
> +/* SPIE register values */
> +#define	SPIE_NE		0x00000200	/* Not empty */
> +#define	SPIE_NF		0x00000100	/* Not full */
> +
> +/* SPIM register values */
> +#define	SPIM_NE		0x00000200	/* Not empty */
> +#define	SPIM_NF		0x00000100	/* Not full */
> +
> +#define	SPIE_TXB	0x00000200	/* Last char is written to tx fifo */
> +#define	SPIE_RXB	0x00000100	/* Last char is written to rx buf */
> +
> +/* SPCOM register values */
> +#define	SPCOM_STR	(1 << 23)	/* Start transmit */
> +
> +#define	SPI_PRAM_SIZE	0x100
> +#define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
> +
> +/* SPI Controller driver's private data. */
> +struct mpc8xxx_spi {
> +	struct device *dev;
> +	struct mpc8xxx_spi_reg __iomem *base;
> +
> +	/* rx & tx bufs from the spi_transfer */
> +	const void *tx;
> +	void *rx;
> +
> +	int subblock;
> +	struct spi_pram __iomem *pram;
> +	struct cpm_buf_desc __iomem *tx_bd;
> +	struct cpm_buf_desc __iomem *rx_bd;
> +
> +	struct spi_transfer *xfer_in_progress;
> +
> +	/* dma addresses for CPM transfers */
> +	dma_addr_t tx_dma;
> +	dma_addr_t rx_dma;
> +	bool map_tx_dma;
> +	bool map_rx_dma;
> +
> +	dma_addr_t dma_dummy_tx;
> +	dma_addr_t dma_dummy_rx;
> +
> +	/* functions to deal with different sized buffers */
> +	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> +	u32(*get_tx) (struct mpc8xxx_spi *);
> +
> +	unsigned int count;
> +	unsigned int irq;
> +
> +	unsigned nsecs;		/* (clock cycle time)/2 */
> +
> +	u32 spibrg;		/* SPIBRG input clock */
> +	u32 rx_shift;		/* RX data reg shift when in qe mode */
> +	u32 tx_shift;		/* TX data reg shift when in qe mode */
> +
> +	unsigned int flags;
> +
> +	struct workqueue_struct *workqueue;
> +	struct work_struct work;
> +
> +	struct list_head queue;
> +	spinlock_t lock;
> +
> +	struct completion done;
> +};
> +
> +static void *mpc8xxx_dummy_rx;
> +static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
> +static int mpc8xxx_dummy_rx_refcnt;
> +
> +struct spi_mpc8xxx_cs {
> +	/* functions to deal with different sized buffers */
> +	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> +	u32 (*get_tx) (struct mpc8xxx_spi *);
> +	u32 rx_shift;		/* RX data reg shift when in qe mode */
> +	u32 tx_shift;		/* TX data reg shift when in qe mode */
> +	u32 hw_mode;		/* Holds HW mode register settings */
> +};
> +
> +static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
> +{
> +	out_be32(reg, val);
> +}
> +
> +static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
> +{
> +	return in_be32(reg);
> +}
> +
> +#define MPC83XX_SPI_RX_BUF(type) 					  \
> +static									  \
> +void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
> +{									  \
> +	type *rx = mpc8xxx_spi->rx;					  \
> +	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
> +	mpc8xxx_spi->rx = rx;						  \
> +}
> +
> +#define MPC83XX_SPI_TX_BUF(type)				\
> +static								\
> +u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
> +{								\
> +	u32 data;						\
> +	const type *tx = mpc8xxx_spi->tx;			\
> +	if (!tx)						\
> +		return 0;					\
> +	data = *tx++ << mpc8xxx_spi->tx_shift;			\
> +	mpc8xxx_spi->tx = tx;					\
> +	return data;						\
> +}
> +
> +MPC83XX_SPI_RX_BUF(u8)
> +MPC83XX_SPI_RX_BUF(u16)
> +MPC83XX_SPI_RX_BUF(u32)
> +MPC83XX_SPI_TX_BUF(u8)
> +MPC83XX_SPI_TX_BUF(u16)
> +MPC83XX_SPI_TX_BUF(u32)
> +
> +static void mpc8xxx_spi_change_mode(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +	__be32 __iomem *mode = &mspi->base->mode;
> +	unsigned long flags;
> +
> +	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
> +		return;
> +
> +	/* Turn off IRQs locally to minimize time that SPI is disabled. */
> +	local_irq_save(flags);
> +
> +	/* Turn off SPI unit prior changing mode */
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
> +
> +	/* When in CPM mode, we need to reinit tx and rx. */
> +	if (mspi->flags & SPI_CPM_MODE) {
> +		if (mspi->flags & SPI_QE) {
> +			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
> +				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
> +		} else {
> +			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
> +			if (mspi->flags & SPI_CPM1) {
> +				out_be16(&mspi->pram->rbptr,
> +					 in_be16(&mspi->pram->rbase));
> +				out_be16(&mspi->pram->tbptr,
> +					 in_be16(&mspi->pram->tbase));
> +			}
> +		}
> +	}
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
> +	local_irq_restore(flags);
> +}
> +
> +static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
> +	bool pol = spi->mode & SPI_CS_HIGH;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	if (value == BITBANG_CS_INACTIVE) {
> +		if (pdata->cs_control)
> +			pdata->cs_control(spi, !pol);
> +	}
> +
> +	if (value == BITBANG_CS_ACTIVE) {
> +		mpc8xxx_spi->rx_shift = cs->rx_shift;
> +		mpc8xxx_spi->tx_shift = cs->tx_shift;
> +		mpc8xxx_spi->get_rx = cs->get_rx;
> +		mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +		mpc8xxx_spi_change_mode(spi);
> +
> +		if (pdata->cs_control)
> +			pdata->cs_control(spi, pol);
> +	}
> +}
> +
> +static int
> +mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
> +			   struct spi_device *spi,
> +			   struct mpc8xxx_spi *mpc8xxx_spi,
> +			   int bits_per_word)
> +{
> +	cs->rx_shift = 0;
> +	cs->tx_shift = 0;
> +	if (bits_per_word <= 8) {
> +		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
> +		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
> +		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +			cs->rx_shift = 16;
> +			cs->tx_shift = 24;
> +		}
> +	} else if (bits_per_word <= 16) {
> +		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
> +		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
> +		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +			cs->rx_shift = 16;
> +			cs->tx_shift = 16;
> +		}
> +	} else if (bits_per_word <= 32) {
> +		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
> +		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
> +	} else
> +		return -EINVAL;
> +
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
> +	    spi->mode & SPI_LSB_FIRST) {
> +		cs->tx_shift = 0;
> +		if (bits_per_word <= 8)
> +			cs->rx_shift = 8;
> +		else
> +			cs->rx_shift = 0;
> +	}
> +	mpc8xxx_spi->rx_shift = cs->rx_shift;
> +	mpc8xxx_spi->tx_shift = cs->tx_shift;
> +	mpc8xxx_spi->get_rx = cs->get_rx;
> +	mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +	return bits_per_word;
> +}
> +
> +static int
> +mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
> +			  struct spi_device *spi,
> +			  int bits_per_word)
> +{
> +	/* QE uses Little Endian for words > 8
> +	 * so transform all words > 8 into 8 bits
> +	 * Unfortnatly that doesn't work for LSB so
> +	 * reject these for now */
> +	/* Note: 32 bits word, LSB works iff
> +	 * tfcr/rfcr is set to CPMFCR_GBL */
> +	if (spi->mode & SPI_LSB_FIRST &&
> +	    bits_per_word > 8)
> +		return -EINVAL;
> +	if (bits_per_word > 8)
> +		return 8; /* pretend its 8 bits */
> +	return bits_per_word;
> +}
> +
> +static
> +int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int bits_per_word;
> +	u8 pm;
> +	u32 hz;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +
> +	if (t) {
> +		bits_per_word = t->bits_per_word;
> +		hz = t->speed_hz;
> +	} else {
> +		bits_per_word = 0;
> +		hz = 0;
> +	}
> +
> +	/* spi_transfer level calls that work per-word */
> +	if (!bits_per_word)
> +		bits_per_word = spi->bits_per_word;
> +
> +	/* Make sure its a bit width we support [4..16, 32] */
> +	if ((bits_per_word < 4)
> +	    || ((bits_per_word > 16) && (bits_per_word != 32)))
> +		return -EINVAL;
> +
> +	if (!hz)
> +		hz = spi->max_speed_hz;
> +
> +	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
> +		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
> +							   mpc8xxx_spi,
> +							   bits_per_word);
> +	else if (mpc8xxx_spi->flags & SPI_QE)
> +		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
> +							  bits_per_word);
> +
> +	if (bits_per_word < 0)
> +		return bits_per_word;
> +
> +	if (bits_per_word == 32)
> +		bits_per_word = 0;
> +	else
> +		bits_per_word = bits_per_word - 1;
> +
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
> +				  | SPMODE_PM(0xF));
> +
> +	cs->hw_mode |= SPMODE_LEN(bits_per_word);
> +
> +	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> +		cs->hw_mode |= SPMODE_DIV16;
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> +
> +		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
> +			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
> +			  hz, mpc8xxx_spi->spibrg / 1024);
> +		if (pm > 16)
> +			pm = 16;
> +	} else
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
> +	if (pm)
> +		pm--;
> +
> +	cs->hw_mode |= SPMODE_PM(pm);
> +
> +	mpc8xxx_spi_change_mode(spi);
> +	return 0;
> +}
> +
> +static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
> +{
> +	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
> +	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
> +	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
> +	unsigned int xfer_ofs;
> +
> +	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
> +
> +	if (mspi->rx_dma == mspi->dma_dummy_rx)
> +		out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
> +	else
> +		out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
> +	out_be16(&rx_bd->cbd_datlen, 0);
> +	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
> +
> +	if (mspi->tx_dma == mspi->dma_dummy_tx)
> +		out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
> +	else
> +		out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
> +	out_be16(&tx_bd->cbd_datlen, xfer_len);
> +	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
> +				 BD_SC_LAST);
> +
> +	/* start transfer */
> +	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
> +}
> +
> +static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
> +				struct spi_transfer *t, bool is_dma_mapped)
> +{
> +	struct device *dev = mspi->dev;
> +
> +	if (is_dma_mapped) {
> +		mspi->map_tx_dma = 0;
> +		mspi->map_rx_dma = 0;
> +	} else {
> +		mspi->map_tx_dma = 1;
> +		mspi->map_rx_dma = 1;
> +	}
> +
> +	if (!t->tx_buf) {
> +		mspi->tx_dma = mspi->dma_dummy_tx;
> +		mspi->map_tx_dma = 0;
> +	}
> +
> +	if (!t->rx_buf) {
> +		mspi->rx_dma = mspi->dma_dummy_rx;
> +		mspi->map_rx_dma = 0;
> +	}
> +
> +	if (mspi->map_tx_dma) {
> +		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
> +
> +		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
> +					      DMA_TO_DEVICE);
> +		if (dma_mapping_error(dev, mspi->tx_dma)) {
> +			dev_err(dev, "unable to map tx dma\n");
> +			return -ENOMEM;
> +		}
> +	} else if (t->tx_buf) {
> +		mspi->tx_dma = t->tx_dma;
> +	}
> +
> +	if (mspi->map_rx_dma) {
> +		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
> +					      DMA_FROM_DEVICE);
> +		if (dma_mapping_error(dev, mspi->rx_dma)) {
> +			dev_err(dev, "unable to map rx dma\n");
> +			goto err_rx_dma;
> +		}
> +	} else if (t->rx_buf) {
> +		mspi->rx_dma = t->rx_dma;
> +	}
> +
> +	/* enable rx ints */
> +	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
> +
> +	mspi->xfer_in_progress = t;
> +	mspi->count = t->len;
> +
> +	/* start CPM transfers */
> +	mpc8xxx_spi_cpm_bufs_start(mspi);
> +
> +	return 0;
> +
> +err_rx_dma:
> +	if (mspi->map_tx_dma)
> +		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
> +	return -ENOMEM;
> +}
> +
> +static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +	struct spi_transfer *t = mspi->xfer_in_progress;
> +
> +	if (mspi->map_tx_dma)
> +		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
> +	if (mspi->map_rx_dma)
> +		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
> +	mspi->xfer_in_progress = NULL;
> +}
> +
> +static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
> +				struct spi_transfer *t, unsigned int len)
> +{
> +	u32 word;
> +
> +	mspi->count = len;
> +
> +	/* enable rx ints */
> +	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
> +
> +	/* transmit word */
> +	word = mspi->get_tx(mspi);
> +	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> +
> +	return 0;
> +}
> +
> +static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
> +			    bool is_dma_mapped)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	unsigned int len = t->len;
> +	u8 bits_per_word;
> +	int ret;
> +
> +	bits_per_word = spi->bits_per_word;
> +	if (t->bits_per_word)
> +		bits_per_word = t->bits_per_word;
> +
> +	if (bits_per_word > 8) {
> +		/* invalid length? */
> +		if (len & 1)
> +			return -EINVAL;
> +		len /= 2;
> +	}
> +	if (bits_per_word > 16) {
> +		/* invalid length? */
> +		if (len & 1)
> +			return -EINVAL;
> +		len /= 2;
> +	}
> +
> +	mpc8xxx_spi->tx = t->tx_buf;
> +	mpc8xxx_spi->rx = t->rx_buf;
> +
> +	INIT_COMPLETION(mpc8xxx_spi->done);
> +
> +	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> +		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
> +	else
> +		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
> +	if (ret)
> +		return ret;
> +
> +	wait_for_completion(&mpc8xxx_spi->done);
> +
> +	/* disable rx ints */
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +
> +	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> +		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
> +
> +	return mpc8xxx_spi->count;
> +}
> +
> +static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
> +{
> +	struct spi_device *spi = m->spi;
> +	struct spi_transfer *t;
> +	unsigned int cs_change;
> +	const int nsecs = 50;
> +	int status;
> +
> +	cs_change = 1;
> +	status = 0;
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if (t->bits_per_word || t->speed_hz) {
> +			/* Don't allow changes if CS is active */
> +			status = -EINVAL;
> +
> +			if (cs_change)
> +				status = mpc8xxx_spi_setup_transfer(spi, t);
> +			if (status < 0)
> +				break;
> +		}
> +
> +		if (cs_change) {
> +			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
> +			ndelay(nsecs);
> +		}
> +		cs_change = t->cs_change;
> +		if (t->len)
> +			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
> +		if (status) {
> +			status = -EMSGSIZE;
> +			break;
> +		}
> +		m->actual_length += t->len;
> +
> +		if (t->delay_usecs)
> +			udelay(t->delay_usecs);
> +
> +		if (cs_change) {
> +			ndelay(nsecs);
> +			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +			ndelay(nsecs);
> +		}
> +	}
> +
> +	m->status = status;
> +	m->complete(m->context);
> +
> +	if (status || !cs_change) {
> +		ndelay(nsecs);
> +		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +	}
> +
> +	mpc8xxx_spi_setup_transfer(spi, NULL);
> +}
> +
> +static void mpc8xxx_spi_work(struct work_struct *work)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
> +						       work);
> +
> +	spin_lock_irq(&mpc8xxx_spi->lock);
> +	while (!list_empty(&mpc8xxx_spi->queue)) {
> +		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
> +						   struct spi_message, queue);
> +
> +		list_del_init(&m->queue);
> +		spin_unlock_irq(&mpc8xxx_spi->lock);
> +
> +		mpc8xxx_spi_do_one_msg(m);
> +
> +		spin_lock_irq(&mpc8xxx_spi->lock);
> +	}
> +	spin_unlock_irq(&mpc8xxx_spi->lock);
> +}
> +
> +static int mpc8xxx_spi_setup(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int retval;
> +	u32 hw_mode;
> +	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> +
> +	if (!spi->max_speed_hz)
> +		return -EINVAL;
> +
> +	if (!cs) {
> +		cs = kzalloc(sizeof *cs, GFP_KERNEL);
> +		if (!cs)
> +			return -ENOMEM;
> +		spi->controller_state = cs;
> +	}
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +
> +	hw_mode = cs->hw_mode; /* Save original settings */
> +	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
> +			 | SPMODE_REV | SPMODE_LOOP);
> +
> +	if (spi->mode & SPI_CPHA)
> +		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
> +	if (spi->mode & SPI_CPOL)
> +		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
> +	if (!(spi->mode & SPI_LSB_FIRST))
> +		cs->hw_mode |= SPMODE_REV;
> +	if (spi->mode & SPI_LOOP)
> +		cs->hw_mode |= SPMODE_LOOP;
> +
> +	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
> +	if (retval < 0) {
> +		cs->hw_mode = hw_mode; /* Restore settings */
> +		return retval;
> +	}
> +	return 0;
> +}
> +
> +static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	u16 len;
> +
> +	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
> +		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
> +
> +	len = in_be16(&mspi->rx_bd->cbd_datlen);
> +	if (len > mspi->count) {
> +		WARN_ON(1);
> +		len = mspi->count;
> +	}
> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +
> +	mspi->count -= len;
> +	if (mspi->count)
> +		mpc8xxx_spi_cpm_bufs_start(mspi);
> +	else
> +		complete(&mspi->done);
> +}
> +
> +static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	/* We need handle RX first */
> +	if (events & SPIE_NE) {
> +		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
> +
> +		if (mspi->rx)
> +			mspi->get_rx(rx_data, mspi);
> +	}
> +
> +	if ((events & SPIE_NF) == 0)
> +		/* spin until TX is done */
> +		while (((events =
> +			mpc8xxx_spi_read_reg(&mspi->base->event)) &
> +						SPIE_NF) == 0)
> +			cpu_relax();
> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +
> +	mspi->count -= 1;
> +	if (mspi->count) {
> +		u32 word = mspi->get_tx(mspi);
> +
> +		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> +	} else {
> +		complete(&mspi->done);
> +	}
> +}
> +
> +static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
> +{
> +	struct mpc8xxx_spi *mspi = context_data;
> +	irqreturn_t ret = IRQ_NONE;
> +	u32 events;
> +
> +	/* Get interrupt events(tx/rx) */
> +	events = mpc8xxx_spi_read_reg(&mspi->base->event);
> +	if (events)
> +		ret = IRQ_HANDLED;
> +
> +	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
> +
> +	if (mspi->flags & SPI_CPM_MODE)
> +		mpc8xxx_spi_cpm_irq(mspi, events);
> +	else
> +		mpc8xxx_spi_cpu_irq(mspi, events);
> +
> +	return ret;
> +}
> +
> +static int mpc8xxx_spi_transfer(struct spi_device *spi,
> +				struct spi_message *m)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	unsigned long flags;
> +
> +	m->actual_length = 0;
> +	m->status = -EINPROGRESS;
> +
> +	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
> +	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
> +	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
> +	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
> +
> +	return 0;
> +}
> +
> +
> +static void mpc8xxx_spi_cleanup(struct spi_device *spi)
> +{
> +	kfree(spi->controller_state);
> +}
> +
> +static void *mpc8xxx_spi_alloc_dummy_rx(void)
> +{
> +	mutex_lock(&mpc8xxx_dummy_rx_lock);
> +
> +	if (!mpc8xxx_dummy_rx)
> +		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
> +	if (mpc8xxx_dummy_rx)
> +		mpc8xxx_dummy_rx_refcnt++;
> +
> +	mutex_unlock(&mpc8xxx_dummy_rx_lock);
> +
> +	return mpc8xxx_dummy_rx;
> +}
> +
> +static void mpc8xxx_spi_free_dummy_rx(void)
> +{
> +	mutex_lock(&mpc8xxx_dummy_rx_lock);
> +
> +	switch (mpc8xxx_dummy_rx_refcnt) {
> +	case 0:
> +		WARN_ON(1);
> +		break;
> +	case 1:
> +		kfree(mpc8xxx_dummy_rx);
> +		mpc8xxx_dummy_rx = NULL;
> +		/* fall through */
> +	default:
> +		mpc8xxx_dummy_rx_refcnt--;
> +		break;
> +	}
> +
> +	mutex_unlock(&mpc8xxx_dummy_rx_lock);
> +}
> +
> +static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +	struct device_node *np = dev->of_node;
> +	const u32 *iprop;
> +	int size;
> +	unsigned long spi_base_ofs;
> +	unsigned long pram_ofs = -ENOMEM;
> +
> +	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
> +	iprop = of_get_property(np, "reg", &size);
> +
> +	/* QE with a fixed pram location? */
> +	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
> +		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
> +
> +	/* QE but with a dynamic pram location? */
> +	if (mspi->flags & SPI_QE) {
> +		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
> +		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
> +				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
> +		return pram_ofs;
> +	}
> +
> +	/* CPM1 and CPM2 pram must be at a fixed addr. */
> +	if (!iprop || size != sizeof(*iprop) * 4)
> +		return -ENOMEM;
> +
> +	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
> +	if (IS_ERR_VALUE(spi_base_ofs))
> +		return -ENOMEM;
> +
> +	if (mspi->flags & SPI_CPM2) {
> +		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
> +		if (!IS_ERR_VALUE(pram_ofs)) {
> +			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
> +
> +			out_be16(spi_base, pram_ofs);
> +		}
> +	} else {
> +		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
> +		u16 rpbase = in_be16(&pram->rpbase);
> +
> +		/* Microcode relocation patch applied? */
> +		if (rpbase)
> +			pram_ofs = rpbase;
> +		else
> +			return spi_base_ofs;
> +	}
> +
> +	cpm_muram_free(spi_base_ofs);
> +	return pram_ofs;
> +}
> +
> +static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +	struct device_node *np = dev->of_node;
> +	const u32 *iprop;
> +	int size;
> +	unsigned long pram_ofs;
> +	unsigned long bds_ofs;
> +
> +	if (!(mspi->flags & SPI_CPM_MODE))
> +		return 0;
> +
> +	if (!mpc8xxx_spi_alloc_dummy_rx())
> +		return -ENOMEM;
> +
> +	if (mspi->flags & SPI_QE) {
> +		iprop = of_get_property(np, "cell-index", &size);
> +		if (iprop && size == sizeof(*iprop))
> +			mspi->subblock = *iprop;
> +
> +		switch (mspi->subblock) {
> +		default:
> +			dev_warn(dev, "cell-index unspecified, assuming SPI1");
> +			/* fall through */
> +		case 0:
> +			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
> +			break;
> +		case 1:
> +			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
> +			break;
> +		}
> +	}
> +
> +	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
> +	if (IS_ERR_VALUE(pram_ofs)) {
> +		dev_err(dev, "can't allocate spi parameter ram\n");
> +		goto err_pram;
> +	}
> +
> +	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
> +				  sizeof(*mspi->rx_bd), 8);
> +	if (IS_ERR_VALUE(bds_ofs)) {
> +		dev_err(dev, "can't allocate bds\n");
> +		goto err_bds;
> +	}
> +
> +	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
> +					    DMA_TO_DEVICE);
> +	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
> +		dev_err(dev, "unable to map dummy tx buffer\n");
> +		goto err_dummy_tx;
> +	}
> +
> +	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
> +					    DMA_FROM_DEVICE);
> +	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
> +		dev_err(dev, "unable to map dummy rx buffer\n");
> +		goto err_dummy_rx;
> +	}
> +
> +	mspi->pram = cpm_muram_addr(pram_ofs);
> +
> +	mspi->tx_bd = cpm_muram_addr(bds_ofs);
> +	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
> +
> +	/* Initialize parameter ram. */
> +	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
> +	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
> +	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
> +	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
> +	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
> +	out_be32(&mspi->pram->rstate, 0);
> +	out_be32(&mspi->pram->rdp, 0);
> +	out_be16(&mspi->pram->rbptr, 0);
> +	out_be16(&mspi->pram->rbc, 0);
> +	out_be32(&mspi->pram->rxtmp, 0);
> +	out_be32(&mspi->pram->tstate, 0);
> +	out_be32(&mspi->pram->tdp, 0);
> +	out_be16(&mspi->pram->tbptr, 0);
> +	out_be16(&mspi->pram->tbc, 0);
> +	out_be32(&mspi->pram->txtmp, 0);
> +
> +	return 0;
> +
> +err_dummy_rx:
> +	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
> +err_dummy_tx:
> +	cpm_muram_free(bds_ofs);
> +err_bds:
> +	cpm_muram_free(pram_ofs);
> +err_pram:
> +	mpc8xxx_spi_free_dummy_rx();
> +	return -ENOMEM;
> +}
> +
> +static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
> +{
> +	struct device *dev = mspi->dev;
> +
> +	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
> +	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
> +	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
> +	cpm_muram_free(cpm_muram_offset(mspi->pram));
> +	mpc8xxx_spi_free_dummy_rx();
> +}
> +
> +static const char *mpc8xxx_spi_strmode(unsigned int flags)
> +{
> +	if (flags & SPI_QE_CPU_MODE) {
> +		return "QE CPU";
> +	} else if (flags & SPI_CPM_MODE) {
> +		if (flags & SPI_QE)
> +			return "QE";
> +		else if (flags & SPI_CPM2)
> +			return "CPM2";
> +		else
> +			return "CPM1";
> +	}
> +	return "CPU";
> +}
> +
> +static struct spi_master * __devinit
> +mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct spi_master *master;
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	u32 regval;
> +	int ret = 0;
> +
> +	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
> +	if (master == NULL) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	dev_set_drvdata(dev, master);
> +
> +	/* the spi->mode bits understood by this driver: */
> +	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
> +			| SPI_LSB_FIRST | SPI_LOOP;
> +
> +	master->setup = mpc8xxx_spi_setup;
> +	master->transfer = mpc8xxx_spi_transfer;
> +	master->cleanup = mpc8xxx_spi_cleanup;
> +	master->dev.of_node = dev->of_node;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->dev = dev;
> +	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
> +	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
> +	mpc8xxx_spi->flags = pdata->flags;
> +	mpc8xxx_spi->spibrg = pdata->sysclk;
> +
> +	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
> +	if (ret)
> +		goto err_cpm_init;
> +
> +	mpc8xxx_spi->rx_shift = 0;
> +	mpc8xxx_spi->tx_shift = 0;
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +		mpc8xxx_spi->rx_shift = 16;
> +		mpc8xxx_spi->tx_shift = 24;
> +	}
> +
> +	init_completion(&mpc8xxx_spi->done);
> +
> +	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
> +	if (mpc8xxx_spi->base == NULL) {
> +		ret = -ENOMEM;
> +		goto err_ioremap;
> +	}
> +
> +	mpc8xxx_spi->irq = irq;
> +
> +	/* Register for SPI Interrupt */
> +	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
> +			  0, "mpc8xxx_spi", mpc8xxx_spi);
> +
> +	if (ret != 0)
> +		goto unmap_io;
> +
> +	master->bus_num = pdata->bus_num;
> +	master->num_chipselect = pdata->max_chipselect;
> +
> +	/* SPI controller initializations */
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
> +
> +	/* Enable SPI interface */
> +	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
> +		regval |= SPMODE_OP;
> +
> +	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
> +	spin_lock_init(&mpc8xxx_spi->lock);
> +	init_completion(&mpc8xxx_spi->done);
> +	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
> +	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
> +
> +	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
> +		dev_name(master->dev.parent));
> +	if (mpc8xxx_spi->workqueue == NULL) {
> +		ret = -EBUSY;
> +		goto free_irq;
> +	}
> +
> +	ret = spi_register_master(master);
> +	if (ret < 0)
> +		goto unreg_master;
> +
> +	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
> +		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
> +
> +	return master;
> +
> +unreg_master:
> +	destroy_workqueue(mpc8xxx_spi->workqueue);
> +free_irq:
> +	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> +unmap_io:
> +	iounmap(mpc8xxx_spi->base);
> +err_ioremap:
> +	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
> +err_cpm_init:
> +	spi_master_put(master);
> +err:
> +	return ERR_PTR(ret);
> +}
> +
> +static int __devexit mpc8xxx_spi_remove(struct device *dev)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct spi_master *master;
> +
> +	master = dev_get_drvdata(dev);
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +
> +	flush_workqueue(mpc8xxx_spi->workqueue);
> +	destroy_workqueue(mpc8xxx_spi->workqueue);
> +	spi_unregister_master(master);
> +
> +	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> +	iounmap(mpc8xxx_spi->base);
> +	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
> +
> +	return 0;
> +}
> +
> +struct mpc8xxx_spi_probe_info {
> +	struct fsl_spi_platform_data pdata;
> +	int *gpios;
> +	bool *alow_flags;
> +};
> +
> +static struct mpc8xxx_spi_probe_info *
> +to_of_pinfo(struct fsl_spi_platform_data *pdata)
> +{
> +	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
> +}
> +
> +static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
> +{
> +	struct device *dev = spi->dev.parent;
> +	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
> +	u16 cs = spi->chip_select;
> +	int gpio = pinfo->gpios[cs];
> +	bool alow = pinfo->alow_flags[cs];
> +
> +	gpio_set_value(gpio, on ^ alow);
> +}
> +
> +static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> +	unsigned int ngpios;
> +	int i = 0;
> +	int ret;
> +
> +	ngpios = of_gpio_count(np);
> +	if (!ngpios) {
> +		/*
> +		 * SPI w/o chip-select line. One SPI device is still permitted
> +		 * though.
> +		 */
> +		pdata->max_chipselect = 1;
> +		return 0;
> +	}
> +
> +	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
> +	if (!pinfo->gpios)
> +		return -ENOMEM;
> +	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
> +
> +	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
> +				    GFP_KERNEL);
> +	if (!pinfo->alow_flags) {
> +		ret = -ENOMEM;
> +		goto err_alloc_flags;
> +	}
> +
> +	for (; i < ngpios; i++) {
> +		int gpio;
> +		enum of_gpio_flags flags;
> +
> +		gpio = of_get_gpio_flags(np, i, &flags);
> +		if (!gpio_is_valid(gpio)) {
> +			dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
> +			ret = gpio;
> +			goto err_loop;
> +		}
> +
> +		ret = gpio_request(gpio, dev_name(dev));
> +		if (ret) {
> +			dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
> +			goto err_loop;
> +		}
> +
> +		pinfo->gpios[i] = gpio;
> +		pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
> +
> +		ret = gpio_direction_output(pinfo->gpios[i],
> +					    pinfo->alow_flags[i]);
> +		if (ret) {
> +			dev_err(dev, "can't set output direction for gpio "
> +				"#%d: %d\n", i, ret);
> +			goto err_loop;
> +		}
> +	}
> +
> +	pdata->max_chipselect = ngpios;
> +	pdata->cs_control = mpc8xxx_spi_cs_control;
> +
> +	return 0;
> +
> +err_loop:
> +	while (i >= 0) {
> +		if (gpio_is_valid(pinfo->gpios[i]))
> +			gpio_free(pinfo->gpios[i]);
> +		i--;
> +	}
> +
> +	kfree(pinfo->alow_flags);
> +	pinfo->alow_flags = NULL;
> +err_alloc_flags:
> +	kfree(pinfo->gpios);
> +	pinfo->gpios = NULL;
> +	return ret;
> +}
> +
> +static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> +	int i;
> +
> +	if (!pinfo->gpios)
> +		return 0;
> +
> +	for (i = 0; i < pdata->max_chipselect; i++) {
> +		if (gpio_is_valid(pinfo->gpios[i]))
> +			gpio_free(pinfo->gpios[i]);
> +	}
> +
> +	kfree(pinfo->gpios);
> +	kfree(pinfo->alow_flags);
> +	return 0;
> +}
> +
> +static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
> +					  const struct of_device_id *ofid)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct device_node *np = ofdev->dev.of_node;
> +	struct mpc8xxx_spi_probe_info *pinfo;
> +	struct fsl_spi_platform_data *pdata;
> +	struct spi_master *master;
> +	struct resource mem;
> +	struct resource irq;
> +	const void *prop;
> +	int ret = -ENOMEM;
> +
> +	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
> +	if (!pinfo)
> +		return -ENOMEM;
> +
> +	pdata = &pinfo->pdata;
> +	dev->platform_data = pdata;
> +
> +	/* Allocate bus num dynamically. */
> +	pdata->bus_num = -1;
> +
> +	/* SPI controller is either clocked from QE or SoC clock. */
> +	pdata->sysclk = get_brgfreq();
> +	if (pdata->sysclk == -1) {
> +		pdata->sysclk = fsl_get_sys_freq();
> +		if (pdata->sysclk == -1) {
> +			ret = -ENODEV;
> +			goto err_clk;
> +		}
> +	}
> +
> +	prop = of_get_property(np, "mode", NULL);
> +	if (prop && !strcmp(prop, "cpu-qe"))
> +		pdata->flags = SPI_QE_CPU_MODE;
> +	else if (prop && !strcmp(prop, "qe"))
> +		pdata->flags = SPI_CPM_MODE | SPI_QE;
> +	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
> +		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
> +	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
> +		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
> +
> +	ret = of_mpc8xxx_spi_get_chipselects(dev);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_address_to_resource(np, 0, &mem);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_irq_to_resource(np, 0, &irq);
> +	if (!ret) {
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
> +	if (IS_ERR(master)) {
> +		ret = PTR_ERR(master);
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	of_mpc8xxx_spi_free_chipselects(dev);
> +err_clk:
> +	kfree(pinfo);
> +	return ret;
> +}
> +
> +static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
> +{
> +	int ret;
> +
> +	ret = mpc8xxx_spi_remove(&ofdev->dev);
> +	if (ret)
> +		return ret;
> +	of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
> +	return 0;
> +}
> +
> +static const struct of_device_id of_mpc8xxx_spi_match[] = {
> +	{ .compatible = "fsl,spi" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
> +
> +static struct of_platform_driver of_mpc8xxx_spi_driver = {
> +	.driver = {
> +		.name = "mpc8xxx_spi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_mpc8xxx_spi_match,
> +	},
> +	.probe		= of_mpc8xxx_spi_probe,
> +	.remove		= __devexit_p(of_mpc8xxx_spi_remove),
> +};
> +
> +#ifdef CONFIG_MPC832x_RDB
> +/*
> + * 				XXX XXX XXX
> + * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
> + * only. The driver should go away soon, since newer MPC8323E-RDB's device
> + * tree can work with OpenFirmware driver. But for now we support old trees
> + * as well.
> + */
> +static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
> +{
> +	struct resource *mem;
> +	int irq;
> +	struct spi_master *master;
> +
> +	if (!pdev->dev.platform_data)
> +		return -EINVAL;
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!mem)
> +		return -EINVAL;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq <= 0)
> +		return -EINVAL;
> +
> +	master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
> +	if (IS_ERR(master))
> +		return PTR_ERR(master);
> +	return 0;
> +}
> +
> +static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
> +{
> +	return mpc8xxx_spi_remove(&pdev->dev);
> +}
> +
> +MODULE_ALIAS("platform:mpc8xxx_spi");
> +static struct platform_driver mpc8xxx_spi_driver = {
> +	.probe = plat_mpc8xxx_spi_probe,
> +	.remove = __devexit_p(plat_mpc8xxx_spi_remove),
> +	.driver = {
> +		.name = "mpc8xxx_spi",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +static bool legacy_driver_failed;
> +
> +static void __init legacy_driver_register(void)
> +{
> +	legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
> +}
> +
> +static void __exit legacy_driver_unregister(void)
> +{
> +	if (legacy_driver_failed)
> +		return;
> +	platform_driver_unregister(&mpc8xxx_spi_driver);
> +}
> +#else
> +static void __init legacy_driver_register(void) {}
> +static void __exit legacy_driver_unregister(void) {}
> +#endif /* CONFIG_MPC832x_RDB */
> +
> +static int __init mpc8xxx_spi_init(void)
> +{
> +	legacy_driver_register();
> +	return of_register_platform_driver(&of_mpc8xxx_spi_driver);
> +}
> +
> +static void __exit mpc8xxx_spi_exit(void)
> +{
> +	of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
> +	legacy_driver_unregister();
> +}
> +
> +module_init(mpc8xxx_spi_init);
> +module_exit(mpc8xxx_spi_exit);
> +
> +MODULE_AUTHOR("Kumar Gala");
> +MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
> deleted file mode 100644
> index 1dd86b8..0000000
> --- a/drivers/spi/spi_mpc8xxx.c
> +++ /dev/null
> @@ -1,1425 +0,0 @@
> -/*
> - * MPC8xxx SPI controller driver.
> - *
> - * Maintainer: Kumar Gala
> - *
> - * Copyright (C) 2006 Polycom, Inc.
> - *
> - * CPM SPI and QE buffer descriptors mode support:
> - * Copyright (c) 2009  MontaVista Software, Inc.
> - * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> - *
> - * This program is free software; you can redistribute  it and/or modify it
> - * under  the terms of  the GNU General  Public License as published by the
> - * Free Software Foundation;  either version 2 of the  License, or (at your
> - * option) any later version.
> - */
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/kernel.h>
> -#include <linux/bug.h>
> -#include <linux/errno.h>
> -#include <linux/err.h>
> -#include <linux/io.h>
> -#include <linux/completion.h>
> -#include <linux/interrupt.h>
> -#include <linux/delay.h>
> -#include <linux/irq.h>
> -#include <linux/device.h>
> -#include <linux/spi/spi.h>
> -#include <linux/spi/spi_bitbang.h>
> -#include <linux/platform_device.h>
> -#include <linux/fsl_devices.h>
> -#include <linux/dma-mapping.h>
> -#include <linux/mm.h>
> -#include <linux/mutex.h>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -#include <linux/gpio.h>
> -#include <linux/of_gpio.h>
> -#include <linux/slab.h>
> -
> -#include <sysdev/fsl_soc.h>
> -#include <asm/cpm.h>
> -#include <asm/qe.h>
> -#include <asm/irq.h>
> -
> -/* CPM1 and CPM2 are mutually exclusive. */
> -#ifdef CONFIG_CPM1
> -#include <asm/cpm1.h>
> -#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
> -#else
> -#include <asm/cpm2.h>
> -#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
> -#endif
> -
> -/* SPI Controller registers */
> -struct mpc8xxx_spi_reg {
> -	u8 res1[0x20];
> -	__be32 mode;
> -	__be32 event;
> -	__be32 mask;
> -	__be32 command;
> -	__be32 transmit;
> -	__be32 receive;
> -};
> -
> -/* SPI Controller mode register definitions */
> -#define	SPMODE_LOOP		(1 << 30)
> -#define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
> -#define	SPMODE_CP_BEGIN_EDGECLK	(1 << 28)
> -#define	SPMODE_DIV16		(1 << 27)
> -#define	SPMODE_REV		(1 << 26)
> -#define	SPMODE_MS		(1 << 25)
> -#define	SPMODE_ENABLE		(1 << 24)
> -#define	SPMODE_LEN(x)		((x) << 20)
> -#define	SPMODE_PM(x)		((x) << 16)
> -#define	SPMODE_OP		(1 << 14)
> -#define	SPMODE_CG(x)		((x) << 7)
> -
> -/*
> - * Default for SPI Mode:
> - * 	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
> - */
> -#define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
> -			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
> -
> -/* SPIE register values */
> -#define	SPIE_NE		0x00000200	/* Not empty */
> -#define	SPIE_NF		0x00000100	/* Not full */
> -
> -/* SPIM register values */
> -#define	SPIM_NE		0x00000200	/* Not empty */
> -#define	SPIM_NF		0x00000100	/* Not full */
> -
> -#define	SPIE_TXB	0x00000200	/* Last char is written to tx fifo */
> -#define	SPIE_RXB	0x00000100	/* Last char is written to rx buf */
> -
> -/* SPCOM register values */
> -#define	SPCOM_STR	(1 << 23)	/* Start transmit */
> -
> -#define	SPI_PRAM_SIZE	0x100
> -#define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
> -
> -/* SPI Controller driver's private data. */
> -struct mpc8xxx_spi {
> -	struct device *dev;
> -	struct mpc8xxx_spi_reg __iomem *base;
> -
> -	/* rx & tx bufs from the spi_transfer */
> -	const void *tx;
> -	void *rx;
> -
> -	int subblock;
> -	struct spi_pram __iomem *pram;
> -	struct cpm_buf_desc __iomem *tx_bd;
> -	struct cpm_buf_desc __iomem *rx_bd;
> -
> -	struct spi_transfer *xfer_in_progress;
> -
> -	/* dma addresses for CPM transfers */
> -	dma_addr_t tx_dma;
> -	dma_addr_t rx_dma;
> -	bool map_tx_dma;
> -	bool map_rx_dma;
> -
> -	dma_addr_t dma_dummy_tx;
> -	dma_addr_t dma_dummy_rx;
> -
> -	/* functions to deal with different sized buffers */
> -	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> -	u32(*get_tx) (struct mpc8xxx_spi *);
> -
> -	unsigned int count;
> -	unsigned int irq;
> -
> -	unsigned nsecs;		/* (clock cycle time)/2 */
> -
> -	u32 spibrg;		/* SPIBRG input clock */
> -	u32 rx_shift;		/* RX data reg shift when in qe mode */
> -	u32 tx_shift;		/* TX data reg shift when in qe mode */
> -
> -	unsigned int flags;
> -
> -	struct workqueue_struct *workqueue;
> -	struct work_struct work;
> -
> -	struct list_head queue;
> -	spinlock_t lock;
> -
> -	struct completion done;
> -};
> -
> -static void *mpc8xxx_dummy_rx;
> -static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
> -static int mpc8xxx_dummy_rx_refcnt;
> -
> -struct spi_mpc8xxx_cs {
> -	/* functions to deal with different sized buffers */
> -	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> -	u32 (*get_tx) (struct mpc8xxx_spi *);
> -	u32 rx_shift;		/* RX data reg shift when in qe mode */
> -	u32 tx_shift;		/* TX data reg shift when in qe mode */
> -	u32 hw_mode;		/* Holds HW mode register settings */
> -};
> -
> -static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
> -{
> -	out_be32(reg, val);
> -}
> -
> -static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
> -{
> -	return in_be32(reg);
> -}
> -
> -#define MPC83XX_SPI_RX_BUF(type) 					  \
> -static									  \
> -void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
> -{									  \
> -	type *rx = mpc8xxx_spi->rx;					  \
> -	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
> -	mpc8xxx_spi->rx = rx;						  \
> -}
> -
> -#define MPC83XX_SPI_TX_BUF(type)				\
> -static								\
> -u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
> -{								\
> -	u32 data;						\
> -	const type *tx = mpc8xxx_spi->tx;			\
> -	if (!tx)						\
> -		return 0;					\
> -	data = *tx++ << mpc8xxx_spi->tx_shift;			\
> -	mpc8xxx_spi->tx = tx;					\
> -	return data;						\
> -}
> -
> -MPC83XX_SPI_RX_BUF(u8)
> -MPC83XX_SPI_RX_BUF(u16)
> -MPC83XX_SPI_RX_BUF(u32)
> -MPC83XX_SPI_TX_BUF(u8)
> -MPC83XX_SPI_TX_BUF(u16)
> -MPC83XX_SPI_TX_BUF(u32)
> -
> -static void mpc8xxx_spi_change_mode(struct spi_device *spi)
> -{
> -	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> -	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> -	__be32 __iomem *mode = &mspi->base->mode;
> -	unsigned long flags;
> -
> -	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
> -		return;
> -
> -	/* Turn off IRQs locally to minimize time that SPI is disabled. */
> -	local_irq_save(flags);
> -
> -	/* Turn off SPI unit prior changing mode */
> -	mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
> -
> -	/* When in CPM mode, we need to reinit tx and rx. */
> -	if (mspi->flags & SPI_CPM_MODE) {
> -		if (mspi->flags & SPI_QE) {
> -			qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
> -				     QE_CR_PROTOCOL_UNSPECIFIED, 0);
> -		} else {
> -			cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
> -			if (mspi->flags & SPI_CPM1) {
> -				out_be16(&mspi->pram->rbptr,
> -					 in_be16(&mspi->pram->rbase));
> -				out_be16(&mspi->pram->tbptr,
> -					 in_be16(&mspi->pram->tbase));
> -			}
> -		}
> -	}
> -	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
> -	local_irq_restore(flags);
> -}
> -
> -static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> -	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
> -	bool pol = spi->mode & SPI_CS_HIGH;
> -	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> -
> -	if (value == BITBANG_CS_INACTIVE) {
> -		if (pdata->cs_control)
> -			pdata->cs_control(spi, !pol);
> -	}
> -
> -	if (value == BITBANG_CS_ACTIVE) {
> -		mpc8xxx_spi->rx_shift = cs->rx_shift;
> -		mpc8xxx_spi->tx_shift = cs->tx_shift;
> -		mpc8xxx_spi->get_rx = cs->get_rx;
> -		mpc8xxx_spi->get_tx = cs->get_tx;
> -
> -		mpc8xxx_spi_change_mode(spi);
> -
> -		if (pdata->cs_control)
> -			pdata->cs_control(spi, pol);
> -	}
> -}
> -
> -static int
> -mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
> -			   struct spi_device *spi,
> -			   struct mpc8xxx_spi *mpc8xxx_spi,
> -			   int bits_per_word)
> -{
> -	cs->rx_shift = 0;
> -	cs->tx_shift = 0;
> -	if (bits_per_word <= 8) {
> -		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
> -		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
> -		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> -			cs->rx_shift = 16;
> -			cs->tx_shift = 24;
> -		}
> -	} else if (bits_per_word <= 16) {
> -		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
> -		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
> -		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> -			cs->rx_shift = 16;
> -			cs->tx_shift = 16;
> -		}
> -	} else if (bits_per_word <= 32) {
> -		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
> -		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
> -	} else
> -		return -EINVAL;
> -
> -	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
> -	    spi->mode & SPI_LSB_FIRST) {
> -		cs->tx_shift = 0;
> -		if (bits_per_word <= 8)
> -			cs->rx_shift = 8;
> -		else
> -			cs->rx_shift = 0;
> -	}
> -	mpc8xxx_spi->rx_shift = cs->rx_shift;
> -	mpc8xxx_spi->tx_shift = cs->tx_shift;
> -	mpc8xxx_spi->get_rx = cs->get_rx;
> -	mpc8xxx_spi->get_tx = cs->get_tx;
> -
> -	return bits_per_word;
> -}
> -
> -static int
> -mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
> -			  struct spi_device *spi,
> -			  int bits_per_word)
> -{
> -	/* QE uses Little Endian for words > 8
> -	 * so transform all words > 8 into 8 bits
> -	 * Unfortnatly that doesn't work for LSB so
> -	 * reject these for now */
> -	/* Note: 32 bits word, LSB works iff
> -	 * tfcr/rfcr is set to CPMFCR_GBL */
> -	if (spi->mode & SPI_LSB_FIRST &&
> -	    bits_per_word > 8)
> -		return -EINVAL;
> -	if (bits_per_word > 8)
> -		return 8; /* pretend its 8 bits */
> -	return bits_per_word;
> -}
> -
> -static
> -int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi;
> -	int bits_per_word;
> -	u8 pm;
> -	u32 hz;
> -	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> -
> -	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> -
> -	if (t) {
> -		bits_per_word = t->bits_per_word;
> -		hz = t->speed_hz;
> -	} else {
> -		bits_per_word = 0;
> -		hz = 0;
> -	}
> -
> -	/* spi_transfer level calls that work per-word */
> -	if (!bits_per_word)
> -		bits_per_word = spi->bits_per_word;
> -
> -	/* Make sure its a bit width we support [4..16, 32] */
> -	if ((bits_per_word < 4)
> -	    || ((bits_per_word > 16) && (bits_per_word != 32)))
> -		return -EINVAL;
> -
> -	if (!hz)
> -		hz = spi->max_speed_hz;
> -
> -	if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
> -		bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
> -							   mpc8xxx_spi,
> -							   bits_per_word);
> -	else if (mpc8xxx_spi->flags & SPI_QE)
> -		bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
> -							  bits_per_word);
> -
> -	if (bits_per_word < 0)
> -		return bits_per_word;
> -
> -	if (bits_per_word == 32)
> -		bits_per_word = 0;
> -	else
> -		bits_per_word = bits_per_word - 1;
> -
> -	/* mask out bits we are going to set */
> -	cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
> -				  | SPMODE_PM(0xF));
> -
> -	cs->hw_mode |= SPMODE_LEN(bits_per_word);
> -
> -	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> -		cs->hw_mode |= SPMODE_DIV16;
> -		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> -
> -		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
> -			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
> -			  hz, mpc8xxx_spi->spibrg / 1024);
> -		if (pm > 16)
> -			pm = 16;
> -	} else
> -		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
> -	if (pm)
> -		pm--;
> -
> -	cs->hw_mode |= SPMODE_PM(pm);
> -
> -	mpc8xxx_spi_change_mode(spi);
> -	return 0;
> -}
> -
> -static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
> -{
> -	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
> -	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
> -	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
> -	unsigned int xfer_ofs;
> -
> -	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
> -
> -	if (mspi->rx_dma == mspi->dma_dummy_rx)
> -		out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
> -	else
> -		out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
> -	out_be16(&rx_bd->cbd_datlen, 0);
> -	out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
> -
> -	if (mspi->tx_dma == mspi->dma_dummy_tx)
> -		out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
> -	else
> -		out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
> -	out_be16(&tx_bd->cbd_datlen, xfer_len);
> -	out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
> -				 BD_SC_LAST);
> -
> -	/* start transfer */
> -	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
> -}
> -
> -static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
> -				struct spi_transfer *t, bool is_dma_mapped)
> -{
> -	struct device *dev = mspi->dev;
> -
> -	if (is_dma_mapped) {
> -		mspi->map_tx_dma = 0;
> -		mspi->map_rx_dma = 0;
> -	} else {
> -		mspi->map_tx_dma = 1;
> -		mspi->map_rx_dma = 1;
> -	}
> -
> -	if (!t->tx_buf) {
> -		mspi->tx_dma = mspi->dma_dummy_tx;
> -		mspi->map_tx_dma = 0;
> -	}
> -
> -	if (!t->rx_buf) {
> -		mspi->rx_dma = mspi->dma_dummy_rx;
> -		mspi->map_rx_dma = 0;
> -	}
> -
> -	if (mspi->map_tx_dma) {
> -		void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
> -
> -		mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
> -					      DMA_TO_DEVICE);
> -		if (dma_mapping_error(dev, mspi->tx_dma)) {
> -			dev_err(dev, "unable to map tx dma\n");
> -			return -ENOMEM;
> -		}
> -	} else if (t->tx_buf) {
> -		mspi->tx_dma = t->tx_dma;
> -	}
> -
> -	if (mspi->map_rx_dma) {
> -		mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
> -					      DMA_FROM_DEVICE);
> -		if (dma_mapping_error(dev, mspi->rx_dma)) {
> -			dev_err(dev, "unable to map rx dma\n");
> -			goto err_rx_dma;
> -		}
> -	} else if (t->rx_buf) {
> -		mspi->rx_dma = t->rx_dma;
> -	}
> -
> -	/* enable rx ints */
> -	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
> -
> -	mspi->xfer_in_progress = t;
> -	mspi->count = t->len;
> -
> -	/* start CPM transfers */
> -	mpc8xxx_spi_cpm_bufs_start(mspi);
> -
> -	return 0;
> -
> -err_rx_dma:
> -	if (mspi->map_tx_dma)
> -		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
> -	return -ENOMEM;
> -}
> -
> -static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
> -{
> -	struct device *dev = mspi->dev;
> -	struct spi_transfer *t = mspi->xfer_in_progress;
> -
> -	if (mspi->map_tx_dma)
> -		dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
> -	if (mspi->map_rx_dma)
> -		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
> -	mspi->xfer_in_progress = NULL;
> -}
> -
> -static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
> -				struct spi_transfer *t, unsigned int len)
> -{
> -	u32 word;
> -
> -	mspi->count = len;
> -
> -	/* enable rx ints */
> -	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
> -
> -	/* transmit word */
> -	word = mspi->get_tx(mspi);
> -	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> -
> -	return 0;
> -}
> -
> -static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
> -			    bool is_dma_mapped)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> -	unsigned int len = t->len;
> -	u8 bits_per_word;
> -	int ret;
> -
> -	bits_per_word = spi->bits_per_word;
> -	if (t->bits_per_word)
> -		bits_per_word = t->bits_per_word;
> -
> -	if (bits_per_word > 8) {
> -		/* invalid length? */
> -		if (len & 1)
> -			return -EINVAL;
> -		len /= 2;
> -	}
> -	if (bits_per_word > 16) {
> -		/* invalid length? */
> -		if (len & 1)
> -			return -EINVAL;
> -		len /= 2;
> -	}
> -
> -	mpc8xxx_spi->tx = t->tx_buf;
> -	mpc8xxx_spi->rx = t->rx_buf;
> -
> -	INIT_COMPLETION(mpc8xxx_spi->done);
> -
> -	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> -		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
> -	else
> -		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
> -	if (ret)
> -		return ret;
> -
> -	wait_for_completion(&mpc8xxx_spi->done);
> -
> -	/* disable rx ints */
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> -
> -	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> -		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
> -
> -	return mpc8xxx_spi->count;
> -}
> -
> -static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
> -{
> -	struct spi_device *spi = m->spi;
> -	struct spi_transfer *t;
> -	unsigned int cs_change;
> -	const int nsecs = 50;
> -	int status;
> -
> -	cs_change = 1;
> -	status = 0;
> -	list_for_each_entry(t, &m->transfers, transfer_list) {
> -		if (t->bits_per_word || t->speed_hz) {
> -			/* Don't allow changes if CS is active */
> -			status = -EINVAL;
> -
> -			if (cs_change)
> -				status = mpc8xxx_spi_setup_transfer(spi, t);
> -			if (status < 0)
> -				break;
> -		}
> -
> -		if (cs_change) {
> -			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
> -			ndelay(nsecs);
> -		}
> -		cs_change = t->cs_change;
> -		if (t->len)
> -			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
> -		if (status) {
> -			status = -EMSGSIZE;
> -			break;
> -		}
> -		m->actual_length += t->len;
> -
> -		if (t->delay_usecs)
> -			udelay(t->delay_usecs);
> -
> -		if (cs_change) {
> -			ndelay(nsecs);
> -			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> -			ndelay(nsecs);
> -		}
> -	}
> -
> -	m->status = status;
> -	m->complete(m->context);
> -
> -	if (status || !cs_change) {
> -		ndelay(nsecs);
> -		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> -	}
> -
> -	mpc8xxx_spi_setup_transfer(spi, NULL);
> -}
> -
> -static void mpc8xxx_spi_work(struct work_struct *work)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
> -						       work);
> -
> -	spin_lock_irq(&mpc8xxx_spi->lock);
> -	while (!list_empty(&mpc8xxx_spi->queue)) {
> -		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
> -						   struct spi_message, queue);
> -
> -		list_del_init(&m->queue);
> -		spin_unlock_irq(&mpc8xxx_spi->lock);
> -
> -		mpc8xxx_spi_do_one_msg(m);
> -
> -		spin_lock_irq(&mpc8xxx_spi->lock);
> -	}
> -	spin_unlock_irq(&mpc8xxx_spi->lock);
> -}
> -
> -static int mpc8xxx_spi_setup(struct spi_device *spi)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi;
> -	int retval;
> -	u32 hw_mode;
> -	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> -
> -	if (!spi->max_speed_hz)
> -		return -EINVAL;
> -
> -	if (!cs) {
> -		cs = kzalloc(sizeof *cs, GFP_KERNEL);
> -		if (!cs)
> -			return -ENOMEM;
> -		spi->controller_state = cs;
> -	}
> -	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> -
> -	hw_mode = cs->hw_mode; /* Save original settings */
> -	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
> -	/* mask out bits we are going to set */
> -	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
> -			 | SPMODE_REV | SPMODE_LOOP);
> -
> -	if (spi->mode & SPI_CPHA)
> -		cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
> -	if (spi->mode & SPI_CPOL)
> -		cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
> -	if (!(spi->mode & SPI_LSB_FIRST))
> -		cs->hw_mode |= SPMODE_REV;
> -	if (spi->mode & SPI_LOOP)
> -		cs->hw_mode |= SPMODE_LOOP;
> -
> -	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
> -	if (retval < 0) {
> -		cs->hw_mode = hw_mode; /* Restore settings */
> -		return retval;
> -	}
> -	return 0;
> -}
> -
> -static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
> -{
> -	u16 len;
> -
> -	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
> -		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
> -
> -	len = in_be16(&mspi->rx_bd->cbd_datlen);
> -	if (len > mspi->count) {
> -		WARN_ON(1);
> -		len = mspi->count;
> -	}
> -
> -	/* Clear the events */
> -	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> -
> -	mspi->count -= len;
> -	if (mspi->count)
> -		mpc8xxx_spi_cpm_bufs_start(mspi);
> -	else
> -		complete(&mspi->done);
> -}
> -
> -static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
> -{
> -	/* We need handle RX first */
> -	if (events & SPIE_NE) {
> -		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
> -
> -		if (mspi->rx)
> -			mspi->get_rx(rx_data, mspi);
> -	}
> -
> -	if ((events & SPIE_NF) == 0)
> -		/* spin until TX is done */
> -		while (((events =
> -			mpc8xxx_spi_read_reg(&mspi->base->event)) &
> -						SPIE_NF) == 0)
> -			cpu_relax();
> -
> -	/* Clear the events */
> -	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> -
> -	mspi->count -= 1;
> -	if (mspi->count) {
> -		u32 word = mspi->get_tx(mspi);
> -
> -		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> -	} else {
> -		complete(&mspi->done);
> -	}
> -}
> -
> -static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
> -{
> -	struct mpc8xxx_spi *mspi = context_data;
> -	irqreturn_t ret = IRQ_NONE;
> -	u32 events;
> -
> -	/* Get interrupt events(tx/rx) */
> -	events = mpc8xxx_spi_read_reg(&mspi->base->event);
> -	if (events)
> -		ret = IRQ_HANDLED;
> -
> -	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
> -
> -	if (mspi->flags & SPI_CPM_MODE)
> -		mpc8xxx_spi_cpm_irq(mspi, events);
> -	else
> -		mpc8xxx_spi_cpu_irq(mspi, events);
> -
> -	return ret;
> -}
> -
> -static int mpc8xxx_spi_transfer(struct spi_device *spi,
> -				struct spi_message *m)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> -	unsigned long flags;
> -
> -	m->actual_length = 0;
> -	m->status = -EINPROGRESS;
> -
> -	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
> -	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
> -	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
> -	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
> -
> -	return 0;
> -}
> -
> -
> -static void mpc8xxx_spi_cleanup(struct spi_device *spi)
> -{
> -	kfree(spi->controller_state);
> -}
> -
> -static void *mpc8xxx_spi_alloc_dummy_rx(void)
> -{
> -	mutex_lock(&mpc8xxx_dummy_rx_lock);
> -
> -	if (!mpc8xxx_dummy_rx)
> -		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
> -	if (mpc8xxx_dummy_rx)
> -		mpc8xxx_dummy_rx_refcnt++;
> -
> -	mutex_unlock(&mpc8xxx_dummy_rx_lock);
> -
> -	return mpc8xxx_dummy_rx;
> -}
> -
> -static void mpc8xxx_spi_free_dummy_rx(void)
> -{
> -	mutex_lock(&mpc8xxx_dummy_rx_lock);
> -
> -	switch (mpc8xxx_dummy_rx_refcnt) {
> -	case 0:
> -		WARN_ON(1);
> -		break;
> -	case 1:
> -		kfree(mpc8xxx_dummy_rx);
> -		mpc8xxx_dummy_rx = NULL;
> -		/* fall through */
> -	default:
> -		mpc8xxx_dummy_rx_refcnt--;
> -		break;
> -	}
> -
> -	mutex_unlock(&mpc8xxx_dummy_rx_lock);
> -}
> -
> -static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
> -{
> -	struct device *dev = mspi->dev;
> -	struct device_node *np = dev->of_node;
> -	const u32 *iprop;
> -	int size;
> -	unsigned long spi_base_ofs;
> -	unsigned long pram_ofs = -ENOMEM;
> -
> -	/* Can't use of_address_to_resource(), QE muram isn't at 0. */
> -	iprop = of_get_property(np, "reg", &size);
> -
> -	/* QE with a fixed pram location? */
> -	if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
> -		return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
> -
> -	/* QE but with a dynamic pram location? */
> -	if (mspi->flags & SPI_QE) {
> -		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
> -		qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
> -				QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
> -		return pram_ofs;
> -	}
> -
> -	/* CPM1 and CPM2 pram must be at a fixed addr. */
> -	if (!iprop || size != sizeof(*iprop) * 4)
> -		return -ENOMEM;
> -
> -	spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
> -	if (IS_ERR_VALUE(spi_base_ofs))
> -		return -ENOMEM;
> -
> -	if (mspi->flags & SPI_CPM2) {
> -		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
> -		if (!IS_ERR_VALUE(pram_ofs)) {
> -			u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
> -
> -			out_be16(spi_base, pram_ofs);
> -		}
> -	} else {
> -		struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
> -		u16 rpbase = in_be16(&pram->rpbase);
> -
> -		/* Microcode relocation patch applied? */
> -		if (rpbase)
> -			pram_ofs = rpbase;
> -		else
> -			return spi_base_ofs;
> -	}
> -
> -	cpm_muram_free(spi_base_ofs);
> -	return pram_ofs;
> -}
> -
> -static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
> -{
> -	struct device *dev = mspi->dev;
> -	struct device_node *np = dev->of_node;
> -	const u32 *iprop;
> -	int size;
> -	unsigned long pram_ofs;
> -	unsigned long bds_ofs;
> -
> -	if (!(mspi->flags & SPI_CPM_MODE))
> -		return 0;
> -
> -	if (!mpc8xxx_spi_alloc_dummy_rx())
> -		return -ENOMEM;
> -
> -	if (mspi->flags & SPI_QE) {
> -		iprop = of_get_property(np, "cell-index", &size);
> -		if (iprop && size == sizeof(*iprop))
> -			mspi->subblock = *iprop;
> -
> -		switch (mspi->subblock) {
> -		default:
> -			dev_warn(dev, "cell-index unspecified, assuming SPI1");
> -			/* fall through */
> -		case 0:
> -			mspi->subblock = QE_CR_SUBBLOCK_SPI1;
> -			break;
> -		case 1:
> -			mspi->subblock = QE_CR_SUBBLOCK_SPI2;
> -			break;
> -		}
> -	}
> -
> -	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
> -	if (IS_ERR_VALUE(pram_ofs)) {
> -		dev_err(dev, "can't allocate spi parameter ram\n");
> -		goto err_pram;
> -	}
> -
> -	bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
> -				  sizeof(*mspi->rx_bd), 8);
> -	if (IS_ERR_VALUE(bds_ofs)) {
> -		dev_err(dev, "can't allocate bds\n");
> -		goto err_bds;
> -	}
> -
> -	mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
> -					    DMA_TO_DEVICE);
> -	if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
> -		dev_err(dev, "unable to map dummy tx buffer\n");
> -		goto err_dummy_tx;
> -	}
> -
> -	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
> -					    DMA_FROM_DEVICE);
> -	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
> -		dev_err(dev, "unable to map dummy rx buffer\n");
> -		goto err_dummy_rx;
> -	}
> -
> -	mspi->pram = cpm_muram_addr(pram_ofs);
> -
> -	mspi->tx_bd = cpm_muram_addr(bds_ofs);
> -	mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
> -
> -	/* Initialize parameter ram. */
> -	out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
> -	out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
> -	out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
> -	out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
> -	out_be16(&mspi->pram->mrblr, SPI_MRBLR);
> -	out_be32(&mspi->pram->rstate, 0);
> -	out_be32(&mspi->pram->rdp, 0);
> -	out_be16(&mspi->pram->rbptr, 0);
> -	out_be16(&mspi->pram->rbc, 0);
> -	out_be32(&mspi->pram->rxtmp, 0);
> -	out_be32(&mspi->pram->tstate, 0);
> -	out_be32(&mspi->pram->tdp, 0);
> -	out_be16(&mspi->pram->tbptr, 0);
> -	out_be16(&mspi->pram->tbc, 0);
> -	out_be32(&mspi->pram->txtmp, 0);
> -
> -	return 0;
> -
> -err_dummy_rx:
> -	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
> -err_dummy_tx:
> -	cpm_muram_free(bds_ofs);
> -err_bds:
> -	cpm_muram_free(pram_ofs);
> -err_pram:
> -	mpc8xxx_spi_free_dummy_rx();
> -	return -ENOMEM;
> -}
> -
> -static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
> -{
> -	struct device *dev = mspi->dev;
> -
> -	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
> -	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
> -	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
> -	cpm_muram_free(cpm_muram_offset(mspi->pram));
> -	mpc8xxx_spi_free_dummy_rx();
> -}
> -
> -static const char *mpc8xxx_spi_strmode(unsigned int flags)
> -{
> -	if (flags & SPI_QE_CPU_MODE) {
> -		return "QE CPU";
> -	} else if (flags & SPI_CPM_MODE) {
> -		if (flags & SPI_QE)
> -			return "QE";
> -		else if (flags & SPI_CPM2)
> -			return "CPM2";
> -		else
> -			return "CPM1";
> -	}
> -	return "CPU";
> -}
> -
> -static struct spi_master * __devinit
> -mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
> -{
> -	struct fsl_spi_platform_data *pdata = dev->platform_data;
> -	struct spi_master *master;
> -	struct mpc8xxx_spi *mpc8xxx_spi;
> -	u32 regval;
> -	int ret = 0;
> -
> -	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
> -	if (master == NULL) {
> -		ret = -ENOMEM;
> -		goto err;
> -	}
> -
> -	dev_set_drvdata(dev, master);
> -
> -	/* the spi->mode bits understood by this driver: */
> -	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
> -			| SPI_LSB_FIRST | SPI_LOOP;
> -
> -	master->setup = mpc8xxx_spi_setup;
> -	master->transfer = mpc8xxx_spi_transfer;
> -	master->cleanup = mpc8xxx_spi_cleanup;
> -	master->dev.of_node = dev->of_node;
> -
> -	mpc8xxx_spi = spi_master_get_devdata(master);
> -	mpc8xxx_spi->dev = dev;
> -	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
> -	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
> -	mpc8xxx_spi->flags = pdata->flags;
> -	mpc8xxx_spi->spibrg = pdata->sysclk;
> -
> -	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
> -	if (ret)
> -		goto err_cpm_init;
> -
> -	mpc8xxx_spi->rx_shift = 0;
> -	mpc8xxx_spi->tx_shift = 0;
> -	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> -		mpc8xxx_spi->rx_shift = 16;
> -		mpc8xxx_spi->tx_shift = 24;
> -	}
> -
> -	init_completion(&mpc8xxx_spi->done);
> -
> -	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
> -	if (mpc8xxx_spi->base == NULL) {
> -		ret = -ENOMEM;
> -		goto err_ioremap;
> -	}
> -
> -	mpc8xxx_spi->irq = irq;
> -
> -	/* Register for SPI Interrupt */
> -	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
> -			  0, "mpc8xxx_spi", mpc8xxx_spi);
> -
> -	if (ret != 0)
> -		goto unmap_io;
> -
> -	master->bus_num = pdata->bus_num;
> -	master->num_chipselect = pdata->max_chipselect;
> -
> -	/* SPI controller initializations */
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
> -
> -	/* Enable SPI interface */
> -	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
> -	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
> -		regval |= SPMODE_OP;
> -
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
> -	spin_lock_init(&mpc8xxx_spi->lock);
> -	init_completion(&mpc8xxx_spi->done);
> -	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
> -	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
> -
> -	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
> -		dev_name(master->dev.parent));
> -	if (mpc8xxx_spi->workqueue == NULL) {
> -		ret = -EBUSY;
> -		goto free_irq;
> -	}
> -
> -	ret = spi_register_master(master);
> -	if (ret < 0)
> -		goto unreg_master;
> -
> -	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
> -		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
> -
> -	return master;
> -
> -unreg_master:
> -	destroy_workqueue(mpc8xxx_spi->workqueue);
> -free_irq:
> -	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> -unmap_io:
> -	iounmap(mpc8xxx_spi->base);
> -err_ioremap:
> -	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
> -err_cpm_init:
> -	spi_master_put(master);
> -err:
> -	return ERR_PTR(ret);
> -}
> -
> -static int __devexit mpc8xxx_spi_remove(struct device *dev)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi;
> -	struct spi_master *master;
> -
> -	master = dev_get_drvdata(dev);
> -	mpc8xxx_spi = spi_master_get_devdata(master);
> -
> -	flush_workqueue(mpc8xxx_spi->workqueue);
> -	destroy_workqueue(mpc8xxx_spi->workqueue);
> -	spi_unregister_master(master);
> -
> -	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> -	iounmap(mpc8xxx_spi->base);
> -	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
> -
> -	return 0;
> -}
> -
> -struct mpc8xxx_spi_probe_info {
> -	struct fsl_spi_platform_data pdata;
> -	int *gpios;
> -	bool *alow_flags;
> -};
> -
> -static struct mpc8xxx_spi_probe_info *
> -to_of_pinfo(struct fsl_spi_platform_data *pdata)
> -{
> -	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
> -}
> -
> -static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
> -{
> -	struct device *dev = spi->dev.parent;
> -	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
> -	u16 cs = spi->chip_select;
> -	int gpio = pinfo->gpios[cs];
> -	bool alow = pinfo->alow_flags[cs];
> -
> -	gpio_set_value(gpio, on ^ alow);
> -}
> -
> -static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
> -{
> -	struct device_node *np = dev->of_node;
> -	struct fsl_spi_platform_data *pdata = dev->platform_data;
> -	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> -	unsigned int ngpios;
> -	int i = 0;
> -	int ret;
> -
> -	ngpios = of_gpio_count(np);
> -	if (!ngpios) {
> -		/*
> -		 * SPI w/o chip-select line. One SPI device is still permitted
> -		 * though.
> -		 */
> -		pdata->max_chipselect = 1;
> -		return 0;
> -	}
> -
> -	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
> -	if (!pinfo->gpios)
> -		return -ENOMEM;
> -	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
> -
> -	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
> -				    GFP_KERNEL);
> -	if (!pinfo->alow_flags) {
> -		ret = -ENOMEM;
> -		goto err_alloc_flags;
> -	}
> -
> -	for (; i < ngpios; i++) {
> -		int gpio;
> -		enum of_gpio_flags flags;
> -
> -		gpio = of_get_gpio_flags(np, i, &flags);
> -		if (!gpio_is_valid(gpio)) {
> -			dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
> -			ret = gpio;
> -			goto err_loop;
> -		}
> -
> -		ret = gpio_request(gpio, dev_name(dev));
> -		if (ret) {
> -			dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
> -			goto err_loop;
> -		}
> -
> -		pinfo->gpios[i] = gpio;
> -		pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
> -
> -		ret = gpio_direction_output(pinfo->gpios[i],
> -					    pinfo->alow_flags[i]);
> -		if (ret) {
> -			dev_err(dev, "can't set output direction for gpio "
> -				"#%d: %d\n", i, ret);
> -			goto err_loop;
> -		}
> -	}
> -
> -	pdata->max_chipselect = ngpios;
> -	pdata->cs_control = mpc8xxx_spi_cs_control;
> -
> -	return 0;
> -
> -err_loop:
> -	while (i >= 0) {
> -		if (gpio_is_valid(pinfo->gpios[i]))
> -			gpio_free(pinfo->gpios[i]);
> -		i--;
> -	}
> -
> -	kfree(pinfo->alow_flags);
> -	pinfo->alow_flags = NULL;
> -err_alloc_flags:
> -	kfree(pinfo->gpios);
> -	pinfo->gpios = NULL;
> -	return ret;
> -}
> -
> -static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
> -{
> -	struct fsl_spi_platform_data *pdata = dev->platform_data;
> -	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> -	int i;
> -
> -	if (!pinfo->gpios)
> -		return 0;
> -
> -	for (i = 0; i < pdata->max_chipselect; i++) {
> -		if (gpio_is_valid(pinfo->gpios[i]))
> -			gpio_free(pinfo->gpios[i]);
> -	}
> -
> -	kfree(pinfo->gpios);
> -	kfree(pinfo->alow_flags);
> -	return 0;
> -}
> -
> -static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
> -					  const struct of_device_id *ofid)
> -{
> -	struct device *dev = &ofdev->dev;
> -	struct device_node *np = ofdev->dev.of_node;
> -	struct mpc8xxx_spi_probe_info *pinfo;
> -	struct fsl_spi_platform_data *pdata;
> -	struct spi_master *master;
> -	struct resource mem;
> -	struct resource irq;
> -	const void *prop;
> -	int ret = -ENOMEM;
> -
> -	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
> -	if (!pinfo)
> -		return -ENOMEM;
> -
> -	pdata = &pinfo->pdata;
> -	dev->platform_data = pdata;
> -
> -	/* Allocate bus num dynamically. */
> -	pdata->bus_num = -1;
> -
> -	/* SPI controller is either clocked from QE or SoC clock. */
> -	pdata->sysclk = get_brgfreq();
> -	if (pdata->sysclk == -1) {
> -		pdata->sysclk = fsl_get_sys_freq();
> -		if (pdata->sysclk == -1) {
> -			ret = -ENODEV;
> -			goto err_clk;
> -		}
> -	}
> -
> -	prop = of_get_property(np, "mode", NULL);
> -	if (prop && !strcmp(prop, "cpu-qe"))
> -		pdata->flags = SPI_QE_CPU_MODE;
> -	else if (prop && !strcmp(prop, "qe"))
> -		pdata->flags = SPI_CPM_MODE | SPI_QE;
> -	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
> -		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
> -	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
> -		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
> -
> -	ret = of_mpc8xxx_spi_get_chipselects(dev);
> -	if (ret)
> -		goto err;
> -
> -	ret = of_address_to_resource(np, 0, &mem);
> -	if (ret)
> -		goto err;
> -
> -	ret = of_irq_to_resource(np, 0, &irq);
> -	if (!ret) {
> -		ret = -EINVAL;
> -		goto err;
> -	}
> -
> -	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
> -	if (IS_ERR(master)) {
> -		ret = PTR_ERR(master);
> -		goto err;
> -	}
> -
> -	return 0;
> -
> -err:
> -	of_mpc8xxx_spi_free_chipselects(dev);
> -err_clk:
> -	kfree(pinfo);
> -	return ret;
> -}
> -
> -static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
> -{
> -	int ret;
> -
> -	ret = mpc8xxx_spi_remove(&ofdev->dev);
> -	if (ret)
> -		return ret;
> -	of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
> -	return 0;
> -}
> -
> -static const struct of_device_id of_mpc8xxx_spi_match[] = {
> -	{ .compatible = "fsl,spi" },
> -	{},
> -};
> -MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
> -
> -static struct of_platform_driver of_mpc8xxx_spi_driver = {
> -	.driver = {
> -		.name = "mpc8xxx_spi",
> -		.owner = THIS_MODULE,
> -		.of_match_table = of_mpc8xxx_spi_match,
> -	},
> -	.probe		= of_mpc8xxx_spi_probe,
> -	.remove		= __devexit_p(of_mpc8xxx_spi_remove),
> -};
> -
> -#ifdef CONFIG_MPC832x_RDB
> -/*
> - * 				XXX XXX XXX
> - * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
> - * only. The driver should go away soon, since newer MPC8323E-RDB's device
> - * tree can work with OpenFirmware driver. But for now we support old trees
> - * as well.
> - */
> -static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
> -{
> -	struct resource *mem;
> -	int irq;
> -	struct spi_master *master;
> -
> -	if (!pdev->dev.platform_data)
> -		return -EINVAL;
> -
> -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!mem)
> -		return -EINVAL;
> -
> -	irq = platform_get_irq(pdev, 0);
> -	if (irq <= 0)
> -		return -EINVAL;
> -
> -	master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
> -	if (IS_ERR(master))
> -		return PTR_ERR(master);
> -	return 0;
> -}
> -
> -static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
> -{
> -	return mpc8xxx_spi_remove(&pdev->dev);
> -}
> -
> -MODULE_ALIAS("platform:mpc8xxx_spi");
> -static struct platform_driver mpc8xxx_spi_driver = {
> -	.probe = plat_mpc8xxx_spi_probe,
> -	.remove = __devexit_p(plat_mpc8xxx_spi_remove),
> -	.driver = {
> -		.name = "mpc8xxx_spi",
> -		.owner = THIS_MODULE,
> -	},
> -};
> -
> -static bool legacy_driver_failed;
> -
> -static void __init legacy_driver_register(void)
> -{
> -	legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
> -}
> -
> -static void __exit legacy_driver_unregister(void)
> -{
> -	if (legacy_driver_failed)
> -		return;
> -	platform_driver_unregister(&mpc8xxx_spi_driver);
> -}
> -#else
> -static void __init legacy_driver_register(void) {}
> -static void __exit legacy_driver_unregister(void) {}
> -#endif /* CONFIG_MPC832x_RDB */
> -
> -static int __init mpc8xxx_spi_init(void)
> -{
> -	legacy_driver_register();
> -	return of_register_platform_driver(&of_mpc8xxx_spi_driver);
> -}
> -
> -static void __exit mpc8xxx_spi_exit(void)
> -{
> -	of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
> -	legacy_driver_unregister();
> -}
> -
> -module_init(mpc8xxx_spi_init);
> -module_exit(mpc8xxx_spi_exit);
> -
> -MODULE_AUTHOR("Kumar Gala");
> -MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
> -MODULE_LICENSE("GPL");
> -- 
> 1.6.4
> 
> 

^ permalink raw reply

* Re: [PATCH v4 2/5] spi/mpc8xxx: refactor the common code for SPI/eSPI controller
From: Grant Likely @ 2010-10-13  3:41 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general
In-Reply-To: <1286878714-13090-3-git-send-email-Mingkai.hu@freescale.com>

On Tue, Oct 12, 2010 at 06:18:31PM +0800, Mingkai Hu wrote:
> Refactor the common code in file spi_fsl_spi.c to spi_fsl_lib.c used
> by SPI/eSPI controller driver as a library, and leave the QE/CPM SPI
> controller code in the SPI controller driver spi_fsl_spi.c.
> 
> Because the register map of the SPI controller and eSPI controller
> is so different, also leave the code operated the register to the
> driver code, not the common code.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>

Applied, thanks.

g.

> ---
> v4:
>  - Updated to latest kernel base(Linux 2.6.36-rc7).
> 
>  drivers/spi/Kconfig       |    5 +
>  drivers/spi/Makefile      |    1 +
>  drivers/spi/spi_fsl_lib.c |  237 +++++++++++++++++++
>  drivers/spi/spi_fsl_lib.h |  119 ++++++++++
>  drivers/spi/spi_fsl_spi.c |  552 +++++++++++++--------------------------------
>  5 files changed, 522 insertions(+), 392 deletions(-)
>  create mode 100644 drivers/spi/spi_fsl_lib.c
>  create mode 100644 drivers/spi/spi_fsl_lib.h
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 6af34c6..79ad06f 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -182,9 +182,14 @@ config SPI_MPC512x_PSC
>  	  This enables using the Freescale MPC5121 Programmable Serial
>  	  Controller in SPI master mode.
>  
> +config SPI_FSL_LIB
> +	tristate
> +	depends on FSL_SOC
> +
>  config SPI_FSL_SPI
>  	tristate "Freescale SPI controller"
>  	depends on FSL_SOC
> +	select SPI_FSL_LIB
>  	help
>  	  This enables using the Freescale SPI controllers in master mode.
>  	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 770817c..7974c21 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -34,6 +34,7 @@ obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
>  obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
> +obj-$(CONFIG_SPI_FSL_LIB)		+= spi_fsl_lib.o
>  obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
>  obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
>  obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
> diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c
> new file mode 100644
> index 0000000..5cd741f
> --- /dev/null
> +++ b/drivers/spi/spi_fsl_lib.c
> @@ -0,0 +1,237 @@
> +/*
> + * Freescale SPI/eSPI controller driver library.
> + *
> + * Maintainer: Kumar Gala
> + *
> + * Copyright (C) 2006 Polycom, Inc.
> + *
> + * CPM SPI and QE buffer descriptors mode support:
> + * Copyright (c) 2009  MontaVista Software, Inc.
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * Copyright 2010 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.
> + */
> +#include <linux/kernel.h>
> +#include <linux/interrupt.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/mm.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_spi.h>
> +#include <sysdev/fsl_soc.h>
> +
> +#include "spi_fsl_lib.h"
> +
> +#define MPC8XXX_SPI_RX_BUF(type) 					  \
> +void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
> +{									  \
> +	type *rx = mpc8xxx_spi->rx;					  \
> +	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
> +	mpc8xxx_spi->rx = rx;						  \
> +}
> +
> +#define MPC8XXX_SPI_TX_BUF(type)				\
> +u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
> +{								\
> +	u32 data;						\
> +	const type *tx = mpc8xxx_spi->tx;			\
> +	if (!tx)						\
> +		return 0;					\
> +	data = *tx++ << mpc8xxx_spi->tx_shift;			\
> +	mpc8xxx_spi->tx = tx;					\
> +	return data;						\
> +}
> +
> +MPC8XXX_SPI_RX_BUF(u8)
> +MPC8XXX_SPI_RX_BUF(u16)
> +MPC8XXX_SPI_RX_BUF(u32)
> +MPC8XXX_SPI_TX_BUF(u8)
> +MPC8XXX_SPI_TX_BUF(u16)
> +MPC8XXX_SPI_TX_BUF(u32)
> +
> +struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
> +{
> +	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
> +}
> +
> +void mpc8xxx_spi_work(struct work_struct *work)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
> +						       work);
> +
> +	spin_lock_irq(&mpc8xxx_spi->lock);
> +	while (!list_empty(&mpc8xxx_spi->queue)) {
> +		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
> +						   struct spi_message, queue);
> +
> +		list_del_init(&m->queue);
> +		spin_unlock_irq(&mpc8xxx_spi->lock);
> +
> +		if (mpc8xxx_spi->spi_do_one_msg)
> +			mpc8xxx_spi->spi_do_one_msg(m);
> +
> +		spin_lock_irq(&mpc8xxx_spi->lock);
> +	}
> +	spin_unlock_irq(&mpc8xxx_spi->lock);
> +}
> +
> +int mpc8xxx_spi_transfer(struct spi_device *spi,
> +				struct spi_message *m)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	unsigned long flags;
> +
> +	m->actual_length = 0;
> +	m->status = -EINPROGRESS;
> +
> +	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
> +	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
> +	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
> +	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
> +
> +	return 0;
> +}
> +
> +void mpc8xxx_spi_cleanup(struct spi_device *spi)
> +{
> +	kfree(spi->controller_state);
> +}
> +
> +const char *mpc8xxx_spi_strmode(unsigned int flags)
> +{
> +	if (flags & SPI_QE_CPU_MODE) {
> +		return "QE CPU";
> +	} else if (flags & SPI_CPM_MODE) {
> +		if (flags & SPI_QE)
> +			return "QE";
> +		else if (flags & SPI_CPM2)
> +			return "CPM2";
> +		else
> +			return "CPM1";
> +	}
> +	return "CPU";
> +}
> +
> +int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
> +			unsigned int irq)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct spi_master *master;
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	int ret = 0;
> +
> +	master = dev_get_drvdata(dev);
> +
> +	/* the spi->mode bits understood by this driver: */
> +	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
> +			| SPI_LSB_FIRST | SPI_LOOP;
> +
> +	master->transfer = mpc8xxx_spi_transfer;
> +	master->cleanup = mpc8xxx_spi_cleanup;
> +	master->dev.of_node = dev->of_node;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->dev = dev;
> +	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
> +	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
> +	mpc8xxx_spi->flags = pdata->flags;
> +	mpc8xxx_spi->spibrg = pdata->sysclk;
> +	mpc8xxx_spi->irq = irq;
> +
> +	mpc8xxx_spi->rx_shift = 0;
> +	mpc8xxx_spi->tx_shift = 0;
> +
> +	init_completion(&mpc8xxx_spi->done);
> +
> +	master->bus_num = pdata->bus_num;
> +	master->num_chipselect = pdata->max_chipselect;
> +
> +	spin_lock_init(&mpc8xxx_spi->lock);
> +	init_completion(&mpc8xxx_spi->done);
> +	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
> +	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
> +
> +	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
> +		dev_name(master->dev.parent));
> +	if (mpc8xxx_spi->workqueue == NULL) {
> +		ret = -EBUSY;
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}
> +
> +int __devexit mpc8xxx_spi_remove(struct device *dev)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct spi_master *master;
> +
> +	master = dev_get_drvdata(dev);
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +
> +	flush_workqueue(mpc8xxx_spi->workqueue);
> +	destroy_workqueue(mpc8xxx_spi->workqueue);
> +	spi_unregister_master(master);
> +
> +	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> +
> +	if (mpc8xxx_spi->spi_remove)
> +		mpc8xxx_spi->spi_remove(mpc8xxx_spi);
> +
> +	return 0;
> +}
> +
> +int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
> +					const struct of_device_id *ofid)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct device_node *np = ofdev->dev.of_node;
> +	struct mpc8xxx_spi_probe_info *pinfo;
> +	struct fsl_spi_platform_data *pdata;
> +	const void *prop;
> +	int ret = -ENOMEM;
> +
> +	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
> +	if (!pinfo)
> +		return -ENOMEM;
> +
> +	pdata = &pinfo->pdata;
> +	dev->platform_data = pdata;
> +
> +	/* Allocate bus num dynamically. */
> +	pdata->bus_num = -1;
> +
> +	/* SPI controller is either clocked from QE or SoC clock. */
> +	pdata->sysclk = get_brgfreq();
> +	if (pdata->sysclk == -1) {
> +		pdata->sysclk = fsl_get_sys_freq();
> +		if (pdata->sysclk == -1) {
> +			ret = -ENODEV;
> +			goto err;
> +		}
> +	}
> +
> +	prop = of_get_property(np, "mode", NULL);
> +	if (prop && !strcmp(prop, "cpu-qe"))
> +		pdata->flags = SPI_QE_CPU_MODE;
> +	else if (prop && !strcmp(prop, "qe"))
> +		pdata->flags = SPI_CPM_MODE | SPI_QE;
> +	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
> +		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
> +	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
> +		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
> +
> +	return 0;
> +
> +err:
> +	kfree(pinfo);
> +	return ret;
> +}
> diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
> new file mode 100644
> index 0000000..6ae8949
> --- /dev/null
> +++ b/drivers/spi/spi_fsl_lib.h
> @@ -0,0 +1,119 @@
> +/*
> + * Freescale SPI/eSPI controller driver library.
> + *
> + * Maintainer: Kumar Gala
> + *
> + * Copyright 2010 Freescale Semiconductor, Inc.
> + * Copyright (C) 2006 Polycom, Inc.
> + *
> + * CPM SPI and QE buffer descriptors mode support:
> + * Copyright (c) 2009  MontaVista Software, Inc.
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * 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.
> + */
> +#ifndef __SPI_FSL_LIB_H__
> +#define __SPI_FSL_LIB_H__
> +
> +/* SPI/eSPI Controller driver's private data. */
> +struct mpc8xxx_spi {
> +	struct device *dev;
> +	void *reg_base;
> +
> +	/* rx & tx bufs from the spi_transfer */
> +	const void *tx;
> +	void *rx;
> +
> +	int subblock;
> +	struct spi_pram __iomem *pram;
> +	struct cpm_buf_desc __iomem *tx_bd;
> +	struct cpm_buf_desc __iomem *rx_bd;
> +
> +	struct spi_transfer *xfer_in_progress;
> +
> +	/* dma addresses for CPM transfers */
> +	dma_addr_t tx_dma;
> +	dma_addr_t rx_dma;
> +	bool map_tx_dma;
> +	bool map_rx_dma;
> +
> +	dma_addr_t dma_dummy_tx;
> +	dma_addr_t dma_dummy_rx;
> +
> +	/* functions to deal with different sized buffers */
> +	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> +	u32(*get_tx) (struct mpc8xxx_spi *);
> +
> +	/* hooks for different controller driver */
> +	void (*spi_do_one_msg) (struct spi_message *m);
> +	void (*spi_remove) (struct mpc8xxx_spi *mspi);
> +
> +	unsigned int count;
> +	unsigned int irq;
> +
> +	unsigned nsecs;		/* (clock cycle time)/2 */
> +
> +	u32 spibrg;		/* SPIBRG input clock */
> +	u32 rx_shift;		/* RX data reg shift when in qe mode */
> +	u32 tx_shift;		/* TX data reg shift when in qe mode */
> +
> +	unsigned int flags;
> +
> +	struct workqueue_struct *workqueue;
> +	struct work_struct work;
> +
> +	struct list_head queue;
> +	spinlock_t lock;
> +
> +	struct completion done;
> +};
> +
> +struct spi_mpc8xxx_cs {
> +	/* functions to deal with different sized buffers */
> +	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> +	u32 (*get_tx) (struct mpc8xxx_spi *);
> +	u32 rx_shift;		/* RX data reg shift when in qe mode */
> +	u32 tx_shift;		/* TX data reg shift when in qe mode */
> +	u32 hw_mode;		/* Holds HW mode register settings */
> +};
> +
> +static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
> +{
> +	out_be32(reg, val);
> +}
> +
> +static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
> +{
> +	return in_be32(reg);
> +}
> +
> +struct mpc8xxx_spi_probe_info {
> +	struct fsl_spi_platform_data pdata;
> +	int *gpios;
> +	bool *alow_flags;
> +};
> +
> +extern u32 mpc8xxx_spi_tx_buf_u8(struct mpc8xxx_spi *mpc8xxx_spi);
> +extern u32 mpc8xxx_spi_tx_buf_u16(struct mpc8xxx_spi *mpc8xxx_spi);
> +extern u32 mpc8xxx_spi_tx_buf_u32(struct mpc8xxx_spi *mpc8xxx_spi);
> +extern void mpc8xxx_spi_rx_buf_u8(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
> +extern void mpc8xxx_spi_rx_buf_u16(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
> +extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
> +
> +extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
> +		struct fsl_spi_platform_data *pdata);
> +extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
> +		struct spi_transfer *t, unsigned int len);
> +extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
> +extern void mpc8xxx_spi_cleanup(struct spi_device *spi);
> +extern const char *mpc8xxx_spi_strmode(unsigned int flags);
> +extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
> +		unsigned int irq);
> +extern int mpc8xxx_spi_remove(struct device *dev);
> +extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev,
> +				const struct of_device_id *ofid);
> +
> +#endif /* __SPI_FSL_LIB_H__ */
> diff --git a/drivers/spi/spi_fsl_spi.c b/drivers/spi/spi_fsl_spi.c
> index 1dd86b8..7ca52d3 100644
> --- a/drivers/spi/spi_fsl_spi.c
> +++ b/drivers/spi/spi_fsl_spi.c
> @@ -1,9 +1,10 @@
>  /*
> - * MPC8xxx SPI controller driver.
> + * Freescale SPI controller driver.
>   *
>   * Maintainer: Kumar Gala
>   *
>   * Copyright (C) 2006 Polycom, Inc.
> + * Copyright 2010 Freescale Semiconductor, Inc.
>   *
>   * CPM SPI and QE buffer descriptors mode support:
>   * Copyright (c) 2009  MontaVista Software, Inc.
> @@ -15,18 +16,11 @@
>   * option) any later version.
>   */
>  #include <linux/module.h>
> -#include <linux/init.h>
>  #include <linux/types.h>
>  #include <linux/kernel.h>
> -#include <linux/bug.h>
> -#include <linux/errno.h>
> -#include <linux/err.h>
> -#include <linux/io.h>
> -#include <linux/completion.h>
>  #include <linux/interrupt.h>
>  #include <linux/delay.h>
>  #include <linux/irq.h>
> -#include <linux/device.h>
>  #include <linux/spi/spi.h>
>  #include <linux/spi/spi_bitbang.h>
>  #include <linux/platform_device.h>
> @@ -38,12 +32,12 @@
>  #include <linux/of_platform.h>
>  #include <linux/gpio.h>
>  #include <linux/of_gpio.h>
> -#include <linux/slab.h>
>  
>  #include <sysdev/fsl_soc.h>
>  #include <asm/cpm.h>
>  #include <asm/qe.h>
> -#include <asm/irq.h>
> +
> +#include "spi_fsl_lib.h"
>  
>  /* CPM1 and CPM2 are mutually exclusive. */
>  #ifdef CONFIG_CPM1
> @@ -55,7 +49,7 @@
>  #endif
>  
>  /* SPI Controller registers */
> -struct mpc8xxx_spi_reg {
> +struct fsl_spi_reg {
>  	u8 res1[0x20];
>  	__be32 mode;
>  	__be32 event;
> @@ -80,7 +74,7 @@ struct mpc8xxx_spi_reg {
>  
>  /*
>   * Default for SPI Mode:
> - * 	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
> + *	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
>   */
>  #define	SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
>  			 SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
> @@ -102,112 +96,16 @@ struct mpc8xxx_spi_reg {
>  #define	SPI_PRAM_SIZE	0x100
>  #define	SPI_MRBLR	((unsigned int)PAGE_SIZE)
>  
> -/* SPI Controller driver's private data. */
> -struct mpc8xxx_spi {
> -	struct device *dev;
> -	struct mpc8xxx_spi_reg __iomem *base;
> -
> -	/* rx & tx bufs from the spi_transfer */
> -	const void *tx;
> -	void *rx;
> -
> -	int subblock;
> -	struct spi_pram __iomem *pram;
> -	struct cpm_buf_desc __iomem *tx_bd;
> -	struct cpm_buf_desc __iomem *rx_bd;
> -
> -	struct spi_transfer *xfer_in_progress;
> -
> -	/* dma addresses for CPM transfers */
> -	dma_addr_t tx_dma;
> -	dma_addr_t rx_dma;
> -	bool map_tx_dma;
> -	bool map_rx_dma;
> -
> -	dma_addr_t dma_dummy_tx;
> -	dma_addr_t dma_dummy_rx;
> -
> -	/* functions to deal with different sized buffers */
> -	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> -	u32(*get_tx) (struct mpc8xxx_spi *);
> -
> -	unsigned int count;
> -	unsigned int irq;
> -
> -	unsigned nsecs;		/* (clock cycle time)/2 */
> -
> -	u32 spibrg;		/* SPIBRG input clock */
> -	u32 rx_shift;		/* RX data reg shift when in qe mode */
> -	u32 tx_shift;		/* TX data reg shift when in qe mode */
> -
> -	unsigned int flags;
> -
> -	struct workqueue_struct *workqueue;
> -	struct work_struct work;
> -
> -	struct list_head queue;
> -	spinlock_t lock;
> -
> -	struct completion done;
> -};
> -
> -static void *mpc8xxx_dummy_rx;
> -static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
> -static int mpc8xxx_dummy_rx_refcnt;
> -
> -struct spi_mpc8xxx_cs {
> -	/* functions to deal with different sized buffers */
> -	void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
> -	u32 (*get_tx) (struct mpc8xxx_spi *);
> -	u32 rx_shift;		/* RX data reg shift when in qe mode */
> -	u32 tx_shift;		/* TX data reg shift when in qe mode */
> -	u32 hw_mode;		/* Holds HW mode register settings */
> -};
> -
> -static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
> -{
> -	out_be32(reg, val);
> -}
> -
> -static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
> -{
> -	return in_be32(reg);
> -}
> -
> -#define MPC83XX_SPI_RX_BUF(type) 					  \
> -static									  \
> -void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
> -{									  \
> -	type *rx = mpc8xxx_spi->rx;					  \
> -	*rx++ = (type)(data >> mpc8xxx_spi->rx_shift);			  \
> -	mpc8xxx_spi->rx = rx;						  \
> -}
> -
> -#define MPC83XX_SPI_TX_BUF(type)				\
> -static								\
> -u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi)	\
> -{								\
> -	u32 data;						\
> -	const type *tx = mpc8xxx_spi->tx;			\
> -	if (!tx)						\
> -		return 0;					\
> -	data = *tx++ << mpc8xxx_spi->tx_shift;			\
> -	mpc8xxx_spi->tx = tx;					\
> -	return data;						\
> -}
> +static void *fsl_dummy_rx;
> +static DEFINE_MUTEX(fsl_dummy_rx_lock);
> +static int fsl_dummy_rx_refcnt;
>  
> -MPC83XX_SPI_RX_BUF(u8)
> -MPC83XX_SPI_RX_BUF(u16)
> -MPC83XX_SPI_RX_BUF(u32)
> -MPC83XX_SPI_TX_BUF(u8)
> -MPC83XX_SPI_TX_BUF(u16)
> -MPC83XX_SPI_TX_BUF(u32)
> -
> -static void mpc8xxx_spi_change_mode(struct spi_device *spi)
> +static void fsl_spi_change_mode(struct spi_device *spi)
>  {
>  	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
>  	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> -	__be32 __iomem *mode = &mspi->base->mode;
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
> +	__be32 __iomem *mode = &reg_base->mode;
>  	unsigned long flags;
>  
>  	if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
> @@ -238,7 +136,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
>  	local_irq_restore(flags);
>  }
>  
> -static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
> +static void fsl_spi_chipselect(struct spi_device *spi, int value)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
>  	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
> @@ -256,18 +154,17 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
>  		mpc8xxx_spi->get_rx = cs->get_rx;
>  		mpc8xxx_spi->get_tx = cs->get_tx;
>  
> -		mpc8xxx_spi_change_mode(spi);
> +		fsl_spi_change_mode(spi);
>  
>  		if (pdata->cs_control)
>  			pdata->cs_control(spi, pol);
>  	}
>  }
>  
> -static int
> -mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
> -			   struct spi_device *spi,
> -			   struct mpc8xxx_spi *mpc8xxx_spi,
> -			   int bits_per_word)
> +static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
> +				struct spi_device *spi,
> +				struct mpc8xxx_spi *mpc8xxx_spi,
> +				int bits_per_word)
>  {
>  	cs->rx_shift = 0;
>  	cs->tx_shift = 0;
> @@ -307,10 +204,9 @@ mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
>  	return bits_per_word;
>  }
>  
> -static int
> -mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
> -			  struct spi_device *spi,
> -			  int bits_per_word)
> +static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
> +				struct spi_device *spi,
> +				int bits_per_word)
>  {
>  	/* QE uses Little Endian for words > 8
>  	 * so transform all words > 8 into 8 bits
> @@ -326,13 +222,13 @@ mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
>  	return bits_per_word;
>  }
>  
> -static
> -int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
> +static int fsl_spi_setup_transfer(struct spi_device *spi,
> +					struct spi_transfer *t)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi;
> -	int bits_per_word;
> +	int bits_per_word = 0;
>  	u8 pm;
> -	u32 hz;
> +	u32 hz = 0;
>  	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
>  
>  	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> @@ -340,9 +236,6 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
>  	if (t) {
>  		bits_per_word = t->bits_per_word;
>  		hz = t->speed_hz;
> -	} else {
> -		bits_per_word = 0;
> -		hz = 0;
>  	}
>  
>  	/* spi_transfer level calls that work per-word */
> @@ -388,23 +281,25 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
>  			  hz, mpc8xxx_spi->spibrg / 1024);
>  		if (pm > 16)
>  			pm = 16;
> -	} else
> +	} else {
>  		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
> +	}
>  	if (pm)
>  		pm--;
>  
>  	cs->hw_mode |= SPMODE_PM(pm);
>  
> -	mpc8xxx_spi_change_mode(spi);
> +	fsl_spi_change_mode(spi);
>  	return 0;
>  }
>  
> -static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
> +static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
>  {
>  	struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
>  	struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
>  	unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
>  	unsigned int xfer_ofs;
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
>  
>  	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
>  
> @@ -424,13 +319,14 @@ static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
>  				 BD_SC_LAST);
>  
>  	/* start transfer */
> -	mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
> +	mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
>  }
>  
> -static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
> +static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
>  				struct spi_transfer *t, bool is_dma_mapped)
>  {
>  	struct device *dev = mspi->dev;
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
>  
>  	if (is_dma_mapped) {
>  		mspi->map_tx_dma = 0;
> @@ -475,13 +371,13 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
>  	}
>  
>  	/* enable rx ints */
> -	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
> +	mpc8xxx_spi_write_reg(&reg_base->mask, SPIE_RXB);
>  
>  	mspi->xfer_in_progress = t;
>  	mspi->count = t->len;
>  
>  	/* start CPM transfers */
> -	mpc8xxx_spi_cpm_bufs_start(mspi);
> +	fsl_spi_cpm_bufs_start(mspi);
>  
>  	return 0;
>  
> @@ -491,7 +387,7 @@ err_rx_dma:
>  	return -ENOMEM;
>  }
>  
> -static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
> +static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
>  {
>  	struct device *dev = mspi->dev;
>  	struct spi_transfer *t = mspi->xfer_in_progress;
> @@ -503,31 +399,34 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
>  	mspi->xfer_in_progress = NULL;
>  }
>  
> -static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
> +static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
>  				struct spi_transfer *t, unsigned int len)
>  {
>  	u32 word;
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
>  
>  	mspi->count = len;
>  
>  	/* enable rx ints */
> -	mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
> +	mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
>  
>  	/* transmit word */
>  	word = mspi->get_tx(mspi);
> -	mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> +	mpc8xxx_spi_write_reg(&reg_base->transmit, word);
>  
>  	return 0;
>  }
>  
> -static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
> +static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
>  			    bool is_dma_mapped)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	struct fsl_spi_reg *reg_base;
>  	unsigned int len = t->len;
>  	u8 bits_per_word;
>  	int ret;
>  
> +	reg_base = mpc8xxx_spi->reg_base;
>  	bits_per_word = spi->bits_per_word;
>  	if (t->bits_per_word)
>  		bits_per_word = t->bits_per_word;
> @@ -551,24 +450,24 @@ static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
>  	INIT_COMPLETION(mpc8xxx_spi->done);
>  
>  	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> -		ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
> +		ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
>  	else
> -		ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
> +		ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
>  	if (ret)
>  		return ret;
>  
>  	wait_for_completion(&mpc8xxx_spi->done);
>  
>  	/* disable rx ints */
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
>  
>  	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
> -		mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
> +		fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
>  
>  	return mpc8xxx_spi->count;
>  }
>  
> -static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
> +static void fsl_spi_do_one_msg(struct spi_message *m)
>  {
>  	struct spi_device *spi = m->spi;
>  	struct spi_transfer *t;
> @@ -584,18 +483,18 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
>  			status = -EINVAL;
>  
>  			if (cs_change)
> -				status = mpc8xxx_spi_setup_transfer(spi, t);
> +				status = fsl_spi_setup_transfer(spi, t);
>  			if (status < 0)
>  				break;
>  		}
>  
>  		if (cs_change) {
> -			mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
> +			fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
>  			ndelay(nsecs);
>  		}
>  		cs_change = t->cs_change;
>  		if (t->len)
> -			status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
> +			status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
>  		if (status) {
>  			status = -EMSGSIZE;
>  			break;
> @@ -607,7 +506,7 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
>  
>  		if (cs_change) {
>  			ndelay(nsecs);
> -			mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +			fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
>  			ndelay(nsecs);
>  		}
>  	}
> @@ -617,35 +516,16 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
>  
>  	if (status || !cs_change) {
>  		ndelay(nsecs);
> -		mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
> +		fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
>  	}
>  
> -	mpc8xxx_spi_setup_transfer(spi, NULL);
> -}
> -
> -static void mpc8xxx_spi_work(struct work_struct *work)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
> -						       work);
> -
> -	spin_lock_irq(&mpc8xxx_spi->lock);
> -	while (!list_empty(&mpc8xxx_spi->queue)) {
> -		struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
> -						   struct spi_message, queue);
> -
> -		list_del_init(&m->queue);
> -		spin_unlock_irq(&mpc8xxx_spi->lock);
> -
> -		mpc8xxx_spi_do_one_msg(m);
> -
> -		spin_lock_irq(&mpc8xxx_spi->lock);
> -	}
> -	spin_unlock_irq(&mpc8xxx_spi->lock);
> +	fsl_spi_setup_transfer(spi, NULL);
>  }
>  
> -static int mpc8xxx_spi_setup(struct spi_device *spi)
> +static int fsl_spi_setup(struct spi_device *spi)
>  {
>  	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct fsl_spi_reg *reg_base;
>  	int retval;
>  	u32 hw_mode;
>  	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
> @@ -661,8 +541,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
>  	}
>  	mpc8xxx_spi = spi_master_get_devdata(spi->master);
>  
> +	reg_base = mpc8xxx_spi->reg_base;
> +
>  	hw_mode = cs->hw_mode; /* Save original settings */
> -	cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
> +	cs->hw_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
>  	/* mask out bits we are going to set */
>  	cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
>  			 | SPMODE_REV | SPMODE_LOOP);
> @@ -676,7 +558,7 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
>  	if (spi->mode & SPI_LOOP)
>  		cs->hw_mode |= SPMODE_LOOP;
>  
> -	retval = mpc8xxx_spi_setup_transfer(spi, NULL);
> +	retval = fsl_spi_setup_transfer(spi, NULL);
>  	if (retval < 0) {
>  		cs->hw_mode = hw_mode; /* Restore settings */
>  		return retval;
> @@ -684,9 +566,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
>  	return 0;
>  }
>  
> -static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
> +static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
>  {
>  	u16 len;
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
>  
>  	dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
>  		in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
> @@ -698,20 +581,22 @@ static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
>  	}
>  
>  	/* Clear the events */
> -	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +	mpc8xxx_spi_write_reg(&reg_base->event, events);
>  
>  	mspi->count -= len;
>  	if (mspi->count)
> -		mpc8xxx_spi_cpm_bufs_start(mspi);
> +		fsl_spi_cpm_bufs_start(mspi);
>  	else
>  		complete(&mspi->done);
>  }
>  
> -static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
> +static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
>  {
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
> +
>  	/* We need handle RX first */
>  	if (events & SPIE_NE) {
> -		u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
> +		u32 rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
>  
>  		if (mspi->rx)
>  			mspi->get_rx(rx_data, mspi);
> @@ -720,102 +605,80 @@ static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
>  	if ((events & SPIE_NF) == 0)
>  		/* spin until TX is done */
>  		while (((events =
> -			mpc8xxx_spi_read_reg(&mspi->base->event)) &
> +			mpc8xxx_spi_read_reg(&reg_base->event)) &
>  						SPIE_NF) == 0)
>  			cpu_relax();
>  
>  	/* Clear the events */
> -	mpc8xxx_spi_write_reg(&mspi->base->event, events);
> +	mpc8xxx_spi_write_reg(&reg_base->event, events);
>  
>  	mspi->count -= 1;
>  	if (mspi->count) {
>  		u32 word = mspi->get_tx(mspi);
>  
> -		mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
> +		mpc8xxx_spi_write_reg(&reg_base->transmit, word);
>  	} else {
>  		complete(&mspi->done);
>  	}
>  }
>  
> -static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
> +static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
>  {
>  	struct mpc8xxx_spi *mspi = context_data;
>  	irqreturn_t ret = IRQ_NONE;
>  	u32 events;
> +	struct fsl_spi_reg *reg_base = mspi->reg_base;
>  
>  	/* Get interrupt events(tx/rx) */
> -	events = mpc8xxx_spi_read_reg(&mspi->base->event);
> +	events = mpc8xxx_spi_read_reg(&reg_base->event);
>  	if (events)
>  		ret = IRQ_HANDLED;
>  
>  	dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
>  
>  	if (mspi->flags & SPI_CPM_MODE)
> -		mpc8xxx_spi_cpm_irq(mspi, events);
> +		fsl_spi_cpm_irq(mspi, events);
>  	else
> -		mpc8xxx_spi_cpu_irq(mspi, events);
> +		fsl_spi_cpu_irq(mspi, events);
>  
>  	return ret;
>  }
>  
> -static int mpc8xxx_spi_transfer(struct spi_device *spi,
> -				struct spi_message *m)
> +static void *fsl_spi_alloc_dummy_rx(void)
>  {
> -	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> -	unsigned long flags;
> +	mutex_lock(&fsl_dummy_rx_lock);
>  
> -	m->actual_length = 0;
> -	m->status = -EINPROGRESS;
> +	if (!fsl_dummy_rx)
> +		fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
> +	if (fsl_dummy_rx)
> +		fsl_dummy_rx_refcnt++;
>  
> -	spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
> -	list_add_tail(&m->queue, &mpc8xxx_spi->queue);
> -	queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
> -	spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
> +	mutex_unlock(&fsl_dummy_rx_lock);
>  
> -	return 0;
> +	return fsl_dummy_rx;
>  }
>  
> -
> -static void mpc8xxx_spi_cleanup(struct spi_device *spi)
> +static void fsl_spi_free_dummy_rx(void)
>  {
> -	kfree(spi->controller_state);
> -}
> +	mutex_lock(&fsl_dummy_rx_lock);
>  
> -static void *mpc8xxx_spi_alloc_dummy_rx(void)
> -{
> -	mutex_lock(&mpc8xxx_dummy_rx_lock);
> -
> -	if (!mpc8xxx_dummy_rx)
> -		mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
> -	if (mpc8xxx_dummy_rx)
> -		mpc8xxx_dummy_rx_refcnt++;
> -
> -	mutex_unlock(&mpc8xxx_dummy_rx_lock);
> -
> -	return mpc8xxx_dummy_rx;
> -}
> -
> -static void mpc8xxx_spi_free_dummy_rx(void)
> -{
> -	mutex_lock(&mpc8xxx_dummy_rx_lock);
> -
> -	switch (mpc8xxx_dummy_rx_refcnt) {
> +	switch (fsl_dummy_rx_refcnt) {
>  	case 0:
>  		WARN_ON(1);
>  		break;
>  	case 1:
> -		kfree(mpc8xxx_dummy_rx);
> -		mpc8xxx_dummy_rx = NULL;
> +		kfree(fsl_dummy_rx);
> +		fsl_dummy_rx = NULL;
>  		/* fall through */
>  	default:
> -		mpc8xxx_dummy_rx_refcnt--;
> +		fsl_dummy_rx_refcnt--;
>  		break;
>  	}
>  
> -	mutex_unlock(&mpc8xxx_dummy_rx_lock);
> +	mutex_unlock(&fsl_dummy_rx_lock);
>  }
>  
> -static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
> +static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
>  {
>  	struct device *dev = mspi->dev;
>  	struct device_node *np = dev->of_node;
> @@ -869,7 +732,7 @@ static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
>  	return pram_ofs;
>  }
>  
> -static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
> +static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
>  {
>  	struct device *dev = mspi->dev;
>  	struct device_node *np = dev->of_node;
> @@ -881,7 +744,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
>  	if (!(mspi->flags & SPI_CPM_MODE))
>  		return 0;
>  
> -	if (!mpc8xxx_spi_alloc_dummy_rx())
> +	if (!fsl_spi_alloc_dummy_rx())
>  		return -ENOMEM;
>  
>  	if (mspi->flags & SPI_QE) {
> @@ -902,7 +765,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
>  		}
>  	}
>  
> -	pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
> +	pram_ofs = fsl_spi_cpm_get_pram(mspi);
>  	if (IS_ERR_VALUE(pram_ofs)) {
>  		dev_err(dev, "can't allocate spi parameter ram\n");
>  		goto err_pram;
> @@ -922,7 +785,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
>  		goto err_dummy_tx;
>  	}
>  
> -	mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
> +	mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
>  					    DMA_FROM_DEVICE);
>  	if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
>  		dev_err(dev, "unable to map dummy rx buffer\n");
> @@ -960,11 +823,11 @@ err_dummy_tx:
>  err_bds:
>  	cpm_muram_free(pram_ofs);
>  err_pram:
> -	mpc8xxx_spi_free_dummy_rx();
> +	fsl_spi_free_dummy_rx();
>  	return -ENOMEM;
>  }
>  
> -static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
> +static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
>  {
>  	struct device *dev = mspi->dev;
>  
> @@ -972,30 +835,22 @@ static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
>  	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
>  	cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
>  	cpm_muram_free(cpm_muram_offset(mspi->pram));
> -	mpc8xxx_spi_free_dummy_rx();
> +	fsl_spi_free_dummy_rx();
>  }
>  
> -static const char *mpc8xxx_spi_strmode(unsigned int flags)
> +static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
>  {
> -	if (flags & SPI_QE_CPU_MODE) {
> -		return "QE CPU";
> -	} else if (flags & SPI_CPM_MODE) {
> -		if (flags & SPI_QE)
> -			return "QE";
> -		else if (flags & SPI_CPM2)
> -			return "CPM2";
> -		else
> -			return "CPM1";
> -	}
> -	return "CPU";
> +	iounmap(mspi->reg_base);
> +	fsl_spi_cpm_free(mspi);
>  }
>  
> -static struct spi_master * __devinit
> -mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
> +static struct spi_master * __devinit fsl_spi_probe(struct device *dev,
> +		struct resource *mem, unsigned int irq)
>  {
>  	struct fsl_spi_platform_data *pdata = dev->platform_data;
>  	struct spi_master *master;
>  	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct fsl_spi_reg *reg_base;
>  	u32 regval;
>  	int ret = 0;
>  
> @@ -1007,132 +862,77 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
>  
>  	dev_set_drvdata(dev, master);
>  
> -	/* the spi->mode bits understood by this driver: */
> -	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
> -			| SPI_LSB_FIRST | SPI_LOOP;
> +	ret = mpc8xxx_spi_probe(dev, mem, irq);
> +	if (ret)
> +		goto err_probe;
>  
> -	master->setup = mpc8xxx_spi_setup;
> -	master->transfer = mpc8xxx_spi_transfer;
> -	master->cleanup = mpc8xxx_spi_cleanup;
> -	master->dev.of_node = dev->of_node;
> +	master->setup = fsl_spi_setup;
>  
>  	mpc8xxx_spi = spi_master_get_devdata(master);
> -	mpc8xxx_spi->dev = dev;
> -	mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
> -	mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
> -	mpc8xxx_spi->flags = pdata->flags;
> -	mpc8xxx_spi->spibrg = pdata->sysclk;
> +	mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
> +	mpc8xxx_spi->spi_remove = fsl_spi_remove;
> +
>  
> -	ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
> +	ret = fsl_spi_cpm_init(mpc8xxx_spi);
>  	if (ret)
>  		goto err_cpm_init;
>  
> -	mpc8xxx_spi->rx_shift = 0;
> -	mpc8xxx_spi->tx_shift = 0;
>  	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
>  		mpc8xxx_spi->rx_shift = 16;
>  		mpc8xxx_spi->tx_shift = 24;
>  	}
>  
> -	init_completion(&mpc8xxx_spi->done);
> -
> -	mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
> -	if (mpc8xxx_spi->base == NULL) {
> +	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
> +	if (mpc8xxx_spi->reg_base == NULL) {
>  		ret = -ENOMEM;
>  		goto err_ioremap;
>  	}
>  
> -	mpc8xxx_spi->irq = irq;
> -
>  	/* Register for SPI Interrupt */
> -	ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
> -			  0, "mpc8xxx_spi", mpc8xxx_spi);
> +	ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
> +			  0, "fsl_spi", mpc8xxx_spi);
>  
>  	if (ret != 0)
> -		goto unmap_io;
> +		goto free_irq;
>  
> -	master->bus_num = pdata->bus_num;
> -	master->num_chipselect = pdata->max_chipselect;
> +	reg_base = mpc8xxx_spi->reg_base;
>  
>  	/* SPI controller initializations */
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
> +	mpc8xxx_spi_write_reg(&reg_base->mode, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->command, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
>  
>  	/* Enable SPI interface */
>  	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
>  	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
>  		regval |= SPMODE_OP;
>  
> -	mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
> -	spin_lock_init(&mpc8xxx_spi->lock);
> -	init_completion(&mpc8xxx_spi->done);
> -	INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
> -	INIT_LIST_HEAD(&mpc8xxx_spi->queue);
> -
> -	mpc8xxx_spi->workqueue = create_singlethread_workqueue(
> -		dev_name(master->dev.parent));
> -	if (mpc8xxx_spi->workqueue == NULL) {
> -		ret = -EBUSY;
> -		goto free_irq;
> -	}
> +	mpc8xxx_spi_write_reg(&reg_base->mode, regval);
>  
>  	ret = spi_register_master(master);
>  	if (ret < 0)
>  		goto unreg_master;
>  
> -	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
> +	dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
>  		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
>  
>  	return master;
>  
>  unreg_master:
> -	destroy_workqueue(mpc8xxx_spi->workqueue);
> -free_irq:
>  	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> -unmap_io:
> -	iounmap(mpc8xxx_spi->base);
> +free_irq:
> +	iounmap(mpc8xxx_spi->reg_base);
>  err_ioremap:
> -	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
> +	fsl_spi_cpm_free(mpc8xxx_spi);
>  err_cpm_init:
> +err_probe:
>  	spi_master_put(master);
>  err:
>  	return ERR_PTR(ret);
>  }
>  
> -static int __devexit mpc8xxx_spi_remove(struct device *dev)
> -{
> -	struct mpc8xxx_spi *mpc8xxx_spi;
> -	struct spi_master *master;
> -
> -	master = dev_get_drvdata(dev);
> -	mpc8xxx_spi = spi_master_get_devdata(master);
> -
> -	flush_workqueue(mpc8xxx_spi->workqueue);
> -	destroy_workqueue(mpc8xxx_spi->workqueue);
> -	spi_unregister_master(master);
> -
> -	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> -	iounmap(mpc8xxx_spi->base);
> -	mpc8xxx_spi_cpm_free(mpc8xxx_spi);
> -
> -	return 0;
> -}
> -
> -struct mpc8xxx_spi_probe_info {
> -	struct fsl_spi_platform_data pdata;
> -	int *gpios;
> -	bool *alow_flags;
> -};
> -
> -static struct mpc8xxx_spi_probe_info *
> -to_of_pinfo(struct fsl_spi_platform_data *pdata)
> -{
> -	return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
> -}
> -
> -static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
> +static void fsl_spi_cs_control(struct spi_device *spi, bool on)
>  {
>  	struct device *dev = spi->dev.parent;
>  	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
> @@ -1143,7 +943,7 @@ static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
>  	gpio_set_value(gpio, on ^ alow);
>  }
>  
> -static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
> +static int of_fsl_spi_get_chipselects(struct device *dev)
>  {
>  	struct device_node *np = dev->of_node;
>  	struct fsl_spi_platform_data *pdata = dev->platform_data;
> @@ -1204,7 +1004,7 @@ static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
>  	}
>  
>  	pdata->max_chipselect = ngpios;
> -	pdata->cs_control = mpc8xxx_spi_cs_control;
> +	pdata->cs_control = fsl_spi_cs_control;
>  
>  	return 0;
>  
> @@ -1223,7 +1023,7 @@ err_alloc_flags:
>  	return ret;
>  }
>  
> -static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
> +static int of_fsl_spi_free_chipselects(struct device *dev)
>  {
>  	struct fsl_spi_platform_data *pdata = dev->platform_data;
>  	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
> @@ -1242,50 +1042,21 @@ static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
>  	return 0;
>  }
>  
> -static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
> -					  const struct of_device_id *ofid)
> +static int __devinit of_fsl_spi_probe(struct platform_device *ofdev,
> +					const struct of_device_id *ofid)
>  {
>  	struct device *dev = &ofdev->dev;
>  	struct device_node *np = ofdev->dev.of_node;
> -	struct mpc8xxx_spi_probe_info *pinfo;
> -	struct fsl_spi_platform_data *pdata;
>  	struct spi_master *master;
>  	struct resource mem;
>  	struct resource irq;
> -	const void *prop;
>  	int ret = -ENOMEM;
>  
> -	pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
> -	if (!pinfo)
> -		return -ENOMEM;
> -
> -	pdata = &pinfo->pdata;
> -	dev->platform_data = pdata;
> -
> -	/* Allocate bus num dynamically. */
> -	pdata->bus_num = -1;
> -
> -	/* SPI controller is either clocked from QE or SoC clock. */
> -	pdata->sysclk = get_brgfreq();
> -	if (pdata->sysclk == -1) {
> -		pdata->sysclk = fsl_get_sys_freq();
> -		if (pdata->sysclk == -1) {
> -			ret = -ENODEV;
> -			goto err_clk;
> -		}
> -	}
> +	ret = of_mpc8xxx_spi_probe(ofdev, ofid);
> +	if (ret)
> +		return ret;
>  
> -	prop = of_get_property(np, "mode", NULL);
> -	if (prop && !strcmp(prop, "cpu-qe"))
> -		pdata->flags = SPI_QE_CPU_MODE;
> -	else if (prop && !strcmp(prop, "qe"))
> -		pdata->flags = SPI_CPM_MODE | SPI_QE;
> -	else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
> -		pdata->flags = SPI_CPM_MODE | SPI_CPM2;
> -	else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
> -		pdata->flags = SPI_CPM_MODE | SPI_CPM1;
> -
> -	ret = of_mpc8xxx_spi_get_chipselects(dev);
> +	ret = of_fsl_spi_get_chipselects(dev);
>  	if (ret)
>  		goto err;
>  
> @@ -1299,7 +1070,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
>  		goto err;
>  	}
>  
> -	master = mpc8xxx_spi_probe(dev, &mem, irq.start);
> +	master = fsl_spi_probe(dev, &mem, irq.start);
>  	if (IS_ERR(master)) {
>  		ret = PTR_ERR(master);
>  		goto err;
> @@ -1308,42 +1079,40 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
>  	return 0;
>  
>  err:
> -	of_mpc8xxx_spi_free_chipselects(dev);
> -err_clk:
> -	kfree(pinfo);
> +	of_fsl_spi_free_chipselects(dev);
>  	return ret;
>  }
>  
> -static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
> +static int __devexit of_fsl_spi_remove(struct platform_device *ofdev)
>  {
>  	int ret;
>  
>  	ret = mpc8xxx_spi_remove(&ofdev->dev);
>  	if (ret)
>  		return ret;
> -	of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
> +	of_fsl_spi_free_chipselects(&ofdev->dev);
>  	return 0;
>  }
>  
> -static const struct of_device_id of_mpc8xxx_spi_match[] = {
> +static const struct of_device_id of_fsl_spi_match[] = {
>  	{ .compatible = "fsl,spi" },
> -	{},
> +	{}
>  };
> -MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
> +MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
>  
> -static struct of_platform_driver of_mpc8xxx_spi_driver = {
> +static struct of_platform_driver of_fsl_spi_driver = {
>  	.driver = {
> -		.name = "mpc8xxx_spi",
> +		.name = "fsl_spi",
>  		.owner = THIS_MODULE,
> -		.of_match_table = of_mpc8xxx_spi_match,
> +		.of_match_table = of_fsl_spi_match,
>  	},
> -	.probe		= of_mpc8xxx_spi_probe,
> -	.remove		= __devexit_p(of_mpc8xxx_spi_remove),
> +	.probe		= of_fsl_spi_probe,
> +	.remove		= __devexit_p(of_fsl_spi_remove),
>  };
>  
>  #ifdef CONFIG_MPC832x_RDB
>  /*
> - * 				XXX XXX XXX
> + * XXX XXX XXX
>   * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
>   * only. The driver should go away soon, since newer MPC8323E-RDB's device
>   * tree can work with OpenFirmware driver. But for now we support old trees
> @@ -1366,7 +1135,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
>  	if (irq <= 0)
>  		return -EINVAL;
>  
> -	master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
> +	master = fsl_spi_probe(&pdev->dev, mem, irq);
>  	if (IS_ERR(master))
>  		return PTR_ERR(master);
>  	return 0;
> @@ -1405,21 +1174,20 @@ static void __init legacy_driver_register(void) {}
>  static void __exit legacy_driver_unregister(void) {}
>  #endif /* CONFIG_MPC832x_RDB */
>  
> -static int __init mpc8xxx_spi_init(void)
> +static int __init fsl_spi_init(void)
>  {
>  	legacy_driver_register();
> -	return of_register_platform_driver(&of_mpc8xxx_spi_driver);
> +	return of_register_platform_driver(&of_fsl_spi_driver);
>  }
> +module_init(fsl_spi_init);
>  
> -static void __exit mpc8xxx_spi_exit(void)
> +static void __exit fsl_spi_exit(void)
>  {
> -	of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
> +	of_unregister_platform_driver(&of_fsl_spi_driver);
>  	legacy_driver_unregister();
>  }
> -
> -module_init(mpc8xxx_spi_init);
> -module_exit(mpc8xxx_spi_exit);
> +module_exit(fsl_spi_exit);
>  
>  MODULE_AUTHOR("Kumar Gala");
> -MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
> +MODULE_DESCRIPTION("Simple Freescale SPI Driver");
>  MODULE_LICENSE("GPL");
> -- 
> 1.6.4
> 
> 

^ permalink raw reply

* Re: [PATCH v4 3/5] eSPI: add eSPI controller support
From: Grant Likely @ 2010-10-13  3:41 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general
In-Reply-To: <1286878714-13090-4-git-send-email-Mingkai.hu@freescale.com>

On Tue, Oct 12, 2010 at 06:18:32PM +0800, Mingkai Hu wrote:
> Add eSPI controller support based on the library code spi_fsl_lib.c.
> 
> The eSPI controller is newer controller 85xx/Pxxx devices supported.
> There're some differences comparing to the SPI controller:
> 
> 1. Has different register map and different bit definition
>    So leave the code operated the register to the driver code, not
>    the common code.
> 
> 2. Support 4 dedicated chip selects
>    The software can't controll the chip selects directly, The SPCOM[CS]
>    field is used to select which chip selects is used, and the
>    SPCOM[TRANLEN] field is set to tell the controller how long the CS
>    signal need to be asserted. So the driver doesn't need the chipselect
>    related function when transfering data, just set corresponding register
>    fields to controll the chipseclect.
> 
> 3. Different Transmit/Receive FIFO access register behavior
>    For SPI controller, the Tx/Rx FIFO access register can hold only
>    one character regardless of the character length, but for eSPI
>    controller, the register can hold 4 or 2 characters according to
>    the character lengths. Access the Tx/Rx FIFO access register of the
>    eSPI controller will shift out/in 4/2 characters one time. For SPI
>    subsystem, the command and data are put into different transfers, so
>    we need to combine all the transfers to one transfer in order to pass
>    the transfer to eSPI controller.
> 
> 4. The max transaction length limitation
>    The max transaction length one time is limitted by the SPCOM[TRANSLEN]
>    field which is 0xFFFF. When used mkfs.ext2 command to create ext2
>    filesystem on the flash, the read length will exceed the max value of
>    the SPCOM[TRANSLEN] field.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>

Applied, thanks.

g.

> ---
> v4:
>  - Updated to latest kernel base(Linux 2.6.36-rc7).
>  - Added support to the transaction that the length is grater than 0xFFFF.
>  - Made some changes according to Anton's comments.
> 
>  drivers/spi/Kconfig        |    9 +
>  drivers/spi/Makefile       |    1 +
>  drivers/spi/spi_fsl_espi.c |  748 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_fsl_lib.h  |    3 +
>  4 files changed, 761 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/spi_fsl_espi.c
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 79ad06f..f6888af 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -195,6 +195,15 @@ config SPI_FSL_SPI
>  	  MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
>  	  MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
>  
> +config SPI_FSL_ESPI
> +	tristate "Freescale eSPI controller"
> +	depends on FSL_SOC
> +	select SPI_FSL_LIB
> +	help
> +	  This enables using the Freescale eSPI controllers in master mode.
> +	  From MPC8536, 85xx platform uses the controller, and all P10xx,
> +	  P20xx, P30xx,P40xx, P50xx uses this controller.
> +
>  config SPI_OMAP_UWIRE
>  	tristate "OMAP1 MicroWire"
>  	depends on ARCH_OMAP1
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 7974c21..833d17e 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC)		+= mpc512x_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
>  obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
>  obj-$(CONFIG_SPI_FSL_LIB)		+= spi_fsl_lib.o
> +obj-$(CONFIG_SPI_FSL_ESPI)		+= spi_fsl_espi.o
>  obj-$(CONFIG_SPI_FSL_SPI)		+= spi_fsl_spi.o
>  obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
>  obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
> diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
> new file mode 100644
> index 0000000..e3b4f64
> --- /dev/null
> +++ b/drivers/spi/spi_fsl_espi.c
> @@ -0,0 +1,748 @@
> +/*
> + * Freescale eSPI controller driver.
> + *
> + * Copyright 2010 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.
> + */
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/spi/spi.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/mm.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_spi.h>
> +#include <linux/interrupt.h>
> +#include <linux/err.h>
> +#include <sysdev/fsl_soc.h>
> +
> +#include "spi_fsl_lib.h"
> +
> +/* eSPI Controller registers */
> +struct fsl_espi_reg {
> +	__be32 mode;		/* 0x000 - eSPI mode register */
> +	__be32 event;		/* 0x004 - eSPI event register */
> +	__be32 mask;		/* 0x008 - eSPI mask register */
> +	__be32 command;		/* 0x00c - eSPI command register */
> +	__be32 transmit;	/* 0x010 - eSPI transmit FIFO access register*/
> +	__be32 receive;		/* 0x014 - eSPI receive FIFO access register*/
> +	u8 res[8];		/* 0x018 - 0x01c reserved */
> +	__be32 csmode[4];	/* 0x020 - 0x02c eSPI cs mode register */
> +};
> +
> +struct fsl_espi_transfer {
> +	const void *tx_buf;
> +	void *rx_buf;
> +	unsigned len;
> +	unsigned n_tx;
> +	unsigned n_rx;
> +	unsigned actual_length;
> +	int status;
> +};
> +
> +/* eSPI Controller mode register definitions */
> +#define SPMODE_ENABLE		(1 << 31)
> +#define SPMODE_LOOP		(1 << 30)
> +#define SPMODE_TXTHR(x)		((x) << 8)
> +#define SPMODE_RXTHR(x)		((x) << 0)
> +
> +/* eSPI Controller CS mode register definitions */
> +#define CSMODE_CI_INACTIVEHIGH	(1 << 31)
> +#define CSMODE_CP_BEGIN_EDGECLK	(1 << 30)
> +#define CSMODE_REV		(1 << 29)
> +#define CSMODE_DIV16		(1 << 28)
> +#define CSMODE_PM(x)		((x) << 24)
> +#define CSMODE_POL_1		(1 << 20)
> +#define CSMODE_LEN(x)		((x) << 16)
> +#define CSMODE_BEF(x)		((x) << 12)
> +#define CSMODE_AFT(x)		((x) << 8)
> +#define CSMODE_CG(x)		((x) << 3)
> +
> +/* Default mode/csmode for eSPI controller */
> +#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
> +#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
> +		| CSMODE_AFT(0) | CSMODE_CG(1))
> +
> +/* SPIE register values */
> +#define	SPIE_NE		0x00000200	/* Not empty */
> +#define	SPIE_NF		0x00000100	/* Not full */
> +
> +/* SPIM register values */
> +#define	SPIM_NE		0x00000200	/* Not empty */
> +#define	SPIM_NF		0x00000100	/* Not full */
> +#define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
> +#define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)
> +
> +/* SPCOM register values */
> +#define SPCOM_CS(x)		((x) << 30)
> +#define SPCOM_TRANLEN(x)	((x) << 0)
> +#define	SPCOM_TRANLEN_MAX	0xFFFF	/* Max transaction length */
> +
> +static void fsl_espi_change_mode(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +	struct fsl_espi_reg *reg_base = mspi->reg_base;
> +	__be32 __iomem *mode = &reg_base->csmode[spi->chip_select];
> +	__be32 __iomem *espi_mode = &reg_base->mode;
> +	u32 tmp;
> +	unsigned long flags;
> +
> +	/* Turn off IRQs locally to minimize time that SPI is disabled. */
> +	local_irq_save(flags);
> +
> +	/* Turn off SPI unit prior changing mode */
> +	tmp = mpc8xxx_spi_read_reg(espi_mode);
> +	mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
> +	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
> +	mpc8xxx_spi_write_reg(espi_mode, tmp);
> +
> +	local_irq_restore(flags);
> +}
> +
> +static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
> +{
> +	u32 data;
> +	u16 data_h;
> +	u16 data_l;
> +	const u32 *tx = mpc8xxx_spi->tx;
> +
> +	if (!tx)
> +		return 0;
> +
> +	data = *tx++ << mpc8xxx_spi->tx_shift;
> +	data_l = data & 0xffff;
> +	data_h = (data >> 16) & 0xffff;
> +	swab16s(&data_l);
> +	swab16s(&data_h);
> +	data = data_h | data_l;
> +
> +	mpc8xxx_spi->tx = tx;
> +	return data;
> +}
> +
> +static int fsl_espi_setup_transfer(struct spi_device *spi,
> +					struct spi_transfer *t)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	int bits_per_word = 0;
> +	u8 pm;
> +	u32 hz = 0;
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +
> +	if (t) {
> +		bits_per_word = t->bits_per_word;
> +		hz = t->speed_hz;
> +	}
> +
> +	/* spi_transfer level calls that work per-word */
> +	if (!bits_per_word)
> +		bits_per_word = spi->bits_per_word;
> +
> +	/* Make sure its a bit width we support [4..16] */
> +	if ((bits_per_word < 4) || (bits_per_word > 16))
> +		return -EINVAL;
> +
> +	if (!hz)
> +		hz = spi->max_speed_hz;
> +
> +	cs->rx_shift = 0;
> +	cs->tx_shift = 0;
> +	cs->get_rx = mpc8xxx_spi_rx_buf_u32;
> +	cs->get_tx = mpc8xxx_spi_tx_buf_u32;
> +	if (bits_per_word <= 8) {
> +		cs->rx_shift = 8 - bits_per_word;
> +	} else if (bits_per_word <= 16) {
> +		cs->rx_shift = 16 - bits_per_word;
> +		if (spi->mode & SPI_LSB_FIRST)
> +			cs->get_tx = fsl_espi_tx_buf_lsb;
> +	} else {
> +		return -EINVAL;
> +	}
> +
> +	mpc8xxx_spi->rx_shift = cs->rx_shift;
> +	mpc8xxx_spi->tx_shift = cs->tx_shift;
> +	mpc8xxx_spi->get_rx = cs->get_rx;
> +	mpc8xxx_spi->get_tx = cs->get_tx;
> +
> +	bits_per_word = bits_per_word - 1;
> +
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF));
> +
> +	cs->hw_mode |= CSMODE_LEN(bits_per_word);
> +
> +	if ((mpc8xxx_spi->spibrg / hz) > 64) {
> +		cs->hw_mode |= CSMODE_DIV16;
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
> +
> +		WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
> +			  "Will use %d Hz instead.\n", dev_name(&spi->dev),
> +			  hz, mpc8xxx_spi->spibrg / 1024);
> +		if (pm > 16)
> +			pm = 16;
> +	} else {
> +		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
> +	}
> +	if (pm)
> +		pm--;
> +
> +	cs->hw_mode |= CSMODE_PM(pm);
> +
> +	fsl_espi_change_mode(spi);
> +	return 0;
> +}
> +
> +static int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t,
> +		unsigned int len)
> +{
> +	u32 word;
> +	struct fsl_espi_reg *reg_base = mspi->reg_base;
> +
> +	mspi->count = len;
> +
> +	/* enable rx ints */
> +	mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
> +
> +	/* transmit word */
> +	word = mspi->get_tx(mspi);
> +	mpc8xxx_spi_write_reg(&reg_base->transmit, word);
> +
> +	return 0;
> +}
> +
> +static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
> +	unsigned int len = t->len;
> +	u8 bits_per_word;
> +	int ret;
> +
> +	bits_per_word = spi->bits_per_word;
> +	if (t->bits_per_word)
> +		bits_per_word = t->bits_per_word;
> +
> +	mpc8xxx_spi->len = t->len;
> +	len = roundup(len, 4) / 4;
> +
> +	mpc8xxx_spi->tx = t->tx_buf;
> +	mpc8xxx_spi->rx = t->rx_buf;
> +
> +	INIT_COMPLETION(mpc8xxx_spi->done);
> +
> +	/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
> +	if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
> +		dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
> +				" beyond the SPCOM[TRANLEN] field\n", t->len);
> +		return -EINVAL;
> +	}
> +	mpc8xxx_spi_write_reg(&reg_base->command,
> +		(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
> +
> +	ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len);
> +	if (ret)
> +		return ret;
> +
> +	wait_for_completion(&mpc8xxx_spi->done);
> +
> +	/* disable rx ints */
> +	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
> +
> +	return mpc8xxx_spi->count;
> +}
> +
> +static void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd)
> +{
> +	if (cmd[1] && cmd[2] && cmd[3]) {
> +		cmd[1] = (u8)(addr >> 16);
> +		cmd[2] = (u8)(addr >> 8);
> +		cmd[3] = (u8)(addr >> 0);
> +	}
> +}
> +
> +static unsigned int fsl_espi_cmd2addr(u8 *cmd)
> +{
> +	if (cmd[1] && cmd[2] && cmd[3])
> +		return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0;
> +
> +	return 0;
> +}
> +
> +static void fsl_espi_do_trans(struct spi_message *m,
> +				struct fsl_espi_transfer *tr)
> +{
> +	struct spi_device *spi = m->spi;
> +	struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
> +	struct fsl_espi_transfer *espi_trans = tr;
> +	struct spi_message message;
> +	struct spi_transfer *t, *first, trans;
> +	int status = 0;
> +
> +	spi_message_init(&message);
> +	memset(&trans, 0, sizeof(trans));
> +
> +	first = list_first_entry(&m->transfers, struct spi_transfer,
> +			transfer_list);
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if ((first->bits_per_word != t->bits_per_word) ||
> +			(first->speed_hz != t->speed_hz)) {
> +			espi_trans->status = -EINVAL;
> +			dev_err(mspi->dev, "bits_per_word/speed_hz should be"
> +					" same for the same SPI transfer\n");
> +			return;
> +		}
> +
> +		trans.speed_hz = t->speed_hz;
> +		trans.bits_per_word = t->bits_per_word;
> +		trans.delay_usecs = max(first->delay_usecs, t->delay_usecs);
> +	}
> +
> +	trans.len = espi_trans->len;
> +	trans.tx_buf = espi_trans->tx_buf;
> +	trans.rx_buf = espi_trans->rx_buf;
> +	spi_message_add_tail(&trans, &message);
> +
> +	list_for_each_entry(t, &message.transfers, transfer_list) {
> +		if (t->bits_per_word || t->speed_hz) {
> +			status = -EINVAL;
> +
> +			status = fsl_espi_setup_transfer(spi, t);
> +			if (status < 0)
> +				break;
> +		}
> +
> +		if (t->len)
> +			status = fsl_espi_bufs(spi, t);
> +
> +		if (status) {
> +			status = -EMSGSIZE;
> +			break;
> +		}
> +
> +		if (t->delay_usecs)
> +			udelay(t->delay_usecs);
> +	}
> +
> +	espi_trans->status = status;
> +	fsl_espi_setup_transfer(spi, NULL);
> +}
> +
> +static void fsl_espi_cmd_trans(struct spi_message *m,
> +				struct fsl_espi_transfer *trans, u8 *rx_buff)
> +{
> +	struct spi_transfer *t;
> +	u8 *local_buf;
> +	int i = 0;
> +	struct fsl_espi_transfer *espi_trans = trans;
> +
> +	local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
> +	if (!local_buf) {
> +		espi_trans->status = -ENOMEM;
> +		return;
> +	}
> +
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if (t->tx_buf) {
> +			memcpy(local_buf + i, t->tx_buf, t->len);
> +			i += t->len;
> +		}
> +	}
> +
> +	espi_trans->tx_buf = local_buf;
> +	espi_trans->rx_buf = local_buf + espi_trans->n_tx;
> +	fsl_espi_do_trans(m, espi_trans);
> +
> +	espi_trans->actual_length = espi_trans->len;
> +	kfree(local_buf);
> +}
> +
> +static void fsl_espi_rw_trans(struct spi_message *m,
> +				struct fsl_espi_transfer *trans, u8 *rx_buff)
> +{
> +	struct fsl_espi_transfer *espi_trans = trans;
> +	unsigned int n_tx = espi_trans->n_tx;
> +	unsigned int n_rx = espi_trans->n_rx;
> +	struct spi_transfer *t;
> +	u8 *local_buf;
> +	u8 *rx_buf = rx_buff;
> +	unsigned int trans_len;
> +	unsigned int addr;
> +	int i, pos, loop;
> +
> +	local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
> +	if (!local_buf) {
> +		espi_trans->status = -ENOMEM;
> +		return;
> +	}
> +
> +	for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) {
> +		trans_len = n_rx - pos;
> +		if (trans_len > SPCOM_TRANLEN_MAX - n_tx)
> +			trans_len = SPCOM_TRANLEN_MAX - n_tx;
> +
> +		i = 0;
> +		list_for_each_entry(t, &m->transfers, transfer_list) {
> +			if (t->tx_buf) {
> +				memcpy(local_buf + i, t->tx_buf, t->len);
> +				i += t->len;
> +			}
> +		}
> +
> +		addr = fsl_espi_cmd2addr(local_buf);
> +		addr += pos;
> +		fsl_espi_addr2cmd(addr, local_buf);
> +
> +		espi_trans->n_tx = n_tx;
> +		espi_trans->n_rx = trans_len;
> +		espi_trans->len = trans_len + n_tx;
> +		espi_trans->tx_buf = local_buf;
> +		espi_trans->rx_buf = local_buf + n_tx;
> +		fsl_espi_do_trans(m, espi_trans);
> +
> +		memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len);
> +
> +		if (loop > 0)
> +			espi_trans->actual_length += espi_trans->len - n_tx;
> +		else
> +			espi_trans->actual_length += espi_trans->len;
> +	}
> +
> +	kfree(local_buf);
> +}
> +
> +static void fsl_espi_do_one_msg(struct spi_message *m)
> +{
> +	struct spi_transfer *t;
> +	u8 *rx_buf = NULL;
> +	unsigned int n_tx = 0;
> +	unsigned int n_rx = 0;
> +	struct fsl_espi_transfer espi_trans;
> +
> +	list_for_each_entry(t, &m->transfers, transfer_list) {
> +		if (t->tx_buf)
> +			n_tx += t->len;
> +		if (t->rx_buf) {
> +			n_rx += t->len;
> +			rx_buf = t->rx_buf;
> +		}
> +	}
> +
> +	espi_trans.n_tx = n_tx;
> +	espi_trans.n_rx = n_rx;
> +	espi_trans.len = n_tx + n_rx;
> +	espi_trans.actual_length = 0;
> +	espi_trans.status = 0;
> +
> +	if (!rx_buf)
> +		fsl_espi_cmd_trans(m, &espi_trans, NULL);
> +	else
> +		fsl_espi_rw_trans(m, &espi_trans, rx_buf);
> +
> +	m->actual_length = espi_trans.actual_length;
> +	m->status = espi_trans.status;
> +	m->complete(m->context);
> +}
> +
> +static int fsl_espi_setup(struct spi_device *spi)
> +{
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct fsl_espi_reg *reg_base;
> +	int retval;
> +	u32 hw_mode;
> +	u32 loop_mode;
> +	struct spi_mpc8xxx_cs *cs = spi->controller_state;
> +
> +	if (!spi->max_speed_hz)
> +		return -EINVAL;
> +
> +	if (!cs) {
> +		cs = kzalloc(sizeof *cs, GFP_KERNEL);
> +		if (!cs)
> +			return -ENOMEM;
> +		spi->controller_state = cs;
> +	}
> +
> +	mpc8xxx_spi = spi_master_get_devdata(spi->master);
> +	reg_base = mpc8xxx_spi->reg_base;
> +
> +	hw_mode = cs->hw_mode; /* Save orginal settings */
> +	cs->hw_mode = mpc8xxx_spi_read_reg(
> +			&reg_base->csmode[spi->chip_select]);
> +	/* mask out bits we are going to set */
> +	cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH
> +			 | CSMODE_REV);
> +
> +	if (spi->mode & SPI_CPHA)
> +		cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK;
> +	if (spi->mode & SPI_CPOL)
> +		cs->hw_mode |= CSMODE_CI_INACTIVEHIGH;
> +	if (!(spi->mode & SPI_LSB_FIRST))
> +		cs->hw_mode |= CSMODE_REV;
> +
> +	/* Handle the loop mode */
> +	loop_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
> +	loop_mode &= ~SPMODE_LOOP;
> +	if (spi->mode & SPI_LOOP)
> +		loop_mode |= SPMODE_LOOP;
> +	mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode);
> +
> +	retval = fsl_espi_setup_transfer(spi, NULL);
> +	if (retval < 0) {
> +		cs->hw_mode = hw_mode; /* Restore settings */
> +		return retval;
> +	}
> +	return 0;
> +}
> +
> +void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
> +{
> +	struct fsl_espi_reg *reg_base = mspi->reg_base;
> +
> +	/* We need handle RX first */
> +	if (events & SPIE_NE) {
> +		u32 rx_data;
> +
> +		/* Spin until RX is done */
> +		while (SPIE_RXCNT(events) < min(4, mspi->len)) {
> +			cpu_relax();
> +			events = mpc8xxx_spi_read_reg(&reg_base->event);
> +		}
> +		mspi->len -= 4;
> +
> +		rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
> +
> +		if (mspi->rx)
> +			mspi->get_rx(rx_data, mspi);
> +	}
> +
> +	if (!(events & SPIE_NF)) {
> +		int ret;
> +
> +		/* spin until TX is done */
> +		ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg(
> +				&reg_base->event)) & SPIE_NF) == 0, 1000, 0);
> +		if (!ret) {
> +			dev_err(mspi->dev, "tired waiting for SPIE_NF\n");
> +			return;
> +		}
> +	}
> +
> +	/* Clear the events */
> +	mpc8xxx_spi_write_reg(&reg_base->event, events);
> +
> +	mspi->count -= 1;
> +	if (mspi->count) {
> +		u32 word = mspi->get_tx(mspi);
> +
> +		mpc8xxx_spi_write_reg(&reg_base->transmit, word);
> +	} else {
> +		complete(&mspi->done);
> +	}
> +}
> +
> +static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
> +{
> +	struct mpc8xxx_spi *mspi = context_data;
> +	struct fsl_espi_reg *reg_base = mspi->reg_base;
> +	irqreturn_t ret = IRQ_NONE;
> +	u32 events;
> +
> +	/* Get interrupt events(tx/rx) */
> +	events = mpc8xxx_spi_read_reg(&reg_base->event);
> +	if (events)
> +		ret = IRQ_HANDLED;
> +
> +	dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events);
> +
> +	fsl_espi_cpu_irq(mspi, events);
> +
> +	return ret;
> +}
> +
> +static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
> +{
> +	iounmap(mspi->reg_base);
> +}
> +
> +static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
> +		struct resource *mem, unsigned int irq)
> +{
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	struct spi_master *master;
> +	struct mpc8xxx_spi *mpc8xxx_spi;
> +	struct fsl_espi_reg *reg_base;
> +	u32 regval;
> +	int i, ret = 0;
> +
> +	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
> +	if (!master) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	dev_set_drvdata(dev, master);
> +
> +	ret = mpc8xxx_spi_probe(dev, mem, irq);
> +	if (ret)
> +		goto err_probe;
> +
> +	master->setup = fsl_espi_setup;
> +
> +	mpc8xxx_spi = spi_master_get_devdata(master);
> +	mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
> +	mpc8xxx_spi->spi_remove = fsl_espi_remove;
> +
> +	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
> +	if (!mpc8xxx_spi->reg_base) {
> +		ret = -ENOMEM;
> +		goto err_probe;
> +	}
> +
> +	reg_base = mpc8xxx_spi->reg_base;
> +
> +	/* Register for SPI Interrupt */
> +	ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq,
> +			  0, "fsl_espi", mpc8xxx_spi);
> +	if (ret)
> +		goto free_irq;
> +
> +	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
> +		mpc8xxx_spi->rx_shift = 16;
> +		mpc8xxx_spi->tx_shift = 24;
> +	}
> +
> +	/* SPI controller initializations */
> +	mpc8xxx_spi_write_reg(&reg_base->mode, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->command, 0);
> +	mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
> +
> +	/* Init eSPI CS mode register */
> +	for (i = 0; i < pdata->max_chipselect; i++)
> +		mpc8xxx_spi_write_reg(&reg_base->csmode[i], CSMODE_INIT_VAL);
> +
> +	/* Enable SPI interface */
> +	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
> +
> +	mpc8xxx_spi_write_reg(&reg_base->mode, regval);
> +
> +	ret = spi_register_master(master);
> +	if (ret < 0)
> +		goto unreg_master;
> +
> +	dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq);
> +
> +	return master;
> +
> +unreg_master:
> +	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
> +free_irq:
> +	iounmap(mpc8xxx_spi->reg_base);
> +err_probe:
> +	spi_master_put(master);
> +err:
> +	return ERR_PTR(ret);
> +}
> +
> +static int of_fsl_espi_get_chipselects(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct fsl_spi_platform_data *pdata = dev->platform_data;
> +	const u32 *prop;
> +	int len;
> +
> +	prop = of_get_property(np, "fsl,espi-num-chipselects", &len);
> +	if (!prop || len < sizeof(*prop)) {
> +		dev_err(dev, "No 'fsl,espi-num-chipselects' property\n");
> +		return -EINVAL;
> +	}
> +
> +	pdata->max_chipselect = *prop;
> +	pdata->cs_control = NULL;
> +
> +	return 0;
> +}
> +
> +static int __devinit of_fsl_espi_probe(struct platform_device *ofdev,
> +					const struct of_device_id *ofid)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct device_node *np = ofdev->dev.of_node;
> +	struct spi_master *master;
> +	struct resource mem;
> +	struct resource irq;
> +	int ret = -ENOMEM;
> +
> +	ret = of_mpc8xxx_spi_probe(ofdev, ofid);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_fsl_espi_get_chipselects(dev);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_address_to_resource(np, 0, &mem);
> +	if (ret)
> +		goto err;
> +
> +	ret = of_irq_to_resource(np, 0, &irq);
> +	if (!ret) {
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	master = fsl_espi_probe(dev, &mem, irq.start);
> +	if (IS_ERR(master)) {
> +		ret = PTR_ERR(master);
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}
> +
> +static int __devexit of_fsl_espi_remove(struct platform_device *dev)
> +{
> +	return mpc8xxx_spi_remove(&dev->dev);
> +}
> +
> +static const struct of_device_id of_fsl_espi_match[] = {
> +	{ .compatible = "fsl,mpc8536-espi" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
> +
> +static struct of_platform_driver fsl_espi_driver = {
> +	.driver = {
> +		.name = "fsl_espi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = of_fsl_espi_match,
> +	},
> +	.probe		= of_fsl_espi_probe,
> +	.remove		= __devexit_p(of_fsl_espi_remove),
> +};
> +
> +static int __init fsl_espi_init(void)
> +{
> +	return of_register_platform_driver(&fsl_espi_driver);
> +}
> +module_init(fsl_espi_init);
> +
> +static void __exit fsl_espi_exit(void)
> +{
> +	of_unregister_platform_driver(&fsl_espi_driver);
> +}
> +module_exit(fsl_espi_exit);
> +
> +MODULE_AUTHOR("Mingkai Hu");
> +MODULE_DESCRIPTION("Enhanced Freescale SPI Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
> index 6ae8949..15aa6c2 100644
> --- a/drivers/spi/spi_fsl_lib.h
> +++ b/drivers/spi/spi_fsl_lib.h
> @@ -26,6 +26,9 @@ struct mpc8xxx_spi {
>  	/* rx & tx bufs from the spi_transfer */
>  	const void *tx;
>  	void *rx;
> +#ifdef CONFIG_SPI_FSL_ESPI
> +	int len;
> +#endif
>  
>  	int subblock;
>  	struct spi_pram __iomem *pram;
> -- 
> 1.6.4
> 
> 

^ permalink raw reply

* Re: [PATCH v4 4/5] powerpc/of: add eSPI controller dts bindings and DTS modification
From: Grant Likely @ 2010-10-13  3:41 UTC (permalink / raw)
  To: Mingkai Hu
  Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general
In-Reply-To: <1286878714-13090-5-git-send-email-Mingkai.hu@freescale.com>

On Tue, Oct 12, 2010 at 06:18:33PM +0800, Mingkai Hu wrote:
> Also modifiy the document of cell-index in SPI controller. Add the
> SPI flash(s25fl128p01) support on p4080ds and mpc8536ds board.
> 
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>

Applied, thanks.

g.

> ---
> v4:
>  - Updated to latest kernel base(Linux 2.6.36-rc7).
> 
>  Documentation/powerpc/dts-bindings/fsl/spi.txt |   24 ++++++++++-
>  arch/powerpc/boot/dts/mpc8536ds.dts            |   52 ++++++++++++++++++++++++
>  arch/powerpc/boot/dts/p4080ds.dts              |   11 ++---
>  3 files changed, 79 insertions(+), 8 deletions(-)
> 
> diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
> index 80510c0..777abd7 100644
> --- a/Documentation/powerpc/dts-bindings/fsl/spi.txt
> +++ b/Documentation/powerpc/dts-bindings/fsl/spi.txt
> @@ -1,7 +1,9 @@
>  * SPI (Serial Peripheral Interface)
>  
>  Required properties:
> -- cell-index : SPI controller index.
> +- cell-index : QE SPI subblock index.
> +		0: QE subblock SPI1
> +		1: QE subblock SPI2
>  - compatible : should be "fsl,spi".
>  - mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
>  - reg : Offset and length of the register set for the device
> @@ -29,3 +31,23 @@ Example:
>  		gpios = <&gpio 18 1	// device reg=<0>
>  			 &gpio 19 1>;	// device reg=<1>
>  	};
> +
> +
> +* eSPI (Enhanced Serial Peripheral Interface)
> +
> +Required properties:
> +- compatible : should be "fsl,mpc8536-espi".
> +- reg : Offset and length of the register set for the device.
> +- interrupts : should contain eSPI interrupt, the device has one interrupt.
> +- fsl,espi-num-chipselects : the number of the chipselect signals.
> +
> +Example:
> +	spi@110000 {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		compatible = "fsl,mpc8536-espi";
> +		reg = <0x110000 0x1000>;
> +		interrupts = <53 0x2>;
> +		interrupt-parent = <&mpic>;
> +		fsl,espi-num-chipselects = <4>;
> +	};
> diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
> index 815cebb..a75c10e 100644
> --- a/arch/powerpc/boot/dts/mpc8536ds.dts
> +++ b/arch/powerpc/boot/dts/mpc8536ds.dts
> @@ -108,6 +108,58 @@
>  			};
>  		};
>  
> +		spi@7000 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			compatible = "fsl,mpc8536-espi";
> +			reg = <0x7000 0x1000>;
> +			interrupts = <59 0x2>;
> +			interrupt-parent = <&mpic>;
> +			fsl,espi-num-chipselects = <4>;
> +
> +			flash@0 {
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				compatible = "spansion,s25sl12801";
> +				reg = <0>;
> +				spi-max-frequency = <40000000>;
> +				partition@u-boot {
> +					label = "u-boot";
> +					reg = <0x00000000 0x00100000>;
> +					read-only;
> +				};
> +				partition@kernel {
> +					label = "kernel";
> +					reg = <0x00100000 0x00500000>;
> +					read-only;
> +				};
> +				partition@dtb {
> +					label = "dtb";
> +					reg = <0x00600000 0x00100000>;
> +					read-only;
> +				};
> +				partition@fs {
> +					label = "file system";
> +					reg = <0x00700000 0x00900000>;
> +				};
> +			};
> +			flash@1 {
> +				compatible = "spansion,s25sl12801";
> +				reg = <1>;
> +				spi-max-frequency = <40000000>;
> +			};
> +			flash@2 {
> +				compatible = "spansion,s25sl12801";
> +				reg = <2>;
> +				spi-max-frequency = <40000000>;
> +			};
> +			flash@3 {
> +				compatible = "spansion,s25sl12801";
> +				reg = <3>;
> +				spi-max-frequency = <40000000>;
> +			};
> +		};
> +
>  		dma@21300 {
>  			#address-cells = <1>;
>  			#size-cells = <1>;
> diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
> index 2f0de24..5b7fc29 100644
> --- a/arch/powerpc/boot/dts/p4080ds.dts
> +++ b/arch/powerpc/boot/dts/p4080ds.dts
> @@ -236,22 +236,19 @@
>  		};
>  
>  		spi@110000 {
> -			cell-index = <0>;
>  			#address-cells = <1>;
>  			#size-cells = <0>;
> -			compatible = "fsl,espi";
> +			compatible = "fsl,p4080-espi", "fsl,mpc8536-espi";
>  			reg = <0x110000 0x1000>;
>  			interrupts = <53 0x2>;
>  			interrupt-parent = <&mpic>;
> -			espi,num-ss-bits = <4>;
> -			mode = "cpu";
> +			fsl,espi-num-chipselects = <4>;
>  
> -			fsl_m25p80@0 {
> +			flash@0 {
>  				#address-cells = <1>;
>  				#size-cells = <1>;
> -				compatible = "fsl,espi-flash";
> +				compatible = "spansion,s25sl12801";
>  				reg = <0>;
> -				linux,modalias = "fsl_m25p80";
>  				spi-max-frequency = <40000000>; /* input clock */
>  				partition@u-boot {
>  					label = "u-boot";
> -- 
> 1.6.4
> 
> 

^ permalink raw reply

* Re: [PATCH v4 5/5] mtd: m25p80: add support to parse the partitions by OF node
From: Grant Likely @ 2010-10-13  3:44 UTC (permalink / raw)
  To: Mingkai Hu, David Woodhouse
  Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general
In-Reply-To: <1286878714-13090-6-git-send-email-Mingkai.hu@freescale.com>

On Tue, Oct 12, 2010 at 06:18:34PM +0800, Mingkai Hu wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>

dwmw2: what are your thoughts on this one?

g.



> ---
> v4:
>  - Updated to latest kernel base(Linux 2.6.36-rc7).
>  - Made changes according to Grant's comments.
> 
>  drivers/mtd/devices/m25p80.c |    5 +++++
>  1 files changed, 5 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index 6f512b5..9d20738 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -924,6 +924,11 @@ static int __devinit m25p_probe(struct spi_device *spi)
>  			nr_parts = data->nr_parts;
>  		}
>  
> +		if (nr_parts <= 0 && spi->dev.of_node) {
> +			nr_parts = of_mtd_parse_partitions(&spi->dev,
> +					spi->dev.of_node, &parts);
> +		}
> +
>  		if (nr_parts > 0) {
>  			for (i = 0; i < nr_parts; i++) {
>  				DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
> -- 
> 1.6.4
> 
> 

^ permalink raw reply

* Re: [PATCH 09/15] ppc/vio: use dma ops helpers
From: Benjamin Herrenschmidt @ 2010-10-13  4:56 UTC (permalink / raw)
  To: Nishanth Aravamudan
  Cc: Brian King, linuxppc-dev, Paul Mackerras, Milton Miller
In-Reply-To: <AANLkTim2Sie0Hop7Akn2CsSgEMPOdq5kDRcfcnAFtghS@mail.gmail.com>

On Wed, 2010-09-15 at 12:33 -0600, Grant Likely wrote:
> On Wed, Sep 15, 2010 at 12:05 PM, Nishanth Aravamudan <nacc@us.ibm.com> wrote:
> > Use the set_dma_ops helper. Instead of modifying vio_dma_mapping_ops,
> > just create a trivial wrapper for dma_supported.
> >
> > Signed-off-by: Milton Miller <miltonm@bga.com>
> > Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
> 
> Looks right to me.

I never saw 8/15 btw ... I'm applying up to 7, please resend the rest.

Cheers,
Ben.

> > ---
> >  arch/powerpc/kernel/vio.c |   11 ++++++++---
> >  1 files changed, 8 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
> > index d692989..3c3083f 100644
> > --- a/arch/powerpc/kernel/vio.c
> > +++ b/arch/powerpc/kernel/vio.c
> > @@ -602,6 +602,11 @@ static void vio_dma_iommu_unmap_sg(struct device *dev,
> >        vio_cmo_dealloc(viodev, alloc_size);
> >  }
> >
> > +static int vio_dma_iommu_dma_supported(struct device *dev, u64 mask)
> > +{
> > +        return dma_iommu_ops.dma_supported(dev, mask);
> > +}
> > +
> >  struct dma_map_ops vio_dma_mapping_ops = {
> >        .alloc_coherent = vio_dma_iommu_alloc_coherent,
> >        .free_coherent  = vio_dma_iommu_free_coherent,
> > @@ -609,6 +614,7 @@ struct dma_map_ops vio_dma_mapping_ops = {
> >        .unmap_sg       = vio_dma_iommu_unmap_sg,
> >        .map_page       = vio_dma_iommu_map_page,
> >        .unmap_page     = vio_dma_iommu_unmap_page,
> > +       .dma_supported  = vio_dma_iommu_dma_supported,
> >
> >  };
> >
> > @@ -860,8 +866,7 @@ static void vio_cmo_bus_remove(struct vio_dev *viodev)
> >
> >  static void vio_cmo_set_dma_ops(struct vio_dev *viodev)
> >  {
> > -       vio_dma_mapping_ops.dma_supported = dma_iommu_ops.dma_supported;
> > -       viodev->dev.archdata.dma_ops = &vio_dma_mapping_ops;
> > +       set_dma_ops(&viodev->dev, &vio_dma_mapping_ops);
> >  }
> >
> >  /**
> > @@ -1246,7 +1251,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
> >        if (firmware_has_feature(FW_FEATURE_CMO))
> >                vio_cmo_set_dma_ops(viodev);
> >        else
> > -               viodev->dev.archdata.dma_ops = &dma_iommu_ops;
> > +               set_dma_ops(&viodev->dev, &dma_iommu_ops);
> >        set_iommu_table_base(&viodev->dev, vio_build_iommu_table(viodev));
> >        set_dev_node(&viodev->dev, of_node_to_nid(of_node));
> >
> > --
> > 1.7.0.4
> >
> >
> 
> 
> 

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2010-10-13  5:18 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <Pine.LNX.4.64.1010081102090.19518@localhost.localdomain>

On Fri, 2010-10-08 at 11:04 -0500, Kumar Gala wrote:
> Ben,
> 
> This isn't critical, but it does fix having the ppc64e_defconfig
> build cleanly.

Doesn't matter, I'm putting it in -next. When is your -next branch btw ?
It's overdue by 3 or 4 rc's already :-)

Cheers,
Ben.

> - k
> 
> The following changes since commit 6b0cd00bc396daf5c2dcf17a8d82055335341f46:
> 
>   Merge branch 'hwpoison-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6 (2010-10-07 13:59:32 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git merge
> 
> Kumar Gala (1):
>       powerpc/ppc64e: Fix link problem when building ppc64e_defconfig
> 
>  arch/powerpc/platforms/85xx/smp.c |    7 +++++++
>  1 files changed, 7 insertions(+), 0 deletions(-)

^ permalink raw reply

* RE: ppc405 + MCP23S17
From: WANG YiFei @ 2010-10-13  6:23 UTC (permalink / raw)
  To: 'tiejun.chen'; +Cc: linuxppc-dev
In-Reply-To: <4CB522D1.5090802@windriver.com>

Hi TieJun,

Thanks a lot for your reply.
So far, I can get ppc405 spi to initialize, however
failed at MCP23S17's probe() routine, I checked the
code, it's due to un-initialized platform data. Here
is my part of dts:

	spi@ef600600 {
		device_type =3D "spi";
		compatible =3D "ibm,ppc4xx-spi", "ibm,spi";
		reg =3D <0xef600600 0x7>;
		interrupt-parent =3D <0x2>;
		interrupts =3D <0x8 0x4>;
		#address-cells =3D <0x1>;
		#size-cells =3D <0x0>;
		gpios =3D <0>;    	/* cs */
	=09
		spi_gpio@0 {
			compatible =3D "mcp,mcp23s08";
			spi-max-frequency =3D <1000000>;
			reg =3D <0>;
		};
	};

I don't know how to provide platform data from dts although
I understand the concept from code. Do I only need to modify
dts OR I need to write some code to supply platform data? Do
you have any URL or sample code to show passing of platform
data?

Anyway, thanks a lot for guiding me.
YiFei

-----Original Message-----
From: tiejun.chen [mailto:tiejun.chen@windriver.com]=20
Sent: Wednesday, October 13, 2010 11:09 AM
To: WANG YiFei
Cc: linuxppc-dev@ozlabs.org
Subject: Re: ppc405 + MCP23S17

WANG YiFei wrote:
> Hi,
>=20
> =20
>=20
> I'm a newbie for linux device driver development.
>=20
> We have a custom ppc405 board which has MCP23S17
>=20
> (16-Bit I/O Expander with SPI Interface) on it.
>=20
> I noticed that current kernel has MCP23S08 driver
>=20
> support, I'd like to know:
>=20
> 1. if passing platform data to MCP23S08 driver, can it make
>=20
>    MCP23S17 work?
>=20

These chips should be same vendor product so I think 16-bit mcp23s17 may =
be
compatible to 8-bit modes. But you have to check the data sheet to =
confirm this
and track how to configure that as 8-bit mode. After that it's possible =
to run
mcp23s17 with mcp23s08.c.

> 2. Generally, I'd like to know how to pass platform data to
>=20
>    a particular device driver. In my mind, platform data should
>=20
>    not be in driver code, right? However, I don't know where is

Firstly you should define this on your dts. Then parse that to register
corresponding of_platform_device or platform_device when you setup your =
target
on <your target>.c.

When spi_register_driver prober successfully, you can get the =
platform_data from
associated spi device.

>=20
>    the suitable place to pass platform data to driver.
>=20
> 3. How to describe this in dts file?
>=20

You can get more from the file, =
Documentation/powerpc/dts-bindings/spi-bus.txt.
Or refer to those existed spi nodes on other platform dts.

Tiejun

> =20
>=20
> Thanks in advance,
>=20
> YiFei
>=20
>=20
>=20
>=20
> =
------------------------------------------------------------------------
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* mpc8548 dtb issue
From: raj kamal @ 2010-10-13  6:28 UTC (permalink / raw)
  To: linuxppc-dev

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

Hi,

I'm getting a problem while trying to bring mpc8548cds board up.

BSP used:-MPC8548CDS_20071214-ltib.iso
Bootloader used:- CFE

When i try to boot the kernel image, throws following and gets struck.
" OF-device-tree at 0xff000000"

Why this is happening?


Thanks & Regards
Raj

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

^ permalink raw reply

* Re: ppc405 + MCP23S17
From: tiejun.chen @ 2010-10-13  7:49 UTC (permalink / raw)
  To: WANG YiFei; +Cc: linuxppc-dev
In-Reply-To: <BAY158-ds2BEE228C7E27E7CE0C28BF5550@phx.gbl>

WANG YiFei wrote:
> Hi TieJun,
> 
> Thanks a lot for your reply.
> So far, I can get ppc405 spi to initialize, however
> failed at MCP23S17's probe() routine, I checked the
> code, it's due to un-initialized platform data. Here
> is my part of dts:
> 
> 	spi@ef600600 {
> 		device_type = "spi";
> 		compatible = "ibm,ppc4xx-spi", "ibm,spi";
> 		reg = <0xef600600 0x7>;
> 		interrupt-parent = <0x2>;
> 		interrupts = <0x8 0x4>;
> 		#address-cells = <0x1>;
> 		#size-cells = <0x0>;
> 		gpios = <0>;    	/* cs */
> 		
> 		spi_gpio@0 {
> 			compatible = "mcp,mcp23s08";
> 			spi-max-frequency = <1000000>;
> 			reg = <0>;
> 		};
> 	};
> 
> I don't know how to provide platform data from dts although
> I understand the concept from code. Do I only need to modify
> dts OR I need to write some code to supply platform data? Do
> you have any URL or sample code to show passing of platform
> data?

Often you SPI bus driver should call spi_register_master() to register your SPI
master controller. Then please go to the following path:
======
spi_register_master()
	|
	+ scan_boardinfo()
		|
		+ spi_new_device()
			^
			Here refer to the function,
------
struct spi_device *spi_new_device(struct spi_master *master,
                                  struct spi_board_info *chip)
{
	struct spi_device       *proxy;
	......
	proxy->dev.platform_data = (void *) chip->platform_data;
	......
	status = spi_add_device(proxy);
	......

And as I previously comment 'spi->dev.platform_data' would be passed to your
platform_data resided in your probe hook within your spi device driver.

So firstly you should register call spi_register_board_info() to register one
given spi_board_info by parsing your device nodes from your dts.

I think you can refer to the file, arch/powerpc/platforms/83xx/mpc832x_rdb.c.

> 
> Anyway, thanks a lot for guiding me.

You're welcome :)

Tiejun

> YiFei
> 
> -----Original Message-----
> From: tiejun.chen [mailto:tiejun.chen@windriver.com] 
> Sent: Wednesday, October 13, 2010 11:09 AM
> To: WANG YiFei
> Cc: linuxppc-dev@ozlabs.org
> Subject: Re: ppc405 + MCP23S17
> 
> WANG YiFei wrote:
>> Hi,
>>
>>  
>>
>> I'm a newbie for linux device driver development.
>>
>> We have a custom ppc405 board which has MCP23S17
>>
>> (16-Bit I/O Expander with SPI Interface) on it.
>>
>> I noticed that current kernel has MCP23S08 driver
>>
>> support, I'd like to know:
>>
>> 1. if passing platform data to MCP23S08 driver, can it make
>>
>>    MCP23S17 work?
>>
> 
> These chips should be same vendor product so I think 16-bit mcp23s17 may be
> compatible to 8-bit modes. But you have to check the data sheet to confirm this
> and track how to configure that as 8-bit mode. After that it's possible to run
> mcp23s17 with mcp23s08.c.
> 
>> 2. Generally, I'd like to know how to pass platform data to
>>
>>    a particular device driver. In my mind, platform data should
>>
>>    not be in driver code, right? However, I don't know where is
> 
> Firstly you should define this on your dts. Then parse that to register
> corresponding of_platform_device or platform_device when you setup your target
> on <your target>.c.
> 
> When spi_register_driver prober successfully, you can get the platform_data from
> associated spi device.
> 
>>    the suitable place to pass platform data to driver.
>>
>> 3. How to describe this in dts file?
>>
> 
> You can get more from the file, Documentation/powerpc/dts-bindings/spi-bus.txt.
> Or refer to those existed spi nodes on other platform dts.
> 
> Tiejun
> 
>>  
>>
>> Thanks in advance,
>>
>> YiFei
>>
>>
>>
>>

^ permalink raw reply

* Re: Serial RapidIO Maintaintance read causes lock up
From: Bastiaan Nijkamp @ 2010-10-13  8:30 UTC (permalink / raw)
  To: John Traill, Bounine, Alexandre; +Cc: linuxppc-dev
In-Reply-To: <AANLkTimKbibzzNc3+DSJHcLC4gA0H5JiM+EHW2k4znZ-@mail.gmail.com>

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

Hi,

I want to rectify my last e-mail. It seemed to be a weird bug in the tool
suite that we are using, since it would be impossible that all the read-only
registers also had that same strange value, it did not happen again
either. I do have another question, however.

Has the driver ever been tested/used without a switch attached? Because when
the host (which has ID 0x0) enumerates the other board it also assigns ID
0x0 to the agent, it seems that the agent should have been assigned 0x1 as
ID. Another thing is that the agent is now hanging on the discovery process.

Regards,
Bastiaan Nijkamp

2010/10/11 Bastiaan Nijkamp <bastiaan.nijkamp@gmail.com>

> Hi,
>
> We have found a poorly documented jumper on our boards that force pci-mode
> to 32bit instead of 64bit. It seems to have an effect on RapidIO aswell
> since the host now completes the enumeration process including finding the
> other board. However, as soon as the agent starts the peer discovery
> process, ALL RapidIO related registers on the agent are set to 0xFF4A.
> Which, offcourse, caused unpredicted behaviour. All other jumpers are set as
> they should be, especially the reference clock (100Mhz) and linkspeed
> settings (1.25Gbps). I am currently having some trouble understanding why
> this happens.
>
> I've double checked Accept All on both boards in the registers and on both
> boards it has been set correctly before discovery/enumeration.
>
> Here is the LAW configuration from u-boot for the agent and host:
>
> Local Access Window Configuration
> LAWBAR00: 0x00000000 LAWAR0x00: 0x80f0001b
>         (EN: 1 TGT: 0x0f SIZE: 256 MiB)
> LAWBAR01: 0x00080000 LAWAR0x01: 0x8000001c
>         (EN: 1 TGT: 0x00 SIZE: 512 MiB)
> LAWBAR02: 0x000e2000 LAWAR0x02: 0x80000016
>         (EN: 1 TGT: 0x00 SIZE: 8 MiB)
> LAWBAR03: 0x000f0000 LAWAR0x03: 0x8040001b
>         (EN: 1 TGT: 0x04 SIZE: 256 MiB)
> LAWBAR04: 0x000c0000 LAWAR0x04: 0x80c0001c
>         (EN: 1 TGT: 0x0c SIZE: 512 MiB)
> LAWBAR05: 0x00000000 LAWAR0x05: 0x00000000
>         (EN: 0 TGT: 0x00 SIZE: 2 Bytes)
> LAWBAR06: 0x00000000 LAWAR0x06: 0x00000000
>         (EN: 0 TGT: 0x00 SIZE: 2 Bytes)
> LAWBAR07: 0x00000000 LAWAR0x07: 0x00000000
>         (EN: 0 TGT: 0x00 SIZE: 2 Bytes)
> LAWBAR08: 0x00000000 LAWAR0x08: 0x00000000
>         (EN: 0 TGT: 0x00 SIZE: 2 Bytes)
> LAWBAR09: 0x00000000 LAWAR0x09: 0x00000000
>         (EN: 0 TGT: 0x00 SIZE: 2 Bytes)
>
> We have removed the RapidIO TLB Entries from u-boot.
>
> Kind regards,
> Bastiaan Nijkamp
>
>
>
>

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

^ permalink raw reply

* [PATCH][v1] powerpc/fsl: 85xx: add cache-sram support
From: harninder.rai @ 2010-10-13  9:17 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Harninder Rai, Vivek Mahajan

From: Harninder Rai <harninder.rai@freescale.com>

It adds cache-sram support in P1/P2 QorIQ platforms as under:

    * A small abstraction over powerpc's remote heap allocator
    * Exports mpc85xx_cache_sram_alloc()/free() APIs
    * Supports only one contiguous SRAM window
    * Drivers can do the following in Kconfig to use these APIs
        "select FSL_85XX_CACHE_SRAM if MPC85xx"
    * Required SRAM size and the offset where SRAM should be mapped must be
      provided at kernel command line as :-
        cache-sram-size=<value>
        cache-sram-offset=<offset>

Signed-off-by: Harninder Rai <harninder.rai@freescale.com>
Signed-off-by: Vivek Mahajan <vivek.mahajan@freescale.com>
---
incorporates review comments

 arch/powerpc/include/asm/fsl_85xx_cache_sram.h |   48 +++++
 arch/powerpc/sysdev/Makefile                   |    1 +
 arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h      |  101 +++++++++++
 arch/powerpc/sysdev/fsl_85xx_cache_sram.c      |  149 +++++++++++++++
 arch/powerpc/sysdev/fsl_85xx_l2ctlr.c          |  231 ++++++++++++++++++++++++
 5 files changed, 530 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/fsl_85xx_cache_sram.h
 create mode 100644 arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
 create mode 100644 arch/powerpc/sysdev/fsl_85xx_cache_sram.c
 create mode 100644 arch/powerpc/sysdev/fsl_85xx_l2ctlr.c

diff --git a/arch/powerpc/include/asm/fsl_85xx_cache_sram.h b/arch/powerpc/include/asm/fsl_85xx_cache_sram.h
new file mode 100644
index 0000000..2af2bdc
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_85xx_cache_sram.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Cache SRAM handling for QorIQ platform
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+#define __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+
+#include <asm/rheap.h>
+#include <linux/spinlock.h>
+
+/*
+ * Cache-SRAM
+ */
+
+struct mpc85xx_cache_sram {
+	phys_addr_t base_phys;
+	void *base_virt;
+	unsigned int size;
+	rh_info_t *rh;
+	spinlock_t lock;
+};
+
+extern void mpc85xx_cache_sram_free(void *ptr);
+extern void *mpc85xx_cache_sram_alloc(unsigned int size,
+				  phys_addr_t *phys, unsigned int align);
+
+#endif /* __AMS_POWERPC_FSL_85XX_CACHE_SRAM_H__ */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5642924..fb60eb1 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_FSL_PMC)		+= fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
 obj-$(CONFIG_FSL_GTM)		+= fsl_gtm.o
 obj-$(CONFIG_MPC8xxx_GPIO)	+= mpc8xxx_gpio.o
+obj-$(CONFIG_FSL_85XX_CACHE_SRAM)	+= fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)	+= simple_gpio.o
 obj-$(CONFIG_RAPIDIO)		+= fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
new file mode 100644
index 0000000..60c9c0b
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc
+ *
+ * QorIQ based Cache Controller Memory Mapped Registers
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FSL_85XX_CACHE_CTLR_H__
+#define __FSL_85XX_CACHE_CTLR_H__
+
+#define L2CR_L2FI		0x40000000	/* L2 flash invalidate */
+#define L2CR_L2IO		0x00200000	/* L2 instruction only */
+#define L2CR_SRAM_ZERO		0x00000000	/* L2SRAM zero size */
+#define L2CR_SRAM_FULL		0x00010000	/* L2SRAM full size */
+#define L2CR_SRAM_HALF		0x00020000	/* L2SRAM half size */
+#define L2CR_SRAM_TWO_HALFS	0x00030000	/* L2SRAM two half sizes */
+#define L2CR_SRAM_QUART		0x00040000	/* L2SRAM one quarter size */
+#define L2CR_SRAM_TWO_QUARTS	0x00050000	/* L2SRAM two quarter size */
+#define L2CR_SRAM_EIGHTH	0x00060000	/* L2SRAM one eighth size */
+#define L2CR_SRAM_TWO_EIGHTH	0x00070000	/* L2SRAM two eighth size */
+
+#define L2SRAM_OPTIMAL_SZ_SHIFT	0x00000003	/* Optimum size for L2SRAM */
+
+#define L2SRAM_BAR_MSK_LO18	0xFFFFC000	/* Lower 18 bits */
+#define L2SRAM_BARE_MSK_HI4	0x0000000F	/* Upper 4 bits */
+
+enum cache_sram_lock_ways {
+	LOCK_WAYS_ZERO,
+	LOCK_WAYS_EIGHTH,
+	LOCK_WAYS_TWO_EIGHTH,
+	LOCK_WAYS_HALF = 4,
+	LOCK_WAYS_FULL = 8,
+};
+
+struct mpc85xx_l2ctlr {
+	u32	ctl;		/* 0x000 - L2 control */
+	u8	res1[0xC];
+	u32	ewar0;		/* 0x010 - External write address 0 */
+	u32	ewarea0;	/* 0x014 - External write address extended 0 */
+	u32	ewcr0;		/* 0x018 - External write ctrl */
+	u8	res2[4];
+	u32	ewar1;		/* 0x020 - External write address 1 */
+	u32	ewarea1;	/* 0x024 - External write address extended 1 */
+	u32	ewcr1;		/* 0x028 - External write ctrl 1 */
+	u8	res3[4];
+	u32	ewar2;		/* 0x030 - External write address 2 */
+	u32	ewarea2;	/* 0x034 - External write address extended 2 */
+	u32	ewcr2;		/* 0x038 - External write ctrl 2 */
+	u8	res4[4];
+	u32	ewar3;		/* 0x040 - External write address 3 */
+	u32	ewarea3;	/* 0x044 - External write address extended 3 */
+	u32	ewcr3;		/* 0x048 - External write ctrl 3 */
+	u8	res5[0xB4];
+	u32	srbar0;		/* 0x100 - SRAM base address 0 */
+	u32	srbarea0;	/* 0x104 - SRAM base addr reg ext address 0 */
+	u32	srbar1;		/* 0x108 - SRAM base address 1 */
+	u32	srbarea1;	/* 0x10C - SRAM base addr reg ext address 1 */
+	u8	res6[0xCF0];
+	u32	errinjhi;	/* 0xE00 - Error injection mask high */
+	u32	errinjlo;	/* 0xE04 - Error injection mask low */
+	u32	errinjctl;	/* 0xE08 - Error injection tag/ecc control */
+	u8	res7[0x14];
+	u32	captdatahi;	/* 0xE20 - Error data high capture */
+	u32	captdatalo;	/* 0xE24 - Error data low capture */
+	u32	captecc;	/* 0xE28 - Error syndrome */
+	u8	res8[0x14];
+	u32	errdet;		/* 0xE40 - Error detect */
+	u32	errdis;		/* 0xE44 - Error disable */
+	u32	errinten;	/* 0xE48 - Error interrupt enable */
+	u32	errattr;	/* 0xE4c - Error attribute capture */
+	u32	erradrrl;	/* 0xE50 - Error address capture low */
+	u32	erradrrh;	/* 0xE54 - Error address capture high */
+	u32	errctl;		/* 0xE58 - Error control */
+	u8	res9[0x1A4];
+};
+
+struct sram_parameters {
+	unsigned int sram_size;
+	uint64_t sram_offset;
+};
+
+extern int instantiate_cache_sram(struct platform_device *dev,
+		struct sram_parameters sram_params);
+extern void remove_cache_sram(struct platform_device *dev);
+
+#endif /* __FSL_85XX_CACHE_CTLR_H__ */
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
new file mode 100644
index 0000000..5a2a623
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <asm/pgtable.h>
+#include <asm/fsl_85xx_cache_sram.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+struct mpc85xx_cache_sram *cache_sram;
+
+void *mpc85xx_cache_sram_alloc(unsigned int size,
+				phys_addr_t *phys, unsigned int align)
+{
+	unsigned long offset;
+	unsigned long flags;
+
+	if (unlikely(cache_sram == NULL))
+		return NULL;
+
+	if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
+		pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
+			__func__, size, align);
+		return NULL;
+	}
+
+	if ((align & (align - 1)) || align <= 1) {
+		pr_err("%s(): align(=%x) must be power of two and >1\n",
+			__func__, align);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&cache_sram->lock, flags);
+	offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
+	spin_unlock_irqrestore(&cache_sram->lock, flags);
+
+	if (IS_ERR_VALUE(offset))
+		return NULL;
+
+	*phys = cache_sram->base_phys + offset;
+
+	return (unsigned char *)cache_sram->base_virt + offset;
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
+
+void mpc85xx_cache_sram_free(void *ptr)
+{
+	unsigned long flags;
+	BUG_ON(!ptr);
+
+	spin_lock_irqsave(&cache_sram->lock, flags);
+	rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
+	spin_unlock_irqrestore(&cache_sram->lock, flags);
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_free);
+
+int __init instantiate_cache_sram(struct platform_device *dev,
+		struct sram_parameters sram_params)
+{
+	if (cache_sram) {
+		dev_err(&dev->dev, "Already initialized cache-sram\n");
+		return -EBUSY;
+	}
+
+	cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
+	if (!cache_sram) {
+		dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
+		return -ENOMEM;
+	}
+
+	cache_sram->base_phys = sram_params.sram_offset;
+	cache_sram->size = sram_params.sram_size;
+
+	if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
+						"fsl_85xx_cache_sram")) {
+		dev_err(&dev->dev, "%s: request memory failed\n",
+				dev->dev.of_node->full_name);
+		kfree(cache_sram);
+		return -ENXIO;
+	}
+
+	cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
+				cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
+	if (!cache_sram->base_virt) {
+		dev_err(&dev->dev, "%s: ioremap_flags failed\n",
+				dev->dev.of_node->full_name);
+		release_mem_region(cache_sram->base_phys, cache_sram->size);
+		kfree(cache_sram);
+		return -ENOMEM;
+	}
+
+	cache_sram->rh = rh_create(sizeof(unsigned int));
+	if (IS_ERR(cache_sram->rh)) {
+		dev_err(&dev->dev, "%s: Unable to create remote heap\n",
+				dev->dev.of_node->full_name);
+		iounmap(cache_sram->base_virt);
+		release_mem_region(cache_sram->base_phys, cache_sram->size);
+		kfree(cache_sram);
+		return PTR_ERR(cache_sram->rh);
+	}
+
+	rh_attach_region(cache_sram->rh, 0, cache_sram->size);
+	spin_lock_init(&cache_sram->lock);
+
+	dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
+		(unsigned long long)cache_sram->base_phys, cache_sram->size);
+	return 0;
+}
+
+void remove_cache_sram(struct platform_device *dev)
+{
+	BUG_ON(!cache_sram);
+
+	rh_detach_region(cache_sram->rh, 0, cache_sram->size);
+	rh_destroy(cache_sram->rh);
+
+	iounmap(cache_sram->base_virt);
+	release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+	kfree(cache_sram);
+	cache_sram = NULL;
+
+	dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
+}
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
new file mode 100644
index 0000000..cc8d655
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+static char *sram_size;
+static char *sram_offset;
+struct mpc85xx_l2ctlr __iomem *l2ctlr;
+
+static long get_cache_sram_size(void)
+{
+	unsigned long val;
+
+	if (!sram_size || (strict_strtoul(sram_size, 0, &val) < 0))
+		return -EINVAL;
+
+	return val;
+}
+
+static long get_cache_sram_offset(void)
+{
+	unsigned long val;
+
+	if (!sram_offset || (strict_strtoul(sram_offset, 0, &val) < 0))
+		return -EINVAL;
+
+	return val;
+}
+
+static int __init get_size_from_cmdline(char *str)
+{
+	if (!str)
+		return 0;
+
+	sram_size = str;
+	return 1;
+}
+
+static int __init get_offset_from_cmdline(char *str)
+{
+	if (!str)
+		return 0;
+
+	sram_offset = str;
+	return 1;
+}
+
+__setup("cache-sram-size=", get_size_from_cmdline);
+__setup("cache-sram-offset=", get_offset_from_cmdline);
+
+static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev,
+					  const struct of_device_id *match)
+{
+	long rval;
+	unsigned int rem;
+	unsigned char ways;
+	const unsigned int *prop;
+	unsigned int l2cache_size;
+	struct sram_parameters sram_params;
+
+	if (!dev->dev.of_node) {
+		dev_err(&dev->dev, "Device's OF-node is NULL\n");
+		return -EINVAL;
+	}
+
+	prop = of_get_property(dev->dev.of_node, "cache-size", NULL);
+	if (!prop) {
+		dev_err(&dev->dev, "Missing L2 cache-size\n");
+		return -EINVAL;
+	}
+	l2cache_size = *prop;
+
+	sram_params.sram_size  = get_cache_sram_size();
+	if (sram_params.sram_size <= 0) {
+		dev_err(&dev->dev,
+			"Entire L2 as cache, Aborting Cache-SRAM stuff\n");
+		return -EINVAL;
+	}
+
+	sram_params.sram_offset  = get_cache_sram_offset();
+	if (sram_params.sram_offset <= 0) {
+		dev_err(&dev->dev,
+			"Entire L2 as cache, provide a valid sram offset\n");
+		return -EINVAL;
+	}
+
+
+	rem = l2cache_size % sram_params.sram_size;
+	ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size;
+	if (rem || (ways & (ways - 1))) {
+		dev_err(&dev->dev, "Illegal cache-sram-size in command line\n");
+		return -EINVAL;
+	}
+
+	l2ctlr = of_iomap(dev->dev.of_node, 0);
+	if (!l2ctlr) {
+		dev_err(&dev->dev, "Can't map L2 controller\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Write bits[0-17] to srbar0
+	 */
+	out_be32(&l2ctlr->srbar0,
+		sram_params.sram_offset & L2SRAM_BAR_MSK_LO18);
+
+	/*
+	 * Write bits[18-21] to srbare0
+	 */
+#ifdef CONFIG_PHYS_64BIT
+	out_be32(&l2ctlr->srbarea0,
+		(sram_params.sram_offset >> 32) & L2SRAM_BARE_MSK_HI4);
+#endif
+
+	clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
+
+	switch (ways) {
+	case LOCK_WAYS_EIGHTH:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
+		break;
+
+	case LOCK_WAYS_TWO_EIGHTH:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
+		break;
+
+	case LOCK_WAYS_HALF:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
+		break;
+
+	case LOCK_WAYS_FULL:
+	default:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
+		break;
+	}
+	eieio();
+
+	rval = instantiate_cache_sram(dev, sram_params);
+	if (rval < 0) {
+		dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n");
+		iounmap(l2ctlr);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __devexit mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
+{
+	BUG_ON(!l2ctlr);
+
+	iounmap(l2ctlr);
+	remove_cache_sram(dev);
+	dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n");
+
+	return 0;
+}
+
+static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
+	{
+		.compatible = "fsl,p2020-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p2010-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1020-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1011-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1013-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1022-l2-cache-controller",
+	},
+	{},
+};
+
+static struct of_platform_driver mpc85xx_l2ctlr_of_platform_driver = {
+	.driver	= {
+		.name		= "fsl-l2ctlr",
+		.owner		= THIS_MODULE,
+		.of_match_table	= mpc85xx_l2ctlr_of_match,
+	},
+	.probe		= mpc85xx_l2ctlr_of_probe,
+	.remove		= __devexit_p(mpc85xx_l2ctlr_of_remove),
+};
+
+static __init int mpc85xx_l2ctlr_of_init(void)
+{
+	return of_register_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+static void __exit mpc85xx_l2ctlr_of_exit(void)
+{
+	of_unregister_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+subsys_initcall(mpc85xx_l2ctlr_of_init);
+module_exit(mpc85xx_l2ctlr_of_exit);
+
+MODULE_DESCRIPTION("Freescale MPC85xx L2 controller init");
+MODULE_LICENSE("GPL v2");
-- 
1.5.6.5

^ permalink raw reply related

* Re: [PATCH][v1] powerpc/fsl: 85xx: add cache-sram support
From: Philipp Ittershagen @ 2010-10-13 10:10 UTC (permalink / raw)
  To: harninder.rai; +Cc: linuxppc-dev, Vivek Mahajan
In-Reply-To: <1286961435-3010-1-git-send-email-harninder.rai@freescale.com>

Hi Harninder,

On Wed, 2010-10-13 at 14:47 +0530, harninder.rai@freescale.com wrote:
> +int __init instantiate_cache_sram(struct platform_device *dev,
> +		struct sram_parameters sram_params)
> +{
> +	if (cache_sram) {
> +		dev_err(&dev->dev, "Already initialized cache-sram\n");
> +		return -EBUSY;
> +	}
> +
> +	cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
> +	if (!cache_sram) {
> +		dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
> +		return -ENOMEM;
> +	}
> +
> +	cache_sram->base_phys = sram_params.sram_offset;
> +	cache_sram->size = sram_params.sram_size;
> +
> +	if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
> +						"fsl_85xx_cache_sram")) {
> +		dev_err(&dev->dev, "%s: request memory failed\n",
> +				dev->dev.of_node->full_name);
> +		kfree(cache_sram);
> +		return -ENXIO;
> +	}
> +
> +	cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
> +				cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
> +	if (!cache_sram->base_virt) {
> +		dev_err(&dev->dev, "%s: ioremap_flags failed\n",
> +				dev->dev.of_node->full_name);
> +		release_mem_region(cache_sram->base_phys, cache_sram->size);
> +		kfree(cache_sram);
> +		return -ENOMEM;
> +	}
> +
> +	cache_sram->rh = rh_create(sizeof(unsigned int));
> +	if (IS_ERR(cache_sram->rh)) {
> +		dev_err(&dev->dev, "%s: Unable to create remote heap\n",
> +				dev->dev.of_node->full_name);
> +		iounmap(cache_sram->base_virt);
> +		release_mem_region(cache_sram->base_phys, cache_sram->size);
> +		kfree(cache_sram);
> +		return PTR_ERR(cache_sram->rh);
> +	}
> +
> +	rh_attach_region(cache_sram->rh, 0, cache_sram->size);
> +	spin_lock_init(&cache_sram->lock);
> +
> +	dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
> +		(unsigned long long)cache_sram->base_phys, cache_sram->size);
> +	return 0;
> +}

You could save some redundant code by using goto statements for error
handling.

For example:

...

int ret;

if (!request_mem_region(...)) {
	ret = -ENXIO;
	goto out_free;
}


if (!ioremap(...)) {
	ret = -ENOMEM;
	goto out_release;
}

if (!IS_ERR(cache_sram->rh)) {
	ret = PTR_ERR(...);
	goto out_unmap;
}

...

return 0;

out_unmap:
	iounmap(...);
out_release:
	release_mem_region(...);
out_free:
	kfree(...);
	return ret;
}



-- Philipp

^ permalink raw reply

* [PATCH][v2] powerpc/fsl: 85xx: add cache-sram support
From: harninder.rai @ 2010-10-13 12:00 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Harninder Rai, Vivek Mahajan

From: Harninder Rai <harninder.rai@freescale.com>

It adds cache-sram support in P1/P2 QorIQ platforms as under:

    * A small abstraction over powerpc's remote heap allocator
    * Exports mpc85xx_cache_sram_alloc()/free() APIs
    * Supports only one contiguous SRAM window
    * Drivers can do the following in Kconfig to use these APIs
        "select FSL_85XX_CACHE_SRAM if MPC85xx"
    * Required SRAM size and the offset where SRAM should be mapped must be
      provided at kernel command line as :-
        cache-sram-size=<value>
        cache-sram-offset=<offset>

Signed-off-by: Harninder Rai <harninder.rai@freescale.com>
Signed-off-by: Vivek Mahajan <vivek.mahajan@freescale.com>
---
incorporated review comments from Philipp

 arch/powerpc/include/asm/fsl_85xx_cache_sram.h |   48 +++++
 arch/powerpc/sysdev/Makefile                   |    1 +
 arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h      |  101 +++++++++++
 arch/powerpc/sysdev/fsl_85xx_cache_sram.c      |  159 ++++++++++++++++
 arch/powerpc/sysdev/fsl_85xx_l2ctlr.c          |  231 ++++++++++++++++++++++++
 5 files changed, 540 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/fsl_85xx_cache_sram.h
 create mode 100644 arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
 create mode 100644 arch/powerpc/sysdev/fsl_85xx_cache_sram.c
 create mode 100644 arch/powerpc/sysdev/fsl_85xx_l2ctlr.c

diff --git a/arch/powerpc/include/asm/fsl_85xx_cache_sram.h b/arch/powerpc/include/asm/fsl_85xx_cache_sram.h
new file mode 100644
index 0000000..2af2bdc
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_85xx_cache_sram.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Cache SRAM handling for QorIQ platform
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+#define __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+
+#include <asm/rheap.h>
+#include <linux/spinlock.h>
+
+/*
+ * Cache-SRAM
+ */
+
+struct mpc85xx_cache_sram {
+	phys_addr_t base_phys;
+	void *base_virt;
+	unsigned int size;
+	rh_info_t *rh;
+	spinlock_t lock;
+};
+
+extern void mpc85xx_cache_sram_free(void *ptr);
+extern void *mpc85xx_cache_sram_alloc(unsigned int size,
+				  phys_addr_t *phys, unsigned int align);
+
+#endif /* __AMS_POWERPC_FSL_85XX_CACHE_SRAM_H__ */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5642924..fb60eb1 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_FSL_PMC)		+= fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
 obj-$(CONFIG_FSL_GTM)		+= fsl_gtm.o
 obj-$(CONFIG_MPC8xxx_GPIO)	+= mpc8xxx_gpio.o
+obj-$(CONFIG_FSL_85XX_CACHE_SRAM)	+= fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)	+= simple_gpio.o
 obj-$(CONFIG_RAPIDIO)		+= fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
new file mode 100644
index 0000000..60c9c0b
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc
+ *
+ * QorIQ based Cache Controller Memory Mapped Registers
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FSL_85XX_CACHE_CTLR_H__
+#define __FSL_85XX_CACHE_CTLR_H__
+
+#define L2CR_L2FI		0x40000000	/* L2 flash invalidate */
+#define L2CR_L2IO		0x00200000	/* L2 instruction only */
+#define L2CR_SRAM_ZERO		0x00000000	/* L2SRAM zero size */
+#define L2CR_SRAM_FULL		0x00010000	/* L2SRAM full size */
+#define L2CR_SRAM_HALF		0x00020000	/* L2SRAM half size */
+#define L2CR_SRAM_TWO_HALFS	0x00030000	/* L2SRAM two half sizes */
+#define L2CR_SRAM_QUART		0x00040000	/* L2SRAM one quarter size */
+#define L2CR_SRAM_TWO_QUARTS	0x00050000	/* L2SRAM two quarter size */
+#define L2CR_SRAM_EIGHTH	0x00060000	/* L2SRAM one eighth size */
+#define L2CR_SRAM_TWO_EIGHTH	0x00070000	/* L2SRAM two eighth size */
+
+#define L2SRAM_OPTIMAL_SZ_SHIFT	0x00000003	/* Optimum size for L2SRAM */
+
+#define L2SRAM_BAR_MSK_LO18	0xFFFFC000	/* Lower 18 bits */
+#define L2SRAM_BARE_MSK_HI4	0x0000000F	/* Upper 4 bits */
+
+enum cache_sram_lock_ways {
+	LOCK_WAYS_ZERO,
+	LOCK_WAYS_EIGHTH,
+	LOCK_WAYS_TWO_EIGHTH,
+	LOCK_WAYS_HALF = 4,
+	LOCK_WAYS_FULL = 8,
+};
+
+struct mpc85xx_l2ctlr {
+	u32	ctl;		/* 0x000 - L2 control */
+	u8	res1[0xC];
+	u32	ewar0;		/* 0x010 - External write address 0 */
+	u32	ewarea0;	/* 0x014 - External write address extended 0 */
+	u32	ewcr0;		/* 0x018 - External write ctrl */
+	u8	res2[4];
+	u32	ewar1;		/* 0x020 - External write address 1 */
+	u32	ewarea1;	/* 0x024 - External write address extended 1 */
+	u32	ewcr1;		/* 0x028 - External write ctrl 1 */
+	u8	res3[4];
+	u32	ewar2;		/* 0x030 - External write address 2 */
+	u32	ewarea2;	/* 0x034 - External write address extended 2 */
+	u32	ewcr2;		/* 0x038 - External write ctrl 2 */
+	u8	res4[4];
+	u32	ewar3;		/* 0x040 - External write address 3 */
+	u32	ewarea3;	/* 0x044 - External write address extended 3 */
+	u32	ewcr3;		/* 0x048 - External write ctrl 3 */
+	u8	res5[0xB4];
+	u32	srbar0;		/* 0x100 - SRAM base address 0 */
+	u32	srbarea0;	/* 0x104 - SRAM base addr reg ext address 0 */
+	u32	srbar1;		/* 0x108 - SRAM base address 1 */
+	u32	srbarea1;	/* 0x10C - SRAM base addr reg ext address 1 */
+	u8	res6[0xCF0];
+	u32	errinjhi;	/* 0xE00 - Error injection mask high */
+	u32	errinjlo;	/* 0xE04 - Error injection mask low */
+	u32	errinjctl;	/* 0xE08 - Error injection tag/ecc control */
+	u8	res7[0x14];
+	u32	captdatahi;	/* 0xE20 - Error data high capture */
+	u32	captdatalo;	/* 0xE24 - Error data low capture */
+	u32	captecc;	/* 0xE28 - Error syndrome */
+	u8	res8[0x14];
+	u32	errdet;		/* 0xE40 - Error detect */
+	u32	errdis;		/* 0xE44 - Error disable */
+	u32	errinten;	/* 0xE48 - Error interrupt enable */
+	u32	errattr;	/* 0xE4c - Error attribute capture */
+	u32	erradrrl;	/* 0xE50 - Error address capture low */
+	u32	erradrrh;	/* 0xE54 - Error address capture high */
+	u32	errctl;		/* 0xE58 - Error control */
+	u8	res9[0x1A4];
+};
+
+struct sram_parameters {
+	unsigned int sram_size;
+	uint64_t sram_offset;
+};
+
+extern int instantiate_cache_sram(struct platform_device *dev,
+		struct sram_parameters sram_params);
+extern void remove_cache_sram(struct platform_device *dev);
+
+#endif /* __FSL_85XX_CACHE_CTLR_H__ */
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
new file mode 100644
index 0000000..54fb192
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <asm/pgtable.h>
+#include <asm/fsl_85xx_cache_sram.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+struct mpc85xx_cache_sram *cache_sram;
+
+void *mpc85xx_cache_sram_alloc(unsigned int size,
+				phys_addr_t *phys, unsigned int align)
+{
+	unsigned long offset;
+	unsigned long flags;
+
+	if (unlikely(cache_sram == NULL))
+		return NULL;
+
+	if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
+		pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
+			__func__, size, align);
+		return NULL;
+	}
+
+	if ((align & (align - 1)) || align <= 1) {
+		pr_err("%s(): align(=%x) must be power of two and >1\n",
+			__func__, align);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&cache_sram->lock, flags);
+	offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
+	spin_unlock_irqrestore(&cache_sram->lock, flags);
+
+	if (IS_ERR_VALUE(offset))
+		return NULL;
+
+	*phys = cache_sram->base_phys + offset;
+
+	return (unsigned char *)cache_sram->base_virt + offset;
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
+
+void mpc85xx_cache_sram_free(void *ptr)
+{
+	unsigned long flags;
+	BUG_ON(!ptr);
+
+	spin_lock_irqsave(&cache_sram->lock, flags);
+	rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
+	spin_unlock_irqrestore(&cache_sram->lock, flags);
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_free);
+
+int __init instantiate_cache_sram(struct platform_device *dev,
+		struct sram_parameters sram_params)
+{
+	int ret = 0;
+
+	if (cache_sram) {
+		dev_err(&dev->dev, "Already initialized cache-sram\n");
+		return -EBUSY;
+	}
+
+	cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
+	if (!cache_sram) {
+		dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
+		return -ENOMEM;
+	}
+
+	cache_sram->base_phys = sram_params.sram_offset;
+	cache_sram->size = sram_params.sram_size;
+
+	if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
+						"fsl_85xx_cache_sram")) {
+		dev_err(&dev->dev, "%s: request memory failed\n",
+				dev->dev.of_node->full_name);
+		ret = -ENXIO;
+		goto out_free;
+	}
+
+	cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
+				cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
+	if (!cache_sram->base_virt) {
+		dev_err(&dev->dev, "%s: ioremap_flags failed\n",
+				dev->dev.of_node->full_name);
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	cache_sram->rh = rh_create(sizeof(unsigned int));
+	if (IS_ERR(cache_sram->rh)) {
+		dev_err(&dev->dev, "%s: Unable to create remote heap\n",
+				dev->dev.of_node->full_name);
+		ret = PTR_ERR(cache_sram->rh);
+		goto out_unmap;
+	}
+
+	rh_attach_region(cache_sram->rh, 0, cache_sram->size);
+	spin_lock_init(&cache_sram->lock);
+
+	dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
+		(unsigned long long)cache_sram->base_phys, cache_sram->size);
+
+	return 0;
+
+out_unmap:
+	iounmap(cache_sram->base_virt);
+
+out_release:
+	release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+out_free:
+	kfree(cache_sram);
+	return ret;
+}
+
+void remove_cache_sram(struct platform_device *dev)
+{
+	BUG_ON(!cache_sram);
+
+	rh_detach_region(cache_sram->rh, 0, cache_sram->size);
+	rh_destroy(cache_sram->rh);
+
+	iounmap(cache_sram->base_virt);
+	release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+	kfree(cache_sram);
+	cache_sram = NULL;
+
+	dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
+}
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
new file mode 100644
index 0000000..cc8d655
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+static char *sram_size;
+static char *sram_offset;
+struct mpc85xx_l2ctlr __iomem *l2ctlr;
+
+static long get_cache_sram_size(void)
+{
+	unsigned long val;
+
+	if (!sram_size || (strict_strtoul(sram_size, 0, &val) < 0))
+		return -EINVAL;
+
+	return val;
+}
+
+static long get_cache_sram_offset(void)
+{
+	unsigned long val;
+
+	if (!sram_offset || (strict_strtoul(sram_offset, 0, &val) < 0))
+		return -EINVAL;
+
+	return val;
+}
+
+static int __init get_size_from_cmdline(char *str)
+{
+	if (!str)
+		return 0;
+
+	sram_size = str;
+	return 1;
+}
+
+static int __init get_offset_from_cmdline(char *str)
+{
+	if (!str)
+		return 0;
+
+	sram_offset = str;
+	return 1;
+}
+
+__setup("cache-sram-size=", get_size_from_cmdline);
+__setup("cache-sram-offset=", get_offset_from_cmdline);
+
+static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev,
+					  const struct of_device_id *match)
+{
+	long rval;
+	unsigned int rem;
+	unsigned char ways;
+	const unsigned int *prop;
+	unsigned int l2cache_size;
+	struct sram_parameters sram_params;
+
+	if (!dev->dev.of_node) {
+		dev_err(&dev->dev, "Device's OF-node is NULL\n");
+		return -EINVAL;
+	}
+
+	prop = of_get_property(dev->dev.of_node, "cache-size", NULL);
+	if (!prop) {
+		dev_err(&dev->dev, "Missing L2 cache-size\n");
+		return -EINVAL;
+	}
+	l2cache_size = *prop;
+
+	sram_params.sram_size  = get_cache_sram_size();
+	if (sram_params.sram_size <= 0) {
+		dev_err(&dev->dev,
+			"Entire L2 as cache, Aborting Cache-SRAM stuff\n");
+		return -EINVAL;
+	}
+
+	sram_params.sram_offset  = get_cache_sram_offset();
+	if (sram_params.sram_offset <= 0) {
+		dev_err(&dev->dev,
+			"Entire L2 as cache, provide a valid sram offset\n");
+		return -EINVAL;
+	}
+
+
+	rem = l2cache_size % sram_params.sram_size;
+	ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size;
+	if (rem || (ways & (ways - 1))) {
+		dev_err(&dev->dev, "Illegal cache-sram-size in command line\n");
+		return -EINVAL;
+	}
+
+	l2ctlr = of_iomap(dev->dev.of_node, 0);
+	if (!l2ctlr) {
+		dev_err(&dev->dev, "Can't map L2 controller\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Write bits[0-17] to srbar0
+	 */
+	out_be32(&l2ctlr->srbar0,
+		sram_params.sram_offset & L2SRAM_BAR_MSK_LO18);
+
+	/*
+	 * Write bits[18-21] to srbare0
+	 */
+#ifdef CONFIG_PHYS_64BIT
+	out_be32(&l2ctlr->srbarea0,
+		(sram_params.sram_offset >> 32) & L2SRAM_BARE_MSK_HI4);
+#endif
+
+	clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
+
+	switch (ways) {
+	case LOCK_WAYS_EIGHTH:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
+		break;
+
+	case LOCK_WAYS_TWO_EIGHTH:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
+		break;
+
+	case LOCK_WAYS_HALF:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
+		break;
+
+	case LOCK_WAYS_FULL:
+	default:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
+		break;
+	}
+	eieio();
+
+	rval = instantiate_cache_sram(dev, sram_params);
+	if (rval < 0) {
+		dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n");
+		iounmap(l2ctlr);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __devexit mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
+{
+	BUG_ON(!l2ctlr);
+
+	iounmap(l2ctlr);
+	remove_cache_sram(dev);
+	dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n");
+
+	return 0;
+}
+
+static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
+	{
+		.compatible = "fsl,p2020-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p2010-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1020-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1011-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1013-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1022-l2-cache-controller",
+	},
+	{},
+};
+
+static struct of_platform_driver mpc85xx_l2ctlr_of_platform_driver = {
+	.driver	= {
+		.name		= "fsl-l2ctlr",
+		.owner		= THIS_MODULE,
+		.of_match_table	= mpc85xx_l2ctlr_of_match,
+	},
+	.probe		= mpc85xx_l2ctlr_of_probe,
+	.remove		= __devexit_p(mpc85xx_l2ctlr_of_remove),
+};
+
+static __init int mpc85xx_l2ctlr_of_init(void)
+{
+	return of_register_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+static void __exit mpc85xx_l2ctlr_of_exit(void)
+{
+	of_unregister_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+subsys_initcall(mpc85xx_l2ctlr_of_init);
+module_exit(mpc85xx_l2ctlr_of_exit);
+
+MODULE_DESCRIPTION("Freescale MPC85xx L2 controller init");
+MODULE_LICENSE("GPL v2");
-- 
1.5.6.5

^ permalink raw reply related

* Re: [PATCH v2] powerpc/fsl-booke: Add support for FSL 64-bit e5500 core
From: Kumar Gala @ 2010-10-13 12:38 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <20101012151138.62d9e14a@udp111988uds.am.freescale.net>


On Oct 12, 2010, at 3:11 PM, Scott Wood wrote:

> On Tue, 12 Oct 2010 14:55:42 -0500
> Kumar Gala <galak@kernel.crashing.org> wrote:
>=20
>>=20
>> On Oct 12, 2010, at 12:33 PM, Scott Wood wrote:
>>=20
>>> On Tue, 12 Oct 2010 10:50:52 -0500
>>> Kumar Gala <galak@kernel.crashing.org> wrote:
>>>=20
>>>> The new e5500 core is similar to the e500mc core but adds 64-bit
>>>> support.  We support running it in 32-bit mode as it is identical =
to the
>>>> e500mc.
>>>>=20
>>>> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
>>>> ---
>>>> * Updated to remove CONFIG_PPC_E5500 and use E500MC
>>>=20
>>> It still has E500 || E500MC all over the place...
>>>=20
>>> If E500MC is not going to imply E500 that should be consistent for =
both
>>> 32 and 64 bit -- though I think it would make more sense that E500MC
>>> does imply E500.
>>>=20
>>> -Scott
>>=20
>> I have a problem with Kconfig and getting E500MC option to only exist =
in the proper cases.
>=20
> Does having P5020DS (and any future 64-bit-capable board)
> explicitly select E500 as well as PPC_E500MC avoid the issue?

it does, kinda ugly but oh well.

- k

^ permalink raw reply

* Re: Please pull 'next' branch of 4xx tree
From: Josh Boyer @ 2010-10-13 13:16 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev
In-Reply-To: <20100928130941.GA31993@zod.rchland.ibm.com>

On Tue, Sep 28, 2010 at 09:09:41AM -0400, Josh Boyer wrote:
>Hi Ben,
>
>A few small updates for the next branch.  A new board/SoC from AMCC, and
>some 476 changes from Shaggy.  Please pull.

OK, below is a fixed up tree that drops the patch Shaggy said was
broken, and rebases on top of your new -next branch.  Please pull.

josh

The following changes since commit 4108d9ba9091c55cfb968d42dd7dcae9a098b876:

  powerpc/Makefiles: Change to new flag variables (2010-10-13 16:19:22 +1100)

are available in the git repository at:
  ssh://master.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git next

Dave Kleikamp (1):
      powerpc/476: lazy flush_tlb_mm for nohash architectures

Josh Boyer (1):
      powerpc/44x: Update ppc44x_defconfig

Tirumala Marri (1):
      powerpc/44x: Add support for the AMCC APM821xx SoC

 arch/powerpc/boot/dts/bluestone.dts          |  254 ++++++++++++++++++++++++++
 arch/powerpc/configs/44x/bluestone_defconfig |   68 +++++++
 arch/powerpc/configs/ppc44x_defconfig        |    9 +-
 arch/powerpc/kernel/cpu_setup_44x.S          |    1 +
 arch/powerpc/kernel/cputable.c               |   15 ++
 arch/powerpc/mm/mmu_context_nohash.c         |  154 ++++++++++++++--
 arch/powerpc/mm/mmu_decl.h                   |    8 +
 arch/powerpc/mm/tlb_nohash.c                 |   28 +++-
 arch/powerpc/platforms/44x/Kconfig           |   16 ++
 arch/powerpc/platforms/44x/ppc44x_simple.c   |    1 +
 10 files changed, 534 insertions(+), 20 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/bluestone.dts
 create mode 100644 arch/powerpc/configs/44x/bluestone_defconfig

^ permalink raw reply

* [PATCH v3] powerpc/fsl-booke: Add support for FSL 64-bit e5500 core
From: Kumar Gala @ 2010-10-13 13:17 UTC (permalink / raw)
  To: linuxppc-dev

The new e5500 core is similar to the e500mc core but adds 64-bit
support.  We support running it in 32-bit mode as it is identical to the
e500mc.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
* clean up kconfig further to reduce use of E500MC

 arch/powerpc/include/asm/reg_booke.h      |    2 +-
 arch/powerpc/kernel/Makefile              |    3 +++
 arch/powerpc/kernel/cpu_setup_fsl_booke.S |   15 +++++++++++++++
 arch/powerpc/kernel/cputable.c            |   28 ++++++++++++++++++++++++++--
 arch/powerpc/kernel/traps.c               |    7 ++++++-
 arch/powerpc/platforms/85xx/Kconfig       |    4 ++++
 arch/powerpc/platforms/Kconfig.cputype    |    9 +++++++--
 7 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 667a498..3a2eaba 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -203,7 +203,7 @@
 #define PPC47x_MCSR_FPR	0x00800000 /* FPR parity error */
 #define PPC47x_MCSR_IPR	0x00400000 /* Imprecise Machine Check Exception */
 
-#ifdef CONFIG_E500
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_BOOK3E_64)
 /* All e500 */
 #define MCSR_MCP 	0x80000000UL /* Machine Check Input Pin */
 #define MCSR_ICPERR 	0x40000000UL /* I-Cache Parity Error */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1dda701..5175d1e 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PPC64)		+= setup_64.o sys_ppc32.o \
 				   paca.o nvram_64.o firmware.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_ppc970.o cpu_setup_pa6t.o
+obj-$(CONFIG_PPC_BOOK3E_64)	+= cpu_setup_fsl_booke.o
 obj64-$(CONFIG_RELOCATABLE)	+= reloc_64.o
 obj-$(CONFIG_PPC_BOOK3E_64)	+= exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC64)		+= vdso64/
@@ -55,7 +56,9 @@ obj-$(CONFIG_IBMVIO)		+= vio.o
 obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)		+= idle_e500.o
+endif
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 0adb50a..894e64f 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -51,6 +51,7 @@ _GLOBAL(__e500_dcache_setup)
 	isync
 	blr
 
+#ifdef CONFIG_PPC32
 _GLOBAL(__setup_cpu_e200)
 	/* enable dedicated debug exception handling resources (Debug APU) */
 	mfspr	r3,SPRN_HID0
@@ -72,3 +73,17 @@ _GLOBAL(__setup_cpu_e500mc)
 	bl	__setup_e500mc_ivors
 	mtlr	r4
 	blr
+#endif
+/* Right now, restore and setup are the same thing */
+_GLOBAL(__restore_cpu_e5500)
+_GLOBAL(__setup_cpu_e5500)
+	mflr	r4
+	bl	__e500_icache_setup
+	bl	__e500_dcache_setup
+#ifdef CONFIG_PPC_BOOK3E_64
+	bl	.__setup_base_ivors
+#else
+	bl	__setup_e500mc_ivors
+#endif
+	mtlr	r4
+	blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 1f9123f..236aa73 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -66,6 +66,10 @@ extern void __restore_cpu_ppc970(void);
 extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power7(void);
 #endif /* CONFIG_PPC64 */
+#if defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_E500)
+extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_e5500(void);
+#endif /* CONFIG_PPC_BOOK3E_64 || CONFIG_E500 */
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -1891,7 +1895,28 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.platform		= "ppc5554",
 	}
 #endif /* CONFIG_E200 */
-#ifdef CONFIG_E500
+#endif /* CONFIG_PPC32 */
+#if defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_E500)
+	{	/* e5500 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x80240000,
+		.cpu_name		= "e5500",
+		.cpu_features		= CPU_FTRS_E500MC,
+		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
+			MMU_FTR_USE_TLBILX,
+		.icache_bsize		= 64,
+		.dcache_bsize		= 64,
+		.num_pmcs		= 4,
+		.oprofile_cpu_type	= "ppc/e500mc",
+		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
+		.cpu_setup		= __setup_cpu_e5500,
+		.cpu_restore		= __restore_cpu_e5500,
+		.machine_check		= machine_check_e500mc,
+		.platform		= "ppce5500",
+	},
+#endif
+#if defined(CONFIG_PPC32) & defined(CONFIG_E500)
 	{	/* e500 */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x80200000,
@@ -1961,7 +1986,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.platform		= "powerpc",
 	}
 #endif /* CONFIG_E500 */
-#endif /* CONFIG_PPC32 */
 
 #ifdef CONFIG_PPC_BOOK3E_64
 	{	/* This is a default entry to get going, to be replaced by
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index a45a63c..5e0985f 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -418,7 +418,7 @@ int machine_check_47x(struct pt_regs *regs)
 
 	return 0;
 }
-#elif defined(CONFIG_E500)
+#elif defined(CONFIG_E500) || defined(CONFIG_PPC_BOOK3E_64)
 int machine_check_e500mc(struct pt_regs *regs)
 {
 	unsigned long mcsr = mfspr(SPRN_MCSR);
@@ -538,6 +538,11 @@ int machine_check_e500(struct pt_regs *regs)
 
 	return 0;
 }
+
+int machine_check_generic(struct pt_regs *regs)
+{
+	return 0;
+}
 #elif defined(CONFIG_E200)
 int machine_check_e200(struct pt_regs *regs)
 {
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 5bde1f2..ae25527 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -11,6 +11,8 @@ menuconfig FSL_SOC_BOOKE
 
 if FSL_SOC_BOOKE
 
+if PPC32
+
 config MPC8540_ADS
 	bool "Freescale MPC8540 ADS"
 	select DEFAULT_UIMAGE
@@ -177,6 +179,8 @@ config P4080_DS
 	help
 	  This option enables support for the P4080 DS board
 
+endif # PPC32
+
 endif # FSL_SOC_BOOKE
 
 config TQM85xx
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index d361f81..b946223 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -129,8 +129,8 @@ config E500
 
 config PPC_E500MC
 	bool "e500mc Support"
-	select PPC_FPU
 	depends on E500
+	select PPC_FPU
 
 config PPC_FPU
 	bool
@@ -166,9 +166,14 @@ config BOOKE
 
 config FSL_BOOKE
 	bool
-	depends on E200 || E500
+	depends on (E200 || E500) && PPC32
 	default y
 
+# this is for common code between PPC32 & PPC64 FSL BOOKE
+config PPC_FSL_BOOK3E
+	bool
+	select FSL_EMB_PERFMON
+	default y if FSL_BOOKE
 
 config PTE_64BIT
 	bool
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v3] powerpc/fsl-booke: Add p5020 DS board support
From: Kumar Gala @ 2010-10-13 13:17 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1286975832-31895-1-git-send-email-galak@kernel.crashing.org>

The P5020DS is in the same family of boards as the P4080 DS and thus
shares the corenet_ds code.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
* Updated based on e5500 support patch

 arch/powerpc/platforms/85xx/Kconfig    |   13 ++++++
 arch/powerpc/platforms/85xx/Makefile   |    1 +
 arch/powerpc/platforms/85xx/p5020_ds.c |   69 ++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/p5020_ds.c

diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index ae25527..2830e0a 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -181,6 +181,19 @@ config P4080_DS
 
 endif # PPC32
 
+config P5020_DS
+	bool "Freescale P5020 DS"
+	select DEFAULT_UIMAGE
+	select PPC_FSL_BOOK3E
+	select E500
+	select PPC_E500MC
+	select PHYS_64BIT
+	select SWIOTLB
+	select MPC8xxx_GPIO
+	select HAS_RAPIDIO
+	help
+	  This option enables support for the P5020 DS board
+
 endif # FSL_SOC_BOOKE
 
 config TQM85xx
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index c3ac071..dd70db7 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
 obj-$(CONFIG_P1022_DS)    += p1022_ds.o
 obj-$(CONFIG_P3041_DS)    += p3041_ds.o corenet_ds.o
 obj-$(CONFIG_P4080_DS)    += p4080_ds.o corenet_ds.o
+obj-$(CONFIG_P5020_DS)    += p5020_ds.o corenet_ds.o
 obj-$(CONFIG_STX_GP3)	  += stx_gp3.o
 obj-$(CONFIG_TQM85xx)	  += tqm85xx.o
 obj-$(CONFIG_SBC8560)     += sbc8560.o
diff --git a/arch/powerpc/platforms/85xx/p5020_ds.c b/arch/powerpc/platforms/85xx/p5020_ds.c
new file mode 100644
index 0000000..7467b71
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/p5020_ds.c
@@ -0,0 +1,69 @@
+/*
+ * P5020 DS Setup
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2009-2010 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p5020_ds_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P5020DS");
+}
+
+define_machine(p5020_ds) {
+	.name			= "P5020 DS",
+	.probe			= p5020_ds_probe,
+	.setup_arch		= corenet_ds_setup_arch,
+	.init_IRQ		= corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
+#ifdef CONFIG_PPC64
+	.get_irq		= mpic_get_irq,
+#else
+	.get_irq		= mpic_get_coreint_irq,
+#endif
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+machine_device_initcall(p5020_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p5020_ds, swiotlb_setup_bus_notifier);
+#endif
-- 
1.7.2.3

^ permalink raw reply related

* RE: Serial RapidIO Maintaintance read causes lock up
From: Bounine, Alexandre @ 2010-10-13 13:38 UTC (permalink / raw)
  To: Bastiaan Nijkamp; +Cc: linuxppc-dev
In-Reply-To: <AANLkTimk2hRhyX4WufjdviDz-OTj7VRfjA94oyoXL9mM@mail.gmail.com>

Bastiaan Nijkamp wrote:
=A0
>Has the driver ever been tested/used without a switch attached? Because =
when the host >(which has ID 0x0) enumerates the other board it also =
assigns ID 0x0 to the agent, it seems >that the agent should have=A0been =
assigned 0x1 as ID.

How the host ID is set on your host board?
Normally rio_enum_host() should increment next_destid in your case.=20

>Another thing is that the agent is now hanging on the discovery =
process.

Make sure that you have the MASTER bit is set in agent's GCCSR register =
(0xC_013C).
If your board uses HW config switches to set host/agent mode this bit =
will be 0 for agent.
For quick test you may keep both boards in the host mode - the current =
RIO implementation relies on "riohdid=3D" command line parameter instead =
of HOST bit.


Alex.
=20
=A0

^ permalink raw reply

* Re: [PATCH] powerpc/fsl: 85xx: add cache-sram support
From: Kumar Gala @ 2010-10-13 14:17 UTC (permalink / raw)
  To: Hollis Blanchard; +Cc: linuxppc-dev, Rai Harninder-B01044
In-Reply-To: <AANLkTi=8q-8+ZR=unxZdhQQZsn33hte_VNEvZpE0uGgp@mail.gmail.com>


On Oct 12, 2010, at 12:19 PM, Hollis Blanchard wrote:

> On Tue, Oct 12, 2010 at 10:02 AM, Rai Harninder-B01044
> <B01044@freescale.com> wrote:
>> Currently the design is that we divide the sram portion into 2 equal
>> parts for AMP
>> That was the part of initial requirement
>> Do we want to remove that?
> 
> Why wouldn't you just pass different cache-sram-size/offset values to
> each kernel?

That was what I was suggesting, but probably wasn't clear :)

- k

^ permalink raw reply


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