LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] i2c-mpc: Do not generate STOP after read.
From: Joakim Tjernlund @ 2009-09-22 11:50 UTC (permalink / raw)
  To: linux-i2c, linuxppc-dev, Esben Haabendal; +Cc: Esben Haabendal

The driver always ends a read with a STOP condition which
breaks subsequent I2C reads/writes in the same transaction as
these expect to do a repeated START(ReSTART).

This will also help I2C multimaster as the bus will not be released
after the first read, but when the whole transaction ends.

Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
---

This should also fix a problem reported by Esben Haabendal:

[PATCH v2] i2c-mpc: generate START condition after STOP caused by read i2c_msg

This fixes MAL (arbitration lost) bug caused by illegal use of
RSTA (repeated START) after STOP condition generated after last byte
of reads. With this patch, it is possible to do an i2c_transfer() with
additional i2c_msg's following the I2C_M_RD messages.

It still needs to be resolved if it is possible to fix this issue
by removing the STOP condition after reads in a robust way.

Signed-off-by: Esben Haabendal <eha@doredevelopment.dk>

 drivers/i2c/busses/i2c-mpc.c |   10 ++--------
 1 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index cdb1858..88ae582 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -369,9 +369,6 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 	unsigned timeout = i2c->adap.timeout;
 	u32 flags = restart ? CCR_RSTA : 0;
 
-	/* Start with MEN */
-	if (!restart)
-		writeccr(i2c, CCR_MEN);
 	/* Start as master */
 	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
 	/* Write target byte */
@@ -400,9 +397,6 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 	int i, result;
 	u32 flags = restart ? CCR_RSTA : 0;
 
-	/* Start with MEN */
-	if (!restart)
-		writeccr(i2c, CCR_MEN);
 	/* Switch to read - restart */
 	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
 	/* Write target address byte - this time with the read flag set */
@@ -429,9 +423,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 		/* Generate txack on next to last byte */
 		if (i == length - 2)
 			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
-		/* Generate stop on last byte */
+		/* Do not generate stop on last byte */
 		if (i == length - 1)
-			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX);
 		data[i] = readb(i2c->base + MPC_I2C_DR);
 	}
 
-- 
1.6.4.3

^ permalink raw reply related

* [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for DS570
From: Richard Röjfors @ 2009-09-22 12:55 UTC (permalink / raw)
  To: spi-devel-general; +Cc: linuxppc-dev, Andrew Morton, dbrownell

This patch splits xilinx_spi into three parts, an OF and a platform
driver and generic part.

The generic part now also works on X86 and also supports the Xilinx
SPI IP DS570

Signed-off-by: Richard Röjfors <richard.rojfors.ext@mocean-labs.com>
---
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2c733c2..eca491b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -218,8 +218,8 @@ config SPI_TXX9
 	  SPI driver for Toshiba TXx9 MIPS SoCs

 config SPI_XILINX
-	tristate "Xilinx SPI controller"
-	depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
+	tristate "Xilinx SPI controller common module"
+	depends on (XILINX_VIRTEX || MICROBLAZE || HAS_IOMEM) && EXPERIMENTAL
 	select SPI_BITBANG
 	help
 	  This exposes the SPI controller IP from the Xilinx EDK.
@@ -227,6 +227,22 @@ config SPI_XILINX
 	  See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
 	  Product Specification document (DS464) for hardware details.

+	  Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
+
+
+config SPI_XILINX_OF
+	tristate "Xilinx SPI controller OF device"
+	depends on SPI_XILINX && XILINX_VIRTEX
+	help
+	  This is the OF driver for the SPI controller IP from the Xilinx EDK.
+
+config SPI_XILINX_PLTFM
+	tristate "Xilinx SPI controller platform device"
+	depends on SPI_XILINX
+	help
+	  This is the platform driver for the SPI controller IP
+	  from the Xilinx EDK.
+
 #
 # Add new SPI master controllers in alphabetical order above this line
 #
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3de408d..5a91cf5 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -30,6 +30,8 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
 obj-$(CONFIG_SPI_TXX9)			+= spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
+obj-$(CONFIG_SPI_XILINX_OF)		+= xilinx_spi_of.o
+obj-$(CONFIG_SPI_XILINX_PLTFM)		+= xilinx_spi_pltfm.o
 obj-$(CONFIG_SPI_SH_SCI)		+= spi_sh_sci.o
 # 	... add above this line ...

diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 46b8c5c..0490820 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -14,22 +14,103 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-#include <linux/of_spi.h>

 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/io.h>

-#define XILINX_SPI_NAME "xilinx_spi"
+#include "xilinx_spi.h"
+
+struct xilinx_spi {
+	/* bitbang has to be first */
+	struct spi_bitbang bitbang;
+	struct completion done;
+	struct resource mem; /* phys mem */
+	void __iomem	*regs;	/* virt. address of the control registers */
+	u32 irq;
+	u8 *rx_ptr;		/* pointer in the Tx buffer */
+	const u8 *tx_ptr;	/* pointer in the Rx buffer */
+	int remaining_bytes;	/* the number of bytes left to transfer */
+	/* offset to the XSPI regs, these might vary... */
+	u8 cr_offset;
+	u8 sr_offset;
+	u8 txd_offset;
+	u8 rxd_offset;
+	u8 ssr_offset;
+	u8 bits_per_word;
+	u8 model;
+};
+
+#ifdef CONFIG_X86
+/* on X86 the block often resides behind a PCI(e) interface which flips the
+ * endian from little to big
+ */
+#define xspi_in8(addr) ioread8(addr)
+#define xspi_in16(addr) ioread16(addr)
+#define xspi_in32(addr) ioread32(addr)
+
+#define xspi_out8(addr, b) iowrite8(b, addr)
+#define xspi_out16(addr, w) iowrite16(w, addr)
+#define xspi_out32(addr, l) iowrite32(l, addr)
+#else
+/* While on for instance PPC we use big endian */
+#define xspi_in8(addr) in_8(addr)
+#define xspi_in16(addr) in_be16(addr)
+#define xspi_in32(addr) in_be32(addr)
+
+#define xspi_out8(addr, b) out_8(addr, b)
+#define xspi_out16(addr, w) out_be16(addr, w)
+#define xspi_out32(addr, l) out_be32(addr, l)
+#endif
+
+
+static inline void xspi_write8(struct xilinx_spi *xspi, u32 offs, u8 val)
+{
+	if (xspi->model == XILINX_SPI_MODEL_DS464)
+		xspi_out8(xspi->regs + offs, val & 0xff);
+	else
+		xspi_out32(xspi->regs + offs, val);
+}
+
+static inline void xspi_write16(struct xilinx_spi *xspi, u32 offs, u16 val)
+{
+	if (xspi->model == XILINX_SPI_MODEL_DS464)
+		xspi_out16(xspi->regs + offs, val & 0xffff);
+	else
+		xspi_out32(xspi->regs + offs, val);
+}
+
+static inline void xspi_write32(struct xilinx_spi *xspi, u32 offs, u32 val)
+{
+	xspi_out32(xspi->regs + offs, val);
+}
+
+static inline u8 xspi_read8(struct xilinx_spi *xspi, u32 offs)
+{
+	if (xspi->model == XILINX_SPI_MODEL_DS464)
+		return xspi_in8(xspi->regs + offs);
+	else
+		return xspi_in32(xspi->regs + offs);
+}
+
+static inline u16 xspi_read16(struct xilinx_spi *xspi, u32 offs)
+{
+	if (xspi->model == XILINX_SPI_MODEL_DS464)
+		return xspi_in16(xspi->regs + offs);
+	else
+		return xspi_in32(xspi->regs + offs);
+}
+
+static inline u32 xspi_read32(struct xilinx_spi *xspi, u32 offs)
+{
+	return xspi_in32(xspi->regs + offs);
+}

 /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
  * Product Specification", DS464
  */
-#define XSPI_CR_OFFSET		0x62	/* 16-bit Control Register */
+#define XSPI_CR_OFFSET_DS464	0x62	/* 16-bit Control Register */
+#define XSPI_CR_OFFSET_DS570	0x60

 #define XSPI_CR_ENABLE		0x02
 #define XSPI_CR_MASTER_MODE	0x04
@@ -40,8 +121,10 @@
 #define XSPI_CR_RXFIFO_RESET	0x40
 #define XSPI_CR_MANUAL_SSELECT	0x80
 #define XSPI_CR_TRANS_INHIBIT	0x100
+#define XSPI_CR_LSB_FIRST	0x200

-#define XSPI_SR_OFFSET		0x67	/* 8-bit Status Register */
+#define XSPI_SR_OFFSET_DS464	0x67	/* 8-bit Status Register */
+#define XSPI_SR_OFFSET_DS570	0x64

 #define XSPI_SR_RX_EMPTY_MASK	0x01	/* Receive FIFO is empty */
 #define XSPI_SR_RX_FULL_MASK	0x02	/* Receive FIFO is full */
@@ -49,10 +132,13 @@
 #define XSPI_SR_TX_FULL_MASK	0x08	/* Transmit FIFO is full */
 #define XSPI_SR_MODE_FAULT_MASK	0x10	/* Mode fault error */

-#define XSPI_TXD_OFFSET		0x6b	/* 8-bit Data Transmit Register */
-#define XSPI_RXD_OFFSET		0x6f	/* 8-bit Data Receive Register */
+#define XSPI_TXD_OFFSET_DS464	0x6b	/* 8-bit Data Transmit Register */
+#define XSPI_TXD_OFFSET_DS570	0x68
+#define XSPI_RXD_OFFSET_DS464	0x6f	/* 8-bit Data Receive Register */
+#define XSPI_RXD_OFFSET_DS570	0x6C

-#define XSPI_SSR_OFFSET		0x70	/* 32-bit Slave Select Register */
+#define XSPI_SSR_OFFSET_DS464	0x70	/* 32-bit Slave Select Register */
+#define XSPI_SSR_OFFSET_DS570	0x70

 /* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
  * IPIF registers are 32 bit
@@ -70,43 +156,27 @@
 #define XSPI_INTR_TX_UNDERRUN		0x08	/* TxFIFO was underrun */
 #define XSPI_INTR_RX_FULL		0x10	/* RxFIFO is full */
 #define XSPI_INTR_RX_OVERRUN		0x20	/* RxFIFO was overrun */
+#define XSPI_INTR_TX_HALF_EMPTY		0x40	/* TxFIFO is half empty */

 #define XIPIF_V123B_RESETR_OFFSET	0x40	/* IPIF reset register */
 #define XIPIF_V123B_RESET_MASK		0x0a	/* the value to write */

-struct xilinx_spi {
-	/* bitbang has to be first */
-	struct spi_bitbang bitbang;
-	struct completion done;
-
-	void __iomem	*regs;	/* virt. address of the control registers */
-
-	u32		irq;
-
-	u32		speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
-
-	u8 *rx_ptr;		/* pointer in the Tx buffer */
-	const u8 *tx_ptr;	/* pointer in the Rx buffer */
-	int remaining_bytes;	/* the number of bytes left to transfer */
-};
-
-static void xspi_init_hw(void __iomem *regs_base)
+static void xspi_init_hw(struct xilinx_spi *xspi)
 {
 	/* Reset the SPI device */
-	out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
-		 XIPIF_V123B_RESET_MASK);
+	xspi_write32(xspi, XIPIF_V123B_RESETR_OFFSET, XIPIF_V123B_RESET_MASK);
 	/* Disable all the interrupts just in case */
-	out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
+	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, 0);
 	/* Enable the global IPIF interrupt */
-	out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
-		 XIPIF_V123B_GINTR_ENABLE);
+	xspi_write32(xspi, XIPIF_V123B_DGIER_OFFSET, XIPIF_V123B_GINTR_ENABLE);
 	/* Deselect the slave on the SPI bus */
-	out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+	xspi_write32(xspi, xspi->ssr_offset, 0xffff);
 	/* Disable the transmitter, enable Manual Slave Select Assertion,
 	 * put SPI controller into master mode, and enable it */
-	out_be16(regs_base + XSPI_CR_OFFSET,
-		 XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
-		 | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
+	xspi_write16(xspi, xspi->cr_offset,
+		 XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
+		 XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
+		 XSPI_CR_RXFIFO_RESET);
 }

 static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
@@ -115,16 +185,16 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)

 	if (is_on == BITBANG_CS_INACTIVE) {
 		/* Deselect the slave on the SPI bus */
-		out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
+		xspi_write32(xspi, xspi->ssr_offset, 0xffff);
 	} else if (is_on == BITBANG_CS_ACTIVE) {
 		/* Set the SPI clock phase and polarity */
-		u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
+		u32 cr = xspi_read16(xspi, xspi->cr_offset)
 			 & ~XSPI_CR_MODE_MASK;
 		if (spi->mode & SPI_CPHA)
 			cr |= XSPI_CR_CPHA;
 		if (spi->mode & SPI_CPOL)
 			cr |= XSPI_CR_CPOL;
-		out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+		xspi_write16(xspi, xspi->cr_offset, cr);

 		/* We do not check spi->max_speed_hz here as the SPI clock
 		 * frequency is not software programmable (the IP block design
@@ -132,24 +202,27 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
 		 */

 		/* Activate the chip select */
-		out_be32(xspi->regs + XSPI_SSR_OFFSET,
+		xspi_write32(xspi, xspi->ssr_offset,
 			 ~(0x0001 << spi->chip_select));
 	}
 }

 /* spi_bitbang requires custom setup_transfer() to be defined if there is a
  * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
- * supports just 8 bits per word, and SPI clock can't be changed in software.
- * Check for 8 bits per word. Chip select delay calculations could be
+ * supports 8 or 16 bits per word, which can not be changed in software.
+ * SPI clock can't be changed in software.
+ * Check for correct bits per word. Chip select delay calculations could be
  * added here as soon as bitbang_work() can be made aware of the delay value.
  */
 static int xilinx_spi_setup_transfer(struct spi_device *spi,
-		struct spi_transfer *t)
+	struct spi_transfer *t)
 {
 	u8 bits_per_word;
+	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);

-	bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
-	if (bits_per_word != 8) {
+	bits_per_word = (t->bits_per_word) ? t->bits_per_word :
+		spi->bits_per_word;
+	if (bits_per_word != xspi->bits_per_word) {
 		dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
 			__func__, bits_per_word);
 		return -EINVAL;
@@ -160,34 +233,50 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,

 static int xilinx_spi_setup(struct spi_device *spi)
 {
-	struct spi_bitbang *bitbang;
-	struct xilinx_spi *xspi;
-	int retval;
-
-	xspi = spi_master_get_devdata(spi->master);
-	bitbang = &xspi->bitbang;
-
-	retval = xilinx_spi_setup_transfer(spi, NULL);
-	if (retval < 0)
-		return retval;
-
+	/* always return 0, we can not check the number of bits.
+	 * There are cases when SPI setup is called before any driver is
+	 * there, in that case the SPI core defaults to 8 bits, which we
+	 * do not support in some cases. But if we return an error, the
+	 * SPI device would not be registered and no driver can get hold of it
+	 * When the driver is there, it will call SPI setup again with the
+	 * correct number of bits per transfer.
+	 * If a driver setups with the wrong bit number, it will fail when
+	 * it tries to do a transfer
+	 */
 	return 0;
 }

 static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
 {
-	u8 sr;
+	u32 sr;
+	u8 wsize;
+	if (xspi->bits_per_word == 8)
+		wsize = 1;
+	else if (xspi->bits_per_word == 16)
+		wsize = 2;
+	else
+		wsize = 4;

 	/* Fill the Tx FIFO with as many bytes as possible */
-	sr = in_8(xspi->regs + XSPI_SR_OFFSET);
-	while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
+	sr = xspi_read8(xspi, xspi->sr_offset);
+	while ((sr & XSPI_SR_TX_FULL_MASK) == 0 &&
+		xspi->remaining_bytes > 0) {
 		if (xspi->tx_ptr) {
-			out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
-		} else {
-			out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
-		}
-		xspi->remaining_bytes--;
-		sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+			if (wsize == 1)
+				xspi_write8(xspi, xspi->txd_offset,
+					*xspi->tx_ptr);
+			else if (wsize == 2)
+				xspi_write16(xspi, xspi->txd_offset,
+					*(u16 *)(xspi->tx_ptr));
+			else if (wsize == 4)
+				xspi_write32(xspi, xspi->txd_offset,
+					*(u32 *)(xspi->tx_ptr));
+
+			xspi->tx_ptr += wsize;
+		} else
+			xspi_write8(xspi, xspi->txd_offset, 0);
+		xspi->remaining_bytes -= wsize;
+		sr = xspi_read8(xspi, xspi->sr_offset);
 	}
 }

@@ -195,7 +284,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
 {
 	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
 	u32 ipif_ier;
-	u16 cr;
+	u32 cr;

 	/* We get here with transmitter inhibited */

@@ -209,23 +298,22 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
 	/* Enable the transmit empty interrupt, which we use to determine
 	 * progress on the transmission.
 	 */
-	ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
-	out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
+	ipif_ier = xspi_read32(xspi, XIPIF_V123B_IIER_OFFSET);
+	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET,
 		 ipif_ier | XSPI_INTR_TX_EMPTY);

 	/* Start the transfer by not inhibiting the transmitter any longer */
-	cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
-	out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+	cr = xspi_read16(xspi, xspi->cr_offset) & ~XSPI_CR_TRANS_INHIBIT;
+	xspi_write16(xspi, xspi->cr_offset, cr);

 	wait_for_completion(&xspi->done);

 	/* Disable the transmit empty interrupt */
-	out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
+	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, ipif_ier);

 	return t->len - xspi->remaining_bytes;
 }

-
 /* This driver supports single master mode only. Hence Tx FIFO Empty
  * is the only interrupt we care about.
  * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
@@ -237,32 +325,50 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
 	u32 ipif_isr;

 	/* Get the IPIF interrupts, and clear them immediately */
-	ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
-	out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
+	ipif_isr = xspi_read32(xspi, XIPIF_V123B_IISR_OFFSET);
+	xspi_write32(xspi, XIPIF_V123B_IISR_OFFSET, ipif_isr);

 	if (ipif_isr & XSPI_INTR_TX_EMPTY) {	/* Transmission completed */
-		u16 cr;
-		u8 sr;
+		u32 cr;
+		u32 sr;
+		u8 rsize;
+		if (xspi->bits_per_word == 8)
+			rsize = 1;
+		else if (xspi->bits_per_word == 16)
+			rsize = 2;
+		else
+			rsize = 4;

 		/* A transmit has just completed. Process received data and
 		 * check for more data to transmit. Always inhibit the
 		 * transmitter while the Isr refills the transmit register/FIFO,
 		 * or make sure it is stopped if we're done.
 		 */
-		cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
-		out_be16(xspi->regs + XSPI_CR_OFFSET,
-			 cr | XSPI_CR_TRANS_INHIBIT);
+		cr = xspi_read16(xspi, xspi->cr_offset);
+		xspi_write16(xspi, xspi->cr_offset, cr | XSPI_CR_TRANS_INHIBIT);

 		/* Read out all the data from the Rx FIFO */
-		sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+		sr = xspi_read8(xspi, xspi->sr_offset);
 		while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
-			u8 data;
+			u32 data;
+			if (rsize == 1)
+				data = xspi_read8(xspi, xspi->rxd_offset);
+			else if (rsize == 2)
+				data = xspi_read16(xspi, xspi->rxd_offset);
+			else
+				data = xspi_read32(xspi, xspi->rxd_offset);

-			data = in_8(xspi->regs + XSPI_RXD_OFFSET);
 			if (xspi->rx_ptr) {
-				*xspi->rx_ptr++ = data;
+				if (rsize == 1)
+					*xspi->rx_ptr = data & 0xff;
+				else if (rsize == 2)
+					*(u16 *)(xspi->rx_ptr) = data & 0xffff;
+				else
+					*((u32 *)(xspi->rx_ptr)) = data;
+				xspi->rx_ptr += rsize;
 			}
-			sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+
+			sr = xspi_read8(xspi, xspi->sr_offset);
 		}

 		/* See if there is more data to send */
