Skip to contentSkip to conversation

Extend LPC32xx functionality and add LPC32xx-based work_92015 board

PATCH Superseded Albert ARIBAUD (3ADEV) 3 participants 16 messages Mar 18, 2015 – Mar 30, 2015

Subsystems (11)

v6 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v6 cover Extend LPC32xx functionality and add LPC32xx-based work_92015 board

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 v6:
- added some missing readl() wraps
- moved descriptors and buffers to SRAM
- rewrite timeout loops
- fix bad block skipping in SPL chainload loop
- remove '+S:' prefixes from defconfig
- use custom LPC32XX linker script
- reset peripherals at startup
- support 128MB boards

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/cpu/arm926ejs/lpc32xx/u-boot.lds          | 161 +++++
 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       |  77 +++
 .../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                       |   6 +
 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                | 718 +++++++++++++++++++++
 drivers/net/Makefile                               |   1 +
 drivers/net/lpc32xx_eth.c                          | 639 ++++++++++++++++++
 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 +++++
 44 files changed, 3673 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/cpu/arm926ejs/lpc32xx/u-boot.lds
 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
Signature · 1 line
2.1.0
#1 lore raw

PATCH v6 1/8 lpc32xx: add Ethernet support

---

Changes in v6:
- added some missing readl() wraps
- moved descriptors and buffers to SRAM

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/cpu/arm926ejs/lpc32xx/u-boot.lds     | 161 +++++++
 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                     | 639 ++++++++++++++++++++++++++
 include/netdev.h                              |   1 +
 8 files changed, 822 insertions(+)
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/u-boot.lds
 create mode 100644 drivers/net/lpc32xx_eth.c
arch/arm/cpu/arm926ejs/lpc32xx/cpu.c +9 -0
index 35095a9..eec4d9e 100644
@@ -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
arch/arm/cpu/arm926ejs/lpc32xx/devices.c +7 -0
index b567657..062db8d 100644
@@ -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);
+}
arch/arm/cpu/arm926ejs/lpc32xx/u-boot.lds new file +161 -0

161 lines not on this page · raw message

arch/arm/include/asm/arch-lpc32xx/config.h +3 -0
index 564441c..d57bc48 100644
@@ -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
arch/arm/include/asm/arch-lpc32xx/sys_proto.h +1 -0
index 28812be..a6b8826 100644
@@ -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 */
drivers/net/Makefile +1 -0
index b8b0803..af8941f 100644
@@ -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
drivers/net/lpc32xx_eth.c new file +639 -0

639 lines not on this page · raw message

include/netdev.h +1 -0
index 90140bd..453c940 100644
@@ -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);
Signature · 1 line
2.1.0
#2 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

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.

---

Changes in v6:
- rewrite timeout loops
- fix bad block skipping in SPL chainload loop

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           | 718 ++++++++++++++++++++++++++
 5 files changed, 730 insertions(+)
 create mode 100644 drivers/mtd/nand/lpc32xx_nand_mlc.c
arch/arm/cpu/arm926ejs/lpc32xx/devices.c +6 -0
index 062db8d..be4c93d 100644
@@ -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);
+}
arch/arm/include/asm/arch-lpc32xx/clk.h +4 -0
index 92f6c15..bc7d33d 100644
@@ -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);
arch/arm/include/asm/arch-lpc32xx/sys_proto.h +1 -0
index a6b8826..0c4e712 100644
@@ -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 */
drivers/mtd/nand/Makefile +1 -0
index 1f02bfc..347ea62 100644
@@ -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
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +718 -0

718 lines not on this page · raw message

Signature · 1 line
2.1.0
#3 lore raw

PATCH v6 3/8 lpc32xx: i2c: add LPC32xx I2C interface support

---

