All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
@ 2015-02-12 17:36 Albert ARIBAUD
  2015-02-12 17:37 ` [U-Boot] [PATCH v2 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
  2015-02-17 13:20 ` [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Tom Rini
  0 siblings, 2 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:36 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: 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.

1. "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.

Changes in v2:
- move from legacy to Driver Model support
- added MUX setting for SSP0
- cosmetic: added a blank line before copyright
- move boot image generation to mkimage framework

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

 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           |  43 ++
 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            |   3 +
 arch/arm/include/asm/arch-lpc32xx/gpio.h           |  43 ++
 arch/arm/include/asm/arch-lpc32xx/mux.h            |  18 +
 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       |  86 +++
 .../work-microwave/work_92105/work_92105_display.c | 349 +++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 common/image.c                                     |   1 +
 configs/work_92105_defconfig                       |   5 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/lpc32xx_gpio.c                        | 268 +++++++++
 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                       | 259 +++++++++
 include/dtt.h                                      |  15 +-
 include/image.h                                    |   1 +
 include/netdev.h                                   |   1 +
 scripts/Makefile.spl                               |   9 +
 tools/Makefile                                     |   1 +
 tools/lpc32xximage.c                               | 178 ++++++
 41 files changed, 3222 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 arch/arm/include/asm/arch-lpc32xx/mux.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/lpc32xximage.c

-- 
2.1.0

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

* [U-Boot] [PATCH v2 1/8] lpc32xx: add Ethernet support
  2015-02-12 17:36 [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
@ 2015-02-12 17:37 ` Albert ARIBAUD
  2015-02-12 17:37   ` [U-Boot] [PATCH v2 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
  2015-02-17 13:20 ` [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Tom Rini
  1 sibling, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 UTC (permalink / raw)
  To: u-boot

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

Changes in v2: None

 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 46c4ac6..35fdb51 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 daffc12..b1b95dc 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] 32+ messages in thread

* [U-Boot] [PATCH v2 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-02-12 17:37 ` [U-Boot] [PATCH v2 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
@ 2015-02-12 17:37   ` Albert ARIBAUD
  2015-02-12 17:37     ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 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>
---

Changes in v2: None

 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] 32+ messages in thread

* [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-02-12 17:37   ` [U-Boot] [PATCH v2 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
@ 2015-02-12 17:37     ` Albert ARIBAUD
  2015-02-12 17:37       ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Albert ARIBAUD
  2015-02-13 10:48       ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Heiko Schocher
  0 siblings, 2 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 UTC (permalink / raw)
  To: u-boot

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

Changes in v2: None

 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 774bc94..26ea854 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -20,6 +20,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] 32+ messages in thread

* [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support
  2015-02-12 17:37     ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
@ 2015-02-12 17:37       ` Albert ARIBAUD
  2015-02-12 17:37         ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
  2015-02-13  5:06         ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Simon Glass
  2015-02-13 10:48       ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Heiko Schocher
  1 sibling, 2 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 UTC (permalink / raw)
  To: u-boot

This driver only supports Driver Model, not legacy model.

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

Changes in v2:
- move from legacy to Driver Model support

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c |   5 +
 arch/arm/include/asm/arch-lpc32xx/gpio.h |  43 +++++
 drivers/gpio/Makefile                    |   1 +
 drivers/gpio/lpc32xx_gpio.c              | 268 +++++++++++++++++++++++++++++++
 4 files changed, 317 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/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index 81b53ea..a407098 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -9,6 +9,7 @@
 #include <asm/arch/clk.h>
 #include <asm/arch/uart.h>
 #include <asm/io.h>
+#include <dm.h>
 
 static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
 static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
@@ -61,3 +62,7 @@ void lpc32xx_i2c_init(unsigned int devnum)
 		ctrl |= CLK_I2C2_ENABLE;
 	writel(ctrl, &clk->i2cclk_ctrl);
 }
+
+U_BOOT_DEVICE(lpc32xx_gpios) = {
+	.name = "gpio_lpc32xx"
+};
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..861975e
--- /dev/null
+++ b/drivers/gpio/lpc32xx_gpio.c
@@ -0,0 +1,268 @@
+/*
+ * LPC32xxGPIO driver
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/**
+ * We only support driver model
+ */
+#ifndef CONFIG_DM_GPIO
+#error Please enable Driver Model GPIO in your target configuration.
+#endif
+
+#include <asm/io.h>
+#include <asm/arch-lpc32xx/cpu.h>
+#include <asm/arch-lpc32xx/gpio.h>
+#include <asm-generic/gpio.h>
+#include <dm.h>
+#include <malloc.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 a single physical GPIO has differing numbers
+ * for setting its direction, reading it and/or writing to it.
+ */
+
+#define LPC32XX_GPIOS 128
+
+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))
+
+/**
+ * Array of current GPIO functions. Allocated as unsigned chars to
+ * limit memory consumption.
+ */
+
+static signed char lpc32xx_function[LPC32XX_GPIOS];
+
+/**
+ * Configure a GPIO number 'offset' as input
+ */
+
+static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+	int port, mask;
+
+	port = GPIO_TO_PORT(offset);
+	mask = GPIO_TO_MASK(offset);
+
+	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;
+	}
+
+	lpc32xx_function[offset] = GPIOF_INPUT;
+
+	return 0;
+}
+
+/**
+ * Get the value of a GPIO
+ */
+
+static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+	int port, rank, mask, value;
+
+	port = GPIO_TO_PORT(offset);
+
+	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(offset);
+	mask = GPIO_TO_MASK(offset);
+
+	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
+ */
+
+static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset,
+				 int value)
+{
+	if (value)
+		return gpio_set(offset);
+	else
+		return gpio_clr(offset);
+}
+
+/**
+ * Configure a GPIO number 'offset' as output with given initial value.
+ */
+
+static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
+				       int value)
+{
+	int port, mask;
+
+	port = GPIO_TO_PORT(offset);
+	mask = GPIO_TO_MASK(offset);
+
+	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;
+	}
+
+	lpc32xx_function[offset] = GPIOF_OUTPUT;
+
+	return lpc32xx_gpio_set_value(dev, offset, value);
+}
+
+static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+	return lpc32xx_function[offset];
+}
+
+static const struct dm_gpio_ops gpio_lpc32xx_ops = {
+	.direction_input	= lpc32xx_gpio_direction_input,
+	.direction_output	= lpc32xx_gpio_direction_output,
+	.get_value		= lpc32xx_gpio_get_value,
+	.set_value		= lpc32xx_gpio_set_value,
+	.get_function		= lpc32xx_gpio_get_function,
+};
+
+static int lpc32xx_gpio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+	if (dev->of_offset == -1) {
+		/* Tell the uclass how many GPIOs we have */
+		uc_priv->gpio_count = LPC32XX_GPIOS;
+	}
+
+	/* all GPIO functions are unknown until requested */
+	memset(lpc32xx_function, GPIOF_UNKNOWN, LPC32XX_GPIOS);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(gpio_lpc32xx) = {
+	.name	= "gpio_lpc32xx",
+	.id	= UCLASS_GPIO,
+	.ops	= &gpio_lpc32xx_ops,
+	.probe	= lpc32xx_gpio_probe,
+	.priv_auto_alloc_size = 0,
+};
-- 
2.1.0

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

* [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode)
  2015-02-12 17:37       ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Albert ARIBAUD
@ 2015-02-12 17:37         ` Albert ARIBAUD
  2015-02-12 17:37           ` [U-Boot] [PATCH v2 6/8] dtt: add ds620 support Albert ARIBAUD
  2015-02-17  9:33           ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Jagan Teki
  2015-02-13  5:06         ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Simon Glass
  1 sibling, 2 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 UTC (permalink / raw)
  To: u-boot

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

Changes in v2:
- added MUX setting for SSP0

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |  14 +++
 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, 151 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 a407098..5a453e3 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -8,11 +8,13 @@
 #include <asm/arch/cpu.h>
 #include <asm/arch/clk.h>
 #include <asm/arch/uart.h>
+#include <asm/arch/mux.h>
 #include <asm/io.h>
 #include <dm.h>
 
 static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
 static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
+static struct mux_regs *mux = (struct mux_regs *)MUX_BASE;
 
 void lpc32xx_uart_init(unsigned int uart_id)
 {
@@ -66,3 +68,15 @@ void lpc32xx_i2c_init(unsigned int devnum)
 U_BOOT_DEVICE(lpc32xx_gpios) = {
 	.name = "gpio_lpc32xx"
 };
+
+/* Mux for SCK0, MISO0, MOSI0. We do not use SSEL0. */
+
+#define P_MUX_SET_SSP0 0x1600
+
+void lpc32xx_ssp_init(void)
+{
+	/* Enable SSP0 interface */
+	writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl);
+	/* Mux SSP0 pins */
+	writel(P_MUX_SET_SSP0, &mux->p_mux_set);
+}
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] 32+ messages in thread

* [U-Boot] [PATCH v2 6/8] dtt: add ds620 support
  2015-02-12 17:37         ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
@ 2015-02-12 17:37           ` Albert ARIBAUD
  2015-02-12 17:37             ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
  2015-02-17  9:33           ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Jagan Teki
  1 sibling, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 UTC (permalink / raw)
  To: u-boot

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

Changes in v2:
- cosmetic: added a blank line before copyright

 drivers/hwmon/Makefile |  1 +
 drivers/hwmon/ds620.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/dtt.h          | 15 ++++++------
 3 files changed, 74 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..1ecc3da
--- /dev/null
+++ b/drivers/hwmon/ds620.c
@@ -0,0 +1,65 @@
+/*
+ * 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] 32+ messages in thread

* [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target
  2015-02-12 17:37           ` [U-Boot] [PATCH v2 6/8] dtt: add ds620 support Albert ARIBAUD