@@ -271,7 +377,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
 			/* Start the transfer by not inhibiting the
 			 * transmitter any longer
 			 */
-			out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+			xspi_write16(xspi, xspi->cr_offset, cr);
 		} else {
 			/* No more data to send.
 			 * Indicate the transfer is completed.
@@ -279,44 +385,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
 			complete(&xspi->done);
 		}
 	}
-
 	return IRQ_HANDLED;
 }

-static int __init xilinx_spi_of_probe(struct of_device *ofdev,
-					const struct of_device_id *match)
+struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
+	u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word)
 {
 	struct spi_master *master;
 	struct xilinx_spi *xspi;
-	struct resource r_irq_struct;
-	struct resource r_mem_struct;
+	int ret = 0;

-	struct resource *r_irq = &r_irq_struct;
-	struct resource *r_mem = &r_mem_struct;
-	int rc = 0;
-	const u32 *prop;
-	int len;
+	master = spi_alloc_master(dev, sizeof(struct xilinx_spi));

-	/* Get resources(memory, IRQ) associated with the device */
-	master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
-
-	if (master == NULL) {
-		return -ENOMEM;
-	}
-
-	dev_set_drvdata(&ofdev->dev, master);
-
-	rc = of_address_to_resource(ofdev->node, 0, r_mem);
-	if (rc) {
-		dev_warn(&ofdev->dev, "invalid address\n");
-		goto put_master;
-	}
-
-	rc = of_irq_to_resource(ofdev->node, 0, r_irq);
-	if (rc == NO_IRQ) {
-		dev_warn(&ofdev->dev, "no IRQ found\n");
-		goto put_master;
-	}
+	if (master == NULL)
+		return ERR_PTR(-ENOMEM);

 	/* the spi->mode bits understood by this driver: */
 	master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -329,128 +411,87 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
 	xspi->bitbang.master->setup = xilinx_spi_setup;
 	init_completion(&xspi->done);

-	xspi->irq = r_irq->start;
-
-	if (!request_mem_region(r_mem->start,
-			r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
-		rc = -ENXIO;
-		dev_warn(&ofdev->dev, "memory request failure\n");
+	if (!request_mem_region(mem->start, resource_size(mem),
+		XILINX_SPI_NAME)) {
+		ret = -ENXIO;
 		goto put_master;
 	}

-	xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
+	xspi->regs = ioremap(mem->start, resource_size(mem));
 	if (xspi->regs == NULL) {
-		rc = -ENOMEM;
-		dev_warn(&ofdev->dev, "ioremap failure\n");
-		goto release_mem;
+		ret = -ENOMEM;
+		dev_warn(dev, "ioremap failure\n");
+		goto map_failed;
 	}
-	xspi->irq = r_irq->start;
-
-	/* dynamic bus assignment */
-	master->bus_num = -1;

-	/* number of slave select bits is required */
-	prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
-	if (!prop || len < sizeof(*prop)) {
-		dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
-		goto unmap_io;
+	master->bus_num = bus_num;
+	master->num_chipselect = num_chipselect;
+
+	xspi->mem = *mem;
+	xspi->irq = irq;
+	xspi->bits_per_word = bits_per_word;
+	xspi->model = model;
+
+	if (model == XILINX_SPI_MODEL_DS464) {
+		xspi->cr_offset = XSPI_CR_OFFSET_DS464;
+		xspi->sr_offset = XSPI_SR_OFFSET_DS464;
+		xspi->txd_offset = XSPI_TXD_OFFSET_DS464;
+		xspi->rxd_offset = XSPI_RXD_OFFSET_DS464;
+		xspi->ssr_offset = XSPI_SSR_OFFSET_DS464;
+	} else {
+		xspi->cr_offset = XSPI_CR_OFFSET_DS570;
+		xspi->sr_offset = XSPI_SR_OFFSET_DS570;
+		xspi->txd_offset = XSPI_TXD_OFFSET_DS570;
+		xspi->rxd_offset = XSPI_RXD_OFFSET_DS570;
+		xspi->ssr_offset = XSPI_SSR_OFFSET_DS570;
 	}
-	master->num_chipselect = *prop;

 	/* SPI controller initializations */
-	xspi_init_hw(xspi->regs);
+	xspi_init_hw(xspi);

 	/* Register for SPI Interrupt */
-	rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
-	if (rc != 0) {
-		dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
+	ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+	if (ret != 0)
 		goto unmap_io;
-	}

-	rc = spi_bitbang_start(&xspi->bitbang);
-	if (rc != 0) {
-		dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
+	ret = spi_bitbang_start(&xspi->bitbang);
+	if (ret != 0) {
+		dev_err(dev, "spi_bitbang_start FAILED\n");
 		goto free_irq;
 	}

-	dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
-			(unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
-
-	/* Add any subnodes on the SPI bus */
-	of_register_spi_devices(master, ofdev->node);
-
-	return rc;
+	dev_info(dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
+		(u32)mem->start, (u32)xspi->regs, xspi->irq);
+	return master;

 free_irq:
 	free_irq(xspi->irq, xspi);
 unmap_io:
 	iounmap(xspi->regs);
-release_mem:
-	release_mem_region(r_mem->start, resource_size(r_mem));
+map_failed:
+	release_mem_region(mem->start, resource_size(mem));
 put_master:
 	spi_master_put(master);
-	return rc;
+	return ERR_PTR(ret);
 }
+EXPORT_SYMBOL(xilinx_spi_init);

-static int __devexit xilinx_spi_remove(struct of_device *ofdev)
+void xilinx_spi_deinit(struct spi_master *master)
 {
 	struct xilinx_spi *xspi;
-	struct spi_master *master;
-	struct resource r_mem;

-	master = platform_get_drvdata(ofdev);
 	xspi = spi_master_get_devdata(master);

 	spi_bitbang_stop(&xspi->bitbang);
 	free_irq(xspi->irq, xspi);
 	iounmap(xspi->regs);
-	if (!of_address_to_resource(ofdev->node, 0, &r_mem))
-		release_mem_region(r_mem.start, resource_size(&r_mem));
-	dev_set_drvdata(&ofdev->dev, 0);
-	spi_master_put(xspi->bitbang.master);
-
-	return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" XILINX_SPI_NAME);
-
-static int __exit xilinx_spi_of_remove(struct of_device *op)
-{
-	return xilinx_spi_remove(op);
-}
-
-static struct of_device_id xilinx_spi_of_match[] = {
-	{ .compatible = "xlnx,xps-spi-2.00.a", },
-	{ .compatible = "xlnx,xps-spi-2.00.b", },
-	{}
-};
-
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-
-static struct of_platform_driver xilinx_spi_of_driver = {
-	.owner = THIS_MODULE,
-	.name = "xilinx-xps-spi",
-	.match_table = xilinx_spi_of_match,
-	.probe = xilinx_spi_of_probe,
-	.remove = __exit_p(xilinx_spi_of_remove),
-	.driver = {
-		.name = "xilinx-xps-spi",
-		.owner = THIS_MODULE,
-	},
-};

-static int __init xilinx_spi_init(void)
-{
-	return of_register_platform_driver(&xilinx_spi_of_driver);
+	release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
+	spi_master_put(xspi->bitbang.master);
 }
-module_init(xilinx_spi_init);
+EXPORT_SYMBOL(xilinx_spi_deinit);

-static void __exit xilinx_spi_exit(void)
-{
-	of_unregister_platform_driver(&xilinx_spi_of_driver);
-}
-module_exit(xilinx_spi_exit);
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
 MODULE_DESCRIPTION("Xilinx SPI driver");
 MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
new file mode 100644
index 0000000..d951b11
--- /dev/null
+++ b/drivers/spi/xilinx_spi.h
@@ -0,0 +1,32 @@
+/*
+ * xilinx_spi.h
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _XILINX_SPI_H_
+#define _XILINX_SPI_H_ 1
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/xilinx_spi.h>
+
+#define XILINX_SPI_NAME "xilinx_spi"
+
+struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
+	u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word);
+
+void xilinx_spi_deinit(struct spi_master *master);
+#endif
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
new file mode 100644
index 0000000..4f54ddd
--- /dev/null
+++ b/drivers/spi/xilinx_spi_of.c
@@ -0,0 +1,120 @@
+/*
+ * xilinx_spi_of.c
+ *
+ * Xilinx SPI controller driver (master mode only)
+ *
+ * Author: MontaVista Software, Inc.
+ *	source@mvista.com
+ *
+ * 2002-2007 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_spi.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include "xilinx_spi.h"
+
+
+static int __init xilinx_spi_of_probe(struct of_device *ofdev,
+					const struct of_device_id *match)
+{
+	struct resource r_irq_struct;
+	struct resource r_mem_struct;
+	struct spi_master *master;
+
+	struct resource *r_irq = &r_irq_struct;
+	struct resource *r_mem = &r_mem_struct;
+	int rc = 0;
+	const u32 *prop;
+	int len;
+
+	rc = of_address_to_resource(ofdev->node, 0, r_mem);
+	if (rc) {
+		dev_warn(&ofdev->dev, "invalid address\n");
+		return rc;
+	}
+
+	rc = of_irq_to_resource(ofdev->node, 0, r_irq);
+	if (rc == NO_IRQ) {
+		dev_warn(&ofdev->dev, "no IRQ found\n");
+		return -ENODEV;
+	}
+
+	/* number of slave select bits is required */
+	prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
+	if (!prop || len < sizeof(*prop)) {
+		dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
+		return -EINVAL;
+	}
+	master = xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start,
+		XILINX_SPI_MODEL_DS464, -1, *prop, 8);
+	if (IS_ERR(master))
+		return PTR_ERR(master);
+
+	dev_set_drvdata(&ofdev->dev, master);
+
+	/* Add any subnodes on the SPI bus */
+	of_register_spi_devices(master, ofdev->node);
+
+	return 0;
+}
+
+static int __devexit xilinx_spi_remove(struct of_device *ofdev)
+{
+	xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
+	dev_set_drvdata(&ofdev->dev, 0);
+	return 0;
+}
+
+static int __exit xilinx_spi_of_remove(struct of_device *op)
+{
+	return xilinx_spi_remove(op);
+}
+
+static struct of_device_id xilinx_spi_of_match[] = {
+	{ .compatible = "xlnx,xps-spi-2.00.a", },
+	{ .compatible = "xlnx,xps-spi-2.00.b", },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+
+static struct of_platform_driver xilinx_spi_of_driver = {
+	.owner = THIS_MODULE,
+	.name = "xilinx-xps-spi",
+	.match_table = xilinx_spi_of_match,
+	.probe = xilinx_spi_of_probe,
+	.remove = __exit_p(xilinx_spi_of_remove),
+	.driver = {
+		.name = "xilinx-xps-spi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init xilinx_spi_of_init(void)
+{
+	return of_register_platform_driver(&xilinx_spi_of_driver);
+}
+module_init(xilinx_spi_of_init);
+
+static void __exit xilinx_spi_of_exit(void)
+{
+	of_unregister_platform_driver(&xilinx_spi_of_driver);
+}
+module_exit(xilinx_spi_of_exit);
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("Xilinx SPI driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltfm.c
new file mode 100644
index 0000000..d59d509
--- /dev/null
+++ b/drivers/spi/xilinx_spi_pltfm.c
@@ -0,0 +1,104 @@
+/*
+ * xilinx_spi_pltfm.c Support for Xilinx SPI platform devices
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Xilinx SPI devices as platform devices
+ *
+ * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/xilinx_spi.h>
+
+#include "xilinx_spi.h"
+
+static int __devinit xilinx_spi_probe(struct platform_device *dev)
+{
+	struct xspi_platform_data *pdata;
+	struct resource *r;
+	int irq;
+	struct spi_master *master;
+	u8 i;
+
+	pdata = dev->dev.platform_data;
+	if (pdata == NULL)
+		return -ENODEV;
+
+	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (r == NULL)
+		return -ENODEV;
+
+	irq = platform_get_irq(dev, 0);
+	if (irq < 0)
+		return -ENXIO;
+
+	master = xilinx_spi_init(&dev->dev, r, irq, pdata->model,
+		dev->id, pdata->num_chipselect, pdata->bits_per_word);
+	if (IS_ERR(master))
+		return PTR_ERR(master);
+
+	for (i = 0; i < pdata->num_devices; i++)
+		spi_new_device(master, pdata->devices + i);
+
+	platform_set_drvdata(dev, master);
+	return 0;
+}
+
+static int __devexit xilinx_spi_remove(struct platform_device *dev)
+{
+	xilinx_spi_deinit(platform_get_drvdata(dev));
+	platform_set_drvdata(dev, 0);
+
+	return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" XILINX_SPI_NAME);
+
+static struct platform_driver xilinx_spi_driver = {
+	.probe	= xilinx_spi_probe,
+	.remove	= __devexit_p(xilinx_spi_remove),
+	.driver = {
+		.name = XILINX_SPI_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init xilinx_spi_pltfm_init(void)
+{
+	return platform_driver_register(&xilinx_spi_driver);
+}
+module_init(xilinx_spi_pltfm_init);
+
+static void __exit xilinx_spi_pltfm_exit(void)
+{
+	platform_driver_unregister(&xilinx_spi_driver);
+}
+module_exit(xilinx_spi_pltfm_exit);
+
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_DESCRIPTION("Xilinx SPI platform driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h
new file mode 100644
index 0000000..e9e6a84
--- /dev/null
+++ b/include/linux/spi/xilinx_spi.h
@@ -0,0 +1,18 @@
+#ifndef __LINUX_SPI_XILINX_SPI_H
+#define __LINUX_SPI_XILINX_SPI_H
+
+#define XILINX_SPI_MODEL_DS464 0
+#define XILINX_SPI_MODEL_DS570 1
+
+/* SPI Controller IP */
+struct xspi_platform_data {
+	u16 num_chipselect;
+	u8 model;
+	u8 bits_per_word;
+	/* devices to add to the bus when the host is up */
+	struct spi_board_info *devices;
+	u8 num_devices;
+};
+
+#endif /* __LINUX_SPI_XILINX_SPI_H */
+

^ permalink raw reply related

* [PATCH] POWERPC: includecheck fix: mm, tlb_low_64e.S
From: Jaswinder Singh Rajput @ 2009-09-22 13:45 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev, LKML


fix the following 'make includecheck' warning:

  arch/powerpc/mm/tlb_low_64e.S: asm/reg.h is included more than once.

Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com>
---
 arch/powerpc/mm/tlb_low_64e.S |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
index ef1cccf..f288279 100644
--- a/arch/powerpc/mm/tlb_low_64e.S
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -18,7 +18,6 @@
 #include <asm/asm-offsets.h>
 #include <asm/cputable.h>
 #include <asm/pgtable.h>
-#include <asm/reg.h>
 #include <asm/exception-64e.h>
 #include <asm/ppc-opcode.h>
 
-- 
1.6.0.6

^ permalink raw reply related

* [PATCH] POWERPC: includecheck fix: exceptions-64e.S
From: Jaswinder Singh Rajput @ 2009-09-22 13:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev, LKML


fix the following 'make includecheck' warning:

  arch/powerpc/kernel/exceptions-64e.S: asm/reg.h is included more than once.

Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com>
---
 arch/powerpc/kernel/exceptions-64e.S |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 9048f96..24dcc0e 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -17,7 +17,6 @@
 #include <asm/cputable.h>
 #include <asm/setup.h>
 #include <asm/thread_info.h>
-#include <asm/reg.h>
 #include <asm/exception-64e.h>
 #include <asm/bug.h>
 #include <asm/irqflags.h>
-- 
1.6.0.6

^ permalink raw reply related

* Re: powerpc: Move 64bit heap above 1TB on machines with 1TB segments
From: Mel Gorman @ 2009-09-22 14:47 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: linuxppc-dev
In-Reply-To: <20090922025235.GD31801@kryten>

Anton Blanchard <anton@samba.org> wrote on 22/09/2009 03:52:35:

> If we are using 1TB segments and we are allowed to randomise the heap, we
can
> put it above 1TB so it is backed by a 1TB segment. Otherwise the heap
will be
> in the bottom 1TB which always uses 256MB segments and this may result in
a
> performance penalty.
>
> This functionality is disabled when heap randomisation is turned off:
>
> echo 1 > /proc/sys/kernel/randomize_va_space
>
> which may be useful when trying to allocate the maximum amount of 16M or
16G
> pages.
>
> On a microbenchmark that repeatedly touches 32GB of memory with a stride
of
> 256MB + 4kB (designed to stress 256MB segments while still mapping nicely
into
> the L1 cache), we see the improvement:
>
> Force malloc to use heap all the time:
> # export MALLOC_MMAP_MAX_=0 MALLOC_TRIM_THRESHOLD_=-1
>
> Disable heap randomization:
> # echo 1 > /proc/sys/kernel/randomize_va_space
> # time ./test
> 12.51s
>
> Enable heap randomization:
> # echo 2 > /proc/sys/kernel/randomize_va_space
> # time ./test
> 1.70s
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
>
> I've cc-ed Mel on this one. As you can see it definitely helps the base
> page size performance, but I'm a bit worried of the impact of taking away
> another of our 1TB slices.
>

Unfortunately, I am not sensitive to issues surrounding 1TB segments or how
they are currently being used. However, as this clearly helps performance
for large amounts of memory, is it worth providing an option to
libhugetlbfs to locate 16MB pages above 1TB when they are otherwise being
unused?

> Index: linux.trees.git/arch/powerpc/kernel/process.c
> ===================================================================
> --- linux.trees.git.orig/arch/powerpc/kernel/process.c   2009-09-17
> 15:47:46.000000000 +1000
> +++ linux.trees.git/arch/powerpc/kernel/process.c   2009-09-17 15:
> 49:11.000000000 +1000
> @@ -1165,7 +1165,22 @@ static inline unsigned long brk_rnd(void
>
>  unsigned long arch_randomize_brk(struct mm_struct *mm)
>  {
> -   unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
> +   unsigned long base = mm->brk;
> +   unsigned long ret;
> +
> +#ifdef CONFIG_PPC64
> +   /*
> +    * If we are using 1TB segments and we are allowed to randomise
> +    * the heap, we can put it above 1TB so it is backed by a 1TB
> +    * segment. Otherwise the heap will be in the bottom 1TB
> +    * which always uses 256MB segments and this may result in a
> +    * performance penalty.
> +    */
> +   if (!is_32bit_task() && (mmu_highuser_ssize == MMU_SEGSIZE_1T))
> +      base = max_t(unsigned long, mm->brk, 1UL << SID_SHIFT_1T);
> +#endif
> +
> +   ret = PAGE_ALIGN(base + brk_rnd());
>
>     if (ret < mm->brk)
>        return mm->brk;

^ permalink raw reply

* [PATCH] powerpc: Cleanup linker script using new linker script macros.
From: Tim Abbott @ 2009-09-22 15:18 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Paul Mackerras, linux-kernel, Sam Ravnborg, Tim Abbott
In-Reply-To: <1253632689-24173-1-git-send-email-tabbott@ksplice.com>

Signed-off-by: Tim Abbott <tabbott@ksplice.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@ozlabs.org
Cc: Sam Ravnborg <sam@ravnborg.org>
---
 arch/powerpc/kernel/vmlinux.lds.S |   69 ++++++++-----------------------------
 1 files changed, 15 insertions(+), 54 deletions(-)

diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 58da407..f564293 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -6,6 +6,7 @@
 #include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/cache.h>
+#include <asm/thread_info.h>
 
 ENTRY(_stext)
 
@@ -71,12 +72,7 @@ SECTIONS
 	/* Read-only data */
 	RODATA
 
-	/* Exception & bug tables */
-	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
-		__start___ex_table = .;
-		*(__ex_table)
-		__stop___ex_table = .;
-	}
+	EXCEPTION_TABLE(0)
 
 	NOTES :kernel :notes
 
@@ -93,12 +89,7 @@ SECTIONS
  */
 	. = ALIGN(PAGE_SIZE);
 	__init_begin = .;
-
-	.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
-		_sinittext = .;
-		INIT_TEXT
-		_einittext = .;
-	} :kernel
+	INIT_TEXT_SECTION(PAGE_SIZE) :kernel
 
 	/* .exit.text is discarded at runtime, not link time,
 	 * to deal with references from __bug_table
@@ -122,23 +113,16 @@ SECTIONS
 #endif
 	}
 
-	. = ALIGN(16);
 	.init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
-		__setup_start = .;
-		*(.init.setup)
-		__setup_end = .;
+		INIT_SETUP(16)
 	}
 
 	.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
-		__initcall_start = .;
-		INITCALLS
-		__initcall_end = .;
-		}
+		INIT_CALLS
+	}
 
 	.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
-		__con_initcall_start = .;
-		*(.con_initcall.init)
-		__con_initcall_end = .;
+		CON_INITCALL
 	}
 
 	SECURITY_INIT
@@ -169,14 +153,10 @@ SECTIONS
 		__stop___fw_ftr_fixup = .;
 	}
 #endif
-#ifdef CONFIG_BLK_DEV_INITRD
-	. = ALIGN(PAGE_SIZE);
 	.init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
-		__initramfs_start = .;
-		*(.init.ramfs)
-		__initramfs_end = .;
+		INIT_RAM_FS
 	}
-#endif
+
 	PERCPU(PAGE_SIZE)
 
 	. = ALIGN(8);
@@ -240,36 +220,24 @@ SECTIONS
 #endif
 
 	/* The initial task and kernel stack */
-#ifdef CONFIG_PPC32
-	. = ALIGN(8192);
-#else
-	. = ALIGN(16384);
-#endif
 	.data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
-		*(.data.init_task)
+		INIT_TASK_DATA(THREAD_SIZE)
 	}
 
-	. = ALIGN(PAGE_SIZE);
 	.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-		*(.data.page_aligned)
+		PAGE_ALIGNED_DATA(PAGE_SIZE)
 	}
 
-	. = ALIGN(L1_CACHE_BYTES);
 	.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-		*(.data.cacheline_aligned)
+		CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
 	}
 
-	. = ALIGN(L1_CACHE_BYTES);
 	.data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
-		*(.data.read_mostly)
+		READ_MOSTLY_DATA(L1_CACHE_BYTES)
 	}
 
-	. = ALIGN(PAGE_SIZE);
 	.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
-		__nosave_begin = .;
-		*(.data.nosave)
-		. = ALIGN(PAGE_SIZE);
-		__nosave_end = .;
+		NOSAVE_DATA
 	}
 
 	. = ALIGN(PAGE_SIZE);
@@ -280,14 +248,7 @@ SECTIONS
  * And finally the bss
  */
 
-	.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
-		__bss_start = .;
-		*(.sbss) *(.scommon)
-		*(.dynbss)
-		*(.bss)
-		*(COMMON)
-		__bss_stop = .;
-	}
+	BSS_SECTION(0, 0, 0)
 
 	. = ALIGN(PAGE_SIZE);
 	_end = . ;
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH v2] Linker script cleanup for powerpc
From: Tim Abbott @ 2009-09-22 15:18 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Paul Mackerras, linux-kernel, Sam Ravnborg, Tim Abbott

This is an updated version of the patch I sent on September 6 cleaning
up the powerpc architecture's linker scripts.  The only change is that
it is rebased on top of Linus's current master.

This cross-architecture linker script cleanup project is in
preparation for adding support for building the kernel with
-ffunction-sections -fdata-sections, which is a prerequisite for
Ksplice.

	-Tim Abbott

Tim Abbott (1):
  powerpc: Cleanup linker script using new linker script macros.

 arch/powerpc/kernel/vmlinux.lds.S |   69 ++++++++-----------------------------
 1 files changed, 15 insertions(+), 54 deletions(-)

^ permalink raw reply

* [PATCH] net: xilinx_emaclite: Fix problem with first incoming packet
From: John Linn @ 2009-09-22 15:24 UTC (permalink / raw)
  To: netdev, davem, linuxppc-dev, grant.likely, jwboyer,
	sadanand.mutyala
  Cc: Michal Simek

From: Michal Simek <monstr@monstr.eu>

You can't ping the board or connect to it unless you send
any packet out from board.

Tested-by: John Williams <john.williams@petalogix.com>
Signed-off-by: Michal Simek <monstr@monstr.eu>
Acked-by: John Linn <john.linn@xilinx.com>
---
 drivers/net/xilinx_emaclite.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index dc22782..83a044d 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -134,18 +134,15 @@ static void xemaclite_enable_interrupts(struct net_local *drvdata)
 	}
 
 	/* Enable the Rx interrupts for the first buffer */
