All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
@ 2015-03-13  8:04 Albert ARIBAUD
  2015-03-13  8:04 ` [U-Boot] [PATCH v5 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
  2015-03-14  0:33 ` [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Simon Glass
  0 siblings, 2 replies; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 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:

A - I2C driver remains non-DM

During v2 review, it was suggested to move to DM for I2C. However,
this caused issues with the 'date', 'dtt' and 'eeprom' commands which
are configured in this board. Therefore the I2C move to DM was not
done.

B - Some checkpatch diagnostics are not fixed

The following warnings checkpatch warnings and checks were not fixed:

1. "warning: arch/arm/Kconfig,135: 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,187: 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 v5:
- switch to CONFIG_SYS_NAND_SELF_INIT
- switched board NAND config to CONFIG_SYS_NAND_SELF_INIT

Changes in v4:
- remove two debugging statements
- add __iomem to regs struct
- remove useless 'else return;'
- take BB marker out of free OOB area
- replace magic numbers in OOB reads/writes
- add timeouts in NAND loops
- use DIV_ROUND_UP where applicable
- fix erroneous comment
- skip bad blocks in SPL chainload loop

Changes in v3:
- move DM dependency constraint into Kconfig
- move regs pointer and function cache into private struct
- discourage readers from using functions implementation as an example
- move regs and functions in private struct
- remove script/Makefile.spl change
- use writel() in DRAM initialization code
- remove useless conditionals in dram.c
- fix and complete the board README
- remove redundant CONFIG_CMD_DM from config header file
- add a note re the hard-coded MAC address
- add 'single flashable file' make target

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

 Makefile                                           |  20 +
 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              |  79 +++
 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           |  10 +
 board/work-microwave/work_92105/README             |  91 +++
 board/work-microwave/work_92105/work_92105.c       |  62 ++
 .../work-microwave/work_92105/work_92105_display.c | 349 +++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 board/work-microwave/work_92105/work_92105_spl.c   |  33 +
 common/image.c                                     |   1 +
 configs/work_92105_defconfig                       |   5 +
 drivers/gpio/Kconfig                               |   7 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/lpc32xx_gpio.c                        | 293 +++++++++
 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                | 674 +++++++++++++++++++++
 drivers/net/Makefile                               |   1 +
 drivers/net/lpc32xx_eth.c                          | 636 +++++++++++++++++++
 drivers/spi/Makefile                               |   1 +
 drivers/spi/lpc32xx_ssp.c                          | 144 +++++
 include/configs/work_92105.h                       | 268 ++++++++
 include/dtt.h                                      |  15 +-
 include/image.h                                    |   1 +
 include/netdev.h                                   |   1 +
 tools/Makefile                                     |   1 +
 tools/lpc32xximage.c                               | 178 ++++++
 43 files changed, 3449 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 board/work-microwave/work_92105/work_92105_spl.c
 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] 25+ messages in thread

* [U-Boot] [PATCH v5 1/8] lpc32xx: add Ethernet support
  2015-03-13  8:04 [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
@ 2015-03-13  8:04 ` Albert ARIBAUD
  2015-03-13  8:04   ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
  2015-03-14  0:33 ` [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Simon Glass
  1 sibling, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 UTC (permalink / raw)
  To: u-boot

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

Changes in v5: None
Changes in v4: None
Changes in v3: None
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 564441c..d57bc48 100644
--- a/arch/arm/include/asm/arch-lpc32xx/config.h
+++ b/arch/arm/include/asm/arch-lpc32xx/config.h
@@ -52,6 +52,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 b8b0803..af8941f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_GRETH) += greth.o
 obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.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 90140bd..453c940 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -57,6 +57,7 @@ int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 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] 25+ messages in thread