@ 2015-02-12 17:37             ` Albert ARIBAUD
  2015-02-12 17:37               ` [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
  2015-02-13  5:06               ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Simon Glass
  0 siblings, 2 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 UTC (permalink / raw)
  To: u-boot

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

Changes in v2:
- move boot image generation to mkimage framework

 common/image.c       |   1 +
 include/image.h      |   1 +
 scripts/Makefile.spl |   9 +++
 tools/Makefile       |   1 +
 tools/lpc32xximage.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 190 insertions(+)
 create mode 100644 tools/lpc32xximage.c

diff --git a/common/image.c b/common/image.c
index a911aa9..162b682 100644
--- a/common/image.c
+++ b/common/image.c
@@ -149,6 +149,7 @@ static const table_entry_t uimage_type[] = {
 	{	IH_TYPE_MXSIMAGE,   "mxsimage",   "Freescale MXS Boot Image",},
 	{	IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",},
 	{	IH_TYPE_X86_SETUP,  "x86_setup",  "x86 setup.bin",    },
+	{	IH_TYPE_LPC32XXIMAGE, "lpc32xximage",  "LPC32XX Boot Image", },
 	{	-1,		    "",		  "",			},
 };
 
diff --git a/include/image.h b/include/image.h
index 0e6af00..3844be6 100644
--- a/include/image.h
+++ b/include/image.h
@@ -242,6 +242,7 @@ struct lmb;
 #define IH_TYPE_ATMELIMAGE	18	/* ATMEL ROM bootable Image	*/
 #define IH_TYPE_SOCFPGAIMAGE	19	/* Altera SOCFPGA Preloader	*/
 #define IH_TYPE_X86_SETUP	20	/* x86 setup.bin Image		*/
+#define IH_TYPE_LPC32XXIMAGE	21	/* x86 setup.bin Image		*/
 
 /*
  * Compression Types
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index e4b9881..55d8b6f 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -147,6 +147,11 @@ endif
 boot.bin: $(obj)/u-boot-spl.bin
 	$(call if_changed,mkimage)
 
+MKIMAGEFLAGS_lpc32xx-boot.bin = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE)
+
+lpc32xx-boot.bin: $(obj)/u-boot-spl.bin
+	$(call if_changed,mkimage)
+
 ALL-y	+= $(obj)/$(SPL_BIN).bin
 
 ifdef CONFIG_SAMSUNG
@@ -159,6 +164,10 @@ ALL-y	+= $(obj)/sunxi-spl.bin
 endif
 endif
 
+ifdef CONFIG_LPC32XX_SPL
+ALL-y	+= lpc32xx-boot.bin
+endif
+
 ifeq ($(CONFIG_SYS_SOC),"at91")
 ALL-y	+= boot.bin
 endif
diff --git a/tools/Makefile b/tools/Makefile
index e4b23eb..c34c448 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -83,6 +83,7 @@ dumpimage-mkimage-objs := aisimage.o \
 			imximage.o \
 			kwbimage.o \
 			lib/md5.o \
+			lpc32xximage.o \
 			mxsimage.o \
 			omapimage.o \
 			os_support.o \
diff --git a/tools/lpc32xximage.c b/tools/lpc32xximage.c
new file mode 100644
index 0000000..6b3865f
--- /dev/null
+++ b/tools/lpc32xximage.c
@@ -0,0 +1,178 @@
+/*
+ * Image manipulator for LPC32XX SoCs
+ *
+ * (C) Copyright 2015  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * Derived from omapimage.c:
+ *
+ * (C) Copyright 2010
+ * Linaro LTD, www.linaro.org
+ * Author: John Rigby <john.rigby@linaro.org>
+ * Based on TI's signGP.c
+ *
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic at denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include <compiler.h>
+#include <image.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
+
+static struct nand_page_0_boot_header lpc32xximage_header;
+
+static int lpc32xximage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_LPC32XXIMAGE)
+		return EXIT_SUCCESS;
+	return EXIT_FAILURE;
+}
+
+static int lpc32xximage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct nand_page_0_boot_header *hdr =
+		(struct nand_page_0_boot_header *)ptr;
+
+	/* turn image size from bytes to NAND pages, page 0 included */
+	int image_size_in_pages = ((image_size - 1)
+				  / LPC32XX_BOOT_NAND_PAGESIZE);
+
+	if (hdr->data[0] != (0xff & LPC32XX_BOOT_ICR))
+		return -1;
+	if (hdr->data[1] != (0xff & ~LPC32XX_BOOT_ICR))
+		return -1;
+	if (hdr->data[2] != (0xff & LPC32XX_BOOT_ICR))
+		return -1;
+	if (hdr->data[3] != (0xff & ~LPC32XX_BOOT_ICR))
+		return -1;
+	if (hdr->data[4] != (0xff & image_size_in_pages))
+		return -1;
+	if (hdr->data[5] != (0xff & ~image_size_in_pages))
+		return -1;
+	if (hdr->data[6] != (0xff & image_size_in_pages))
+		return -1;
+	if (hdr->data[7] != (0xff & ~image_size_in_pages))
+		return -1;
+	if (hdr->data[8] != (0xff & image_size_in_pages))
+		return -1;
+	if (hdr->data[9] != (0xff & ~image_size_in_pages))
+		return -1;
+	if (hdr->data[10] != (0xff & image_size_in_pages))
+		return -1;
+	if (hdr->data[11] != (0xff & ~image_size_in_pages))
+		return -1;
+	if (hdr->data[12] != LPC32XX_BOOT_BLOCK_OK)
+		return -1;
+	if (hdr->data[128] != LPC32XX_BOOT_BLOCK_OK)
+		return -1;
+	return 0;
+}
+
+static void print_hdr_byte(struct nand_page_0_boot_header *hdr, int ofs)
+{
+	printf("header[%d] = %02x\n", ofs, hdr->data[ofs]);
+}
+
+static void lpc32xximage_print_header(const void *ptr)
+{
+	struct nand_page_0_boot_header *hdr =
+		(struct nand_page_0_boot_header *)ptr;
+	int ofs;
+
+	for (ofs = 0; ofs <= 12; ofs++)
+		print_hdr_byte(hdr, ofs);
+	print_hdr_byte(hdr, 128);
+}
+
+static void lpc32xximage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	struct nand_page_0_boot_header *hdr =
+		(struct nand_page_0_boot_header *)ptr;
+
+	/* turn image size from bytes to NAND pages, page 0 included */
+	int image_size_in_pages = ((sbuf->st_size
+				  + LPC32XX_BOOT_NAND_PAGESIZE - 1)
+				  / LPC32XX_BOOT_NAND_PAGESIZE);
+
+	/* fill header -- default byte value is 0x00, not 0xFF */
+	memset((void *)hdr, 0, sizeof(*hdr));
+	hdr->data[0] = (hdr->data[2] = 0xff & LPC32XX_BOOT_ICR);
+	hdr->data[1] = (hdr->data[3] = 0xff & ~LPC32XX_BOOT_ICR);
+	hdr->data[4] = (hdr->data[6] = (hdr->data[8]
+		       = (hdr->data[10] = 0xff & image_size_in_pages)));
+	hdr->data[5] = (hdr->data[7] = (hdr->data[9]
+		       = (hdr->data[11] = 0xff & ~image_size_in_pages)));
+	hdr->data[12] = (hdr->data[128] = LPC32XX_BOOT_BLOCK_OK);
+}
+
+/*
+ * lpc32xximage parameters
+ */
+U_BOOT_IMAGE_TYPE(
+	lpc32xximage,
+	"LPC32XX Boot Image",
+	sizeof(lpc32xximage_header),
+	(void *)&lpc32xximage_header,
+	NULL,
+	lpc32xximage_verify_header,
+	lpc32xximage_print_header,
+	lpc32xximage_set_header,
+	NULL,
+	lpc32xximage_check_image_types,
+	NULL,
+	NULL
+);
-- 
2.1.0

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