-	reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET);
 	out_be32(drvdata->base_addr + XEL_RSR_OFFSET,
-		 reg_data | XEL_RSR_RECV_IE_MASK);
+		 XEL_RSR_RECV_IE_MASK);
 
 	/* Enable the Rx interrupts for the second Buffer if
 	 * configured in HW */
 	if (drvdata->rx_ping_pong != 0) {
-		reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
-				   XEL_RSR_OFFSET);
 		out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
 			 XEL_RSR_OFFSET,
-			 reg_data | XEL_RSR_RECV_IE_MASK);
+			 XEL_RSR_RECV_IE_MASK);
 	}
 
 	/* Enable the Global Interrupt Enable */
-- 
1.6.2.1



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

^ permalink raw reply related

* RE: [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for DS570
From: John Linn @ 2009-09-22 16:00 UTC (permalink / raw)
  To: Richard Röjfors, spi-devel-general
  Cc: linuxppc-dev, Andrew Morton, dbrownell
In-Reply-To: <4AB8C936.5090409@mocean-labs.com>

> -----Original Message-----
> From: linuxppc-dev-bounces+john.linn=3Dxilinx.com@lists.ozlabs.org [mailt=
o:linuxppc-dev-
> bounces+john.linn=3Dxilinx.com@lists.ozlabs.org] On Behalf Of Richard R=
=F6jfors
> Sent: Tuesday, September 22, 2009 6:55 AM
> To: spi-devel-general@lists.sourceforge.net
> Cc: linuxppc-dev@ozlabs.org; Andrew Morton; dbrownell@users.sourceforge.n=
et
> Subject: [PATCH v3] xilinx_spi: Splitted into generic, of and platform dr=
iver, added support for
> DS570
> =

> This patch splits xilinx_spi into three parts, an OF and a platform
> driver and generic part.
> =

> The generic part now also works on X86 and also supports the Xilinx
> SPI IP DS570

Hi Richard,

The current driver (without this change) works for the newer XPS SPI device=
 already as I run tests on it each day using an SPI EEPROM. =


Do you think that's not the case, or it doesn't work for some other type of=
 devices that I'm not testing with?

I'll hold off commenting on the rest of the code changes for a bit.

Thanks,
John

> =

> Signed-off-by: Richard R=F6jfors <richard.rojfors.ext@mocean-labs.com>
> ---
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 2c733c2..eca491b 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -218,8 +218,8 @@ config SPI_TXX9
>  	  SPI driver for Toshiba TXx9 MIPS SoCs
> =

>  config SPI_XILINX
> -	tristate "Xilinx SPI controller"
> -	depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
> +	tristate "Xilinx SPI controller common module"
> +	depends on (XILINX_VIRTEX || MICROBLAZE || HAS_IOMEM) && EXPERIMENTAL
>  	select SPI_BITBANG
>  	help
>  	  This exposes the SPI controller IP from the Xilinx EDK.
> @@ -227,6 +227,22 @@ config SPI_XILINX
>  	  See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
>  	  Product Specification document (DS464) for hardware details.
> =

> +	  Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)=
"
> +
> +
> +config SPI_XILINX_OF
> +	tristate "Xilinx SPI controller OF device"
> +	depends on SPI_XILINX && XILINX_VIRTEX
> +	help
> +	  This is the OF driver for the SPI controller IP from the Xilinx EDK.
> +
> +config SPI_XILINX_PLTFM
> +	tristate "Xilinx SPI controller platform device"
> +	depends on SPI_XILINX
> +	help
> +	  This is the platform driver for the SPI controller IP
> +	  from the Xilinx EDK.
> +
>  #
>  # Add new SPI master controllers in alphabetical order above this line
>  #
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 3de408d..5a91cf5 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -30,6 +30,8 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)		+=3D spi_s3c24xx_gpio.o=

>  obj-$(CONFIG_SPI_S3C24XX)		+=3D spi_s3c24xx.o
>  obj-$(CONFIG_SPI_TXX9)			+=3D spi_txx9.o
>  obj-$(CONFIG_SPI_XILINX)		+=3D xilinx_spi.o
> +obj-$(CONFIG_SPI_XILINX_OF)		+=3D xilinx_spi_of.o
> +obj-$(CONFIG_SPI_XILINX_PLTFM)		+=3D xilinx_spi_pltfm.o
>  obj-$(CONFIG_SPI_SH_SCI)		+=3D spi_sh_sci.o
>  # 	... add above this line ...
> =

> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> index 46b8c5c..0490820 100644
> --- a/drivers/spi/xilinx_spi.c
> +++ b/drivers/spi/xilinx_spi.c
> @@ -14,22 +14,103 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/interrupt.h>
> -#include <linux/platform_device.h>
> -
> -#include <linux/of_platform.h>
> -#include <linux/of_device.h>
> -#include <linux/of_spi.h>
> =

>  #include <linux/spi/spi.h>
>  #include <linux/spi/spi_bitbang.h>
>  #include <linux/io.h>
> =

> -#define XILINX_SPI_NAME "xilinx_spi"
> +#include "xilinx_spi.h"
> +
> +struct xilinx_spi {
> +	/* bitbang has to be first */
> +	struct spi_bitbang bitbang;
> +	struct completion done;
> +	struct resource mem; /* phys mem */
> +	void __iomem	*regs;	/* virt. address of the control registers */
> +	u32 irq;
> +	u8 *rx_ptr;		/* pointer in the Tx buffer */
> +	const u8 *tx_ptr;	/* pointer in the Rx buffer */
> +	int remaining_bytes;	/* the number of bytes left to transfer */
> +	/* offset to the XSPI regs, these might vary... */
> +	u8 cr_offset;
> +	u8 sr_offset;
> +	u8 txd_offset;
> +	u8 rxd_offset;
> +	u8 ssr_offset;
> +	u8 bits_per_word;
> +	u8 model;
> +};
> +
> +#ifdef CONFIG_X86
> +/* on X86 the block often resides behind a PCI(e) interface which flips =
the
> + * endian from little to big
> + */
> +#define xspi_in8(addr) ioread8(addr)
> +#define xspi_in16(addr) ioread16(addr)
> +#define xspi_in32(addr) ioread32(addr)
> +
> +#define xspi_out8(addr, b) iowrite8(b, addr)
> +#define xspi_out16(addr, w) iowrite16(w, addr)
> +#define xspi_out32(addr, l) iowrite32(l, addr)
> +#else
> +/* While on for instance PPC we use big endian */
> +#define xspi_in8(addr) in_8(addr)
> +#define xspi_in16(addr) in_be16(addr)
> +#define xspi_in32(addr) in_be32(addr)
> +
> +#define xspi_out8(addr, b) out_8(addr, b)
> +#define xspi_out16(addr, w) out_be16(addr, w)
> +#define xspi_out32(addr, l) out_be32(addr, l)
> +#endif
> +
> +
> +static inline void xspi_write8(struct xilinx_spi *xspi, u32 offs, u8 val=
)
> +{
> +	if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> +		xspi_out8(xspi->regs + offs, val & 0xff);
> +	else
> +		xspi_out32(xspi->regs + offs, val);
> +}
> +
> +static inline void xspi_write16(struct xilinx_spi *xspi, u32 offs, u16 v=
al)
> +{
> +	if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> +		xspi_out16(xspi->regs + offs, val & 0xffff);
> +	else
> +		xspi_out32(xspi->regs + offs, val);
> +}
> +
> +static inline void xspi_write32(struct xilinx_spi *xspi, u32 offs, u32 v=
al)
> +{
> +	xspi_out32(xspi->regs + offs, val);
> +}
> +
> +static inline u8 xspi_read8(struct xilinx_spi *xspi, u32 offs)
> +{
> +	if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> +		return xspi_in8(xspi->regs + offs);
> +	else
> +		return xspi_in32(xspi->regs + offs);
> +}
> +
> +static inline u16 xspi_read16(struct xilinx_spi *xspi, u32 offs)
> +{
> +	if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> +		return xspi_in16(xspi->regs + offs);
> +	else
> +		return xspi_in32(xspi->regs + offs);
> +}
> +
> +static inline u32 xspi_read32(struct xilinx_spi *xspi, u32 offs)
> +{
> +	return xspi_in32(xspi->regs + offs);
> +}
> =

>  /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v=
1.00e)
>   * Product Specification", DS464
>   */
> -#define XSPI_CR_OFFSET		0x62	/* 16-bit Control Register */
> +#define XSPI_CR_OFFSET_DS464	0x62	/* 16-bit Control Register */
> +#define XSPI_CR_OFFSET_DS570	0x60
> =

>  #define XSPI_CR_ENABLE		0x02
>  #define XSPI_CR_MASTER_MODE	0x04
> @@ -40,8 +121,10 @@
>  #define XSPI_CR_RXFIFO_RESET	0x40
>  #define XSPI_CR_MANUAL_SSELECT	0x80
>  #define XSPI_CR_TRANS_INHIBIT	0x100
> +#define XSPI_CR_LSB_FIRST	0x200
> =

> -#define XSPI_SR_OFFSET		0x67	/* 8-bit Status Register */
> +#define XSPI_SR_OFFSET_DS464	0x67	/* 8-bit Status Register */
> +#define XSPI_SR_OFFSET_DS570	0x64
> =

>  #define XSPI_SR_RX_EMPTY_MASK	0x01	/* Receive FIFO is empty */
>  #define XSPI_SR_RX_FULL_MASK	0x02	/* Receive FIFO is full */
> @@ -49,10 +132,13 @@
>  #define XSPI_SR_TX_FULL_MASK	0x08	/* Transmit FIFO is full */
>  #define XSPI_SR_MODE_FAULT_MASK	0x10	/* Mode fault error */
> =

> -#define XSPI_TXD_OFFSET		0x6b	/* 8-bit Data Transmit Register */
> -#define XSPI_RXD_OFFSET		0x6f	/* 8-bit Data Receive Register */
> +#define XSPI_TXD_OFFSET_DS464	0x6b	/* 8-bit Data Transmit Register */
> +#define XSPI_TXD_OFFSET_DS570	0x68
> +#define XSPI_RXD_OFFSET_DS464	0x6f	/* 8-bit Data Receive Register */
> +#define XSPI_RXD_OFFSET_DS570	0x6C
> =

> -#define XSPI_SSR_OFFSET		0x70	/* 32-bit Slave Select Register */
> +#define XSPI_SSR_OFFSET_DS464	0x70	/* 32-bit Slave Select Register */
> +#define XSPI_SSR_OFFSET_DS570	0x70
> =

>  /* Register definitions as per "OPB IPIF (v3.01c) Product Specification"=
, DS414
>   * IPIF registers are 32 bit
> @@ -70,43 +156,27 @@
>  #define XSPI_INTR_TX_UNDERRUN		0x08	/* TxFIFO was underrun */
>  #define XSPI_INTR_RX_FULL		0x10	/* RxFIFO is full */
>  #define XSPI_INTR_RX_OVERRUN		0x20	/* RxFIFO was overrun */
> +#define XSPI_INTR_TX_HALF_EMPTY		0x40	/* TxFIFO is half empty */
> =

>  #define XIPIF_V123B_RESETR_OFFSET	0x40	/* IPIF reset register */
>  #define XIPIF_V123B_RESET_MASK		0x0a	/* the value to write */
> =

> -struct xilinx_spi {
> -	/* bitbang has to be first */
> -	struct spi_bitbang bitbang;
> -	struct completion done;
> -
> -	void __iomem	*regs;	/* virt. address of the control registers */
> -
> -	u32		irq;
> -
> -	u32		speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
> -
> -	u8 *rx_ptr;		/* pointer in the Tx buffer */
> -	const u8 *tx_ptr;	/* pointer in the Rx buffer */
> -	int remaining_bytes;	/* the number of bytes left to transfer */
> -};
> -
> -static void xspi_init_hw(void __iomem *regs_base)
> +static void xspi_init_hw(struct xilinx_spi *xspi)
>  {
>  	/* Reset the SPI device */
> -	out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
> -		 XIPIF_V123B_RESET_MASK);
> +	xspi_write32(xspi, XIPIF_V123B_RESETR_OFFSET, XIPIF_V123B_RESET_MASK);
>  	/* Disable all the interrupts just in case */
> -	out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
> +	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, 0);
>  	/* Enable the global IPIF interrupt */
> -	out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
> -		 XIPIF_V123B_GINTR_ENABLE);
> +	xspi_write32(xspi, XIPIF_V123B_DGIER_OFFSET, XIPIF_V123B_GINTR_ENABLE);=

>  	/* Deselect the slave on the SPI bus */
> -	out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
> +	xspi_write32(xspi, xspi->ssr_offset, 0xffff);
>  	/* Disable the transmitter, enable Manual Slave Select Assertion,
>  	 * put SPI controller into master mode, and enable it */
> -	out_be16(regs_base + XSPI_CR_OFFSET,
> -		 XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
> -		 | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
> +	xspi_write16(xspi, xspi->cr_offset,
> +		 XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
> +		 XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
> +		 XSPI_CR_RXFIFO_RESET);
>  }
> =

>  static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
> @@ -115,16 +185,16 @@ static void xilinx_spi_chipselect(struct spi_device=
 *spi, int is_on)
> =

>  	if (is_on =3D=3D BITBANG_CS_INACTIVE) {
>  		/* Deselect the slave on the SPI bus */
> -		out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
> +		xspi_write32(xspi, xspi->ssr_offset, 0xffff);
>  	} else if (is_on =3D=3D BITBANG_CS_ACTIVE) {
>  		/* Set the SPI clock phase and polarity */
> -		u16 cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET)
> +		u32 cr =3D xspi_read16(xspi, xspi->cr_offset)
>  			 & ~XSPI_CR_MODE_MASK;
>  		if (spi->mode & SPI_CPHA)
>  			cr |=3D XSPI_CR_CPHA;
>  		if (spi->mode & SPI_CPOL)
>  			cr |=3D XSPI_CR_CPOL;
> -		out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> +		xspi_write16(xspi, xspi->cr_offset, cr);
> =

>  		/* We do not check spi->max_speed_hz here as the SPI clock
>  		 * frequency is not software programmable (the IP block design
> @@ -132,24 +202,27 @@ static void xilinx_spi_chipselect(struct spi_device=
 *spi, int is_on)
>  		 */
> =

>  		/* Activate the chip select */
> -		out_be32(xspi->regs + XSPI_SSR_OFFSET,
> +		xspi_write32(xspi, xspi->ssr_offset,
>  			 ~(0x0001 << spi->chip_select));
>  	}
>  }
> =

