Merge branch 'master' of git://git.denx.de/u-boot-arm

This commit is contained in:
Tom Rini 2015-04-10 09:38:38 -04:00
commit 59064346dd
57 changed files with 3653 additions and 77 deletions

View File

@ -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

10
README
View File

@ -3607,6 +3607,16 @@ FIT uImage format:
CONFIG_SPL_STACK
Adress of the start of the stack SPL will use
CONFIG_SPL_PANIC_ON_RAW_IMAGE
When defined, SPL will panic() if the image it has
loaded does not have a signature.
Defining this is useful when code which loads images
in SPL cannot guarantee that absolutely all read errors
will be caught.
An example is the LPC32XX MLC NAND driver, which will
consider that a completely unreadable NAND block is bad,
and thus should be skipped silently.
CONFIG_SPL_RELOC_STACK
Adress of the start of the stack SPL will use after
relocation. If unspecified, this is equal to

View File

@ -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"

View File

@ -2,6 +2,38 @@
# SPDX-License-Identifier: GPL-2.0+
#
# This selects which instruction set is used.
arch-$(CONFIG_CPU_ARM720T) =-march=armv4
arch-$(CONFIG_CPU_ARM920T) =-march=armv4
arch-$(CONFIG_CPU_ARM926EJS) =-march=armv5te
arch-$(CONFIG_CPU_ARM946ES) =-march=armv4
arch-$(CONFIG_CPU_SA1100) =-march=armv4
arch-$(CONFIG_CPU_PXA) =
arch-$(CONFIG_CPU_ARM1136) =-march=armv5
arch-$(CONFIG_CPU_ARM1176) =-march=armv5t
arch-$(CONFIG_CPU_V7) =$(call cc-option, -march=armv7-a, -march=armv5)
arch-$(CONFIG_ARM64) =-march=armv8-a
# Evaluate arch cc-option calls now
arch-y := $(arch-y)
# This selects how we optimise for the processor.
tune-$(CONFIG_CPU_ARM720T) =-mtune=arm7tdmi
tune-$(CONFIG_CPU_ARM920T) =
tune-$(CONFIG_CPU_ARM926EJS) =
tune-$(CONFIG_CPU_ARM946ES) =
tune-$(CONFIG_CPU_SA1100) =-mtune=strongarm1100
tune-$(CONFIG_CPU_PXA) =-mcpu=xscale
tune-$(CONFIG_CPU_ARM1136) =
tune-$(CONFIG_CPU_ARM1176) =
tune-$(CONFIG_CPU_V7) =
tune-$(CONFIG_ARM64) =
# Evaluate tune cc-option calls now
tune-y := $(tune-y)
PLATFORM_CPPFLAGS += $(arch-y) $(tune-y)
# Machine directory name. This list is sorted alphanumerically
# by CONFIG_* macro name.
machine-$(CONFIG_ARCH_AT91) += at91

View File

@ -1,9 +0,0 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
# Make ARMv5 to allow more compilers to work, even though its v6.
PLATFORM_CPPFLAGS += -march=armv5

View File

@ -1,9 +0,0 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
# Make ARMv5 to allow more compilers to work, even though its v6.
PLATFORM_CPPFLAGS += -march=armv5t

View File

@ -1,9 +0,0 @@
#
# (C) Copyright 2002
# Sysgo Real-Time Solutions, GmbH <www.elinos.com>
# Marius Groeger <mgroeger@sysgo.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -march=armv4 -mtune=arm7tdmi

View File

@ -1,8 +0,0 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -march=armv4

View File

@ -1,8 +0,0 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -march=armv5te

View File

@ -6,3 +6,5 @@
#
obj-y = cpu.o clk.o devices.o timer.o
obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o

View File

@ -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();

View File

@ -5,9 +5,11 @@
*/
#include <common.h>
#include <netdev.h>
#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;
@ -55,3 +57,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

View File

@ -8,10 +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)
{
@ -37,3 +40,43 @@ 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);
}
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);
}
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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -1,8 +0,0 @@
#
# (C) Copyright 2002
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -march=armv4

View File

@ -5,11 +5,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
# If armv7-a is not supported by GCC fall-back to armv5, which is
# supported by more tool-chains
PF_CPPFLAGS_ARMV7 := $(call cc-option, -march=armv7-a, -march=armv5)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARMV7)
# On supported platforms we set the bit which causes us to trap on unaligned
# memory access. This is the opposite of what the compiler expects to be
# the default so we must pass in -mno-unaligned-access so that it is aware

View File

@ -6,7 +6,5 @@
#
PLATFORM_RELFLAGS += -fno-common -ffixed-x18
PF_CPPFLAGS_ARMV8 := $(call cc-option, -march=armv8-a)
PF_NO_UNALIGNED := $(call cc-option, -mstrict-align)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARMV8)
PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)

View File

@ -6,8 +6,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -mcpu=xscale
#
# !WARNING!
# The PXA's OneNAND SPL uses .text.0 and .text.1 segments to allow booting from

View File

@ -1,9 +0,0 @@
#
# (C) Copyright 2002
# Sysgo Real-Time Solutions, GmbH <www.elinos.com>
# Marius Groeger <mgroeger@sysgo.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
PLATFORM_CPPFLAGS += -march=armv4 -mtune=strongarm1100

View File

@ -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)
@ -123,6 +124,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)
@ -147,11 +152,22 @@ 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)
/* 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 */

View File

@ -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

View File

@ -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 */
@ -37,6 +38,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 */

View File

@ -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 */

View File

@ -0,0 +1,43 @@
/*
* LPC32xx GPIO interface
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/**
* GPIO Register map for LPC32xx
*/
struct gpio_regs {
u32 p3_inp_state;
u32 p3_outp_set;
u32 p3_outp_clr;
u32 p3_outp_state;
/* Watch out! the following are shared between p2 and p3 */
u32 p2_p3_dir_set;
u32 p2_p3_dir_clr;
u32 p2_p3_dir_state;
/* Now back to 'one register for one port' */
u32 p2_inp_state;
u32 p2_outp_set;
u32 p2_outp_clr;
u32 reserved1[6];
u32 p0_inp_state;
u32 p0_outp_set;
u32 p0_outp_clr;
u32 p0_outp_state;
u32 p0_dir_set;
u32 p0_dir_clr;
u32 p0_dir_state;
u32 reserved2;
u32 p1_inp_state;
u32 p1_outp_set;
u32 p1_outp_clr;
u32 p1_outp_state;
u32 p1_dir_set;
u32 p1_dir_clr;
u32 p1_dir_state;
};

View File

@ -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;
};

View File

@ -7,6 +7,14 @@
#ifndef _LPC32XX_SYS_PROTO_H
#define _LPC32XX_SYS_PROTO_H
void lpc32xx_uart_init(unsigned int uart_id);
#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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);

View File

@ -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;
}

View File

@ -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, "", "", },
};

View File

@ -101,10 +101,22 @@ void spl_parse_image_header(const struct image_header *header)
(int)sizeof(spl_image.name), spl_image.name,
spl_image.load_addr, spl_image.size);
} else {
#ifdef CONFIG_SPL_PANIC_ON_RAW_IMAGE
/*
* CONFIG_SPL_PANIC_ON_RAW_IMAGE is defined when the
* code which loads images in SPL cannot guarantee that
* absolutely all read errors will be reported.
* An example is the LPC32XX MLC NAND driver, which
* will consider that a completely unreadable NAND block
* is bad, and thus should be skipped silently.
*/
panic("** no mkimage signature but raw image not supported");
#else
/* Signature not found - assume u-boot.bin */
debug("mkimage signature not found - ih_magic = %x\n",
header->ih_magic);
spl_set_header_raw_uboot();
#endif
}
}

View File

@ -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=""

View File

@ -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.

View File

@ -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

293
drivers/gpio/lpc32xx_gpio.c Normal file
View File