* [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105
  2015-02-12 17:37             ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
@ 2015-02-12 17:37               ` Albert ARIBAUD
  2015-02-13  9:36                 ` Stefan Roese
  2015-02-17  1:08                 ` [U-Boot] [U-Boot, v2, " Tom Rini
  2015-02-13  5:06               ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Simon Glass
  1 sibling, 2 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-12 17:37 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>
---

Changes in v2: None

 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/cpu.h            |   1 +
 arch/arm/include/asm/arch-lpc32xx/mux.h            |  18 ++
 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       |  86 +++++
 .../work-microwave/work_92105/work_92105_display.c | 349 +++++++++++++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 configs/work_92105_defconfig                       |   5 +
 include/configs/work_92105.h                       | 259 +++++++++++++++
 19 files changed, 963 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 arch/arm/include/asm/arch-lpc32xx/mux.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 include/configs/work_92105.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 47806f8..42983a3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -247,6 +247,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
@@ -999,6 +1004,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/cpu.h b/arch/arm/include/asm/arch-lpc32xx/cpu.h
index 1067107..0b5dca1 100644
--- a/arch/arm/include/asm/arch-lpc32xx/cpu.h
+++ b/arch/arm/include/asm/arch-lpc32xx/cpu.h
@@ -27,6 +27,7 @@
 #define HS_UART7_BASE	0x4001C000	/* High speed UART 7 registers base */
 #define RTC_BASE	0x40024000	/* RTC registers base               */
 #define GPIO_BASE	0x40028000	/* GPIO registers base              */
+#define MUX_BASE	0x40028100	/* MUX registers base               */
 #define WDT_BASE	0x4003C000	/* Watchdog timer registers base    */
 #define TIMER0_BASE	0x40044000	/* Timer0 registers base            */
 #define TIMER1_BASE	0x4004C000	/* Timer1 registers base            */
diff --git a/arch/arm/include/asm/arch-lpc32xx/mux.h b/arch/arm/include/asm/arch-lpc32xx/mux.h
new file mode 100644
index 0000000..dc1b5bc
--- /dev/null
+++ b/arch/arm/include/asm/arch-lpc32xx/mux.h
@@ -0,0 +1,18 @@
+/*
+ * LPC32xx MUX interface
+ *
+ * (C) Copyright 2015  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/**
+ * MUX register map for LPC32xx
+ */
+
+struct mux_regs {
+	u32 p_mux_set;
+	u32 p_mux_clr;
+	u32 p_mux_state;
+};
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..cad0d75
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105.c
@@ -0,0 +1,86 @@
+/*
+ * 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_request(GPO_19, "NAND_nWP");
+	gpio_direction_output(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..c8b1013
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105_display.c
@@ -0,0 +1,349 @@
+/*
+ * 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);
+
+	/* request GPO_15 as an output initially set to 1 */
+	gpio_request(GPO_15, "MAX6957_nCS");
+	gpio_direction_output(GPO_15, 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..9be52a8
--- /dev/null
+++ b/configs/work_92105_defconfig
@@ -0,0 +1,5 @@
+CONFIG_DM=y
+CONFIG_DM_GPIO=y
+CONFIG_SPL=y
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_WORK_92105=y
diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h
new file mode 100644
index 0000000..fd242fb
--- /dev/null
+++ b/include/configs/work_92105.h
@@ -0,0 +1,259 @@
+/*
+ * 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_512K \
+					 - 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
+
+#define CONFIG_CMD_DM
+
+/*
+ * 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] 32+ messages in thread

* [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target
  2015-02-12 17:37             ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
  2015-02-12 17:37               ` [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
@ 2015-02-13  5:06               ` Simon Glass
  1 sibling, 0 replies; 32+ messages in thread
From: Simon Glass @ 2015-02-13  5:06 UTC (permalink / raw)
  To: u-boot

On 12 February 2015 at 10:37, Albert ARIBAUD (3ADEV)
<albert.aribaud@3adev.fr> wrote:
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
>
> Changes in v2:
> - move boot image generation to mkimage framework
>
>  common/image.c       |   1 +
>  include/image.h      |   1 +
>  scripts/Makefile.spl |   9 +++
>  tools/Makefile       |   1 +
>  tools/lpc32xximage.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 190 insertions(+)
>  create mode 100644 tools/lpc32xximage.c

Reviewed-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support
  2015-02-12 17:37       ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Albert ARIBAUD
  2015-02-12 17:37         ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
@ 2015-02-13  5:06         ` Simon Glass
  2015-02-13  6:30           ` Albert ARIBAUD
  1 sibling, 1 reply; 32+ messages in thread
From: Simon Glass @ 2015-02-13  5:06 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 12 February 2015 at 10:37, Albert ARIBAUD (3ADEV)
<albert.aribaud@3adev.fr> wrote:
> This driver only supports Driver Model, not legacy model.
>
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
>
> Changes in v2:
> - move from legacy to Driver Model support
>
>  arch/arm/cpu/arm926ejs/lpc32xx/devices.c |   5 +
>  arch/arm/include/asm/arch-lpc32xx/gpio.h |  43 +++++
>  drivers/gpio/Makefile                    |   1 +
>  drivers/gpio/lpc32xx_gpio.c              | 268 +++++++++++++++++++++++++++++++
>  4 files changed, 317 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/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> index 81b53ea..a407098 100644
> --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> @@ -9,6 +9,7 @@
>  #include <asm/arch/clk.h>
>  #include <asm/arch/uart.h>
>  #include <asm/io.h>
> +#include <dm.h>
>
>  static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
>  static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
> @@ -61,3 +62,7 @@ void lpc32xx_i2c_init(unsigned int devnum)
>                 ctrl |= CLK_I2C2_ENABLE;
>         writel(ctrl, &clk->i2cclk_ctrl);
>  }
> +
> +U_BOOT_DEVICE(lpc32xx_gpios) = {
> +       .name = "gpio_lpc32xx"
> +};
> 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..861975e
> --- /dev/null
> +++ b/drivers/gpio/lpc32xx_gpio.c
> @@ -0,0 +1,268 @@
> +/*
> + * LPC32xxGPIO driver
> + *
> + * (C) Copyright 2014  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +/**
> + * We only support driver model
> + */
> +#ifndef CONFIG_DM_GPIO
> +#error Please enable Driver Model GPIO in your target configuration.
> +#endif

Minor note - if you base this on dm/master you can use Kconfig
'depends on DM' in this driver's Kconfig bit.

(pull request to mainline coming soon)

> +
> +#include <asm/io.h>
> +#include <asm/arch-lpc32xx/cpu.h>
> +#include <asm/arch-lpc32xx/gpio.h>
> +#include <asm-generic/gpio.h>
> +#include <dm.h>
> +#include <malloc.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 a single physical GPIO has differing numbers
> + * for setting its direction, reading it and/or writing to it.
> + */
> +
> +#define LPC32XX_GPIOS 128
> +
> +static struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE;

Normally this would go in a

struct lpc32xx_priv

in the driver.

> +
> +/**
> + * 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))
> +
> +/**
> + * Array of current GPIO functions. Allocated as unsigned chars to
> + * limit memory consumption.
> + */
> +
> +static signed char lpc32xx_function[LPC32XX_GPIOS];

...along with this.

> +
> +/**
> + * Configure a GPIO number 'offset' as input
> + */
> +
> +static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
> +{
> +       int port, mask;
> +
> +       port = GPIO_TO_PORT(offset);
> +       mask = GPIO_TO_MASK(offset);
> +
> +       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;
> +       }
> +
> +       lpc32xx_function[offset] = GPIOF_INPUT;

Another way of doing this is to read the status from the hardware.
This might allow you to support GPIOF_FUNCTION - i.e. the GPIO is
currently used by a function.

> +
> +       return 0;
> +}
> +
> +/**
> + * Get the value of a GPIO
> + */
> +
> +static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
> +{
> +       int port, rank, mask, value;
> +
> +       port = GPIO_TO_PORT(offset);
> +
> +       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(offset);
> +       mask = GPIO_TO_MASK(offset);
> +
> +       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
> + */
> +
> +static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset,
> +                                int value)
> +{
> +       if (value)
> +               return gpio_set(offset);
> +       else
> +               return gpio_clr(offset);
> +}
> +
> +/**
> + * Configure a GPIO number 'offset' as output with given initial value.
> + */
> +
> +static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
> +                                      int value)
> +{
> +       int port, mask;
> +
> +       port = GPIO_TO_PORT(offset);
> +       mask = GPIO_TO_MASK(offset);
> +
> +       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;
> +       }
> +
> +       lpc32xx_function[offset] = GPIOF_OUTPUT;
> +
> +       return lpc32xx_gpio_set_value(dev, offset, value);
> +}
> +
> +static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
> +{
> +       return lpc32xx_function[offset];
> +}
> +
> +static const struct dm_gpio_ops gpio_lpc32xx_ops = {
> +       .direction_input        = lpc32xx_gpio_direction_input,
> +       .direction_output       = lpc32xx_gpio_direction_output,
> +       .get_value              = lpc32xx_gpio_get_value,
> +       .set_value              = lpc32xx_gpio_set_value,
> +       .get_function           = lpc32xx_gpio_get_function,
> +};
> +
> +static int lpc32xx_gpio_probe(struct udevice *dev)
> +{
> +       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
> +
> +       if (dev->of_offset == -1) {
> +               /* Tell the uclass how many GPIOs we have */
> +               uc_priv->gpio_count = LPC32XX_GPIOS;
> +       }
> +
> +       /* all GPIO functions are unknown until requested */
> +       memset(lpc32xx_function, GPIOF_UNKNOWN, LPC32XX_GPIOS);
> +
> +       return 0;
> +}
> +
> +U_BOOT_DRIVER(gpio_lpc32xx) = {
> +       .name   = "gpio_lpc32xx",
> +       .id     = UCLASS_GPIO,
> +       .ops    = &gpio_lpc32xx_ops,
> +       .probe  = lpc32xx_gpio_probe,
> +       .priv_auto_alloc_size = 0,

You can use sizeof(struct lpc32xx_priv) here and it will automatically
allocate your structure when the device is probed.

> +};
> --
> 2.1.0
>

Regards,
Simon

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

* [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support
  2015-02-13  5:06         ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Simon Glass
@ 2015-02-13  6:30           ` Albert ARIBAUD
  2015-02-13 14:33             ` Simon Glass
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-13  6:30 UTC (permalink / raw)
  To: u-boot

Hi Simon,

Le Thu, 12 Feb 2015 22:06:51 -0700, Simon Glass <sjg@chromium.org> a
?crit :

> Hi Albert,
> 
> On 12 February 2015 at 10:37, Albert ARIBAUD (3ADEV)
> <albert.aribaud@3adev.fr> wrote:
> > This driver only supports Driver Model, not legacy model.
> >
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> >
> > Changes in v2:
> > - move from legacy to Driver Model support
> >
> >  arch/arm/cpu/arm926ejs/lpc32xx/devices.c |   5 +
> >  arch/arm/include/asm/arch-lpc32xx/gpio.h |  43 +++++
> >  drivers/gpio/Makefile                    |   1 +
> >  drivers/gpio/lpc32xx_gpio.c              | 268 +++++++++++++++++++++++++++++++
> >  4 files changed, 317 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/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> > index 81b53ea..a407098 100644
> > --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> > +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> > @@ -9,6 +9,7 @@
> >  #include <asm/arch/clk.h>
> >  #include <asm/arch/uart.h>
> >  #include <asm/io.h>
> > +#include <dm.h>
> >
> >  static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
> >  static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
> > @@ -61,3 +62,7 @@ void lpc32xx_i2c_init(unsigned int devnum)
> >                 ctrl |= CLK_I2C2_ENABLE;
> >         writel(ctrl, &clk->i2cclk_ctrl);
> >  }
> > +
> > +U_BOOT_DEVICE(lpc32xx_gpios) = {
> > +       .name = "gpio_lpc32xx"
> > +};
> > 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..861975e
> > --- /dev/null
> > +++ b/drivers/gpio/lpc32xx_gpio.c
> > @@ -0,0 +1,268 @@
> > +/*
> > + * LPC32xxGPIO driver
> > + *
> > + * (C) Copyright 2014  DENX Software Engineering GmbH
> > + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
> > + *
> > + * SPDX-License-Identifier:    GPL-2.0+
> > + */
> > +
> > +/**
> > + * We only support driver model
> > + */
> > +#ifndef CONFIG_DM_GPIO
> > +#error Please enable Driver Model GPIO in your target configuration.
> > +#endif
> 
> Minor note - if you base this on dm/master you can use Kconfig
> 'depends on DM' in this driver's Kconfig bit.
> 
> (pull request to mainline coming soon)

I will rebase then for v3.

> > +#include <asm/io.h>
> > +#include <asm/arch-lpc32xx/cpu.h>
> > +#include <asm/arch-lpc32xx/gpio.h>
> > +#include <asm-generic/gpio.h>
> > +#include <dm.h>
> > +#include <malloc.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 a single physical GPIO has differing numbers
> > + * for setting its direction, reading it and/or writing to it.
> > + */
> > +
> > +#define LPC32XX_GPIOS 128
> > +
> > +static struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE;
> 
> Normally this would go in a
> 
> struct lpc32xx_priv
> 
> in the driver.

Will change this.

> > +
> > +/**
> > + * 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))
> > +
> > +/**
> > + * Array of current GPIO functions. Allocated as unsigned chars to
> > + * limit memory consumption.
> > + */
> > +
> > +static signed char lpc32xx_function[LPC32XX_GPIOS];
> 
> ...along with this.

Ditto.

> > +
> > +/**
> > + * Configure a GPIO number 'offset' as input
> > + */
> > +
> > +static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
> > +{
> > +       int port, mask;
> > +
> > +       port = GPIO_TO_PORT(offset);
> > +       mask = GPIO_TO_MASK(offset);
> > +
> > +       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;
> > +       }
> > +
> > +       lpc32xx_function[offset] = GPIOF_INPUT;
> 
> Another way of doing this is to read the status from the hardware.
> This might allow you to support GPIOF_FUNCTION - i.e. the GPIO is
> currently used by a function.

Even under the simplified model I used for LPC32XX GPIOs, finding out
the state of an individual gpio would be quite complicated and would
incur much work for a feature which is actually only useful for the
'gpio' command -- a commodity but not a necessity as far a the actual
board user is concerned.

> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * Get the value of a GPIO
> > + */
> > +
> > +static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
> > +{
> > +       int port, rank, mask, value;
> > +
> > +       port = GPIO_TO_PORT(offset);
> > +
> > +       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(offset);
> > +       mask = GPIO_TO_MASK(offset);
> > +
> > +       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
> > + */
> > +
> > +static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset,
> > +                                int value)
> > +{
> > +       if (value)
> > +               return gpio_set(offset);
> > +       else
> > +               return gpio_clr(offset);
> > +}
> > +
> > +/**
> > + * Configure a GPIO number 'offset' as output with given initial value.
> > + */
> > +
> > +static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
> > +                                      int value)
> > +{
> > +       int port, mask;
> > +
> > +       port = GPIO_TO_PORT(offset);
> > +       mask = GPIO_TO_MASK(offset);
> > +
> > +       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;
> > +       }
> > +
> > +       lpc32xx_function[offset] = GPIOF_OUTPUT;
> > +
> > +       return lpc32xx_gpio_set_value(dev, offset, value);
> > +}
> > +
> > +static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
> > +{
> > +       return lpc32xx_function[offset];
> > +}
> > +
> > +static const struct dm_gpio_ops gpio_lpc32xx_ops = {
> > +       .direction_input        = lpc32xx_gpio_direction_input,
> > +       .direction_output       = lpc32xx_gpio_direction_output,
> > +       .get_value              = lpc32xx_gpio_get_value,
> > +       .set_value              = lpc32xx_gpio_set_value,
> > +       .get_function           = lpc32xx_gpio_get_function,
> > +};
> > +
> > +static int lpc32xx_gpio_probe(struct udevice *dev)
> > +{
> > +       struct gpio_dev_priv *uc_priv = dev->uclass_priv;
> > +
> > +       if (dev->of_offset == -1) {
> > +               /* Tell the uclass how many GPIOs we have */
> > +               uc_priv->gpio_count = LPC32XX_GPIOS;
> > +       }
> > +
> > +       /* all GPIO functions are unknown until requested */
> > +       memset(lpc32xx_function, GPIOF_UNKNOWN, LPC32XX_GPIOS);
> > +
> > +       return 0;
> > +}
> > +
> > +U_BOOT_DRIVER(gpio_lpc32xx) = {
> > +       .name   = "gpio_lpc32xx",
> > +       .id     = UCLASS_GPIO,
> > +       .ops    = &gpio_lpc32xx_ops,
> > +       .probe  = lpc32xx_gpio_probe,
> > +       .priv_auto_alloc_size = 0,
> 
> You can use sizeof(struct lpc32xx_priv) here and it will automatically
> allocate your structure when the device is probed.

Yep, that'll get in along with moving the base address and intenal
gpio state array.

> > +};
> > --
> > 2.1.0
> >
> 
> Regards,
> Simon

Thanks for your review!

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105
  2015-02-12 17:37               ` [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
@ 2015-02-13  9:36                 ` Stefan Roese
  2015-02-13 11:08                   ` Albert ARIBAUD
  2015-02-17  1:08                 ` [U-Boot] [U-Boot, v2, " Tom Rini
  1 sibling, 1 reply; 32+ messages in thread
From: Stefan Roese @ 2015-02-13  9:36 UTC (permalink / raw)
  To: u-boot

Hi Albert,

please find some review comments below.

On 12.02.2015 18:37, Albert ARIBAUD (3ADEV) wrote:
> 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>
> ---
>
> Changes in v2: None
>
>   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/cpu.h            |   1 +
>   arch/arm/include/asm/arch-lpc32xx/mux.h            |  18 ++
>   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       |  86 +++++
>   .../work-microwave/work_92105/work_92105_display.c | 349 +++++++++++++++++++++
>   .../work-microwave/work_92105/work_92105_display.h |  14 +
>   configs/work_92105_defconfig                       |   5 +
>   include/configs/work_92105.h                       | 259 +++++++++++++++
>   19 files changed, 963 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 arch/arm/include/asm/arch-lpc32xx/mux.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 include/configs/work_92105.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 47806f8..42983a3 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -247,6 +247,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
> @@ -999,6 +1004,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)

Why don't you move this compiler switch to the Makefiles instead?

> +
> +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/cpu.h b/arch/arm/include/asm/arch-lpc32xx/cpu.h
> index 1067107..0b5dca1 100644
> --- a/arch/arm/include/asm/arch-lpc32xx/cpu.h
> +++ b/arch/arm/include/asm/arch-lpc32xx/cpu.h
> @@ -27,6 +27,7 @@
>   #define HS_UART7_BASE	0x4001C000	/* High speed UART 7 registers base */
>   #define RTC_BASE	0x40024000	/* RTC registers base               */
>   #define GPIO_BASE	0x40028000	/* GPIO registers base              */
> +#define MUX_BASE	0x40028100	/* MUX registers base               */
>   #define WDT_BASE	0x4003C000	/* Watchdog timer registers base    */
>   #define TIMER0_BASE	0x40044000	/* Timer0 registers base            */
>   #define TIMER1_BASE	0x4004C000	/* Timer1 registers base            */
> diff --git a/arch/arm/include/asm/arch-lpc32xx/mux.h b/arch/arm/include/asm/arch-lpc32xx/mux.h
> new file mode 100644
> index 0000000..dc1b5bc
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-lpc32xx/mux.h
> @@ -0,0 +1,18 @@
> +/*
> + * LPC32xx MUX interface
> + *
> + * (C) Copyright 2015  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +/**
> + * MUX register map for LPC32xx
> + */
> +
> +struct mux_regs {
> +	u32 p_mux_set;
> +	u32 p_mux_clr;
> +	u32 p_mux_state;
> +};
> 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

Really u-boot.bin? Why don't you use u-boot.img with the header / CRC 
instead? This is commonly used by other SPL platforms.

And wouldn't it be nice to combine (concatenate) those two images into 
one image that can be flashed to the board? There are already some 
Makefile rules for doing this.

> 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..cad0d75
> --- /dev/null
> +++ b/board/work-microwave/work_92105/work_92105.c
> @@ -0,0 +1,86 @@
> +/*
> + * 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)

I would perfer to move those SPL related function into a seperate file 
(e.g. spl.c) instead. And the Makefile can handle the conditional 
compilation then.

> +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_request(GPO_19, "NAND_nWP");
> +	gpio_direction_output(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..c8b1013
> --- /dev/null
> +++ b/board/work-microwave/work_92105/work_92105_display.c
> @@ -0,0 +1,349 @@
> +/*
> + * 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);
> +
> +	/* request GPO_15 as an output initially set to 1 */
> +	gpio_request(GPO_15, "MAX6957_nCS");
> +	gpio_direction_output(GPO_15, 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..9be52a8
> --- /dev/null
> +++ b/configs/work_92105_defconfig
> @@ -0,0 +1,5 @@
> +CONFIG_DM=y
> +CONFIG_DM_GPIO=y
> +CONFIG_SPL=y
> ++S:CONFIG_ARM=y
> ++S:CONFIG_TARGET_WORK_92105=y
> diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h
> new file mode 100644
> index 0000000..fd242fb
> --- /dev/null
> +++ b/include/configs/work_92105.h
> @@ -0,0 +1,259 @@
> +/*
> + * 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_512K \
> +					 - 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
> +
> +#define CONFIG_CMD_DM
> +
> +/*
> + * 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

We usually don't allow MAC addresses to be set in the board config 
files. Is this really needed?

Thanks,
Stefan

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

* [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-02-12 17:37     ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
  2015-02-12 17:37       ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Albert ARIBAUD
@ 2015-02-13 10:48       ` Heiko Schocher
  2015-02-13 11:09         ` Albert ARIBAUD
  1 sibling, 1 reply; 32+ messages in thread
From: Heiko Schocher @ 2015-02-13 10:48 UTC (permalink / raw)
  To: u-boot

Hello Albert,

Am 12.02.2015 18:37, schrieb Albert ARIBAUD (3ADEV):
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
>
> Changes in v2: None
>
>   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

Acked-by: Heiko Schocher <hs@denx.de>

Do you have a chance to use DM on this HW?

bye,
Heiko
>
> 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 774bc94..26ea854 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -20,6 +20,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)
>

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105
  2015-02-13  9:36                 ` Stefan Roese
@ 2015-02-13 11:08                   ` Albert ARIBAUD
  2015-02-13 11:19                     ` Stefan Roese
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-13 11:08 UTC (permalink / raw)
  To: u-boot

Hi Stefan,

Le Fri, 13 Feb 2015 10:36:52 +0100, Stefan Roese <sr@denx.de> a ?crit :

> > +++ 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)  
> 
> Why don't you move this compiler switch to the Makefiles instead?

Indeed, why? :)
Will do in v3.

> > +++ b/board/work-microwave/work_92105/README

> > +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
> 
> Really u-boot.bin? Why don't you use u-boot.img with the header / CRC 
> instead? This is commonly used by other SPL platforms.

u-boot.bin (headerless) is what the old process used, so I went for the
least change path, but of course u-boot.img works too. I'll fix the
text to mention u-boot.img and just note that u-boot.bin would work too
but would not be checked for integrity.

(plus I need to fix the SPL image name anyway, since I changed it
when switching to mkimage.)

> And wouldn't it be nice to combine (concatenate) those two images into 
> one image that can be flashed to the board? There are already some 
> Makefile rules for doing this.

Actually it would have to concatenate two (redundant) copies of the SPL
image then one of U-Boot, bu yes, you're right. I'll look into it --
and add notes to this effect in the board README file.

> > +++ b/board/work-microwave/work_92105/work_92105.c
> > @@ -0,0 +1,86 @@
> > +/*
> > + * 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)
> 
> I would perfer to move those SPL related function into a seperate file 
> (e.g. spl.c) instead. And the Makefile can handle the conditional 
> compilation then.

Ok.

> > +++ b/include/configs/work_92105.h

> > +#define CONFIG_ETHADDR			00:12:B4:00:AF:FE
> > +#define	CONFIG_OVERWRITE_ETHADDR_ONCE
> 
> We usually don't allow MAC addresses to be set in the board config 
> files. Is this really needed?

If CONFIG_ETH.*ADDR are not to be allowed, then maybe ./README should
be updated to reflect this, and the more than 08 existing definitions
in include/configs should be fixed. :)

This is what was in the boards's default config initially. I'd rather
leave it there in case the actual board provisioning process assumes
the board to have this eth MAC address on very first boot. I can add a
big red blinking comment though.

> Thanks,
> Stefan

Thanks for your review!

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-02-13 10:48       ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Heiko Schocher
@ 2015-02-13 11:09         ` Albert ARIBAUD
  2015-02-13 11:20           ` Heiko Schocher
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-13 11:09 UTC (permalink / raw)
  To: u-boot

Hi Heiko,

Le Fri, 13 Feb 2015 11:48:26 +0100, Heiko Schocher <hs@denx.de> a
?crit :

> Hello Albert,
> 
> Am 12.02.2015 18:37, schrieb Albert ARIBAUD (3ADEV):
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> >
> > Changes in v2: None
> >
> >   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
> 
> Acked-by: Heiko Schocher <hs@denx.de>
> 
> Do you have a chance to use DM on this HW?

I am using it for GPIOs already. I guess you would like I2C to use it
too?

> bye,
> Heiko

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105
  2015-02-13 11:08                   ` Albert ARIBAUD
@ 2015-02-13 11:19                     ` Stefan Roese
  0 siblings, 0 replies; 32+ messages in thread
From: Stefan Roese @ 2015-02-13 11:19 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 13.02.2015 12:08, Albert ARIBAUD wrote:
>>> +++ b/board/work-microwave/work_92105/README
>
>>> +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
>>
>> Really u-boot.bin? Why don't you use u-boot.img with the header / CRC
>> instead? This is commonly used by other SPL platforms.
>
> u-boot.bin (headerless) is what the old process used, so I went for the
> least change path, but of course u-boot.img works too. I'll fix the
> text to mention u-boot.img and just note that u-boot.bin would work too
> but would not be checked for integrity.

Good. Thanks.

> (plus I need to fix the SPL image name anyway, since I changed it
> when switching to mkimage.)
>
>> And wouldn't it be nice to combine (concatenate) those two images into
>> one image that can be flashed to the board? There are already some
>> Makefile rules for doing this.
>
> Actually it would have to concatenate two (redundant) copies of the SPL
> image then one of U-Boot, bu yes, you're right. I'll look into it --
> and add notes to this effect in the board README file.

Thanks.

>>> +++ b/include/configs/work_92105.h
>
>>> +#define CONFIG_ETHADDR			00:12:B4:00:AF:FE
>>> +#define	CONFIG_OVERWRITE_ETHADDR_ONCE
>>
>> We usually don't allow MAC addresses to be set in the board config
>> files. Is this really needed?
>
> If CONFIG_ETH.*ADDR are not to be allowed, then maybe ./README should
> be updated to reflect this, and the more than 08 existing definitions
> in include/configs should be fixed. :)

Yes. We've been less strict with code reviews a few years ago. Thats 
most likely when those defines "slipped in".

> This is what was in the boards's default config initially. I'd rather
> leave it there in case the actual board provisioning process assumes
> the board to have this eth MAC address on very first boot. I can add a
> big red blinking comment though.

Okay.

Thanks,
Stefan

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

* [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-02-13 11:09         ` Albert ARIBAUD
@ 2015-02-13 11:20           ` Heiko Schocher
  2015-02-15 21:48             ` Simon Glass
  0 siblings, 1 reply; 32+ messages in thread
From: Heiko Schocher @ 2015-02-13 11:20 UTC (permalink / raw)
  To: u-boot

Hello Albert,

Am 13.02.2015 12:09, schrieb Albert ARIBAUD:
> Hi Heiko,
>
> Le Fri, 13 Feb 2015 11:48:26 +0100, Heiko Schocher <hs@denx.de> a
> ?crit :
>
>> Hello Albert,
>>
>> Am 12.02.2015 18:37, schrieb Albert ARIBAUD (3ADEV):
>>> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
>>> ---
>>>
>>> Changes in v2: None
>>>
>>>    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
>>
>> Acked-by: Heiko Schocher <hs@denx.de>
>>
>> Do you have a chance to use DM on this HW?
>
> I am using it for GPIOs already. I guess you would like I2C to use it
> too?

Yes, if it is possible for you to convert the driver to it, that would
be great!

DM is the future ;-)

bye,
Heiko
-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support
  2015-02-13  6:30           ` Albert ARIBAUD
@ 2015-02-13 14:33             ` Simon Glass
  0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2015-02-13 14:33 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 12 February 2015 at 23:30, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> Hi Simon,
>
> Le Thu, 12 Feb 2015 22:06:51 -0700, Simon Glass <sjg@chromium.org> a
> ?crit :
>
>> Hi Albert,
>>
>> On 12 February 2015 at 10:37, Albert ARIBAUD (3ADEV)
>> <albert.aribaud@3adev.fr> wrote:
>> > This driver only supports Driver Model, not legacy model.
>> >
>> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
>> > ---
>> >
>> > Changes in v2:
>> > - move from legacy to Driver Model support
[snip]
>> > +static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
>> > +{
>> > +       int port, mask;
>> > +
>> > +       port = GPIO_TO_PORT(offset);
>> > +       mask = GPIO_TO_MASK(offset);
>> > +
>> > +       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;
>> > +       }
>> > +
>> > +       lpc32xx_function[offset] = GPIOF_INPUT;
>>
>> Another way of doing this is to read the status from the hardware.
>> This might allow you to support GPIOF_FUNCTION - i.e. the GPIO is
>> currently used by a function.
>
> Even under the simplified model I used for LPC32XX GPIOs, finding out
> the state of an individual gpio would be quite complicated and would
> incur much work for a feature which is actually only useful for the
> 'gpio' command -- a commodity but not a necessity as far a the actual
> board user is concerned.

Yes it's only a nicety and can easily be added later if someone wants
it. But it might be worth adding a comment to that effect - someone
using this driver for inspiration might get the wrong idea.

Regards,
Simon

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

* [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-02-13 11:20           ` Heiko Schocher
@ 2015-02-15 21:48             ` Simon Glass
  0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2015-02-15 21:48 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 13 February 2015 at 04:20, Heiko Schocher <hs@denx.de> wrote:
> Hello Albert,
>
> Am 13.02.2015 12:09, schrieb Albert ARIBAUD:
>>
>> Hi Heiko,
>>
>> Le Fri, 13 Feb 2015 11:48:26 +0100, Heiko Schocher <hs@denx.de> a
>> ?crit :
>>
>>> Hello Albert,
>>>
>>> Am 12.02.2015 18:37, schrieb Albert ARIBAUD (3ADEV):
>>>>
>>>> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
>>>> ---
>>>>
>>>> Changes in v2: None
>>>>
>>>>    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
>>>
>>>
>>> Acked-by: Heiko Schocher <hs@denx.de>
>>>
>>> Do you have a chance to use DM on this HW?
>>
>>
>> I am using it for GPIOs already. I guess you would like I2C to use it
>> too?
>
>
> Yes, if it is possible for you to convert the driver to it, that would
> be great!
>
> DM is the future ;-)

It is fairly straightforward for I2C now. There is no detailed
documentation but i2c.h explains the methods and you can see examples
with tegra, sandbox and samsung (s3c24x0.c).

Regards,
Simon

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

* [U-Boot] [U-Boot, v2, 8/8] lpc32xx: add support for board work_92105
  2015-02-12 17:37               ` [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
  2015-02-13  9:36                 ` Stefan Roese
@ 2015-02-17  1:08                 ` Tom Rini
  2015-02-17  7:06                   ` Albert ARIBAUD
  1 sibling, 1 reply; 32+ messages in thread
From: Tom Rini @ 2015-02-17  1:08 UTC (permalink / raw)
  To: u-boot

On Thu, Feb 12, 2015 at 06:37:07PM +0100, Albert ARIBAUD (3ADEV) wrote:

> 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>

This adds a warning about CONFIG_CMD_DM being redefined for every file,
please fix.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20150216/00dca215/attachment.sig>

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

* [U-Boot] [U-Boot, v2, 8/8] lpc32xx: add support for board work_92105
  2015-02-17  1:08                 ` [U-Boot] [U-Boot, v2, " Tom Rini
@ 2015-02-17  7:06                   ` Albert ARIBAUD
  0 siblings, 0 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-17  7:06 UTC (permalink / raw)
  To: u-boot

Bonjour Tom,

Le Mon, 16 Feb 2015 20:08:29 -0500, Tom Rini <trini@ti.com> a ?crit :

> On Thu, Feb 12, 2015 at 06:37:07PM +0100, Albert ARIBAUD (3ADEV) wrote:
> 
> > 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>
> 
> This adds a warning about CONFIG_CMD_DM being redefined for every file,
> please fix.  Thanks!

Weird... I didn't hit this warning here. Will fix, of course.

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode)
  2015-02-12 17:37         ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
  2015-02-12 17:37           ` [U-Boot] [PATCH v2 6/8] dtt: add ds620 support Albert ARIBAUD
@ 2015-02-17  9:33           ` Jagan Teki
  2015-02-17  9:51             ` Albert ARIBAUD
  1 sibling, 1 reply; 32+ messages in thread
From: Jagan Teki @ 2015-02-17  9:33 UTC (permalink / raw)
  To: u-boot

On 12 February 2015 at 23:07, Albert ARIBAUD (3ADEV)
<albert.aribaud@3adev.fr> wrote:
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> ---
>
> Changes in v2:
> - added MUX setting for SSP0
>
>  arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |  14 +++
>  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, 151 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 a407098..5a453e3 100644
> --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> @@ -8,11 +8,13 @@
>  #include <asm/arch/cpu.h>
>  #include <asm/arch/clk.h>
>  #include <asm/arch/uart.h>
> +#include <asm/arch/mux.h>
>  #include <asm/io.h>
>  #include <dm.h>
>
>  static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
>  static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
> +static struct mux_regs *mux = (struct mux_regs *)MUX_BASE;
>
>  void lpc32xx_uart_init(unsigned int uart_id)
>  {
> @@ -66,3 +68,15 @@ void lpc32xx_i2c_init(unsigned int devnum)
>  U_BOOT_DEVICE(lpc32xx_gpios) = {
>         .name = "gpio_lpc32xx"
>  };
> +
> +/* Mux for SCK0, MISO0, MOSI0. We do not use SSEL0. */
> +
> +#define P_MUX_SET_SSP0 0x1600
> +
> +void lpc32xx_ssp_init(void)
> +{
> +       /* Enable SSP0 interface */
> +       writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl);
> +       /* Mux SSP0 pins */
> +       writel(P_MUX_SET_SSP0, &mux->p_mux_set);
> +}
> 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;