>  /* spi_bitbang requires custom setup_transfer() to be defined if there i=
s a
>   * custom txrx_bufs(). We have nothing to setup here as the SPI IP block=

> - * supports just 8 bits per word, and SPI clock can't be changed in soft=
ware.
> - * Check for 8 bits per word. Chip select delay calculations could be
> + * supports 8 or 16 bits per word, which can not be changed in software.=

> + * SPI clock can't be changed in software.
> + * Check for correct bits per word. Chip select delay calculations could=
 be
>   * added here as soon as bitbang_work() can be made aware of the delay v=
alue.
>   */
>  static int xilinx_spi_setup_transfer(struct spi_device *spi,
> -		struct spi_transfer *t)
> +	struct spi_transfer *t)
>  {
>  	u8 bits_per_word;
> +	struct xilinx_spi *xspi =3D spi_master_get_devdata(spi->master);
> =

> -	bits_per_word =3D (t) ? t->bits_per_word : spi->bits_per_word;
> -	if (bits_per_word !=3D 8) {
> +	bits_per_word =3D (t->bits_per_word) ? t->bits_per_word :
> +		spi->bits_per_word;
> +	if (bits_per_word !=3D xspi->bits_per_word) {
>  		dev_err(&spi->dev, "%s, unsupported bits_per_word=3D%d\n",
>  			__func__, bits_per_word);
>  		return -EINVAL;
> @@ -160,34 +233,50 @@ static int xilinx_spi_setup_transfer(struct spi_dev=
ice *spi,
> =

>  static int xilinx_spi_setup(struct spi_device *spi)
>  {
> -	struct spi_bitbang *bitbang;
> -	struct xilinx_spi *xspi;
> -	int retval;
> -
> -	xspi =3D spi_master_get_devdata(spi->master);
> -	bitbang =3D &xspi->bitbang;
> -
> -	retval =3D xilinx_spi_setup_transfer(spi, NULL);
> -	if (retval < 0)
> -		return retval;
> -
> +	/* always return 0, we can not check the number of bits.
> +	 * There are cases when SPI setup is called before any driver is
> +	 * there, in that case the SPI core defaults to 8 bits, which we
> +	 * do not support in some cases. But if we return an error, the
> +	 * SPI device would not be registered and no driver can get hold of it
> +	 * When the driver is there, it will call SPI setup again with the
> +	 * correct number of bits per transfer.
> +	 * If a driver setups with the wrong bit number, it will fail when
> +	 * it tries to do a transfer
> +	 */
>  	return 0;
>  }
> =

>  static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
>  {
> -	u8 sr;
> +	u32 sr;
> +	u8 wsize;
> +	if (xspi->bits_per_word =3D=3D 8)
> +		wsize =3D 1;
> +	else if (xspi->bits_per_word =3D=3D 16)
> +		wsize =3D 2;
> +	else
> +		wsize =3D 4;
> =

>  	/* Fill the Tx FIFO with as many bytes as possible */
> -	sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> -	while ((sr & XSPI_SR_TX_FULL_MASK) =3D=3D 0 && xspi->remaining_bytes > =
0) {
> +	sr =3D xspi_read8(xspi, xspi->sr_offset);
> +	while ((sr & XSPI_SR_TX_FULL_MASK) =3D=3D 0 &&
> +		xspi->remaining_bytes > 0) {
>  		if (xspi->tx_ptr) {
> -			out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
> -		} else {
> -			out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
> -		}
> -		xspi->remaining_bytes--;
> -		sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> +			if (wsize =3D=3D 1)
> +				xspi_write8(xspi, xspi->txd_offset,
> +					*xspi->tx_ptr);
> +			else if (wsize =3D=3D 2)
> +				xspi_write16(xspi, xspi->txd_offset,
> +					*(u16 *)(xspi->tx_ptr));
> +			else if (wsize =3D=3D 4)
> +				xspi_write32(xspi, xspi->txd_offset,
> +					*(u32 *)(xspi->tx_ptr));
> +
> +			xspi->tx_ptr +=3D wsize;
> +		} else
> +			xspi_write8(xspi, xspi->txd_offset, 0);
> +		xspi->remaining_bytes -=3D wsize;
> +		sr =3D xspi_read8(xspi, xspi->sr_offset);
>  	}
>  }
> =

> @@ -195,7 +284,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *sp=
i, struct spi_transfer *t)
>  {
>  	struct xilinx_spi *xspi =3D spi_master_get_devdata(spi->master);
>  	u32 ipif_ier;
> -	u16 cr;
> +	u32 cr;
> =

>  	/* We get here with transmitter inhibited */
> =

> @@ -209,23 +298,22 @@ static int xilinx_spi_txrx_bufs(struct spi_device *=
spi, struct spi_transfer *t)
>  	/* Enable the transmit empty interrupt, which we use to determine
>  	 * progress on the transmission.
>  	 */
> -	ipif_ier =3D in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
> -	out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
> +	ipif_ier =3D xspi_read32(xspi, XIPIF_V123B_IIER_OFFSET);
> +	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET,
>  		 ipif_ier | XSPI_INTR_TX_EMPTY);
> =

>  	/* Start the transfer by not inhibiting the transmitter any longer */
> -	cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
> -	out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> +	cr =3D xspi_read16(xspi, xspi->cr_offset) & ~XSPI_CR_TRANS_INHIBIT;
> +	xspi_write16(xspi, xspi->cr_offset, cr);
> =

>  	wait_for_completion(&xspi->done);
> =

>  	/* Disable the transmit empty interrupt */
> -	out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
> +	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, ipif_ier);
> =

>  	return t->len - xspi->remaining_bytes;
>  }
> =

> -
>  /* This driver supports single master mode only. Hence Tx FIFO Empty
>   * is the only interrupt we care about.
>   * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave M=
ode
> @@ -237,32 +325,50 @@ static irqreturn_t xilinx_spi_irq(int irq, void *de=
v_id)
>  	u32 ipif_isr;
> =

>  	/* Get the IPIF interrupts, and clear them immediately */
> -	ipif_isr =3D in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
> -	out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
> +	ipif_isr =3D xspi_read32(xspi, XIPIF_V123B_IISR_OFFSET);
> +	xspi_write32(xspi, XIPIF_V123B_IISR_OFFSET, ipif_isr);
> =

>  	if (ipif_isr & XSPI_INTR_TX_EMPTY) {	/* Transmission completed */
> -		u16 cr;
> -		u8 sr;
> +		u32 cr;
> +		u32 sr;
> +		u8 rsize;
> +		if (xspi->bits_per_word =3D=3D 8)
> +			rsize =3D 1;
> +		else if (xspi->bits_per_word =3D=3D 16)
> +			rsize =3D 2;
> +		else
> +			rsize =3D 4;
> =

>  		/* A transmit has just completed. Process received data and
>  		 * check for more data to transmit. Always inhibit the
>  		 * transmitter while the Isr refills the transmit register/FIFO,
>  		 * or make sure it is stopped if we're done.
>  		 */
> -		cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET);
> -		out_be16(xspi->regs + XSPI_CR_OFFSET,
> -			 cr | XSPI_CR_TRANS_INHIBIT);
> +		cr =3D xspi_read16(xspi, xspi->cr_offset);
> +		xspi_write16(xspi, xspi->cr_offset, cr | XSPI_CR_TRANS_INHIBIT);
> =

>  		/* Read out all the data from the Rx FIFO */
> -		sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> +		sr =3D xspi_read8(xspi, xspi->sr_offset);
>  		while ((sr & XSPI_SR_RX_EMPTY_MASK) =3D=3D 0) {
> -			u8 data;
> +			u32 data;
> +			if (rsize =3D=3D 1)
> +				data =3D xspi_read8(xspi, xspi->rxd_offset);
> +			else if (rsize =3D=3D 2)
> +				data =3D xspi_read16(xspi, xspi->rxd_offset);
> +			else
> +				data =3D xspi_read32(xspi, xspi->rxd_offset);
> =

> -			data =3D in_8(xspi->regs + XSPI_RXD_OFFSET);
>  			if (xspi->rx_ptr) {
> -				*xspi->rx_ptr++ =3D data;
> +				if (rsize =3D=3D 1)
> +					*xspi->rx_ptr =3D data & 0xff;
> +				else if (rsize =3D=3D 2)
> +					*(u16 *)(xspi->rx_ptr) =3D data & 0xffff;
> +				else
> +					*((u32 *)(xspi->rx_ptr)) =3D data;
> +				xspi->rx_ptr +=3D rsize;
>  			}
> -			sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> +
> +			sr =3D xspi_read8(xspi, xspi->sr_offset);
>  		}
> =

>  		/* See if there is more data to send */
> @@ -271,7 +377,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_=
id)
>  			/* Start the transfer by not inhibiting the
>  			 * transmitter any longer
>  			 */
> -			out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> +			xspi_write16(xspi, xspi->cr_offset, cr);
>  		} else {
>  			/* No more data to send.
>  			 * Indicate the transfer is completed.
> @@ -279,44 +385,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *de=
v_id)
>  			complete(&xspi->done);
>  		}
>  	}
> -
>  	return IRQ_HANDLED;
>  }
> =

> -static int __init xilinx_spi_of_probe(struct of_device *ofdev,
> -					const struct of_device_id *match)
> +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *=
mem,
> +	u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word)
>  {
>  	struct spi_master *master;
>  	struct xilinx_spi *xspi;
> -	struct resource r_irq_struct;
> -	struct resource r_mem_struct;
> +	int ret =3D 0;
> =

> -	struct resource *r_irq =3D &r_irq_struct;
> -	struct resource *r_mem =3D &r_mem_struct;
> -	int rc =3D 0;
> -	const u32 *prop;
> -	int len;
> +	master =3D spi_alloc_master(dev, sizeof(struct xilinx_spi));
> =

> -	/* Get resources(memory, IRQ) associated with the device */
> -	master =3D spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
> -
> -	if (master =3D=3D NULL) {
> -		return -ENOMEM;
> -	}
> -
> -	dev_set_drvdata(&ofdev->dev, master);
> -
> -	rc =3D of_address_to_resource(ofdev->node, 0, r_mem);
> -	if (rc) {
> -		dev_warn(&ofdev->dev, "invalid address\n");
> -		goto put_master;
> -	}
> -
> -	rc =3D of_irq_to_resource(ofdev->node, 0, r_irq);
> -	if (rc =3D=3D NO_IRQ) {
> -		dev_warn(&ofdev->dev, "no IRQ found\n");
> -		goto put_master;
> -	}
> +	if (master =3D=3D NULL)
> +		return ERR_PTR(-ENOMEM);
> =

>  	/* the spi->mode bits understood by this driver: */
>  	master->mode_bits =3D SPI_CPOL | SPI_CPHA;
> @@ -329,128 +411,87 @@ static int __init xilinx_spi_of_probe(struct of_de=
vice *ofdev,
>  	xspi->bitbang.master->setup =3D xilinx_spi_setup;
>  	init_completion(&xspi->done);
> =

> -	xspi->irq =3D r_irq->start;
> -
> -	if (!request_mem_region(r_mem->start,
> -			r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
> -		rc =3D -ENXIO;
> -		dev_warn(&ofdev->dev, "memory request failure\n");
> +	if (!request_mem_region(mem->start, resource_size(mem),
> +		XILINX_SPI_NAME)) {
> +		ret =3D -ENXIO;
>  		goto put_master;
>  	}
> =

> -	xspi->regs =3D ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
> +	xspi->regs =3D ioremap(mem->start, resource_size(mem));
>  	if (xspi->regs =3D=3D NULL) {
> -		rc =3D -ENOMEM;
> -		dev_warn(&ofdev->dev, "ioremap failure\n");
> -		goto release_mem;
> +		ret =3D -ENOMEM;
> +		dev_warn(dev, "ioremap failure\n");
> +		goto map_failed;
>  	}
> -	xspi->irq =3D r_irq->start;
> -
> -	/* dynamic bus assignment */
> -	master->bus_num =3D -1;
> =

> -	/* number of slave select bits is required */
> -	prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
> -	if (!prop || len < sizeof(*prop)) {
> -		dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
> -		goto unmap_io;
> +	master->bus_num =3D bus_num;
> +	master->num_chipselect =3D num_chipselect;
> +
> +	xspi->mem =3D *mem;
> +	xspi->irq =3D irq;
> +	xspi->bits_per_word =3D bits_per_word;
> +	xspi->model =3D model;
> +
> +	if (model =3D=3D XILINX_SPI_MODEL_DS464) {
> +		xspi->cr_offset =3D XSPI_CR_OFFSET_DS464;
> +		xspi->sr_offset =3D XSPI_SR_OFFSET_DS464;
> +		xspi->txd_offset =3D XSPI_TXD_OFFSET_DS464;
> +		xspi->rxd_offset =3D XSPI_RXD_OFFSET_DS464;
> +		xspi->ssr_offset =3D XSPI_SSR_OFFSET_DS464;
> +	} else {
> +		xspi->cr_offset =3D XSPI_CR_OFFSET_DS570;
> +		xspi->sr_offset =3D XSPI_SR_OFFSET_DS570;
> +		xspi->txd_offset =3D XSPI_TXD_OFFSET_DS570;
> +		xspi->rxd_offset =3D XSPI_RXD_OFFSET_DS570;
> +		xspi->ssr_offset =3D XSPI_SSR_OFFSET_DS570;
>  	}
> -	master->num_chipselect =3D *prop;
> =

>  	/* SPI controller initializations */
> -	xspi_init_hw(xspi->regs);
> +	xspi_init_hw(xspi);
> =

>  	/* Register for SPI Interrupt */
> -	rc =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi)=
;
> -	if (rc !=3D 0) {
> -		dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
> +	ret =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi=
);
> +	if (ret !=3D 0)
>  		goto unmap_io;
> -	}
> =

> -	rc =3D spi_bitbang_start(&xspi->bitbang);
> -	if (rc !=3D 0) {
> -		dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
> +	ret =3D spi_bitbang_start(&xspi->bitbang);
> +	if (ret !=3D 0) {
> +		dev_err(dev, "spi_bitbang_start FAILED\n");
>  		goto free_irq;
>  	}
> =

> -	dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=3D%d\n",
> -			(unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
> -
> -	/* Add any subnodes on the SPI bus */
> -	of_register_spi_devices(master, ofdev->node);
> -
> -	return rc;
> +	dev_info(dev, "at 0x%08X mapped to 0x%08X, irq=3D%d\n",
> +		(u32)mem->start, (u32)xspi->regs, xspi->irq);
> +	return master;
> =

>  free_irq:
>  	free_irq(xspi->irq, xspi);
>  unmap_io:
>  	iounmap(xspi->regs);
> -release_mem:
> -	release_mem_region(r_mem->start, resource_size(r_mem));
> +map_failed:
> +	release_mem_region(mem->start, resource_size(mem));
>  put_master:
>  	spi_master_put(master);
> -	return rc;
> +	return ERR_PTR(ret);
>  }
> +EXPORT_SYMBOL(xilinx_spi_init);
> =

> -static int __devexit xilinx_spi_remove(struct of_device *ofdev)
> +void xilinx_spi_deinit(struct spi_master *master)
>  {
>  	struct xilinx_spi *xspi;
> -	struct spi_master *master;
> -	struct resource r_mem;
> =

> -	master =3D platform_get_drvdata(ofdev);
>  	xspi =3D spi_master_get_devdata(master);
> =

>  	spi_bitbang_stop(&xspi->bitbang);
>  	free_irq(xspi->irq, xspi);
>  	iounmap(xspi->regs);
> -	if (!of_address_to_resource(ofdev->node, 0, &r_mem))
> -		release_mem_region(r_mem.start, resource_size(&r_mem));
> -	dev_set_drvdata(&ofdev->dev, 0);
> -	spi_master_put(xspi->bitbang.master);
> -
> -	return 0;
> -}
> -
> -/* work with hotplug and coldplug */
> -MODULE_ALIAS("platform:" XILINX_SPI_NAME);
> -
> -static int __exit xilinx_spi_of_remove(struct of_device *op)
> -{
> -	return xilinx_spi_remove(op);
> -}
> -
> -static struct of_device_id xilinx_spi_of_match[] =3D {
> -	{ .compatible =3D "xlnx,xps-spi-2.00.a", },
> -	{ .compatible =3D "xlnx,xps-spi-2.00.b", },
> -	{}
> -};
> -
> -MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
> -
> -static struct of_platform_driver xilinx_spi_of_driver =3D {
> -	.owner =3D THIS_MODULE,
> -	.name =3D "xilinx-xps-spi",
> -	.match_table =3D xilinx_spi_of_match,
> -	.probe =3D xilinx_spi_of_probe,
> -	.remove =3D __exit_p(xilinx_spi_of_remove),
> -	.driver =3D {
> -		.name =3D "xilinx-xps-spi",
> -		.owner =3D THIS_MODULE,
> -	},
> -};
> =

> -static int __init xilinx_spi_init(void)
> -{
> -	return of_register_platform_driver(&xilinx_spi_of_driver);
> +	release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
> +	spi_master_put(xspi->bitbang.master);
>  }
> -module_init(xilinx_spi_init);
> +EXPORT_SYMBOL(xilinx_spi_deinit);
> =

> -static void __exit xilinx_spi_exit(void)
> -{
> -	of_unregister_platform_driver(&xilinx_spi_of_driver);
> -}
> -module_exit(xilinx_spi_exit);
>  MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
>  MODULE_DESCRIPTION("Xilinx SPI driver");
>  MODULE_LICENSE("GPL");
> +
> diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
> new file mode 100644
> index 0000000..d951b11
> --- /dev/null
> +++ b/drivers/spi/xilinx_spi.h
> @@ -0,0 +1,32 @@
> +/*
> + * xilinx_spi.h
> + * Copyright (c) 2009 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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 _XILINX_SPI_H_
> +#define _XILINX_SPI_H_ 1
> +
> +#include <linux/spi/spi.h>
> +#include <linux/spi/spi_bitbang.h>
> +#include <linux/spi/xilinx_spi.h>
> +
> +#define XILINX_SPI_NAME "xilinx_spi"
> +
> +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *=
mem,
> +	u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word);
> +
> +void xilinx_spi_deinit(struct spi_master *master);
> +#endif
> diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
> new file mode 100644
> index 0000000..4f54ddd
> --- /dev/null
> +++ b/drivers/spi/xilinx_spi_of.c
> @@ -0,0 +1,120 @@
> +/*
> + * xilinx_spi_of.c
> + *
> + * Xilinx SPI controller driver (master mode only)
> + *
> + * Author: MontaVista Software, Inc.
> + *	source@mvista.com
> + *
> + * 2002-2007 (c) MontaVista Software, Inc.  This file is licensed under =
the
> + * terms of the GNU General Public License version 2.  This program is l=
icensed
> + * "as is" without any warranty of any kind, whether express or implied.=

> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/of_platform.h>
> +#include <linux/of_device.h>
> +#include <linux/of_spi.h>
> +
> +#include <linux/spi/spi.h>
> +#include <linux/spi/spi_bitbang.h>
> +
> +#include "xilinx_spi.h"
> +
> +
> +static int __init xilinx_spi_of_probe(struct of_device *ofdev,
> +					const struct of_device_id *match)
> +{
> +	struct resource r_irq_struct;
> +	struct resource r_mem_struct;
> +	struct spi_master *master;
> +
> +	struct resource *r_irq =3D &r_irq_struct;
> +	struct resource *r_mem =3D &r_mem_struct;
> +	int rc =3D 0;
> +	const u32 *prop;
> +	int len;
> +
> +	rc =3D of_address_to_resource(ofdev->node, 0, r_mem);
> +	if (rc) {
> +		dev_warn(&ofdev->dev, "invalid address\n");
> +		return rc;
> +	}
> +
> +	rc =3D of_irq_to_resource(ofdev->node, 0, r_irq);
> +	if (rc =3D=3D NO_IRQ) {
> +		dev_warn(&ofdev->dev, "no IRQ found\n");
> +		return -ENODEV;
> +	}
> +
> +	/* number of slave select bits is required */
> +	prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
> +	if (!prop || len < sizeof(*prop)) {
> +		dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
> +		return -EINVAL;
> +	}
> +	master =3D xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start,
> +		XILINX_SPI_MODEL_DS464, -1, *prop, 8);
> +	if (IS_ERR(master))
> +		return PTR_ERR(master);
> +
> +	dev_set_drvdata(&ofdev->dev, master);
> +
> +	/* Add any subnodes on the SPI bus */
> +	of_register_spi_devices(master, ofdev->node);
> +
> +	return 0;
> +}
> +
> +static int __devexit xilinx_spi_remove(struct of_device *ofdev)
> +{
> +	xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
> +	dev_set_drvdata(&ofdev->dev, 0);
> +	return 0;
> +}
> +
> +static int __exit xilinx_spi_of_remove(struct of_device *op)
> +{
> +	return xilinx_spi_remove(op);
> +}
> +
> +static struct of_device_id xilinx_spi_of_match[] =3D {
> +	{ .compatible =3D "xlnx,xps-spi-2.00.a", },
> +	{ .compatible =3D "xlnx,xps-spi-2.00.b", },
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
> +
> +static struct of_platform_driver xilinx_spi_of_driver =3D {
> +	.owner =3D THIS_MODULE,
> +	.name =3D "xilinx-xps-spi",
> +	.match_table =3D xilinx_spi_of_match,
> +	.probe =3D xilinx_spi_of_probe,
> +	.remove =3D __exit_p(xilinx_spi_of_remove),
> +	.driver =3D {
> +		.name =3D "xilinx-xps-spi",
> +		.owner =3D THIS_MODULE,
> +	},
> +};
> +
> +static int __init xilinx_spi_of_init(void)
> +{
> +	return of_register_platform_driver(&xilinx_spi_of_driver);
> +}
> +module_init(xilinx_spi_of_init);
> +
> +static void __exit xilinx_spi_of_exit(void)
> +{
> +	of_unregister_platform_driver(&xilinx_spi_of_driver);
> +}
> +module_exit(xilinx_spi_of_exit);
> +MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> +MODULE_DESCRIPTION("Xilinx SPI driver");
> +MODULE_LICENSE("GPL");
> +
> diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltf=
m.c
> new file mode 100644
> index 0000000..d59d509
> --- /dev/null
> +++ b/drivers/spi/xilinx_spi_pltfm.c
> @@ -0,0 +1,104 @@
> +/*
> + * xilinx_spi_pltfm.c Support for Xilinx SPI platform devices
> + * Copyright (c) 2009 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +/* Supports:
> + * Xilinx SPI devices as platform devices
> + *
> + * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/spi/spi.h>
> +#include <linux/spi/spi_bitbang.h>
> +#include <linux/spi/xilinx_spi.h>
> +
> +#include "xilinx_spi.h"
> +
> +static int __devinit xilinx_spi_probe(struct platform_device *dev)
> +{
> +	struct xspi_platform_data *pdata;
> +	struct resource *r;
> +	int irq;
> +	struct spi_master *master;
> +	u8 i;
> +
> +	pdata =3D dev->dev.platform_data;
> +	if (pdata =3D=3D NULL)
> +		return -ENODEV;
> +
> +	r =3D platform_get_resource(dev, IORESOURCE_MEM, 0);
> +	if (r =3D=3D NULL)
> +		return -ENODEV;
> +
> +	irq =3D platform_get_irq(dev, 0);
> +	if (irq < 0)
> +		return -ENXIO;
> +
> +	master =3D xilinx_spi_init(&dev->dev, r, irq, pdata->model,
> +		dev->id, pdata->num_chipselect, pdata->bits_per_word);
> +	if (IS_ERR(master))
> +		return PTR_ERR(master);
> +
> +	for (i =3D 0; i < pdata->num_devices; i++)
> +		spi_new_device(master, pdata->devices + i);
> +
> +	platform_set_drvdata(dev, master);
> +	return 0;
> +}
> +
> +static int __devexit xilinx_spi_remove(struct platform_device *dev)
> +{
> +	xilinx_spi_deinit(platform_get_drvdata(dev));
> +	platform_set_drvdata(dev, 0);
> +
> +	return 0;
> +}
> +
> +/* work with hotplug and coldplug */
> +MODULE_ALIAS("platform:" XILINX_SPI_NAME);
> +
> +static struct platform_driver xilinx_spi_driver =3D {
> +	.probe	=3D xilinx_spi_probe,
> +	.remove	=3D __devexit_p(xilinx_spi_remove),
> +	.driver =3D {
> +		.name =3D XILINX_SPI_NAME,
> +		.owner =3D THIS_MODULE,
> +	},
> +};
> +
> +static int __init xilinx_spi_pltfm_init(void)
> +{
> +	return platform_driver_register(&xilinx_spi_driver);
> +}
> +module_init(xilinx_spi_pltfm_init);
> +
> +static void __exit xilinx_spi_pltfm_exit(void)
> +{
> +	platform_driver_unregister(&xilinx_spi_driver);
> +}
> +module_exit(xilinx_spi_pltfm_exit);
> +
> +MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
> +MODULE_DESCRIPTION("Xilinx SPI platform driver");
> +MODULE_LICENSE("GPL v2");
> +
> diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_sp=
i.h
> new file mode 100644
> index 0000000..e9e6a84
> --- /dev/null
> +++ b/include/linux/spi/xilinx_spi.h
> @@ -0,0 +1,18 @@
> +#ifndef __LINUX_SPI_XILINX_SPI_H
> +#define __LINUX_SPI_XILINX_SPI_H
> +
> +#define XILINX_SPI_MODEL_DS464 0
> +#define XILINX_SPI_MODEL_DS570 1
> +
> +/* SPI Controller IP */
> +struct xspi_platform_data {
> +	u16 num_chipselect;
> +	u8 model;
> +	u8 bits_per_word;
> +	/* devices to add to the bus when the host is up */
> +	struct spi_board_info *devices;
> +	u8 num_devices;
> +};
> +
> +#endif /* __LINUX_SPI_XILINX_SPI_H */
> +
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* Re: [PATCH] net: xilinx_emaclite: Fix problem with first incoming packet
From: Grant Likely @ 2009-09-22 16:53 UTC (permalink / raw)
  To: John Linn; +Cc: Michal Simek, sadanand.mutyala, netdev, linuxppc-dev, davem
In-Reply-To: <fac40d47-5b19-4225-9fee-f7a058851fc0@SG2EHSMHS017.ehs.local>

On Tue, Sep 22, 2009 at 8:24 AM, John Linn <john.linn@xilinx.com> wrote:
> From: Michal Simek <monstr@monstr.eu>
>
> You can't ping the board or connect to it unless you send
> any packet out from board.
>
> Tested-by: John Williams <john.williams@petalogix.com>
> Signed-off-by: Michal Simek <monstr@monstr.eu>
> Acked-by: John Linn <john.linn@xilinx.com>

John, Since this patch is being *sent* by you, then you should use a
"signed-off-by" tag instead because it actually passed through your
hands.

Oh, and:
Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
> =A0drivers/net/xilinx_emaclite.c | =A0 =A07 ++-----
> =A01 files changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.=
c
> index dc22782..83a044d 100644
> --- a/drivers/net/xilinx_emaclite.c
> +++ b/drivers/net/xilinx_emaclite.c
> @@ -134,18 +134,15 @@ static void xemaclite_enable_interrupts(struct net_=
local *drvdata)
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0/* Enable the Rx interrupts for the first buffer */
> - =A0 =A0 =A0 reg_data =3D in_be32(drvdata->base_addr + XEL_RSR_OFFSET);
> =A0 =A0 =A0 =A0out_be32(drvdata->base_addr + XEL_RSR_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg_data | XEL_RSR_RECV_IE_MASK);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XEL_RSR_RECV_IE_MASK);
>
> =A0 =A0 =A0 =A0/* Enable the Rx interrupts for the second Buffer if
> =A0 =A0 =A0 =A0 * configured in HW */
> =A0 =A0 =A0 =A0if (drvdata->rx_ping_pong !=3D 0) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg_data =3D in_be32(drvdata->base_addr + X=
EL_BUFFER_OFFSET +
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XEL_=
RSR_OFFSET);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0out_be32(drvdata->base_addr + XEL_BUFFER_O=
FFSET +
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 XEL_RSR_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg_data | XEL_RSR_RECV_=
IE_MASK);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XEL_RSR_RECV_IE_MASK);
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0/* Enable the Global Interrupt Enable */
> --
> 1.6.2.1
>
>
>
> This email and any attachments are intended for the sole use of the named=
 recipient(s) and contain(s) confidential information that may be proprieta=
ry, privileged or copyrighted under applicable law. If you are not the inte=
nded recipient, do not read, copy, or forward this email message or any att=
achments. Delete this email message and any attachments immediately.
>
>
>



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

^ permalink raw reply

* RE: [PATCH] net: xilinx_emaclite: Fix problem with first incoming packet
From: John Linn @ 2009-09-22 16:56 UTC (permalink / raw)
  To: Grant Likely; +Cc: Michal Simek, linuxppc-dev, netdev, Sadanand Mutyala, davem
In-Reply-To: <fa686aa40909220953g708445d9s9c25bd839cc2dd2e@mail.gmail.com>

Thanks Grant, I wondered about that myself.

> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On Behalf Of Gra=
nt Likely
> Sent: Tuesday, September 22, 2009 10:54 AM
> To: John Linn
> Cc: netdev@vger.kernel.org; davem@davemloft.net; linuxppc-dev@ozlabs.org;=
 jwboyer@linux.vnet.ibm.com;
> Sadanand Mutyala; Michal Simek
> Subject: Re: [PATCH] net: xilinx_emaclite: Fix problem with first incomin=
g packet
> =

> On Tue, Sep 22, 2009 at 8:24 AM, John Linn <john.linn@xilinx.com> wrote:
> > From: Michal Simek <monstr@monstr.eu>
> >
> > You can't ping the board or connect to it unless you send
> > any packet out from board.
> >
> > Tested-by: John Williams <john.williams@petalogix.com>
> > Signed-off-by: Michal Simek <monstr@monstr.eu>
> > Acked-by: John Linn <john.linn@xilinx.com>
> =

> John, Since this patch is being *sent* by you, then you should use a
> "signed-off-by" tag instead because it actually passed through your
> hands.
> =

> Oh, and:
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
> =

> > ---
> > =A0drivers/net/xilinx_emaclite.c | =A0 =A07 ++-----
> > =A01 files changed, 2 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclit=
e.c
> > index dc22782..83a044d 100644
> > --- a/drivers/net/xilinx_emaclite.c
> > +++ b/drivers/net/xilinx_emaclite.c
> > @@ -134,18 +134,15 @@ static void xemaclite_enable_interrupts(struct ne=
t_local *drvdata)
> > =A0 =A0 =A0 =A0}
> >
> > =A0 =A0 =A0 =A0/* Enable the Rx interrupts for the first buffer */
> > - =A0 =A0 =A0 reg_data =3D in_be32(drvdata->base_addr + XEL_RSR_OFFSET)=
;
> > =A0 =A0 =A0 =A0out_be32(drvdata->base_addr + XEL_RSR_OFFSET,
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg_data | XEL_RSR_RECV_IE_MASK);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XEL_RSR_RECV_IE_MASK);
> >
> > =A0 =A0 =A0 =A0/* Enable the Rx interrupts for the second Buffer if
> > =A0 =A0 =A0 =A0 * configured in HW */
> > =A0 =A0 =A0 =A0if (drvdata->rx_ping_pong !=3D 0) {
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 reg_data =3D in_be32(drvdata->base_addr +=
 XEL_BUFFER_OFFSET +
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XE=
L_RSR_OFFSET);
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0out_be32(drvdata->base_addr + XEL_BUFFER=
_OFFSET +
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 XEL_RSR_OFFSET,
> > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reg_data | XEL_RSR_REC=
V_IE_MASK);
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XEL_RSR_RECV_IE_MASK);=

