diff options
22 files changed, 1129 insertions, 1 deletions
@@ -909,6 +909,26 @@ OBJCOPYFLAGS_u-boot-with-spl.bin = -I binary -O binary \ u-boot-with-spl.bin: spl/u-boot-spl.bin $(SPL_PAYLOAD) FORCE $(call if_changed,pad_cat) +MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE) + +lpc32xx-spl.img: spl/u-boot-spl.bin FORCE + $(call if_changed,mkimage) + +OBJCOPYFLAGS_lpc32xx-boot-0.bin = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO) + +lpc32xx-boot-0.bin: lpc32xx-spl.img + $(call if_changed,objcopy) + +OBJCOPYFLAGS_lpc32xx-boot-1.bin = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO) + +lpc32xx-boot-1.bin: lpc32xx-spl.img + $(call if_changed,objcopy) + +lpc32xx-full.bin: lpc32xx-boot-0.bin lpc32xx-boot-1.bin u-boot.img + $(call if_changed,cat) + +CLEAN_FILES += lpc32xx-* + OBJCOPYFLAGS_u-boot-with-tpl.bin = -I binary -O binary \ --pad-to=$(CONFIG_TPL_PAD_TO) tpl/u-boot-with-tpl.bin: tpl/u-boot-tpl.bin u-boot.bin FORCE diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 80b0d34..086ca85 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -132,6 +132,11 @@ config TARGET_DEVKIT3250 bool "Support devkit3250" select CPU_ARM926EJS +config TARGET_WORK_92105 + bool "Support work_92105" + select CPU_ARM926EJS + select SUPPORT_SPL + config TARGET_MX25PDK bool "Support mx25pdk" select CPU_ARM926EJS @@ -872,6 +877,7 @@ source "board/vpac270/Kconfig" source "board/wandboard/Kconfig" source "board/warp/Kconfig" source "board/woodburn/Kconfig" +source "board/work-microwave/work_92105/Kconfig" source "board/xaeniax/Kconfig" source "board/xilinx/zynqmp/Kconfig" source "board/zipitz2/Kconfig" diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile index 314f004..4837377 100644 --- a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile +++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile @@ -6,3 +6,5 @@ # obj-y = cpu.o clk.o devices.o timer.o + +obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c index b7a44d5..1ef8a36 100644 --- a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c +++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c @@ -98,6 +98,40 @@ unsigned int get_periph_clk_rate(void) return get_hclk_pll_rate() / get_periph_clk_div(); } +unsigned int get_sdram_clk_rate(void) +{ + unsigned int src_clk; + + if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) + return get_sys_clk_rate(); + + src_clk = get_hclk_pll_rate(); + + if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) { + /* using DDR */ + switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) { + case CLK_HCLK_DDRAM_HALF: + return src_clk/2; + case CLK_HCLK_DDRAM_NOMINAL: + return src_clk; + default: + return 0; + } + } else { + /* using SDR */ + switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) { + case CLK_HCLK_ARM_PLL_DIV_4: + return src_clk/4; + case CLK_HCLK_ARM_PLL_DIV_2: + return src_clk/2; + case CLK_HCLK_ARM_PLL_DIV_1: + return src_clk; + default: + return 0; + } + } +} + int get_serial_clock(void) { return get_periph_clk_rate(); diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c index eec4d9e..f757474 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; diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/dram.c b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c new file mode 100644 index 0000000..1eea8e2 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c @@ -0,0 +1,77 @@ +/* + * LPC32xx dram init + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * This is called by SPL to gain access to the SDR DRAM. + * + * This code runs from SRAM. + * + * Actual CONFIG_LPC32XX_SDRAM_* parameters must be provided + * by the board configuration file. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <netdev.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/wdt.h> +#include <asm/arch/emc.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct emc_regs *emc = (struct emc_regs *)EMC_BASE; + +void ddr_init(struct emc_dram_settings *dram) +{ + uint32_t ck; + + /* Enable EMC interface and choose little endian mode */ + writel(1, &emc->ctrl); + writel(0, &emc->config); + /* Select maximum EMC Dynamic Memory Refresh Time */ + writel(0x7FF, &emc->refresh); + /* Determine CLK */ + ck = get_sdram_clk_rate(); + /* Configure SDRAM */ + writel(dram->cmddelay, &clk->sdramclk_ctrl); + writel(dram->config0, &emc->config0); + writel(dram->rascas0, &emc->rascas0); + writel(dram->rdconfig, &emc->read_config); + /* Set timings */ + writel((ck / dram->trp) & 0x0000000F, &emc->t_rp); + writel((ck / dram->tras) & 0x0000000F, &emc->t_ras); + writel((ck / dram->tsrex) & 0x0000007F, &emc->t_srex); + writel((ck / dram->twr) & 0x0000000F, &emc->t_wr); + writel((ck / dram->trc) & 0x0000001F, &emc->t_rc); + writel((ck / dram->trfc) & 0x0000001F, &emc->t_rfc); + writel((ck / dram->txsr) & 0x000000FF, &emc->t_xsr); + writel(dram->trrd, &emc->t_rrd); + writel(dram->tmrd, &emc->t_mrd); + writel(dram->tcdlr, &emc->t_cdlr); + /* Dynamic refresh */ + writel((((ck / dram->refresh) >> 4) & 0x7FF), &emc->refresh); + udelay(10); + /* Force all clocks, enable inverted ck, issue NOP command */ + writel(0x00000193, &emc->control); + udelay(100); + /* Keep all clocks enabled, issue a PRECHARGE ALL command */ + writel(0x00000113, &emc->control); + /* Fast dynamic refresh for at least a few SDRAM ck cycles */ + writel((((128) >> 4) & 0x7FF), &emc->refresh); + udelay(10); + /* set correct dynamic refresh timing */ + writel((((ck / dram->refresh) >> 4) & 0x7FF), &emc->refresh); + udelay(10); + /* set normal mode to CAS=3 */ + writel(0x00000093, &emc->control); + readl(EMC_DYCS0_BASE | dram->mode); + /* set extended mode to all zeroes */ + writel(0x00000093, &emc->control); + readl(EMC_DYCS0_BASE | dram->emode); + /* stop forcing clocks, keep inverted clock, issue normal mode */ + writel(0x00000010, &emc->control); +} diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S new file mode 100644 index 0000000..4b8053e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S @@ -0,0 +1,45 @@ +/* + * WORK Microwave work_92105 board low level init + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * Low level init is called from SPL to set up the clocks. + * On entry, the LPC3250 is in Direct Run mode with all clocks + * running at 13 MHz; on exit, ARM clock is 208 MHz, HCLK is + * 104 MHz and PCLK is 13 MHz. + * + * This code must run from SRAM so that the clock changes do + * not prevent it from executing. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +.globl lowlevel_init + +lowlevel_init: + + /* Set ARM, HCLK, PCLK dividers for normal mode */ + ldr r0, =0x0000003D + ldr r1, =0x40004040 + str r0, [r1] + + /* Start HCLK PLL for 208 MHz */ + ldr r0, =0x0001401E + ldr r1, =0x40004058 + str r0, [r1] + + /* wait for HCLK PLL to lock */ +1: + ldr r0, [r1] + ands r0, r0, #1 + beq 1b + + /* switch to normal mode */ + ldr r1, =0x40004044 + ldr r0, [r1] + orr r0, #0x00000004 + str r0, [r1] + + /* Return to U-boot via saved link register */ + mov pc, lr diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h index 2cb5703..9449869 100644 --- a/arch/arm/include/asm/arch-lpc32xx/clk.h +++ b/arch/arm/include/asm/arch-lpc32xx/clk.h @@ -71,6 +71,7 @@ struct clk_pm_regs { }; /* HCLK Divider Control Register bits */ +#define CLK_HCLK_DDRAM_MASK (0x3 << 7) #define CLK_HCLK_DDRAM_HALF (0x2 << 7) #define CLK_HCLK_DDRAM_NOMINAL (0x1 << 7) #define CLK_HCLK_DDRAM_STOPPED (0x0 << 7) @@ -158,11 +159,15 @@ struct clk_pm_regs { /* SSP Clock Control Register bits */ #define CLK_SSP0_ENABLE_CLOCK (1 << 0) +/* SDRAMCLK register bits */ +#define CLK_SDRAM_DDR_SEL (1 << 1) + unsigned int get_sys_clk_rate(void); unsigned int get_hclk_pll_rate(void); unsigned int get_hclk_clk_div(void); unsigned int get_hclk_clk_rate(void); unsigned int get_periph_clk_div(void); unsigned int get_periph_clk_rate(void); +unsigned int get_sdram_clk_rate(void); #endif /* _LPC32XX_CLK_H */ diff --git a/arch/arm/include/asm/arch-lpc32xx/cpu.h b/arch/arm/include/asm/arch-lpc32xx/cpu.h index 1067107..0b5dca1 100644 --- a/arch/arm/include/asm/arch-lpc32xx/cpu.h +++ b/arch/arm/include/asm/arch-lpc32xx/cpu.h @@ -27,6 +27,7 @@ #define HS_UART7_BASE 0x4001C000 /* High speed UART 7 registers base */ #define RTC_BASE 0x40024000 /* RTC registers base */ #define GPIO_BASE 0x40028000 /* GPIO registers base */ +#define MUX_BASE 0x40028100 /* MUX registers base */ #define WDT_BASE 0x4003C000 /* Watchdog timer registers base */ #define TIMER0_BASE 0x40044000 /* Timer0 registers base */ #define TIMER1_BASE 0x4004C000 /* Timer1 registers base */ diff --git a/arch/arm/include/asm/arch-lpc32xx/emc.h b/arch/arm/include/asm/arch-lpc32xx/emc.h index 82d9bcc..1a2bab2 100644 --- a/arch/arm/include/asm/arch-lpc32xx/emc.h +++ b/arch/arm/include/asm/arch-lpc32xx/emc.h @@ -76,4 +76,25 @@ struct emc_regs { #define EMC_STAT_WAITWR(n) (((n) - 2) & 0x1F) #define EMC_STAT_WAITTURN(n) (((n) - 1) & 0x0F) +/* EMC settings for DRAM */ +struct emc_dram_settings { + u32 cmddelay; + u32 config0; + u32 rascas0; + u32 rdconfig; + u32 trp; + u32 tras; + u32 tsrex; + u32 twr; + u32 trc; + u32 trfc; + u32 txsr; + u32 trrd; + u32 tmrd; + u32 tcdlr; + u32 refresh; + u32 mode; + u32 emode; +}; + #endif /* _LPC32XX_EMC_H */ diff --git a/arch/arm/include/asm/arch-lpc32xx/mux.h b/arch/arm/include/asm/arch-lpc32xx/mux.h new file mode 100644 index 0000000..dc1b5bc --- /dev/null +++ b/arch/arm/include/asm/arch-lpc32xx/mux.h @@ -0,0 +1,18 @@ +/* + * LPC32xx MUX interface + * + * (C) Copyright 2015 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/** + * MUX register map for LPC32xx + */ + +struct mux_regs { + u32 p_mux_set; + u32 p_mux_clr; + u32 p_mux_state; +}; diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h index 86d5ee9..c3d890d 100644 --- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h +++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h @@ -7,10 +7,14 @@ #ifndef _LPC32XX_SYS_PROTO_H #define _LPC32XX_SYS_PROTO_H +#include <asm/arch/emc.h> + 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); - +#if defined(CONFIG_SPL_BUILD) +void ddr_init(const struct emc_dram_settings *dram); +#endif #endif /* _LPC32XX_SYS_PROTO_H */ diff --git a/board/work-microwave/work_92105/Kconfig b/board/work-microwave/work_92105/Kconfig new file mode 100644 index 0000000..74f004f --- /dev/null +++ b/board/work-microwave/work_92105/Kconfig @@ -0,0 +1,15 @@ +if TARGET_WORK_92105 + +config SYS_BOARD + default "work_92105" + +config SYS_VENDOR + default "work-microwave" + +config SYS_SOC + default "lpc32xx" + +config SYS_CONFIG_NAME + default "work_92105" + +endif diff --git a/board/work-microwave/work_92105/MAINTAINERS b/board/work-microwave/work_92105/MAINTAINERS new file mode 100644 index 0000000..29a92c5 --- /dev/null +++ b/board/work-microwave/work_92105/MAINTAINERS @@ -0,0 +1,6 @@ +WORK_92105 BOARD +M: Albert ARIBAUD <albert.aribaud@3adev.fr> +S: Maintained +F: board/work-microwave/work_92105/ +F: include/configs/work_92105.h +F: configs/work_92105_defconfig diff --git a/board/work-microwave/work_92105/Makefile b/board/work-microwave/work_92105/Makefile new file mode 100644 index 0000000..ba31c8e --- /dev/null +++ b/board/work-microwave/work_92105/Makefile @@ -0,0 +1,10 @@ +# +# (C) Copyright 2014 DENX Software Engineering GmbH +# Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := work_92105.o work_92105_display.o + +obj-$(CONFIG_SPL_BUILD) += work_92105_spl.o diff --git a/board/work-microwave/work_92105/README b/board/work-microwave/work_92105/README new file mode 100644 index 0000000..3c256e0 --- /dev/null +++ b/board/work-microwave/work_92105/README @@ -0,0 +1,91 @@ +Work_92105 from Work Microwave is an LPC3250- based board with the +following features: + + - 64MB SDR DRAM + - 1 GB SLC NAND, managed through MLC controller. + - Ethernet + - Ethernet + PHY SMSC8710 + - I2C: + - EEPROM (24M01-compatible) + - RTC (DS1374-compatible) + - Temperature sensor (DS620) + - DACs (2 x MAX518) + - SPI (through SSP interface) + - Port expander MAX6957 + - LCD display (HD44780-compatible), controlled + through the port expander and DACs + +Standard SPL and U-Boot binaries +-------------------------------- + +The default 'make' (or the 'make all') command will produce the +following files: + +1. spl/u-boot-spl.bin SPL, intended to run from SRAM at address 0. + This file can be loaded in SRAM through a JTAG + debugger or through the LPC32XX Service Boot + mechanism. + +2. u-boot.bin The raw U-Boot image, which can be loaded in + DDR through a JTAG debugger (for instance by + breaking SPL after DDR init), or by a running + U-Boot through e.g. 'loady' or 'tftp' and then + executed with 'go'. + +3. u-boot.img A U-Boot image with a mkimage header prepended. + SPL assumes (even when loaded through JTAG or + Service Boot) that such an image will be found + at offset 0x00040000 in NAND. + +NAND cold-boot binaries +----------------------- + +The board can boot entirely from power-on with only SPL and U-Boot in +NAND. The LPC32XX-specific 'make lpc32xx-full.bin' command will produce +(in addition to spl/u-boot-spl.bin and u-boot.img if they were not made +already) the following files: + +4. lpc32xx-spl.img spl/u-boot-spl.bin, with a LPC32XX boot header + prepended. This header is required for the ROM + code to load SPL into SRAM and branch into it. + The content of this file is expected to reside + in NAND at addresses 0x00000000 and 0x00020000 + (two copies). + +5. lpc32xx-boot-0.bin lpc32xx-spl.img, padded with 0xFF bytes to a + size of 0x20000 bytes. This file covers exactly + the reserved area for the first bootloader copy + in NAND. + +6. lpc32xx-boot-1.bin Same as lpc32xx-boot-0.bin. This is intended to + be used as the second bootloader copy. + +7. lpc32xx-full.bin lpc32xx-boot-0.bin, lpc32xx-boot-1.bin and + u-boot.img concatenated. This file represents + the content of whole bootloader as present in + NAND at offset 00x00000000. + +Flashing instructions +--------------------- + +The following assumes a working U-Boot on the target, with the ability +to load files into DDR. + +To update the whole bootloader: + + nand erase 0x00000000 0x80000 + (load lpc32xx-full.bin at location $loadaddr) + nand write $loadaddr 0x00000000 $filesize + +To update SPL only (note the double nand write) : + + nand erase 0x00000000 0x40000 + (load lpc32xx-spl.img or lpc32xx-boot-N.bin at location $loadaddr) + nand write $loadaddr 0x00000000 $filesize + nand write $loadaddr 0x00020000 $filesize + +To update U-Boot only: + + nand erase 0x00040000 0x40000 + (load u-boot.img at location $loadaddr) + nand write $loadaddr 0x00040000 $filesize diff --git a/board/work-microwave/work_92105/work_92105.c b/board/work-microwave/work_92105/work_92105.c new file mode 100644 index 0000000..f782284 --- /dev/null +++ b/board/work-microwave/work_92105/work_92105.c @@ -0,0 +1,77 @@ +/* + * WORK Microwave work_92105 board support + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/emc.h> +#include <asm/arch/wdt.h> +#include <asm/gpio.h> +#include <spl.h> +#include "work_92105_display.h" + +DECLARE_GLOBAL_DATA_PTR; + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE; + +void reset_periph(void) +{ + setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); + writel(WDTIM_MCTRL_RESFRC1, &wdt->mctrl); + udelay(150); + writel(0, &wdt->mctrl); + clrbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); +} + +int board_early_init_f(void) +{ + /* initialize serial port for console */ + lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART); + /* enable I2C, SSP, MAC, NAND */ + lpc32xx_i2c_init(1); /* only I2C1 has devices, I2C2 has none */ + lpc32xx_ssp_init(); + lpc32xx_mac_init(); + lpc32xx_mlc_nand_init(); + /* Display must wait until after relocation and devices init */ + return 0; +} + +#define GPO_19 115 + +int board_early_init_r(void) +{ + /* Set NAND !WP to 1 through GPO_19 */ + gpio_request(GPO_19, "NAND_nWP"); + gpio_direction_output(GPO_19, 1); + + /* initialize display */ + work_92105_display_init(); + + return 0; +} + +int board_init(void) +{ + reset_periph(); + /* adress of boot parameters */ + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + + return 0; +} + +int dram_init(void) +{ + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_SYS_SDRAM_SIZE); + + return 0; +} diff --git a/board/work-microwave/work_92105/work_92105_display.c b/board/work-microwave/work_92105/work_92105_display.c new file mode 100644 index 0000000..c8b1013 --- /dev/null +++ b/board/work-microwave/work_92105/work_92105_display.c @@ -0,0 +1,349 @@ +/* + * work_92105 display support + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * The work_92105 display is a HD44780-compatible module + * controlled through a MAX6957AAX SPI port expander, two + * MAX518 I2C DACs and native LPC32xx GPO 15. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/cpu.h> +#include <asm/arch/emc.h> +#include <asm/gpio.h> +#include <spi.h> +#include <i2c.h> +#include <version.h> +#include <vsprintf.h> + +/* + * GPO 15 in port 3 is gpio 3*32+15 = 111 + */ + +#define GPO_15 111 + +/** + * MAX6957AAX registers that we will be using + */ + +#define MAX6957_CONF 0x04 + +#define MAX6957_CONF_08_11 0x0A +#define MAX6957_CONF_12_15 0x0B +#define MAX6957_CONF_16_19 0x0C + +/** + * Individual gpio ports (one per gpio) to HD44780 + */ + +#define MAX6957AAX_HD44780_RS 0x29 +#define MAX6957AAX_HD44780_R_W 0x2A +#define MAX6957AAX_HD44780_EN 0x2B +#define MAX6957AAX_HD44780_DATA 0x4C + +/** + * Display controller instructions + */ + +/* Function set: eight bits, two lines, 8-dot font */ +#define HD44780_FUNCTION_SET 0x38 + +/* Display ON / OFF: turn display on */ +#define HD44780_DISPLAY_ON_OFF_CONTROL 0x0C + +/* Entry mode: increment */ +#define HD44780_ENTRY_MODE_SET 0x06 + +/* Clear */ +#define HD44780_CLEAR_DISPLAY 0x01 + +/* Set DDRAM addr (to be ORed with exact address) */ +#define HD44780_SET_DDRAM_ADDR 0x80 + +/* Set CGRAM addr (to be ORed with exact address) */ +#define HD44780_SET_CGRAM_ADDR 0x40 + +/** + * Default value for contrats + */ + +#define CONTRAST_DEFAULT 25 + +/** + * Define slave as a module-wide local to save passing it around, + * plus we will need it after init for the "hd44780" command. + */ + +static struct spi_slave *slave; + +/* + * Write a value into a MAX6957AAX register. + */ + +static void max6957aax_write(uint8_t reg, uint8_t value) +{ + uint8_t dout[2]; + + dout[0] = reg; + dout[1] = value; + gpio_set_value(GPO_15, 0); + /* do SPI read/write (passing din==dout is OK) */ + spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END); + gpio_set_value(GPO_15, 1); +} + +/* + * Read a value from a MAX6957AAX register. + * + * According to the MAX6957AAX datasheet, we should release the chip + * select halfway through the read sequence, when the actual register + * value is read; but the WORK_92105 hardware prevents the MAX6957AAX + * SPI OUT from reaching the LPC32XX SIP MISO if chip is not selected. + * so let's release the CS an hold it again while reading the result. + */ + +static uint8_t max6957aax_read(uint8_t reg) +{ + uint8_t dout[2], din[2]; + + /* send read command */ + dout[0] = reg | 0x80; /* set bit 7 to indicate read */ + dout[1] = 0; + gpio_set_value(GPO_15, 0); + /* do SPI read/write (passing din==dout is OK) */ + spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END); + /* latch read command */ + gpio_set_value(GPO_15, 1); + /* read register -- din = noop on xmit, din[1] = reg on recv */ + din[0] = 0; + din[1] = 0; + gpio_set_value(GPO_15, 0); + /* do SPI read/write (passing din==dout is OK) */ + spi_xfer(slave, 16, din, din, SPI_XFER_BEGIN | SPI_XFER_END); + /* end of read. */ + gpio_set_value(GPO_15, 1); + return din[1]; +} + +static void hd44780_instruction(unsigned long instruction) +{ + max6957aax_write(MAX6957AAX_HD44780_RS, 0); + max6957aax_write(MAX6957AAX_HD44780_R_W, 0); + max6957aax_write(MAX6957AAX_HD44780_EN, 1); + max6957aax_write(MAX6957AAX_HD44780_DATA, instruction); + max6957aax_write(MAX6957AAX_HD44780_EN, 0); + /* HD44780 takes 37 us for most instructions, 1520 for clear */ + if (instruction == HD44780_CLEAR_DISPLAY) + udelay(2000); + else + udelay(100); +} + +static void hd44780_write_char(char c) +{ + max6957aax_write(MAX6957AAX_HD44780_RS, 1); + max6957aax_write(MAX6957AAX_HD44780_R_W, 0); + max6957aax_write(MAX6957AAX_HD44780_EN, 1); + max6957aax_write(MAX6957AAX_HD44780_DATA, c); + max6957aax_write(MAX6957AAX_HD44780_EN, 0); + /* HD44780 takes 37 us to write to DDRAM or CGRAM */ + udelay(100); +} + +static void hd44780_write_str(char *s) +{ + max6957aax_write(MAX6957AAX_HD44780_RS, 1); + max6957aax_write(MAX6957AAX_HD44780_R_W, 0); + while (*s) { + max6957aax_write(MAX6957AAX_HD44780_EN, 1); + max6957aax_write(MAX6957AAX_HD44780_DATA, *s); + max6957aax_write(MAX6957AAX_HD44780_EN, 0); + s++; + /* HD44780 takes 37 us to write to DDRAM or CGRAM */ + udelay(100); + } +} + +/* + * Existing user code might expect these custom characters to be + * recognized and displayed on the LCD + */ + +static u8 char_gen_chars[] = { + /* #8, empty rectangle */ + 0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F, + /* #9, filled right arrow */ + 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00, + /* #10, filled left arrow */ + 0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, + /* #11, up and down arrow */ + 0x04, 0x0E, 0x1F, 0x00, 0x00, 0x1F, 0x0E, 0x04, + /* #12, plus/minus */ + 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F, 0x00, + /* #13, fat exclamation mark */ + 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, + /* #14, empty square */ + 0x00, 0x1F, 0x11, 0x11, 0x11, 0x1F, 0x00, 0x00, + /* #15, struck out square */ + 0x00, 0x1F, 0x19, 0x15, 0x13, 0x1F, 0x00, 0x00, +}; + +static void hd44780_init_char_gen(void) +{ + int i; + + hd44780_instruction(HD44780_SET_CGRAM_ADDR); + + for (i = 0; i < sizeof(char_gen_chars); i++) + hd44780_write_char(char_gen_chars[i]); + + hd44780_instruction(HD44780_SET_DDRAM_ADDR); +} + +void work_92105_display_init(void) +{ + int claim_err; + char *display_contrast_str; + uint8_t display_contrast = CONTRAST_DEFAULT; + uint8_t enable_backlight = 0x96; + + slave = spi_setup_slave(0, 0, 500000, 0); + + if (!slave) { + printf("Failed to set up SPI slave\n"); + return; + } + + claim_err = spi_claim_bus(slave); + + if (claim_err) + debug("Failed to claim SPI bus: %d\n", claim_err); + + /* enable backlight */ + i2c_write(0x2c, 0x01, 1, &enable_backlight, 1); + + /* set display contrast */ + display_contrast_str = getenv("fwopt_dispcontrast"); + if (display_contrast_str) + display_contrast = simple_strtoul(display_contrast_str, + NULL, 10); + i2c_write(0x2c, 0x00, 1, &display_contrast, 1); + + /* request GPO_15 as an output initially set to 1 */ + gpio_request(GPO_15, "MAX6957_nCS"); + gpio_direction_output(GPO_15, 1); + + /* enable MAX6957 portexpander */ + max6957aax_write(MAX6957_CONF, 0x01); + /* configure pin 8 as input, pins 9..19 as outputs */ + max6957aax_write(MAX6957_CONF_08_11, 0x56); + max6957aax_write(MAX6957_CONF_12_15, 0x55); + max6957aax_write(MAX6957_CONF_16_19, 0x55); + + /* initialize HD44780 */ + max6957aax_write(MAX6957AAX_HD44780_EN, 0); + hd44780_instruction(HD44780_FUNCTION_SET); + hd44780_instruction(HD44780_DISPLAY_ON_OFF_CONTROL); + hd44780_instruction(HD44780_ENTRY_MODE_SET); + + /* write custom character glyphs */ + hd44780_init_char_gen(); + + /* Show U-Boot version, date and time as a sign-of-life */ + hd44780_instruction(HD44780_CLEAR_DISPLAY); + hd44780_instruction(HD44780_SET_DDRAM_ADDR | 0); + hd44780_write_str(U_BOOT_VERSION); + hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64); + hd44780_write_str(U_BOOT_DATE); + hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64 | 20); + hd44780_write_str(U_BOOT_TIME); +} + +#ifdef CONFIG_CMD_MAX6957 + +static int do_max6957aax(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + int reg, val; + + if (argc != 3) + return CMD_RET_USAGE; + switch (argv[1][0]) { + case 'r': + case 'R': + reg = simple_strtoul(argv[2], NULL, 0); + val = max6957aax_read(reg); + printf("MAX6957 reg 0x%02x read 0x%02x\n", reg, val); + return 0; + default: + reg = simple_strtoul(argv[1], NULL, 0); + val = simple_strtoul(argv[2], NULL, 0); + max6957aax_write(reg, val); + printf("MAX6957 reg 0x%02x wrote 0x%02x\n", reg, val); + return 0; + } + return 1; +} + +#ifdef CONFIG_SYS_LONGHELP +static char max6957aax_help_text[] = + "max6957aax - write or read display register:\n" + "\tmax6957aax R|r reg - read display register;\n" + "\tmax6957aax reg val - write display register."; +#endif + +U_BOOT_CMD( + max6957aax, 6, 1, do_max6957aax, + "SPI MAX6957 display write/read", + max6957aax_help_text +); +#endif /* CONFIG_CMD_MAX6957 */ + +#ifdef CONFIG_CMD_HD44760 + +/* + * We need the HUSH parser because we need string arguments, and + * only HUSH can understand them. + */ + +#if !defined(CONFIG_SYS_HUSH_PARSER) +#error CONFIG_CMD_HD44760 requires CONFIG_SYS_HUSH_PARSER +#endif + +static int do_hd44780(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + char *cmd; + + if (argc != 3) + return CMD_RET_USAGE; + + cmd = argv[1]; + + if (strcasecmp(cmd, "cmd") == 0) + hd44780_instruction(simple_strtol(argv[2], NULL, 0)); + else if (strcasecmp(cmd, "data") == 0) + hd44780_write_char(simple_strtol(argv[2], NULL, 0)); + else if (strcasecmp(cmd, "str") == 0) + hd44780_write_str(argv[2]); + return 0; +} + +#ifdef CONFIG_SYS_LONGHELP +static char hd44780_help_text[] = + "hd44780 - control LCD driver:\n" + "\thd44780 cmd <val> - send command <val> to driver;\n" + "\thd44780 data <val> - send data <val> to driver;\n" + "\thd44780 str \"<text>\" - send \"<text>\" to driver."; +#endif + +U_BOOT_CMD( + hd44780, 6, 1, do_hd44780, + "HD44780 LCD driver control", + hd44780_help_text +); +#endif /* CONFIG_CMD_HD44780 */ diff --git a/board/work-microwave/work_92105/work_92105_display.h b/board/work-microwave/work_92105/work_92105_display.h new file mode 100644 index 0000000..dd6e768 --- /dev/null +++ b/board/work-microwave/work_92105/work_92105_display.h @@ -0,0 +1,14 @@ +/* + * work_92105 display support interface + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * The work_92105 display is a HD44780-compatible module + * controlled through a MAX6957AAX SPI port expander, two + * MAX518 I2C DACs and native LPC32xx GPO 15. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +void work_92105_display_init(void); diff --git a/board/work-microwave/work_92105/work_92105_spl.c b/board/work-microwave/work_92105/work_92105_spl.c new file mode 100644 index 0000000..282a6dd --- /dev/null +++ b/board/work-microwave/work_92105/work_92105_spl.c @@ -0,0 +1,85 @@ +/* + * WORK Microwave work_92105 board support + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/cpu.h> +#include <asm/arch/emc.h> +#include <asm/gpio.h> +#include <spl.h> +#include "work_92105_display.h" + +struct emc_dram_settings dram_64mb = { + .cmddelay = 0x0001C000, + .config0 = 0x00005682, + .rascas0 = 0x00000302, + .rdconfig = 0x00000011, + .trp = 52631578, + .tras = 20833333, + .tsrex = 12500000, + .twr = 66666666, + .trc = 13888888, + .trfc = 10256410, + .txsr = 12500000, + .trrd = 1, + .tmrd = 1, + .tcdlr = 0, + .refresh = 128000, + .mode = 0x00018000, + .emode = 0x02000000 +}; + +const struct emc_dram_settings dram_128mb = { + .cmddelay = 0x0001C000, + .config0 = 0x00005882, + .rascas0 = 0x00000302, + .rdconfig = 0x00000011, + .trp = 52631578, + .tras = 22222222, + .tsrex = 8333333, + .twr = 66666666, + .trc = 14814814, + .trfc = 10256410, + .txsr = 8333333, + .trrd = 1, + .tmrd = 1, + .tcdlr = 0, + .refresh = 128000, + .mode = 0x00030000, + .emode = 0x02000000 +}; + +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(&dram_128mb); + /* + * If this is actually a 64MB module, then the highest column + * bit in any address will be ignored, and thus address 0x80000000 + * should be mirrored at address 0x80000800. Test this. + */ + writel(0x31415926, 0x80000000); /* write Pi at 0x80000000 */ + writel(0x16180339, 0x80000800); /* write Phi at 0x80000800 */ + if (readl(0x80000000) == 0x16180339) /* check 0x80000000 */ { + /* actually 64MB mirrored: reconfigure controller */ + ddr_init(&dram_64mb); + } + /* initialize NAND controller to load U-Boot from NAND */ + lpc32xx_mlc_nand_init(); +} + +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_NAND; +} diff --git a/configs/work_92105_defconfig b/configs/work_92105_defconfig new file mode 100644 index 0000000..142a505 --- /dev/null +++ b/configs/work_92105_defconfig @@ -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="" diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h new file mode 100644 index 0000000..dc8e99f --- /dev/null +++ b/include/configs/work_92105.h @@ -0,0 +1,241 @@ +/* + * WORK Microwave work_92105 board configuration file + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_WORK_92105_H__ +#define __CONFIG_WORK_92105_H__ + +/* SoC and board defines */ +#include <linux/sizes.h> +#include <asm/arch/cpu.h> + +/* + * Define work_92105 machine type by hand -- done only for compatibility + * with original board code + */ +#define MACH_TYPE_WORK_92105 736 +#define CONFIG_MACH_TYPE MACH_TYPE_WORK_92105 + +#define CONFIG_SYS_ICACHE_OFF +#define CONFIG_SYS_DCACHE_OFF +#if !defined(CONFIG_SPL_BUILD) +#define CONFIG_SKIP_LOWLEVEL_INIT +#endif +#define CONFIG_BOARD_EARLY_INIT_F +#define CONFIG_BOARD_EARLY_INIT_R + +/* generate LPC32XX-specific SPL image */ +#define CONFIG_LPC32XX_SPL + +/* + * Memory configurations + */ +#define CONFIG_NR_DRAM_BANKS 1 +#define CONFIG_SYS_MALLOC_LEN SZ_1M +#define CONFIG_SYS_SDRAM_BASE EMC_DYCS0_BASE +#define CONFIG_SYS_SDRAM_SIZE SZ_128M +#define CONFIG_SYS_TEXT_BASE 0x80100000 +#define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + SZ_32K) +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_TEXT_BASE - SZ_1M) + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_32K) + +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_512K \ + - GENERATED_GBL_DATA_SIZE) + +/* + * Serial Driver + */ +#define CONFIG_SYS_LPC32XX_UART 5 /* UART5 - NS16550 */ +#define CONFIG_BAUDRATE 115200 + +/* + * Ethernet Driver + */ + +#define CONFIG_PHY_SMSC +#define CONFIG_LPC32XX_ETH +#define CONFIG_PHYLIB +#define CONFIG_PHY_ADDR 0 +#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN +#define CONFIG_CMD_MII +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +/* FIXME: remove "Waiting for PHY auto negotiation to complete..." message */ + +/* + * I2C driver + */ + +#define CONFIG_SYS_I2C_LPC32XX +#define CONFIG_SYS_I2C +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C_SPEED 350000 + +/* + * I2C EEPROM + */ + +#define CONFIG_CMD_EEPROM +#define CONFIG_SYS_I2C_EEPROM_ADDR 0x56 +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2 + +/* + * I2C RTC + */ + +#define CONFIG_CMD_DATE +#define CONFIG_RTC_DS1374 + +/* + * I2C Temperature Sensor (DTT) + */ + +#define CONFIG_CMD_DTT +#define CONFIG_DTT_SENSORS { 0, 1 } +#define CONFIG_DTT_DS620 + +/* + * U-Boot General Configurations + */ +#define CONFIG_SYS_GENERIC_BOARD +#define CONFIG_SYS_LONGHELP +#define CONFIG_SYS_CBSIZE 1024 +#define CONFIG_SYS_PBSIZE \ + (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16) +#define CONFIG_SYS_MAXARGS 16 +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + +#define CONFIG_SYS_HUSH_PARSER + +#define CONFIG_AUTO_COMPLETE +#define CONFIG_CMDLINE_EDITING +#define CONFIG_VERSION_VARIABLE +#define CONFIG_DISPLAY_CPUINFO +#define CONFIG_DOS_PARTITION + +/* + * No NOR + */ + +#define CONFIG_SYS_NO_FLASH + +/* + * NAND chip timings for FIXME: which one? + */ + +#define CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY 333333333 +#define CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY 10000000 +#define CONFIG_LPC32XX_NAND_MLC_NAND_TA 18181818 +#define CONFIG_LPC32XX_NAND_MLC_RD_HIGH 31250000 +#define CONFIG_LPC32XX_NAND_MLC_RD_LOW 45454545 +#define CONFIG_LPC32XX_NAND_MLC_WR_HIGH 40000000 +#define CONFIG_LPC32XX_NAND_MLC_WR_LOW 83333333 + +/* + * NAND + */ + +/* driver configuration */ +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_SYS_MAX_NAND_CHIPS 1 +#define CONFIG_SYS_NAND_BASE MLC_NAND_BASE +#define CONFIG_NAND_LPC32XX_MLC + +#define CONFIG_CMD_NAND + +/* + * GPIO + */ + +#define CONFIG_CMD_GPIO +#define CONFIG_LPC32XX_GPIO + +/* + * SSP/SPI/DISPLAY + */ + +#define CONFIG_CMD_SPI +#define CONFIG_LPC32XX_SSP +#define CONFIG_LPC32XX_SSP_TIMEOUT 100000 +#define CONFIG_CMD_MAX6957 +#define CONFIG_CMD_HD44760 +/* + * Environment + */ + +#define CONFIG_ENV_IS_IN_NAND 1 +#define CONFIG_ENV_SIZE 0x00020000 +#define CONFIG_ENV_OFFSET 0x00100000 +#define CONFIG_ENV_OFFSET_REDUND 0x00120000 +#define CONFIG_ENV_ADDR 0x80000100 + +/* + * Provide default ethernet address + * + * THIS IS NORMALLY NOT DONE. HERE WE KEEP WHAT WAS IN THE PORTED + * BOARD CONFIG IN CASE SOME PROVISIONING PROCESS OUT THERE EXPECTS + * THIS MAC ADDRESS WHEN THE DEVICE HAS STILL ITS DEFAULT CONFIG. + */ + +#define CONFIG_ETHADDR 00:12:B4:00:AF:FE +#define CONFIG_OVERWRITE_ETHADDR_ONCE + +/* + * U-Boot Commands + */ +#include <config_cmd_default.h> + +/* + * Boot Linux + */ +#define CONFIG_CMDLINE_TAG +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_INITRD_TAG + +#define CONFIG_ZERO_BOOTDELAY_CHECK +#define CONFIG_BOOTDELAY 3 + +#define CONFIG_BOOTFILE "uImage" +#define CONFIG_BOOTARGS "console=ttyS2,115200n8" +#define CONFIG_LOADADDR 0x80008000 + +/* + * SPL + */ + +/* SPL will be executed at offset 0 */ +#define CONFIG_SPL_TEXT_BASE 0x00000000 +/* SPL will use SRAM as stack */ +#define CONFIG_SPL_STACK 0x0000FFF8 +#define CONFIG_SPL_BOARD_INIT +/* Use the framework and generic lib */ +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_LIBCOMMON_SUPPORT +/* SPL will use serial */ +#define CONFIG_SPL_SERIAL_SUPPORT +/* SPL will load U-Boot from NAND offset 0x40000 */ +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_DRIVERS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_NAND_BOOT +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x00040000 +#define CONFIG_SPL_PAD_TO 0x20000 +/* U-Boot will be 0x40000 bytes, loaded and run at CONFIG_SYS_TEXT_BASE */ +#define CONFIG_SYS_MONITOR_LEN 0x40000 /* actually, MAX size */ +#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_TEXT_BASE + +/* + * Include SoC specific configuration + */ +#include <asm/arch/config.h> + +#endif /* __CONFIG_WORK_92105_H__*/ |