Pls- use static inline instead of direct macro assignment.

> +
> +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
> +};

This wouldn't require - spi_alloc_slave() is a generic func to do all the stuff.
See comments below...

> +
> +/* 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)
> +{

Define spi_cs_is_valid() that wikk ensure the controlling bus and cs
options command prompt

use spi_alloc_slave() and members will be having reg_base and slave that's.
See drivers/spi/zynq_spi.c for more info.

Suggested code:
static struct ssp0_spi_slave {
     struct spi_slave slave;
     struct ssp_regs *base;
};

static inline struct ssp0_regs *get_ssp0_spi_base(void)
{
           return (struct ssp0_regs *) SSP0_BASE;
}

in spi_setup_slave()

{
    struct ssp0_spi_slave *ssp0;

    /* valid bus and cs */

    /* allocate */
    ssp0 = spi_alloc_slave(struct ssp0_spi_slave, bus, cs);

    ssp0->base = get_ssp0_spi_base();

}

> +       /* 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
>

thanks!
-- 
Jagan.

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

* [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode)
  2015-02-17  9:33           ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Jagan Teki
@ 2015-02-17  9:51             ` Albert ARIBAUD
  2015-02-17 13:15               ` Jagan Teki
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-17  9:51 UTC (permalink / raw)
  To: u-boot

Bonjour Jagan,

Le Tue, 17 Feb 2015 15:03:16 +0530, Jagan Teki
<jagannadh.teki@gmail.com> a ?crit :

> On 12 February 2015 at 23:07, Albert ARIBAUD (3ADEV)
> <albert.aribaud@3adev.fr> wrote:
> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
> > ---
> >
> > Changes in v2:
> > - added MUX setting for SSP0
> >
> >  arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |  14 +++
> >  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, 151 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 a407098..5a453e3 100644
> > --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> > +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
> > @@ -8,11 +8,13 @@
> >  #include <asm/arch/cpu.h>
> >  #include <asm/arch/clk.h>
> >  #include <asm/arch/uart.h>
> > +#include <asm/arch/mux.h>
> >  #include <asm/io.h>
> >  #include <dm.h>
> >
> >  static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
> >  static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
> > +static struct mux_regs *mux = (struct mux_regs *)MUX_BASE;
> >
> >  void lpc32xx_uart_init(unsigned int uart_id)
> >  {
> > @@ -66,3 +68,15 @@ void lpc32xx_i2c_init(unsigned int devnum)
> >  U_BOOT_DEVICE(lpc32xx_gpios) = {
> >         .name = "gpio_lpc32xx"
> >  };
> > +
> > +/* Mux for SCK0, MISO0, MOSI0. We do not use SSEL0. */
> > +
> > +#define P_MUX_SET_SSP0 0x1600
> > +
> > +void lpc32xx_ssp_init(void)
> > +{
> > +       /* Enable SSP0 interface */
> > +       writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl);
> > +       /* Mux SSP0 pins */
> > +       writel(P_MUX_SET_SSP0, &mux->p_mux_set);
> > +}
> > 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;
> 
> Pls- use static inline instead of direct macro assignment.