> > =A0 =A0 =A0 =A0}
> >
> > =A0 =A0 =A0 =A0/* Enable the Global Interrupt Enable */
> > --
> > 1.6.2.1
> >
> >
> >
> > This email and any attachments are intended for the sole use of the nam=
ed recipient(s) and
> contain(s) confidential information that may be proprietary, privileged o=
r copyrighted under
> applicable law. If you are not the intended recipient, do not read, copy,=
 or forward this email
> message or any attachments. Delete this email message and any attachments=
 immediately.
> >
> >
> >
> =

> =

> =

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


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* PCI HotPlug and Adding Resources after Linux Boots
From: Morrison, Tom @ 2009-09-22 19:36 UTC (permalink / raw)
  To: linuxppc-dev@ozlabs.org, linux-kernel@vger.kernel.org

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

I am not exactly sure who to direct this question to (general Linux kernel or LinuxPPC),
so I am directing to both - in hopes that someone will recognize this problem - and perhaps
give me some suggestions on how to proceed...

I am running Linux (2.6.23x (and 2.6.27.x)) on a MPC8572 based system.

I have an 8616 switch that has a Port (6) connected to a FPGA that is
NOT loaded at before Linux boots (note: this port is configured for HOTPLUG
events - which we do get after FPGA  is loaded). We are NOT using a
static device tree map (because the devices in the system are very dynamic).

We use instead the pci auto scan mechanism(s) to scan/assign resources
(including into the BAR registers) at bootup to all of the devices that are
attached to this MPC8572...

Here is the port that is attached to the device (note: there are NO
resources assigned at this point this port):

-------------------------------------------------------------------------------------------------
02:06.0 PCI bridge: PLX Technology, Inc.: Unknown device 8616 (rev bb) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0
        Bus: primary=02, secondary=05, subordinate=05, sec-latency=0
        Capabilities: [40] Power Management version 3
        Capabilities: [48] Message Signalled Interrupts: 64bit+ Queue=0/2 Enable+
        Capabilities: [68] #10 [0162]
        Capabilities: [a4] #0d [0000]

root@slave7 ~ # lspci -t
-+-[01]---00.0-[02-05]--+-01.0
 |                      +-04.0-[03]--
 |                      +-05.0-[04]--
 |                      \-06.0-[05]-

-------------------------------------------------------------------------------------------------

Later, after I detect there is an FPGA to load - I load it. At completion of the
loading of the FPGA - the 8616  detects the FPGA - and creates a HotPlug
event that the PCI Express HotPlug Driver handles:
-------------------------------------------------------------------------------------------------

root@slave7 ~ # pciehp: pcie_isr: intr_loc 8
pciehp: pciehp:  Presence/Notify input change.
pciehp: Card present on Slot(0005_0070)
pciehp: Surprise Removal
pciehp: hpc_get_power_status: SLOTCTRL 80 value read 8
pciehp: hpc_get_attention_status: SLOTCTRL 80, value read 8
pciehp: board_added: slot device, slot offset, hp slot = 0, 0 ,0
pciehp: hpc_check_lnk_status: lnk_status = 2021
PCI: Found 0000:05:00.0 [1172/0004] 00ff00 00
PCI: Calling quirk c0012d3c for 0000:05:00.0
program_fw_provided_values: Could not get hotplug parameters
entering assign resources (size: 2000000)
PCI: Failed to allocate mem resource #0:2000000@0 for 0000:05:00.0
bus pci: add device 0000:05:00.0
entering uevent
pci: Trying to Match Device 0000:05:00.0 with Driver pcieport-driver
pci: Trying to Match Device 0000:05:00.0 with Driver serial
pci: Trying to Match Device 0000:05:00.0 with Driver pexntb
pciehp: hpc_get_power_status: SLOTCTRL 80 value read 8
pciehp: hpc_get_attention_status: SLOTCTRL 80, value read 8

02:06.0 PCI bridge: PLX Technology, Inc.: Unknown device 8616 (rev bb) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0
        Bus: primary=02, secondary=05, subordinate=05, sec-latency=0
        Capabilities: [40] Power Management version 3
        Capabilities: [48] Message Signalled Interrupts: 64bit+ Queue=0/2 Enable+
        Capabilities: [68] #10 [0162]
        Capabilities: [a4] #0d [0000]

05:00.0 Class ff00: Altera Corporation: Unknown device 0004 (rev 01)
        Subsystem: Altera Corporation: Unknown device 0004
        Flags: fast devsel
        Capabilities: [50] Message Signalled Interrupts: 64bit+ Queue=0/5 Enable-
        Capabilities: [78] Power Management version 3
        Capabilities: [80] #10 [0001]

root@slave7 ~ # lspci -t
-+-[01]---00.0-[02-05]--+-01.0
 |                      +-04.0-[03]--
 |                      +-05.0-[04]--
 |                      \-06.0-[05]----00.0
 \-[00]---00.0

-------------------------------------------------------------------------------------------------

So, as you can see - the device has been read - and it requires 32M of resources, but
because its parent doesn't have any resources allocated - it seemingly can't allocate and
use any additional resources.

How do I 'customize' and/or add resources at this point for this device (using semi-standard mechanisms)?

Thanks in advance for any/all ideas...


I


Tom Morrison
Principal Software Engineer
EMPIRIX
20 Crosby Drive - Bedford, MA  01730
p: 781.266.3567 f: 781.266.3670
email: tmorrison@empirix.com<mailto:tmorrison@empirix.com>
www.empirix.com<http://www.empirix.com/>




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

^ permalink raw reply

* Re: powerpc: Move 64bit heap above 1TB on machines with 1TB segments
From: Benjamin Herrenschmidt @ 2009-09-22 21:08 UTC (permalink / raw)
  To: Mel Gorman; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <OFE590BAE9.6FD7FAB3-ON80257639.0050F8A6-80257639.00514A5E@ie.ibm.com>


> Unfortunately, I am not sensitive to issues surrounding 1TB segments or how
> they are currently being used. However, as this clearly helps performance
> for large amounts of memory, is it worth providing an option to
> libhugetlbfs to locate 16MB pages above 1TB when they are otherwise being
> unused?

AFAIK, that is already the case, at least the kernel will hand out pages
above 1T preferentially iirc.

There were talks about making huge pages below 1T not even come up
untily you ask for them with MAP_FIXED, dunno where that went.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] net: xilinx_emaclite: Fix problem with first incoming packet
From: David Miller @ 2009-09-22 21:17 UTC (permalink / raw)
  To: John.Linn; +Cc: monstr, linuxppc-dev, netdev, sadanan
In-Reply-To: <20090922165612.584554A8052@mail195-sin.bigfish.com>

From: John Linn <John.Linn@xilinx.com>
Date: Tue, 22 Sep 2009 10:56:27 -0600

> Thanks Grant, I wondered about that myself.

I've applied this patch, thanks.

^ permalink raw reply

* Re: [PATCH 2/6] mtd: m25p80: Convert to device table matching
From: Andrew Morton @ 2009-09-22 21:17 UTC (permalink / raw)
  To: David Brownell
  Cc: ben, linux-kernel, lm-sensors, linuxppc-dev, linux-mtd, khali,
	dwmw2
In-Reply-To: <200908031954.50955.david-b@pacbell.net>

On Mon, 3 Aug 2009 19:54:50 -0700
David Brownell <david-b@pacbell.net> wrote:

> On Thursday 30 July 2009, Anton Vorontsov wrote:
> > This patch converts the m25p80 driver so that now it uses .id_table
> > for device matching, making it properly detect devices on OpenFirmware
> > platforms (prior to this patch the driver misdetected non-JEDEC chips,
> > seeing all chips as "m25p80").
> 
> I suspect "detect" is a misnomer there.  It only "detects" JEDEC chips.
> All others got explicit declarations ... so if there's misbehavior for
> other chips, it's because those declarations were poorly handled.  Maybe
> they were not properly flagged as non-JDEC
> 
>  
> > Also, now jedec_probe() only does jedec probing, nothing else. If it
> > is not able to detect a chip, NULL is returned and the driver fall
> > backs to the information specified by the platform (platform_data, or
> > exact ID).
> 
> I'd rather keep the warning, so there's a clue about what's really
> going on:  JEDEC chip found, but its ID is not handled.
> 