* [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-03-13  8:04 ` [U-Boot] [PATCH v5 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
@ 2015-03-13  8:04   ` Albert ARIBAUD
  2015-03-13  8:04     ` [U-Boot] [PATCH v5 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
  2015-03-13 21:57     ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Scott Wood
  0 siblings, 2 replies; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 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 v5:
- switch to CONFIG_SYS_NAND_SELF_INIT

Changes in v4:
- remove two debugging statements
- add __iomem to regs struct
- remove useless 'else return;'
- take BB marker out of free OOB area
- replace magic numbers in OOB reads/writes
- add timeouts in NAND loops
- use DIV_ROUND_UP where applicable
- fix erroneous comment
- skip bad blocks in SPL chainload loop

Changes in v3: None
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           | 674 ++++++++++++++++++++++++++
 5 files changed, 686 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..6b376c4
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_nand_mlc.c
@@ -0,0 +1,674 @@
+/*
+ * 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
+
+/* time-out for NAND chip / controller loops */
+#define LPC32X_NAND_TIMEOUT 100000
+
+/*
+ * There is a single instance of the NAND MLC controller
+ */
+
+static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers
+	= (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE;
+
+#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o)
+
+/**
+ * OOB data in each small page are 6 'free' then 10 ECC bytes.
+ * To make things easier, when reading large pages, the four pages'
+ * 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer,
+ * while the the four ECC bytes are groupe in its last 40 bytes.
+ *
+ * The struct below represents how free vs ecc oob bytes are stored
+ * in the buffer.
+ *
+ * Note: the OOB bytes contain the bad block marker@offsets 0 and 1.
+ */
+
+struct lpc32xx_oob {
+	struct {
+		uint8_t free_oob_bytes[6];
+	} free[4];
+	struct {
+		uint8_t ecc_oob_bytes[10];
+	} ecc[4];
+};
+
+/*
+ * 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);
+}
+
+/**
+ * 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 = {
+		/* bytes 0 and 1 are used for the bad block marker */
+		{
+			.offset = 2,
+			.length = 22
+		},
+	}
+};
+
+/**
+ * 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, timeout, err, max_bitflips = 0;
+	struct lpc32xx_oob *oob = (struct lpc32xx_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 */
+		timeout = LPC32X_NAND_TIMEOUT;
+		do {
+			if (timeout-- == 0)
+				return -1;
+			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->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+		/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(&oob->ecc[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, timeout;
+	struct lpc32xx_oob *oob = (struct lpc32xx_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 */
+		timeout = LPC32X_NAND_TIMEOUT;
+		do {
+			if (timeout-- == 0)
+				return -1;
+			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->free[i], lpc32xx_nand_mlc_registers->data, 6);
+		/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(&oob->ecc[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, timeout, err, max_bitflips = 0;
+	struct lpc32xx_oob *oob = (struct lpc32xx_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 */
+		timeout = LPC32X_NAND_TIMEOUT;
+		do {
+			if (timeout-- == 0)
+				/* this amounts to 'fatal error' */
+				max_bitflips = 5;
+			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->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+		/* copy next 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(&oob->ecc[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, timeout;
+	struct lpc32xx_oob *oob = (struct lpc32xx_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->free[i], 6);
+		/* wait for ECC to return to ready state */
+		timeout = LPC32X_NAND_TIMEOUT;
+		while (!(readl(&lpc32xx_nand_mlc_registers->isr)
+			 & ISR_ECC_READY))
+			if (timeout-- == 0)
+				return -1;
+		/* 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 */
+		timeout = LPC32X_NAND_TIMEOUT;
+		while (!(readl(&lpc32xx_nand_mlc_registers->isr)
+			& ISR_CONTROLLER_READY))
+			if (timeout-- == 0)
+				return -1;
+	}
+	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;
+	struct lpc32xx_oob *oob = (struct lpc32xx_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->free[i], 6);
+		/* copy next 10 bytes into OOB buffer -- that is 'ECC' */
+		memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[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, timeout;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	for (i = 0; i < 4; i++) {
+		/* start data input */
+		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->free[i], 6);
+		/* program page */
+		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+		/* wait for NAND to return to ready state */
+		timeout = LPC32X_NAND_TIMEOUT;
+		while (!(readl(&lpc32xx_nand_mlc_registers->isr)
+			& ISR_NAND_READY))
+			if (timeout-- == 0)
+				return -1;
+	}
+	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)
+{
+	int status;
+	unsigned int timeout;
+	/* wait until both controller and NAND are ready */
+	timeout = LPC32X_NAND_TIMEOUT;
+	do {
+		if (timeout-- == 0)
+			return -1;
+		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);
+}
+
+/*
+ * We are self-initializing, so we need our own chip struct
+ */
+
+static struct nand_chip lpc32xx_chip;
+
+/*
+ * Initialize the controller
+ */
+
+void board_nand_init(void)
+{
+	/* we have only one device anyway */
+	struct mtd_info *mtd = &nand_info[0];
+	/* chip is struct nand_chip, and is now provided by the driver. */
+	mtd->priv = &lpc32xx_chip;
+	/* to store return status in case we need to print it */
+	int ret;
+
+	/* Set all BOARDSPECIFIC (actually core-specific) fields  */
+
+	lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff;
+	lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff;
+	lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl;
+	/* do not set init_size: nand_base.c will read sizes from chip */
+	lpc32xx_chip.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. */
+	lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE;
+
+	/* Set needed ECC fields */
+
+	lpc32xx_chip.ecc.mode = NAND_ECC_HW;
+	lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout;
+	lpc32xx_chip.ecc.size = 512;
+	lpc32xx_chip.ecc.bytes = 10;
+	lpc32xx_chip.ecc.strength = 4;
+	lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc;
+	lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw;
+	lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc;
+	lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw;
+	lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob;
+	lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob;
+	lpc32xx_chip.waitfunc = lpc32xx_waitfunc;
+
+	lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */
+
+	/* BBT options: read from last two pages */
+	lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK
+		| NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE
+		| NAND_BBT_WRITE;
+
+	/* Initialize NAND interface */
+	lpc32xx_nand_init();
+
+	/* identify chip */
+	ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL);
+	if (ret) {
+		error("nand_scan_ident returned %i", ret);
+		return;
+	}
+
+	/* finish scanning the chip */
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		error("nand_scan_tail returned %i", ret);
+		return;
+	}
+
+	/* chip is good, register it */
+	ret = nand_register(0);
+	if (ret)
+		error("nand_register returned %i", ret);
+}
+
+#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,
+	struct lpc32xx_oob *oob)
+{
+	int status, i, timeout, 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 */
+		timeout = LPC32X_NAND_TIMEOUT;
+		do {
+			if (timeout-- == 0)
+				return -1;
+			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);
+		/* copy next 6 bytes bytes into OOB buffer */
+		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+	}
+	return max_bitflips;
+}
+
+#define LARGE_PAGE_SIZE 2048
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	struct lpc32xx_oob oob;
+	unsigned int page = offs / LARGE_PAGE_SIZE;
+	unsigned int left = DIV_ROUND_UP(size, LARGE_PAGE_SIZE);
+
+	while (left) {
+		int res = read_single_page(dst, page, &oob);
+		page++;
+		/* if read succeeded, even if fixed by ECC */
+		if (res >= 0) {
+			/* skip bad block */
+			if (oob.free[0].free_oob_bytes[0] != 0xff)
+				continue;
+			if (oob.free[0].free_oob_bytes[1] != 0xff)
+				continue;
+			/* page is good, keep it */
+			dst += LARGE_PAGE_SIZE;
+			left--;
+		}
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
-- 
2.1.0

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

* [U-Boot] [PATCH v5 3/8] lpc32xx: i2c: add LPC32xx I2C interface support
  2015-03-13  8:04   ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
@ 2015-03-13  8:04     ` Albert ARIBAUD
  2015-03-13  8:04       ` [U-Boot] [PATCH v5 4/8] lpc32xx: add GPIO support Albert ARIBAUD
  2015-03-13 21:57     ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Scott Wood
  1 sibling, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 UTC (permalink / raw)
  To: u-boot

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

Changes in v5: None
Changes in v4: None
Changes in v3: None
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] 25+ messages in thread

* [U-Boot] [PATCH v5 4/8] lpc32xx: add GPIO support
  2015-03-13  8:04     ` [U-Boot] [PATCH v5 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
@ 2015-03-13  8:04       ` Albert ARIBAUD
  2015-03-13  8:04         ` [U-Boot] [PATCH v5 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 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 v5: None
Changes in v4: None
Changes in v3:
- move DM dependency constraint into Kconfig
- move regs pointer and function cache into private struct
- discourage readers from using functions implementation as an example

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/Kconfig                     |   7 +
 drivers/gpio/Makefile                    |   1 +
 drivers/gpio/lpc32xx_gpio.c              | 293 +++++++++++++++++++++++++++++++
 5 files changed, 349 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/Kconfig b/drivers/gpio/Kconfig
index b609e73..7b5178a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -7,3 +7,10 @@ config DM_GPIO
 	  the GPIO uclass. Drivers provide methods to query the
 	  particular GPIOs that they provide. The uclass interface
 	  is defined in include/asm-generic/gpio.h.
+
+config LPC32XX_GPIO
+	bool "LPC32XX GPIO driver"
+	depends on DM
+	default n
+	help
+	  Support for the LPC32XX GPIO driver.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fe9a3b2..85f71c5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -41,3 +41,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..96b3125
--- /dev/null
+++ b/drivers/gpio/lpc32xx_gpio.c
@@ -0,0 +1,293 @@
+/*
+ * LPC32xxGPIO driver
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm/io.h>
+#include <asm/arch-lpc32xx/cpu.h>
+#include <asm/arch-lpc32xx/gpio.h>
+#include <asm-generic/gpio.h>
+#include <dm.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 #1 **
+ *
+ * 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.
+ *
+ *	** WARNING #2 **
+ *
+ * Please read NOTE in description of lpc32xx_gpio_get_function().
+ */
+
+#define LPC32XX_GPIOS 128
+
+struct lpc32xx_gpio_platdata {
+	struct gpio_regs *regs;
+	/* GPIO FUNCTION: SEE WARNING #2 */
+	signed char function[LPC32XX_GPIOS];
+};
+
+/**
+ * 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))
+
+/**
+ * Configure a GPIO number 'offset' as input
+ */
+
+static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+	int port, mask;
+	struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+	struct gpio_regs *regs = gpio_platdata->regs;
+
+	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;
+	}
+
+	/* GPIO FUNCTION: SEE WARNING #2 */
+	gpio_platdata->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;
+	struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+	struct gpio_regs *regs = gpio_platdata->regs;
+
+	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(struct udevice *dev, unsigned gpio)
+{
+	int port, mask;
+	struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+	struct gpio_regs *regs = gpio_platdata->regs;
+
+	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(struct udevice *dev, unsigned gpio)
+{
+	int port, mask;
+	struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+	struct gpio_regs *regs = gpio_platdata->regs;
+
+	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(dev, offset);
+	else
+		return gpio_clr(dev, 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;
+	struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+	struct gpio_regs *regs = gpio_platdata->regs;
+
+	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;
+	}
+
+	/* GPIO FUNCTION: SEE WARNING #2 */
+	gpio_platdata->function[offset] = GPIOF_OUTPUT;
+
+	return lpc32xx_gpio_set_value(dev, offset, value);
+}
+
+/**
+ * GPIO functions are supposed to be computed from their current
+ * configuration, but that's way too complicated in LPC32XX. A simpler
+ * approach is used, where the GPIO functions are cached in an array.
+ * When the GPIO is in use, its function is either "input" or "output"
+ * depending on its direction, otherwise its function is "unknown".
+ *
+ *	** NOTE **
+ *
+ * THIS APPROACH WAS CHOSEN DU TO THE COMPLEX NATURE OF THE LPC32XX
+ * GPIOS; DO NOT TAKE THIS AS AN EXAMPLE FOR NEW CODE.
+ */
+
+static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+	struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
+	return gpio_platdata->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 lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(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;
+	}
+
+	/* set base address for GPIO registers */
+	gpio_platdata->regs = (struct gpio_regs *)GPIO_BASE;
+
+	/* all GPIO functions are unknown until requested */
+	/* GPIO FUNCTION: SEE WARNING #2 */
+	memset(gpio_platdata->function, GPIOF_UNKNOWN,
+	       sizeof(gpio_platdata->function));
+
+	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 = sizeof(struct lpc32xx_gpio_platdata),
+};
-- 
2.1.0

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

* [U-Boot] [PATCH v5 5/8] lpc32xx: add LPC32xx SSP support (SPI mode)
  2015-03-13  8:04       ` [U-Boot] [PATCH v5 4/8] lpc32xx: add GPIO support Albert ARIBAUD
@ 2015-03-13  8:04         ` Albert ARIBAUD
  2015-03-13  8:04           ` [U-Boot] [PATCH v5 6/8] dtt: add ds620 support Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 UTC (permalink / raw)
  To: u-boot

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

Changes in v5: None
Changes in v4: None
Changes in v3:
- move regs and functions in private struct

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                     | 144 ++++++++++++++++++++++++++
 5 files changed, 163 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..0fc44a0
--- /dev/null
+++ b/drivers/spi/lpc32xx_ssp.c
@@ -0,0 +1,144 @@
+/*
+ * 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
+
+/* zynq spi slave */
+struct lpc32xx_spi_slave {
+	struct spi_slave slave;
+	struct ssp_regs *regs;
+};
+
+static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave(
+	struct spi_slave *slave)
+{
+	return container_of(slave, struct lpc32xx_spi_slave, slave);
+}
+
+/* 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)
+{
+	struct lpc32xx_spi_slave *lslave;
+
+	/* 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;
+	}
+
+	lslave = spi_alloc_slave(struct lpc32xx_spi_slave, bus, cs);
+	if (!lslave) {
+		printf("SPI_error: Fail to allocate lpc32xx_spi_slave\n");
+		return NULL;
+	}
+
+	lslave->regs = (struct ssp_regs *)SSP0_BASE;
+
+	/*
+	 * 8 bit frame, SPI fmt, 500kbps -> clock divider is 26.
+	 * Set SCR to 0 and CPSDVSR to 26.
+	 */
+
+	writel(0x7, &lslave->regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */
+	writel(26, &lslave->regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */
+	writel(0, &lslave->regs->imsc); /* do not raise any interrupts */
+	writel(0, &lslave->regs->icr); /* clear any pending interrupt */
+	writel(0, &lslave->regs->dmacr); /* do not do DMAs */
+	writel(SSP_CR1_SSP_ENABLE, &lslave->regs->cr1); /* enable SSP0 */
+	return &lslave->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave);
+
+	debug("(lpc32xx) spi_free_slave: 0x%08x\n", (u32)lslave);
+	free(lslave);
+}
+
+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)
+{
+	struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave);
+	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(&lslave->regs->sr);
+		if ((idx_out < bytelen) && (status & SSP_SR_TNF))
+			writel(((u8 *)dout)[idx_out++], &lslave->regs->data);
+		if ((idx_in < bytelen) && (status & status & SSP_SR_RNE))
+			((u8 *)din)[idx_in++] = readl(&lslave->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 */
+}
-- 
2.1.0

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

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

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

Changes in v5: None
Changes in v4: None
Changes in v3: None
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] 25+ messages in thread

* [U-Boot] [PATCH v5 7/8] lpc32xx: add lpc32xx-spl.bin boot image target
  2015-03-13  8:04           ` [U-Boot] [PATCH v5 6/8] dtt: add ds620 support Albert ARIBAUD
@ 2015-03-13  8:04             ` Albert ARIBAUD
  2015-03-13  8:04               ` [U-Boot] [PATCH v5 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 UTC (permalink / raw)
  To: u-boot

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

Changes in v5: None
Changes in v4: None
Changes in v3:
- remove script/Makefile.spl change

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

 common/image.c       |   1 +
 include/image.h      |   1 +
 tools/Makefile       |   1 +
 tools/lpc32xximage.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 181 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/tools/Makefile b/tools/Makefile
index 88770b0..4bbb153 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] 25+ messages in thread

* [U-Boot] [PATCH v5 8/8] lpc32xx: add support for board work_92105
  2015-03-13  8:04             ` [U-Boot] [PATCH v5 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
@ 2015-03-13  8:04               ` Albert ARIBAUD
  0 siblings, 0 replies; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-13  8:04 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 v5:
- switched board NAND config to CONFIG_SYS_NAND_SELF_INIT

Changes in v4: None
Changes in v3:
- use writel() in DRAM initialization code
- remove useless conditionals in dram.c
- fix and complete the board README
- remove redundant CONFIG_CMD_DM from config header file
- add a note re the hard-coded MAC address
- add 'single flashable file' make target

Changes in v2: None

 Makefile                                           |  20 ++
 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              |  79 +++++
 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           |  10 +
 board/work-microwave/work_92105/README             |  91 ++++++
 board/work-microwave/work_92105/work_92105.c       |  62 ++++
 .../work-microwave/work_92105/work_92105_display.c | 349 +++++++++++++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 board/work-microwave/work_92105/work_92105_spl.c   |  33 ++
 configs/work_92105_defconfig                       |   5 +
 include/configs/work_92105.h                       | 268 ++++++++++++++++
 21 files changed, 1070 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 board/work-microwave/work_92105/work_92105_spl.c
 create mode 100644 configs/work_92105_defconfig
 create mode 100644 include/configs/work_92105.h

diff --git a/Makefile b/Makefile
index 9747bd2..6013712 100644
--- a/Makefile
+++ b/Makefile
@@ -896,6 +896,26 @@ OBJCOPYFLAGS_u-boot-with-spl.bin = -I binary -O binary \
 u-boot-with-spl.bin: spl/u-boot-spl.bin $(SPL_PAYLOAD) FORCE
 	$(call if_changed,pad_cat)
 
+MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE)
+
+lpc32xx-spl.img: spl/u-boot-spl.bin FORCE
+	$(call if_changed,mkimage)
+
+OBJCOPYFLAGS_lpc32xx-boot-0.bin = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO)
+
+lpc32xx-boot-0.bin: lpc32xx-spl.img
+	$(call if_changed,objcopy)
+
+OBJCOPYFLAGS_lpc32xx-boot-1.bin = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO)
+
+lpc32xx-boot-1.bin: lpc32xx-spl.img
+	$(call if_changed,objcopy)
+
+lpc32xx-full.bin: lpc32xx-boot-0.bin lpc32xx-boot-1.bin u-boot.img
+	$(call if_changed,cat)
+
+CLEAN_FILES += lpc32xx-*
+
 OBJCOPYFLAGS_u-boot-with-tpl.bin = -I binary -O binary \
 				   --pad-to=$(CONFIG_TPL_PAD_TO)
 tpl/u-boot-with-tpl.bin: tpl/u-boot-tpl.bin u-boot.bin FORCE
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b9ebee1..10d9280 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -132,6 +132,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_MX25PDK
 	bool "Support mx25pdk"
 	select CPU_ARM926EJS