Hmm... What's the benefit of going through a static inline function
when all that is performed is an assignment?

> > +
> > +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
> > +};
> 
> This wouldn't require - spi_alloc_slave() is a generic func to do all the stuff.
> See comments below...
> 
> > +
> > +/* 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)
> > +{
> 
> Define spi_cs_is_valid() that wikk ensure the controlling bus and cs
> options command prompt

Not sure I understand what you mean here.

> use spi_alloc_slave() and members will be having reg_base and slave that's.
> See drivers/spi/zynq_spi.c for more info.
> 
> Suggested code:
> static struct ssp0_spi_slave {
>      struct spi_slave slave;
>      struct ssp_regs *base;
> };
> 
> static inline struct ssp0_regs *get_ssp0_spi_base(void)
> {
>            return (struct ssp0_regs *) SSP0_BASE;
> }
> 
> in spi_setup_slave()
> 
> {
>     struct ssp0_spi_slave *ssp0;
> 
>     /* valid bus and cs */
> 
>     /* allocate */
>     ssp0 = spi_alloc_slave(struct ssp0_spi_slave, bus, cs);
> 
>     ssp0->base = get_ssp0_spi_base();
> 
> }

Ditto -- I don't see in what respect the code you suggest is supposed to
improve things. Can you please develop?