afaik there was no response to David's review comments, so this patch
is in the "stuck" state.


> > Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> > ---
> >  drivers/mtd/devices/m25p80.c |  146 +++++++++++++++++++++++-------------------
> >  1 files changed, 80 insertions(+), 66 deletions(-)
> > 
> > diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> > index 10ed195..0d74b38 100644
> > --- a/drivers/mtd/devices/m25p80.c
> > +++ b/drivers/mtd/devices/m25p80.c
> > 			... deletia ...
> 
> > @@ -481,74 +480,83 @@ struct flash_info {
> >  #define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */
> >  };
> >  
> > +#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
> > +	((kernel_ulong_t)&(struct flash_info) {				\
> > +		.jedec_id = (_jedec_id),				\
> > +		.ext_id = (_ext_id),					\
> > +		.sector_size = (_sector_size),				\
> > +		.n_sectors = (_n_sectors),				\
> > +		.flags = (_flags),					\
> > +	})
> 
> Anonymous inlined structures ... kind of ugly, but I can
> understand why you might not want to declare and name a
> few dozen single-use structures.
> 
> 
> >  
> >  /* NOTE: double check command sets and memory organization when you add
> >   * more flash chips.  This current list focusses on newer chips, which
> >   * have been converging on command sets which including JEDEC ID.
> >   */
> > -static struct flash_info __devinitdata m25p_data [] = {
> > -
> > +static const struct spi_device_id m25p_ids[] = {
> >  	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
> > -	{ "at25fs010",  0x1f6601, 0, 32 * 1024, 4, SECT_4K, },
> > -	{ "at25fs040",  0x1f6604, 0, 64 * 1024, 8, SECT_4K, },
> > +	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) },
> > +	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
> >  
> > 		... deletia ...
> >  
> 
> > @@ -596,6 +602,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
> >   */
> >  static int __devinit m25p_probe(struct spi_device *spi)
> >  {
> > +	const struct spi_device_id	*id;
> >  	struct flash_platform_data	*data;
> >  	struct m25p			*flash;
> >  	struct flash_info		*info;
> > @@ -608,32 +615,38 @@ static int __devinit m25p_probe(struct spi_device *spi)
> >  	 */
> >  	data = spi->dev.platform_data;
> >  	if (data && data->type) {
> 
> At this point I wonder why you're not changing the probe sequence
> more.  Get "id" and then "id" here.  If it's for "m25p80" assume
> it's an old-style board init and do the current logic.  Else just
> verify "info".
> 
> There's a new error case of course:  new-style but data->type
> doesn't match id->name.
> 
> 
> > -		for (i = 0, info = m25p_data;
> > -				i < ARRAY_SIZE(m25p_data);
> > -				i++, info++) {
> > -			if (strcmp(data->type, info->name) == 0)
> > -				break;
> > +		for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) {
> > +			id = &m25p_ids[i];
> > +			info = (void *)m25p_ids[i].driver_data;
> > +			if (strcmp(data->type, id->name))
> > +				continue;
> > +			break;
> >  		}
> >  
> >  		/* unrecognized chip? */
> > -		if (i == ARRAY_SIZE(m25p_data)) {
> > +		if (i == ARRAY_SIZE(m25p_ids) - 1) {
> 
> Better:  "if (info == NULL) ..."   You've got all the pointers
> in hand; don't use indices.
> 
> >  			DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
> >  					dev_name(&spi->dev), data->type);
> >  			info = NULL;
> >  
> >  		/* recognized; is that chip really what's there? */
> >  		} else if (info->jedec_id) {
> > -			struct flash_info	*chip = jedec_probe(spi);
> > +			id = jedec_probe(spi);
> >  
> > -			if (!chip || chip != info) {
> > +			if (id != &m25p_ids[i]) {
> 
> Again, don't use indices except during the lookup.
> 
> >  				dev_warn(&spi->dev, "found %s, expected %s\n",
> > -						chip ? chip->name : "UNKNOWN",
> > -						info->name);
> > +						id ? id->name : "UNKNOWN",
> > +						m25p_ids[i].name);
> >  				info = NULL;
> >  			}
> >  		}
> > -	} else
> > -		info = jedec_probe(spi);
> > +	} else {
> > +		id = jedec_probe(spi);
> > +		if (!id)
> > +			id = spi_get_device_id(spi);
> > +
> > +		info = (void *)id->driver_data;
> > +	}
> >  
> >  	if (!info)
> >  		return -ENODEV;
> 

^ permalink raw reply

* Re: [PATCH] rtc: Set wakeup capability for I2C and SPI RTC drivers
From: Andrew Morton @ 2009-09-22 21:19 UTC (permalink / raw)
  To: avorontsov
  Cc: dbrownell, linux-kernel, david-b, linuxppc-dev, ben-linux, khali,
	linux-pm
In-Reply-To: <20090828003010.GA19160@oksana.dev.rtsoft.ru>

On Fri, 28 Aug 2009 04:30:10 +0400
Anton Vorontsov <avorontsov@ru.mvista.com> wrote:

> On Fri, Aug 28, 2009 at 03:19:25AM +0400, Anton Vorontsov wrote:
> [...]
> > > That is why platform code should device_init_wakeup() and
> > > drivers should check device_can_wakeup(dev) ...
> > 
> > They should (and do) check may_wakeup() (i.e. should_wakeup) before
> > suspending, not can_wakeup().
> > 
> > static int ds1374_suspend(struct i2c_client *client, pm_message_t state)
> > {
> >         if (client->irq >= 0 && device_may_wakeup(&client->dev))
> >                 enable_irq_wake(client->irq);
> >         return 0;
> > }
> > 
> > (quite funny, they issue enable_irq_wake(), assuming that otherwise
> > IRQ line won't trigger CPU wakeup. But in reality, there are interrupt
> > controllers that you can't control in that regard: any IRQ activity
> > will always resume CPU. And so 'echo disable > /sys/.../wakeup' won't
> > guarantee anything. Unreliable, nasty? Could be.)
> 
> BTW, of course we can fix this by masking interrupts before
> suspending, but nobody actually do this (but should, I think).
> 
> And if RTC's IRQ is wired to power switch you're in trouble
> without any way to fix this.
> 

afaik nothing got resolved here, so this patch is floating about
wondering what its future will be.



From: Anton Vorontsov <avorontsov@ru.mvista.com>

RTC core won't allow wakeup alarms to be set if RTC devices' parent (i.e. 
i2c_client or spi_device) isn't wakeup capable.

For I2C devices there is I2C_CLIENT_WAKE flag exists that we can pass via
board info, and if set, I2C core will initialize wakeup capability.  For
SPI devices there is no such flag at all.

I believe that it's not platform code responsibility to allow or disallow
wakeups, instead, drivers themselves should set the capability if a device
can trigger wakeups.

That's what drivers/base/power/sysfs.c says:

 * It is the responsibility of device drivers to enable (or disable)
 * wakeup signaling as part of changing device power states, respecting
 * the policy choices provided through the driver model.

I2C and SPI RTC devices send wakeup events via interrupt lines, so we
should set the wakeup capability if IRQ is routed.

Ideally we should also check irq for wakeup capability before setting
device's capability, i.e.

	if (can_irq_wake(irq))
		device_set_wakeup_capable(&client->dev, 1);

But there is no can_irq_wake() call exist, and it is not that trivial to
implement it for all interrupts controllers and complex/cascaded setups.

drivers/base/power/sysfs.c also covers these cases:

 * Devices may not be able to generate wakeup events from all power
 * states.  Also, the events may be ignored in some configurations;
 * for example, they might need help from other devices that aren't
 * active

So there is no guarantee that wakeup will actually work, and so I think
there is no point in being pedantic wrt checking IRQ wakeup capability.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 drivers/rtc/rtc-ds1305.c |    2 ++
 drivers/rtc/rtc-ds1307.c |    2 ++
 drivers/rtc/rtc-ds1374.c |    2 ++
 3 files changed, 6 insertions(+)

diff -puN drivers/rtc/rtc-ds1305.c~rtc-set-wakeup-capability-for-i2c-and-spi-rtc-drivers drivers/rtc/rtc-ds1305.c
--- a/drivers/rtc/rtc-ds1305.c~rtc-set-wakeup-capability-for-i2c-and-spi-rtc-drivers
+++ a/drivers/rtc/rtc-ds1305.c
@@ -780,6 +780,8 @@ static int __devinit ds1305_probe(struct
 					spi->irq, status);
 			goto fail1;
 		}
+
+		device_set_wakeup_capable(&spi->dev, 1);
 	}
 
 	/* export NVRAM */
diff -puN drivers/rtc/rtc-ds1307.c~rtc-set-wakeup-capability-for-i2c-and-spi-rtc-drivers drivers/rtc/rtc-ds1307.c
--- a/drivers/rtc/rtc-ds1307.c~rtc-set-wakeup-capability-for-i2c-and-spi-rtc-drivers
+++ a/drivers/rtc/rtc-ds1307.c
@@ -881,6 +881,8 @@ read_rtc:
 				"unable to request IRQ!\n");
 			goto exit_irq;
 		}
+
+		device_set_wakeup_capable(&client->dev, 1);
 		set_bit(HAS_ALARM, &ds1307->flags);
 		dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
 	}
diff -puN drivers/rtc/rtc-ds1374.c~rtc-set-wakeup-capability-for-i2c-and-spi-rtc-drivers drivers/rtc/rtc-ds1374.c
--- a/drivers/rtc/rtc-ds1374.c~rtc-set-wakeup-capability-for-i2c-and-spi-rtc-drivers
+++ a/drivers/rtc/rtc-ds1374.c
@@ -383,6 +383,8 @@ static int ds1374_probe(struct i2c_clien
 			dev_err(&client->dev, "unable to request IRQ\n");
 			goto out_free;
 		}