@@ -871,6 +876,7 @@ source "board/vpac270/Kconfig"
 source "board/wandboard/Kconfig"
 source "board/warp/Kconfig"
 source "board/woodburn/Kconfig"
+source "board/work-microwave/work_92105/Kconfig"
 source "board/xaeniax/Kconfig"
 source "board/xilinx/zynqmp/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..c439233
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+void ddr_init(void)
+{
+	uint32_t ck;
+
+	/* Enable EMC interface and choose little endian mode */
+	writel(1, &emc->ctrl);
+	writel(0, &emc->config);
+	/* Select maximum EMC Dynamic Memory Refresh Time */
+	writel(0x7FF, &emc->refresh);
+	/* Determine CLK */
+	ck = get_sdram_clk_rate();
+	/* Configure SDRAM */
+	writel(CONFIG_LPC32XX_SDRAM_COMMAND_DELAY << 14, &clk->sdramclk_ctrl);
+	writel(CONFIG_LPC32XX_SDRAM_CONFIG0, &emc->config0);
+	writel(CONFIG_LPC32XX_SDRAM_RASCAS0, &emc->rascas0);
+	writel(CONFIG_LPC32XX_SDRAM_READ_CONFIG, &emc->read_config);
+	/* Set timings */
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_RP) & 0x0000000F, &emc->t_rp);
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_RAS) & 0x0000000F, &emc->t_ras);
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_SREX) & 0x0000007F, &emc->t_srex);
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_WR) & 0x0000000F, &emc->t_wr);
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_RC) & 0x0000001F, &emc->t_rc);
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_RFC) & 0x0000001F, &emc->t_rfc);
+	writel((ck / CONFIG_LPC32XX_SDRAM_T_XSR) & 0x000000FF, &emc->t_xsr);
+	writel(CONFIG_LPC32XX_SDRAM_T_RRD, &emc->t_rrd);
+	writel(CONFIG_LPC32XX_SDRAM_T_MRD, &emc->t_mrd);
+	writel(CONFIG_LPC32XX_SDRAM_T_CDLR, &emc->t_cdlr);
+	/* Dynamic refresh */
+	writel((((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF),
+	       &emc->refresh);
+	udelay(10);
+	/* Force all clocks, enable inverted ck, issue NOP command */
+	writel(0x00000193, &emc->control);
+	udelay(100);
+	/* Keep all clocks enabled, issue a PRECHARGE ALL command */
+	writel(0x00000113, &emc->control);
+	/* Fast dynamic refresh for at least a few SDRAM ck cycles */
+	writel((((128) >> 4) & 0x7FF), &emc->refresh);
+	udelay(10);
+	/* set correct dynamic refresh timing */
+	writel((((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF),
+	       &emc->refresh);
+	udelay(10);
+	/* set normal mode to CAS=3 */
+	writel(0x00000093, &emc->control);
+	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_MODE);
+	/* set extended mode to all zeroes */
+	writel(0x00000093, &emc->control);
+	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_EMODE);
+	/* stop forcing clocks, keep inverted clock, issue normal mode */
+	writel(0x00000010, &emc->control);
+}
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..ba31c8e
--- /dev/null
+++ b/board/work-microwave/work_92105/Makefile
@@ -0,0 +1,10 @@
+#
+# (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
+
+obj-$(CONFIG_SPL_BUILD) += work_92105_spl.o
diff --git a/board/work-microwave/work_92105/README b/board/work-microwave/work_92105/README
new file mode 100644
index 0000000..3c256e0
--- /dev/null
+++ b/board/work-microwave/work_92105/README
@@ -0,0 +1,91 @@
+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
+
+Standard SPL and U-Boot binaries
+--------------------------------
+
+The default 'make' (or the 'make all') command will produce the
+following files:
+
+1. spl/u-boot-spl.bin	SPL, intended to run from SRAM at address 0.
+			This file can be loaded in SRAM through a JTAG
+			debugger or through the LPC32XX Service Boot
+			mechanism.
+
+2. u-boot.bin		The raw U-Boot image, which can be loaded in
+			DDR through a JTAG debugger (for instance by
+			breaking SPL after DDR init), or by a running
+			U-Boot through e.g. 'loady' or 'tftp' and then
+			executed with 'go'.
+
+3. u-boot.img		A U-Boot image with a mkimage header prepended.
+			SPL assumes (even when loaded through JTAG or
+			Service Boot) that such an image will be found
+			at offset 0x00040000 in NAND.
+
+NAND cold-boot binaries
+-----------------------
+
+The board can boot entirely from power-on with only SPL and U-Boot in
+NAND. The LPC32XX-specific 'make lpc32xx-full.bin' command will produce
+(in addition to spl/u-boot-spl.bin and u-boot.img if they were not made
+already) the following files:
+
+4. lpc32xx-spl.img	spl/u-boot-spl.bin, with a LPC32XX boot header
+			prepended. This header is required for the ROM
+			code to load SPL into SRAM and branch into it.
+			The content of this file is expected to reside
+			in NAND at addresses 0x00000000 and 0x00020000
+			(two copies).
+
+5. lpc32xx-boot-0.bin	lpc32xx-spl.img, padded with 0xFF bytes to a
+			size of 0x20000 bytes. This file covers exactly
+			the reserved area for the first bootloader copy
+			in NAND.
+
+6. lpc32xx-boot-1.bin	Same as lpc32xx-boot-0.bin. This is intended to
+			be used as the second bootloader copy.
+
+7. lpc32xx-full.bin	lpc32xx-boot-0.bin, lpc32xx-boot-1.bin and
+			u-boot.img concatenated. This file represents
+			the content of whole bootloader as present in
+			NAND at offset 00x00000000.
+
+Flashing instructions
+---------------------
+
+The following assumes a working U-Boot on the target, with the ability
+to load files into DDR.
+
+To update the whole bootloader:
+
+	nand erase 0x00000000 0x80000
+	(load lpc32xx-full.bin at location $loadaddr)
+	nand write $loadaddr 0x00000000 $filesize
+
+To update SPL only (note the double nand write) :
+
+	nand erase 0x00000000 0x40000
+	(load lpc32xx-spl.img or lpc32xx-boot-N.bin at location $loadaddr)
+	nand write $loadaddr 0x00000000 $filesize
+	nand write $loadaddr 0x00020000 $filesize
+
+To update U-Boot only:
+
+	nand erase 0x00040000 0x40000
+	(load u-boot.img at location $loadaddr)
+	nand write $loadaddr 0x00040000 $filesize
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..e1b8056
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105.c
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+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;
+}
+
+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;
+}
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/board/work-microwave/work_92105/work_92105_spl.c b/board/work-microwave/work_92105/work_92105_spl.c
new file mode 100644
index 0000000..c0d71b4
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105_spl.c
@@ -0,0 +1,33 @@
+/*
+ * 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"
+
+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();
+}
+
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_NAND;
+}
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..2ce1f6d
--- /dev/null
+++ b/include/configs/work_92105.h
@@ -0,0 +1,268 @@
+/*
+ * 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
+
+/*
+ * 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_NAND_SELF_INIT
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_MAX_NAND_CHIPS 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
+ *
+ * THIS IS NORMALLY NOT DONE. HERE WE KEEP WHAT WAS IN THE PORTED
+ * BOARD CONFIG IN CASE SOME PROVISIONING PROCESS OUT THERE EXPECTS
+ * THIS MAC ADDRESS WHEN THE DEVICE HAS STILL ITS DEFAULT CONFIG.
+ */
+
+#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
+#define CONFIG_SPL_PAD_TO 0x20000
+/* 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] 25+ messages in thread

* [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-03-13  8:04   ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
  2015-03-13  8:04     ` [U-Boot] [PATCH v5 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
@ 2015-03-13 21:57     ` Scott Wood
  2015-03-14 14:27       ` Albert ARIBAUD
  1 sibling, 1 reply; 25+ messages in thread
From: Scott Wood @ 2015-03-13 21:57 UTC (permalink / raw)
  To: u-boot

On Fri, 2015-03-13 at 09:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> +	/* 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 */
> +		timeout = LPC32X_NAND_TIMEOUT;
> +		do {
> +			if (timeout-- == 0)
> +				return -1;
> +			status = readl(&lpc32xx_nand_mlc_registers->isr);
> +		} while (!(status & ISR_CONTROLLER_READY));