> > +       /* 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
> >
> 
> thanks!

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode)
  2015-02-17  9:51             ` Albert ARIBAUD
@ 2015-02-17 13:15               ` Jagan Teki
  0 siblings, 0 replies; 32+ messages in thread
From: Jagan Teki @ 2015-02-17 13:15 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 17 February 2015 at 15:21, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> Bonjour Jagan,
>
> Le Tue, 17 Feb 2015 15:03:16 +0530, Jagan Teki
> <jagannadh.teki@gmail.com> a ?crit :
>
>> On 12 February 2015 at 23:07, Albert ARIBAUD (3ADEV)
>> <albert.aribaud@3adev.fr> wrote:
>> > Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
>> > ---
>> >
>> > Changes in v2:
>> > - added MUX setting for SSP0
>> >
>> >  arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |  14 +++
>> >  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, 151 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 a407098..5a453e3 100644
>> > --- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
>> > +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
>> > @@ -8,11 +8,13 @@
>> >  #include <asm/arch/cpu.h>
>> >  #include <asm/arch/clk.h>
>> >  #include <asm/arch/uart.h>
>> > +#include <asm/arch/mux.h>
>> >  #include <asm/io.h>
>> >  #include <dm.h>
>> >
>> >  static struct clk_pm_regs    *clk  = (struct clk_pm_regs *)CLK_PM_BASE;
>> >  static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
>> > +static struct mux_regs *mux = (struct mux_regs *)MUX_BASE;
>> >
>> >  void lpc32xx_uart_init(unsigned int uart_id)
>> >  {
>> > @@ -66,3 +68,15 @@ void lpc32xx_i2c_init(unsigned int devnum)
>> >  U_BOOT_DEVICE(lpc32xx_gpios) = {
>> >         .name = "gpio_lpc32xx"
>> >  };
>> > +
>> > +/* Mux for SCK0, MISO0, MOSI0. We do not use SSEL0. */
>> > +
>> > +#define P_MUX_SET_SSP0 0x1600
>> > +
>> > +void lpc32xx_ssp_init(void)
>> > +{
>> > +       /* Enable SSP0 interface */
>> > +       writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl);
>> > +       /* Mux SSP0 pins */
>> > +       writel(P_MUX_SET_SSP0, &mux->p_mux_set);
>> > +}
>> > 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;
>>
>> Pls- use static inline instead of direct macro assignment.
>
> Hmm... What's the benefit of going through a static inline function
> when all that is performed is an assignment?