@ -0,0 +1,293 @@
/*
* LPC32xxGPIO driver
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/io.h>
#include <asm/arch-lpc32xx/cpu.h>
#include <asm/arch-lpc32xx/gpio.h>
#include <asm-generic/gpio.h>
#include <dm.h>
/**
* LPC32xx GPIOs work in banks but are non-homogeneous:
* - each bank holds a different number of GPIOs
* - some GPIOs are input/ouput, some input only, some output only;
* - some GPIOs have different meanings as an input and as an output;
* - some GPIOs are controlled on a given port and bit index, but
* read on another one.
*
* In order to keep this code simple, GPIOS are considered here as
* homogeneous and linear, from 0 to 127.
*
* ** WARNING #1 **
*
* Client code is responsible for properly using valid GPIO numbers,
* including cases where a single physical GPIO has differing numbers
* for setting its direction, reading it and/or writing to it.
*
* ** WARNING #2 **
*
* Please read NOTE in description of lpc32xx_gpio_get_function().
*/
#define LPC32XX_GPIOS 128
struct lpc32xx_gpio_platdata {
struct gpio_regs *regs;
/* GPIO FUNCTION: SEE WARNING #2 */
signed char function[LPC32XX_GPIOS];
};
/**
* We have 4 GPIO ports of 32 bits each
*/
#define MAX_GPIO 128
#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3)
#define GPIO_TO_RANK(gpio) (gpio % 32)
#define GPIO_TO_MASK(gpio) (1 << (gpio % 32))
/**
* Configure a GPIO number 'offset' as input
*/
static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
{
int port, mask;
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
struct gpio_regs *regs = gpio_platdata->regs;
port = GPIO_TO_PORT(offset);
mask = GPIO_TO_MASK(offset);
switch (port) {
case 0:
writel(mask, &regs->p0_dir_clr);
break;
case 1:
writel(mask, &regs->p1_dir_clr);
break;
case 2:
/* ports 2 and 3 share a common direction */
case 3:
writel(mask, &regs->p2_p3_dir_clr);
break;
default:
return -1;
}
/* GPIO FUNCTION: SEE WARNING #2 */
gpio_platdata->function[offset] = GPIOF_INPUT;
return 0;
}
/**
* Get the value of a GPIO
*/
static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
{
int port, rank, mask, value;
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
struct gpio_regs *regs = gpio_platdata->regs;
port = GPIO_TO_PORT(offset);
switch (port) {
case 0:
value = readl(&regs->p0_inp_state);
break;
case 1:
value = readl(&regs->p1_inp_state);
break;
case 2:
value = readl(&regs->p2_inp_state);
break;
case 3:
value = readl(&regs->p3_inp_state);
break;
default:
return -1;
}
rank = GPIO_TO_RANK(offset);
mask = GPIO_TO_MASK(offset);
return (value & mask) >> rank;
}
/**
* Set a GPIO
*/
static int gpio_set(struct udevice *dev, unsigned gpio)
{
int port, mask;
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
struct gpio_regs *regs = gpio_platdata->regs;
port = GPIO_TO_PORT(gpio);
mask = GPIO_TO_MASK(gpio);
switch (port) {
case 0:
writel(mask, &regs->p0_outp_set);
break;
case 1:
writel(mask, &regs->p1_outp_set);
break;
case 2:
writel(mask, &regs->p2_outp_set);
break;
case 3:
writel(mask, &regs->p3_outp_set);
break;
default:
return -1;
}
return 0;
}
/**
* Clear a GPIO
*/
static int gpio_clr(struct udevice *dev, unsigned gpio)
{
int port, mask;
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
struct gpio_regs *regs = gpio_platdata->regs;
port = GPIO_TO_PORT(gpio);
mask = GPIO_TO_MASK(gpio);
switch (port) {
case 0:
writel(mask, &regs->p0_outp_clr);
break;
case 1:
writel(mask, &regs->p1_outp_clr);
break;
case 2:
writel(mask, &regs->p2_outp_clr);
break;
case 3:
writel(mask, &regs->p3_outp_clr);
break;
default:
return -1;
}
return 0;
}
/**
* Set the value of a GPIO
*/
static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset,
int value)
{
if (value)
return gpio_set(dev, offset);
else
return gpio_clr(dev, offset);
}
/**
* Configure a GPIO number 'offset' as output with given initial value.
*/
static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
int value)
{
int port, mask;
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
struct gpio_regs *regs = gpio_platdata->regs;
port = GPIO_TO_PORT(offset);
mask = GPIO_TO_MASK(offset);
switch (port) {
case 0:
writel(mask, &regs->p0_dir_set);
break;
case 1:
writel(mask, &regs->p1_dir_set);
break;
case 2:
/* ports 2 and 3 share a common direction */
case 3:
writel(mask, &regs->p2_p3_dir_set);
break;
default:
return -1;
}
/* GPIO FUNCTION: SEE WARNING #2 */
gpio_platdata->function[offset] = GPIOF_OUTPUT;
return lpc32xx_gpio_set_value(dev, offset, value);
}
/**
* GPIO functions are supposed to be computed from their current
* configuration, but that's way too complicated in LPC32XX. A simpler
* approach is used, where the GPIO functions are cached in an array.
* When the GPIO is in use, its function is either "input" or "output"
* depending on its direction, otherwise its function is "unknown".
*
* ** NOTE **
*
* THIS APPROACH WAS CHOSEN DU TO THE COMPLEX NATURE OF THE LPC32XX
* GPIOS; DO NOT TAKE THIS AS AN EXAMPLE FOR NEW CODE.
*/
static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset)
{
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
return gpio_platdata->function[offset];
}
static const struct dm_gpio_ops gpio_lpc32xx_ops = {
.direction_input = lpc32xx_gpio_direction_input,
.direction_output = lpc32xx_gpio_direction_output,
.get_value = lpc32xx_gpio_get_value,
.set_value = lpc32xx_gpio_set_value,
.get_function = lpc32xx_gpio_get_function,
};
static int lpc32xx_gpio_probe(struct udevice *dev)
{
struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
if (dev->of_offset == -1) {
/* Tell the uclass how many GPIOs we have */
uc_priv->gpio_count = LPC32XX_GPIOS;
}
/* set base address for GPIO registers */
gpio_platdata->regs = (struct gpio_regs *)GPIO_BASE;
/* all GPIO functions are unknown until requested */
/* GPIO FUNCTION: SEE WARNING #2 */
memset(gpio_platdata->function, GPIOF_UNKNOWN,
sizeof(gpio_platdata->function));
return 0;
}
U_BOOT_DRIVER(gpio_lpc32xx) = {
.name = "gpio_lpc32xx",
.id = UCLASS_GPIO,
.ops = &gpio_lpc32xx_ops,
.probe = lpc32xx_gpio_probe,
.priv_auto_alloc_size = sizeof(struct lpc32xx_gpio_platdata),
};

View File

@ -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

65
drivers/hwmon/ds620.c Normal file
View File

@ -0,0 +1,65 @@
/*
* DS620 DTT support
*
* (C) Copyright 2014 3ADEV <http://www.3adev.com>
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* Dallas Semiconductor's DS1621/1631 Digital Thermometer and Thermostat.
*/
#include <common.h>
#include <i2c.h>
#include <dtt.h>
/*
* Device code
*/
#define DTT_I2C_DEV_CODE 0x48
#define DTT_START_CONVERT 0x51
#define DTT_TEMP 0xAA
#define DTT_CONFIG 0xAC
/*
* Config register MSB bits
*/
#define DTT_CONFIG_1SHOT 0x01
#define DTT_CONFIG_AUTOC 0x02
#define DTT_CONFIG_R0 0x04 /* always 1 */
#define DTT_CONFIG_R1 0x08 /* always 1 */
#define DTT_CONFIG_TLF 0x10
#define DTT_CONFIG_THF 0x20
#define DTT_CONFIG_NVB 0x40
#define DTT_CONFIG_DONE 0x80
#define CHIP(sensor) (DTT_I2C_DEV_CODE + (sensor & 0x07))
int dtt_init_one(int sensor)
{
uint8_t config = DTT_CONFIG_1SHOT
| DTT_CONFIG_R0
| DTT_CONFIG_R1;
return i2c_write(CHIP(sensor), DTT_CONFIG, 1, &config, 1);
}
int dtt_get_temp(int sensor)
{
uint8_t status;
uint8_t temp[2];
/* Start a conversion, may take up to 1 second. */
i2c_write(CHIP(sensor), DTT_START_CONVERT, 1, NULL, 0);
do {
if (i2c_read(CHIP(sensor), DTT_CONFIG, 1, &status, 1))
/* bail out if I2C error */
status |= DTT_CONFIG_DONE;
} while (!(status & DTT_CONFIG_DONE));
if (i2c_read(CHIP(sensor), DTT_TEMP, 1, temp, 2))
/* bail out if I2C error */
return -274; /* below absolute zero == error */
return ((int16_t)(temp[1] | (temp[0] << 8))) >> 7;
}

View File

@ -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

249
drivers/i2c/lpc32xx_i2c.c Normal file
View File