Changes in v6: None
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
arch/arm/cpu/arm926ejs/lpc32xx/devices.c +11 -0
index be4c93d..81b53ea 100644
@@ -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);
+}
arch/arm/include/asm/arch-lpc32xx/clk.h +4 -0
index bc7d33d..781ac07 100644
@@ -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)
arch/arm/include/asm/arch-lpc32xx/cpu.h +2 -0
index 199b4a0..1067107 100644
@@ -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         */
arch/arm/include/asm/arch-lpc32xx/sys_proto.h +1 -0
index 0c4e712..a4a05d1 100644
@@ -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 */
drivers/i2c/Makefile +1 -0
index 774bc94..26ea854 100644
@@ -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
drivers/i2c/lpc32xx_i2c.c new file +249 -0

249 lines not on this page · raw message

Signature · 1 line
2.1.0
#4 lore raw

PATCH v6 4/8 lpc32xx: add GPIO support

This driver only supports Driver Model, not legacy model.

---

Changes in v6: None
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
arch/arm/cpu/arm926ejs/lpc32xx/devices.c +5 -0
index 81b53ea..a407098 100644
@@ -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"
+};
arch/arm/include/asm/arch-lpc32xx/gpio.h new file +43 -0

43 lines not on this page · raw message

drivers/gpio/Kconfig +7 -0
index b609e73..7b5178a 100644
@@ -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.
drivers/gpio/Makefile +1 -0
index fe9a3b2..85f71c5 100644
@@ -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
drivers/gpio/lpc32xx_gpio.c new file +293 -0

293 lines not on this page · raw message

Signature · 1 line
2.1.0
#5 lore raw

PATCH v6 5/8 lpc32xx: add LPC32xx SSP support (SPI mode)

---

Changes in v6: None
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
arch/arm/cpu/arm926ejs/lpc32xx/devices.c +14 -0
index a407098..5a453e3 100644
@@ -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);
+}
arch/arm/include/asm/arch-lpc32xx/clk.h +3 -0
index 781ac07..2cb5703 100644
@@ -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);
arch/arm/include/asm/arch-lpc32xx/sys_proto.h +1 -0
index a4a05d1..86d5ee9 100644
@@ -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 */
drivers/spi/Makefile +1 -0
index edbd520..ce6f1cc 100644
@@ -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
drivers/spi/lpc32xx_ssp.c new file +144 -0

144 lines not on this page · raw message

Signature · 1 line
2.1.0
#6 lore raw

PATCH v6 6/8 dtt: add ds620 support

---

Changes in v6: None
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
drivers/hwmon/Makefile +1 -0
index 25b8e8a..b4fb057 100644
@@ -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
drivers/hwmon/ds620.c new file +65 -0

65 lines not on this page · raw message

include/dtt.h +8 -7
index 058bca4..173159d 100644
@@ -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 */
 
Signature · 1 line
2.1.0
#7 lore raw

PATCH v6 7/8 lpc32xx: add lpc32xx-spl.bin boot image target

---

Changes in v6: None
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
common/image.c +1 -0
index a911aa9..162b682 100644
@@ -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,		    "",		  "",			},
 };
 
include/image.h +1 -0
index 0e6af00..3844be6 100644
@@ -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
tools/Makefile +1 -0
index 88770b0..4bbb153 100644
@@ -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 \
tools/lpc32xximage.c new file +178 -0

178 lines not on this page · raw message

Signature · 1 line
2.1.0
#8 lore raw

PATCH v6 8/8 lpc32xx: add support for board work_92105

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.

---

Changes in v6:
- remove '+S:' prefixes from defconfig
- use custom LPC32XX linker script
- reset peripherals at startup
- support 128MB boards

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       |  77 +++++
 .../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                       |   6 +
 include/configs/work_92105.h                       | 268 ++++++++++++++++
 21 files changed, 1086 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
Makefile +20 -0
index 1b3ebe7..98b3cd8 100644
@@ -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
arch/arm/Kconfig +6 -0
index b9ebee1..10d9280 100644
@@ -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"
arch/arm/cpu/arm926ejs/lpc32xx/Makefile +2 -0
index 314f004..4837377 100644
@@ -6,3 +6,5 @@
 #
 
 obj-y   = cpu.o clk.o devices.o timer.o
+
+obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o
arch/arm/cpu/arm926ejs/lpc32xx/clk.c +34 -0
index b7a44d5..1ef8a36 100644
@@ -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();
arch/arm/cpu/arm926ejs/lpc32xx/cpu.c +4 -0
index eec4d9e..f4d7f02 100644
@@ -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
arch/arm/cpu/arm926ejs/lpc32xx/dram.c new file +79 -0