+
+		device_set_wakeup_capable(&client->dev, 1);
 	}
 
 	ds1374->rtc = rtc_device_register(client->name, &client->dev,
_

^ permalink raw reply

* NAND ECC Error with wrong SMC ording bug
From: Sean MacLennan @ 2009-09-22 21:20 UTC (permalink / raw)
  To: linuxppc-dev

What is the status of this bug?

Cheers,
   Sean

^ permalink raw reply

* Re: [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for DS570
From: Richard Röjfors @ 2009-09-22 21:59 UTC (permalink / raw)
  To: John Linn; +Cc: spi-devel-general, Andrew Morton, dbrownell, linuxppc-dev
In-Reply-To: <20090922155952.8171518B8046@mail30-sin.bigfish.com>

John Linn wrote:
>> -----Original Message-----
>> From: linuxppc-dev-bounces+john.linn=xilinx.com@lists.ozlabs.org [mailto:linuxppc-dev-
>> bounces+john.linn=xilinx.com@lists.ozlabs.org] On Behalf Of Richard Röjfors
>> Sent: Tuesday, September 22, 2009 6:55 AM
>> To: spi-devel-general@lists.sourceforge.net
>> Cc: linuxppc-dev@ozlabs.org; Andrew Morton; dbrownell@users.sourceforge.net
>> Subject: [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for
>> DS570
>>
>> This patch splits xilinx_spi into three parts, an OF and a platform
>> driver and generic part.
>>
>> The generic part now also works on X86 and also supports the Xilinx
>> SPI IP DS570
> 
> Hi Richard,

Hi John,

> 
> The current driver (without this change) works for the newer XPS SPI device already as I run tests on it each day using an SPI EEPROM. 

I'm not an expert of the Xilinx SPI blocks, I have only used one, the DS570.

I don't think you use the DS570. I don't have the datasheet of the older one, but the register
offsets of the DS570 don't match the driver you are using. All the registers of the DS570 are at 4
bytes boundries.

For instance the Status register of the code (DS464 is at offset 0x67), while the "Xilinx DS570 XPS
Serial Peripheral Interface (SPI) (v2.00b), Data Sheet", clearly specifies that the Status register
offset of the DS570 is 0x64, which also matches the FPGA IP we run.

> 
> Do you think that's not the case, or it doesn't work for some other type of devices that I'm not testing with?

I think you use some other IP block. Could that be the case?

> 
> I'll hold off commenting on the rest of the code changes for a bit.
> 
> Thanks,
> John
> 
>> Signed-off-by: Richard Röjfors <richard.rojfors.ext@mocean-labs.com>
>> ---
>> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
>> index 2c733c2..eca491b 100644
>> --- a/drivers/spi/Kconfig
>> +++ b/drivers/spi/Kconfig
>> @@ -218,8 +218,8 @@ config SPI_TXX9
>>  	  SPI driver for Toshiba TXx9 MIPS SoCs
>>
>>  config SPI_XILINX
>> -	tristate "Xilinx SPI controller"
>> -	depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
>> +	tristate "Xilinx SPI controller common module"
>> +	depends on (XILINX_VIRTEX || MICROBLAZE || HAS_IOMEM) && EXPERIMENTAL
>>  	select SPI_BITBANG
>>  	help
>>  	  This exposes the SPI controller IP from the Xilinx EDK.
>> @@ -227,6 +227,22 @@ config SPI_XILINX
>>  	  See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
>>  	  Product Specification document (DS464) for hardware details.
>>
>> +	  Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
>> +
>> +
>> +config SPI_XILINX_OF
>> +	tristate "Xilinx SPI controller OF device"
>> +	depends on SPI_XILINX && XILINX_VIRTEX
>> +	help
>> +	  This is the OF driver for the SPI controller IP from the Xilinx EDK.
>> +
>> +config SPI_XILINX_PLTFM
>> +	tristate "Xilinx SPI controller platform device"
>> +	depends on SPI_XILINX
>> +	help
>> +	  This is the platform driver for the SPI controller IP
>> +	  from the Xilinx EDK.
>> +
>>  #
>>  # Add new SPI master controllers in alphabetical order above this line
>>  #
>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
>> index 3de408d..5a91cf5 100644
>> --- a/drivers/spi/Makefile
>> +++ b/drivers/spi/Makefile
>> @@ -30,6 +30,8 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
>>  obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
>>  obj-$(CONFIG_SPI_TXX9)			+= spi_txx9.o
>>  obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
>> +obj-$(CONFIG_SPI_XILINX_OF)		+= xilinx_spi_of.o
>> +obj-$(CONFIG_SPI_XILINX_PLTFM)		+= xilinx_spi_pltfm.o
>>  obj-$(CONFIG_SPI_SH_SCI)		+= spi_sh_sci.o
>>  # 	... add above this line ...
>>
>> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
>> index 46b8c5c..0490820 100644
>> --- a/drivers/spi/xilinx_spi.c
>> +++ b/drivers/spi/xilinx_spi.c
>> @@ -14,22 +14,103 @@
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>>  #include <linux/interrupt.h>
>> -#include <linux/platform_device.h>
>> -
>> -#include <linux/of_platform.h>
>> -#include <linux/of_device.h>
>> -#include <linux/of_spi.h>
>>
>>  #include <linux/spi/spi.h>
>>  #include <linux/spi/spi_bitbang.h>
>>  #include <linux/io.h>
>>
>> -#define XILINX_SPI_NAME "xilinx_spi"
>> +#include "xilinx_spi.h"
>> +
>> +struct xilinx_spi {
>> +	/* bitbang has to be first */
>> +	struct spi_bitbang bitbang;
>> +	struct completion done;
>> +	struct resource mem; /* phys mem */
>> +	void __iomem	*regs;	/* virt. address of the control registers */
>> +	u32 irq;
>> +	u8 *rx_ptr;		/* pointer in the Tx buffer */
>> +	const u8 *tx_ptr;	/* pointer in the Rx buffer */
>> +	int remaining_bytes;	/* the number of bytes left to transfer */
>> +	/* offset to the XSPI regs, these might vary... */
>> +	u8 cr_offset;
>> +	u8 sr_offset;
>> +	u8 txd_offset;
>> +	u8 rxd_offset;
>> +	u8 ssr_offset;
>> +	u8 bits_per_word;
>> +	u8 model;
>> +};
>> +
>> +#ifdef CONFIG_X86
>> +/* on X86 the block often resides behind a PCI(e) interface which flips the
>> + * endian from little to big
>> + */
>> +#define xspi_in8(addr) ioread8(addr)
>> +#define xspi_in16(addr) ioread16(addr)
>> +#define xspi_in32(addr) ioread32(addr)
>> +
>> +#define xspi_out8(addr, b) iowrite8(b, addr)
>> +#define xspi_out16(addr, w) iowrite16(w, addr)
>> +#define xspi_out32(addr, l) iowrite32(l, addr)
>> +#else
>> +/* While on for instance PPC we use big endian */
>> +#define xspi_in8(addr) in_8(addr)
>> +#define xspi_in16(addr) in_be16(addr)
>> +#define xspi_in32(addr) in_be32(addr)
>> +
>> +#define xspi_out8(addr, b) out_8(addr, b)
>> +#define xspi_out16(addr, w) out_be16(addr, w)
>> +#define xspi_out32(addr, l) out_be32(addr, l)
>> +#endif
>> +
>> +
>> +static inline void xspi_write8(struct xilinx_spi *xspi, u32 offs, u8 val)
>> +{
>> +	if (xspi->model == XILINX_SPI_MODEL_DS464)
>> +		xspi_out8(xspi->regs + offs, val & 0xff);
>> +	else
>> +		xspi_out32(xspi->regs + offs, val);
>> +}
>> +
>> +static inline void xspi_write16(struct xilinx_spi *xspi, u32 offs, u16 val)
>> +{
>> +	if (xspi->model == XILINX_SPI_MODEL_DS464)
>> +		xspi_out16(xspi->regs + offs, val & 0xffff);
>> +	else
>> +		xspi_out32(xspi->regs + offs, val);
>> +}
>> +
>> +static inline void xspi_write32(struct xilinx_spi *xspi, u32 offs, u32 val)
>> +{
>> +	xspi_out32(xspi->regs + offs, val);
>> +}
>> +
>> +static inline u8 xspi_read8(struct xilinx_spi *xspi, u32 offs)
>> +{
>> +	if (xspi->model == XILINX_SPI_MODEL_DS464)
>> +		return xspi_in8(xspi->regs + offs);
>> +	else
>> +		return xspi_in32(xspi->regs + offs);
>> +}
>> +
>> +static inline u16 xspi_read16(struct xilinx_spi *xspi, u32 offs)
>> +{
>> +	if (xspi->model == XILINX_SPI_MODEL_DS464)
>> +		return xspi_in16(xspi->regs + offs);
>> +	else
>> +		return xspi_in32(xspi->regs + offs);
>> +}
>> +
>> +static inline u32 xspi_read32(struct xilinx_spi *xspi, u32 offs)
>> +{
>> +	return xspi_in32(xspi->regs + offs);
>> +}
>>
>>  /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
>>   * Product Specification", DS464
>>   */
>> -#define XSPI_CR_OFFSET		0x62	/* 16-bit Control Register */
>> +#define XSPI_CR_OFFSET_DS464	0x62	/* 16-bit Control Register */
>> +#define XSPI_CR_OFFSET_DS570	0x60
>>
>>  #define XSPI_CR_ENABLE		0x02
>>  #define XSPI_CR_MASTER_MODE	0x04
>> @@ -40,8 +121,10 @@
>>  #define XSPI_CR_RXFIFO_RESET	0x40
>>  #define XSPI_CR_MANUAL_SSELECT	0x80
>>  #define XSPI_CR_TRANS_INHIBIT	0x100
>> +#define XSPI_CR_LSB_FIRST	0x200
>>
>> -#define XSPI_SR_OFFSET		0x67	/* 8-bit Status Register */
>> +#define XSPI_SR_OFFSET_DS464	0x67	/* 8-bit Status Register */
>> +#define XSPI_SR_OFFSET_DS570	0x64
>>
>>  #define XSPI_SR_RX_EMPTY_MASK	0x01	/* Receive FIFO is empty */
>>  #define XSPI_SR_RX_FULL_MASK	0x02	/* Receive FIFO is full */
>> @@ -49,10 +132,13 @@
>>  #define XSPI_SR_TX_FULL_MASK	0x08	/* Transmit FIFO is full */
>>  #define XSPI_SR_MODE_FAULT_MASK	0x10	/* Mode fault error */
>>
>> -#define XSPI_TXD_OFFSET		0x6b	/* 8-bit Data Transmit Register */
>> -#define XSPI_RXD_OFFSET		0x6f	/* 8-bit Data Receive Register */
>> +#define XSPI_TXD_OFFSET_DS464	0x6b	/* 8-bit Data Transmit Register */
>> +#define XSPI_TXD_OFFSET_DS570	0x68
>> +#define XSPI_RXD_OFFSET_DS464	0x6f	/* 8-bit Data Receive Register */
>> +#define XSPI_RXD_OFFSET_DS570	0x6C
>>
>> -#define XSPI_SSR_OFFSET		0x70	/* 32-bit Slave Select Register */
>> +#define XSPI_SSR_OFFSET_DS464	0x70	/* 32-bit Slave Select Register */
>> +#define XSPI_SSR_OFFSET_DS570	0x70
>>
>>  /* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
>>   * IPIF registers are 32 bit
>> @@ -70,43 +156,27 @@
>>  #define XSPI_INTR_TX_UNDERRUN		0x08	/* TxFIFO was underrun */
>>  #define XSPI_INTR_RX_FULL		0x10	/* RxFIFO is full */
>>  #define XSPI_INTR_RX_OVERRUN		0x20	/* RxFIFO was overrun */
>> +#define XSPI_INTR_TX_HALF_EMPTY		0x40	/* TxFIFO is half empty */
>>
>>  #define XIPIF_V123B_RESETR_OFFSET	0x40	/* IPIF reset register */
>>  #define XIPIF_V123B_RESET_MASK		0x0a	/* the value to write */
>>
>> -struct xilinx_spi {
>> -	/* bitbang has to be first */
>> -	struct spi_bitbang bitbang;
>> -	struct completion done;
>> -
>> -	void __iomem	*regs;	/* virt. address of the control registers */
>> -
>> -	u32		irq;
>> -
>> -	u32		speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
>> -
>> -	u8 *rx_ptr;		/* pointer in the Tx buffer */
>> -	const u8 *tx_ptr;	/* pointer in the Rx buffer */
>> -	int remaining_bytes;	/* the number of bytes left to transfer */
>> -};
>> -
>> -static void xspi_init_hw(void __iomem *regs_base)
>> +static void xspi_init_hw(struct xilinx_spi *xspi)
>>  {
>>  	/* Reset the SPI device */
>> -	out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
>> -		 XIPIF_V123B_RESET_MASK);
>> +	xspi_write32(xspi, XIPIF_V123B_RESETR_OFFSET, XIPIF_V123B_RESET_MASK);
>>  	/* Disable all the interrupts just in case */
>> -	out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
>> +	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, 0);
>>  	/* Enable the global IPIF interrupt */
>> -	out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
>> -		 XIPIF_V123B_GINTR_ENABLE);
>> +	xspi_write32(xspi, XIPIF_V123B_DGIER_OFFSET, XIPIF_V123B_GINTR_ENABLE);
>>  	/* Deselect the slave on the SPI bus */
>> -	out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
>> +	xspi_write32(xspi, xspi->ssr_offset, 0xffff);
>>  	/* Disable the transmitter, enable Manual Slave Select Assertion,
>>  	 * put SPI controller into master mode, and enable it */
>> -	out_be16(regs_base + XSPI_CR_OFFSET,
>> -		 XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
>> -		 | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
>> +	xspi_write16(xspi, xspi->cr_offset,
>> +		 XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
>> +		 XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
>> +		 XSPI_CR_RXFIFO_RESET);
>>  }
>>
>>  static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
>> @@ -115,16 +185,16 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
>>
>>  	if (is_on == BITBANG_CS_INACTIVE) {
>>  		/* Deselect the slave on the SPI bus */
>> -		out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
>> +		xspi_write32(xspi, xspi->ssr_offset, 0xffff);
>>  	} else if (is_on == BITBANG_CS_ACTIVE) {
>>  		/* Set the SPI clock phase and polarity */
>> -		u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
>> +		u32 cr = xspi_read16(xspi, xspi->cr_offset)
>>  			 & ~XSPI_CR_MODE_MASK;
>>  		if (spi->mode & SPI_CPHA)
>>  			cr |= XSPI_CR_CPHA;
>>  		if (spi->mode & SPI_CPOL)
>>  			cr |= XSPI_CR_CPOL;
>> -		out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
>> +		xspi_write16(xspi, xspi->cr_offset, cr);
>>
>>  		/* We do not check spi->max_speed_hz here as the SPI clock
>>  		 * frequency is not software programmable (the IP block design
>> @@ -132,24 +202,27 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
>>  		 */
>>
>>  		/* Activate the chip select */
>> -		out_be32(xspi->regs + XSPI_SSR_OFFSET,
>> +		xspi_write32(xspi, xspi->ssr_offset,
>>  			 ~(0x0001 << spi->chip_select));
>>  	}
>>  }
>>
>>  /* spi_bitbang requires custom setup_transfer() to be defined if there is a
>>   * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
>> - * supports just 8 bits per word, and SPI clock can't be changed in software.
>> - * Check for 8 bits per word. Chip select delay calculations could be
>> + * supports 8 or 16 bits per word, which can not be changed in software.
>> + * SPI clock can't be changed in software.
>> + * Check for correct bits per word. Chip select delay calculations could be
>>   * added here as soon as bitbang_work() can be made aware of the delay value.
>>   */
>>  static int xilinx_spi_setup_transfer(struct spi_device *spi,
>> -		struct spi_transfer *t)
>> +	struct spi_transfer *t)
>>  {
>>  	u8 bits_per_word;
>> +	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
>>
>> -	bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
>> -	if (bits_per_word != 8) {
>> +	bits_per_word = (t->bits_per_word) ? t->bits_per_word :
>> +		spi->bits_per_word;
>> +	if (bits_per_word != xspi->bits_per_word) {
>>  		dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
>>  			__func__, bits_per_word);
>>  		return -EINVAL;
>> @@ -160,34 +233,50 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
>>
>>  static int xilinx_spi_setup(struct spi_device *spi)
>>  {
>> -	struct spi_bitbang *bitbang;
>> -	struct xilinx_spi *xspi;
>> -	int retval;
>> -
>> -	xspi = spi_master_get_devdata(spi->master);
>> -	bitbang = &xspi->bitbang;
>> -
>> -	retval = xilinx_spi_setup_transfer(spi, NULL);
>> -	if (retval < 0)
>> -		return retval;
>> -
>> +	/* always return 0, we can not check the number of bits.
>> +	 * There are cases when SPI setup is called before any driver is
>> +	 * there, in that case the SPI core defaults to 8 bits, which we
>> +	 * do not support in some cases. But if we return an error, the
>> +	 * SPI device would not be registered and no driver can get hold of it
>> +	 * When the driver is there, it will call SPI setup again with the
>> +	 * correct number of bits per transfer.
>> +	 * If a driver setups with the wrong bit number, it will fail when
>> +	 * it tries to do a transfer
>> +	 */
>>  	return 0;
>>  }
>>
>>  static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
>>  {
>> -	u8 sr;
>> +	u32 sr;
>> +	u8 wsize;
>> +	if (xspi->bits_per_word == 8)
>> +		wsize = 1;
>> +	else if (xspi->bits_per_word == 16)
>> +		wsize = 2;
>> +	else
>> +		wsize = 4;
>>
>>  	/* Fill the Tx FIFO with as many bytes as possible */
>> -	sr = in_8(xspi->regs + XSPI_SR_OFFSET);
>> -	while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
>> +	sr = xspi_read8(xspi, xspi->sr_offset);
>> +	while ((sr & XSPI_SR_TX_FULL_MASK) == 0 &&
>> +		xspi->remaining_bytes > 0) {
>>  		if (xspi->tx_ptr) {
>> -			out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
>> -		} else {
>> -			out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
>> -		}
>> -		xspi->remaining_bytes--;
>> -		sr = in_8(xspi->regs + XSPI_SR_OFFSET);
>> +			if (wsize == 1)
>> +				xspi_write8(xspi, xspi->txd_offset,
>> +					*xspi->tx_ptr);
>> +			else if (wsize == 2)
>> +				xspi_write16(xspi, xspi->txd_offset,
>> +					*(u16 *)(xspi->tx_ptr));
>> +			else if (wsize == 4)
>> +				xspi_write32(xspi, xspi->txd_offset,
>> +					*(u32 *)(xspi->tx_ptr));
>> +
>> +			xspi->tx_ptr += wsize;
>> +		} else
>> +			xspi_write8(xspi, xspi->txd_offset, 0);
>> +		xspi->remaining_bytes -= wsize;
>> +		sr = xspi_read8(xspi, xspi->sr_offset);
>>  	}
>>  }
>>
>> @@ -195,7 +284,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
>>  {
>>  	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
>>  	u32 ipif_ier;
>> -	u16 cr;
>> +	u32 cr;
>>
>>  	/* We get here with transmitter inhibited */
>>
>> @@ -209,23 +298,22 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
>>  	/* Enable the transmit empty interrupt, which we use to determine
>>  	 * progress on the transmission.
>>  	 */
>> -	ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
>> -	out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
>> +	ipif_ier = xspi_read32(xspi, XIPIF_V123B_IIER_OFFSET);
>> +	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET,
>>  		 ipif_ier | XSPI_INTR_TX_EMPTY);
>>
>>  	/* Start the transfer by not inhibiting the transmitter any longer */
>> -	cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
>> -	out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
>> +	cr = xspi_read16(xspi, xspi->cr_offset) & ~XSPI_CR_TRANS_INHIBIT;
>> +	xspi_write16(xspi, xspi->cr_offset, cr);
>>
>>  	wait_for_completion(&xspi->done);
>>
>>  	/* Disable the transmit empty interrupt */
>> -	out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
>> +	xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, ipif_ier);
>>
>>  	return t->len - xspi->remaining_bytes;
>>  }
>>
>> -
>>  /* This driver supports single master mode only. Hence Tx FIFO Empty
>>   * is the only interrupt we care about.
>>   * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
>> @@ -237,32 +325,50 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
>>  	u32 ipif_isr;
>>
>>  	/* Get the IPIF interrupts, and clear them immediately */
>> -	ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
>> -	out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
>> +	ipif_isr = xspi_read32(xspi, XIPIF_V123B_IISR_OFFSET);
>> +	xspi_write32(xspi, XIPIF_V123B_IISR_OFFSET, ipif_isr);
>>
>>  	if (ipif_isr & XSPI_INTR_TX_EMPTY) {	/* Transmission completed */
>> -		u16 cr;
>> -		u8 sr;
>> +		u32 cr;
>> +		u32 sr;
>> +		u8 rsize;
>> +		if (xspi->bits_per_word == 8)
>> +			rsize = 1;
>> +		else if (xspi->bits_per_word == 16)
>> +			rsize = 2;
>> +		else
>> +			rsize = 4;
>>
>>  		/* A transmit has just completed. Process received data and
>>  		 * check for more data to transmit. Always inhibit the
>>  		 * transmitter while the Isr refills the transmit register/FIFO,
>>  		 * or make sure it is stopped if we're done.
>>  		 */
>> -		cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
>> -		out_be16(xspi->regs + XSPI_CR_OFFSET,
>> -			 cr | XSPI_CR_TRANS_INHIBIT);
>> +		cr = xspi_read16(xspi, xspi->cr_offset);
>> +		xspi_write16(xspi, xspi->cr_offset, cr | XSPI_CR_TRANS_INHIBIT);
>>
>>  		/* Read out all the data from the Rx FIFO */
>> -		sr = in_8(xspi->regs + XSPI_SR_OFFSET);
>> +		sr = xspi_read8(xspi, xspi->sr_offset);
>>  		while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
>> -			u8 data;
>> +			u32 data;
>> +			if (rsize == 1)
>> +				data = xspi_read8(xspi, xspi->rxd_offset);
>> +			else if (rsize == 2)
>> +				data = xspi_read16(xspi, xspi->rxd_offset);
>> +			else
>> +				data = xspi_read32(xspi, xspi->rxd_offset);
>>
>> -			data = in_8(xspi->regs + XSPI_RXD_OFFSET);
>>  			if (xspi->rx_ptr) {
>> -				*xspi->rx_ptr++ = data;
>> +				if (rsize == 1)
>> +					*xspi->rx_ptr = data & 0xff;
>> +				else if (rsize == 2)
>> +					*(u16 *)(xspi->rx_ptr) = data & 0xffff;
>> +				else
>> +					*((u32 *)(xspi->rx_ptr)) = data;
>> +				xspi->rx_ptr += rsize;
>>  			}
>> -			sr = in_8(xspi->regs + XSPI_SR_OFFSET);
>> +
>> +			sr = xspi_read8(xspi, xspi->sr_offset);
>>  		}
>>
>>  		/* See if there is more data to send */
>> @@ -271,7 +377,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
>>  			/* Start the transfer by not inhibiting the
>>  			 * transmitter any longer
>>  			 */
>> -			out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
>> +			xspi_write16(xspi, xspi->cr_offset, cr);
>>  		} else {
>>  			/* No more data to send.
>>  			 * Indicate the transfer is completed.
>> @@ -279,44 +385,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
>>  			complete(&xspi->done);
>>  		}
>>  	}
>> -
>>  	return IRQ_HANDLED;
>>  }
>>
>> -static int __init xilinx_spi_of_probe(struct of_device *ofdev,
>> -					const struct of_device_id *match)
>> +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
>> +	u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word)
>>  {
>>  	struct spi_master *master;
>>  	struct xilinx_spi *xspi;
>> -	struct resource r_irq_struct;
>> -	struct resource r_mem_struct;
>> +	int ret = 0;
>>
>> -	struct resource *r_irq = &r_irq_struct;
>> -	struct resource *r_mem = &r_mem_struct;
>> -	int rc = 0;
>> -	const u32 *prop;
>> -	int len;
>> +	master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
>>
>> -	/* Get resources(memory, IRQ) associated with the device */
>> -	master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
>> -
>> -	if (master == NULL) {
>> -		return -ENOMEM;
>> -	}
>> -
>> -	dev_set_drvdata(&ofdev->dev, master);
>> -
>> -	rc = of_address_to_resource(ofdev->node, 0, r_mem);
>> -	if (rc) {
>> -		dev_warn(&ofdev->dev, "invalid address\n");
>> -		goto put_master;
>> -	}
>> -
>> -	rc = of_irq_to_resource(ofdev->node, 0, r_irq);
>> -	if (rc == NO_IRQ) {
>> -		dev_warn(&ofdev->dev, "no IRQ found\n");
>> -		goto put_master;
>> -	}
>> +	if (master == NULL)
>> +		return ERR_PTR(-ENOMEM);
>>
>>  	/* the spi->mode bits understood by this driver: */
>>  	master->mode_bits = SPI_CPOL | SPI_CPHA;
>> @@ -329,128 +411,87 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
>>  	xspi->bitbang.master->setup = xilinx_spi_setup;
>>  	init_completion(&xspi->done);
>>
>> -	xspi->irq = r_irq->start;
>> -
>> -	if (!request_mem_region(r_mem->start,
>> -			r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
>> -		rc = -ENXIO;
>> -		dev_warn(&ofdev->dev, "memory request failure\n");
>> +	if (!request_mem_region(mem->start, resource_size(mem),
>> +		XILINX_SPI_NAME)) {
>> +		ret = -ENXIO;
>>  		goto put_master;
>>  	}
>>
>> -	xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
>> +	xspi->regs = ioremap(mem->start, resource_size(mem));
>>  	if (xspi->regs == NULL) {
>> -		rc = -ENOMEM;
>> -		dev_warn(&ofdev->dev, "ioremap failure\n");
>> -		goto release_mem;
>> +		ret = -ENOMEM;
>> +		dev_warn(dev, "ioremap failure\n");
>> +		goto map_failed;
>>  	}
>> -	xspi->irq = r_irq->start;
>> -
>> -	/* dynamic bus assignment */
>> -	master->bus_num = -1;
>>
>> -	/* number of slave select bits is required */
>> -	prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
>> -	if (!prop || len < sizeof(*prop)) {
>> -		dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
>> -		goto unmap_io;
>> +	master->bus_num = bus_num;
>> +	master->num_chipselect = num_chipselect;
>> +
>> +	xspi->mem = *mem;
>> +	xspi->irq = irq;
>> +	xspi->bits_per_word = bits_per_word;
>> +	xspi->model = model;
>> +
>> +	if (model == XILINX_SPI_MODEL_DS464) {
>> +		xspi->cr_offset = XSPI_CR_OFFSET_DS464;
>> +		xspi->sr_offset = XSPI_SR_OFFSET_DS464;
>> +		xspi->txd_offset = XSPI_TXD_OFFSET_DS464;
>> +		xspi->rxd_offset = XSPI_RXD_OFFSET_DS464;
>> +		xspi->ssr_offset = XSPI_SSR_OFFSET_DS464;
>> +	} else {
>> +		xspi->cr_offset = XSPI_CR_OFFSET_DS570;
>> +		xspi->sr_offset = XSPI_SR_OFFSET_DS570;
>> +		xspi->txd_offset = XSPI_TXD_OFFSET_DS570;
>> +		xspi->rxd_offset = XSPI_RXD_OFFSET_DS570;
>> +		xspi->ssr_offset = XSPI_SSR_OFFSET_DS570;
>>  	}
>> -	master->num_chipselect = *prop;
>>
>>  	/* SPI controller initializations */
>> -	xspi_init_hw(xspi->regs);
>> +	xspi_init_hw(xspi);
>>
>>  	/* Register for SPI Interrupt */
>> -	rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
>> -	if (rc != 0) {
>> -		dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
>> +	ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
>> +	if (ret != 0)
>>  		goto unmap_io;
>> -	}
>>
>> -	rc = spi_bitbang_start(&xspi->bitbang);
>> -	if (rc != 0) {
>> -		dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
>> +	ret = spi_bitbang_start(&xspi->bitbang);
>> +	if (ret != 0) {
>> +		dev_err(dev, "spi_bitbang_start FAILED\n");
>>  		goto free_irq;
>>  	}
>>
>> -	dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
>> -			(unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
>> -
>> -	/* Add any subnodes on the SPI bus */
>> -	of_register_spi_devices(master, ofdev->node);
>> -
>> -	return rc;
>> +	dev_info(dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
>> +		(u32)mem->start, (u32)xspi->regs, xspi->irq);
>> +	return master;
>>
>>  free_irq:
>>  	free_irq(xspi->irq, xspi);
>>  unmap_io:
>>  	iounmap(xspi->regs);
>> -release_mem:
>> -	release_mem_region(r_mem->start, resource_size(r_mem));
>> +map_failed:
>> +	release_mem_region(mem->start, resource_size(mem));
>>  put_master:
>>  	spi_master_put(master);
>> -	return rc;
>> +	return ERR_PTR(ret);
>>  }
>> +EXPORT_SYMBOL(xilinx_spi_init);
>>
>> -static int __devexit xilinx_spi_remove(struct of_device *ofdev)
>> +void xilinx_spi_deinit(struct spi_master *master)
>>  {
>>  	struct xilinx_spi *xspi;
>> -	struct spi_master *master;
>> -	struct resource r_mem;
>>
>> -	master = platform_get_drvdata(ofdev);
>>  	xspi = spi_master_get_devdata(master);
>>
>>  	spi_bitbang_stop(&xspi->bitbang);
>>  	free_irq(xspi->irq, xspi);
>>  	iounmap(xspi->regs);
>> -	if (!of_address_to_resource(ofdev->node, 0, &r_mem))
>> -		release_mem_region(r_mem.start, resource_size(&r_mem));
>> -	dev_set_drvdata(&ofdev->dev, 0);
>> -	spi_master_put(xspi->bitbang.master);
>> -
>> -	return 0;
>> -}
>> -
>> -/* work with hotplug and coldplug */
>> -MODULE_ALIAS("platform:" XILINX_SPI_NAME);
>> -
>> -static int __exit xilinx_spi_of_remove(struct of_device *op)
>> -{
>> -	return xilinx_spi_remove(op);
>> -}
>> -
>> -static struct of_device_id xilinx_spi_of_match[] = {
>> -	{ .compatible = "xlnx,xps-spi-2.00.a", },
>> -	{ .compatible = "xlnx,xps-spi-2.00.b", },
>> -	{}
>> -};
>> -
>> -MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
>> -
>> -static struct of_platform_driver xilinx_spi_of_driver = {
>> -	.owner = THIS_MODULE,
>> -	.name = "xilinx-xps-spi",
>> -	.match_table = xilinx_spi_of_match,
>> -	.probe = xilinx_spi_of_probe,
>> -	.remove = __exit_p(xilinx_spi_of_remove),
>> -	.driver = {
>> -		.name = "xilinx-xps-spi",
>> -		.owner = THIS_MODULE,
>> -	},
>> -};
>>
>> -static int __init xilinx_spi_init(void)
>> -{
>> -	return of_register_platform_driver(&xilinx_spi_of_driver);
>> +	release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
>> +	spi_master_put(xspi->bitbang.master);
>>  }
>> -module_init(xilinx_spi_init);
>> +EXPORT_SYMBOL(xilinx_spi_deinit);
>>
>> -static void __exit xilinx_spi_exit(void)
>> -{
>> -	of_unregister_platform_driver(&xilinx_spi_of_driver);
>> -}
>> -module_exit(xilinx_spi_exit);
>>  MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
>>  MODULE_DESCRIPTION("Xilinx SPI driver");
>>  MODULE_LICENSE("GPL");
>> +
>> diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
>> new file mode 100644
>> index 0000000..d951b11
>> --- /dev/null
>> +++ b/drivers/spi/xilinx_spi.h
>> @@ -0,0 +1,32 @@
>> +/*
>> + * xilinx_spi.h
>> + * Copyright (c) 2009 Intel Corporation
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * 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 _XILINX_SPI_H_
>> +#define _XILINX_SPI_H_ 1
>> +
>> +#include <linux/spi/spi.h>
>> +#include <linux/spi/spi_bitbang.h>
>> +#include <linux/spi/xilinx_spi.h>
>> +
>> +#define XILINX_SPI_NAME "xilinx_spi"
>> +
>> +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
>> +	u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word);
>> +
>> +void xilinx_spi_deinit(struct spi_master *master);
>> +#endif
>> diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
>> new file mode 100644
>> index 0000000..4f54ddd
>> --- /dev/null
>> +++ b/drivers/spi/xilinx_spi_of.c
>> @@ -0,0 +1,120 @@
>> +/*
>> + * xilinx_spi_of.c
>> + *
>> + * Xilinx SPI controller driver (master mode only)
>> + *
>> + * Author: MontaVista Software, Inc.
>> + *	source@mvista.com
>> + *
>> + * 2002-2007 (c) MontaVista Software, Inc.  This file is licensed under the
>> + * terms of the GNU General Public License version 2.  This program is licensed
>> + * "as is" without any warranty of any kind, whether express or implied.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include <linux/of_platform.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_spi.h>
>> +
>> +#include <linux/spi/spi.h>
>> +#include <linux/spi/spi_bitbang.h>
>> +
>> +#include "xilinx_spi.h"
>> +
>> +
>> +static int __init xilinx_spi_of_probe(struct of_device *ofdev,
>> +					const struct of_device_id *match)
>> +{
>> +	struct resource r_irq_struct;
>> +	struct resource r_mem_struct;
>> +	struct spi_master *master;
>> +
>> +	struct resource *r_irq = &r_irq_struct;
>> +	struct resource *r_mem = &r_mem_struct;
>> +	int rc = 0;
>> +	const u32 *prop;
>> +	int len;
>> +
>> +	rc = of_address_to_resource(ofdev->node, 0, r_mem);
>> +	if (rc) {
>> +		dev_warn(&ofdev->dev, "invalid address\n");
>> +		return rc;
>> +	}
>> +
>> +	rc = of_irq_to_resource(ofdev->node, 0, r_irq);
>> +	if (rc == NO_IRQ) {
>> +		dev_warn(&ofdev->dev, "no IRQ found\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	/* number of slave select bits is required */
>> +	prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
>> +	if (!prop || len < sizeof(*prop)) {
>> +		dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
>> +		return -EINVAL;
>> +	}
>> +	master = xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start,
>> +		XILINX_SPI_MODEL_DS464, -1, *prop, 8);
>> +	if (IS_ERR(master))
>> +		return PTR_ERR(master);
>> +
>> +	dev_set_drvdata(&ofdev->dev, master);
>> +
>> +	/* Add any subnodes on the SPI bus */
>> +	of_register_spi_devices(master, ofdev->node);
>> +
>> +	return 0;
>> +}
>> +
>> +static int __devexit xilinx_spi_remove(struct of_device *ofdev)
>> +{
>> +	xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
>> +	dev_set_drvdata(&ofdev->dev, 0);
>> +	return 0;
>> +}
>> +
>> +static int __exit xilinx_spi_of_remove(struct of_device *op)
>> +{
>> +	return xilinx_spi_remove(op);
>> +}
>> +
>> +static struct of_device_id xilinx_spi_of_match[] = {
>> +	{ .compatible = "xlnx,xps-spi-2.00.a", },
>> +	{ .compatible = "xlnx,xps-spi-2.00.b", },
>> +	{}
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
>> +
>> +static struct of_platform_driver xilinx_spi_of_driver = {
>> +	.owner = THIS_MODULE,
>> +	.name = "xilinx-xps-spi",
>> +	.match_table = xilinx_spi_of_match,
>> +	.probe = xilinx_spi_of_probe,
>> +	.remove = __exit_p(xilinx_spi_of_remove),
>> +	.driver = {
>> +		.name = "xilinx-xps-spi",
>> +		.owner = THIS_MODULE,
>> +	},
>> +};
>> +
>> +static int __init xilinx_spi_of_init(void)
>> +{
>> +	return of_register_platform_driver(&xilinx_spi_of_driver);
>> +}
>> +module_init(xilinx_spi_of_init);
>> +
>> +static void __exit xilinx_spi_of_exit(void)
>> +{
>> +	of_unregister_platform_driver(&xilinx_spi_of_driver);
>> +}
>> +module_exit(xilinx_spi_of_exit);
>> +MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
>> +MODULE_DESCRIPTION("Xilinx SPI driver");
>> +MODULE_LICENSE("GPL");
>> +
>> diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltfm.c
>> new file mode 100644
>> index 0000000..d59d509
>> --- /dev/null
>> +++ b/drivers/spi/xilinx_spi_pltfm.c
>> @@ -0,0 +1,104 @@
>> +/*
>> + * xilinx_spi_pltfm.c Support for Xilinx SPI platform devices
>> + * Copyright (c) 2009 Intel Corporation
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * 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.
>> + */
>> +
>> +/* Supports:
>> + * Xilinx SPI devices as platform devices
>> + *
>> + * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include <linux/spi/spi.h>
>> +#include <linux/spi/spi_bitbang.h>
>> +#include <linux/spi/xilinx_spi.h>
>> +
>> +#include "xilinx_spi.h"
>> +
>> +static int __devinit xilinx_spi_probe(struct platform_device *dev)
>> +{
>> +	struct xspi_platform_data *pdata;
>> +	struct resource *r;
>> +	int irq;
>> +	struct spi_master *master;
>> +	u8 i;
>> +
>> +	pdata = dev->dev.platform_data;
>> +	if (pdata == NULL)
>> +		return -ENODEV;
>> +
>> +	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
>> +	if (r == NULL)
>> +		return -ENODEV;
>> +
>> +	irq = platform_get_irq(dev, 0);
>> +	if (irq < 0)
>> +		return -ENXIO;
>> +
>> +	master = xilinx_spi_init(&dev->dev, r, irq, pdata->model,
>> +		dev->id, pdata->num_chipselect, pdata->bits_per_word);
>> +	if (IS_ERR(master))
>> +		return PTR_ERR(master);
>> +
>> +	for (i = 0; i < pdata->num_devices; i++)
>> +		spi_new_device(master, pdata->devices + i);
>> +
>> +	platform_set_drvdata(dev, master);
>> +	return 0;
>> +}
>> +
>> +static int __devexit xilinx_spi_remove(struct platform_device *dev)
>> +{
>> +	xilinx_spi_deinit(platform_get_drvdata(dev));
>> +	platform_set_drvdata(dev, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +/* work with hotplug and coldplug */
>> +MODULE_ALIAS("platform:" XILINX_SPI_NAME);
>> +
>> +static struct platform_driver xilinx_spi_driver = {
>> +	.probe	= xilinx_spi_probe,
>> +	.remove	= __devexit_p(xilinx_spi_remove),
>> +	.driver = {
>> +		.name = XILINX_SPI_NAME,
>> +		.owner = THIS_MODULE,
>> +	},
>> +};
>> +
>> +static int __init xilinx_spi_pltfm_init(void)
>> +{
>> +	return platform_driver_register(&xilinx_spi_driver);
>> +}
>> +module_init(xilinx_spi_pltfm_init);
>> +
>> +static void __exit xilinx_spi_pltfm_exit(void)
>> +{
>> +	platform_driver_unregister(&xilinx_spi_driver);
>> +}
>> +module_exit(xilinx_spi_pltfm_exit);
>> +
>> +MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
>> +MODULE_DESCRIPTION("Xilinx SPI platform driver");
>> +MODULE_LICENSE("GPL v2");
>> +
>> diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h
>> new file mode 100644
>> index 0000000..e9e6a84
>> --- /dev/null
>> +++ b/include/linux/spi/xilinx_spi.h
>> @@ -0,0 +1,18 @@
>> +#ifndef __LINUX_SPI_XILINX_SPI_H
>> +#define __LINUX_SPI_XILINX_SPI_H
>> +
>> +#define XILINX_SPI_MODEL_DS464 0
>> +#define XILINX_SPI_MODEL_DS570 1
>> +
>> +/* SPI Controller IP */
>> +struct xspi_platform_data {
>> +	u16 num_chipselect;
>> +	u8 model;
>> +	u8 bits_per_word;
>> +	/* devices to add to the bus when the host is up */
>> +	struct spi_board_info *devices;
>> +	u8 num_devices;
>> +};
>> +
>> +#endif /* __LINUX_SPI_XILINX_SPI_H */
>> +
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 
> 
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
> 
> 

^ permalink raw reply

* Re: [PATCH 2/6] mtd: m25p80: Convert to device table matching
From: Anton Vorontsov @ 2009-09-22 23:01 UTC (permalink / raw)
  To: Andrew Morton
  Cc: ben, linux-kernel, lm-sensors, David Brownell, linuxppc-dev,
	linux-mtd, khali, dwmw2
In-Reply-To: <20090922141705.b5d31e24.akpm@linux-foundation.org>

On Tue, Sep 22, 2009 at 02:17:05PM -0700, Andrew Morton wrote:
> On Mon, 3 Aug 2009 19:54:50 -0700
> David Brownell <david-b@pacbell.net> wrote:
> 
> > On Thursday 30 July 2009, Anton Vorontsov wrote:
> > > This patch converts the m25p80 driver so that now it uses .id_table
> > > for device matching, making it properly detect devices on OpenFirmware
> > > platforms (prior to this patch the driver misdetected non-JEDEC chips,
> > > seeing all chips as "m25p80").
> > 
> > I suspect "detect" is a misnomer there.  It only "detects" JEDEC chips.
> > All others got explicit declarations ... so if there's misbehavior for
> > other chips, it's because those declarations were poorly handled.  Maybe
> > they were not properly flagged as non-JDEC
> > 
> >  
> > > Also, now jedec_probe() only does jedec probing, nothing else. If it
> > > is not able to detect a chip, NULL is returned and the driver fall
> > > backs to the information specified by the platform (platform_data, or
> > > exact ID).
> > 
> > I'd rather keep the warning, so there's a clue about what's really
> > going on:  JEDEC chip found, but its ID is not handled.
> > 
> 
> afaik there was no response to David's review comments, so this patch
> is in the "stuck" state.

Hm? Response:

http://lkml.org/lkml/2009/8/18/363

And the two patches I sent on top:

http://lkml.org/lkml/2009/8/18/364
http://lkml.org/lkml/2009/8/18/366

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH 2/2] mtd: m25p80: Add support for CAT25xxx serial EEPROMs
From: Andrew Morton @ 2009-09-22 23:25 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: dbrownell, dedekind1, linux-kernel, linuxppc-dev, linux-mtd,
	dwmw2
In-Reply-To: <20090818214628.GB22651@oksana.dev.rtsoft.ru>

On Wed, 19 Aug 2009 01:46:28 +0400
Anton Vorontsov <avorontsov@ru.mvista.com> wrote:

> CAT25 chips (as manufactured by On Semiconductor, previously Catalyst
> Semiconductor) are similar to the original M25Px0 chips, except:
> 
> - Address width can vary (1-2 bytes, in contrast to 3 bytes in M25P
>   chips). So, implement convenient m25p_addr2cmd() and m25p_cmdsz()
>   calls, and place address width information into flash_info struct;
> 
> - Page size can vary, therefore we shouldn't hardcode it, so get rid
>   of FLASH_PAGESIZE definition, and place the page size information
>   into flash_info struct;
> 
> - CAT25 EEPROMs don't need to be erased, so add NO_ERASE flag, and
>   propagate it to the mtd subsystem.

This patch (still) doesn't know about the mx25l3205d, mx25l12805d and
mx25l12855e devices.

I randomly did this:

->	{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 256, 3, 0) },
->	{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 256, 3, 0) },
	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 256, 3, 0) },