@ -0,0 +1,249 @@
/*
* LPC32xx I2C interface driver
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <i2c.h>
#include <asm/errno.h>
#include <asm/arch/clk.h>
/*
* Provide default speed and slave if target did not
*/
#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED)
#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000
#endif
#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE)
#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0
#endif
/* i2c register set */
struct lpc32xx_i2c_registers {
union {
u32 rx;
u32 tx;
};
u32 stat;
u32 ctrl;
u32 clk_hi;
u32 clk_lo;
u32 adr;
u32 rxfl;
u32 txfl;
u32 rxb;
u32 txb;
u32 stx;
u32 stxfl;
};
/* TX register fields */
#define LPC32XX_I2C_TX_START 0x00000100
#define LPC32XX_I2C_TX_STOP 0x00000200
/* Control register values */
#define LPC32XX_I2C_SOFT_RESET 0x00000100
/* Status register values */
#define LPC32XX_I2C_STAT_TFF 0x00000400
#define LPC32XX_I2C_STAT_RFE 0x00000200
#define LPC32XX_I2C_STAT_DRMI 0x00000008
#define LPC32XX_I2C_STAT_NAI 0x00000004
#define LPC32XX_I2C_STAT_TDI 0x00000001
static struct lpc32xx_i2c_registers *lpc32xx_i2c[] = {
(struct lpc32xx_i2c_registers *)I2C1_BASE,
(struct lpc32xx_i2c_registers *)I2C2_BASE
};
/* Set I2C bus speed */
static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
int half_period;
if (speed == 0)
return -EINVAL;
half_period = (105000000 / speed) / 2;
if ((half_period > 255) || (half_period < 0))
return -EINVAL;
writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi);
writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo);
return 0;
}
/* I2C init called by cmd_i2c when doing 'i2c reset'. */
static void _i2c_init(struct i2c_adapter *adap,
int requested_speed, int slaveadd)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
/* soft reset (auto-clears) */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
/* set HI and LO periods for about 350 kHz */
lpc32xx_i2c_set_bus_speed(adap, requested_speed);
}
/* I2C probe called by cmd_i2c when doing 'i2c probe'. */
static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
int stat;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* Addre slave for write with start before and stop after */
writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP,
&i2c->tx);
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* was there no acknowledge? */
return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0;
}
/*
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*/
static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
int stat, wlen;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* do we need to write an address at all? */
if (alen) {
/* Address slave in write mode */
writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
/* write address bytes */
while (alen--) {
/* compute address byte + stop for the last one */
int a = (addr >> (8 * alen)) & 0xff;
if (!alen)
a |= LPC32XX_I2C_TX_STOP;
/* Send address byte */
writel(a, &i2c->tx);
}
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &i2c->stat);
}
/* do we have to read data at all? */
if (length) {
/* Address slave in read mode */
writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
wlen = length;
/* get data */
while (length | wlen) {
/* read status for TFF and RFE */
stat = readl(&i2c->stat);
/* must we, can we write a trigger byte? */
if ((wlen > 0)
& (!(stat & LPC32XX_I2C_STAT_TFF))) {
wlen--;
/* write trigger byte + stop if last */
writel(wlen ? 0 :
LPC32XX_I2C_TX_STOP, &i2c->tx);
}
/* must we, can we read a data byte? */
if ((length > 0)
& (!(stat & LPC32XX_I2C_STAT_RFE))) {
length--;
/* read byte */
*(data++) = readl(&i2c->rx);
}
}
}
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &i2c->stat);
/* success */
return 0;
}
/*
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
int stat;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* do we need to write anything at all? */
if (alen | length)
/* Address slave in write mode */
writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
/* write address bytes */
while (alen) {
/* wait for transmit fifo not full */
stat = readl(&i2c->stat);
if (!(stat & LPC32XX_I2C_STAT_TFF)) {
alen--;
int a = (addr >> (8 * alen)) & 0xff;
if (!(alen | length))
a |= LPC32XX_I2C_TX_STOP;
/* Send address byte */
writel(a, &i2c->tx);
}
}
while (length) {
/* wait for transmit fifo not full */
stat = readl(&i2c->stat);
if (!(stat & LPC32XX_I2C_STAT_TFF)) {
/* compute data byte, add stop if length==0 */
length--;
int d = *(data++);
if (!length)
d |= LPC32XX_I2C_TX_STOP;
/* Send data byte */
writel(d, &i2c->tx);
}
}
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &i2c->stat);
return 0;
}
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, _i2c_init, lpc32xx_i2c_probe,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_LPC32XX_SPEED,
CONFIG_SYS_I2C_LPC32XX_SLAVE,
0)
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, _i2c_init, lpc32xx_i2c_probe,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_LPC32XX_SPEED,
CONFIG_SYS_I2C_LPC32XX_SLAVE,
1)

View File

@ -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

View File