79 lines not on this page · raw message

arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S new file +45 -0

45 lines not on this page · raw message

arch/arm/include/asm/arch-lpc32xx/clk.h +5 -0
index 2cb5703..9449869 100644
@@ -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 */
arch/arm/include/asm/arch-lpc32xx/cpu.h +1 -0
index 1067107..0b5dca1 100644
@@ -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            */
arch/arm/include/asm/arch-lpc32xx/mux.h new file +18 -0
new file mode 100644
index 0000000..dc1b5bc
@@ -0,0 +1,18 @@
+/*
+ * LPC32xx MUX interface
+ *
+ * (C) Copyright 2015  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <[email protected]>
+ *
+ * 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;
+};
arch/arm/include/asm/arch-lpc32xx/sys_proto.h +3 -1
index 86d5ee9..edcc4bc 100644
@@ -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 */
board/work-microwave/work_92105/Kconfig new file +15 -0
new file mode 100644
index 0000000..74f004f
@@ -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
board/work-microwave/work_92105/MAINTAINERS new file +6 -0
new file mode 100644
index 0000000..29a92c5
@@ -0,0 +1,6 @@
+WORK_92105 BOARD
+M:	Albert ARIBAUD <[email protected]>
+S:	Maintained
+F:	board/work-microwave/work_92105/
+F:	include/configs/work_92105.h
+F:	configs/work_92105_defconfig
board/work-microwave/work_92105/Makefile new file +10 -0
new file mode 100644
index 0000000..ba31c8e
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2014  DENX Software Engineering GmbH
+# Written-by: Albert ARIBAUD <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= work_92105.o work_92105_display.o
+
+obj-$(CONFIG_SPL_BUILD) += work_92105_spl.o
board/work-microwave/work_92105/README new file +91 -0

91 lines not on this page · raw message

board/work-microwave/work_92105/work_92105.c new file +77 -0

77 lines not on this page · raw message

board/work-microwave/work_92105/work_92105_display.c new file +349 -0

349 lines not on this page · raw message

board/work-microwave/work_92105/work_92105_display.h new file +14 -0
new file mode 100644
index 0000000..dd6e768
@@ -0,0 +1,14 @@
+/*
+ * work_92105 display support interface
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <[email protected]>
+ *
+ * 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);
board/work-microwave/work_92105/work_92105_spl.c new file +33 -0
new file mode 100644
index 0000000..c0d71b4
@@ -0,0 +1,33 @@
+/*
+ * WORK Microwave work_92105 board support
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <[email protected]>
+ *
+ * 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;
+}
configs/work_92105_defconfig new file +6 -0
new file mode 100644
index 0000000..307add2
@@ -0,0 +1,6 @@
+CONFIG_ARM=y
+CONFIG_TARGET_WORK_92105=y
+CONFIG_DM=y
+CONFIG_DM_GPIO=y
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="SYS_LDSCRIPT=arch/arm/cpu/arm926ejs/lpc32xx/u-boot.lds"
include/configs/work_92105.h new file +268 -0

268 lines not on this page · raw message

Signature · 1 line
2.1.0
#9 lore raw

PATCH v6 5/8 lpc32xx: add LPC32xx SSP support (SPI mode)

In reply to Albert ARIBAUD (3ADEV)
Quoted 126 lines · On 18 March 2015 at 14:34, Albert ARIBAUD (3ADEV) <[email protected]>…

---

Changes in v6: None
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
arch/arm/cpu/arm926ejs/lpc32xx/devices.c +14 -0
index a407098..5a453e3 100644
@@ -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);
+}
arch/arm/include/asm/arch-lpc32xx/clk.h +3 -0
index 781ac07..2cb5703 100644
@@ -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);
arch/arm/include/asm/arch-lpc32xx/sys_proto.h +1 -0
index a4a05d1..86d5ee9 100644
@@ -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 */
drivers/spi/Makefile +1 -0
index edbd520..ce6f1cc 100644
@@ -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
drivers/spi/lpc32xx_ssp.c new file +29 -0
new file mode 100644
index 0000000..0fc44a0
@@ -0,0 +1,144 @@
+/*
+ * LPC32xx SSP interface (SPI mode)
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <[email protected]>
+ *
+ * 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;
+};

drivers/spi/lpc32xx_ssp.c line 39

Quoted 10 lines
drivers/spi/lpc32xx_ssp.c new file +10 -0
+
+/* 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 */