How much time does 10000 reads of this register equate to?  Are you sure
it's enough?  Timeouts should generally be in terms of time, not loop
iterations.

> +static int read_single_page(uint8_t *dest, int page,
> +	struct lpc32xx_oob *oob)
> +{
> +	int status, i, timeout, 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 */
> +		timeout = LPC32X_NAND_TIMEOUT;
> +		do {
> +			if (timeout-- == 0)
> +				return -1;
> +			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);
> +		/* copy next 6 bytes bytes into OOB buffer */
> +		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
> +	}
> +	return max_bitflips;
> +}
> +

Why keep track of max_bitflips if the caller doesn't use it?

> +#define LARGE_PAGE_SIZE 2048
> +
> +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> +{
> +	struct lpc32xx_oob oob;
> +	unsigned int page = offs / LARGE_PAGE_SIZE;
> +	unsigned int left = DIV_ROUND_UP(size, LARGE_PAGE_SIZE);
> +
> +	while (left) {
> +		int res = read_single_page(dst, page, &oob);
> +		page++;
> +		/* if read succeeded, even if fixed by ECC */
> +		if (res >= 0) {
> +			/* skip bad block */
> +			if (oob.free[0].free_oob_bytes[0] != 0xff)
> +				continue;
> +			if (oob.free[0].free_oob_bytes[1] != 0xff)
> +				continue;
> +			/* page is good, keep it */
> +			dst += LARGE_PAGE_SIZE;
> +			left--;
> +		}

You should be checking the designated page(s) of the block, rather than
the current page, for the bad block markers -- and skipping the entire
block if it's bad.

Also, if you fail ECC, that should be a fatal error, not something to
silently skip.

-Scott

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-13  8:04 [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
  2015-03-13  8:04 ` [U-Boot] [PATCH v5 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
@ 2015-03-14  0:33 ` Simon Glass
  2015-03-14 13:49   ` Albert ARIBAUD
  1 sibling, 1 reply; 25+ messages in thread
From: Simon Glass @ 2015-03-14  0:33 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 13 March 2015 at 02:04, Albert ARIBAUD (3ADEV)
<albert.aribaud@3adev.fr> wrote:
> This series extends functionality for the LPC32xx platform and
> introduces the WORK Microwave work_92105 board which makes use
> of the extended functionality.
>
> NOTES:
>
> A - I2C driver remains non-DM
>
> During v2 review, it was suggested to move to DM for I2C. However,
> this caused issues with the 'date', 'dtt' and 'eeprom' commands which
> are configured in this board. Therefore the I2C move to DM was not
> done.

Does CONFIG_DM_I2C_COMPAT help with this? If you define that you get
the old API.

Otherwise if you can share the (broken) patches I can take a look at
how to fix those commands.

Regards,
Simon

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-14  0:33 ` [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Simon Glass
@ 2015-03-14 13:49   ` Albert ARIBAUD
  2015-03-16 15:46     ` Simon Glass
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-14 13:49 UTC (permalink / raw)
  To: u-boot

Hi Simon,

Le Fri, 13 Mar 2015 18:33:51 -0600, Simon Glass <sjg@chromium.org> a
?crit :

> Hi Albert,
> 
> On 13 March 2015 at 02:04, Albert ARIBAUD (3ADEV)
> <albert.aribaud@3adev.fr> wrote:
> > This series extends functionality for the LPC32xx platform and
> > introduces the WORK Microwave work_92105 board which makes use
> > of the extended functionality.
> >
> > NOTES:
> >
> > A - I2C driver remains non-DM
> >
> > During v2 review, it was suggested to move to DM for I2C. However,
> > this caused issues with the 'date', 'dtt' and 'eeprom' commands which
> > are configured in this board. Therefore the I2C move to DM was not
> > done.
> 
> Does CONFIG_DM_I2C_COMPAT help with this? If you define that you get
> the old API.

Nope, I tried CONFIG_I2C_COMPAT as soon as I hit the errors, and itdid
not fix things.
 
> Otherwise if you can share the (broken) patches I can take a look at
> how to fix those commands.

I'll push a branch on Monday for this.

> Regards,
> Simon

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-03-13 21:57     ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Scott Wood
@ 2015-03-14 14:27       ` Albert ARIBAUD
  2015-03-16 21:30         ` Scott Wood
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-14 14:27 UTC (permalink / raw)
  To: u-boot

Bonjour Scott,

Le Fri, 13 Mar 2015 16:57:33 -0500, Scott Wood
<scottwood@freescale.com> a ?crit :

> On Fri, 2015-03-13 at 09:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> > +	/* 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 */
> > +		timeout = LPC32X_NAND_TIMEOUT;
> > +		do {
> > +			if (timeout-- == 0)
> > +				return -1;
> > +			status = readl(&lpc32xx_nand_mlc_registers->isr);
> > +		} while (!(status & ISR_CONTROLLER_READY));
> 
> How much time does 10000 reads of this register equate to?  Are you sure
> it's enough?  Timeouts should generally be in terms of time, not loop
> iterations.

I followed the examples in several drivers where timeouts are by
iteration. Note that  -- while this does not void your point --  I did
not use 10000 but 100000, which at a CPU clock of 208 MHz, and assuming
an optimistic one instruction per cycle and two instructions per loop,
makes the loop last at least 960 us, well over the 600 us which the
NAND takes for any page programming.

> > +static int read_single_page(uint8_t *dest, int page,
> > +	struct lpc32xx_oob *oob)
> > +{
> > +	int status, i, timeout, 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 */
> > +		timeout = LPC32X_NAND_TIMEOUT;
> > +		do {
> > +			if (timeout-- == 0)
> > +				return -1;
> > +			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);
> > +		/* copy next 6 bytes bytes into OOB buffer */
> > +		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
> > +	}
> > +	return max_bitflips;
> > +}
> > +
> 
> Why keep track of max_bitflips if the caller doesn't use it?

Because I modeled read_single_page from another read function, and I
preferred to minimize modifications and keep returning as much info
as I have, which can help debugging and cannot cause harm as it does
not affect the caller indeed.

> > +#define LARGE_PAGE_SIZE 2048
> > +
> > +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> > +{
> > +	struct lpc32xx_oob oob;
> > +	unsigned int page = offs / LARGE_PAGE_SIZE;
> > +	unsigned int left = DIV_ROUND_UP(size, LARGE_PAGE_SIZE);
> > +
> > +	while (left) {
> > +		int res = read_single_page(dst, page, &oob);
> > +		page++;
> > +		/* if read succeeded, even if fixed by ECC */
> > +		if (res >= 0) {
> > +			/* skip bad block */
> > +			if (oob.free[0].free_oob_bytes[0] != 0xff)
> > +				continue;
> > +			if (oob.free[0].free_oob_bytes[1] != 0xff)
> > +				continue;
> > +			/* page is good, keep it */
> > +			dst += LARGE_PAGE_SIZE;
> > +			left--;
> > +		}
> 
> You should be checking the designated page(s) of the block, rather than
> the current page, for the bad block markers -- and skipping the entire
> block if it's bad.

Will fix this -- is there any helper function in the bad block
management code for this? I could not find one, but I'm no NAND expert.

> Also, if you fail ECC, that should be a fatal error, not something to
> silently skip.

Will fix.

> -Scott

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-14 13:49   ` Albert ARIBAUD
@ 2015-03-16 15:46     ` Simon Glass
  2015-03-16 16:28       ` Anish Khurana
  0 siblings, 1 reply; 25+ messages in thread
From: Simon Glass @ 2015-03-16 15:46 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 14 March 2015 at 07:49, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>
> Hi Simon,
>
> Le Fri, 13 Mar 2015 18:33:51 -0600, Simon Glass <sjg@chromium.org> a
> ?crit :
>
> > Hi Albert,
> >
> > On 13 March 2015 at 02:04, Albert ARIBAUD (3ADEV)
> > <albert.aribaud@3adev.fr> wrote:
> > > This series extends functionality for the LPC32xx platform and
> > > introduces the WORK Microwave work_92105 board which makes use
> > > of the extended functionality.
> > >
> > > NOTES:
> > >
> > > A - I2C driver remains non-DM
> > >
> > > During v2 review, it was suggested to move to DM for I2C. However,
> > > this caused issues with the 'date', 'dtt' and 'eeprom' commands which
> > > are configured in this board. Therefore the I2C move to DM was not
> > > done.
> >
> > Does CONFIG_DM_I2C_COMPAT help with this? If you define that you get
> > the old API.
>
> Nope, I tried CONFIG_I2C_COMPAT as soon as I hit the errors, and itdid
> not fix things.

That's unfortunate. Perhaps there are some things missing.

>
>
> > Otherwise if you can share the (broken) patches I can take a look at
> > how to fix those commands.
>
> I'll push a branch on Monday for this.

Thanks, I'll take a look when I get it.

Regards,
Simon

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-16 15:46     ` Simon Glass
@ 2015-03-16 16:28       ` Anish Khurana
  2015-03-16 17:40         ` Simon Glass
  0 siblings, 1 reply; 25+ messages in thread
From: Anish Khurana @ 2015-03-16 16:28 UTC (permalink / raw)
  To: u-boot

Hi Simon,

can you please share the git branch so that I can also review it. I am
writing for LPC2148 board.

Thanks,
Anish



On Mon, Mar 16, 2015 at 9:16 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Albert,
>
> On 14 March 2015 at 07:49, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>>
>> Hi Simon,
>>
>> Le Fri, 13 Mar 2015 18:33:51 -0600, Simon Glass <sjg@chromium.org> a
>> ?crit :
>>
>> > Hi Albert,
>> >
>> > On 13 March 2015 at 02:04, Albert ARIBAUD (3ADEV)
>> > <albert.aribaud@3adev.fr> wrote:
>> > > This series extends functionality for the LPC32xx platform and
>> > > introduces the WORK Microwave work_92105 board which makes use
>> > > of the extended functionality.
>> > >
>> > > NOTES:
>> > >
>> > > A - I2C driver remains non-DM
>> > >
>> > > During v2 review, it was suggested to move to DM for I2C. However,
>> > > this caused issues with the 'date', 'dtt' and 'eeprom' commands which
>> > > are configured in this board. Therefore the I2C move to DM was not
>> > > done.
>> >
>> > Does CONFIG_DM_I2C_COMPAT help with this? If you define that you get
>> > the old API.
>>
>> Nope, I tried CONFIG_I2C_COMPAT as soon as I hit the errors, and itdid
>> not fix things.
>
> That's unfortunate. Perhaps there are some things missing.
>
>>
>>
>> > Otherwise if you can share the (broken) patches I can take a look at
>> > how to fix those commands.
>>
>> I'll push a branch on Monday for this.
>
> Thanks, I'll take a look when I get it.
>
> Regards,
> Simon
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-16 16:28       ` Anish Khurana
@ 2015-03-16 17:40         ` Simon Glass
  2015-03-16 20:28           ` Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Simon Glass @ 2015-03-16 17:40 UTC (permalink / raw)
  To: u-boot

Hi Anish,

On 16 March 2015 at 10:28, Anish Khurana <anish.khurana130181@gmail.com> wrote:
> Hi Simon,
>
> can you please share the git branch so that I can also review it. I am
> writing for LPC2148 board.

This is Albert's work. Once he shares if I am sure it will be public.

Regards,
Simon

>
> Thanks,
> Anish
>
>
>
> On Mon, Mar 16, 2015 at 9:16 PM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Albert,
>>
>> On 14 March 2015 at 07:49, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>>>
>>> Hi Simon,
>>>
>>> Le Fri, 13 Mar 2015 18:33:51 -0600, Simon Glass <sjg@chromium.org> a
>>> ?crit :
>>>
>>> > Hi Albert,
>>> >
>>> > On 13 March 2015 at 02:04, Albert ARIBAUD (3ADEV)
>>> > <albert.aribaud@3adev.fr> wrote:
>>> > > This series extends functionality for the LPC32xx platform and
>>> > > introduces the WORK Microwave work_92105 board which makes use
>>> > > of the extended functionality.
>>> > >
>>> > > NOTES:
>>> > >
>>> > > A - I2C driver remains non-DM
>>> > >
>>> > > During v2 review, it was suggested to move to DM for I2C. However,
>>> > > this caused issues with the 'date', 'dtt' and 'eeprom' commands which
>>> > > are configured in this board. Therefore the I2C move to DM was not
>>> > > done.
>>> >
>>> > Does CONFIG_DM_I2C_COMPAT help with this? If you define that you get
>>> > the old API.
>>>
>>> Nope, I tried CONFIG_I2C_COMPAT as soon as I hit the errors, and itdid
>>> not fix things.
>>
>> That's unfortunate. Perhaps there are some things missing.
>>
>>>
>>>
>>> > Otherwise if you can share the (broken) patches I can take a look at
>>> > how to fix those commands.
>>>
>>> I'll push a branch on Monday for this.
>>
>> Thanks, I'll take a look when I get it.
>>
>> Regards,
>> Simon
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-16 17:40         ` Simon Glass
@ 2015-03-16 20:28           ` Albert ARIBAUD
  2015-03-23 23:55             ` Simon Glass
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-16 20:28 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On Mon, 16 Mar 2015 11:40:54 -0600, Simon Glass <sjg@chromium.org>
wrote:
> Hi Anish,
> 
> On 16 March 2015 at 10:28, Anish Khurana <anish.khurana130181@gmail.com> wrote:
> > Hi Simon,
> >
> > can you please share the git branch so that I can also review it. I am
> > writing for LPC2148 board.
> 
> This is Albert's work. Once he shares if I am sure it will be public.

Since this is a derivative of the patch series I've posted here, I
could hardly see a problem in making it public anyway.

I've pushed the broken series, the one with I2C DM and COMPAT, as
branch dm-i2c of repo u-boot-arm. Anyone feel free to fiddle with
it.

> Regards,
> Simon

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-03-14 14:27       ` Albert ARIBAUD
@ 2015-03-16 21:30         ` Scott Wood
  2015-03-17  7:31           ` Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Scott Wood @ 2015-03-16 21:30 UTC (permalink / raw)
  To: u-boot

On Sat, 2015-03-14 at 15:27 +0100, Albert ARIBAUD wrote:
> Bonjour Scott,
> 
> Le Fri, 13 Mar 2015 16:57:33 -0500, Scott Wood
> <scottwood@freescale.com> a ?crit :
> 
> > On Fri, 2015-03-13 at 09:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> > > +	/* 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 */
> > > +		timeout = LPC32X_NAND_TIMEOUT;
> > > +		do {
> > > +			if (timeout-- == 0)
> > > +				return -1;
> > > +			status = readl(&lpc32xx_nand_mlc_registers->isr);
> > > +		} while (!(status & ISR_CONTROLLER_READY));
> > 
> > How much time does 10000 reads of this register equate to?  Are you sure
> > it's enough?  Timeouts should generally be in terms of time, not loop
> > iterations.
> 
> I followed the examples in several drivers where timeouts are by
> iteration. Note that  -- while this does not void your point --  I did
> not use 10000 but 100000, which at a CPU clock of 208 MHz, and assuming
> an optimistic one instruction per cycle and two instructions per loop,
> makes the loop last at least 960 us, well over the 600 us which the
> NAND takes for any page programming.

What if this driver ends up being used on hardware that runs
significantly faster than 208 MHz?  I could understand if it's hugely
space-constrained SPL code (like the ones that have to fit in 4K), but
otherwise why not make use of the timekeeping code that exists in U-Boot
(either by reading the timer, or by putting udelay(1) in the loop body)?

> > > +#define LARGE_PAGE_SIZE 2048
> > > +
> > > +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> > > +{
> > > +	struct lpc32xx_oob oob;
> > > +	unsigned int page = offs / LARGE_PAGE_SIZE;
> > > +	unsigned int left = DIV_ROUND_UP(size, LARGE_PAGE_SIZE);
> > > +
> > > +	while (left) {
> > > +		int res = read_single_page(dst, page, &oob);
> > > +		page++;
> > > +		/* if read succeeded, even if fixed by ECC */
> > > +		if (res >= 0) {
> > > +			/* skip bad block */
> > > +			if (oob.free[0].free_oob_bytes[0] != 0xff)
> > > +				continue;
> > > +			if (oob.free[0].free_oob_bytes[1] != 0xff)
> > > +				continue;
> > > +			/* page is good, keep it */
> > > +			dst += LARGE_PAGE_SIZE;
> > > +			left--;
> > > +		}
> > 
> > You should be checking the designated page(s) of the block, rather than
> > the current page, for the bad block markers -- and skipping the entire
> > block if it's bad.
> 
> Will fix this -- is there any helper function in the bad block
> management code for this? I could not find one, but I'm no NAND expert.

I don't know of any such helper -- outside of SPL it's handled via the
BBT.  fsl_ifc_spl.c is an example that checks for bad block markers, but
it's hardcoded to assume the first two pages of a block which is a bit
simpler than checking at the end of the block.

-Scott

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

* [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller
  2015-03-16 21:30         ` Scott Wood
@ 2015-03-17  7:31           ` Albert ARIBAUD
  0 siblings, 0 replies; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-17  7:31 UTC (permalink / raw)
  To: u-boot

Hi Scott,

Le Mon, 16 Mar 2015 16:30:29 -0500, Scott Wood
<scottwood@freescale.com> a ?crit :

> On Sat, 2015-03-14 at 15:27 +0100, Albert ARIBAUD wrote:
> > Bonjour Scott,
> > 
> > Le Fri, 13 Mar 2015 16:57:33 -0500, Scott Wood
> > <scottwood@freescale.com> a ?crit :
> > 
> > > On Fri, 2015-03-13 at 09:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> > > > +	/* 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 */
> > > > +		timeout = LPC32X_NAND_TIMEOUT;
> > > > +		do {
> > > > +			if (timeout-- == 0)
> > > > +				return -1;
> > > > +			status = readl(&lpc32xx_nand_mlc_registers->isr);
> > > > +		} while (!(status & ISR_CONTROLLER_READY));
> > > 
> > > How much time does 10000 reads of this register equate to?  Are you sure
> > > it's enough?  Timeouts should generally be in terms of time, not loop
> > > iterations.
> > 
> > I followed the examples in several drivers where timeouts are by
> > iteration. Note that  -- while this does not void your point --  I did
> > not use 10000 but 100000, which at a CPU clock of 208 MHz, and assuming
> > an optimistic one instruction per cycle and two instructions per loop,
> > makes the loop last at least 960 us, well over the 600 us which the
> > NAND takes for any page programming.
> 
> What if this driver ends up being used on hardware that runs
> significantly faster than 208 MHz?  I could understand if it's hugely
> space-constrained SPL code (like the ones that have to fit in 4K), but
> otherwise why not make use of the timekeeping code that exists in U-Boot
> (either by reading the timer, or by putting udelay(1) in the loop body)?

The udelay(1) in the loop is ok with me -- I'll put it in v6.

> > > > +#define LARGE_PAGE_SIZE 2048
> > > > +
> > > > +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> > > > +{
> > > > +	struct lpc32xx_oob oob;
> > > > +	unsigned int page = offs / LARGE_PAGE_SIZE;
> > > > +	unsigned int left = DIV_ROUND_UP(size, LARGE_PAGE_SIZE);
> > > > +
> > > > +	while (left) {
> > > > +		int res = read_single_page(dst, page, &oob);
> > > > +		page++;
> > > > +		/* if read succeeded, even if fixed by ECC */
> > > > +		if (res >= 0) {
> > > > +			/* skip bad block */
> > > > +			if (oob.free[0].free_oob_bytes[0] != 0xff)
> > > > +				continue;
> > > > +			if (oob.free[0].free_oob_bytes[1] != 0xff)
> > > > +				continue;
> > > > +			/* page is good, keep it */
> > > > +			dst += LARGE_PAGE_SIZE;
> > > > +			left--;
> > > > +		}
> > > 
> > > You should be checking the designated page(s) of the block, rather than
> > > the current page, for the bad block markers -- and skipping the entire
> > > block if it's bad.
> > 
> > Will fix this -- is there any helper function in the bad block
> > management code for this? I could not find one, but I'm no NAND expert.
> 
> I don't know of any such helper -- outside of SPL it's handled via the
> BBT.  fsl_ifc_spl.c is an example that checks for bad block markers, but
> it's hardcoded to assume the first two pages of a block which is a bit
> simpler than checking at the end of the block.

Thanks -- I'll dig into the BBT code to see how it's handled in my
target and put a fix in v6 based on that.

> -Scott

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-16 20:28           ` Albert ARIBAUD
@ 2015-03-23 23:55             ` Simon Glass
  2015-03-24  8:09               ` Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Simon Glass @ 2015-03-23 23:55 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 16 March 2015 at 14:28, Albert ARIBAUD <albert.u.boot@aribaud.net> wrote:
> Hello Simon,
>
> On Mon, 16 Mar 2015 11:40:54 -0600, Simon Glass <sjg@chromium.org>
> wrote:
>> Hi Anish,
>>
>> On 16 March 2015 at 10:28, Anish Khurana <anish.khurana130181@gmail.com> wrote:
>> > Hi Simon,
>> >
>> > can you please share the git branch so that I can also review it. I am
>> > writing for LPC2148 board.
>>
>> This is Albert's work. Once he shares if I am sure it will be public.
>
> Since this is a derivative of the patch series I've posted here, I
> could hardly see a problem in making it public anyway.
>
> I've pushed the broken series, the one with I2C DM and COMPAT, as
> branch dm-i2c of repo u-boot-arm. Anyone feel free to fiddle with
> it.

This does not build for me - e.g. lpc32xx_i2c_set_bus_speed() uses a
struct i2c_adaptor * when it should use struct udevice *.

Do I have the right version?

/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:64:4:
warning: ?struct i2c_adapter? declared inside parameter list [enabled
by default]
    unsigned int speed)
    ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:64:4:
warning: its scope is only this definition or declaration, which is
probably not what you want [enabled by default]
In file included from
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:13:0:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
In function ?lpc32xx_i2c_set_bus_speed?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:76:39:
error: dereferencing pointer to incomplete type
  writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi);
                                       ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/arch/arm/include/asm/io.h:77:55:
note: in definition of macro ?__arch_putl?
 #define __arch_putl(v,a)  (*(volatile unsigned int *)(a) = (v))
                                                       ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:76:2:
note: in expansion of macro ?writel?
  writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi);
  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:77:39:
error: dereferencing pointer to incomplete type
  writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo);
                                       ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/arch/arm/include/asm/io.h:146:48:
note: in expansion of macro ?__arch_putl?
 #define writel(v,c) ({ u32 __v = v; __iowmb(); __arch_putl(__v,c); __v; })
                                                ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:77:2:
note: in expansion of macro ?writel?
  writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo);
  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
