public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v1 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
@ 2015-01-16  7:19 Albert ARIBAUD
  2015-01-16  7:19 ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
  0 siblings, 1 reply; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

This series extends functionality for the LPC32xx platform and
introduces the WORK Microwave work_92105 board which makes use
of the extended functionality.

NOTES:

The series is not entirely checkpatch-clean. The following warnings
and checks were not fixed:

1. "warning: tools/mklpc32xxboot.c,81: quoted string split across lines"
   There seems to be no way to remove this error without making the
   line longer than 80 characters, which causes checkpatch to complain.

2. "warning: arch/arm/Kconfig,241: please write a paragraph that describes
    the config symbol fully"
   Other symbols in the same file have no description either. For
   consistency, I did not add the requested description.

3. "check: include/configs/work_92105.h,177: spaces required around that
   ':' (ctx:VxV)
   (5 occurrences on the same line)
   This is due to the value of CONFIG_ETHADDR not being in quotes. As it
   never is in any other definition of CONFIG_ETHADDR, I left it
   unchanged.


Albert ARIBAUD (3ADEV) (8):
  lpc32xx: add Ethernet support
  lpc32xx: mtd: nand: add MLC NAND controller
  lpc32xx: i2c: add LPC32xx I2C interface support
  lpc32xx: add GPIO support
  lpc32xx: add LPC32xx SSP support (SPI mode)
  dtt: add ds620 support
  lpc32xx: add lpc32xx-spl.bin boot image target
  lpc32xx: add support for board work_92105

 Makefile                                           |   3 +
 arch/arm/Kconfig                                   |   6 +
 arch/arm/cpu/arm926ejs/lpc32xx/Makefile            |   2 +
 arch/arm/cpu/arm926ejs/lpc32xx/clk.c               |  34 ++
 arch/arm/cpu/arm926ejs/lpc32xx/cpu.c               |  13 +
 arch/arm/cpu/arm926ejs/lpc32xx/devices.c           |  30 +
 arch/arm/cpu/arm926ejs/lpc32xx/dram.c              |  80 +++
 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S     |  45 ++
 arch/arm/include/asm/arch-lpc32xx/clk.h            |  16 +
 arch/arm/include/asm/arch-lpc32xx/config.h         |   3 +
 arch/arm/include/asm/arch-lpc32xx/cpu.h            |   2 +
 arch/arm/include/asm/arch-lpc32xx/gpio.h           |  43 ++
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h      |   8 +-
 board/work-microwave/work_92105/Kconfig            |  15 +
 board/work-microwave/work_92105/MAINTAINERS        |   6 +
 board/work-microwave/work_92105/Makefile           |   8 +
 board/work-microwave/work_92105/README             |  23 +
 board/work-microwave/work_92105/work_92105.c       |  85 +++
 .../work-microwave/work_92105/work_92105_display.c | 345 +++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 configs/work_92105_defconfig                       |   3 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/lpc32xx_gpio.c                        | 223 ++++++++
 drivers/hwmon/Makefile                             |   1 +
 drivers/hwmon/ds620.c                              |  65 +++
 drivers/i2c/Makefile                               |   1 +
 drivers/i2c/lpc32xx_i2c.c                          | 249 ++++++++
 drivers/mtd/nand/Makefile                          |   1 +
 drivers/mtd/nand/lpc32xx_nand_mlc.c                | 589 +++++++++++++++++++
 drivers/net/Makefile                               |   1 +
 drivers/net/lpc32xx_eth.c                          | 636 +++++++++++++++++++++
 drivers/spi/Makefile                               |   1 +
 drivers/spi/lpc32xx_ssp.c                          | 132 +++++
 include/configs/work_92105.h                       | 257 +++++++++
 include/dtt.h                                      |  15 +-
 include/netdev.h                                   |   1 +
 scripts/Makefile.spl                               |  11 +
 tools/.gitignore                                   |   1 +
 tools/Makefile                                     |   2 +
 tools/mklpc32xxboot.c                              | 169 ++++++
 40 files changed, 3132 insertions(+), 8 deletions(-)
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/dram.c
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
 create mode 100644 arch/arm/include/asm/arch-lpc32xx/gpio.h
 create mode 100644 board/work-microwave/work_92105/Kconfig
 create mode 100644 board/work-microwave/work_92105/MAINTAINERS
 create mode 100644 board/work-microwave/work_92105/Makefile
 create mode 100644 board/work-microwave/work_92105/README
 create mode 100644 board/work-microwave/work_92105/work_92105.c
 create mode 100644 board/work-microwave/work_92105/work_92105_display.c
 create mode 100644 board/work-microwave/work_92105/work_92105_display.h
 create mode 100644 configs/work_92105_defconfig
 create mode 100644 drivers/gpio/lpc32xx_gpio.c
 create mode 100644 drivers/hwmon/ds620.c
 create mode 100644 drivers/i2c/lpc32xx_i2c.c
 create mode 100644 drivers/mtd/nand/lpc32xx_nand_mlc.c
 create mode 100644 drivers/net/lpc32xx_eth.c
 create mode 100644 drivers/spi/lpc32xx_ssp.c
 create mode 100644 include/configs/work_92105.h
 create mode 100644 tools/mklpc32xxboot.c

-- 
2.1.0

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

* [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support
  2015-01-16  7:19 [U-Boot] [PATCH v1 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
@ 2015-01-16  7:19 ` Albert ARIBAUD
  2015-01-16  7:19   ` [U-Boot] [PATCH v1 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
  2015-01-16 16:46   ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Joe Hershberger
  0 siblings, 2 replies; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/cpu/arm926ejs/lpc32xx/cpu.c          |   9 +
 arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |   7 +
 arch/arm/include/asm/arch-lpc32xx/config.h    |   3 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h |   1 +
 drivers/net/Makefile                          |   1 +
 drivers/net/lpc32xx_eth.c                     | 636 ++++++++++++++++++++++++++
 include/netdev.h                              |   1 +
 7 files changed, 658 insertions(+)
 create mode 100644 drivers/net/lpc32xx_eth.c

diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
index 35095a9..eec4d9e 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/clk.h>
 #include <asm/arch/wdt.h>
@@ -55,3 +56,11 @@ int print_cpuinfo(void)
 	return 0;
 }
 #endif
+
+#ifdef CONFIG_LPC32XX_ETH
+int cpu_eth_init(bd_t *bis)
+{
+	lpc32xx_eth_initialize(bis);
+	return 0;
+}
+#endif
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index b567657..062db8d 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -37,3 +37,10 @@ void lpc32xx_uart_init(unsigned int uart_id)
 	writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1),
 	       &clk->u3clk + (uart_id - 3));
 }
+
+void lpc32xx_mac_init(void)
+{
+	/* Enable MAC interface */
+	writel(CLK_MAC_REG | CLK_MAC_SLAVE | CLK_MAC_MASTER
+		| CLK_MAC_MII, &clk->macclk_ctrl);
+}
diff --git a/arch/arm/include/asm/arch-lpc32xx/config.h b/arch/arm/include/asm/arch-lpc32xx/config.h
index 8f6426b..6c9526d 100644
--- a/arch/arm/include/asm/arch-lpc32xx/config.h
+++ b/arch/arm/include/asm/arch-lpc32xx/config.h
@@ -50,6 +50,9 @@
 #define CONFIG_SYS_BAUDRATE_TABLE	\
 		{ 9600, 19200, 38400, 57600, 115200, 230400, 460800 }
 
+/* Ethernet */
+#define LPC32XX_ETH_BASE ETHERNET_BASE
+
 /* NOR Flash */
 #if defined(CONFIG_SYS_FLASH_CFI)
 #define CONFIG_FLASH_CFI_DRIVER
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index 28812be..a6b8826 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -8,5 +8,6 @@
 #define _LPC32XX_SYS_PROTO_H
 
 void lpc32xx_uart_init(unsigned int uart_id);
+void lpc32xx_mac_init(void);
 
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index fb0cf8c..61197fb 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
 obj-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
 obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
 obj-$(CONFIG_LAN91C96) += lan91c96.o
+obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
 obj-$(CONFIG_MACB) += macb.o
 obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
 obj-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
