[U-Boot] [PATCH v2 8/8] lpc32xx: add support for board work_92105

Stefan Roese sr at denx.de
Fri Feb 13 10:36:52 CET 2015


Hi Albert,

please find some review comments below.

On 12.02.2015 18:37, Albert ARIBAUD (3ADEV) wrote:
> Work_92105 from Work Microwave is an LPC3250-
> based board with the following features:
> - 64MB SDR DRAM
> - 1 GB SLC NAND, managed through MLC controller.
> - Ethernet
> - Ethernet + PHY SMSC8710
> - I2C:
>    - EEPROM (24M01-compatible)
>    - RTC (DS1374-compatible)
>    - Temperature sensor (DS620)
>    - DACs (2 x MAX518)
> - SPI (through SSP interface)
>    - Port expander MAX6957
> - LCD display (HD44780-compatible), controlled
>    through the port expander and DACs
>
> This board has SPL support, and uses the LPC32XX boot
> image format.
>
> Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud at 3adev.fr>
> ---
>
> Changes in v2: None
>
>   arch/arm/Kconfig                                   |   6 +
>   arch/arm/cpu/arm926ejs/lpc32xx/Makefile            |   2 +
>   arch/arm/cpu/arm926ejs/lpc32xx/clk.c               |  34 ++
>   arch/arm/cpu/arm926ejs/lpc32xx/cpu.c               |   4 +
>   arch/arm/cpu/arm926ejs/lpc32xx/dram.c              |  80 +++++
>   arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S     |  45 +++
>   arch/arm/include/asm/arch-lpc32xx/clk.h            |   5 +
>   arch/arm/include/asm/arch-lpc32xx/cpu.h            |   1 +
>   arch/arm/include/asm/arch-lpc32xx/mux.h            |  18 ++
>   arch/arm/include/asm/arch-lpc32xx/sys_proto.h      |   4 +-
>   board/work-microwave/work_92105/Kconfig            |  15 +
>   board/work-microwave/work_92105/MAINTAINERS        |   6 +
>   board/work-microwave/work_92105/Makefile           |   8 +
>   board/work-microwave/work_92105/README             |  23 ++
>   board/work-microwave/work_92105/work_92105.c       |  86 +++++
>   .../work-microwave/work_92105/work_92105_display.c | 349 +++++++++++++++++++++
>   .../work-microwave/work_92105/work_92105_display.h |  14 +
>   configs/work_92105_defconfig                       |   5 +
>   include/configs/work_92105.h                       | 259 +++++++++++++++
>   19 files changed, 963 insertions(+), 1 deletion(-)
>   create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/dram.c
>   create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
>   create mode 100644 arch/arm/include/asm/arch-lpc32xx/mux.h
>   create mode 100644 board/work-microwave/work_92105/Kconfig
>   create mode 100644 board/work-microwave/work_92105/MAINTAINERS
>   create mode 100644 board/work-microwave/work_92105/Makefile
>   create mode 100644 board/work-microwave/work_92105/README
>   create mode 100644 board/work-microwave/work_92105/work_92105.c
>   create mode 100644 board/work-microwave/work_92105/work_92105_display.c
>   create mode 100644 board/work-microwave/work_92105/work_92105_display.h
>   create mode 100644 configs/work_92105_defconfig
>   create mode 100644 include/configs/work_92105.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 47806f8..42983a3 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -247,6 +247,11 @@ config TARGET_DEVKIT3250
>   	bool "Support devkit3250"
>   	select CPU_ARM926EJS
>
> +config TARGET_WORK_92105
> +	bool "Support work_92105"
> +	select CPU_ARM926EJS
> +	select SUPPORT_SPL
> +
>   config TARGET_JADECPU
>   	bool "Support jadecpu"
>   	select CPU_ARM926EJS
> @@ -999,6 +1004,7 @@ source "board/udoo/Kconfig"
>   source "board/vpac270/Kconfig"
>   source "board/wandboard/Kconfig"
>   source "board/woodburn/Kconfig"
> +source "board/work-microwave/work_92105/Kconfig"
>   source "board/xaeniax/Kconfig"
>   source "board/zipitz2/Kconfig"
>
> diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
> index 314f004..4837377 100644
> --- a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
> @@ -6,3 +6,5 @@
>   #
>
>   obj-y   = cpu.o clk.o devices.o timer.o
> +
> +obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o
> diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
> index b7a44d5..1ef8a36 100644
> --- a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
> @@ -98,6 +98,40 @@ unsigned int get_periph_clk_rate(void)
>   	return get_hclk_pll_rate() / get_periph_clk_div();
>   }
>
> +unsigned int get_sdram_clk_rate(void)
> +{
> +	unsigned int src_clk;
> +
> +	if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
> +		return get_sys_clk_rate();
> +
> +	src_clk = get_hclk_pll_rate();
> +
> +	if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) {
> +		/* using DDR */
> +		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) {
> +		case CLK_HCLK_DDRAM_HALF:
> +			return src_clk/2;
> +		case CLK_HCLK_DDRAM_NOMINAL:
> +			return src_clk;
> +		default:
> +			return 0;
> +		}
> +	} else {
> +		/* using SDR */
> +		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) {
> +		case CLK_HCLK_ARM_PLL_DIV_4:
> +			return src_clk/4;
> +		case CLK_HCLK_ARM_PLL_DIV_2:
> +			return src_clk/2;
> +		case CLK_HCLK_ARM_PLL_DIV_1:
> +			return src_clk;
> +		default:
> +			return 0;
> +		}
> +	}
> +}
> +
>   int get_serial_clock(void)
>   {
>   	return get_periph_clk_rate();
> diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
> index eec4d9e..f4d7f02 100644
> --- a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
> @@ -9,6 +9,7 @@
>   #include <asm/arch/cpu.h>
>   #include <asm/arch/clk.h>
>   #include <asm/arch/wdt.h>
> +#include <asm/arch/sys_proto.h>
>   #include <asm/io.h>
>
>   static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
> @@ -33,6 +34,9 @@ void reset_cpu(ulong addr)
>   #if defined(CONFIG_ARCH_CPU_INIT)
>   int arch_cpu_init(void)
>   {
> +#if defined(CONFIG_SPL_BUILD)
> +	ddr_init();
> +#endif
>   	/*
>   	 * It might be necessary to flush data cache, if U-boot is loaded
>   	 * from kickstart bootloader, e.g. from S1L loader
> diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/dram.c b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
> new file mode 100644
> index 0000000..606f49d
> --- /dev/null
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
> @@ -0,0 +1,80 @@
> +/*
> + * LPC32xx dram init
> + *
> + * (C) Copyright 2014  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud at 3adev.fr>
> + *
> + * This is called by SPL to gain access to the SDR DRAM.
> + *
> + * This code runs from SRAM.
> + *
> + * Actual CONFIG_LPC32XX_SDRAM_* parameters must be provided
> + * by the board configuration file.
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <netdev.h>
> +#include <asm/arch/cpu.h>
> +#include <asm/arch/clk.h>
> +#include <asm/arch/wdt.h>
> +#include <asm/arch/emc.h>
> +#include <asm/io.h>
> +
> +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
> +static struct emc_regs *emc = (struct emc_regs *)EMC_BASE;
> +
> +#if defined(CONFIG_SPL_BUILD)

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

> +
> +void ddr_init(void)
> +{
> +	uint32_t ck;
> +
> +	/* Enable EMC interface and choose little endian mode */
> +	emc->ctrl = 1;
> +	emc->config = 0;
> +	/* Select maximum EMC Dynamic Memory Refresh Time */
> +	emc->refresh = 0x7FF;
> +	/* Determine CLK */
> +	ck = get_sdram_clk_rate();
> +	/* Configure SDRAM */
> +	clk->sdramclk_ctrl = (CONFIG_LPC32XX_SDRAM_COMMAND_DELAY << 14);
> +	emc->config0 = CONFIG_LPC32XX_SDRAM_CONFIG0;
> +	emc->rascas0 = CONFIG_LPC32XX_SDRAM_RASCAS0;
> +	emc->read_config = CONFIG_LPC32XX_SDRAM_READ_CONFIG;
> +	/* Set timings */
> +	emc->t_rp = (ck / CONFIG_LPC32XX_SDRAM_T_RP) & 0x0000000F;
> +	emc->t_ras = (ck / CONFIG_LPC32XX_SDRAM_T_RAS) & 0x0000000F;
> +	emc->t_srex = (ck / CONFIG_LPC32XX_SDRAM_T_SREX) & 0x0000007F;
> +	emc->t_wr = (ck / CONFIG_LPC32XX_SDRAM_T_WR) & 0x0000000F;
> +	emc->t_rc = (ck / CONFIG_LPC32XX_SDRAM_T_RC) & 0x0000001F;
> +	emc->t_rfc = (ck / CONFIG_LPC32XX_SDRAM_T_RFC) & 0x0000001F;
> +	emc->t_xsr = (ck / CONFIG_LPC32XX_SDRAM_T_XSR) & 0x000000FF;
> +	emc->t_rrd = CONFIG_LPC32XX_SDRAM_T_RRD;
> +	emc->t_mrd = CONFIG_LPC32XX_SDRAM_T_MRD;
> +	emc->t_cdlr = CONFIG_LPC32XX_SDRAM_T_CDLR;
> +	/* Dynamic refresh */
> +	emc->refresh = (((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF);
> +	udelay(10);
> +	/* Force all clocks, enable inverted ck, issue NOP command */
> +	emc->control = 0x00000193;
> +	udelay(100);
> +	/* Keep all clocks enabled, issue a PRECHARGE ALL command */
> +	emc->control = 0x00000113;
> +	/* Fast dynamic refresh for at least a few SDRAM ck cycles */
> +	emc->refresh = (((128) >> 4) & 0x7FF);
> +	udelay(10);
> +	/* set correct dynamic refresh timing */
> +	emc->refresh = (((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF);
> +	udelay(10);
> +	/* set normal mode to CAS=3 */
> +	emc->control = 0x00000093;
> +	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_MODE);
> +	/* set extended mode to all zeroes */
> +	emc->control = 0x00000093;
> +	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_EMODE);
> +	/* stop forcing clocks, keep inverted clock, issue normal mode */
> +	emc->control = 0x00000010;
> +}
> +#endif
> diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
> new file mode 100644
> index 0000000..4b8053e
> --- /dev/null
> +++ b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
> @@ -0,0 +1,45 @@
> +/*
> + * WORK Microwave work_92105 board low level init
> + *
> + * (C) Copyright 2014  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud at 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 at 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 at 3adev.fr>
> +S:	Maintained
> +F:	board/work-microwave/work_92105/
> +F:	include/configs/work_92105.h
> +F:	configs/work_92105_defconfig
> diff --git a/board/work-microwave/work_92105/Makefile b/board/work-microwave/work_92105/Makefile
> new file mode 100644
> index 0000000..853dea9
> --- /dev/null
> +++ b/board/work-microwave/work_92105/Makefile
> @@ -0,0 +1,8 @@
> +#
> +# (C) Copyright 2014  DENX Software Engineering GmbH
> +# Written-by: Albert ARIBAUD <albert.aribaud at 3adev.fr>
> +#
> +# SPDX-License-Identifier:	GPL-2.0+
> +#
> +
> +obj-y	:= work_92105.o work_92105_display.o
> diff --git a/board/work-microwave/work_92105/README b/board/work-microwave/work_92105/README
> new file mode 100644
> index 0000000..091d731
> --- /dev/null
> +++ b/board/work-microwave/work_92105/README
> @@ -0,0 +1,23 @@
> +Work_92105 from Work Microwave is an LPC3250- based board with the
> +following features:
> +
> +    - 64MB SDR DRAM
> +    - 1 GB SLC NAND, managed through MLC controller.
> +    - Ethernet
> +    - Ethernet + PHY SMSC8710
> +    - I2C:
> +      - EEPROM (24M01-compatible)
> +      - RTC (DS1374-compatible)
> +      - Temperature sensor (DS620)
> +      - DACs (2 x MAX518)
> +    - SPI (through SSP interface)
> +      - Port expander MAX6957
> +    - LCD display (HD44780-compatible), controlled
> +      through the port expander and DACs
> +
> +This board has SPL support, and uses the LPC32XX boot image format.
> +Once the U-Boot target "work_92105" is built, the following two files
> +can be flashed:
> +
> +	spl/lpc32xx-spl.bin at offset 0x0
> +	u-boot.bin at offset 0x40000

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

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

> diff --git a/board/work-microwave/work_92105/work_92105.c b/board/work-microwave/work_92105/work_92105.c
> new file mode 100644
> index 0000000..cad0d75
> --- /dev/null
> +++ b/board/work-microwave/work_92105/work_92105.c
> @@ -0,0 +1,86 @@
> +/*
> + * WORK Microwave work_92105 board support
> + *
> + * (C) Copyright 2014  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud at 3adev.fr>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/arch/sys_proto.h>
> +#include <asm/arch/cpu.h>
> +#include <asm/arch/emc.h>
> +#include <asm/gpio.h>
> +#include <spl.h>
> +#include "work_92105_display.h"
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#if defined(CONFIG_SPL_BUILD)

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

> +void spl_board_init(void)
> +{
> +	/* initialize serial port for console */
> +	lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART);
> +	/* initialize console */
> +	preloader_console_init();
> +	/* init DDR and NAND to chainload U-Boot */
> +	ddr_init();
> +	lpc32xx_mlc_nand_init();
> +}
> +
> +#else /* ! defined(CONFIG_SPL_BUILD) */
> +
> +int board_early_init_f(void)
> +{
> +	/* initialize serial port for console */
> +	lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART);
> +	/* enable I2C, SSP, MAC, NAND */
> +	lpc32xx_i2c_init(1); /* only I2C1 has devices, I2C2 has none */
> +	lpc32xx_ssp_init();
> +	lpc32xx_mac_init();
> +	lpc32xx_mlc_nand_init();
> +	/* Display must wait until after relocation and devices init */
> +	return 0;
> +}
> +
> +#define GPO_19 115
> +
> +int board_early_init_r(void)
> +{
> +	/* Set NAND !WP to 1 through GPO_19 */
> +	gpio_request(GPO_19, "NAND_nWP");
> +	gpio_direction_output(GPO_19, 1);
> +
> +	/* initialize display */
> +	work_92105_display_init();
> +
> +	return 0;
> +}
> +
> +#endif /* CONFIG_SPL_BUILD */
> +
> +int board_init(void)
> +{
> +	/* adress of boot parameters */
> +	gd->bd->bi_boot_params  = CONFIG_SYS_SDRAM_BASE + 0x100;
> +
> +	return 0;
> +}
> +
> +int dram_init(void)
> +{
> +	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
> +				    CONFIG_SYS_SDRAM_SIZE);
> +
> +	return 0;
> +}
> +
> +#if defined(CONFIG_SPL_BUILD)
> +u32 spl_boot_device(void)
> +{
> +	return BOOT_DEVICE_NAND;
> +}
> +#endif
> diff --git a/board/work-microwave/work_92105/work_92105_display.c b/board/work-microwave/work_92105/work_92105_display.c
> new file mode 100644
> index 0000000..c8b1013
> --- /dev/null
> +++ b/board/work-microwave/work_92105/work_92105_display.c
> @@ -0,0 +1,349 @@
> +/*
> + * work_92105 display support
> + *
> + * (C) Copyright 2014  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud at 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 at 3adev.fr>
> + *
> + * The work_92105 display is a HD44780-compatible module
> + * controlled through a MAX6957AAX SPI port expander, two
> + * MAX518 I2C DACs and native LPC32xx GPO 15.
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +void work_92105_display_init(void);
> diff --git a/configs/work_92105_defconfig b/configs/work_92105_defconfig
> new file mode 100644
> index 0000000..9be52a8
> --- /dev/null
> +++ b/configs/work_92105_defconfig
> @@ -0,0 +1,5 @@
> +CONFIG_DM=y
> +CONFIG_DM_GPIO=y
> +CONFIG_SPL=y
> ++S:CONFIG_ARM=y
> ++S:CONFIG_TARGET_WORK_92105=y
> diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h
> new file mode 100644
> index 0000000..fd242fb
> --- /dev/null
> +++ b/include/configs/work_92105.h
> @@ -0,0 +1,259 @@
> +/*
> + * WORK Microwave work_92105 board configuration file
> + *
> + * (C) Copyright 2014  DENX Software Engineering GmbH
> + * Written-by: Albert ARIBAUD <albert.aribaud at 3adev.fr>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef __CONFIG_WORK_92105_H__
> +#define __CONFIG_WORK_92105_H__
> +
> +/* SoC and board defines */
> +#include <linux/sizes.h>
> +#include <asm/arch/cpu.h>
> +
> +/*
> + * Define work_92105 machine type by hand -- done only for compatibility
> + * with original board code
> + */
> +#define MACH_TYPE_WORK_92105		736
> +#define CONFIG_MACH_TYPE		MACH_TYPE_WORK_92105
> +
> +#define CONFIG_SYS_ICACHE_OFF
> +#define CONFIG_SYS_DCACHE_OFF
> +#if !defined(CONFIG_SPL_BUILD)
> +#define CONFIG_SKIP_LOWLEVEL_INIT
> +#endif
> +#define CONFIG_BOARD_EARLY_INIT_F
> +#define CONFIG_BOARD_EARLY_INIT_R
> +
> +/* generate LPC32XX-specific SPL image */
> +#define CONFIG_LPC32XX_SPL
> +
> +/*
> + * Memory configurations
> + */
> +#define CONFIG_NR_DRAM_BANKS		1
> +#define CONFIG_SYS_MALLOC_LEN		SZ_1M
> +#define CONFIG_SYS_SDRAM_BASE		EMC_DYCS0_BASE
> +#define CONFIG_SYS_SDRAM_SIZE		SZ_64M
> +#define CONFIG_SYS_TEXT_BASE		0x80100000
> +#define CONFIG_SYS_MEMTEST_START	(CONFIG_SYS_SDRAM_BASE + SZ_32K)
> +#define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_TEXT_BASE - SZ_1M)
> +
> +#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_32K)
> +
> +#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_512K \
> +					 - GENERATED_GBL_DATA_SIZE)
> +
> +/*
> + * Serial Driver
> + */
> +#define CONFIG_SYS_LPC32XX_UART		5   /* UART5 - NS16550 */
> +#define CONFIG_BAUDRATE			115200
> +
> +/*
> + * Ethernet Driver
> + */
> +
> +#define CONFIG_PHY_SMSC
> +#define CONFIG_LPC32XX_ETH
> +#define CONFIG_PHYLIB
> +#define CONFIG_PHY_ADDR 0
> +#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN
> +#define CONFIG_CMD_MII
> +#define CONFIG_CMD_PING
> +#define CONFIG_CMD_DHCP
> +/* FIXME: remove "Waiting for PHY auto negotiation to complete..." message */
> +
> +/*
> + * I2C driver
> + */
> +
> +#define CONFIG_SYS_I2C_LPC32XX
> +#define CONFIG_SYS_I2C
> +#define CONFIG_CMD_I2C
> +#define CONFIG_SYS_I2C_SPEED 350000
> +
> +/*
> + * I2C EEPROM
> + */
> +
> +#define CONFIG_CMD_EEPROM
> +#define CONFIG_SYS_I2C_EEPROM_ADDR 0x56
> +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
> +
> +/*
> + * I2C RTC
> + */
> +
> +#define CONFIG_CMD_DATE
> +#define CONFIG_RTC_DS1374
> +
> +/*
> + * I2C Temperature Sensor (DTT)
> + */
> +
> +#define CONFIG_CMD_DTT
> +#define CONFIG_DTT_SENSORS { 0, 1 }
> +#define CONFIG_DTT_DS620
> +
> +/*
> + * U-Boot General Configurations
> + */
> +#define CONFIG_SYS_GENERIC_BOARD
> +#define CONFIG_SYS_LONGHELP
> +#define CONFIG_SYS_CBSIZE		1024
> +#define CONFIG_SYS_PBSIZE		\
> +	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
> +#define CONFIG_SYS_MAXARGS		16
> +#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
> +
> +#define CONFIG_SYS_HUSH_PARSER
> +
> +#define CONFIG_AUTO_COMPLETE
> +#define CONFIG_CMDLINE_EDITING
> +#define CONFIG_VERSION_VARIABLE
> +#define CONFIG_DISPLAY_CPUINFO
> +#define CONFIG_DOS_PARTITION
> +
> +#define CONFIG_CMD_DM
> +
> +/*
> + * No NOR
> + */
> +
> +#define CONFIG_SYS_NO_FLASH
> +
> +/*
> + * NAND chip timings for FIXME: which one?
> + */
> +
> +#define CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY  333333333
> +#define CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY   10000000
> +#define CONFIG_LPC32XX_NAND_MLC_NAND_TA      18181818
> +#define CONFIG_LPC32XX_NAND_MLC_RD_HIGH      31250000
> +#define CONFIG_LPC32XX_NAND_MLC_RD_LOW       45454545
> +#define CONFIG_LPC32XX_NAND_MLC_WR_HIGH      40000000
> +#define CONFIG_LPC32XX_NAND_MLC_WR_LOW       83333333
> +
> +/*
> + * NAND
> + */
> +
> +/* driver configuration */
> +#define CONFIG_SYS_MAX_NAND_DEVICE 1
> +#define CONFIG_SYS_NAND_BASE MLC_NAND_BASE
> +#define CONFIG_NAND_LPC32XX_MLC
> +
> +#define CONFIG_CMD_NAND
> +
> +/*
> + * GPIO
> + */
> +
> +#define CONFIG_CMD_GPIO
> +#define CONFIG_LPC32XX_GPIO
> +
> +/*
> + * SSP/SPI/DISPLAY
> + */
> +
> +#define CONFIG_CMD_SPI
> +#define CONFIG_LPC32XX_SSP
> +#define CONFIG_LPC32XX_SSP_TIMEOUT 100000
> +#define CONFIG_CMD_MAX6957
> +#define CONFIG_CMD_HD44760
> +/*
> + * Environment
> + */
> +
> +#define CONFIG_ENV_IS_IN_NAND		1
> +#define CONFIG_ENV_SIZE			0x00020000
> +#define CONFIG_ENV_OFFSET		0x00100000
> +#define CONFIG_ENV_OFFSET_REDUND	0x00120000
> +#define CONFIG_ENV_ADDR			0x80000100
> +/* provide default ethernet address */
> +#define CONFIG_ETHADDR			00:12:B4:00:AF:FE
> +#define	CONFIG_OVERWRITE_ETHADDR_ONCE

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

Thanks,
Stefan



More information about the U-Boot mailing list