At top level:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:82:37:
warning: ?struct i2c_adapter? declared inside parameter list [enabled
by default]
 static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev)
                                     ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
In function ?lpc32xx_i2c_probe?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:84:54:
error: dereferencing pointer to incomplete type
  struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
                                                      ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
In function ?lpc32xx_i2c_read_data?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:133:7:
error: ?data? undeclared (first use in this function)
     *(data++) = readl(&regs->rx);
       ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:133:7:
note: each undeclared identifier is reported only once for each
function it appears in
In file included from
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:13:0:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
In function ?lpc32xx_i2c_xfer?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:194:34:
error: ?i2c? undeclared (first use in this function)
  writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
                                  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/arch/arm/include/asm/io.h:77:55:
note: in definition of macro ?__arch_putl?
 #define __arch_putl(v,a)  (*(volatile unsigned int *)(a) = (v))
                                                       ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:194:2:
note: in expansion of macro ?writel?
  writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
In function ?lpc32xx_i2c_ofdata_to_platdata?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:223:9:
error: ?struct lpc32xx_i2c_bus? has no member named ?regs?
  i2c_bus->regs = (struct lpc32xx_i2c_registers *)
         ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:219:12:
warning: unused variable ?flags? [-Wunused-variable]
  int node, flags;
            ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:
At top level:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:231:2:
warning: initialization from incompatible pointer type [enabled by
default]
  .probe_chip = lpc32xx_i2c_probe,
  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:231:2:
warning: (near initialization for ?lpc32xx_i2c_ops.probe_chip?)
[enabled by default]
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:232:2:
warning: initialization from incompatible pointer type [enabled by
default]
  .set_bus_speed = lpc32xx_i2c_set_bus_speed,
  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:232:2:
warning: (near initialization for ?lpc32xx_i2c_ops.set_bus_speed?)
[enabled by default]
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/i2c/lpc32xx_i2c.c:236:45:
error: ?LPC32XX_I2C? undeclared here (not in a function)
  { .compatible = "nxp,lpc32xx-i2c", .data = LPC32XX_I2C },
                                             ^
make[2]: *** [drivers/i2c/lpc32xx_i2c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:
In function ?rtc_read?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:217:2:
warning: implicit declaration of function ?i2c_reg_read?
[-Wimplicit-function-declaration]
  return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
  ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:
In function ?rtc_write?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:224:3:
warning: implicit declaration of function ?i2c_reg_write?
[-Wimplicit-function-declaration]
   i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
   ^
make[1]: *** [drivers/i2c] Error 2
make[1]: *** Waiting for unfinished jobs....
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:
In function ?do_date?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:42:14:
error: ?CONFIG_SYS_RTC_BUS_NUM? undeclared (first use in this
function)
  I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM);
              ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:42:14:
note: each undeclared identifier is reported only once for each
function it appears in
make[2]: *** [common/cmd_date.o] Error 1
make[2]: *** Waiting for unfinished jobs....
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:
In function ?eeprom_read?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:155:16:
error: ?I2C_RXTX_LEN? undeclared (first use in this function)
   if (maxlen > I2C_RXTX_LEN)
                ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:155:16:
note: each undeclared identifier is reported only once for each
function it appears in
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:
In function ?eeprom_write?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:253:16:
error: ?I2C_RXTX_LEN? undeclared (first use in this function)
   if (maxlen > I2C_RXTX_LEN)
                ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:
In function ?dtt_init?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:41:14:
error: ?CONFIG_SYS_DTT_BUS_NUM? undeclared (first use in this
function)
  I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
              ^
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:41:14:
note: each undeclared identifier is reported only once for each
function it appears in
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:
In function ?dtt_i2c?:
/usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:65:14:
error: ?CONFIG_SYS_DTT_BUS_NUM? undeclared (first use in this
function)
  I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
              ^
make[2]: *** [common/cmd_eeprom.o] Error 1
make[2]: *** [common/cmd_dtt.o] Error 1
make[1]: *** [common] Error 2
make[1]: *** wait: No child processes.  Stop.


Regards,
Simon

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-23 23:55             ` Simon Glass
@ 2015-03-24  8:09               ` Albert ARIBAUD
  2015-04-08  3:20                 ` Simon Glass
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-03-24  8:09 UTC (permalink / raw)
  To: u-boot

Bonjour Simon,

Le Mon, 23 Mar 2015 17:55:56 -0600, Simon Glass <sjg@chromium.org> a
?crit :

> Hi Albert,
> 
> On 16 March 2015 at 14:28, Albert ARIBAUD <albert.u.boot@aribaud.net> wrote:
> > Hello Simon,
> >
> > On Mon, 16 Mar 2015 11:40:54 -0600, Simon Glass <sjg@chromium.org>
> > wrote:
> >> Hi Anish,
> >>
> >> On 16 March 2015 at 10:28, Anish Khurana <anish.khurana130181@gmail.com> wrote:
> >> > Hi Simon,
> >> >
> >> > can you please share the git branch so that I can also review it. I am
> >> > writing for LPC2148 board.
> >>
> >> This is Albert's work. Once he shares if I am sure it will be public.
> >
> > Since this is a derivative of the patch series I've posted here, I
> > could hardly see a problem in making it public anyway.
> >
> > I've pushed the broken series, the one with I2C DM and COMPAT, as
> > branch dm-i2c of repo u-boot-arm. Anyone feel free to fiddle with
> > it.
> 
> This does not build for me - e.g. lpc32xx_i2c_set_bus_speed() uses a
> struct i2c_adaptor * when it should use struct udevice *.
> 
> Do I have the right version?

Yes you have, but it most probably misses attempts I did at fixing
the LPC32XX driver, sorry.

Since the problem is not with this driver /per se/, try with removing
the lpc32xx driver from the build altogether; you should end up with
"only" these errors:

> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:
> In function ?rtc_read?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:217:2:
> warning: implicit declaration of function ?i2c_reg_read?
> [-Wimplicit-function-declaration]
>   return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
>   ^
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:
> In function ?rtc_write?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:224:3:
> warning: implicit declaration of function ?i2c_reg_write?
> [-Wimplicit-function-declaration]
>    i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
>    ^
> make[1]: *** [drivers/i2c] Error 2
> make[1]: *** Waiting for unfinished jobs....
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:
> In function ?do_date?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:42:14:
> error: ?CONFIG_SYS_RTC_BUS_NUM? undeclared (first use in this
> function)
>   I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM);
>               ^
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:42:14:
> note: each undeclared identifier is reported only once for each
> function it appears in
> make[2]: *** [common/cmd_date.o] Error 1
> make[2]: *** Waiting for unfinished jobs....
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:
> In function ?eeprom_read?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:155:16:
> error: ?I2C_RXTX_LEN? undeclared (first use in this function)
>    if (maxlen > I2C_RXTX_LEN)
>                 ^
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:155:16:
> note: each undeclared identifier is reported only once for each
> function it appears in
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:
> In function ?eeprom_write?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:253:16:
> error: ?I2C_RXTX_LEN? undeclared (first use in this function)
>    if (maxlen > I2C_RXTX_LEN)
>                 ^
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:
> In function ?dtt_init?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:41:14:
> error: ?CONFIG_SYS_DTT_BUS_NUM? undeclared (first use in this
> function)
>   I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
>               ^
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:41:14:
> note: each undeclared identifier is reported only once for each
> function it appears in
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:
> In function ?dtt_i2c?:
> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:65:14:
> error: ?CONFIG_SYS_DTT_BUS_NUM? undeclared (first use in this
> function)
>   I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
>               ^
> make[2]: *** [common/cmd_eeprom.o] Error 1
> make[2]: *** [common/cmd_dtt.o] Error 1
> make[1]: *** [common] Error 2
> make[1]: *** wait: No child processes.  Stop.

Of course the link stage will probably fail, but I guess once the
compiler stage works for ds1374, date, eeprom and dtt, the linking
should work.

> Regards,
> Simon

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-03-24  8:09               ` Albert ARIBAUD
@ 2015-04-08  3:20                 ` Simon Glass
  2015-04-08  6:12                   ` Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Simon Glass @ 2015-04-08  3:20 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 24 March 2015 at 02:09, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> Bonjour Simon,