diff --git a/drivers/net/lpc32xx_eth.c b/drivers/net/lpc32xx_eth.c
new file mode 100644
index 0000000..16c8ef0
--- /dev/null
+++ b/drivers/net/lpc32xx_eth.c
@@ -0,0 +1,636 @@
+/*
+ * LPC32xx Ethernet MAC interface driver
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/types.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/config.h>
+
+/*
+ * Notes:
+ *
+ * 1. Unless specified otherwise, all references to tables or paragraphs
+ *    are to UM10326, "LPC32x0 and LPC32x0/01 User manual".
+ *
+ * 2. Only bitfield masks/values which are actually used by the driver
+ *    are defined.
+ */
+
+/* a single RX descriptor. The controller has an array of these */
+struct lpc32xx_eth_rxdesc {
+	u32 packet;		/* Receive packet pointer */
+	u32 control;		/* Descriptor command status */
+};
+
+#define LPC32XX_ETH_RX_DESC_SIZE (sizeof(struct lpc32xx_eth_rxdesc))
+
+/* RX control bitfields/masks (see Table 330) */
+#define LPC32XX_ETH_RX_CTRL_SIZE_MASK 0x000007FF
+#define LPC32XX_ETH_RX_CTRL_UNUSED    0x7FFFF800
+#define LPC32XX_ETH_RX_CTRL_INTERRUPT 0x80000000
+
+/* a single RX status. The controller has an array of these */
+struct lpc32xx_eth_rxstat {
+	u32 statusinfo;		/* Transmit Descriptor status */
+	u32 statushashcrc;	/* Transmit Descriptor CRCs */
+};
+
+#define LPC32XX_ETH_RX_STAT_SIZE (sizeof(struct lpc32xx_eth_rxstat))
+
+/* RX statusinfo bitfields/masks (see Table 333) */
+#define RX_STAT_RXSIZE 0x000007FF
+/* Helper: OR of all errors except RANGE */
+#define RX_STAT_ERRORS 0x1B800000
+
+/* a single TX descriptor. The controller has an array of these */
+struct lpc32xx_eth_txdesc {
+	u32 packet;		/* Transmit packet pointer */
+	u32 control;		/* Descriptor control */
+};
+
+#define LPC32XX_ETH_TX_DESC_SIZE (sizeof(struct lpc32xx_eth_txdesc))
+
+/* TX control bitfields/masks (see Table 335) */
+#define TX_CTRL_TXSIZE    0x000007FF
+#define TX_CTRL_LAST      0x40000000
+
+/* a single TX status. The controller has an array of these */
+struct lpc32xx_eth_txstat {
+	u32 statusinfo;		/* Transmit Descriptor status */
+};
+
+#define LPC32XX_ETH_TX_STAT_SIZE (sizeof(struct lpc32xx_eth_txstat))
+
+/* Ethernet MAC interface registers (see Table 283) */
+struct lpc32xx_eth_registers {
+	/* MAC registers - 0x3106_0000 to 0x3106_01FC */
+	u32 mac1;		/* MAC configuration register 1 */
+	u32 mac2;		/* MAC configuration register 2 */
+	u32 ipgt;		/* Back-to-back Inter-Packet Gap reg. */
+	u32 ipgr;		/* Non-back-to-back IPG register */
+	u32 clrt;		/* Collision Window / Retry register */
+	u32 maxf;		/* Maximum Frame register */
+	u32 supp;		/* Phy Support register */
+	u32 test;
+	u32 mcfg;		/* MII management configuration reg. */
+	u32 mcmd;		/* MII management command register */
+	u32 madr;		/* MII management address register */
+	u32 mwtd;		/* MII management wite data register */
+	u32 mrdd;		/* MII management read data register */
+	u32 mind;		/* MII management indicators register */
+	u32 reserved1[2];
+	u32 sa0;		/* Station address register 0 */
+	u32 sa1;		/* Station address register 1 */
+	u32 sa2;		/* Station address register 2 */
+	u32 reserved2[45];
+	/* Control registers */
+	u32 command;
+	u32 status;
+	u32 rxdescriptor;
+	u32 rxstatus;
+	u32 rxdescriptornumber;	/* actually, number MINUS ONE */
+	u32 rxproduceindex;	/* head of rx desc fifo */
+	u32 rxconsumeindex;	/* tail of rx desc fifo */
+	u32 txdescriptor;
+	u32 txstatus;
+	u32 txdescriptornumber;	/* actually, number MINUS ONE */
+	u32 txproduceindex;	/* head of rx desc fifo */
+	u32 txconsumeindex;	/* tail of rx desc fifo */
+	u32 reserved3[10];
+	u32 tsv0;		/* Transmit status vector register 0 */
+	u32 tsv1;		/* Transmit status vector register 1 */
+	u32 rsv;		/* Receive status vector register */
+	u32 reserved4[3];
+	u32 flowcontrolcounter;
+	u32 flowcontrolstatus;
+	u32 reserved5[34];
+	/* RX filter registers - 0x3106_0200 to 0x3106_0FDC */
+	u32 rxfilterctrl;
+	u32 rxfilterwolstatus;
+	u32 rxfilterwolclear;
+	u32 reserved6;
+	u32 hashfilterl;
+	u32 hashfilterh;
+	u32 reserved7[882];
+	/* Module control registers - 0x3106_0FE0 to 0x3106_0FF8 */
+	u32 intstatus;		/* Interrupt status register */
+	u32 intenable;
+	u32 intclear;
+	u32 intset;
+	u32 reserved8;
+	u32 powerdown;
+	u32 reserved9;
+};
+
+/* MAC1 register bitfields/masks and offsets (see Table 283) */
+#define MAC1_RECV_ENABLE        0x00000001
+#define MAC1_PASS_ALL_RX_FRAMES 0x00000002
+#define MAC1_SOFT_RESET         0x00008000
+/* Helper: general reset */
+#define MAC1_RESETS             0x0000CF00
+
+/* MAC2 register bitfields/masks and offsets (see Table 284) */
+#define MAC2_FULL_DUPLEX    0x00000001
+#define MAC2_CRC_ENABLE     0x00000010
+#define MAC2_PAD_CRC_ENABLE 0x00000020
+
+/* SUPP register bitfields/masks and offsets (see Table 290) */
+#define SUPP_SPEED 0x00000100
+
+/* MCFG register bitfields/masks and offsets (see Table 292) */
+#define MCFG_CLOCK_SELECT_MASK  0x0000001C
+/* divide clock by 28 (see Table 293) */
+#define MCFG_CLOCK_SELECT_DIV28 0x0000001C
+
+/* MADR register bitfields/masks and offsets (see Table 295) */
+#define MADR_REG_MASK   0x0000001F
+#define MADR_PHY_MASK   0x00001F00
+#define MADR_REG_OFFSET 0
+#define MADR_PHY_OFFSET 8
+
+/* MIND register bitfields/masks (see Table 298) */
+#define MIND_BUSY      0x00000001
+
+/* COMMAND register bitfields/masks and offsets (see Table 283) */
+#define COMMAND_RXENABLE      0x00000001
+#define COMMAND_TXENABLE      0x00000002
+#define COMMAND_PASSRUNTFRAME 0x00000040
+#define COMMAND_FULL_DUPLEX   0x00000400
+/* Helper: general reset */
+#define COMMAND_RESETS        0x0000001C
+
+/* STATUS register bitfields/masks and offsets (see Table 283) */
+#define STATUS_RXSTATUS 0x00000001
+#define STATUS_TXSTATUS 0x00000002
+
+/* RXFILTERCTRL register bitfields/masks (see Table 319) */
+#define RXFILTERCTRL_ACCEPTBROADCAST 0x00000002
+#define RXFILTERCTRL_ACCEPTPERFECT   0x00000020
+
+/* port device data struct */
+struct lpc32xx_eth_device {
+	struct eth_device dev;
+	struct lpc32xx_eth_registers *regs;
+	struct lpc32xx_eth_txdesc *p_txdesc;
+	struct lpc32xx_eth_txstat *p_txstat;
+	struct lpc32xx_eth_rxdesc *p_rxdesc;
+	struct lpc32xx_eth_rxstat *p_rxstat;
+	u8 *p_rxbuf;
+	u8 *p_txbuf;
+};
+
+#define LPC32XX_ETH_DEVICE_SIZE (sizeof(struct lpc32xx_eth_device))
+
+/* generic macros */
+#define to_lpc32xx_eth(_d) container_of(_d, struct lpc32xx_eth_device, dev)
+
+/* timeout for MII polling */
+#define MII_TIMEOUT 10000000
+
+/* limits for PHY and register addresses */
+#define MII_MAX_REG (MADR_REG_MASK >> MADR_REG_OFFSET)
+
+#define MII_MAX_PHY (MADR_PHY_MASK >> MADR_PHY_OFFSET)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+/*
+ * mii_reg_read - miiphy_read callback function.
+ *
+ * Returns 16bit phy register value, or 0xffff on error
+ */
+static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
+	struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
+	u32 mind_reg;
+	u32 timeout;
+
+	/* check parameters */
+	if (phy_adr > MII_MAX_PHY) {
+		printf("%s:%u: Invalid PHY address %d\n",
+		       __func__, __LINE__, phy_adr);
+		return -EFAULT;
+	}
+	if (reg_ofs > MII_MAX_REG) {
+		printf("%s:%u: Invalid register offset %d\n",
+		       __func__, __LINE__, reg_ofs);
+		return -EFAULT;
+	}
+
+	/* write the phy and reg addressse into the MII address reg */
+	writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET),
+	       &regs->madr);
+
+	/* write 1 to the MII command register to cause a read */
+	writel(1, &regs->mcmd);
+
+	/* wait till the MII is not busy */
+	timeout = MII_TIMEOUT;
+	do {
+		/* read MII indicators register */
+		mind_reg = readl(&regs->mind);
+		if (--timeout == 0)
+			break;
+	} while (mind_reg & MIND_BUSY);
+
+	/* write 0 to the MII command register to finish the read */
+	writel(0, &regs->mcmd);
+
+	if (timeout == 0) {
+		printf("%s:%u: MII busy timeout\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	*data = (u16) readl(&regs->mrdd);
+
+	debug("%s:(adr %d, off %d) => %04x\n", __func__, phy_adr,
+	      reg_ofs, *data);
+
+	return 0;
+}
+
+/*
+ * mii_reg_write - imiiphy_write callback function.
+ *
+ * Returns 0 if write succeed, -EINVAL on bad parameters
+ * -ETIME on timeout
+ */
+static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
+	struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
+	u32 mind_reg;
+	u32 timeout;
+
+	/* check parameters */
+	if (phy_adr > MII_MAX_PHY) {
+		printf("%s:%u: Invalid PHY address %d\n",
+		       __func__, __LINE__, phy_adr);
+		return -EFAULT;
+	}
+	if (reg_ofs > MII_MAX_REG) {
+		printf("%s:%u: Invalid register offset %d\n",
+		       __func__, __LINE__, reg_ofs);
+		return -EFAULT;
+	}
+
+	/* wait till the MII is not busy */
+	timeout = MII_TIMEOUT;
+	do {
+		/* read MII indicators register */
+		mind_reg = readl(&regs->mind);
+		if (--timeout == 0)
+			break;
+	} while (mind_reg & MIND_BUSY);
+
+	if (timeout == 0) {
+		printf("%s:%u: MII busy timeout\n", __func__,
+		       __LINE__);
+		return -EFAULT;
+	}
+
+	/* write the phy and reg addressse into the MII address reg */
+	writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET),
+	       &regs->madr);
+
+	/* write data to the MII write register */
+	writel(data, &regs->mwtd);
+
+	/*debug("%s:(adr %d, off %d) <= %04x\n", __func__, phy_adr,
+		reg_ofs, data);*/
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_PHYLIB)
+int lpc32xx_eth_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+	int reg_addr)
+{
+	u16 data;
+	int ret;
+	ret = mii_reg_read(bus->name, phy_addr, reg_addr, &data);
+	if (ret)
+		return ret;
+	return data;
+}
+
+int lpc32xx_eth_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+	int reg_addr, u16 data)
+{
+	return mii_reg_write(bus->name, phy_addr, reg_addr, data);
+}
+#endif
+
+/* Use static aligned variables for the driver  */
+
+/* this driver needs at least 4  RX and 4 TX buffers */
+
+#define TX_BUF_COUNT 4
+static __aligned(4) struct lpc32xx_eth_txdesc tx_desc[TX_BUF_COUNT];
+static __aligned(4) struct lpc32xx_eth_txstat tx_stat[TX_BUF_COUNT];
+static __aligned(PKTALIGN) u8 tx_buf[TX_BUF_COUNT*PKTSIZE_ALIGN];
+
+#define RX_BUF_COUNT 4
+static __aligned(4) struct lpc32xx_eth_rxdesc rx_desc[RX_BUF_COUNT];
+static __aligned(8) struct lpc32xx_eth_rxstat rx_stat[RX_BUF_COUNT];
+static __aligned(PKTALIGN) u8 rx_buf[RX_BUF_COUNT*PKTSIZE_ALIGN];
+
+static struct lpc32xx_eth_device lpc32xx_eth = {
+	.regs = (void *)LPC32XX_ETH_BASE,
+	.p_txdesc = tx_desc,
+	.p_txstat = tx_stat,
+	.p_rxdesc = rx_desc,
+	.p_rxstat = rx_stat,
+	.p_txbuf = tx_buf,
+	.p_rxbuf = rx_buf,
+};
+
+#define TX_TIMEOUT 10000
+
+static int lpc32xx_eth_send(struct eth_device *dev, void *dataptr, int datasize)
+{
+	struct lpc32xx_eth_device *lpc32xx_eth_device =
+		container_of(dev, struct lpc32xx_eth_device, dev);
+	struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+	int timeout, tx_index;
+
+	/* time out if transmit descriptor array remains full too long */
+	timeout = TX_TIMEOUT;
+	while ((regs->status & STATUS_TXSTATUS) &&
+	       (regs->txconsumeindex == regs->txproduceindex)) {
+		if (timeout-- == 0) {
+			debug("%s:%u: time out\n", __func__,
+			      __LINE__);
+			return -1;
+		}
+	}
+
+	/* determine next transmit packet index to use */
+	tx_index = regs->txproduceindex;
+
+	/* set up transmit packet */
+	writel((u32)dataptr, &tx_desc[tx_index].packet);
+	writel(TX_CTRL_LAST | ((datasize - 1) & TX_CTRL_TXSIZE),
+	       &tx_desc[tx_index].control);
+	writel(0, &tx_stat[tx_index].statusinfo);
+
+	/* pass transmit packet to DMA engine */
+	tx_index = (tx_index + 1) % TX_BUF_COUNT;
+	writel(tx_index, &regs->txproduceindex);
+
+	/* transmission succeeded */
+	return 0;
+}
+
+#define RX_TIMEOUT 1000000
+
+static int lpc32xx_eth_recv(struct eth_device *dev)
+{
+	struct lpc32xx_eth_device *lpc32xx_eth_device =
+		container_of(dev, struct lpc32xx_eth_device, dev);
+	struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+	int timeout, rx_index;
+
+	/* time out if receive descriptor array remains empty too long */
+	timeout = RX_TIMEOUT;
+	while (regs->rxproduceindex == regs->rxconsumeindex) {
+		if (timeout-- == 0)
+			return -1;
+	}
+
+	/* determine next receive packet index to use */
+	rx_index = regs->rxconsumeindex;
+
+	/* if data was valid, pass it on */
+	if (!(rx_stat[rx_index].statusinfo & RX_STAT_ERRORS))
+		NetReceive(&(rx_buf[rx_index*PKTSIZE_ALIGN]),
+			   (rx_stat[rx_index].statusinfo & RX_STAT_RXSIZE)
+			   + 1);
+
+	/* pass receive slot back to DMA engine */
+	rx_index = (rx_index + 1) % RX_BUF_COUNT;
+	writel(rx_index, &regs->rxconsumeindex);
+
+	/* reception successful */
+	return 0;
+}
+
+static int lpc32xx_eth_write_hwaddr(struct eth_device *dev)
+{
+	struct lpc32xx_eth_device *lpc32xx_eth_device =
+		container_of(dev, struct lpc32xx_eth_device, dev);
+	struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+
+	/* Save station address */
+	writel((unsigned long) (dev->enetaddr[0] |
+		(dev->enetaddr[1] << 8)), &regs->sa2);
+	writel((unsigned long) (dev->enetaddr[2] |
+		(dev->enetaddr[3] << 8)), &regs->sa1);
+	writel((unsigned long) (dev->enetaddr[4] |
+		(dev->enetaddr[5] << 8)), &regs->sa0);
+
+	return 0;
+}
+
+static int lpc32xx_eth_init(struct eth_device *dev)
+{
+	struct lpc32xx_eth_device *lpc32xx_eth_device =
+		container_of(dev, struct lpc32xx_eth_device, dev);
+	struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+	int index;
+
+	/* Release SOFT reset to let MII talk to PHY */
+	clrbits_le32(&regs->mac1, MAC1_SOFT_RESET);
+
+	/* Configure Full/Half Duplex mode */
+	if (miiphy_duplex(dev->name, CONFIG_PHY_ADDR) == FULL) {
+		setbits_le32(&regs->mac2, MAC2_FULL_DUPLEX);
+		setbits_le32(&regs->command, COMMAND_FULL_DUPLEX);
+		writel(0x15, &regs->ipgt);
+	} else {
+		writel(0x12, &regs->ipgt);
+	}
+
+	/* Configure 100MBit/10MBit mode */
+	if (miiphy_speed(dev->name, CONFIG_PHY_ADDR) == _100BASET)
+		writel(SUPP_SPEED, &regs->supp);
+	else
+		writel(0, &regs->supp);
+
+	/* Initial MAC initialization */
+	writel(MAC1_PASS_ALL_RX_FRAMES, &regs->mac1);
+	writel(MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE, &regs->mac2);
+	writel(PKTSIZE_ALIGN, &regs->maxf);
+
+	/* Retries: 15 (0xF). Collision window: 57 (0x37). */
+	writel(0x370F, &regs->clrt);
+
+	/* Set IP gap pt 2 to default 0x12 but pt 1 to non-default 0 */
+	writel(0x0012, &regs->ipgr);
+
+	/* pass runt (smaller than 64 bytes) frames */
+	writel(COMMAND_PASSRUNTFRAME, &regs->command);
+
+	/* Save station address */
+	writel((unsigned long) (dev->enetaddr[0] |
+		(dev->enetaddr[1] << 8)), &regs->sa2);
+	writel((unsigned long) (dev->enetaddr[2] |
+		(dev->enetaddr[3] << 8)), &regs->sa1);
+	writel((unsigned long) (dev->enetaddr[4] |
+		(dev->enetaddr[5] << 8)), &regs->sa0);
+
+	/* set up transmit buffers */
+	for (index = 0; index < TX_BUF_COUNT; index++) {
+		tx_desc[index].control = 0;
+		tx_stat[index].statusinfo = 0;
+	}
+	writel((u32)tx_desc, (u32 *)&regs->txdescriptor);
+	writel((u32)tx_stat, &regs->txstatus);
+	writel(TX_BUF_COUNT-1, &regs->txdescriptornumber);
+
+	/* set up receive buffers */
+	for (index = 0; index < RX_BUF_COUNT; index++) {
+		rx_desc[index].packet = (u32) (rx_buf+index*PKTSIZE_ALIGN);
+		rx_desc[index].control = PKTSIZE_ALIGN - 1;
+		rx_stat[index].statusinfo = 0;
+		rx_stat[index].statushashcrc = 0;
+	}
+	writel((u32)rx_desc, &regs->rxdescriptor);
+	writel((u32)rx_stat, &regs->rxstatus);
+	writel(RX_BUF_COUNT-1, &regs->rxdescriptornumber);
+
+	/* Enable broadcast and matching address packets */
+	writel(RXFILTERCTRL_ACCEPTBROADCAST |
+		RXFILTERCTRL_ACCEPTPERFECT, &regs->rxfilterctrl);
+
+	/* Clear and disable interrupts */
+	writel(0xFFFF, &regs->intclear);
+	writel(0, &regs->intenable);
+
+	/* Enable receive and transmit mode of MAC ethernet core */
+	setbits_le32(&regs->command, COMMAND_RXENABLE | COMMAND_TXENABLE);
+	setbits_le32(&regs->mac1, MAC1_RECV_ENABLE);
+
+	/*
+	 * Perform a 'dummy' first send to work around Ethernet.1
+	 * erratum (see ES_LPC3250 rev. 9 dated 1 June 2011).
+	 * Use zeroed "index" variable as the dummy.
+	 */
+
+	index = 0;
+	lpc32xx_eth_send(dev, &index, 4);
+
+	return 0;
+}
+
+static int lpc32xx_eth_halt(struct eth_device *dev)
+{
+	struct lpc32xx_eth_device *lpc32xx_eth_device =
+		container_of(dev, struct lpc32xx_eth_device, dev);
+	struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
+
+	/* Reset all MAC logic */
+	writel(MAC1_RESETS, &regs->mac1);
+	writel(COMMAND_RESETS, &regs->command);
+	/* Let reset condition settle */
+	udelay(2000);
+
+	return 0;
+}
+
+#if defined(CONFIG_PHYLIB)
+int lpc32xx_eth_phylib_init(struct eth_device *dev, int phyid)
+{
+	struct mii_dev *bus;
+	struct phy_device *phydev;
+	int ret;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		printf("mdio_alloc failed\n");
+		return -ENOMEM;
+	}
+	bus->read = lpc32xx_eth_phy_read;
+	bus->write = lpc32xx_eth_phy_write;
+	sprintf(bus->name, dev->name);
+
+	ret = mdio_register(bus);
+	if (ret) {
+		printf("mdio_register failed\n");
+		free(bus);
+		return -ENOMEM;
+	}
+
+	phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_MII);
+	if (!phydev) {
+		printf("phy_connect failed\n");
+		return -ENODEV;
+	}
+
+	phy_config(phydev);
+	phy_startup(phydev);
+
+	return 0;
+}
+#endif
+
+int lpc32xx_eth_initialize(bd_t *bis)
+{
+	struct eth_device *dev = &lpc32xx_eth.dev;
+	struct lpc32xx_eth_registers *regs = lpc32xx_eth.regs;
+
+	/*
+	 * Set RMII management clock rate. With HCLK at 104 MHz and
+	 * a divider of 28, this will be 3.72 MHz.
+	 */
+
+	writel(MCFG_CLOCK_SELECT_DIV28, &regs->mcfg);
+
+	/* Reset all MAC logic */
+	writel(MAC1_RESETS, &regs->mac1);
+	writel(COMMAND_RESETS, &regs->command);
+
+	/* wait 10 ms for the whole I/F to reset */
+	udelay(10000);
+
+	/* must be less than sizeof(dev->name) */
+	strcpy(dev->name, "eth0");
+
+	dev->init = (void *)lpc32xx_eth_init;
+	dev->halt = (void *)lpc32xx_eth_halt;
+	dev->send = (void *)lpc32xx_eth_send;
+	dev->recv = (void *)lpc32xx_eth_recv;
+	dev->write_hwaddr = (void *)lpc32xx_eth_write_hwaddr;
+
+	/* Release SOFT reset to let MII talk to PHY */
+	clrbits_le32(&regs->mac1, MAC1_SOFT_RESET);
+
+	/* register driver before talking to phy */
+	eth_register(dev);
+
+#if defined(CONFIG_PHYLIB)
+	lpc32xx_eth_phylib_init(dev, 0);
+#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, mii_reg_read, mii_reg_write);
+#endif
+
+	return 0;
+}
diff --git a/include/netdev.h b/include/netdev.h
index 34651ab..9a4e3d8 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -58,6 +58,7 @@ void gt6426x_eth_initialize(bd_t *bis);
 int ks8695_eth_initialize(void);
 int ks8851_mll_initialize(u8 dev_num, int base_addr);
 int lan91c96_initialize(u8 dev_num, int base_addr);
+int lpc32xx_eth_initialize(bd_t *bis);
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int mcdmafec_initialize(bd_t *bis);
 int mcffec_initialize(bd_t *bis);
-- 
2.1.0

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