->	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 256, 3, 0) },

^ permalink raw reply

* Re: [PATCH 2/2] mtd: m25p80: Add support for CAT25xxx serial EEPROMs
From: Anton Vorontsov @ 2009-09-22 23:40 UTC (permalink / raw)
  To: Andrew Morton
  Cc: dbrownell, dedekind1, linux-kernel, linuxppc-dev, linux-mtd,
	dwmw2
In-Reply-To: <20090922162548.3e20e67c.akpm@linux-foundation.org>

On Tue, Sep 22, 2009 at 04:25:48PM -0700, Andrew Morton wrote:
> On Wed, 19 Aug 2009 01:46:28 +0400
> Anton Vorontsov <avorontsov@ru.mvista.com> wrote:
> 
> > CAT25 chips (as manufactured by On Semiconductor, previously Catalyst
> > Semiconductor) are similar to the original M25Px0 chips, except:
> > 
> > - Address width can vary (1-2 bytes, in contrast to 3 bytes in M25P
> >   chips). So, implement convenient m25p_addr2cmd() and m25p_cmdsz()
> >   calls, and place address width information into flash_info struct;
> > 
> > - Page size can vary, therefore we shouldn't hardcode it, so get rid
> >   of FLASH_PAGESIZE definition, and place the page size information
> >   into flash_info struct;
> > 
> > - CAT25 EEPROMs don't need to be erased, so add NO_ERASE flag, and
> >   propagate it to the mtd subsystem.
> 
> This patch (still) doesn't know about the mx25l3205d, mx25l12805d and
> mx25l12855e devices.

Yes, support for these chips commited on Fri, 4 Sep 2009 08:40:27
+0000 (09:40 +0100). And the patch dated 19 Aug.

> I randomly did this:
> 
> ->	{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 256, 3, 0) },
> ->	{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 256, 3, 0) },
> 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 256, 3, 0) },
> ->	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 256, 3, 0) },

Looks correct, thanks a lot.

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH 2/6] mtd: m25p80: Convert to device table matching
From: David Woodhouse @ 2009-09-22 23:43 UTC (permalink / raw)
  To: avorontsov
  Cc: ben, linux-kernel, lm-sensors, David Brownell, linuxppc-dev,
	linux-mtd, khali, Andrew Morton
In-Reply-To: <20090922230150.GA27593@oksana.dev.rtsoft.ru>

On Wed, 2009-09-23 at 03:01 +0400, Anton Vorontsov wrote:
> 
> And the two patches I sent on top:
> 
> http://lkml.org/lkml/2009/8/18/364
> http://lkml.org/lkml/2009/8/18/366

Got versions of those which apply to the mtd-2.6.git tree (which I'm
about to ask Linus to pull)? 

-- 
dwmw2

^ permalink raw reply

* Re: [PATCH 2/6] mtd: m25p80: Convert to device table matching
From: Andrew Morton @ 2009-09-22 23:52 UTC (permalink / raw)
  To: David Woodhouse
  Cc: ben, linux-kernel, lm-sensors, david-b, linuxppc-dev, linux-mtd,
	khali
In-Reply-To: <1253663027.27055.528.camel@macbook.infradead.org>

On Tue, 22 Sep 2009 16:43:47 -0700
David Woodhouse <dwmw2@infradead.org> wrote:

> On Wed, 2009-09-23 at 03:01 +0400, Anton Vorontsov wrote:
> > 
> > And the two patches I sent on top:
> > 
> > http://lkml.org/lkml/2009/8/18/364
> > http://lkml.org/lkml/2009/8/18/366
> 
> Got versions of those which apply to the mtd-2.6.git tree (which I'm
> about to ask Linus to pull)? 
> 

I'll send them in a sec.

^ permalink raw reply

* Re: [PATCH 2/6] mtd: m25p80: Convert to device table matching
From: Anton Vorontsov @ 2009-09-22 23:55 UTC (permalink / raw)
  To: David Woodhouse
  Cc: ben, linux-kernel, lm-sensors, David Brownell, linuxppc-dev,
	linux-mtd, khali, Andrew Morton
In-Reply-To: <1253663027.27055.528.camel@macbook.infradead.org>

On Tue, Sep 22, 2009 at 04:43:47PM -0700, David Woodhouse wrote:
> On Wed, 2009-09-23 at 03:01 +0400, Anton Vorontsov wrote:
> > 
> > And the two patches I sent on top:
> > 
> > http://lkml.org/lkml/2009/8/18/364
> > http://lkml.org/lkml/2009/8/18/366
> 
> Got versions of those which apply to the mtd-2.6.git tree (which I'm
> about to ask Linus to pull)? 

I'd love to, but they depend on a bunch of SPI patches that are still
in -mm tree. As soon as SPI core changes hit Linus' tree, I think
Andrew will send all m25p80 patches to you anyway.

Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: powerpc: Move 64bit heap above 1TB on machines with 1TB segments
From: David Gibson @ 2009-09-23  0:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Mel Gorman, Anton Blanchard
In-Reply-To: <1253653702.7103.244.camel@pasglop>

On Wed, Sep 23, 2009 at 07:08:22AM +1000, Benjamin Herrenschmidt wrote:
> 
> > Unfortunately, I am not sensitive to issues surrounding 1TB segments or how
> > they are currently being used. However, as this clearly helps performance
> > for large amounts of memory, is it worth providing an option to
> > libhugetlbfs to locate 16MB pages above 1TB when they are otherwise being
> > unused?
> 
> AFAIK, that is already the case, at least the kernel will hand out pages
> above 1T preferentially iirc.
> 
> There were talks about making huge pages below 1T not even come up
> untily you ask for them with MAP_FIXED, dunno where that went.

That was already the case as far as I remember.  But it's just
possible that changed when the general slice handling code came in,

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ 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