>
> Le Mon, 23 Mar 2015 17:55:56 -0600, Simon Glass <sjg@chromium.org> a
> ?crit :
>
>> Hi Albert,
>>
>> On 16 March 2015 at 14:28, Albert ARIBAUD <albert.u.boot@aribaud.net> wrote:
>> > Hello Simon,
>> >
>> > On Mon, 16 Mar 2015 11:40:54 -0600, Simon Glass <sjg@chromium.org>
>> > wrote:
>> >> Hi Anish,
>> >>
>> >> On 16 March 2015 at 10:28, Anish Khurana <anish.khurana130181@gmail.com> wrote:
>> >> > Hi Simon,
>> >> >
>> >> > can you please share the git branch so that I can also review it. I am
>> >> > writing for LPC2148 board.
>> >>
>> >> This is Albert's work. Once he shares if I am sure it will be public.
>> >
>> > Since this is a derivative of the patch series I've posted here, I
>> > could hardly see a problem in making it public anyway.
>> >
>> > I've pushed the broken series, the one with I2C DM and COMPAT, as
>> > branch dm-i2c of repo u-boot-arm. Anyone feel free to fiddle with
>> > it.
>>
>> This does not build for me - e.g. lpc32xx_i2c_set_bus_speed() uses a
>> struct i2c_adaptor * when it should use struct udevice *.
>>
>> Do I have the right version?
>
> Yes you have, but it most probably misses attempts I did at fixing
> the LPC32XX driver, sorry.
>
> Since the problem is not with this driver /per se/, try with removing
> the lpc32xx driver from the build altogether; you should end up with
> "only" these errors:
>
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:
>> In function ?rtc_read?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:217:2:
>> warning: implicit declaration of function ?i2c_reg_read?
>> [-Wimplicit-function-declaration]
>>   return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
>>   ^
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:
>> In function ?rtc_write?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/drivers/rtc/ds1374.c:224:3:
>> warning: implicit declaration of function ?i2c_reg_write?
>> [-Wimplicit-function-declaration]
>>    i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
>>    ^
>> make[1]: *** [drivers/i2c] Error 2
>> make[1]: *** Waiting for unfinished jobs....
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:
>> In function ?do_date?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:42:14:
>> error: ?CONFIG_SYS_RTC_BUS_NUM? undeclared (first use in this
>> function)
>>   I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM);
>>               ^
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_date.c:42:14:
>> note: each undeclared identifier is reported only once for each
>> function it appears in
>> make[2]: *** [common/cmd_date.o] Error 1
>> make[2]: *** Waiting for unfinished jobs....
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:
>> In function ?eeprom_read?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:155:16:
>> error: ?I2C_RXTX_LEN? undeclared (first use in this function)
>>    if (maxlen > I2C_RXTX_LEN)
>>                 ^
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:155:16:
>> note: each undeclared identifier is reported only once for each
>> function it appears in
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:
>> In function ?eeprom_write?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_eeprom.c:253:16:
>> error: ?I2C_RXTX_LEN? undeclared (first use in this function)
>>    if (maxlen > I2C_RXTX_LEN)
>>                 ^
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:
>> In function ?dtt_init?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:41:14:
>> error: ?CONFIG_SYS_DTT_BUS_NUM? undeclared (first use in this
>> function)
>>   I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
>>               ^
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:41:14:
>> note: each undeclared identifier is reported only once for each
>> function it appears in
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:
>> In function ?dtt_i2c?:
>> /usr/local/google/c/cosarm/src/third_party/u-boot/files/common/cmd_dtt.c:65:14:
>> error: ?CONFIG_SYS_DTT_BUS_NUM? undeclared (first use in this
>> function)
>>   I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM);
>>               ^
>> make[2]: *** [common/cmd_eeprom.o] Error 1
>> make[2]: *** [common/cmd_dtt.o] Error 1
>> make[1]: *** [common] Error 2
>> make[1]: *** wait: No child processes.  Stop.
>
> Of course the link stage will probably fail, but I guess once the
> compiler stage works for ds1374, date, eeprom and dtt, the linking
> should work.

Well the problem is that we don't have driver model support in rtc, We
do have an eeprom uclass, but it is currently implemented only for
sandbox. We don't have a hwmon uclass (although there is thermal, and
I wonder if that is similar?

I'd be willing to create an rtc uclass and convert over ds1374 if you
are happy to test it?

Regards,
Simon

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-04-08  3:20                 ` Simon Glass
@ 2015-04-08  6:12                   ` Albert ARIBAUD
  2015-04-23 15:16                     ` Simon Glass
  0 siblings, 1 reply; 25+ messages in thread
From: Albert ARIBAUD @ 2015-04-08  6:12 UTC (permalink / raw)
  To: u-boot

Hi Simon,

Le Tue, 7 Apr 2015 21:20:22 -0600, Simon Glass <sjg@chromium.org> a
?crit :

> Well the problem is that we don't have driver model support in rtc, We
> do have an eeprom uclass, but it is currently implemented only for
> sandbox. We don't have a hwmon uclass (although there is thermal, and
> I wonder if that is similar?

No idea. :/

> I'd be willing to create an rtc uclass and convert over ds1374 if you
> are happy to test it?

I can test ds1374 right now, but that is not a hardware that I can keep.
I should be able to test eeprom on some other HW which I own.

> Regards,
> Simon

Cordialement,
Albert ARIBAUD
3ADEV

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-04-08  6:12                   ` Albert ARIBAUD
@ 2015-04-23 15:16                     ` Simon Glass
  2015-04-24  5:24                       ` Albert ARIBAUD
  0 siblings, 1 reply; 25+ messages in thread
From: Simon Glass @ 2015-04-23 15:16 UTC (permalink / raw)
  To: u-boot

Hi Albert,

On 8 April 2015 at 00:12, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> Hi Simon,
>
> Le Tue, 7 Apr 2015 21:20:22 -0600, Simon Glass <sjg@chromium.org> a
> ?crit :
>
>> Well the problem is that we don't have driver model support in rtc, We
>> do have an eeprom uclass, but it is currently implemented only for
>> sandbox. We don't have a hwmon uclass (although there is thermal, and
>> I wonder if that is similar?
>
> No idea. :/
>
>> I'd be willing to create an rtc uclass and convert over ds1374 if you
>> are happy to test it?
>
> I can test ds1374 right now, but that is not a hardware that I can keep.
> I should be able to test eeprom on some other HW which I own.

I posted an RTC conversion series. Are you still able to test ds1374?

Regards,
Simon

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

* [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board
  2015-04-23 15:16                     ` Simon Glass
@ 2015-04-24  5:24                       ` Albert ARIBAUD
  0 siblings, 0 replies; 25+ messages in thread
From: Albert ARIBAUD @ 2015-04-24  5:24 UTC (permalink / raw)
  To: u-boot

Hi Simon,

Le Thu, 23 Apr 2015 09:16:32 -0600, Simon Glass <sjg@chromium.org> a
?crit :

> Hi Albert,
> 
> On 8 April 2015 at 00:12, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> > Hi Simon,
> >
> > Le Tue, 7 Apr 2015 21:20:22 -0600, Simon Glass <sjg@chromium.org> a
> > ?crit :
> >
> >> Well the problem is that we don't have driver model support in rtc, We
> >> do have an eeprom uclass, but it is currently implemented only for
> >> sandbox. We don't have a hwmon uclass (although there is thermal, and
> >> I wonder if that is similar?
> >
> > No idea. :/
> >
> >> I'd be willing to create an rtc uclass and convert over ds1374 if you
> >> are happy to test it?
> >
> > I can test ds1374 right now, but that is not a hardware that I can keep.
> > I should be able to test eeprom on some other HW which I own.
> 
> I posted an RTC conversion series. Are you still able to test ds1374?

I should, but I only have a slight chance to do so today; otherwise,
not before sunday afternoon.

> Regards,
> Simon

Cordialement,
Albert ARIBAUD
3ADEV

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

end of thread, other threads:[~2015-04-24  5:24 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-13  8:04 [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Albert ARIBAUD
2015-03-13  8:04 ` [U-Boot] [PATCH v5 1/8] lpc32xx: add Ethernet support Albert ARIBAUD
2015-03-13  8:04   ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Albert ARIBAUD
2015-03-13  8:04     ` [U-Boot] [PATCH v5 3/8] lpc32xx: i2c: add LPC32xx I2C interface support Albert ARIBAUD
2015-03-13  8:04       ` [U-Boot] [PATCH v5 4/8] lpc32xx: add GPIO support Albert ARIBAUD
2015-03-13  8:04         ` [U-Boot] [PATCH v5 5/8] lpc32xx: add LPC32xx SSP support (SPI mode) Albert ARIBAUD
2015-03-13  8:04           ` [U-Boot] [PATCH v5 6/8] dtt: add ds620 support Albert ARIBAUD
2015-03-13  8:04             ` [U-Boot] [PATCH v5 7/8] lpc32xx: add lpc32xx-spl.bin boot image target Albert ARIBAUD
2015-03-13  8:04               ` [U-Boot] [PATCH v5 8/8] lpc32xx: add support for board work_92105 Albert ARIBAUD
2015-03-13 21:57     ` [U-Boot] [PATCH v5 2/8] lpc32xx: mtd: nand: add MLC NAND controller Scott Wood
2015-03-14 14:27       ` Albert ARIBAUD
2015-03-16 21:30         ` Scott Wood
2015-03-17  7:31           ` Albert ARIBAUD
2015-03-14  0:33 ` [U-Boot] [PATCH v5 0/8] Extend LPC32xx functionality and add LPC32xx-based work_92015 board Simon Glass
2015-03-14 13:49   ` Albert ARIBAUD
2015-03-16 15:46     ` Simon Glass
2015-03-16 16:28       ` Anish Khurana
2015-03-16 17:40         ` Simon Glass
2015-03-16 20:28           ` Albert ARIBAUD
2015-03-23 23:55             ` Simon Glass
2015-03-24  8:09               ` Albert ARIBAUD
2015-04-08  3:20                 ` Simon Glass
2015-04-08  6:12                   ` Albert ARIBAUD
2015-04-23 15:16                     ` Simon Glass
2015-04-24  5:24                       ` 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.