* [U-Boot] [PATCH v1 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-01-16  7:19 ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
@ 2015-01-16  7:19   ` Albert ARIBAUD
  2015-01-16  7:19     ` [U-Boot] [PATCH v1 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
  2015-01-16 16:46   ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Joe Hershberger
  1 sibling, 1 reply; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

The controller's Reed-Solomon ECC hardware is
used except of course for raw reads and writes.
It covers in- and out-of-band data together.

The SPL framework is supported.

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |   6 +
 arch/arm/include/asm/arch-lpc32xx/clk.h       |   4 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h |   1 +
 drivers/mtd/nand/Makefile                     |   1 +
 drivers/mtd/nand/lpc32xx_nand_mlc.c           | 589 ++++++++++++++++++++++++++
 5 files changed, 601 insertions(+)
 create mode 100644 drivers/mtd/nand/lpc32xx_nand_mlc.c

diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index 062db8d..be4c93d 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -44,3 +44,9 @@ void lpc32xx_mac_init(void)
 	writel(CLK_MAC_REG | CLK_MAC_SLAVE | CLK_MAC_MASTER
 		| CLK_MAC_MII, &clk->macclk_ctrl);
 }
+
+void lpc32xx_mlc_nand_init(void)
+{
+	/* Enable NAND interface */
+	writel(CLK_NAND_MLC | CLK_NAND_MLC_INT, &clk->flashclk_ctrl);
+}
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h
index 92f6c15..bc7d33d 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -147,6 +147,10 @@ struct clk_pm_regs {
 /* DMA Clock Control Register bits */
 #define CLK_DMA_ENABLE			(1 << 0)
 
+/* NAND Clock Control Register bits */
+#define CLK_NAND_MLC			(1 << 1)
+#define CLK_NAND_MLC_INT		(1 << 5)
+
 unsigned int get_sys_clk_rate(void);
 unsigned int get_hclk_pll_rate(void);
 unsigned int get_hclk_clk_div(void);
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index a6b8826..0c4e712 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -9,5 +9,6 @@
 
 void lpc32xx_uart_init(unsigned int uart_id);
 void lpc32xx_mac_init(void);
+void lpc32xx_mlc_nand_init(void);
 
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 1f02bfc..347ea62 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
 obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
+obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
 obj-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
 obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
 obj-$(CONFIG_NAND_MXC) += mxc_nand.o
diff --git a/drivers/mtd/nand/lpc32xx_nand_mlc.c b/drivers/mtd/nand/lpc32xx_nand_mlc.c
new file mode 100644
index 0000000..cb23972
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_nand_mlc.c
@@ -0,0 +1,589 @@
+/*
+ * LPC32xx MLC NAND flash controller driver
+ *
+ * (C) Copyright 2014 3ADEV <http://3adev.com>
+ * Written by Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * NOTE:
+ *
+ * The MLC NAND flash controller provides hardware Reed-Solomon ECC
+ * covering in- and out-of-band data together. Therefore, in- and out-
+ * of-band data must be written together in order to have a valid ECC.
+ *
+ * Consequently, pages with meaningful in-band data are written with
+ * blank (all-ones) out-of-band data and a valid ECC, and any later
+ * out-of-band data write will void the ECC.
+ *
+ * Therefore, code which reads such late-written out-of-band data
+ * should not rely on the ECC validity.
+ */
+
+#include <common.h>
+#include <nand.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/sys_proto.h>
+
+/*
+ * MLC NAND controller registers.
+ */
+struct lpc32xx_nand_mlc_registers {
+	u8 buff[32768]; /* controller's serial data buffer */
+	u8 data[32768]; /* NAND's raw data buffer */
+	u32 cmd;
+	u32 addr;
+	u32 ecc_enc_reg;
+	u32 ecc_dec_reg;
+	u32 ecc_auto_enc_reg;
+	u32 ecc_auto_dec_reg;
+	u32 rpr;
+	u32 wpr;
+	u32 rubp;
+	u32 robp;
+	u32 sw_wp_add_low;
+	u32 sw_wp_add_hig;
+	u32 icr;
+	u32 time_reg;
+	u32 irq_mr;
+	u32 irq_sr;
+	u32 lock_pr;
+	u32 isr;
+	u32 ceh;
+};
+
+/* LOCK_PR register defines */
+#define LOCK_PR_UNLOCK_KEY 0x0000A25E  /* Magic unlock value */
+
+/* ICR defines */
+#define ICR_LARGE_BLOCKS 0x00000004	/* configure for 2KB blocks */
+#define ICR_ADDR4        0x00000002	/* configure for 4-word addrs */
+
+/* CEH defines */
+#define CEH_NORMAL_CE  0x00000001	/* do not force CE ON */
+
+/* ISR register defines */
+#define ISR_NAND_READY        0x00000001
+#define ISR_CONTROLLER_READY  0x00000002
+#define ISR_ECC_READY         0x00000004
+#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1)
+#define ISR_DECODER_FAILURE   0x00000040
+#define ISR_DECODER_ERROR     0x00000008
+
+/*
+ * There is a single instance of the NAND MLC controller
+ */
+
+static struct lpc32xx_nand_mlc_registers *lpc32xx_nand_mlc_registers
+	= (struct lpc32xx_nand_mlc_registers *)MLC_NAND_BASE;
+
+#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o)
+
+/*
+ * Initialize the controller
+ */
+
+static void lpc32xx_nand_init(void)
+{
+	unsigned int clk;
+
+	/* Configure controller for no software write protection, x8 bus
+	   width, large block device, and 4 address words */
+
+	/* unlock controller registers with magic key */
+	writel(LOCK_PR_UNLOCK_KEY,
+	       &lpc32xx_nand_mlc_registers->lock_pr);
+
+	/* enable large blocks and large NANDs */
+	writel(ICR_LARGE_BLOCKS | ICR_ADDR4,
+	       &lpc32xx_nand_mlc_registers->icr);
+
+	/* Make sure MLC interrupts are disabled */
+	writel(0, &lpc32xx_nand_mlc_registers->irq_mr);
+
+	/* Normal chip enable operation */
+	writel(CEH_NORMAL_CE,
+	       &lpc32xx_nand_mlc_registers->ceh);
+
+	/* Setup NAND timing */
+	clk = get_hclk_clk_rate();
+
+	writel(
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA,    0x07, 16) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH,    0x0F, 12) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW,     0x0F, 8) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH,    0x0F, 4) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW,     0x0F, 0),
+		&lpc32xx_nand_mlc_registers->time_reg);
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+
+/**
+ * lpc32xx_cmd_ctrl - write command to either cmd or data register
+ */
+
+static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd);
+	else if (ctrl & NAND_ALE)
+		writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr);
+	else
+		return;
+}
+
+/**
+ * lpc32xx_read_byte - read a byte from the NAND
+ * @mtd:	MTD device structure
+ */
+
+static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
+{
+	return readb(&lpc32xx_nand_mlc_registers->data);
+}
+
+/**
+ * lpc32xx_dev_ready - test if NAND device (actually controller) is ready
+ * @mtd:	MTD device structure
+ * @mode:	mode to set the ECC HW to.
+ */
+
+static int lpc32xx_dev_ready(struct mtd_info *mtd)
+{
+	/* means *controller* ready for us */
+	int status = readl(&lpc32xx_nand_mlc_registers->isr);
+	return status & ISR_CONTROLLER_READY;
+}
+
+/**
+ * ECC layout -- this is needed whatever ECC mode we are using.
+ * In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes.
+ * To make U-Boot's life easier, we pack 'useable' OOB at the
+ * front and R/S ECC at the back.
+ */
+
+static struct nand_ecclayout lpc32xx_largepage_ecclayout = {
+	.eccbytes = 40,
+	.eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+		   34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+		   44, 45, 46, 47, 48, 48, 50, 51, 52, 53,
+		   54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+		   },
+	.oobfree = {
+		{
+			.offset = 0,
+			.length = 24
+		},
+	}
+};
+
+/**
+ * lpc32xx_read_page_hwecc - read in- and out-of-band data with ECC
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Use large block Auto Decode Read Mode(1) as described in User Manual
+ * section 8.6.2.1.
+ *
+ * The initial Read Mode and Read Start commands are sent by the caller.
+ *
+ * ECC will be false if out-of-band data has been updated since in-band
+ * data was initially written.
+ */
+
+static int lpc32xx_read_page_hwecc(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required,
+	int page)
+{
+	unsigned int i, status, err, max_bitflips = 0;
+	uint8_t *oob = chip->oob_poi;
+
+	/* go through all four small pages */
+	for (i = 0; i < 4; i++) {
+		/* start auto decode (reads 528 NAND bytes) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+		/* wait for controller to return to ready state */
+		do
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+		while (!(status & ISR_CONTROLLER_READY));
+		/* return -1 if hard error */
+		if (status & ISR_DECODER_FAILURE)
+			return -1;
+		/* keep count of maximum bitflips performed */
+		if (status & ISR_DECODER_ERROR) {
+			err = ISR_DECODER_ERRORS(status);
+			if (err > max_bitflips)
+				max_bitflips = err;
+		}
+		/* copy first 512 bytes into buffer */
+		memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512);
+		/* copy next 6 bytes at front of OOB buffer */
+		memcpy(oob+6*i, lpc32xx_nand_mlc_registers->buff, 6);
+		/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(oob+24+10*i, lpc32xx_nand_mlc_registers->buff, 10);
+	}
+	return max_bitflips;
+}
+
+/**
+ * lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Read NAND directly; can read pages with invalid ECC.
+ */
+
+static int lpc32xx_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required,
+	int page)
+{
+	unsigned int i, status;
+	uint8_t *oob = chip->oob_poi;
+
+	/* when we get here we've already had the Read Mode(1) */
+
+	/* go through all four small pages */
+	for (i = 0; i < 4; i++) {
+		/* wait for NAND to return to ready state */
+		do
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+		while (!(status & ISR_NAND_READY));
+		/* copy first 512 bytes into buffer */
+		memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512);
+		/* copy next 6 bytes at front of OOB buffer */
+		memcpy(oob+6*i, lpc32xx_nand_mlc_registers->data, 6);
+		/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(oob+24+10*i, lpc32xx_nand_mlc_registers->data, 10);
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_read_oob - read out-of-band data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ *
+ * Read out-of-band data. User Manual section 8.6.4 suggests using Read
+ * Mode(3) which the controller will turn into a Read Mode(1) internally
+ * but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0)
+ * directly.
+ *
+ * ECC covers in- and out-of-band data and was written when out-of-band
+ * data was blank. Therefore, if the out-of-band being read here is not
+ * blank, then the ECC will be false and the read will return bitflips,
+ * even in case of ECC failure where we will return 5 bitflips. The
+ * caller should be prepared to handle this.
+ */
+
+static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+	int page)
+{
+	unsigned int i, status, err, max_bitflips = 0;
+	uint8_t *oob = chip->oob_poi;
+
+	/* No command was sent before calling read_oob() so send one */
+
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+	/* go through all four small pages */
+	for (i = 0; i < 4; i++) {
+		/* start auto decode (reads 528 NAND bytes) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+		/* wait for controller to return to ready state */
+		do
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+		while (!(status & ISR_CONTROLLER_READY));
+		/* count 5 bitflips if error, will return -1 later */
+		if (status & ISR_DECODER_FAILURE)
+			max_bitflips = 5;
+		/* keep count of maximum bitflips performed */
+		if (status & ISR_DECODER_ERROR) {
+			err = ISR_DECODER_ERRORS(status);
+			if (err > max_bitflips)
+				max_bitflips = err;
+		}
+		/* set read pointer to OOB area */
+		writel(0, &lpc32xx_nand_mlc_registers->robp);
+		/* copy next 6 bytes at front of OOB buffer */
+		memcpy(oob+6*i, lpc32xx_nand_mlc_registers->buff, 6);
+		/* copy next 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(oob+24+10*i, lpc32xx_nand_mlc_registers->buff, 10);
+	}
+	return max_bitflips;
+}
+
+/**
+ * lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ *
+ * Use large block Auto Encode as per User Manual section 8.6.4.
+ *
+ * The initial Write Serial Input and final Auto Program commands are
+ * sent by the caller.
+ */
+
+static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	unsigned int i;
+	uint8_t *oob = chip->oob_poi;
+
+	/* when we get here we've already had the SEQIN */
+	for (i = 0; i < 4; i++) {
+		/* start encode (expects 518 writes to buff) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg);
+		/* copy first 512 bytes from buffer */
+		memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
+		/* copy next 6 bytes from OOB buffer -- excluding ECC */
+		memcpy(&lpc32xx_nand_mlc_registers->buff, oob+6*i, 6);
+		/* wait for ECC to return to ready state */
+		while (!(readl(&lpc32xx_nand_mlc_registers->isr)
+			 & ISR_ECC_READY))
+			;
+		/* Trigger auto encode (writes 528 bytes to NAND) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg);
+		/* wait for controller to return to ready state */
+		while (!(readl(&lpc32xx_nand_mlc_registers->isr)
+			& ISR_CONTROLLER_READY))
+			;
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Use large block write but without encode.
+ *
+ * The initial Write Serial Input and final Auto Program commands are
+ * sent by the caller.
+ *
+ * This function will write the full out-of-band data, including the
+ * ECC area. Therefore, it can write pages with valid *or* invalid ECC.
+ */
+
+static int lpc32xx_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	unsigned int i;
+	uint8_t *oob = chip->oob_poi;
+
+	/* when we get here we've already had the Read Mode(1) */
+	for (i = 0; i < 4; i++) {
+		/* copy first 512 bytes from buffer */
+		memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
+		/* copy next 6 bytes into OOB buffer -- excluding ECC */
+		memcpy(lpc32xx_nand_mlc_registers->buff, oob+6*i, 6);
+		/* copy next 10 bytes into OOB buffer -- that is 'ECC' */
+		memcpy(lpc32xx_nand_mlc_registers->buff, oob+24+10*i, 10);
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_write_oob - write out-of-band data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ *
+ * Since ECC covers in- and out-of-band data, writing out-of-band data
+ * with ECC will render the page ECC wrong -- or, if the page was blank,
+ * then it will produce a good ECC but a later in-band data write will
+ * render it wrong.
+ *
+ * Therefore, do not compute or write any ECC, and always return success.
+ *
+ * This implies that we do four writes, since non-ECC out-of-band data
+ * are not contiguous in a large page.
+ */
+
+static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+	int page)
+{
+	/* update oob on all 4 subpages in sequence */
+	unsigned int i;
+	uint8_t *oob = chip->oob_poi;
+
+	for (i = 0; i < 4; i++) {
+		/* start data input */
+		oob[6*i] = ((0xfe << i) & 0xff);
+		oob[6*i+5] = ((0x7f >> i) & 0xff);
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page);
+		/* copy 6 non-ECC out-of-band bytes directly into NAND */
+		memcpy(lpc32xx_nand_mlc_registers->data, oob+6*i, 6);
+		/* program page */
+		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+		/* wait for NAND to return to ready state */
+		while (!(readl(&lpc32xx_nand_mlc_registers->isr)
+			& ISR_NAND_READY))
+			;
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_waitfunc - wait until a command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for controller and FLASH to both be ready.
+ */
+
+static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	/* FIXME: put a time-out here */
+	int status;
+	/* wait until both controller and NAND are ready */
+	do {
+		status = readl(&lpc32xx_nand_mlc_registers->isr);
+	} while ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
+		 != (ISR_CONTROLLER_READY || ISR_NAND_READY));
+	/* write NAND status command */
+	writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd);
+	/* read back status and return it */
+	return readb(&lpc32xx_nand_mlc_registers->data);
+}
+
+/*
+ * Initialize the controller
+ */
+
+int board_nand_init(struct nand_chip *nand)
+{
+	/* Set all BOARDSPECIFIC (actually core-specific) fields  */
+
+	nand->IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff;
+	nand->IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff;
+	nand->cmd_ctrl = lpc32xx_cmd_ctrl;
+	/* do not set init_size: nand_base.c will read sizes from chip */
+	nand->dev_ready = lpc32xx_dev_ready;
+	/* do not set setup_read_retry: this is NAND-chip-specific */
+	/* do not set chip_delay: we have dev_ready defined. */
+	nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+	/* Set needed ECC fields */
+
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.layout = &lpc32xx_largepage_ecclayout;
+	nand->ecc.size = 512;
+	nand->ecc.bytes = 10;
+	nand->ecc.strength = 4;
+	nand->ecc.read_page = lpc32xx_read_page_hwecc;
+	nand->ecc.read_page_raw = lpc32xx_read_page_raw;
+	nand->ecc.write_page = lpc32xx_write_page_hwecc;
+	nand->ecc.write_page_raw = lpc32xx_write_page_raw;
+	nand->ecc.read_oob = lpc32xx_read_oob;
+	nand->ecc.write_oob = lpc32xx_write_oob;
+	nand->waitfunc = lpc32xx_waitfunc;
+
+	nand->read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */
+
+	/* BBT options: read from last two pages, don't write */
+	nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK
+		| NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE
+		| NAND_BBT_WRITE;
+
+	/* Initial NAND interface */
+	lpc32xx_nand_init();
+
+	return 0;
+}
+
+#else /* defined(CONFIG_SPL_BUILD) */
+
+void nand_init(void)
+{
+	/* enable NAND controller */
+	lpc32xx_mlc_nand_init();
+	/* initialize NAND controller */
+	lpc32xx_nand_init();
+}
+
+void nand_deselect(void)
+{
+	/* nothing to do, but SPL requires this function */
+}
+
+static int read_single_page(uint8_t *dest, int page)
+{
+	int status, i, err, max_bitflips = 0;
+
+	/* enter read mode */
+	writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd);
+	/* send column (lsb then MSB) and page (lsb to MSB) */
+	writel(0, &lpc32xx_nand_mlc_registers->addr);
+	writel(0, &lpc32xx_nand_mlc_registers->addr);
+	writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr);
+	writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr);
+	writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr);
+	/* start reading */
+	writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd);
+
+	/* large page auto decode read */
+	for (i = 0; i < 4; i++) {
+		/* start auto decode (reads 528 NAND bytes) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+		/* wait for controller to return to ready state */
+		do
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+		while (!(status & ISR_CONTROLLER_READY))
+			;
+		/* return -1 if hard error */
+		if (status & ISR_DECODER_FAILURE)
+			return -1;
+		/* keep count of maximum bitflips performed */
+		if (status & ISR_DECODER_ERROR) {
+			err = ISR_DECODER_ERRORS(status);
+			if (err > max_bitflips)
+				max_bitflips = err;
+		}
+		/* copy first 512 bytes into buffer */
+		memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512);
+	}
+	return max_bitflips;
+}
+
+#define LARGE_PAGE_SIZE 2048
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	unsigned int page = offs / LARGE_PAGE_SIZE;
+	unsigned int left = (size + LARGE_PAGE_SIZE - 1) / LARGE_PAGE_SIZE;
+
+	while (left) {
+		if (read_single_page(dst, page) >= 0) {
+			dst += LARGE_PAGE_SIZE;
+			page++;
+			left--;
+		}
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
-- 
2.1.0

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

* [U-Boot] [PATCH v1 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-01-16  7:19   ` [U-Boot] [PATCH v1 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
@ 2015-01-16  7:19     ` Albert ARIBAUD
  2015-01-16  7:19       ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Albert ARIBAUD
  0 siblings, 1 reply; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |  11 ++
 arch/arm/include/asm/arch-lpc32xx/clk.h       |   4 +
 arch/arm/include/asm/arch-lpc32xx/cpu.h       |   2 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h |   1 +
 drivers/i2c/Makefile                          |   1 +
 drivers/i2c/lpc32xx_i2c.c                     | 249 ++++++++++++++++++++++++++
 6 files changed, 268 insertions(+)
 create mode 100644 drivers/i2c/lpc32xx_i2c.c

diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index be4c93d..81b53ea 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -50,3 +50,14 @@ void lpc32xx_mlc_nand_init(void)
 	/* Enable NAND interface */
 	writel(CLK_NAND_MLC | CLK_NAND_MLC_INT, &clk->flashclk_ctrl);
 }
+
+void lpc32xx_i2c_init(unsigned int devnum)
+{
+	/* Enable I2C interface */
+	uint32_t ctrl = readl(&clk->i2cclk_ctrl);
+	if (devnum == 1)
+		ctrl |= CLK_I2C1_ENABLE;
+	if (devnum == 2)
+		ctrl |= CLK_I2C2_ENABLE;
+	writel(ctrl, &clk->i2cclk_ctrl);
+}
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h
index bc7d33d..781ac07 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -123,6 +123,10 @@ struct clk_pm_regs {
 #define CLK_MAC_SLAVE			(1 << 1)
 #define CLK_MAC_REG			(1 << 0)
 
+/* I2C Clock Control Register bits	*/
+#define CLK_I2C2_ENABLE			(1 << 1)
+#define CLK_I2C1_ENABLE			(1 << 0)
+
 /* Timer Clock Control1 Register bits */
 #define CLK_TIMCLK_MOTOR		(1 << 6)
 #define CLK_TIMCLK_TIMER3		(1 << 5)
diff --git a/arch/arm/include/asm/arch-lpc32xx/cpu.h b/arch/arm/include/asm/arch-lpc32xx/cpu.h
index 199b4a0..1067107 100644
--- a/arch/arm/include/asm/arch-lpc32xx/cpu.h
+++ b/arch/arm/include/asm/arch-lpc32xx/cpu.h
@@ -37,6 +37,8 @@
 #define UART4_BASE	0x40088000	/* UART 4 registers base            */
 #define UART5_BASE	0x40090000	/* UART 5 registers base            */
 #define UART6_BASE	0x40098000	/* UART 6 registers base            */
+#define I2C1_BASE	0x400A0000	/* I2C  1 registers base            */
+#define I2C2_BASE	0x400A8000	/* I2C  2 registers base            */
 
 /* External SDRAM Memory Bank base addresses */
 #define EMC_DYCS0_BASE	0x80000000	/* SDRAM DYCS0 base address         */
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index 0c4e712..a4a05d1 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -10,5 +10,6 @@
 void lpc32xx_uart_init(unsigned int uart_id);
 void lpc32xx_mac_init(void);
 void lpc32xx_mlc_nand_init(void);
+void lpc32xx_i2c_init(unsigned int devnum);
 
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 6f3c86c..b7b45b1 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
 obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
 obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
 obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
+obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
 obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
 obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
 obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o
diff --git a/drivers/i2c/lpc32xx_i2c.c b/drivers/i2c/lpc32xx_i2c.c
new file mode 100644
index 0000000..78d26e4
--- /dev/null
+++ b/drivers/i2c/lpc32xx_i2c.c
@@ -0,0 +1,249 @@
+/*
+ * LPC32xx I2C interface driver
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <asm/errno.h>
+#include <asm/arch/clk.h>
+
+/*
+ * Provide default speed and slave if target did not
+ */
+
+#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED)
+#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000
+#endif
+
+#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE)
+#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0
+#endif
+
+/* i2c register set */
+struct lpc32xx_i2c_registers {
+	union {
+		u32 rx;
+		u32 tx;
+	};
+	u32 stat;
+	u32 ctrl;
+	u32 clk_hi;
+	u32 clk_lo;
+	u32 adr;
+	u32 rxfl;
+	u32 txfl;
+	u32 rxb;
+	u32 txb;
+	u32 stx;
+	u32 stxfl;
+};
+
+/* TX register fields */
+#define LPC32XX_I2C_TX_START		0x00000100
+#define LPC32XX_I2C_TX_STOP		0x00000200
+
+/* Control register values */
+#define LPC32XX_I2C_SOFT_RESET		0x00000100
+
+/* Status register values */
+#define LPC32XX_I2C_STAT_TFF		0x00000400
+#define LPC32XX_I2C_STAT_RFE		0x00000200
+#define LPC32XX_I2C_STAT_DRMI		0x00000008
+#define LPC32XX_I2C_STAT_NAI		0x00000004
+#define LPC32XX_I2C_STAT_TDI		0x00000001
+
+static struct lpc32xx_i2c_registers *lpc32xx_i2c[] = {
+	(struct lpc32xx_i2c_registers *)I2C1_BASE,
+	(struct lpc32xx_i2c_registers *)I2C2_BASE
+};
+
+/* Set I2C bus speed */
+static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap,
+			unsigned int speed)
+{
+	int half_period;
+
+	if (speed == 0)
+		return -EINVAL;
+
+	half_period = (105000000 / speed) / 2;
+
+	if ((half_period > 255) || (half_period < 0))
+		return -EINVAL;
+
+	writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi);
+	writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo);
+	return 0;
+}
+
+/* I2C init called by cmd_i2c when doing 'i2c reset'. */
+static void _i2c_init(struct i2c_adapter *adap,
+	int requested_speed, int slaveadd)
+{
+	struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+
+	/* soft reset (auto-clears) */
+	writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+	/* set HI and LO periods for about 350 kHz */
+	lpc32xx_i2c_set_bus_speed(adap, requested_speed);
+}
+
+/* I2C probe called by cmd_i2c when doing 'i2c probe'. */
+static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev)
+{
+	struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+	int stat;
+
+	/* Soft-reset the controller */
+	writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+	while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
+		;
+	/* Addre slave for write with start before and stop after */
+	writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP,
+	       &i2c->tx);
+	/* wait for end of transation */
+	while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+		;
+	/* was there no acknowledge? */
+	return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0;
+}
+
+/*
+ * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
+ * Begin write, send address byte(s), begin read, receive data bytes, end.
+ */
+static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
+			 int alen, u8 *data, int length)
+{
+	struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+	int stat, wlen;
+
+	/* Soft-reset the controller */
+	writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+	while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
+		;
+	/* do we need to write an address at all? */
+	if (alen) {
+		/* Address slave in write mode */
+		writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
+		/* write address bytes */
+		while (alen--) {
+			/* compute address byte + stop for the last one */
+			int a = (addr >> (8 * alen)) & 0xff;
+			if (!alen)
+				a |= LPC32XX_I2C_TX_STOP;
+			/* Send address byte */
+			writel(a, &i2c->tx);
+		}
+		/* wait for end of transation */
+		while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+			;
+		/* clear end-of-transaction flag */
+		writel(1, &i2c->stat);
+	}
+	/* do we have to read data at all? */
+	if (length) {
+		/* Address slave in read mode */
+		writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
+		wlen = length;
+		/* get data */
+		while (length | wlen) {
+			/* read status for TFF and RFE */
+			stat = readl(&i2c->stat);
+			/* must we, can we write a trigger byte? */
+			if ((wlen > 0)
+			   & (!(stat & LPC32XX_I2C_STAT_TFF))) {
+				wlen--;
+				/* write trigger byte + stop if last */
+				writel(wlen ? 0 :
+				LPC32XX_I2C_TX_STOP, &i2c->tx);
+			}
+			/* must we, can we read a data byte? */
+			if ((length > 0)
+			   & (!(stat & LPC32XX_I2C_STAT_RFE))) {
+				length--;
+				/* read byte */
+				*(data++) = readl(&i2c->rx);
+			}
+		}
+	}
+	/* wait for end of transation */
+	while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+		;
+	/* clear end-of-transaction flag */
+	writel(1, &i2c->stat);
+	/* success */
+	return 0;
+}
+
+/*
+ * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
+ * Begin write, send address byte(s), send data bytes, end.
+ */
+static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
+			  int alen, u8 *data, int length)
+{
+	struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
+	int stat;
+
+	/* Soft-reset the controller */
+	writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
+	while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
+		;
+	/* do we need to write anything at all? */
+	if (alen | length)
+		/* Address slave in write mode */
+		writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
+	/* write address bytes */
+	while (alen) {
+		/* wait for transmit fifo not full */
+		stat = readl(&i2c->stat);
+		if (!(stat & LPC32XX_I2C_STAT_TFF)) {
+			alen--;
+			int a = (addr >> (8 * alen)) & 0xff;
+			if (!(alen | length))
+				a |= LPC32XX_I2C_TX_STOP;
+			/* Send address byte */
+			writel(a, &i2c->tx);
+		}
+	}
+	while (length) {
+		/* wait for transmit fifo not full */
+		stat = readl(&i2c->stat);
+		if (!(stat & LPC32XX_I2C_STAT_TFF)) {
+			/* compute data byte, add stop if length==0 */
+			length--;
+			int d = *(data++);
+			if (!length)
+				d |= LPC32XX_I2C_TX_STOP;
+			/* Send data byte */
+			writel(d, &i2c->tx);
+		}
+	}
+	/* wait for end of transation */
+	while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
+		;
+	/* clear end-of-transaction flag */
+	writel(1, &i2c->stat);
+	return 0;
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, _i2c_init, lpc32xx_i2c_probe,
+			 lpc32xx_i2c_read, lpc32xx_i2c_write,
+			 lpc32xx_i2c_set_bus_speed,
+			 CONFIG_SYS_I2C_LPC32XX_SPEED,
+			 CONFIG_SYS_I2C_LPC32XX_SLAVE,
+			 0)
+
+U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, _i2c_init, lpc32xx_i2c_probe,
+			 lpc32xx_i2c_read, lpc32xx_i2c_write,
+			 lpc32xx_i2c_set_bus_speed,
+			 CONFIG_SYS_I2C_LPC32XX_SPEED,
+			 CONFIG_SYS_I2C_LPC32XX_SLAVE,
+			 1)
-- 
2.1.0

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

