From 412ae53aadb53cd63e754d638bafe6e426aeafee Mon Sep 17 00:00:00 2001 From: "Albert ARIBAUD \\(3ADEV\\)" Date: Tue, 31 Mar 2015 11:40:51 +0200 Subject: lpc32xx: add support for board work_92105 Work_92105 from Work Microwave is an LPC3250- based board with the following features: - 64MB or 128MB 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) --- 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 | 1 + arch/arm/cpu/arm926ejs/lpc32xx/dram.c | 77 ++++++++++++++++++++++++++ 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/emc.h | 21 +++++++ arch/arm/include/asm/arch-lpc32xx/mux.h | 18 ++++++ arch/arm/include/asm/arch-lpc32xx/sys_proto.h | 6 +- 11 files changed, 215 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 (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 80b0d34190f..086ca8514f8 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 314f004ebaf..48373776ff0 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 b7a44d59dac..1ef8a366696 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 eec4d9e880b..f7574740765 100644 --- a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c +++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c @@ -9,6 +9,7 @@ #include #include #include +#include #include 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 00000000000..1eea8e2bbfd --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include + +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 00000000000..4b8053e3f98 --- /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 + * + * 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 2cb5703877d..94498695a02 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 1067107b644..0b5dca11b8d 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 82d9bcce50f..1a2bab251f0 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 00000000000..dc1b5bcdfda --- /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 + * + * 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 86d5ee9b051..c3d890dde43 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 + 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 */ -- cgit v1.2.3