@ -0,0 +1,764 @@
/*
* LPC32xx MLC NAND flash controller driver
*
* (C) Copyright 2014 3ADEV <http://3adev.com>
* Written by Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*
* NOTE:
*
* The MLC NAND flash controller provides hardware Reed-Solomon ECC
* covering in- and out-of-band data together. Therefore, in- and out-
* of-band data must be written together in order to have a valid ECC.
*
* Consequently, pages with meaningful in-band data are written with
* blank (all-ones) out-of-band data and a valid ECC, and any later
* out-of-band data write will void the ECC.
*
* Therefore, code which reads such late-written out-of-band data
* should not rely on the ECC validity.
*/
#include <common.h>
#include <nand.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <nand.h>
#include <asm/arch/clk.h>
#include <asm/arch/sys_proto.h>
/*
* MLC NAND controller registers.
*/
struct lpc32xx_nand_mlc_registers {
u8 buff[32768]; /* controller's serial data buffer */
u8 data[32768]; /* NAND's raw data buffer */
u32 cmd;
u32 addr;
u32 ecc_enc_reg;
u32 ecc_dec_reg;
u32 ecc_auto_enc_reg;
u32 ecc_auto_dec_reg;
u32 rpr;
u32 wpr;
u32 rubp;
u32 robp;
u32 sw_wp_add_low;
u32 sw_wp_add_hig;
u32 icr;
u32 time_reg;
u32 irq_mr;
u32 irq_sr;
u32 lock_pr;
u32 isr;
u32 ceh;
};
/* LOCK_PR register defines */
#define LOCK_PR_UNLOCK_KEY 0x0000A25E /* Magic unlock value */
/* ICR defines */
#define ICR_LARGE_BLOCKS 0x00000004 /* configure for 2KB blocks */
#define ICR_ADDR4 0x00000002 /* configure for 4-word addrs */
/* CEH defines */
#define CEH_NORMAL_CE 0x00000001 /* do not force CE ON */
/* ISR register defines */
#define ISR_NAND_READY 0x00000001
#define ISR_CONTROLLER_READY 0x00000002
#define ISR_ECC_READY 0x00000004
#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1)
#define ISR_DECODER_FAILURE 0x00000040
#define ISR_DECODER_ERROR 0x00000008
/* time-out for NAND chip / controller loops, in us */
#define LPC32X_NAND_TIMEOUT 5000
/*
* There is a single instance of the NAND MLC controller
*/
static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers
= (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE;
#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o)
/**
* OOB data in each small page are 6 'free' then 10 ECC bytes.
* To make things easier, when reading large pages, the four pages'
* 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer,
* while the the four ECC bytes are groupe in its last 40 bytes.
*
* The struct below represents how free vs ecc oob bytes are stored
* in the buffer.
*
* Note: the OOB bytes contain the bad block marker at offsets 0 and 1.
*/
struct lpc32xx_oob {
struct {
uint8_t free_oob_bytes[6];
} free[4];
struct {
uint8_t ecc_oob_bytes[10];
} ecc[4];
};
/*
* Initialize the controller
*/
static void lpc32xx_nand_init(void)
{
unsigned int clk;
/* Configure controller for no software write protection, x8 bus
width, large block device, and 4 address words */
/* unlock controller registers with magic key */
writel(LOCK_PR_UNLOCK_KEY,
&lpc32xx_nand_mlc_registers->lock_pr);
/* enable large blocks and large NANDs */
writel(ICR_LARGE_BLOCKS | ICR_ADDR4,
&lpc32xx_nand_mlc_registers->icr);
/* Make sure MLC interrupts are disabled */
writel(0, &lpc32xx_nand_mlc_registers->irq_mr);
/* Normal chip enable operation */
writel(CEH_NORMAL_CE,
&lpc32xx_nand_mlc_registers->ceh);
/* Setup NAND timing */
clk = get_hclk_clk_rate();
writel(
clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) |
clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) |
clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA, 0x07, 16) |
clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH, 0x0F, 12) |
clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW, 0x0F, 8) |
clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH, 0x0F, 4) |
clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW, 0x0F, 0),
&lpc32xx_nand_mlc_registers->time_reg);
}
#if !defined(CONFIG_SPL_BUILD)
/**
* lpc32xx_cmd_ctrl - write command to either cmd or data register
*/
static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd);
else if (ctrl & NAND_ALE)
writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr);
}
/**
* lpc32xx_read_byte - read a byte from the NAND
* @mtd: MTD device structure
*/
static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
{
return readb(&lpc32xx_nand_mlc_registers->data);
}
/**
* lpc32xx_dev_ready - test if NAND device (actually controller) is ready
* @mtd: MTD device structure
* @mode: mode to set the ECC HW to.
*/
static int lpc32xx_dev_ready(struct mtd_info *mtd)
{
/* means *controller* ready for us */
int status = readl(&lpc32xx_nand_mlc_registers->isr);
return status & ISR_CONTROLLER_READY;
}
/**
* ECC layout -- this is needed whatever ECC mode we are using.
* In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes.
* To make U-Boot's life easier, we pack 'useable' OOB at the
* front and R/S ECC at the back.
*/
static struct nand_ecclayout lpc32xx_largepage_ecclayout = {
.eccbytes = 40,
.eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 48, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
},
.oobfree = {
/* bytes 0 and 1 are used for the bad block marker */
{
.offset = 2,
.length = 22
},
}
};
/**
* lpc32xx_read_page_hwecc - read in- and out-of-band data with ECC
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Use large block Auto Decode Read Mode(1) as described in User Manual
* section 8.6.2.1.
*
* The initial Read Mode and Read Start commands are sent by the caller.
*
* ECC will be false if out-of-band data has been updated since in-band
* data was initially written.
*/
static int lpc32xx_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required,
int page)
{
unsigned int i, status, timeout, err, max_bitflips = 0;
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
/* go through all four small pages */
for (i = 0; i < 4; i++) {
/* start auto decode (reads 528 NAND bytes) */
writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
/* wait for controller to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_CONTROLLER_READY)
break;
udelay(1);
}
/* if decoder failed, return failure */
if (status & ISR_DECODER_FAILURE)
return -1;
/* keep count of maximum bitflips performed */
if (status & ISR_DECODER_ERROR) {
err = ISR_DECODER_ERRORS(status);
if (err > max_bitflips)
max_bitflips = err;
}
/* copy first 512 bytes into buffer */
memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512);
/* copy next 6 bytes at front of OOB buffer */
memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10);
}
return max_bitflips;
}
/**
* lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Read NAND directly; can read pages with invalid ECC.
*/
static int lpc32xx_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required,
int page)
{
unsigned int i, status, timeout;
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
/* when we get here we've already had the Read Mode(1) */
/* go through all four small pages */
for (i = 0; i < 4; i++) {
/* wait for NAND to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_NAND_READY)
break;
udelay(1);
}
/* if NAND stalled, return failure */
if (!(status & ISR_NAND_READY))
return -1;
/* copy first 512 bytes into buffer */
memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512);
/* copy next 6 bytes at front of OOB buffer */
memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->data, 6);
/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->data, 10);
}
return 0;
}
/**
* lpc32xx_read_oob - read out-of-band data
* @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*
* Read out-of-band data. User Manual section 8.6.4 suggests using Read
* Mode(3) which the controller will turn into a Read Mode(1) internally
* but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0)
* directly.
*
* ECC covers in- and out-of-band data and was written when out-of-band
* data was blank. Therefore, if the out-of-band being read here is not
* blank, then the ECC will be false and the read will return bitflips,
* even in case of ECC failure where we will return 5 bitflips. The
* caller should be prepared to handle this.
*/
static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
unsigned int i, status, timeout, err, max_bitflips = 0;
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
/* No command was sent before calling read_oob() so send one */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
/* go through all four small pages */
for (i = 0; i < 4; i++) {
/* start auto decode (reads 528 NAND bytes) */
writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
/* wait for controller to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_CONTROLLER_READY)
break;
udelay(1);
}
/* if decoder failure, count 'one too many' bitflips */
if (status & ISR_DECODER_FAILURE)
max_bitflips = 5;
/* keep count of maximum bitflips performed */
if (status & ISR_DECODER_ERROR) {
err = ISR_DECODER_ERRORS(status);
if (err > max_bitflips)
max_bitflips = err;
}
/* set read pointer to OOB area */
writel(0, &lpc32xx_nand_mlc_registers->robp);
/* copy next 6 bytes at front of OOB buffer */
memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
/* copy next 10 bytes (R/S ECC) at back of OOB buffer */
memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10);
}
return max_bitflips;
}
/**
* lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*
* Use large block Auto Encode as per User Manual section 8.6.4.
*
* The initial Write Serial Input and final Auto Program commands are
* sent by the caller.
*/
static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
unsigned int i, status, timeout;
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
/* when we get here we've already had the SEQIN */
for (i = 0; i < 4; i++) {
/* start encode (expects 518 writes to buff) */
writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg);
/* copy first 512 bytes from buffer */
memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
/* copy next 6 bytes from OOB buffer -- excluding ECC */
memcpy(&lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6);
/* wait for ECC to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_ECC_READY)
break;
udelay(1);
}
/* if ECC stalled, return failure */
if (!(status & ISR_ECC_READY))
return -1;
/* Trigger auto encode (writes 528 bytes to NAND) */
writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg);
/* wait for controller to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_CONTROLLER_READY)
break;
udelay(1);
}
/* if controller stalled, return error */
if (!(status & ISR_CONTROLLER_READY))
return -1;
}
return 0;
}
/**
* lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Use large block write but without encode.
*
* The initial Write Serial Input and final Auto Program commands are
* sent by the caller.
*
* This function will write the full out-of-band data, including the
* ECC area. Therefore, it can write pages with valid *or* invalid ECC.
*/
static int lpc32xx_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
unsigned int i;
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
/* when we get here we've already had the Read Mode(1) */
for (i = 0; i < 4; i++) {
/* copy first 512 bytes from buffer */
memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
/* copy next 6 bytes into OOB buffer -- excluding ECC */
memcpy(lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6);
/* copy next 10 bytes into OOB buffer -- that is 'ECC' */
memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[i], 10);
}
return 0;
}
/**
* lpc32xx_write_oob - write out-of-band data
* @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*
* Since ECC covers in- and out-of-band data, writing out-of-band data
* with ECC will render the page ECC wrong -- or, if the page was blank,
* then it will produce a good ECC but a later in-band data write will
* render it wrong.
*
* Therefore, do not compute or write any ECC, and always return success.
*
* This implies that we do four writes, since non-ECC out-of-band data
* are not contiguous in a large page.
*/
static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
/* update oob on all 4 subpages in sequence */
unsigned int i, status, timeout;
struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
for (i = 0; i < 4; i++) {
/* start data input */
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page);
/* copy 6 non-ECC out-of-band bytes directly into NAND */
memcpy(lpc32xx_nand_mlc_registers->data, &oob->free[i], 6);
/* program page */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
/* wait for NAND to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_NAND_READY)
break;
udelay(1);
}
/* if NAND stalled, return error */
if (!(status & ISR_NAND_READY))
return -1;
}
return 0;
}
/**
* lpc32xx_waitfunc - wait until a command is done
* @mtd: MTD device structure
* @chip: NAND chip structure
*
* Wait for controller and FLASH to both be ready.
*/
static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
{
int status;
unsigned int timeout;
/* wait until both controller and NAND are ready */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
== (ISR_CONTROLLER_READY || ISR_NAND_READY))
break;
udelay(1);
}
/* if controller or NAND stalled, return error */
if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
!= (ISR_CONTROLLER_READY || ISR_NAND_READY))
return -1;
/* write NAND status command */
writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd);
/* read back status and return it */
return readb(&lpc32xx_nand_mlc_registers->data);
}
/*
* We are self-initializing, so we need our own chip struct
*/
static struct nand_chip lpc32xx_chip;
/*
* Initialize the controller
*/
void board_nand_init(void)
{
/* we have only one device anyway */
struct mtd_info *mtd = &nand_info[0];
/* chip is struct nand_chip, and is now provided by the driver. */
mtd->priv = &lpc32xx_chip;
/* to store return status in case we need to print it */
int ret;
/* Set all BOARDSPECIFIC (actually core-specific) fields */
lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff;
lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff;
lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl;
/* do not set init_size: nand_base.c will read sizes from chip */
lpc32xx_chip.dev_ready = lpc32xx_dev_ready;
/* do not set setup_read_retry: this is NAND-chip-specific */
/* do not set chip_delay: we have dev_ready defined. */
lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE;
/* Set needed ECC fields */
lpc32xx_chip.ecc.mode = NAND_ECC_HW;
lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout;
lpc32xx_chip.ecc.size = 512;
lpc32xx_chip.ecc.bytes = 10;
lpc32xx_chip.ecc.strength = 4;
lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc;
lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw;
lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc;
lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw;
lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob;
lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob;
lpc32xx_chip.waitfunc = lpc32xx_waitfunc;
lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */
/* BBT options: read from last two pages */
lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK
| NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE
| NAND_BBT_WRITE;
/* Initialize NAND interface */
lpc32xx_nand_init();
/* identify chip */
ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL);
if (ret) {
error("nand_scan_ident returned %i", ret);
return;
}
/* finish scanning the chip */
ret = nand_scan_tail(mtd);
if (ret) {
error("nand_scan_tail returned %i", ret);
return;
}
/* chip is good, register it */
ret = nand_register(0);
if (ret)
error("nand_register returned %i", ret);
}
#else /* defined(CONFIG_SPL_BUILD) */
void nand_init(void)
{
/* enable NAND controller */
lpc32xx_mlc_nand_init();
/* initialize NAND controller */
lpc32xx_nand_init();
}
void nand_deselect(void)
{
/* nothing to do, but SPL requires this function */
}
static int read_single_page(uint8_t *dest, int page,
struct lpc32xx_oob *oob)
{
int status, i, timeout, err, max_bitflips = 0;
/* enter read mode */
writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd);
/* send column (lsb then MSB) and page (lsb to MSB) */
writel(0, &lpc32xx_nand_mlc_registers->addr);
writel(0, &lpc32xx_nand_mlc_registers->addr);
writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr);
writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr);
writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr);
/* start reading */
writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd);
/* large page auto decode read */
for (i = 0; i < 4; i++) {
/* start auto decode (reads 528 NAND bytes) */
writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
/* wait for controller to return to ready state */
for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
status = readl(&lpc32xx_nand_mlc_registers->isr);
if (status & ISR_CONTROLLER_READY)
break;
udelay(1);
}
/* if controller stalled, return error */
if (!(status & ISR_CONTROLLER_READY))
return -1;
/* if decoder failure, return error */
if (status & ISR_DECODER_FAILURE)
return -1;
/* keep count of maximum bitflips performed */
if (status & ISR_DECODER_ERROR) {
err = ISR_DECODER_ERRORS(status);
if (err > max_bitflips)
max_bitflips = err;
}
/* copy first 512 bytes into buffer */
memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512);
/* copy next 6 bytes bytes into OOB buffer */
memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
}
return max_bitflips;
}
/*
* Load U-Boot signed image.
* This loads an image from NAND, skipping bad blocks.
* A block is declared bad if at least one of its readable pages has
* a bad block marker in its OOB at position 0.
* If all pages ion a block are unreadable, the block is considered
* bad (i.e., assumed not to be part of the image) and skipped.
*
* IMPORTANT NOTE:
*
* If the first block of the image is fully unreadable, it will be
* ignored and skipped as if it had been marked bad. If it was not
* actually marked bad at the time of writing the image, the resulting
* image loaded will lack a header and magic number. It could thus be
* considered as a raw, headerless, image and SPL might erroneously
* jump into it.
*
* In order to avoid this risk, LPC32XX-based boards which use this
* driver MUST define CONFIG_SPL_PANIC_ON_RAW_IMAGE.
*/
#define BYTES_PER_PAGE 2048
#define PAGES_PER_BLOCK 64
#define BYTES_PER_BLOCK (BYTES_PER_PAGE * PAGES_PER_BLOCK)
#define PAGES_PER_CHIP_MAX 524288
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
{
int bytes_left = size;
int pages_left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
int blocks_left = DIV_ROUND_UP(size, BYTES_PER_BLOCK);
int block = 0;
int page = offs / BYTES_PER_PAGE;
/* perform reads block by block */
while (blocks_left) {
/* compute first page number to read */
void *block_page_dst = dst;
/* read at most one block, possibly less */
int block_bytes_left = bytes_left;
if (block_bytes_left > BYTES_PER_BLOCK)
block_bytes_left = BYTES_PER_BLOCK;
/* keep track of good, failed, and "bad" pages */
int block_pages_good = 0;
int block_pages_bad = 0;
int block_pages_err = 0;
/* we shall read a full block of pages, maybe less */
int block_pages_left = pages_left;
if (block_pages_left > PAGES_PER_BLOCK)
block_pages_left = PAGES_PER_BLOCK;
int block_pages = block_pages_left;
int block_page = page;
/* while pages are left and the block is not known as bad */
while ((block_pages > 0) && (block_pages_bad == 0)) {
/* we will read OOB, too, for bad block markers */
struct lpc32xx_oob oob;
/* read page */
int res = read_single_page(block_page_dst, block_page,
&oob);
/* count readable pages */
if (res >= 0) {
/* this page is good */
block_pages_good++;
/* this page is bad */
if ((oob.free[0].free_oob_bytes[0] != 0xff)
| (oob.free[0].free_oob_bytes[1] != 0xff))
block_pages_bad++;
} else
/* count errors */
block_pages_err++;
/* we're done with this page */
block_page++;
block_page_dst += BYTES_PER_PAGE;
if (block_pages)
block_pages--;
}
/* a fully unreadable block is considered bad */
if (block_pages_good == 0)
block_pages_bad = block_pages_err;
/* errors are fatal only in good blocks */
if ((block_pages_err > 0) && (block_pages_bad == 0))
return -1;
/* we keep reads only of good blocks */
if (block_pages_bad == 0) {
dst += block_bytes_left;
bytes_left -= block_bytes_left;
pages_left -= block_pages_left;
blocks_left--;
}
/* good or bad, we're done with this block */
block++;
page += PAGES_PER_BLOCK;
}
/* report success */
return 0;
}
#endif /* CONFIG_SPL_BUILD */