Typo here.. zynq

Quoted 106 lines
drivers/spi/lpc32xx_ssp.c new file +105 -1
+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 */
+}
--
Quoted 1 line

2.1.0

thanks!

Signature · 1 line
Jagan.
#10 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

In reply to Albert ARIBAUD (3ADEV)

drivers/mtd/nand/lpc32xx_nand_mlc.c line 673

Quoted 3 lines · On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +3 -0
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	int block_good;

bool?

Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+	struct lpc32xx_oob oob;
+	unsigned int page, left;
+
+	/* if starting mid-block consider block good */

drivers/mtd/nand/lpc32xx_nand_mlc.c line 687

Quoted 10 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +10 -0
+	block_good = 1;
+
+	for (page = offs / BYTES_PER_PAGE,
+	     left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
+	     left && (page < PAGES_PER_CHIP_MAX); page++) {
+		/* read inband and oob page data anyway */
+		int res = read_single_page(dst, page, &oob);
+		/* return error if a good block's page was not readable */
+		if ((res < 0) && block_good)
+			return -1;

Why even try to read it if it's been marked bad?

drivers/mtd/nand/lpc32xx_nand_mlc.c line 688

Quoted 1 line
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +1 -0
+		/* if first page in a block, update 'block good' status */

The non-SPL driver appears to be checking the last two pages in the block, not the first page.

drivers/mtd/nand/lpc32xx_nand_mlc.c line 694

Quoted 6 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +6 -0
+		if ((page % PAGES_PER_BLOCK) == 0) {
+			/* assume block is good */
+			block_good = 1;
+			/* if page could not be read, assume block is bad */
+			if (res < 0)
+				block_good = 0;

No. A block is to be skipped if and only if it has a bad block marker. ECC errors should not be silently ignored just because they happen on the first page of a block. If the writer of this data didn't skip the block, then skipping it when reading will result in unusable data regardless of the underlying ECC problem.

-Scott

#11 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

Hi Scott,

Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 7 lines · On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:

drivers/mtd/nand/lpc32xx_nand_mlc.c line 673

Quoted 3 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +3 -0
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	int block_good;

bool?

Quoted 16 lines
Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+	struct lpc32xx_oob oob;
+	unsigned int page, left;
+
+	/* if starting mid-block consider block good */

drivers/mtd/nand/lpc32xx_nand_mlc.c line 687

Quoted 10 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +10 -0
+	block_good = 1;
+
+	for (page = offs / BYTES_PER_PAGE,
+	     left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
+	     left && (page < PAGES_PER_CHIP_MAX); page++) {
+		/* read inband and oob page data anyway */
+		int res = read_single_page(dst, page, &oob);
+		/* return error if a good block's page was not readable */
+		if ((res < 0) && block_good)
+			return -1;

Why even try to read it if it's been marked bad?

Actually, at this point, we may not know yet if the block is good or bad, since we might be reading a page of it for the first time. Will fix, see below.

Quoted 4 lines

drivers/mtd/nand/lpc32xx_nand_mlc.c line 688

Quoted 1 line
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +1 -0
+		/* if first page in a block, update 'block good' status */

The non-SPL driver appears to be checking the last two pages in the block, not the first page.

Thanks for pointing out this discrepancy.

I took the first page option here after checking the NAND's datasheet, which says that for factory bad block marking at least, while all pages in a bad block /should/ bear the bad block marker, only the first one is /guaranteed/ to have it. The driver might have inherited the 'last page' option from the previous NAND chip used, or from a mistake of my own.

BTW, is there a standard way to ask a NAND chip which page(s) in a bad block should be checked?

Quoted 4 lines
Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+		if ((page % PAGES_PER_BLOCK) == 0) {
+			/* assume block is good */
+			block_good = 1;
+			/* if page could not be read, assume block is bad */
Quoted 8 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+			if (res < 0)
+				block_good = 0;

No. A block is to be skipped if and only if it has a bad block marker. ECC errors should not be silently ignored just because they happen on the first page of a block. If the writer of this data didn't skip the block, then skipping it when reading will result in unusable data regardless of the underlying ECC problem.

You're correct of course.

However, I do want the SPL chainloading to be as resilient as possible, and we have established that it will have to read some part of a bad block -- possibly resulting in a read failure -- before knowing that the block is bad, which means it may have to finally ignore the read failure.

I guess I could wait to declare the block good or bad until I could read at least one if its pages (actually, one of its pages' OOB data) properly, only bail out if the OOB says the block is supposed to be good.

Now, if none of the block's pages could be read, this still prevents us from knowing whether these read failures are catastrophic. If the block was actually bad and skipped, then the resulting image might be intact, will pass the checksum test, and will run; if the block was actually good, SPL will detect it and not boot the corrupt image -- except if the completely unreadable good block was the first one, which holds the signature and checksum, in which case SPL will fall back to considering a raw, unsigned, unverifiable image, and will jump into corrupt code.

This may happen; but I think the probability of having a completely unreadable sector is very low, and the probability of this sector being the first one of the image is very low too [1].

Which leads me to two possible courses of action:

- consider the risk even though the probabilities are very low, thus consider any totally unreadable sector as good, and bail out in this case, or

- add an option to SPL that prevents common/spl/spl.c from falling back to running the image as raw if no signature is found, and consider any totally unreadable sector as bad and therefore ignore the read errors. Either the sector was actually good, and SPL will catch the image as corrupt or missing a signature, or the sector was actually bad, and the image will run as expected.

I personally prefer the second one, as it bring a valuable (I think) feature to U-Boot, for any board on which one wants to prevent an unverifiable image from running.

Quoted 1 line

-Scott

Cordialement,
Albert ARIBAUD
3ADEV

Signature · 3 lines
[1] Both together would require Douglas Adam's infinite improbability
generator while probably attracting its arch-nemesis, Murphy's Law.
I wouldn't like to be trapped between the two. :)
#12 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

Quoted 38 lines · Albert ARIBAUD

Hi Scott,

Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 7 lines · On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:

drivers/mtd/nand/lpc32xx_nand_mlc.c line 673

Quoted 3 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +3 -0
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	int block_good;

bool?

Quoted 16 lines
Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+	struct lpc32xx_oob oob;
+	unsigned int page, left;
+
+	/* if starting mid-block consider block good */

drivers/mtd/nand/lpc32xx_nand_mlc.c line 687

Quoted 10 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +10 -0
+	block_good = 1;
+
+	for (page = offs / BYTES_PER_PAGE,
+	     left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
+	     left && (page < PAGES_PER_CHIP_MAX); page++) {
+		/* read inband and oob page data anyway */
+		int res = read_single_page(dst, page, &oob);
+		/* return error if a good block's page was not readable */
+		if ((res < 0) && block_good)
+			return -1;

Why even try to read it if it's been marked bad?

Actually, at this point, we may not know yet if the block is good or bad, since we might be reading a page of it for the first time. Will fix, see below.

Quoted 4 lines

drivers/mtd/nand/lpc32xx_nand_mlc.c line 688

Quoted 1 line
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +1 -0
+		/* if first page in a block, update 'block good' status */

The non-SPL driver appears to be checking the last two pages in the block, not the first page.

Quoted 7 lines

Thanks for pointing out this discrepancy.

I took the first page option here after checking the NAND's datasheet, which says that for factory bad block marking at least, while all pages in a bad block /should/ bear the bad block marker, only the first one is /guaranteed/ to have it. The driver might have inherited the 'last page' option from the previous NAND chip used, or from a mistake of my own.

Are there any plans for this controller to be used with different chips?

Quoted 2 lines

BTW, is there a standard way to ask a NAND chip which page(s) in a bad block should be checked?

Yes and no:
http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html

Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+		if ((page % PAGES_PER_BLOCK) == 0) {
+			/* assume block is good */
+			block_good = 1;
+			/* if page could not be read, assume block is bad */
Quoted 8 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+			if (res < 0)
+				block_good = 0;

No. A block is to be skipped if and only if it has a bad block marker. ECC errors should not be silently ignored just because they happen on the first page of a block. If the writer of this data didn't skip the block, then skipping it when reading will result in unusable data regardless of the underlying ECC problem.

Quoted 7 lines

You're correct of course.

However, I do want the SPL chainloading to be as resilient as possible, and we have established that it will have to read some part of a bad block -- possibly resulting in a read failure -- before knowing that the block is bad, which means it may have to finally ignore the read failure.

FWIW, the eLBC/IFC SPL functions have the same problem regarding halting on an ECC error before checking the bad block status. Instead it should return an error code, and let the caller halt after it's sure it's not marked bad.

Quoted 20 lines

I guess I could wait to declare the block good or bad until I could read at least one if its pages (actually, one of its pages' OOB data) properly, only bail out if the OOB says the block is supposed to be good.

Now, if none of the block's pages could be read, this still prevents us from knowing whether these read failures are catastrophic.

If the block was actually bad and skipped, then the resulting image might be intact, will pass the checksum test, and will run; if the block was actually good, SPL will detect it and not boot the corrupt image -- except if the completely unreadable good block was the first one, which holds the signature and checksum, in which case SPL will fall back to considering a raw, unsigned, unverifiable image, and will jump into corrupt code.

This may happen; but I think the probability of having a completely unreadable sector is very low, and the probability of this sector being the first one of the image is very low too [1].

Quoted 5 lines

Which leads me to two possible courses of action:

- consider the risk even though the probabilities are very low, thus consider any totally unreadable sector as good, and bail out in this case, or

I was thinking instead to distinguish between a hard failure where you got no data from the NAND (e.g. a timeout), versus an ECC failure. In the later case you can still look in the OOB for a bad block marker.

Quoted 6 lines

- add an option to SPL that prevents common/spl/spl.c from falling back to running the image as raw if no signature is found, and consider any totally unreadable sector as bad and therefore ignore the read errors. Either the sector was actually good, and SPL will catch the image as corrupt or missing a signature, or the sector was actually bad, and the image will run as expected.

...but this seems reasonable as well (it wouldn't work for eLBC/IFC since they need to support tiny SPLs that can only handle raw images). If you want to do this, just put a comment in explaining why you're skipping in that situation.

-Scott

#13 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

Bonjour Scott,

Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 41 lines · Albert ARIBAUD
Quoted 40 lines

Hi Scott,

Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 7 lines · On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:

drivers/mtd/nand/lpc32xx_nand_mlc.c line 673

Quoted 3 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +3 -0
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	int block_good;

bool?

Quoted 16 lines
Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+	struct lpc32xx_oob oob;
+	unsigned int page, left;
+
+	/* if starting mid-block consider block good */

drivers/mtd/nand/lpc32xx_nand_mlc.c line 687

Quoted 10 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +10 -0
+	block_good = 1;
+
+	for (page = offs / BYTES_PER_PAGE,
+	     left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
+	     left && (page < PAGES_PER_CHIP_MAX); page++) {
+		/* read inband and oob page data anyway */
+		int res = read_single_page(dst, page, &oob);
+		/* return error if a good block's page was not readable */
+		if ((res < 0) && block_good)
+			return -1;

Why even try to read it if it's been marked bad?

Actually, at this point, we may not know yet if the block is good or bad, since we might be reading a page of it for the first time. Will fix, see below.

Quoted 4 lines

drivers/mtd/nand/lpc32xx_nand_mlc.c line 688

Quoted 1 line
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +1 -0
+		/* if first page in a block, update 'block good' status */

The non-SPL driver appears to be checking the last two pages in the block, not the first page.

Thanks for pointing out this discrepancy.

Quoted 7 lines
Quoted 5 lines

I took the first page option here after checking the NAND's datasheet, which says that for factory bad block marking at least, while all pages in a bad block /should/ bear the bad block marker, only the first one is /guaranteed/ to have it. The driver might have inherited the 'last page' option from the previous NAND chip used, or from a mistake of my own.

Are there any plans for this controller to be used with different chips?

Not that I know; but in the same vein, the current LPC32XX maintainer did not consider there were any plans for a few devices in it, and then came my patch series :) so I cannot rule out that someday a new LPC32XX board pops up in U-Boot with another NAND device.

Quoted 5 lines
Quoted 2 lines

BTW, is there a standard way to ask a NAND chip which page(s) in a bad block should be checked?

Yes and no:
http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html

... right.

How about this: the driver expects a driver-specific configuration option which tells it which page(s) in a block, and which byte in a page's OOB area, should be scanned for bad block markers, and "my" board provides a value for said option.

This way, when the driver is used with a new NAND chip in another board, it can be configured for this board's specific case.

Quoted 21 lines
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/mtd/nand/lpc32xx_nand_mlc.c new file +4 -0
+		if ((page % PAGES_PER_BLOCK) == 0) {
+			/* assume block is good */
+			block_good = 1;
+			/* if page could not be read, assume block is bad */
Quoted 8 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+			if (res < 0)
+				block_good = 0;

No. A block is to be skipped if and only if it has a bad block marker. ECC errors should not be silently ignored just because they happen on the first page of a block. If the writer of this data didn't skip the block, then skipping it when reading will result in unusable data regardless of the underlying ECC problem.

Quoted 7 lines

You're correct of course.

However, I do want the SPL chainloading to be as resilient as possible, and we have established that it will have to read some part of a bad block -- possibly resulting in a read failure -- before knowing that the block is bad, which means it may have to finally ignore the read failure.

Quoted 4 lines

FWIW, the eLBC/IFC SPL functions have the same problem regarding halting on an ECC error before checking the bad block status. Instead it should return an error code, and let the caller halt after it's sure it's not marked bad.

Maybe we could generalize an SPL chainloading common/spl/spl.c routine and have boards /SoCs only provide the hardware-specific page/OOB read function(s) ? Honestly, that would be way beyond my scope for this patch series.

Quoted 37 lines
Quoted 20 lines

I guess I could wait to declare the block good or bad until I could read at least one if its pages (actually, one of its pages' OOB data) properly, only bail out if the OOB says the block is supposed to be good.

Now, if none of the block's pages could be read, this still prevents us from knowing whether these read failures are catastrophic.

If the block was actually bad and skipped, then the resulting image might be intact, will pass the checksum test, and will run; if the block was actually good, SPL will detect it and not boot the corrupt image -- except if the completely unreadable good block was the first one, which holds the signature and checksum, in which case SPL will fall back to considering a raw, unsigned, unverifiable image, and will jump into corrupt code.

This may happen; but I think the probability of having a completely unreadable sector is very low, and the probability of this sector being the first one of the image is very low too [1].

Quoted 5 lines

Which leads me to two possible courses of action:

- consider the risk even though the probabilities are very low, thus consider any totally unreadable sector as good, and bail out in this case, or

I was thinking instead to distinguish between a hard failure where you got no data from the NAND (e.g. a timeout), versus an ECC failure. In the later case you can still look in the OOB for a bad block marker.

Quoted 6 lines

- add an option to SPL that prevents common/spl/spl.c from falling back to running the image as raw if no signature is found, and consider any totally unreadable sector as bad and therefore ignore the read errors. Either the sector was actually good, and SPL will catch the image as corrupt or missing a signature, or the sector was actually bad, and the image will run as expected.

Quoted 2 lines

...but this seems reasonable as well (it wouldn't work for eLBC/IFC since they need to support tiny SPLs that can only handle raw images).

This leads me to a half-OT question: so those SPL, while too tiny to handle non-raw images, still do include the whole common/spl/spl.c and thus contain code which will never apply to them? Then maybe we should have /two/ options, one enabling raw images, and one enabling 'non-raw' images (and at least one enabled for any SPL), so that each SPL could choose what code it wants in. Again, I am not offering to do that in this patch series.

Quoted 2 lines

If you want to do this, just put a comment in explaining why you're skipping in that situation.

Ok -- I will go with the 'option' method then, and add a (lengthy, I'm afraid) comment in common/spl/spl.c explaining that skipping the raw image handling is required when chainloading from NAND and the NAND driver considers totally unreadable sectors bad, in order not to confuse a missing image header with a raw image.

Quoted 1 line

-Scott

Thanks for the feedback!

Cordialement,
Albert ARIBAUD
3ADEV

#14 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

Quoted 12 lines · Albert ARIBAUD

Bonjour Scott,

Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 6 lines · Albert ARIBAUD
Quoted 2 lines

BTW, is there a standard way to ask a NAND chip which page(s) in a bad block should be checked?

Yes and no:
http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html

Quoted 6 lines

... right.

How about this: the driver expects a driver-specific configuration option which tells it which page(s) in a block, and which byte in a page's OOB area, should be scanned for bad block markers, and "my" board provides a value for said option.

It looks like the common NAND code will set NAND_BBT_SCANLASTPAGE/NAND_BBT_SCAN2NDPAGE automatically if it sees certain manufacturer IDs, so I don't think drivers should be setting them at all (and currently, none do).

That still leaves the question of what to do in SPL. For simplicity you could check every page as you do the normal read.

Quoted 2 lines

This leads me to a half-OT question: so those SPL, while too tiny to handle non-raw images, still do include the whole common/spl/spl.c

No, there's no room for that.

Quoted 8 lines
Quoted 2 lines

If you want to do this, just put a comment in explaining why you're skipping in that situation.

Ok -- I will go with the 'option' method then, and add a (lengthy, I'm afraid) comment in common/spl/spl.c explaining that skipping the raw image handling is required when chainloading from NAND and the NAND driver considers totally unreadable sectors bad, in order not to confuse a missing image header with a raw image.

Skipping raw wouldn't be needed for all NAND drivers, only those that aren't guaranteed to halt on a legitimate unrecoverable ECC error.

-Scott

#15 lore raw

PATCH v6 2/8 lpc32xx: mtd: nand: add MLC NAND controller

Hi Scott,

Le Mon, 23 Mar 2015 20:20:50 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 20 lines · Albert ARIBAUD
Quoted 12 lines

Bonjour Scott,

Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
<[email protected]> a ?crit :

Quoted 6 lines · Albert ARIBAUD
Quoted 2 lines

BTW, is there a standard way to ask a NAND chip which page(s) in a bad block should be checked?

Yes and no:
http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html

Quoted 6 lines

... right.

How about this: the driver expects a driver-specific configuration option which tells it which page(s) in a block, and which byte in a page's OOB area, should be scanned for bad block markers, and "my" board provides a value for said option.

Quoted 4 lines

It looks like the common NAND code will set NAND_BBT_SCANLASTPAGE/NAND_BBT_SCAN2NDPAGE automatically if it sees certain manufacturer IDs, so I don't think drivers should be setting them at all (and currently, none do).

Ok.

Quoted 2 lines

That still leaves the question of what to do in SPL. For simplicity you could check every page as you do the normal read.

Ok. Patch series v7 to follow... as soon as I have completed it.

Quoted 4 lines
Quoted 2 lines

This leads me to a half-OT question: so those SPL, while too tiny to handle non-raw images, still do include the whole common/spl/spl.c

No, there's no room for that.

Ok.

Quoted 11 lines
Quoted 8 lines
Quoted 2 lines

If you want to do this, just put a comment in explaining why you're skipping in that situation.

Ok -- I will go with the 'option' method then, and add a (lengthy, I'm afraid) comment in common/spl/spl.c explaining that skipping the raw image handling is required when chainloading from NAND and the NAND driver considers totally unreadable sectors bad, in order not to confuse a missing image header with a raw image.

Skipping raw wouldn't be needed for all NAND drivers, only those that aren't guaranteed to halt on a legitimate unrecoverable ECC error.

Understood.

Quoted 1 line

-Scott

Cordialement,
Albert ARIBAUD
3ADEV