Sorry, it's my mistake i thought the driver handling more than one
controller base.
Your macro assignment is correct in that sense.

All I'm explained below is that changes in spi driver like how well it
uses the generic spi calls
and the format of the driver resembles same as others (reff. driver
drivers/spi/zynq_spi.c)

All (most) of the drivers will follow the same.

If you still confused, may be I will look at it but pls- understand.

>
>> > +
>> > +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
>> > +};
>>
>> This wouldn't require - spi_alloc_slave() is a generic func to do all the stuff.
>> See comments below...
>>
>> > +
>> > +/* 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)
>> > +{
>>
>> Define spi_cs_is_valid() that wikk ensure the controlling bus and cs
>> options command prompt
>
> Not sure I understand what you mean here.
>
>> use spi_alloc_slave() and members will be having reg_base and slave that's.
>> See drivers/spi/zynq_spi.c for more info.
>>
>> Suggested code:
>> static struct ssp0_spi_slave {
>>      struct spi_slave slave;
>>      struct ssp_regs *base;
>> };
>>
>> static inline struct ssp0_regs *get_ssp0_spi_base(void)
>> {
>>            return (struct ssp0_regs *) SSP0_BASE;
>> }
>>
>> in spi_setup_slave()
>>
>> {
>>     struct ssp0_spi_slave *ssp0;
>>
>>     /* valid bus and cs */
>>
>>     /* allocate */
>>     ssp0 = spi_alloc_slave(struct ssp0_spi_slave, bus, cs);
>>
>>     ssp0->base = get_ssp0_spi_base();
>>
>> }
>
> Ditto -- I don't see in what respect the code you suggest is supposed to
> improve things. Can you please develop?
>
>> > +       /* 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
>> >
>>
>> thanks!

thanks!
-- 
Jagan.

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-02-12 17:36 [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
  2015-02-12 17:37 ` [U-Boot] [PATCH v2 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
@ 2015-02-17 13:20 ` Tom Rini
  2015-02-17 13:26   ` Albert ARIBAUD
  1 sibling, 1 reply; 32+ messages in thread
From: Tom Rini @ 2015-02-17 13:20 UTC (permalink / raw)
  To: u-boot

On Thu, Feb 12, 2015 at 06:36:59PM +0100, Albert ARIBAUD (3ADEV) wrote:

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

Along with the work_92105 problem, just dropping that patch results in
devkit3250 failing in another way:
+(devkit3250) ../arch/arm/cpu/arm926ejs/lpc32xx/devices.c:11:26: fatal
error: asm/arch/mux.h: No such file or directory
+(devkit3250)  #include <asm/arch/mux.h>
+(devkit3250) compilation terminated.
+(devkit3250) make[3]: *** [arch/arm/cpu/arm926ejs/lpc32xx/devices.o]
Error 1
+(devkit3250) make[2]: *** [arch/arm/cpu/arm926ejs/lpc32xx] Error 2
+(devkit3250) make[1]: *** [arch/arm/cpu/arm926ejs] Error 2

Not that it should matter here but my default toolchain is ELDK 5.5.2

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20150217/29197acb/attachment.sig>

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-02-17 13:20 ` [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Tom Rini
@ 2015-02-17 13:26   ` Albert ARIBAUD
  2015-02-17 16:10     ` Tom Rini
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-02-17 13:26 UTC (permalink / raw)
  To: u-boot

Bonjour Tom,

Le Tue, 17 Feb 2015 08:20:09 -0500, Tom Rini <trini@ti.com> a ?crit :

> On Thu, Feb 12, 2015 at 06:36:59PM +0100, Albert ARIBAUD (3ADEV) wrote:
> 
> > This series extends functionality for the LPC32xx platform and
> > introduces the WORK Microwave work_92105 board which makes use
> > of the extended functionality.
> 
> Along with the work_92105 problem, just dropping that patch results in
> devkit3250 failing in another way:
> +(devkit3250) ../arch/arm/cpu/arm926ejs/lpc32xx/devices.c:11:26: fatal
> error: asm/arch/mux.h: No such file or directory
> +(devkit3250)  #include <asm/arch/mux.h>
> +(devkit3250) compilation terminated.
> +(devkit3250) make[3]: *** [arch/arm/cpu/arm926ejs/lpc32xx/devices.o]
> Error 1
> +(devkit3250) make[2]: *** [arch/arm/cpu/arm926ejs/lpc32xx] Error 2
> +(devkit3250) make[1]: *** [arch/arm/cpu/arm926ejs] Error 2
> 
> Not that it should matter here but my default toolchain is ELDK 5.5.2

I've just (re-)tried building devkit3250 and it builds fine (apart from
the warning that the board should be converted to generic).

What commit did you apply the patch series over?

[My toolchain is gcc version 4.7.4 (Ubuntu/Linaro 4.7.4-2ubuntu1) but I
agree with you that it most probably does not matter.]

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-02-17 13:26   ` Albert ARIBAUD
@ 2015-02-17 16:10     ` Tom Rini
  2015-03-30 12:07       ` Jagan Teki
  0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2015-02-17 16:10 UTC (permalink / raw)
  To: u-boot

On Tue, Feb 17, 2015 at 02:26:47PM +0100, Albert ARIBAUD wrote:
> Bonjour Tom,
> 
> Le Tue, 17 Feb 2015 08:20:09 -0500, Tom Rini <trini@ti.com> a ?crit :
> 
> > On Thu, Feb 12, 2015 at 06:36:59PM +0100, Albert ARIBAUD (3ADEV) wrote:
> > 
> > > This series extends functionality for the LPC32xx platform and
> > > introduces the WORK Microwave work_92105 board which makes use
> > > of the extended functionality.
> > 
> > Along with the work_92105 problem, just dropping that patch results in
> > devkit3250 failing in another way:
> > +(devkit3250) ../arch/arm/cpu/arm926ejs/lpc32xx/devices.c:11:26: fatal
> > error: asm/arch/mux.h: No such file or directory
> > +(devkit3250)  #include <asm/arch/mux.h>
> > +(devkit3250) compilation terminated.
> > +(devkit3250) make[3]: *** [arch/arm/cpu/arm926ejs/lpc32xx/devices.o]
> > Error 1
> > +(devkit3250) make[2]: *** [arch/arm/cpu/arm926ejs/lpc32xx] Error 2
> > +(devkit3250) make[1]: *** [arch/arm/cpu/arm926ejs] Error 2
> > 
> > Not that it should matter here but my default toolchain is ELDK 5.5.2
> 
> I've just (re-)tried building devkit3250 and it builds fine (apart from
> the warning that the board should be converted to generic).
> 
> What commit did you apply the patch series over?

There's a handful of things I'm merging shortly but that shouldn't
matter, so this is odd.  I see Jagan requested a few changes to the SPI
stuff so I'll pick up the series after that?  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20150217/3f35292d/attachment.sig>

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-02-17 16:10     ` Tom Rini
@ 2015-03-30 12:07       ` Jagan Teki
  2015-03-31  5:24         ` Albert ARIBAUD
  0 siblings, 1 reply; 32+ messages in thread
From: Jagan Teki @ 2015-03-30 12:07 UTC (permalink / raw)
  To: u-boot

Tom,

On 17 February 2015 at 21:40, Tom Rini <trini@ti.com> wrote:
> On Tue, Feb 17, 2015 at 02:26:47PM +0100, Albert ARIBAUD wrote:
>> Bonjour Tom,
>>
>> Le Tue, 17 Feb 2015 08:20:09 -0500, Tom Rini <trini@ti.com> a ?crit :
>>
>> > On Thu, Feb 12, 2015 at 06:36:59PM +0100, Albert ARIBAUD (3ADEV) wrote:
>> >
>> > > This series extends functionality for the LPC32xx platform and
>> > > introduces the WORK Microwave work_92105 board which makes use
>> > > of the extended functionality.
>> >
>> > Along with the work_92105 problem, just dropping that patch results in
>> > devkit3250 failing in another way:
>> > +(devkit3250) ../arch/arm/cpu/arm926ejs/lpc32xx/devices.c:11:26: fatal
>> > error: asm/arch/mux.h: No such file or directory
>> > +(devkit3250)  #include <asm/arch/mux.h>
>> > +(devkit3250) compilation terminated.
>> > +(devkit3250) make[3]: *** [arch/arm/cpu/arm926ejs/lpc32xx/devices.o]
>> > Error 1
>> > +(devkit3250) make[2]: *** [arch/arm/cpu/arm926ejs/lpc32xx] Error 2
>> > +(devkit3250) make[1]: *** [arch/arm/cpu/arm926ejs] Error 2
>> >
>> > Not that it should matter here but my default toolchain is ELDK 5.5.2
>>
>> I've just (re-)tried building devkit3250 and it builds fine (apart from
>> the warning that the board should be converted to generic).
>>
>> What commit did you apply the patch series over?
>
> There's a handful of things I'm merging shortly but that shouldn't
> matter, so this is odd.  I see Jagan requested a few changes to the SPI
> stuff so I'll pick up the series after that?  Thanks!

Updated my reviewed-by tag on v6 spi patch along with some typo, pick that
when you take the series.

thanks!
-- 
Jagan.

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-30 12:07       ` Jagan Teki
@ 2015-03-31  5:24         ` Albert ARIBAUD
  2015-03-31  7:00           ` Jagan Teki
  0 siblings, 1 reply; 32+ messages in thread
From: Albert ARIBAUD @ 2015-03-31  5:24 UTC (permalink / raw)
  To: u-boot

Bonjour Jagan,

Le Mon, 30 Mar 2015 17:37:47 +0530, Jagan Teki
<jagannadh.teki@gmail.com> a ?crit :

> Tom,
> 
> On 17 February 2015 at 21:40, Tom Rini <trini@ti.com> wrote:
> > On Tue, Feb 17, 2015 at 02:26:47PM +0100, Albert ARIBAUD wrote:
> >> Bonjour Tom,
> >>
> >> Le Tue, 17 Feb 2015 08:20:09 -0500, Tom Rini <trini@ti.com> a ?crit :
> >>
> >> > On Thu, Feb 12, 2015 at 06:36:59PM +0100, Albert ARIBAUD (3ADEV) wrote:
> >> >
> >> > > This series extends functionality for the LPC32xx platform and
> >> > > introduces the WORK Microwave work_92105 board which makes use
> >> > > of the extended functionality.
> >> >
> >> > Along with the work_92105 problem, just dropping that patch results in
> >> > devkit3250 failing in another way:
> >> > +(devkit3250) ../arch/arm/cpu/arm926ejs/lpc32xx/devices.c:11:26: fatal
> >> > error: asm/arch/mux.h: No such file or directory
> >> > +(devkit3250)  #include <asm/arch/mux.h>
> >> > +(devkit3250) compilation terminated.
> >> > +(devkit3250) make[3]: *** [arch/arm/cpu/arm926ejs/lpc32xx/devices.o]
> >> > Error 1
> >> > +(devkit3250) make[2]: *** [arch/arm/cpu/arm926ejs/lpc32xx] Error 2
> >> > +(devkit3250) make[1]: *** [arch/arm/cpu/arm926ejs] Error 2
> >> >
> >> > Not that it should matter here but my default toolchain is ELDK 5.5.2
> >>
> >> I've just (re-)tried building devkit3250 and it builds fine (apart from
> >> the warning that the board should be converted to generic).
> >>
> >> What commit did you apply the patch series over?
> >
> > There's a handful of things I'm merging shortly but that shouldn't
> > matter, so this is odd.  I see Jagan requested a few changes to the SPI
> > stuff so I'll pick up the series after that?  Thanks!
> 
> Updated my reviewed-by tag on v6 spi patch along with some typo, pick that
> when you take the series.

Actually there's a (normally final!) v7 coming in the next hours, but
there was no change on the SSP/SPI code. With your permission, I'll
'port over' your Reviewed-by from v6 5/8 to v7 5/9.

> thanks!

Thanks to you for reviewing.

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-31  5:24         ` Albert ARIBAUD
@ 2015-03-31  7:00           ` Jagan Teki
  2015-03-31  9:26             ` Albert ARIBAUD
  0 siblings, 1 reply; 32+ messages in thread
From: Jagan Teki @ 2015-03-31  7:00 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 10:54, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> Bonjour Jagan,
>
> Le Mon, 30 Mar 2015 17:37:47 +0530, Jagan Teki
> <jagannadh.teki@gmail.com> a ?crit :
>
>> Tom,
>>
>> On 17 February 2015 at 21:40, Tom Rini <trini@ti.com> wrote:
>> > On Tue, Feb 17, 2015 at 02:26:47PM +0100, Albert ARIBAUD wrote:
>> >> Bonjour Tom,
>> >>
>> >> Le Tue, 17 Feb 2015 08:20:09 -0500, Tom Rini <trini@ti.com> a ?crit :
>> >>
>> >> > On Thu, Feb 12, 2015 at 06:36:59PM +0100, Albert ARIBAUD (3ADEV) wrote:
>> >> >
>> >> > > This series extends functionality for the LPC32xx platform and
>> >> > > introduces the WORK Microwave work_92105 board which makes use
>> >> > > of the extended functionality.
>> >> >
>> >> > Along with the work_92105 problem, just dropping that patch results in
>> >> > devkit3250 failing in another way:
>> >> > +(devkit3250) ../arch/arm/cpu/arm926ejs/lpc32xx/devices.c:11:26: fatal
>> >> > error: asm/arch/mux.h: No such file or directory
>> >> > +(devkit3250)  #include <asm/arch/mux.h>
>> >> > +(devkit3250) compilation terminated.
>> >> > +(devkit3250) make[3]: *** [arch/arm/cpu/arm926ejs/lpc32xx/devices.o]
>> >> > Error 1
>> >> > +(devkit3250) make[2]: *** [arch/arm/cpu/arm926ejs/lpc32xx] Error 2
>> >> > +(devkit3250) make[1]: *** [arch/arm/cpu/arm926ejs] Error 2
>> >> >
>> >> > Not that it should matter here but my default toolchain is ELDK 5.5.2
>> >>
>> >> I've just (re-)tried building devkit3250 and it builds fine (apart from
>> >> the warning that the board should be converted to generic).
>> >>
>> >> What commit did you apply the patch series over?
>> >
>> > There's a handful of things I'm merging shortly but that shouldn't
>> > matter, so this is odd.  I see Jagan requested a few changes to the SPI
>> > stuff so I'll pick up the series after that?  Thanks!
>>
>> Updated my reviewed-by tag on v6 spi patch along with some typo, pick that
>> when you take the series.
>
> Actually there's a (normally final!) v7 coming in the next hours, but
> there was no change on the SSP/SPI code. With your permission, I'll
> 'port over' your Reviewed-by from v6 5/8 to v7 5/9.

Sure, please fix a typo which I pointed in v6

>
>> thanks!
>
> Thanks to you for reviewing.

thanks!
-- 
Jagan.

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

* [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-31  7:00           ` Jagan Teki
@ 2015-03-31  9:26             ` Albert ARIBAUD
  0 siblings, 0 replies; 32+ messages in thread
From: Albert ARIBAUD @ 2015-03-31  9:26 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

Le Tue, 31 Mar 2015 12:30:51 +0530, Jagan Teki
<jagannadh.teki@gmail.com> a ?crit :

> > Actually there's a (normally final!) v7 coming in the next hours, but
> > there was no change on the SSP/SPI code. With your permission, I'll
> > 'port over' your Reviewed-by from v6 5/8 to v7 5/9.
> 
> Sure, please fix a typo which I pointed in v6

Fixed, thanks.

Cordialement,
Albert ARIBAUD
3ADEV

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

end of thread, other threads:[~2015-03-31  9:26 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-12 17:36 [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
2015-02-12 17:37 ` [U-Boot] [PATCH v2 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
2015-02-12 17:37   ` [U-Boot] [PATCH v2 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
2015-02-12 17:37     ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
2015-02-12 17:37       ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Albert ARIBAUD
2015-02-12 17:37         ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
2015-02-12 17:37           ` [U-Boot] [PATCH v2 6/8] dtt: add ds620 support Albert ARIBAUD
2015-02-12 17:37             ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
2015-02-12 17:37               ` [U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
2015-02-13  9:36                 ` Stefan Roese
2015-02-13 11:08                   ` Albert ARIBAUD
2015-02-13 11:19                     ` Stefan Roese
2015-02-17  1:08                 ` [U-Boot] [U-Boot, v2, " Tom Rini
2015-02-17  7:06                   ` Albert ARIBAUD
2015-02-13  5:06               ` [U-Boot] [PATCH v2 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Simon Glass
2015-02-17  9:33           ` [U-Boot] [PATCH v2 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Jagan Teki
2015-02-17  9:51             ` Albert ARIBAUD
2015-02-17 13:15               ` Jagan Teki
2015-02-13  5:06         ` [U-Boot] [PATCH v2 4/8] lpc32xx: add GPIO support Simon Glass
2015-02-13  6:30           ` Albert ARIBAUD
2015-02-13 14:33             ` Simon Glass
2015-02-13 10:48       ` [U-Boot] [PATCH v2 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Heiko Schocher
2015-02-13 11:09         ` Albert ARIBAUD
2015-02-13 11:20           ` Heiko Schocher
2015-02-15 21:48             ` Simon Glass
2015-02-17 13:20 ` [U-Boot] [PATCH v2 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Tom Rini
2015-02-17 13:26   ` Albert ARIBAUD
2015-02-17 16:10     ` Tom Rini
2015-03-30 12:07       ` Jagan Teki
2015-03-31  5:24         ` Albert ARIBAUD
2015-03-31  7:00           ` Jagan Teki
2015-03-31  9:26             ` Albert ARIBAUD

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.