View File

@ -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

637
drivers/net/lpc32xx_eth.c Normal file
View File

@ -0,0 +1,637 @@
/*
* LPC32xx Ethernet MAC interface driver
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <net.h>
#include <malloc.h>
#include <miiphy.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/types.h>
#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/arch/cpu.h>
#include <asm/arch/config.h>
/*
* Notes:
*
* 1. Unless specified otherwise, all references to tables or paragraphs
* are to UM10326, "LPC32x0 and LPC32x0/01 User manual".
*
* 2. Only bitfield masks/values which are actually used by the driver
* are defined.
*/
/* a single RX descriptor. The controller has an array of these */
struct lpc32xx_eth_rxdesc {
u32 packet; /* Receive packet pointer */
u32 control; /* Descriptor command status */
};
#define LPC32XX_ETH_RX_DESC_SIZE (sizeof(struct lpc32xx_eth_rxdesc))
/* RX control bitfields/masks (see Table 330) */
#define LPC32XX_ETH_RX_CTRL_SIZE_MASK 0x000007FF
#define LPC32XX_ETH_RX_CTRL_UNUSED 0x7FFFF800
#define LPC32XX_ETH_RX_CTRL_INTERRUPT 0x80000000
/* a single RX status. The controller has an array of these */
struct lpc32xx_eth_rxstat {
u32 statusinfo; /* Transmit Descriptor status */
u32 statushashcrc; /* Transmit Descriptor CRCs */
};
#define LPC32XX_ETH_RX_STAT_SIZE (sizeof(struct lpc32xx_eth_rxstat))
/* RX statusinfo bitfields/masks (see Table 333) */
#define RX_STAT_RXSIZE 0x000007FF
/* Helper: OR of all errors except RANGE */
#define RX_STAT_ERRORS 0x1B800000
/* a single TX descriptor. The controller has an array of these */
struct lpc32xx_eth_txdesc {
u32 packet; /* Transmit packet pointer */
u32 control; /* Descriptor control */
};
#define LPC32XX_ETH_TX_DESC_SIZE (sizeof(struct lpc32xx_eth_txdesc))
/* TX control bitfields/masks (see Table 335) */
#define TX_CTRL_TXSIZE 0x000007FF
#define TX_CTRL_LAST 0x40000000
/* a single TX status. The controller has an array of these */
struct lpc32xx_eth_txstat {
u32 statusinfo; /* Transmit Descriptor status */
};
#define LPC32XX_ETH_TX_STAT_SIZE (sizeof(struct lpc32xx_eth_txstat))
/* Ethernet MAC interface registers (see Table 283) */
struct lpc32xx_eth_registers {
/* MAC registers - 0x3106_0000 to 0x3106_01FC */
u32 mac1; /* MAC configuration register 1 */
u32 mac2; /* MAC configuration register 2 */
u32 ipgt; /* Back-to-back Inter-Packet Gap reg. */
u32 ipgr; /* Non-back-to-back IPG register */
u32 clrt; /* Collision Window / Retry register */
u32 maxf; /* Maximum Frame register */
u32 supp; /* Phy Support register */
u32 test;
u32 mcfg; /* MII management configuration reg. */
u32 mcmd; /* MII management command register */
u32 madr; /* MII management address register */
u32 mwtd; /* MII management wite data register */
u32 mrdd; /* MII management read data register */
u32 mind; /* MII management indicators register */
u32 reserved1[2];
u32 sa0; /* Station address register 0 */
u32 sa1; /* Station address register 1 */
u32 sa2; /* Station address register 2 */
u32 reserved2[45];
/* Control registers */
u32 command;
u32 status;
u32 rxdescriptor;
u32 rxstatus;
u32 rxdescriptornumber; /* actually, number MINUS ONE */
u32 rxproduceindex; /* head of rx desc fifo */
u32 rxconsumeindex; /* tail of rx desc fifo */
u32 txdescriptor;
u32 txstatus;
u32 txdescriptornumber; /* actually, number MINUS ONE */
u32 txproduceindex; /* head of rx desc fifo */
u32 txconsumeindex; /* tail of rx desc fifo */
u32 reserved3[10];
u32 tsv0; /* Transmit status vector register 0 */
u32 tsv1; /* Transmit status vector register 1 */
u32 rsv; /* Receive status vector register */
u32 reserved4[3];
u32 flowcontrolcounter;
u32 flowcontrolstatus;
u32 reserved5[34];
/* RX filter registers - 0x3106_0200 to 0x3106_0FDC */
u32 rxfilterctrl;
u32 rxfilterwolstatus;
u32 rxfilterwolclear;
u32 reserved6;
u32 hashfilterl;
u32 hashfilterh;
u32 reserved7[882];
/* Module control registers - 0x3106_0FE0 to 0x3106_0FF8 */
u32 intstatus; /* Interrupt status register */
u32 intenable;
u32 intclear;
u32 intset;
u32 reserved8;
u32 powerdown;
u32 reserved9;
};
/* MAC1 register bitfields/masks and offsets (see Table 283) */
#define MAC1_RECV_ENABLE 0x00000001
#define MAC1_PASS_ALL_RX_FRAMES 0x00000002
#define MAC1_SOFT_RESET 0x00008000
/* Helper: general reset */
#define MAC1_RESETS 0x0000CF00
/* MAC2 register bitfields/masks and offsets (see Table 284) */
#define MAC2_FULL_DUPLEX 0x00000001
#define MAC2_CRC_ENABLE 0x00000010
#define MAC2_PAD_CRC_ENABLE 0x00000020
/* SUPP register bitfields/masks and offsets (see Table 290) */
#define SUPP_SPEED 0x00000100
/* MCFG register bitfields/masks and offsets (see Table 292) */
#define MCFG_CLOCK_SELECT_MASK 0x0000001C
/* divide clock by 28 (see Table 293) */
#define MCFG_CLOCK_SELECT_DIV28 0x0000001C
/* MADR register bitfields/masks and offsets (see Table 295) */
#define MADR_REG_MASK 0x0000001F
#define MADR_PHY_MASK 0x00001F00
#define MADR_REG_OFFSET 0
#define MADR_PHY_OFFSET 8
/* MIND register bitfields/masks (see Table 298) */
#define MIND_BUSY 0x00000001
/* COMMAND register bitfields/masks and offsets (see Table 283) */
#define COMMAND_RXENABLE 0x00000001
#define COMMAND_TXENABLE 0x00000002
#define COMMAND_PASSRUNTFRAME 0x00000040
#define COMMAND_FULL_DUPLEX 0x00000400
/* Helper: general reset */
#define COMMAND_RESETS 0x0000001C
/* STATUS register bitfields/masks and offsets (see Table 283) */
#define STATUS_RXSTATUS 0x00000001
#define STATUS_TXSTATUS 0x00000002
/* RXFILTERCTRL register bitfields/masks (see Table 319) */
#define RXFILTERCTRL_ACCEPTBROADCAST 0x00000002
#define RXFILTERCTRL_ACCEPTPERFECT 0x00000020
/* Buffers and descriptors */
#define ATTRS(n) __aligned(n)
#define TX_BUF_COUNT 4
#define RX_BUF_COUNT 4
struct lpc32xx_eth_buffers {
ATTRS(4) struct lpc32xx_eth_txdesc tx_desc[TX_BUF_COUNT];
ATTRS(4) struct lpc32xx_eth_txstat tx_stat[TX_BUF_COUNT];
ATTRS(PKTALIGN) u8 tx_buf[TX_BUF_COUNT*PKTSIZE_ALIGN];
ATTRS(4) struct lpc32xx_eth_rxdesc rx_desc[RX_BUF_COUNT];
ATTRS(8) struct lpc32xx_eth_rxstat rx_stat[RX_BUF_COUNT];
ATTRS(PKTALIGN) u8 rx_buf[RX_BUF_COUNT*PKTSIZE_ALIGN];
};
/* port device data struct */
struct lpc32xx_eth_device {
struct eth_device dev;
struct lpc32xx_eth_registers *regs;
struct lpc32xx_eth_buffers *bufs;
};
#define LPC32XX_ETH_DEVICE_SIZE (sizeof(struct lpc32xx_eth_device))
/* generic macros */
#define to_lpc32xx_eth(_d) container_of(_d, struct lpc32xx_eth_device, dev)
/* timeout for MII polling */
#define MII_TIMEOUT 10000000
/* limits for PHY and register addresses */
#define MII_MAX_REG (MADR_REG_MASK >> MADR_REG_OFFSET)
#define MII_MAX_PHY (MADR_PHY_MASK >> MADR_PHY_OFFSET)
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
/*
* mii_reg_read - miiphy_read callback function.
*
* Returns 16bit phy register value, or 0xffff on error
*/
static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data)
{
struct eth_device *dev = eth_get_dev_by_name(devname);
struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
u32 mind_reg;
u32 timeout;
/* check parameters */
if (phy_adr > MII_MAX_PHY) {
printf("%s:%u: Invalid PHY address %d\n",
__func__, __LINE__, phy_adr);
return -EFAULT;
}
if (reg_ofs > MII_MAX_REG) {
printf("%s:%u: Invalid register offset %d\n",
__func__, __LINE__, reg_ofs);
return -EFAULT;
}
/* write the phy and reg addressse into the MII address reg */
writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET),
&regs->madr);
/* write 1 to the MII command register to cause a read */
writel(1, &regs->mcmd);
/* wait till the MII is not busy */
timeout = MII_TIMEOUT;
do {
/* read MII indicators register */
mind_reg = readl(&regs->mind);
if (--timeout == 0)
break;
} while (mind_reg & MIND_BUSY);
/* write 0 to the MII command register to finish the read */
writel(0, &regs->mcmd);
if (timeout == 0) {
printf("%s:%u: MII busy timeout\n", __func__, __LINE__);
return -EFAULT;
}
*data = (u16) readl(&regs->mrdd);
debug("%s:(adr %d, off %d) => %04x\n", __func__, phy_adr,
reg_ofs, *data);
return 0;
}
/*
* mii_reg_write - imiiphy_write callback function.
*
* Returns 0 if write succeed, -EINVAL on bad parameters
* -ETIME on timeout
*/
static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
{
struct eth_device *dev = eth_get_dev_by_name(devname);
struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev);
struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs;
u32 mind_reg;
u32 timeout;
/* check parameters */
if (phy_adr > MII_MAX_PHY) {
printf("%s:%u: Invalid PHY address %d\n",
__func__, __LINE__, phy_adr);
return -EFAULT;
}
if (reg_ofs > MII_MAX_REG) {
printf("%s:%u: Invalid register offset %d\n",
__func__, __LINE__, reg_ofs);
return -EFAULT;
}
/* wait till the MII is not busy */
timeout = MII_TIMEOUT;
do {
/* read MII indicators register */
mind_reg = readl(&regs->mind);
if (--timeout == 0)
break;
} while (mind_reg & MIND_BUSY);
if (timeout == 0) {
printf("%s:%u: MII busy timeout\n", __func__,
__LINE__);
return -EFAULT;
}
/* write the phy and reg addressse into the MII address reg */
writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET),
&regs->madr);
/* write data to the MII write register */
writel(data, &regs->mwtd);
/*debug("%s:(adr %d, off %d) <= %04x\n", __func__, phy_adr,
reg_ofs, data);*/
return 0;
}
#endif
#if defined(CONFIG_PHYLIB)
int lpc32xx_eth_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr)
{
u16 data;
int ret;
ret = mii_reg_read(bus->name, phy_addr, reg_addr, &data);
if (ret)
return ret;
return data;
}
int lpc32xx_eth_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr, u16 data)
{
return mii_reg_write(bus->name, phy_addr, reg_addr, data);
}
#endif
/*
* Locate buffers in SRAM at 0x00001000 to avoid cache issues and
* maximize throughput.
*/
#define LPC32XX_ETH_BUFS 0x00001000
static struct lpc32xx_eth_device lpc32xx_eth = {
.regs = (struct lpc32xx_eth_registers *)LPC32XX_ETH_BASE,
.bufs = (struct lpc32xx_eth_buffers *)LPC32XX_ETH_BUFS
};
#define TX_TIMEOUT 10000
static int lpc32xx_eth_send(struct eth_device *dev, void *dataptr, int datasize)
{
struct lpc32xx_eth_device *lpc32xx_eth_device =
container_of(dev, struct lpc32xx_eth_device, dev);
struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs;
int timeout, tx_index;
/* time out if transmit descriptor array remains full too long */
timeout = TX_TIMEOUT;
while ((readl(&regs->status) & STATUS_TXSTATUS) &&
(readl(&regs->txconsumeindex)
== readl(&regs->txproduceindex))) {
if (timeout-- == 0)
return -1;
}
/* determine next transmit packet index to use */
tx_index = readl(&regs->txproduceindex);
/* set up transmit packet */
writel((u32)dataptr, &bufs->tx_desc[tx_index].packet);
writel(TX_CTRL_LAST | ((datasize - 1) & TX_CTRL_TXSIZE),
&bufs->tx_desc[tx_index].control);
writel(0, &bufs->tx_stat[tx_index].statusinfo);
/* pass transmit packet to DMA engine */
tx_index = (tx_index + 1) % TX_BUF_COUNT;
writel(tx_index, &regs->txproduceindex);
/* transmission succeeded */
return 0;
}
#define RX_TIMEOUT 1000000
static int lpc32xx_eth_recv(struct eth_device *dev)
{
struct lpc32xx_eth_device *lpc32xx_eth_device =
container_of(dev, struct lpc32xx_eth_device, dev);
struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs;
int timeout, rx_index;
/* time out if receive descriptor array remains empty too long */
timeout = RX_TIMEOUT;
while (readl(&regs->rxproduceindex) == readl(&regs->rxconsumeindex)) {
if (timeout-- == 0)
return -1;
}
/* determine next receive packet index to use */
rx_index = readl(&regs->rxconsumeindex);
/* if data was valid, pass it on */
if (!(bufs->rx_stat[rx_index].statusinfo & RX_STAT_ERRORS))
NetReceive(&(bufs->rx_buf[rx_index*PKTSIZE_ALIGN]),
(bufs->rx_stat[rx_index].statusinfo
& RX_STAT_RXSIZE) + 1);
/* pass receive slot back to DMA engine */
rx_index = (rx_index + 1) % RX_BUF_COUNT;
writel(rx_index, &regs->rxconsumeindex);
/* reception successful */
return 0;
}
static int lpc32xx_eth_write_hwaddr(struct eth_device *dev)
{
struct lpc32xx_eth_device *lpc32xx_eth_device =
container_of(dev, struct lpc32xx_eth_device, dev);
struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
/* Save station address */
writel((unsigned long) (dev->enetaddr[0] |
(dev->enetaddr[1] << 8)), &regs->sa2);
writel((unsigned long) (dev->enetaddr[2] |
(dev->enetaddr[3] << 8)), &regs->sa1);
writel((unsigned long) (dev->enetaddr[4] |
(dev->enetaddr[5] << 8)), &regs->sa0);
return 0;
}
static int lpc32xx_eth_init(struct eth_device *dev)
{
struct lpc32xx_eth_device *lpc32xx_eth_device =
container_of(dev, struct lpc32xx_eth_device, dev);
struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs;
int index;
/* Release SOFT reset to let MII talk to PHY */
clrbits_le32(&regs->mac1, MAC1_SOFT_RESET);
/* Configure Full/Half Duplex mode */
if (miiphy_duplex(dev->name, CONFIG_PHY_ADDR) == FULL) {
setbits_le32(&regs->mac2, MAC2_FULL_DUPLEX);
setbits_le32(&regs->command, COMMAND_FULL_DUPLEX);
writel(0x15, &regs->ipgt);
} else {
writel(0x12, &regs->ipgt);
}
/* Configure 100MBit/10MBit mode */
if (miiphy_speed(dev->name, CONFIG_PHY_ADDR) == _100BASET)
writel(SUPP_SPEED, &regs->supp);
else
writel(0, &regs->supp);
/* Initial MAC initialization */
writel(MAC1_PASS_ALL_RX_FRAMES, &regs->mac1);
writel(MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE, &regs->mac2);
writel(PKTSIZE_ALIGN, &regs->maxf);
/* Retries: 15 (0xF). Collision window: 57 (0x37). */
writel(0x370F, &regs->clrt);
/* Set IP gap pt 2 to default 0x12 but pt 1 to non-default 0 */
writel(0x0012, &regs->ipgr);
/* pass runt (smaller than 64 bytes) frames */
writel(COMMAND_PASSRUNTFRAME, &regs->command);
/* Save station address */
writel((unsigned long) (dev->enetaddr[0] |
(dev->enetaddr[1] << 8)), &regs->sa2);
writel((unsigned long) (dev->enetaddr[2] |
(dev->enetaddr[3] << 8)), &regs->sa1);
writel((unsigned long) (dev->enetaddr[4] |
(dev->enetaddr[5] << 8)), &regs->sa0);
/* set up transmit buffers */
for (index = 0; index < TX_BUF_COUNT; index++) {
bufs->tx_desc[index].control = 0;
bufs->tx_stat[index].statusinfo = 0;
}
writel((u32)(&bufs->tx_desc), (u32 *)&regs->txdescriptor);
writel((u32)(&bufs->tx_stat), &regs->txstatus);
writel(TX_BUF_COUNT-1, &regs->txdescriptornumber);
/* set up receive buffers */
for (index = 0; index < RX_BUF_COUNT; index++) {
bufs->rx_desc[index].packet =
(u32) (bufs->rx_buf+index*PKTSIZE_ALIGN);
bufs->rx_desc[index].control = PKTSIZE_ALIGN - 1;
bufs->rx_stat[index].statusinfo = 0;
bufs->rx_stat[index].statushashcrc = 0;
}
writel((u32)(&bufs->rx_desc), &regs->rxdescriptor);
writel((u32)(&bufs->rx_stat), &regs->rxstatus);
writel(RX_BUF_COUNT-1, &regs->rxdescriptornumber);
/* Enable broadcast and matching address packets */
writel(RXFILTERCTRL_ACCEPTBROADCAST |
RXFILTERCTRL_ACCEPTPERFECT, &regs->rxfilterctrl);
/* Clear and disable interrupts */
writel(0xFFFF, &regs->intclear);
writel(0, &regs->intenable);
/* Enable receive and transmit mode of MAC ethernet core */
setbits_le32(&regs->command, COMMAND_RXENABLE | COMMAND_TXENABLE);
setbits_le32(&regs->mac1, MAC1_RECV_ENABLE);
/*
* Perform a 'dummy' first send to work around Ethernet.1
* erratum (see ES_LPC3250 rev. 9 dated 1 June 2011).
* Use zeroed "index" variable as the dummy.
*/
index = 0;
lpc32xx_eth_send(dev, &index, 4);
return 0;
}
static int lpc32xx_eth_halt(struct eth_device *dev)
{
struct lpc32xx_eth_device *lpc32xx_eth_device =
container_of(dev, struct lpc32xx_eth_device, dev);
struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs;
/* Reset all MAC logic */
writel(MAC1_RESETS, &regs->mac1);
writel(COMMAND_RESETS, &regs->command);
/* Let reset condition settle */
udelay(2000);
return 0;
}
#if defined(CONFIG_PHYLIB)
int lpc32xx_eth_phylib_init(struct eth_device *dev, int phyid)
{
struct mii_dev *bus;
struct phy_device *phydev;
int ret;
bus = mdio_alloc();
if (!bus) {
printf("mdio_alloc failed\n");
return -ENOMEM;
}
bus->read = lpc32xx_eth_phy_read;
bus->write = lpc32xx_eth_phy_write;
sprintf(bus->name, dev->name);
ret = mdio_register(bus);
if (ret) {
printf("mdio_register failed\n");
free(bus);
return -ENOMEM;
}
phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_MII);
if (!phydev) {
printf("phy_connect failed\n");
return -ENODEV;
}
phy_config(phydev);
phy_startup(phydev);
return 0;
}
#endif
int lpc32xx_eth_initialize(bd_t *bis)
{
struct eth_device *dev = &lpc32xx_eth.dev;
struct lpc32xx_eth_registers *regs = lpc32xx_eth.regs;
/*
* Set RMII management clock rate. With HCLK at 104 MHz and
* a divider of 28, this will be 3.72 MHz.
*/
writel(MCFG_CLOCK_SELECT_DIV28, &regs->mcfg);
/* Reset all MAC logic */
writel(MAC1_RESETS, &regs->mac1);
writel(COMMAND_RESETS, &regs->command);
/* wait 10 ms for the whole I/F to reset */
udelay(10000);
/* must be less than sizeof(dev->name) */
strcpy(dev->name, "eth0");
dev->init = (void *)lpc32xx_eth_init;
dev->halt = (void *)lpc32xx_eth_halt;
dev->send = (void *)lpc32xx_eth_send;
dev->recv = (void *)lpc32xx_eth_recv;
dev->write_hwaddr = (void *)lpc32xx_eth_write_hwaddr;
/* Release SOFT reset to let MII talk to PHY */
clrbits_le32(&regs->mac1, MAC1_SOFT_RESET);
/* register driver before talking to phy */
eth_register(dev);
#if defined(CONFIG_PHYLIB)
lpc32xx_eth_phylib_init(dev, 0);
#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
miiphy_register(dev->name, mii_reg_read, mii_reg_write);
#endif
return 0;
}