* [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support
  2015-01-16  7:19     ` [U-Boot] [PATCH v1 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
@ 2015-01-16  7:19       ` Albert ARIBAUD
  2015-01-16  7:19         ` [U-Boot] [PATCH v1 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
  2015-01-16 17:17         ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Simon Glass
  0 siblings, 2 replies; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/include/asm/arch-lpc32xx/gpio.h |  43 ++++++
 drivers/gpio/Makefile                    |   1 +
 drivers/gpio/lpc32xx_gpio.c              | 223 +++++++++++++++++++++++++++++++
 3 files changed, 267 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-lpc32xx/gpio.h
 create mode 100644 drivers/gpio/lpc32xx_gpio.c

diff --git a/arch/arm/include/asm/arch-lpc32xx/gpio.h b/arch/arm/include/asm/arch-lpc32xx/gpio.h
new file mode 100644
index 0000000..3bd94e3
--- /dev/null
+++ b/arch/arm/include/asm/arch-lpc32xx/gpio.h
@@ -0,0 +1,43 @@
+/*
+ * LPC32xx GPIO interface
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/**
+ * GPIO Register map for LPC32xx
+ */
+
+struct gpio_regs {
+	u32 p3_inp_state;
+	u32 p3_outp_set;
+	u32 p3_outp_clr;
+	u32 p3_outp_state;
+	/* Watch out! the following are shared between p2 and p3 */
+	u32 p2_p3_dir_set;
+	u32 p2_p3_dir_clr;
+	u32 p2_p3_dir_state;
+	/* Now back to 'one register for one port' */
+	u32 p2_inp_state;
+	u32 p2_outp_set;
+	u32 p2_outp_clr;
+	u32 reserved1[6];
+	u32 p0_inp_state;
+	u32 p0_outp_set;
+	u32 p0_outp_clr;
+	u32 p0_outp_state;
+	u32 p0_dir_set;
+	u32 p0_dir_clr;
+	u32 p0_dir_state;
+	u32 reserved2;
+	u32 p1_inp_state;
+	u32 p1_outp_set;
+	u32 p1_outp_clr;
+	u32 p1_outp_state;
+	u32 p1_dir_set;
+	u32 p1_dir_clr;
+	u32 p1_dir_state;
+};
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index aa11f15..559894a 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -37,3 +37,4 @@ obj-$(CONFIG_ADI_GPIO2)	+= adi_gpio2.o
 obj-$(CONFIG_TCA642X)		+= tca642x.o
 oby-$(CONFIG_SX151X)		+= sx151x.o
 obj-$(CONFIG_SUNXI_GPIO)	+= sunxi_gpio.o
+obj-$(CONFIG_LPC32XX_GPIO)	+= lpc32xx_gpio.o
diff --git a/drivers/gpio/lpc32xx_gpio.c b/drivers/gpio/lpc32xx_gpio.c
new file mode 100644
index 0000000..0c08b00
--- /dev/null
+++ b/drivers/gpio/lpc32xx_gpio.c
@@ -0,0 +1,223 @@
+/*
+ * LPC32xxGPIO driver
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch-lpc32xx/cpu.h>
+#include <asm/arch-lpc32xx/gpio.h>
+
+/**
+ * LPC32xx GPIOs work in banks but are non-homogeneous:
+ * - each bank holds a different number of GPIOs
+ * - some GPIOs are input/ouput, some input only, some output only;
+ * - some GPIOs have different meanings as an input and as an output;
+ * - some GPIOs are controlled on a given port and bit index, but
+ *   read on another one.
+*
+ * In order to keep this code simple, GPIOS are considered here as
+ * homogeneous and linear, from 0 to 127.
+ *
+ *	** WARNING **
+ *
+ * Client code is responsible for properly using valid GPIO numbers,
+ * including cases where reading back a GPIO is done on a different
+ * register and bit than writing it.
+ */
+
+static struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE;
+
+/**
+ * We have 4 GPIO ports of 32 bits each
+ */
+
+#define MAX_GPIO 128
+
+#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3)
+#define GPIO_TO_RANK(gpio) (gpio % 32)
+#define GPIO_TO_MASK(gpio) (1 << (gpio % 32))
+
+/**
+ * GPIO requesting and freeing are not implemented
+ */
+
+int gpio_request(unsigned gpio, const char *label)
+{
+	debug("%s: GPIO %d requested as \"%s\"\n", __func__, gpio, label);
+	return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+	debug("%s: GPIO %d freed\n", __func__, gpio);
+	return 0;
+}
+
+/**
+ * Configure a GPIO as input
+ */
+
+int gpio_direction_input(unsigned gpio)
+{
+	int port, mask;
+
+	port = GPIO_TO_PORT(gpio);
+	mask = GPIO_TO_MASK(gpio);
+
+	switch (port) {
+	case 0:
+		writel(mask, &regs->p0_dir_clr);
+		break;
+	case 1:
+		writel(mask, &regs->p1_dir_clr);
+		break;
+	case 2:
+		/* ports 2 and 3 share a common direction */
+	case 3:
+		writel(mask, &regs->p2_p3_dir_clr);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Configure a GPIO as output
+ */
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+	int port, mask;
+
+	port = GPIO_TO_PORT(gpio);
+	mask = GPIO_TO_MASK(gpio);
+
+	switch (port) {
+	case 0:
+		writel(mask, &regs->p0_dir_set);
+		break;
+	case 1:
+		writel(mask, &regs->p1_dir_set);
+		break;
+	case 2:
+		/* ports 2 and 3 share a common direction */
+	case 3:
+		writel(mask, &regs->p2_p3_dir_set);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Get the value of a GPIO
+ */
+
+int gpio_get_value(unsigned gpio)
+{
+	int port, rank, mask, value;
+
+	port = GPIO_TO_PORT(gpio);
+
+	switch (port) {
+	case 0:
+		value = readl(&regs->p0_inp_state);
+		break;
+	case 1:
+		value = readl(&regs->p1_inp_state);
+		break;
+	case 2:
+		value = readl(&regs->p2_inp_state);
+		break;
+	case 3:
+		value = readl(&regs->p3_inp_state);
+		break;
+	default:
+		return -1;
+	}
+
+	rank = GPIO_TO_RANK(gpio);
+	mask = GPIO_TO_MASK(gpio);
+
+	return (value & mask) >> rank;
+}
+
+/**
+ * Set a GPIO
+ */
+
+static int gpio_set(unsigned gpio)
+{
+	int port, mask;
+
+	port = GPIO_TO_PORT(gpio);
+	mask = GPIO_TO_MASK(gpio);
+
+	switch (port) {
+	case 0:
+		writel(mask, &regs->p0_outp_set);
+		break;
+	case 1:
+		writel(mask, &regs->p1_outp_set);
+		break;
+	case 2:
+		writel(mask, &regs->p2_outp_set);
+		break;
+	case 3:
+		writel(mask, &regs->p3_outp_set);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Clear a GPIO
+ */
+
+static int gpio_clr(unsigned gpio)
+{
+	int port, mask;
+
+	port = GPIO_TO_PORT(gpio);
+	mask = GPIO_TO_MASK(gpio);
+
+	switch (port) {
+	case 0:
+		writel(mask, &regs->p0_outp_clr);
+		break;
+	case 1:
+		writel(mask, &regs->p1_outp_clr);
+		break;
+	case 2:
+		writel(mask, &regs->p2_outp_clr);
+		break;
+	case 3:
+		writel(mask, &regs->p3_outp_clr);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Set the value of a GPIO
+ */
+
+int gpio_set_value(unsigned gpio, int value)
+{
+	if (value)
+		return gpio_set(gpio);
+	else
+		return gpio_clr(gpio);
+}
-- 
2.1.0

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

* [U-Boot] [PATCH v1 5/8] lpc32xx: add LPC32xx SSP support (SPI mode)
  2015-01-16  7:19       ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Albert ARIBAUD
@ 2015-01-16  7:19         ` Albert ARIBAUD
  2015-01-16  7:19           ` [U-Boot] [PATCH v1 6/8] dtt: add ds620 support Albert ARIBAUD
  2015-01-16 17:17         ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Simon Glass
  1 sibling, 1 reply; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |   6 ++
 arch/arm/include/asm/arch-lpc32xx/clk.h       |   3 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h |   1 +
 drivers/spi/Makefile                          |   1 +
 drivers/spi/lpc32xx_ssp.c                     | 132 ++++++++++++++++++++++++++
 5 files changed, 143 insertions(+)
 create mode 100644 drivers/spi/lpc32xx_ssp.c

diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index 81b53ea..56ce9ab 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -61,3 +61,9 @@ void lpc32xx_i2c_init(unsigned int devnum)
 		ctrl |= CLK_I2C2_ENABLE;
 	writel(ctrl, &clk->i2cclk_ctrl);
 }
+
+void lpc32xx_ssp_init(void)
+{
+	/* Enable SSP0 interface */
+	writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl);
+}
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h
index 781ac07..2cb5703 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -155,6 +155,9 @@ struct clk_pm_regs {
 #define CLK_NAND_MLC			(1 << 1)
 #define CLK_NAND_MLC_INT		(1 << 5)
 
+/* SSP Clock Control Register bits */
+#define CLK_SSP0_ENABLE_CLOCK		(1 << 0)
+
 unsigned int get_sys_clk_rate(void);
 unsigned int get_hclk_pll_rate(void);
 unsigned int get_hclk_clk_div(void);
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index a4a05d1..86d5ee9 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -11,5 +11,6 @@ void lpc32xx_uart_init(unsigned int uart_id);
 void lpc32xx_mac_init(void);
 void lpc32xx_mlc_nand_init(void);
 void lpc32xx_i2c_init(unsigned int devnum);
+void lpc32xx_ssp_init(void);
 
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index edbd520..ce6f1cc 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
 obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 obj-$(CONFIG_ICH_SPI) +=  ich.o
 obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
+obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
 obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
 obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
 obj-$(CONFIG_MXC_SPI) += mxc_spi.o
diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c
new file mode 100644
index 0000000..40270df
--- /dev/null
+++ b/drivers/spi/lpc32xx_ssp.c
@@ -0,0 +1,132 @@
+/*
+ * LPC32xx SSP interface (SPI mode)
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/arch/clk.h>
+
+/* SSP chip registers */
+struct ssp_regs {
+	u32 cr0;
+	u32 cr1;
+	u32 data;
+	u32 sr;
+	u32 cpsr;
+	u32 imsc;
+	u32 ris;
+	u32 mis;
+	u32 icr;
+	u32 dmacr;
+};
+
+/* CR1 register defines  */
+#define SSP_CR1_SSP_ENABLE 0x0002
+
+/* SR register defines  */
+#define SSP_SR_TNF 0x0002
+/* SSP status RX FIFO not empty bit */
+#define SSP_SR_RNE 0x0004
+
+static struct ssp_regs *ssp0_regs = (struct ssp_regs *)SSP0_BASE;
+
+static struct spi_slave ssp0_slave = {
+	.bus = 0,
+	.cs = 0,
+	.op_mode_rx = 0,
+	.op_mode_tx = 0,
+	.wordlen = 8,
+	.max_write_size = 1, /* this is for SPI FLASHes -- don't care */
+	.memory_map = NULL, /* for SPI FLASHes too */
+	.option = 0,
+	.flags = 0
+};
+
+/* spi_init is called during boot when CONFIG_CMD_SPI is defined */
+void spi_init(void)
+{
+	/*
+	 *  nothing to do: clocking was enabled in lpc32xx_ssp_enable()
+	 * and configuration will be done in spi_setup_slave()
+	*/
+}
+
+/* the following is called in sequence by do_spi_xfer() */
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+	/* we only set up SSP0 for now, so ignore bus */
+
+	if (mode & SPI_3WIRE) {
+		error("3-wire mode not supported");
+		return NULL;
+	}
+
+	if (mode & SPI_SLAVE) {
+		error("slave mode not supported\n");
+		return NULL;
+	}
+
+	if (mode & SPI_PREAMBLE) {
+		error("preamble byte skipping not supported\n");
+		return NULL;
+	}
+
+	/*
+	 * 8 bit frame, SPI fmt, 500kbps -> clock divider is 26.
+	 * Set SCR to 0 and CPSDVSR to 26.
+	 */
+
+	writel(0x7, &ssp0_regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */
+	writel(26, &ssp0_regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */
+	writel(0, &ssp0_regs->imsc); /* do not raise any interrupts */
+	writel(0, &ssp0_regs->icr); /* clear any pending interrupt */
+	writel(0, &ssp0_regs->dmacr); /* do not do DMAs */
+	writel(SSP_CR1_SSP_ENABLE, &ssp0_regs->cr1); /* enable SSP0 */
+	return &ssp0_slave;
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	/* only one bus and slave so far, always available */
+	return 0;
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+	const void *dout, void *din, unsigned long flags)
+{
+	int bytelen = bitlen >> 3;
+	int idx_out = 0;
+	int idx_in = 0;
+	int start_time;
+
+	start_time = get_timer(0);
+	while ((idx_out < bytelen) || (idx_in < bytelen)) {
+		int status = readl(&ssp0_regs->sr);
+		if ((idx_out < bytelen) && (status & SSP_SR_TNF))
+			writel(((u8 *)dout)[idx_out++], &ssp0_regs->data);
+		if ((idx_in < bytelen) && (status & status & SSP_SR_RNE))
+			((u8 *)din)[idx_in++] = readl(&ssp0_regs->data);
+		if (get_timer(start_time) >= CONFIG_LPC32XX_SSP_TIMEOUT)
+			return -1;
+	}
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	/* do nothing */
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	/* do nothing */
+}
-- 
2.1.0

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

* [U-Boot] [PATCH v1 6/8] dtt: add ds620 support
  2015-01-16  7:19         ` [U-Boot] [PATCH v1 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
@ 2015-01-16  7:19           ` Albert ARIBAUD
  2015-01-16  7:19             ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
  0 siblings, 1 reply; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 drivers/hwmon/Makefile |  1 +
 drivers/hwmon/ds620.c  | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/dtt.h          | 15 ++++++------
 3 files changed, 73 insertions(+), 7 deletions(-)
 create mode 100644 drivers/hwmon/ds620.c

diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 25b8e8a..b4fb057 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DTT_ADT7460) += adt7460.o
 obj-$(CONFIG_DTT_DS1621) += ds1621.o
 obj-$(CONFIG_DTT_DS1722) += ds1722.o
 obj-$(CONFIG_DTT_DS1775) += ds1775.o
+obj-$(CONFIG_DTT_DS620) += ds620.o
 obj-$(CONFIG_DTT_LM63) += lm63.o
 obj-$(CONFIG_DTT_LM73) += lm73.o
 obj-$(CONFIG_DTT_LM75) += lm75.o
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
new file mode 100644
index 0000000..b9a60fc
--- /dev/null
+++ b/drivers/hwmon/ds620.c
@@ -0,0 +1,64 @@
+/*
+ * DS620 DTT support
+ * (C) Copyright 2014 3ADEV <http://www.3adev.com>
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Dallas Semiconductor's DS1621/1631 Digital Thermometer and Thermostat.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <dtt.h>
+
+/*
+ * Device code
+ */
+#define DTT_I2C_DEV_CODE	0x48
+#define DTT_START_CONVERT	0x51
+#define DTT_TEMP		0xAA
+#define DTT_CONFIG		0xAC
+
+/*
+ * Config register MSB bits
+ */
+#define DTT_CONFIG_1SHOT	0x01
+#define DTT_CONFIG_AUTOC	0x02
+#define DTT_CONFIG_R0		0x04 /* always 1 */
+#define DTT_CONFIG_R1		0x08 /* always 1 */
+#define DTT_CONFIG_TLF	0x10
+#define DTT_CONFIG_THF	0x20
+#define DTT_CONFIG_NVB	0x40
+#define DTT_CONFIG_DONE	0x80
+
+#define CHIP(sensor) (DTT_I2C_DEV_CODE + (sensor & 0x07))
+
+int dtt_init_one(int sensor)
+{
+	uint8_t config = DTT_CONFIG_1SHOT
+			| DTT_CONFIG_R0
+			| DTT_CONFIG_R1;
+	return i2c_write(CHIP(sensor), DTT_CONFIG, 1, &config, 1);
+}
+
+int dtt_get_temp(int sensor)
+{
+	uint8_t status;
+	uint8_t temp[2];
+
+	/* Start a conversion, may take up to 1 second. */
+	i2c_write(CHIP(sensor), DTT_START_CONVERT, 1, NULL, 0);
+	do {
+		if (i2c_read(CHIP(sensor), DTT_CONFIG, 1, &status, 1))
+			/* bail out if I2C error */
+			status |= DTT_CONFIG_DONE;
+	} while (!(status & DTT_CONFIG_DONE));
+	if (i2c_read(CHIP(sensor), DTT_TEMP, 1, temp, 2))
+		/* bail out if I2C error */
+		return -274; /* below absolute zero == error */
+
+	return ((int16_t)(temp[1] | (temp[0] << 8))) >> 7;
+}
diff --git a/include/dtt.h b/include/dtt.h
index 058bca4..173159d 100644
--- a/include/dtt.h
+++ b/include/dtt.h
@@ -12,13 +12,14 @@
 #define _DTT_H_
 
 #if defined(CONFIG_DTT_ADM1021)	|| \
-    defined(CONFIG_DTT_ADT7460)	|| \
-    defined(CONFIG_DTT_DS1621)	|| \
-    defined(CONFIG_DTT_DS1775)	|| \
-    defined(CONFIG_DTT_LM63)	|| \
-    defined(CONFIG_DTT_LM73)	|| \
-    defined(CONFIG_DTT_LM75)	|| \
-    defined(CONFIG_DTT_LM81)
+	defined(CONFIG_DTT_ADT7460)	|| \
+	defined(CONFIG_DTT_DS1621)	|| \
+	defined(CONFIG_DTT_DS1775)	|| \
+	defined(CONFIG_DTT_DS620)	|| \
+	defined(CONFIG_DTT_LM63)	|| \
+	defined(CONFIG_DTT_LM73)	|| \
+	defined(CONFIG_DTT_LM75)	|| \
+	defined(CONFIG_DTT_LM81)
 
 #define CONFIG_DTT				/* We have a DTT */
 
-- 
2.1.0

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

* [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target
  2015-01-16  7:19           ` [U-Boot] [PATCH v1 6/8] dtt: add ds620 support Albert ARIBAUD
@ 2015-01-16  7:19             ` Albert ARIBAUD
  2015-01-16  7:19               ` [U-Boot] [PATCH v1 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
  2015-01-16 13:08               ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Marek Vasut
  0 siblings, 2 replies; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 Makefile              |   3 +
 scripts/Makefile.spl  |  11 ++++
 tools/.gitignore      |   1 +
 tools/Makefile        |   2 +
 tools/mklpc32xxboot.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 186 insertions(+)
 create mode 100644 tools/mklpc32xxboot.c

diff --git a/Makefile b/Makefile
index 36a9a28..f5c9da5 100644
--- a/Makefile
+++ b/Makefile
@@ -1198,6 +1198,9 @@ spl/u-boot-spl: tools prepare
 spl/sunxi-spl.bin: spl/u-boot-spl
 	@:
 
+spl/lpc32xx-spl.bin: spl/u-boot-spl
+	@:
+
 tpl/u-boot-tpl.bin: tools prepare
 	$(Q)$(MAKE) obj=tpl -f $(srctree)/scripts/Makefile.spl all
 
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index ecf3037..4020383 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -158,6 +158,10 @@ ALL-y	+= $(obj)/sunxi-spl.bin
 endif
 endif
 
+ifdef CONFIG_LPC32XX_SPL
+ALL-y	+= $(obj)/lpc32xx-spl.bin
+endif
+
 ifeq ($(CONFIG_SYS_SOC),"at91")
 ALL-y	+= boot.bin
 endif
@@ -196,6 +200,13 @@ $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin
 	$(call if_changed,mksunxiboot)
 endif
 
+ifdef CONFIG_LPC32XX_SPL
+quiet_cmd_mklpc32xxboot = MKLPC32XX $@
+cmd_mklpc32xxboot = $(objtree)/tools/mklpc32xxboot $< $@
+$(obj)/lpc32xx-spl.bin: $(obj)/$(SPL_BIN).bin
+	$(call if_changed,mklpc32xxboot)
+endif
+
 quiet_cmd_u-boot-spl = LD      $@
       cmd_u-boot-spl = (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
 		       $(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \
diff --git a/tools/.gitignore b/tools/.gitignore
index 9bc9fec..79a5d75 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -11,6 +11,7 @@
 /mkenvimage
 /mkimage
 /mkexynosspl
+/mklpc32xxboot
 /mpc86x_clk
 /mxsboot
 /mksunxiboot
diff --git a/tools/Makefile b/tools/Makefile
index e549f8e..6fe21b0 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -135,6 +135,8 @@ HOSTCFLAGS_mxsboot.o := -pedantic
 
 hostprogs-$(CONFIG_SUNXI) += mksunxiboot
 
+hostprogs-$(CONFIG_LPC32XX_SPL) += mklpc32xxboot
+
 hostprogs-$(CONFIG_NETCONSOLE) += ncb
 hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1
 
diff --git a/tools/mklpc32xxboot.c b/tools/mklpc32xxboot.c
new file mode 100644
index 0000000..9f7d72e
--- /dev/null
+++ b/tools/mklpc32xxboot.c
@@ -0,0 +1,169 @@
+/*
+ * LPC32XX NAND boot image generator
+ *
+ * For details on NAND boot, see LPC32XX UM chapter 35 (boot process)
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*
+ * NAND page 0 boot header
+ */
+
+struct nand_page_0_boot_header {
+	uint32_t data[129];
+	uint32_t pad[383];
+};
+
+/*
+ * Default ICC (interface configuration data [sic]) if none specified
+ * in board config
+ */
+
+#ifndef LPC32XX_BOOT_ICR
+#define LPC32XX_BOOT_ICR 0x00000096
+#endif
+
+/*
+ * Default boot NAND page size if none specified in board config
+ */
+
+#ifndef LPC32XX_BOOT_NAND_PAGESIZE
+#define LPC32XX_BOOT_NAND_PAGESIZE 2048
+#endif
+
+/*
+ * Default boot NAND pages per sector if none specified in board config
+ */
+
+#ifndef LPC32XX_BOOT_NAND_PAGES_PER_SECTOR
+#define LPC32XX_BOOT_NAND_PAGES_PER_SECTOR 64
+#endif
+
+/*
+ * Maximum size for boot code is 56K unless defined in board config
+ */
+
+#ifndef LPC32XX_BOOT_CODESIZE
+#define LPC32XX_BOOT_CODESIZE (56*1024)
+#endif
+
+/* signature byte for a readable block */
+
+#define LPC32XX_BOOT_BLOCK_OK 0xaa
+
+/*
+ * Output boot data for both sectors 0 and 1
+ */
+
+int main(int argc, char *argv[])
+{
+	int fd_in, fd_out;
+	struct nand_page_0_boot_header header;
+	uint8_t page[LPC32XX_BOOT_NAND_PAGESIZE];
+	unsigned file_size_b;
+	unsigned file_size_p;
+	int sectors_left, pages_left, bytes_left, bytes_read;
+
+	if (argc < 2) {
+		printf("\tThis program takes an u-boot-spl.bin file "
+		       "as input and produces an LPC32XX boot image.\n"
+		       "\tUsage: %s input_file output_file\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	fd_in = open(argv[1], O_RDONLY);
+	if (fd_in < 0) {
+		perror(argv[1]);
+		return 1;
+	}
+
+	/* get input file size in bytes */
+	file_size_b = lseek(fd_in, 0, SEEK_END);
+
+	/* check maximum size */
+	if (file_size_b > LPC32XX_BOOT_CODESIZE) {
+		fprintf(stderr, "ERROR: File too large!\n");
+		return 2;
+	}
+
+	/* turn filesize from bytes to NAND pages, page 0 included */
+	file_size_p = ((file_size_b + (2 * LPC32XX_BOOT_NAND_PAGESIZE) - 1)
+		      / LPC32XX_BOOT_NAND_PAGESIZE);
+
+	/* fill header -- default byte value is 0x00, not 0xFF */
+	memset(&header, 0, sizeof(header));
+	header.data[0] = (header.data[2] = 0xff & LPC32XX_BOOT_ICR);
+	header.data[1] = (header.data[3] = 0xff & ~LPC32XX_BOOT_ICR);
+	header.data[4] = (header.data[6] = (header.data[8]
+		       = (header.data[10] = 0xff & file_size_p)));
+	header.data[5] = (header.data[7] = (header.data[9]
+		       = (header.data[11] = 0xff & ~file_size_p)));
+	header.data[12] = (header.data[128] = LPC32XX_BOOT_BLOCK_OK);
+
+	/* open the boot file for writing */
+	fd_out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	if (fd_out < 0) {
+		perror(argv[2]);
+		return 3;
+	}
+
+	/* write sectors 0 then 1 */
+	for (sectors_left = 2; sectors_left > 0; sectors_left--) {
+		/* write header */
+		if (write(fd_out, &header, sizeof(header)) != sizeof(header)) {
+			perror(argv[2]);
+			return 4;
+		}
+
+		/* write file, page-wise */
+		bytes_left = file_size_b;
+		lseek(fd_in, 0, SEEK_SET);
+		while (bytes_left) {
+			bytes_read = sizeof(page);
+			if (bytes_read > bytes_left)
+				bytes_read = bytes_left;
+			memset(page, 0xFF, sizeof(page));
+			if (read(fd_in, page, bytes_read) != bytes_read) {
+				perror(argv[1]);
+				return 5;
+			}
+			if (write(fd_out, page, sizeof(page))
+			    != sizeof(page)) {
+				perror(argv[2]);
+				return 6;
+			}
+			bytes_left -= bytes_read;
+		}
+
+		/* pad with blank pages */
+		memset(page, 0xFF, sizeof(page));
+		/* fill sector minus header and SPL */
+		pages_left = LPC32XX_BOOT_NAND_PAGES_PER_SECTOR
+			     - file_size_p - 1;
+		while (pages_left) {
+			if (write(fd_out, page, sizeof(page))
+			    != sizeof(page)) {
+				perror(argv[2]);
+				return 7;
+			}
+			pages_left--;
+		}
+	}
+
+	close(fd_in);
+	close(fd_out);
+
+	return 0;
+}
-- 
2.1.0

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

* [U-Boot] [PATCH v1 8/8] lpc32xx: add support for board work_92105
  2015-01-16  7:19             ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
@ 2015-01-16  7:19               ` Albert ARIBAUD
  2015-01-16 13:08               ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Marek Vasut
  1 sibling, 0 replies; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-16  7:19 UTC (permalink / raw)
  To: u-boot

Work_92105 from Work Microwave is an LPC3250-
based board with the following features:
- 64MB SDR DRAM
- 1 GB SLC NAND, managed through MLC controller.
- Ethernet
- Ethernet + PHY SMSC8710
- I2C:
  - EEPROM (24M01-compatible)
  - RTC (DS1374-compatible)
  - Temperature sensor (DS620)
  - DACs (2 x MAX518)
- SPI (through SSP interface)
  - Port expander MAX6957
- LCD display (HD44780-compatible), controlled
  through the port expander and DACs

This board has SPL support, and uses the LPC32XX boot
image format.

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/Kconfig                                   |   6 +
 arch/arm/cpu/arm926ejs/lpc32xx/Makefile            |   2 +
 arch/arm/cpu/arm926ejs/lpc32xx/clk.c               |  34 ++
 arch/arm/cpu/arm926ejs/lpc32xx/cpu.c               |   4 +
 arch/arm/cpu/arm926ejs/lpc32xx/dram.c              |  80 +++++
 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S     |  45 +++
 arch/arm/include/asm/arch-lpc32xx/clk.h            |   5 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h      |   4 +-
 board/work-microwave/work_92105/Kconfig            |  15 +
 board/work-microwave/work_92105/MAINTAINERS        |   6 +
 board/work-microwave/work_92105/Makefile           |   8 +
 board/work-microwave/work_92105/README             |  23 ++
 board/work-microwave/work_92105/work_92105.c       |  85 +++++
 .../work-microwave/work_92105/work_92105_display.c | 345 +++++++++++++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 configs/work_92105_defconfig                       |   3 +
 drivers/hwmon/ds620.c                              |   1 +
 include/configs/work_92105.h                       | 257 +++++++++++++++
 18 files changed, 936 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/dram.c
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
 create mode 100644 board/work-microwave/work_92105/Kconfig
 create mode 100644 board/work-microwave/work_92105/MAINTAINERS
 create mode 100644 board/work-microwave/work_92105/Makefile
 create mode 100644 board/work-microwave/work_92105/README
 create mode 100644 board/work-microwave/work_92105/work_92105.c
 create mode 100644 board/work-microwave/work_92105/work_92105_display.c
 create mode 100644 board/work-microwave/work_92105/work_92105_display.h
 create mode 100644 configs/work_92105_defconfig
 create mode 100644 include/configs/work_92105.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5eb1d03..0907136 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -238,6 +238,11 @@ config TARGET_DEVKIT3250
 	bool "Support devkit3250"
 	select CPU_ARM926EJS
 
+config TARGET_WORK_92105
+	bool "Support work_92105"
+	select CPU_ARM926EJS
+	select SUPPORT_SPL
+
 config TARGET_JADECPU
 	bool "Support jadecpu"
 	select CPU_ARM926EJS
@@ -981,6 +986,7 @@ source "board/udoo/Kconfig"
 source "board/vpac270/Kconfig"
 source "board/wandboard/Kconfig"
 source "board/woodburn/Kconfig"
+source "board/work-microwave/work_92105/Kconfig"
 source "board/xaeniax/Kconfig"
 source "board/zipitz2/Kconfig"
 
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
index 314f004..4837377 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
@@ -6,3 +6,5 @@
 #
 
 obj-y   = cpu.o clk.o devices.o timer.o
+
+obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
index b7a44d5..1ef8a36 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
@@ -98,6 +98,40 @@ unsigned int get_periph_clk_rate(void)
 	return get_hclk_pll_rate() / get_periph_clk_div();
 }
 
+unsigned int get_sdram_clk_rate(void)
+{
+	unsigned int src_clk;
+
+	if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
+		return get_sys_clk_rate();
+
+	src_clk = get_hclk_pll_rate();
+
+	if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) {
+		/* using DDR */
+		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) {
+		case CLK_HCLK_DDRAM_HALF:
+			return src_clk/2;
+		case CLK_HCLK_DDRAM_NOMINAL:
+			return src_clk;
+		default:
+			return 0;
+		}
+	} else {
+		/* using SDR */
+		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) {
+		case CLK_HCLK_ARM_PLL_DIV_4:
+			return src_clk/4;
+		case CLK_HCLK_ARM_PLL_DIV_2:
+			return src_clk/2;
+		case CLK_HCLK_ARM_PLL_DIV_1:
+			return src_clk;
+		default:
+			return 0;
+		}
+	}
+}
+
 int get_serial_clock(void)
 {
 	return get_periph_clk_rate();
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
index eec4d9e..f4d7f02 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
@@ -9,6 +9,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/arch/clk.h>
 #include <asm/arch/wdt.h>
+#include <asm/arch/sys_proto.h>
 #include <asm/io.h>
 
 static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
@@ -33,6 +34,9 @@ void reset_cpu(ulong addr)
 #if defined(CONFIG_ARCH_CPU_INIT)
 int arch_cpu_init(void)
 {
+#if defined(CONFIG_SPL_BUILD)
+	ddr_init();
+#endif
 	/*
 	 * It might be necessary to flush data cache, if U-boot is loaded
 	 * from kickstart bootloader, e.g. from S1L loader
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/dram.c b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
new file mode 100644
index 0000000..606f49d
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
@@ -0,0 +1,80 @@
+/*
+ * LPC32xx dram init
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * This is called by SPL to gain access to the SDR DRAM.
+ *
+ * This code runs from SRAM.
+ *
+ * Actual CONFIG_LPC32XX_SDRAM_* parameters must be provided
+ * by the board configuration file.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/wdt.h>
+#include <asm/arch/emc.h>
+#include <asm/io.h>
+
+static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
+static struct emc_regs *emc = (struct emc_regs *)EMC_BASE;
+
+#if defined(CONFIG_SPL_BUILD)
+
+void ddr_init(void)
+{
+	uint32_t ck;
+
+	/* Enable EMC interface and choose little endian mode */
+	emc->ctrl = 1;
+	emc->config = 0;
+	/* Select maximum EMC Dynamic Memory Refresh Time */
+	emc->refresh = 0x7FF;
+	/* Determine CLK */
+	ck = get_sdram_clk_rate();
+	/* Configure SDRAM */
+	clk->sdramclk_ctrl = (CONFIG_LPC32XX_SDRAM_COMMAND_DELAY << 14);
+	emc->config0 = CONFIG_LPC32XX_SDRAM_CONFIG0;
+	emc->rascas0 = CONFIG_LPC32XX_SDRAM_RASCAS0;
+	emc->read_config = CONFIG_LPC32XX_SDRAM_READ_CONFIG;
+	/* Set timings */
+	emc->t_rp = (ck / CONFIG_LPC32XX_SDRAM_T_RP) & 0x0000000F;
+	emc->t_ras = (ck / CONFIG_LPC32XX_SDRAM_T_RAS) & 0x0000000F;
+	emc->t_srex = (ck / CONFIG_LPC32XX_SDRAM_T_SREX) & 0x0000007F;
+	emc->t_wr = (ck / CONFIG_LPC32XX_SDRAM_T_WR) & 0x0000000F;
+	emc->t_rc = (ck / CONFIG_LPC32XX_SDRAM_T_RC) & 0x0000001F;
+	emc->t_rfc = (ck / CONFIG_LPC32XX_SDRAM_T_RFC) & 0x0000001F;
+	emc->t_xsr = (ck / CONFIG_LPC32XX_SDRAM_T_XSR) & 0x000000FF;
+	emc->t_rrd = CONFIG_LPC32XX_SDRAM_T_RRD;
+	emc->t_mrd = CONFIG_LPC32XX_SDRAM_T_MRD;
+	emc->t_cdlr = CONFIG_LPC32XX_SDRAM_T_CDLR;
+	/* Dynamic refresh */
+	emc->refresh = (((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF);
+	udelay(10);
+	/* Force all clocks, enable inverted ck, issue NOP command */
+	emc->control = 0x00000193;
+	udelay(100);
+	/* Keep all clocks enabled, issue a PRECHARGE ALL command */
+	emc->control = 0x00000113;
+	/* Fast dynamic refresh for at least a few SDRAM ck cycles */
+	emc->refresh = (((128) >> 4) & 0x7FF);
+	udelay(10);
+	/* set correct dynamic refresh timing */
+	emc->refresh = (((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF);
+	udelay(10);
+	/* set normal mode to CAS=3 */
+	emc->control = 0x00000093;
+	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_MODE);
+	/* set extended mode to all zeroes */
+	emc->control = 0x00000093;
+	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_EMODE);
+	/* stop forcing clocks, keep inverted clock, issue normal mode */
+	emc->control = 0x00000010;
+}
+#endif
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
new file mode 100644
index 0000000..4b8053e
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
@@ -0,0 +1,45 @@
+/*
+ * WORK Microwave work_92105 board low level init
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * Low level init is called from SPL to set up the clocks.
+ * On entry, the LPC3250 is in Direct Run mode with all clocks
+ * running at 13 MHz; on exit, ARM clock is 208 MHz, HCLK is
+ * 104 MHz and PCLK is 13 MHz.
+ *
+ * This code must run from SRAM so that the clock changes do
+ * not prevent it from executing.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+.globl lowlevel_init
+
+lowlevel_init:
+
+	/* Set ARM, HCLK, PCLK dividers for normal mode */
+	ldr	r0, =0x0000003D
+	ldr	r1, =0x40004040
+	str	r0, [r1]
+
+	/* Start HCLK PLL for 208 MHz */
+	ldr	r0, =0x0001401E
+	ldr	r1, =0x40004058
+	str	r0, [r1]
+
+	/* wait for HCLK PLL to lock */
+1:
+	ldr	r0, [r1]
+	ands	r0, r0, #1
+	beq	1b
+
+	/* switch to normal mode */
+	ldr	r1, =0x40004044
+	ldr	r0, [r1]
+	orr	r0, #0x00000004
+	str	r0, [r1]
+
+	/* Return to U-boot via saved link register */
+	mov	pc, lr
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h
index 2cb5703..9449869 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -71,6 +71,7 @@ struct clk_pm_regs {
 };
 
 /* HCLK Divider Control Register bits */
+#define CLK_HCLK_DDRAM_MASK		(0x3 << 7)
 #define CLK_HCLK_DDRAM_HALF		(0x2 << 7)
 #define CLK_HCLK_DDRAM_NOMINAL		(0x1 << 7)
 #define CLK_HCLK_DDRAM_STOPPED		(0x0 << 7)
@@ -158,11 +159,15 @@ struct clk_pm_regs {
 /* SSP Clock Control Register bits */
 #define CLK_SSP0_ENABLE_CLOCK		(1 << 0)
 
+/* SDRAMCLK register bits */
+#define CLK_SDRAM_DDR_SEL		(1 << 1)
+
 unsigned int get_sys_clk_rate(void);
 unsigned int get_hclk_pll_rate(void);
 unsigned int get_hclk_clk_div(void);
 unsigned int get_hclk_clk_rate(void);
 unsigned int get_periph_clk_div(void);
 unsigned int get_periph_clk_rate(void);
+unsigned int get_sdram_clk_rate(void);
 
 #endif /* _LPC32XX_CLK_H */
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index 86d5ee9..edcc4bc 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -12,5 +12,7 @@ void lpc32xx_mac_init(void);
 void lpc32xx_mlc_nand_init(void);
 void lpc32xx_i2c_init(unsigned int devnum);
 void lpc32xx_ssp_init(void);
-
+#if defined(CONFIG_SPL_BUILD)
+void ddr_init(void);
+#endif
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/board/work-microwave/work_92105/Kconfig b/board/work-microwave/work_92105/Kconfig
new file mode 100644
index 0000000..74f004f
--- /dev/null
+++ b/board/work-microwave/work_92105/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_WORK_92105
+
+config SYS_BOARD
+	default "work_92105"
+
+config SYS_VENDOR
+	default "work-microwave"
+
+config SYS_SOC
+	default "lpc32xx"
+
+config SYS_CONFIG_NAME
+	default "work_92105"
+
+endif
diff --git a/board/work-microwave/work_92105/MAINTAINERS b/board/work-microwave/work_92105/MAINTAINERS
new file mode 100644
index 0000000..29a92c5
--- /dev/null
+++ b/board/work-microwave/work_92105/MAINTAINERS
@@ -0,0 +1,6 @@
+WORK_92105 BOARD
+M:	Albert ARIBAUD <albert.aribaud@3adev.fr>
+S:	Maintained
+F:	board/work-microwave/work_92105/
+F:	include/configs/work_92105.h
+F:	configs/work_92105_defconfig
diff --git a/board/work-microwave/work_92105/Makefile b/board/work-microwave/work_92105/Makefile
new file mode 100644
index 0000000..853dea9
--- /dev/null
+++ b/board/work-microwave/work_92105/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2014  DENX Software Engineering GmbH
+# Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= work_92105.o work_92105_display.o
diff --git a/board/work-microwave/work_92105/README b/board/work-microwave/work_92105/README
new file mode 100644
index 0000000..091d731
--- /dev/null
+++ b/board/work-microwave/work_92105/README
@@ -0,0 +1,23 @@
+Work_92105 from Work Microwave is an LPC3250- based board with the
+following features:
+
+    - 64MB SDR DRAM
+    - 1 GB SLC NAND, managed through MLC controller.
+    - Ethernet
+    - Ethernet + PHY SMSC8710
+    - I2C:
+      - EEPROM (24M01-compatible)
+      - RTC (DS1374-compatible)
+      - Temperature sensor (DS620)
+      - DACs (2 x MAX518)
+    - SPI (through SSP interface)
+      - Port expander MAX6957
+    - LCD display (HD44780-compatible), controlled
+      through the port expander and DACs
+
+This board has SPL support, and uses the LPC32XX boot image format.
+Once the U-Boot target "work_92105" is built, the following two files
+can be flashed:
+
+	spl/lpc32xx-spl.bin at offset 0x0
+	u-boot.bin at offset 0x40000
diff --git a/board/work-microwave/work_92105/work_92105.c b/board/work-microwave/work_92105/work_92105.c
new file mode 100644
index 0000000..399a7cd
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105.c
@@ -0,0 +1,85 @@
+/*
+ * WORK Microwave work_92105 board support
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/emc.h>
+#include <asm/gpio.h>
+#include <spl.h>
+#include "work_92105_display.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_SPL_BUILD)
+
+void spl_board_init(void)
+{
+	/* initialize serial port for console */
+	lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART);
+	/* initialize console */
+	preloader_console_init();
+	/* init DDR and NAND to chainload U-Boot */
+	ddr_init();
+	lpc32xx_mlc_nand_init();
+}
+
+#else /* ! defined(CONFIG_SPL_BUILD) */
+
+int board_early_init_f(void)
+{
+	/* initialize serial port for console */
+	lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART);
+	/* enable I2C, SSP, MAC, NAND */
+	lpc32xx_i2c_init(1); /* only I2C1 has devices, I2C2 has none */
+	lpc32xx_ssp_init();
+	lpc32xx_mac_init();
+	lpc32xx_mlc_nand_init();
+	/* Display must wait until after relocation and devices init */
+	return 0;
+}
+
+#define GPO_19 115
+
+int board_early_init_r(void)
+{
+	/* Set NAND !WP to 1 through GPO_19 */
+	gpio_set_value(GPO_19, 1);
+
+	/* initialize display */
+	work_92105_display_init();
+
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
+
+int board_init(void)
+{
+	/* adress of boot parameters */
+	gd->bd->bi_boot_params  = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
+				    CONFIG_SYS_SDRAM_SIZE);
+
+	return 0;
+}
+
+#if defined(CONFIG_SPL_BUILD)
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_NAND;
+}
+#endif
diff --git a/board/work-microwave/work_92105/work_92105_display.c b/board/work-microwave/work_92105/work_92105_display.c
new file mode 100644
index 0000000..31d945e
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105_display.c
@@ -0,0 +1,345 @@
+/*
+ * work_92105 display support
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * The work_92105 display is a HD44780-compatible module
+ * controlled through a MAX6957AAX SPI port expander, two
+ * MAX518 I2C DACs and native LPC32xx GPO 15.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/emc.h>
+#include <asm/gpio.h>
+#include <spi.h>
+#include <i2c.h>
+#include <version.h>
+#include <vsprintf.h>
+
+/*
+ * GPO 15 in port 3 is gpio 3*32+15 = 111
+ */
+
+#define GPO_15 111
+
+/**
+ * MAX6957AAX registers that we will be using
+ */
+
+#define MAX6957_CONF		0x04
+
+#define MAX6957_CONF_08_11	0x0A
+#define MAX6957_CONF_12_15	0x0B
+#define MAX6957_CONF_16_19	0x0C
+
+/**
+ * Individual gpio ports (one per gpio) to HD44780
+ */
+
+#define MAX6957AAX_HD44780_RS	0x29
+#define MAX6957AAX_HD44780_R_W	0x2A
+#define MAX6957AAX_HD44780_EN	0x2B
+#define MAX6957AAX_HD44780_DATA	0x4C
+
+/**
+ * Display controller instructions
+ */
+
+/* Function set: eight bits, two lines, 8-dot font */
+#define HD44780_FUNCTION_SET		0x38
+
+/* Display ON / OFF: turn display on */
+#define HD44780_DISPLAY_ON_OFF_CONTROL	0x0C
+
+/* Entry mode: increment */
+#define HD44780_ENTRY_MODE_SET		0x06
+
+/* Clear */
+#define HD44780_CLEAR_DISPLAY		0x01
+
+/* Set DDRAM addr (to be ORed with exact address) */
+#define HD44780_SET_DDRAM_ADDR		0x80
+
+/* Set CGRAM addr (to be ORed with exact address) */
+#define HD44780_SET_CGRAM_ADDR		0x40
+
+/**
+ * Default value for contrats
+ */
+
+#define CONTRAST_DEFAULT  25
+
+/**
+ * Define slave as a module-wide local to save passing it around,
+ * plus we will need it after init for the "hd44780" command.
+ */
+
+static struct spi_slave *slave;
+
+/*
+ * Write a value into a MAX6957AAX register.
+ */
+
+static void max6957aax_write(uint8_t reg, uint8_t value)
+{
+	uint8_t dout[2];
+
+	dout[0] = reg;
+	dout[1] = value;
+	gpio_set_value(GPO_15, 0);
+	/* do SPI read/write (passing din==dout is OK) */
+	spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END);
+	gpio_set_value(GPO_15, 1);
+}
+
+/*
+ * Read a value from a MAX6957AAX register.
+ *
+ * According to the MAX6957AAX datasheet, we should release the chip
+ * select halfway through the read sequence, when the actual register
+ * value is read; but the WORK_92105 hardware prevents the MAX6957AAX
+ * SPI OUT from reaching the LPC32XX SIP MISO if chip is not selected.
+ * so let's release the CS an hold it again while reading the result.
+ */
+
+static uint8_t max6957aax_read(uint8_t reg)
+{
+	uint8_t dout[2], din[2];
+
+	/* send read command */
+	dout[0] = reg | 0x80; /* set bit 7 to indicate read */
+	dout[1] = 0;
+	gpio_set_value(GPO_15, 0);
+	/* do SPI read/write (passing din==dout is OK) */
+	spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END);
+	/* latch read command */
+	gpio_set_value(GPO_15, 1);
+	/* read register -- din = noop on xmit, din[1] = reg on recv */
+	din[0] = 0;
+	din[1] = 0;
+	gpio_set_value(GPO_15, 0);
+	/* do SPI read/write (passing din==dout is OK) */
+	spi_xfer(slave, 16, din, din, SPI_XFER_BEGIN | SPI_XFER_END);
+	/* end of read. */
+	gpio_set_value(GPO_15, 1);
+	return din[1];
+}
+
+static void hd44780_instruction(unsigned long instruction)
+{
+	max6957aax_write(MAX6957AAX_HD44780_RS, 0);
+	max6957aax_write(MAX6957AAX_HD44780_R_W, 0);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 1);
+	max6957aax_write(MAX6957AAX_HD44780_DATA, instruction);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+	/* HD44780 takes 37 us for most instructions, 1520 for clear */
+	if (instruction == HD44780_CLEAR_DISPLAY)
+		udelay(2000);
+	else
+		udelay(100);
+}
+
+static void hd44780_write_char(char c)
+{
+	max6957aax_write(MAX6957AAX_HD44780_RS, 1);
+	max6957aax_write(MAX6957AAX_HD44780_R_W, 0);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 1);
+	max6957aax_write(MAX6957AAX_HD44780_DATA, c);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+	/* HD44780 takes 37 us to write to DDRAM or CGRAM */
+	udelay(100);
+}
+
+static void hd44780_write_str(char *s)
+{
+	max6957aax_write(MAX6957AAX_HD44780_RS, 1);
+	max6957aax_write(MAX6957AAX_HD44780_R_W, 0);
+	while (*s) {
+		max6957aax_write(MAX6957AAX_HD44780_EN, 1);
+		max6957aax_write(MAX6957AAX_HD44780_DATA, *s);
+		max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+		s++;
+		/* HD44780 takes 37 us to write to DDRAM or CGRAM */
+		udelay(100);
+	}
+}
+
+/*
+ * Existing user code might expect these custom characters to be
+ * recognized and displayed on the LCD
+ */
+
+static u8 char_gen_chars[] = {
+	/* #8, empty rectangle */
+	0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F,
+	/* #9, filled right arrow */
+	0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
+	/* #10, filled left arrow */
+	0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00,
+	/* #11, up and down arrow */
+	0x04, 0x0E, 0x1F, 0x00, 0x00, 0x1F, 0x0E, 0x04,
+	/* #12, plus/minus */
+	0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F, 0x00,
+	/* #13, fat exclamation mark */
+	0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00,
+	/* #14, empty square */
+	0x00, 0x1F, 0x11, 0x11, 0x11, 0x1F, 0x00, 0x00,
+	/* #15, struck out square */
+	0x00, 0x1F, 0x19, 0x15, 0x13, 0x1F, 0x00, 0x00,
+};
+
+static void hd44780_init_char_gen(void)
+{
+	int i;
+
+	hd44780_instruction(HD44780_SET_CGRAM_ADDR);
+
+	for (i = 0; i < sizeof(char_gen_chars); i++)
+		hd44780_write_char(char_gen_chars[i]);
+
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR);
+}
+
+void work_92105_display_init(void)
+{
+	int claim_err;
+	char *display_contrast_str;
+	uint8_t display_contrast = CONTRAST_DEFAULT;
+	uint8_t enable_backlight = 0x96;
+
+	slave = spi_setup_slave(0, 0, 500000, 0);
+
+	if (!slave) {
+		printf("Failed to set up SPI slave\n");
+		return;
+	}
+
+	claim_err = spi_claim_bus(slave);
+
+	if (claim_err)
+		debug("Failed to claim SPI bus: %d\n", claim_err);
+
+	/* enable backlight */
+	i2c_write(0x2c, 0x01, 1, &enable_backlight, 1);
+
+	/* set display contrast */
+	display_contrast_str = getenv("fwopt_dispcontrast");
+	if (display_contrast_str)
+		display_contrast = simple_strtoul(display_contrast_str,
+			NULL, 10);
+	i2c_write(0x2c, 0x00, 1, &display_contrast, 1);
+
+	/* enable MAX6957 portexpander */
+	max6957aax_write(MAX6957_CONF, 0x01);
+	/* configure pin 8 as input, pins 9..19 as outputs */
+	max6957aax_write(MAX6957_CONF_08_11, 0x56);
+	max6957aax_write(MAX6957_CONF_12_15, 0x55);
+	max6957aax_write(MAX6957_CONF_16_19, 0x55);
+
+	/* initialize HD44780 */
+	max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+	hd44780_instruction(HD44780_FUNCTION_SET);
+	hd44780_instruction(HD44780_DISPLAY_ON_OFF_CONTROL);
+	hd44780_instruction(HD44780_ENTRY_MODE_SET);
+
+	/* write custom character glyphs */
+	hd44780_init_char_gen();
+
+	/* Show U-Boot version, date and time as a sign-of-life */
+	hd44780_instruction(HD44780_CLEAR_DISPLAY);
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR | 0);
+	hd44780_write_str(U_BOOT_VERSION);
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64);
+	hd44780_write_str(U_BOOT_DATE);
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64 | 20);
+	hd44780_write_str(U_BOOT_TIME);
+}
+
+#ifdef CONFIG_CMD_MAX6957
+
+static int do_max6957aax(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	int reg, val;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+	switch (argv[1][0]) {
+	case 'r':
+	case 'R':
+		reg = simple_strtoul(argv[2], NULL, 0);
+		val = max6957aax_read(reg);
+		printf("MAX6957 reg 0x%02x read 0x%02x\n", reg, val);
+		return 0;
+	default:
+		reg = simple_strtoul(argv[1], NULL, 0);
+		val = simple_strtoul(argv[2], NULL, 0);
+		max6957aax_write(reg, val);
+		printf("MAX6957 reg 0x%02x wrote 0x%02x\n", reg, val);
+		return 0;
+	}
+	return 1;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char max6957aax_help_text[] =
+	"max6957aax - write or read display register:\n"
+		"\tmax6957aax R|r reg - read display register;\n"
+		"\tmax6957aax reg val - write display register.";
+#endif
+
+U_BOOT_CMD(
+	max6957aax, 6, 1, do_max6957aax,
+	"SPI MAX6957 display write/read",
+	max6957aax_help_text
+);
+#endif /* CONFIG_CMD_MAX6957 */
+
+#ifdef CONFIG_CMD_HD44760
+
+/*
+ * We need the HUSH parser because we need string arguments, and
+ * only HUSH can understand them.
+ */
+
+#if !defined(CONFIG_SYS_HUSH_PARSER)
+#error CONFIG_CMD_HD44760 requires CONFIG_SYS_HUSH_PARSER
+#endif
+
+static int do_hd44780(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	char *cmd;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	cmd = argv[1];
+
+	if (strcasecmp(cmd, "cmd") == 0)
+		hd44780_instruction(simple_strtol(argv[2], NULL, 0));
+	else if (strcasecmp(cmd, "data") == 0)
+		hd44780_write_char(simple_strtol(argv[2], NULL, 0));
+	else if (strcasecmp(cmd, "str") == 0)
+		hd44780_write_str(argv[2]);
+	return 0;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char hd44780_help_text[] =
+	"hd44780 - control LCD driver:\n"
+		"\thd44780 cmd <val> - send command <val> to driver;\n"
+		"\thd44780 data <val> - send data <val> to driver;\n"
+		"\thd44780 str \"<text>\" - send \"<text>\" to driver.";
+#endif
+
+U_BOOT_CMD(
+	hd44780, 6, 1, do_hd44780,
+	"HD44780 LCD driver control",
+	hd44780_help_text
+);
+#endif /* CONFIG_CMD_HD44780 */
diff --git a/board/work-microwave/work_92105/work_92105_display.h b/board/work-microwave/work_92105/work_92105_display.h
new file mode 100644
index 0000000..dd6e768
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105_display.h
@@ -0,0 +1,14 @@
+/*
+ * work_92105 display support interface
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * The work_92105 display is a HD44780-compatible module
+ * controlled through a MAX6957AAX SPI port expander, two
+ * MAX518 I2C DACs and native LPC32xx GPO 15.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+void work_92105_display_init(void);
diff --git a/configs/work_92105_defconfig b/configs/work_92105_defconfig
new file mode 100644
index 0000000..b982c10
--- /dev/null
+++ b/configs/work_92105_defconfig
@@ -0,0 +1,3 @@
+CONFIG_SPL=y
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_WORK_92105=y
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index b9a60fc..1ecc3da 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -1,5 +1,6 @@
 /*
  * DS620 DTT support
+ *
  * (C) Copyright 2014 3ADEV <http://www.3adev.com>
  * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
  *
diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h
new file mode 100644
index 0000000..b1badbe
--- /dev/null
+++ b/include/configs/work_92105.h
@@ -0,0 +1,257 @@
+/*
+ * WORK Microwave work_92105 board configuration file
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_WORK_92105_H__
+#define __CONFIG_WORK_92105_H__
+
+/* SoC and board defines */
+#include <linux/sizes.h>
+#include <asm/arch/cpu.h>
+
+/*
+ * Define work_92105 machine type by hand -- done only for compatibility
+ * with original board code
+ */
+#define MACH_TYPE_WORK_92105		736
+#define CONFIG_MACH_TYPE		MACH_TYPE_WORK_92105
+
+#define CONFIG_SYS_ICACHE_OFF
+#define CONFIG_SYS_DCACHE_OFF
+#if !defined(CONFIG_SPL_BUILD)
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#endif
+#define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_BOARD_EARLY_INIT_R
+
+/* generate LPC32XX-specific SPL image */
+#define CONFIG_LPC32XX_SPL
+
+/*
+ * Memory configurations
+ */
+#define CONFIG_NR_DRAM_BANKS		1
+#define CONFIG_SYS_MALLOC_LEN		SZ_1M
+#define CONFIG_SYS_SDRAM_BASE		EMC_DYCS0_BASE
+#define CONFIG_SYS_SDRAM_SIZE		SZ_64M
+#define CONFIG_SYS_TEXT_BASE		0x80100000
+#define CONFIG_SYS_MEMTEST_START	(CONFIG_SYS_SDRAM_BASE + SZ_32K)
+#define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_TEXT_BASE - SZ_1M)
+
+#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_32K)
+
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_4K \
+					 - GENERATED_GBL_DATA_SIZE)
+
+/*
+ * Serial Driver
+ */
+#define CONFIG_SYS_LPC32XX_UART		5   /* UART5 - NS16550 */
+#define CONFIG_BAUDRATE			115200
+
+/*
+ * Ethernet Driver
+ */
+
+#define CONFIG_PHY_SMSC
+#define CONFIG_LPC32XX_ETH
+#define CONFIG_PHYLIB
+#define CONFIG_PHY_ADDR 0
+#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+/* FIXME: remove "Waiting for PHY auto negotiation to complete..." message */
+
+/*
+ * I2C driver
+ */
+
+#define CONFIG_SYS_I2C_LPC32XX
+#define CONFIG_SYS_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SPEED 350000
+
+/*
+ * I2C EEPROM
+ */
+
+#define CONFIG_CMD_EEPROM
+#define CONFIG_SYS_I2C_EEPROM_ADDR 0x56
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
+
+/*
+ * I2C RTC
+ */
+
+#define CONFIG_CMD_DATE
+#define CONFIG_RTC_DS1374
+
+/*
+ * I2C Temperature Sensor (DTT)
+ */
+
+#define CONFIG_CMD_DTT
+#define CONFIG_DTT_SENSORS { 0, 1 }
+#define CONFIG_DTT_DS620
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_SYS_CBSIZE		1024
+#define CONFIG_SYS_PBSIZE		\
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS		16
+#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_HUSH_PARSER
+
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_VERSION_VARIABLE
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DOS_PARTITION
+
+/*
+ * No NOR
+ */
+
+#define CONFIG_SYS_NO_FLASH
+
+/*
+ * NAND chip timings for FIXME: which one?
+ */
+
+#define CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY  333333333
+#define CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY   10000000
+#define CONFIG_LPC32XX_NAND_MLC_NAND_TA      18181818
+#define CONFIG_LPC32XX_NAND_MLC_RD_HIGH      31250000
+#define CONFIG_LPC32XX_NAND_MLC_RD_LOW       45454545
+#define CONFIG_LPC32XX_NAND_MLC_WR_HIGH      40000000
+#define CONFIG_LPC32XX_NAND_MLC_WR_LOW       83333333
+
+/*
+ * NAND
+ */
+
+/* driver configuration */
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE MLC_NAND_BASE
+#define CONFIG_NAND_LPC32XX_MLC
+
+#define CONFIG_CMD_NAND
+
+/*
+ * GPIO
+ */
+
+#define CONFIG_CMD_GPIO
+#define CONFIG_LPC32XX_GPIO
+
+/*
+ * SSP/SPI/DISPLAY
+ */
+
+#define CONFIG_CMD_SPI
+#define CONFIG_LPC32XX_SSP
+#define CONFIG_LPC32XX_SSP_TIMEOUT 100000
+#define CONFIG_CMD_MAX6957
+#define CONFIG_CMD_HD44760
+/*
+ * Environment
+ */
+
+#define CONFIG_ENV_IS_IN_NAND		1
+#define CONFIG_ENV_SIZE			0x00020000
+#define CONFIG_ENV_OFFSET		0x00100000
+#define CONFIG_ENV_OFFSET_REDUND	0x00120000
+#define CONFIG_ENV_ADDR			0x80000100
+/* provide default ethernet address */
+#define CONFIG_ETHADDR			00:12:B4:00:AF:FE
+#define	CONFIG_OVERWRITE_ETHADDR_ONCE
+
+/*
+ * U-Boot Commands
+ */
+#include <config_cmd_default.h>
+
+/*
+ * Boot Linux
+ */
+#define CONFIG_CMDLINE_TAG
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
+
+#define CONFIG_ZERO_BOOTDELAY_CHECK
+#define CONFIG_BOOTDELAY		3
+
+#define CONFIG_BOOTFILE			"uImage"
+#define CONFIG_BOOTARGS			"console=ttyS2,115200n8"
+#define CONFIG_LOADADDR			0x80008000
+
+/*
+ * DRAM timings for MT48H16M16LFBF-8 (x2 chips -> 64MB)
+ */
+
+/* delay commands by 7*0.25 = 1.75 ns */
+#define CONFIG_LPC32XX_SDRAM_COMMAND_DELAY  7
+/* 256Mb (16Mx16), 4banks, row len 13, column len 9, LP SDR */
+#define CONFIG_LPC32XX_SDRAM_CONFIG0 0x00005682
+/* CAS latency 6 * 0.5 = 3 clk, RAS latency = 2 clk */
+#define CONFIG_LPC32XX_SDRAM_RASCAS0 0x00000302
+/* capture on HCLK pos edge, apply command delay */
+#define CONFIG_LPC32XX_SDRAM_READ_CONFIG 0x00000011
+/* Timings */
+#define CONFIG_LPC32XX_SDRAM_T_RP   52631578 /* 19 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RAS  20833333 /* 48 ns */
+#define CONFIG_LPC32XX_SDRAM_T_SREX 12500000 /* 80 ns */
+#define CONFIG_LPC32XX_SDRAM_T_WR   66666666 /* 15 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RC   13888888 /* 72 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RFC  10256410 /* 97.5 ns */
+#define CONFIG_LPC32XX_SDRAM_T_XSR  12500000 /* 80 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RRD         1 /* 2 clocks */
+#define CONFIG_LPC32XX_SDRAM_T_MRD         1 /* 2 clocks */
+#define CONFIG_LPC32XX_SDRAM_T_CDLR        0 /* 1 clock */
+#define CONFIG_LPC32XX_SDRAM_REFRESH  128000
+#define CONFIG_LPC32XX_DRAM_MODE  0x00000030 /* CAS = 3 */
+#define CONFIG_LPC32XX_DRAM_EMODE 0x02000000 /* all zeroes */
+
+/*
+ * SPL
+ */
+
+/* SPL will be executed at offset 0 */
+#define CONFIG_SPL_TEXT_BASE 0x00000000
+/* SPL will use SRAM as stack */
+#define CONFIG_SPL_STACK     0x0000FFF8
+#define CONFIG_SPL_BOARD_INIT
+/* Use the framework and generic lib */
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+/* SPL will use serial */
+#define CONFIG_SPL_SERIAL_SUPPORT
+/* SPL will load U-Boot from NAND offset 0x40000 */
+#define CONFIG_SPL_NAND_SUPPORT
+#define CONFIG_SPL_NAND_DRIVERS
+#define CONFIG_SPL_NAND_BASE
+#define CONFIG_SPL_NAND_BOOT
+#define CONFIG_SYS_NAND_U_BOOT_OFFS  0x00040000
+/* U-Boot will be 0x40000 bytes, loaded and run at CONFIG_SYS_TEXT_BASE */
+#define CONFIG_SYS_MONITOR_LEN 0x40000 /* actually, MAX size */
+#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_NAND_U_BOOT_DST   CONFIG_SYS_TEXT_BASE
+
+/*
+ * Include SoC specific configuration
+ */
+#include <asm/arch/config.h>
+
+#endif  /* __CONFIG_WORK_92105_H__*/
-- 
2.1.0

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

* [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target
  2015-01-16  7:19             ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
  2015-01-16  7:19               ` [U-Boot] [PATCH v1 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
@ 2015-01-16 13:08               ` Marek Vasut
  2015-01-19  7:11                 ` Albert ARIBAUD
  1 sibling, 1 reply; 14+ messages in thread
From: Marek Vasut @ 2015-01-16 13:08 UTC (permalink / raw)
  To: u-boot

On Friday, January 16, 2015 at 08:19:19 AM, Albert ARIBAUD (3ADEV) wrote:
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
> 
>  Makefile              |   3 +
>  scripts/Makefile.spl  |  11 ++++
>  tools/.gitignore      |   1 +
>  tools/Makefile        |   2 +
>  tools/mklpc32xxboot.c | 169
> ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 186
> insertions(+)
>  create mode 100644 tools/mklpc32xxboot.c

Hi!

Are you positive this shouldn't be part of mkimage please ?

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support
  2015-01-16  7:19 ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
  2015-01-16  7:19   ` [U-Boot] [PATCH v1 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
@ 2015-01-16 16:46   ` Joe Hershberger
  1 sibling, 0 replies; 14+ messages in thread
From: Joe Hershberger @ 2015-01-16 16:46 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 16, 2015 at 1:19 AM, Albert ARIBAUD (3ADEV) <
albert.aribaud@3adev.fr> wrote:
>
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>

Looks reasonable.

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

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

* [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support
  2015-01-16  7:19       ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Albert ARIBAUD
  2015-01-16  7:19         ` [U-Boot] [PATCH v1 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
@ 2015-01-16 17:17         ` Simon Glass
  2015-01-19  7:12           ` Albert ARIBAUD
  1 sibling, 1 reply; 14+ messages in thread
From: Simon Glass @ 2015-01-16 17:17 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 16 January 2015 at 00:19, Albert ARIBAUD (3ADEV)
<albert.aribaud@3adev.fr> wrote:
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
>
>  arch/arm/include/asm/arch-lpc32xx/gpio.h |  43 ++++++
>  drivers/gpio/Makefile                    |   1 +
>  drivers/gpio/lpc32xx_gpio.c              | 223 +++++++++++++++++++++++++++++++
>  3 files changed, 267 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-lpc32xx/gpio.h
>  create mode 100644 drivers/gpio/lpc32xx_gpio.c

This should be done with driver model these days.

Regards,
Simon

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

* [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target
  2015-01-16 13:08               ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Marek Vasut
@ 2015-01-19  7:11                 ` Albert ARIBAUD
  0 siblings, 0 replies; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-19  7:11 UTC (permalink / raw)
  To: u-boot

Hello Marek,

On Fri, 16 Jan 2015 14:08:58 +0100, Marek Vasut <marex@denx.de> wrote:
> On Friday, January 16, 2015 at 08:19:19 AM, Albert ARIBAUD (3ADEV) wrote:
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> > 
> >  Makefile              |   3 +
> >  scripts/Makefile.spl  |  11 ++++
> >  tools/.gitignore      |   1 +
> >  tools/Makefile        |   2 +
> >  tools/mklpc32xxboot.c | 169
> > ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 186
> > insertions(+)
> >  create mode 100644 tools/mklpc32xxboot.c
> 
> Hi!
> 
> Are you positive this shouldn't be part of mkimage please ?

No, I'm not positive. :)

I'll move this to mkimage in v2.

> Best regards,
> Marek Vasut

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support
  2015-01-16 17:17         ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Simon Glass
@ 2015-01-19  7:12           ` Albert ARIBAUD
  0 siblings, 0 replies; 14+ messages in thread
From: Albert ARIBAUD @ 2015-01-19  7:12 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On Fri, 16 Jan 2015 10:17:52 -0700, Simon Glass <sjg@chromium.org>
wrote:
> Hi Albert,
> 
> On 16 January 2015 at 00:19, Albert ARIBAUD (3ADEV)
> <albert.aribaud@3adev.fr> wrote:
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> >
> >  arch/arm/include/asm/arch-lpc32xx/gpio.h |  43 ++++++
> >  drivers/gpio/Makefile                    |   1 +
> >  drivers/gpio/lpc32xx_gpio.c              | 223 +++++++++++++++++++++++++++++++
> >  3 files changed, 267 insertions(+)
> >  create mode 100644 arch/arm/include/asm/arch-lpc32xx/gpio.h
> >  create mode 100644 drivers/gpio/lpc32xx_gpio.c
> 
> This should be done with driver model these days.

I'll move it to DM in v2.

> Regards,
> Simon

Amicalement,
-- 
Albert.

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

end of thread, other threads:[~2015-01-19  7:12 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-16  7:19 [U-Boot] [PATCH v1 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
2015-01-16  7:19 ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
2015-01-16  7:19   ` [U-Boot] [PATCH v1 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
2015-01-16  7:19     ` [U-Boot] [PATCH v1 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
2015-01-16  7:19       ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Albert ARIBAUD
2015-01-16  7:19         ` [U-Boot] [PATCH v1 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
2015-01-16  7:19           ` [U-Boot] [PATCH v1 6/8] dtt: add ds620 support Albert ARIBAUD
2015-01-16  7:19             ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
2015-01-16  7:19               ` [U-Boot] [PATCH v1 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
2015-01-16 13:08               ` [U-Boot] [PATCH v1 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Marek Vasut
2015-01-19  7:11                 ` Albert ARIBAUD
2015-01-16 17:17         ` [U-Boot] [PATCH v1 4/8] lpc32xx: add GPIO support Simon Glass
2015-01-19  7:12           ` Albert ARIBAUD
2015-01-16 16:46   ` [U-Boot] [PATCH v1 1/8] lpc32xx: add Ethernet support Joe Hershberger

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