View File

@ -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

144
drivers/spi/lpc32xx_ssp.c Normal file
View File

@ -0,0 +1,144 @@
/*
* LPC32xx SSP interface (SPI mode)
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/compat.h>
#include <asm/io.h>
#include <malloc.h>
#include <spi.h>
#include <asm/arch/clk.h>
/* SSP chip registers */
struct ssp_regs {
u32 cr0;
u32 cr1;
u32 data;
u32 sr;
u32 cpsr;
u32 imsc;
u32 ris;
u32 mis;
u32 icr;
u32 dmacr;
};
/* CR1 register defines */
#define SSP_CR1_SSP_ENABLE 0x0002
/* SR register defines */
#define SSP_SR_TNF 0x0002
/* SSP status RX FIFO not empty bit */
#define SSP_SR_RNE 0x0004
/* lpc32xx spi slave */
struct lpc32xx_spi_slave {
struct spi_slave slave;
struct ssp_regs *regs;
};
static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave(
struct spi_slave *slave)
{
return container_of(slave, struct lpc32xx_spi_slave, slave);
}
/* spi_init is called during boot when CONFIG_CMD_SPI is defined */
void spi_init(void)
{
/*
* nothing to do: clocking was enabled in lpc32xx_ssp_enable()
* and configuration will be done in spi_setup_slave()
*/
}
/* the following is called in sequence by do_spi_xfer() */
struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
{
struct lpc32xx_spi_slave *lslave;
/* we only set up SSP0 for now, so ignore bus */
if (mode & SPI_3WIRE) {
error("3-wire mode not supported");
return NULL;
}
if (mode & SPI_SLAVE) {
error("slave mode not supported\n");
return NULL;
}
if (mode & SPI_PREAMBLE) {
error("preamble byte skipping not supported\n");
return NULL;
}
lslave = spi_alloc_slave(struct lpc32xx_spi_slave, bus, cs);
if (!lslave) {
printf("SPI_error: Fail to allocate lpc32xx_spi_slave\n");
return NULL;
}
lslave->regs = (struct ssp_regs *)SSP0_BASE;
/*
* 8 bit frame, SPI fmt, 500kbps -> clock divider is 26.
* Set SCR to 0 and CPSDVSR to 26.
*/
writel(0x7, &lslave->regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */
writel(26, &lslave->regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */
writel(0, &lslave->regs->imsc); /* do not raise any interrupts */
writel(0, &lslave->regs->icr); /* clear any pending interrupt */
writel(0, &lslave->regs->dmacr); /* do not do DMAs */
writel(SSP_CR1_SSP_ENABLE, &lslave->regs->cr1); /* enable SSP0 */
return &lslave->slave;
}
void spi_free_slave(struct spi_slave *slave)
{
struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave);
debug("(lpc32xx) spi_free_slave: 0x%08x\n", (u32)lslave);
free(lslave);
}
int spi_claim_bus(struct spi_slave *slave)
{
/* only one bus and slave so far, always available */
return 0;
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave);
int bytelen = bitlen >> 3;
int idx_out = 0;
int idx_in = 0;
int start_time;
start_time = get_timer(0);
while ((idx_out < bytelen) || (idx_in < bytelen)) {
int status = readl(&lslave->regs->sr);
if ((idx_out < bytelen) && (status & SSP_SR_TNF))
writel(((u8 *)dout)[idx_out++], &lslave->regs->data);
if ((idx_in < bytelen) && (status & status & SSP_SR_RNE))
((u8 *)din)[idx_in++] = readl(&lslave->regs->data);
if (get_timer(start_time) >= CONFIG_LPC32XX_SSP_TIMEOUT)
return -1;
}
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
/* do nothing */
}

View File

@ -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__*/

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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 \

178
tools/lpc32xximage.c Normal file
View File

@ -0,0 +1,178 @@
/*
* Image manipulator for LPC32XX SoCs
*
* (C) Copyright 2015 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* Derived from omapimage.c:
*
* (C) Copyright 2010
* Linaro LTD, www.linaro.org
* Author: John Rigby <john.rigby@linaro.org>
* Based on TI's signGP.c
*
* (C) Copyright 2009
* Stefano Babic, DENX Software Engineering, sbabic@denx.de.
*
* (C) Copyright 2008
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "imagetool.h"
#include <compiler.h>
#include <image.h>
/*
* NAND page 0 boot header
*/
struct nand_page_0_boot_header {
uint32_t data[129];
uint32_t pad[383];
};
/*
* Default ICC (interface configuration data [sic]) if none specified
* in board config
*/
#ifndef LPC32XX_BOOT_ICR
#define LPC32XX_BOOT_ICR 0x00000096
#endif
/*
* Default boot NAND page size if none specified in board config
*/
#ifndef LPC32XX_BOOT_NAND_PAGESIZE
#define LPC32XX_BOOT_NAND_PAGESIZE 2048
#endif
/*
* Default boot NAND pages per sector if none specified in board config
*/
#ifndef LPC32XX_BOOT_NAND_PAGES_PER_SECTOR
#define LPC32XX_BOOT_NAND_PAGES_PER_SECTOR 64
#endif
/*
* Maximum size for boot code is 56K unless defined in board config
*/
#ifndef LPC32XX_BOOT_CODESIZE
#define LPC32XX_BOOT_CODESIZE (56*1024)
#endif
/* signature byte for a readable block */
#define LPC32XX_BOOT_BLOCK_OK 0xaa
static struct nand_page_0_boot_header lpc32xximage_header;
static int lpc32xximage_check_image_types(uint8_t type)
{
if (type == IH_TYPE_LPC32XXIMAGE)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
static int lpc32xximage_verify_header(unsigned char *ptr, int image_size,
struct image_tool_params *params)
{
struct nand_page_0_boot_header *hdr =
(struct nand_page_0_boot_header *)ptr;
/* turn image size from bytes to NAND pages, page 0 included */
int image_size_in_pages = ((image_size - 1)
/ LPC32XX_BOOT_NAND_PAGESIZE);
if (hdr->data[0] != (0xff & LPC32XX_BOOT_ICR))
return -1;
if (hdr->data[1] != (0xff & ~LPC32XX_BOOT_ICR))
return -1;
if (hdr->data[2] != (0xff & LPC32XX_BOOT_ICR))
return -1;
if (hdr->data[3] != (0xff & ~LPC32XX_BOOT_ICR))
return -1;
if (hdr->data[4] != (0xff & image_size_in_pages))
return -1;
if (hdr->data[5] != (0xff & ~image_size_in_pages))
return -1;
if (hdr->data[6] != (0xff & image_size_in_pages))
return -1;
if (hdr->data[7] != (0xff & ~image_size_in_pages))
return -1;
if (hdr->data[8] != (0xff & image_size_in_pages))
return -1;
if (hdr->data[9] != (0xff & ~image_size_in_pages))
return -1;
if (hdr->data[10] != (0xff & image_size_in_pages))
return -1;
if (hdr->data[11] != (0xff & ~image_size_in_pages))
return -1;
if (hdr->data[12] != LPC32XX_BOOT_BLOCK_OK)
return -1;
if (hdr->data[128] != LPC32XX_BOOT_BLOCK_OK)
return -1;
return 0;
}
static void print_hdr_byte(struct nand_page_0_boot_header *hdr, int ofs)
{
printf("header[%d] = %02x\n", ofs, hdr->data[ofs]);
}
static void lpc32xximage_print_header(const void *ptr)
{
struct nand_page_0_boot_header *hdr =
(struct nand_page_0_boot_header *)ptr;
int ofs;
for (ofs = 0; ofs <= 12; ofs++)
print_hdr_byte(hdr, ofs);
print_hdr_byte(hdr, 128);
}
static void lpc32xximage_set_header(void *ptr, struct stat *sbuf, int ifd,
struct image_tool_params *params)
{
struct nand_page_0_boot_header *hdr =
(struct nand_page_0_boot_header *)ptr;
/* turn image size from bytes to NAND pages, page 0 included */
int image_size_in_pages = ((sbuf->st_size
+ LPC32XX_BOOT_NAND_PAGESIZE - 1)
/ LPC32XX_BOOT_NAND_PAGESIZE);
/* fill header -- default byte value is 0x00, not 0xFF */
memset((void *)hdr, 0, sizeof(*hdr));
hdr->data[0] = (hdr->data[2] = 0xff & LPC32XX_BOOT_ICR);
hdr->data[1] = (hdr->data[3] = 0xff & ~LPC32XX_BOOT_ICR);
hdr->data[4] = (hdr->data[6] = (hdr->data[8]
= (hdr->data[10] = 0xff & image_size_in_pages)));
hdr->data[5] = (hdr->data[7] = (hdr->data[9]
= (hdr->data[11] = 0xff & ~image_size_in_pages)));
hdr->data[12] = (hdr->data[128] = LPC32XX_BOOT_BLOCK_OK);
}
/*
* lpc32xximage parameters
*/
U_BOOT_IMAGE_TYPE(
lpc32xximage,
"LPC32XX Boot Image",
sizeof(lpc32xximage_header),
(void *)&lpc32xximage_header,
NULL,
lpc32xximage_verify_header,
lpc32xximage_print_header,
lpc32xximage_set_header,
NULL,
lpc32xximage_check_image_types,
NULL,
NULL
);