Commit 59064346dd2713e5259a32d5ef55792a8f91171b
Exists in
v2017.01-smarct4x
and in
37 other branches
Merge branch 'master' of git://git.denx.de/u-boot-arm
Showing 57 changed files Side-by-side Diff
- Makefile
- README
- arch/arm/Kconfig
- arch/arm/Makefile
- arch/arm/cpu/arm1136/config.mk
- arch/arm/cpu/arm1176/config.mk
- arch/arm/cpu/arm720t/config.mk
- arch/arm/cpu/arm920t/config.mk
- arch/arm/cpu/arm926ejs/config.mk
- arch/arm/cpu/arm926ejs/lpc32xx/Makefile
- arch/arm/cpu/arm926ejs/lpc32xx/clk.c
- arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
- arch/arm/cpu/arm926ejs/lpc32xx/devices.c
- arch/arm/cpu/arm926ejs/lpc32xx/dram.c
- arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
- arch/arm/cpu/arm946es/config.mk
- arch/arm/cpu/armv7/config.mk
- arch/arm/cpu/armv8/config.mk
- arch/arm/cpu/pxa/config.mk
- arch/arm/cpu/sa1100/config.mk
- arch/arm/include/asm/arch-lpc32xx/clk.h
- arch/arm/include/asm/arch-lpc32xx/config.h
- arch/arm/include/asm/arch-lpc32xx/cpu.h
- arch/arm/include/asm/arch-lpc32xx/emc.h
- arch/arm/include/asm/arch-lpc32xx/gpio.h
- arch/arm/include/asm/arch-lpc32xx/mux.h
- arch/arm/include/asm/arch-lpc32xx/sys_proto.h
- board/work-microwave/work_92105/Kconfig
- board/work-microwave/work_92105/MAINTAINERS
- board/work-microwave/work_92105/Makefile
- board/work-microwave/work_92105/README
- board/work-microwave/work_92105/work_92105.c
- board/work-microwave/work_92105/work_92105_display.c
- board/work-microwave/work_92105/work_92105_display.h
- board/work-microwave/work_92105/work_92105_spl.c
- common/image.c
- common/spl/spl.c
- configs/work_92105_defconfig
- drivers/gpio/Kconfig
- drivers/gpio/Makefile
- drivers/gpio/lpc32xx_gpio.c
- drivers/hwmon/Makefile
- drivers/hwmon/ds620.c
- drivers/i2c/Makefile
- drivers/i2c/lpc32xx_i2c.c
- drivers/mtd/nand/Makefile
- drivers/mtd/nand/lpc32xx_nand_mlc.c
- drivers/net/Makefile
- drivers/net/lpc32xx_eth.c
- drivers/spi/Makefile
- drivers/spi/lpc32xx_ssp.c
- include/configs/work_92105.h
- include/dtt.h
- include/image.h
- include/netdev.h
- tools/Makefile
- tools/lpc32xximage.c
Makefile
... | ... | @@ -909,6 +909,26 @@ |
909 | 909 | u-boot-with-spl.bin: spl/u-boot-spl.bin $(SPL_PAYLOAD) FORCE |
910 | 910 | $(call if_changed,pad_cat) |
911 | 911 | |
912 | +MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE) | |
913 | + | |
914 | +lpc32xx-spl.img: spl/u-boot-spl.bin FORCE | |
915 | + $(call if_changed,mkimage) | |
916 | + | |
917 | +OBJCOPYFLAGS_lpc32xx-boot-0.bin = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO) | |
918 | + | |
919 | +lpc32xx-boot-0.bin: lpc32xx-spl.img | |
920 | + $(call if_changed,objcopy) | |
921 | + | |
922 | +OBJCOPYFLAGS_lpc32xx-boot-1.bin = -I binary -O binary --pad-to=$(CONFIG_SPL_PAD_TO) | |
923 | + | |
924 | +lpc32xx-boot-1.bin: lpc32xx-spl.img | |
925 | + $(call if_changed,objcopy) | |
926 | + | |
927 | +lpc32xx-full.bin: lpc32xx-boot-0.bin lpc32xx-boot-1.bin u-boot.img | |
928 | + $(call if_changed,cat) | |
929 | + | |
930 | +CLEAN_FILES += lpc32xx-* | |
931 | + | |
912 | 932 | OBJCOPYFLAGS_u-boot-with-tpl.bin = -I binary -O binary \ |
913 | 933 | --pad-to=$(CONFIG_TPL_PAD_TO) |
914 | 934 | tpl/u-boot-with-tpl.bin: tpl/u-boot-tpl.bin u-boot.bin FORCE |
README
... | ... | @@ -3607,6 +3607,16 @@ |
3607 | 3607 | CONFIG_SPL_STACK |
3608 | 3608 | Adress of the start of the stack SPL will use |
3609 | 3609 | |
3610 | + CONFIG_SPL_PANIC_ON_RAW_IMAGE | |
3611 | + When defined, SPL will panic() if the image it has | |
3612 | + loaded does not have a signature. | |
3613 | + Defining this is useful when code which loads images | |
3614 | + in SPL cannot guarantee that absolutely all read errors | |
3615 | + will be caught. | |
3616 | + An example is the LPC32XX MLC NAND driver, which will | |
3617 | + consider that a completely unreadable NAND block is bad, | |
3618 | + and thus should be skipped silently. | |
3619 | + | |
3610 | 3620 | CONFIG_SPL_RELOC_STACK |
3611 | 3621 | Adress of the start of the stack SPL will use after |
3612 | 3622 | relocation. If unspecified, this is equal to |
arch/arm/Kconfig
... | ... | @@ -132,6 +132,11 @@ |
132 | 132 | bool "Support devkit3250" |
133 | 133 | select CPU_ARM926EJS |
134 | 134 | |
135 | +config TARGET_WORK_92105 | |
136 | + bool "Support work_92105" | |
137 | + select CPU_ARM926EJS | |
138 | + select SUPPORT_SPL | |
139 | + | |
135 | 140 | config TARGET_MX25PDK |
136 | 141 | bool "Support mx25pdk" |
137 | 142 | select CPU_ARM926EJS |
... | ... | @@ -872,6 +877,7 @@ |
872 | 877 | source "board/wandboard/Kconfig" |
873 | 878 | source "board/warp/Kconfig" |
874 | 879 | source "board/woodburn/Kconfig" |
880 | +source "board/work-microwave/work_92105/Kconfig" | |
875 | 881 | source "board/xaeniax/Kconfig" |
876 | 882 | source "board/xilinx/zynqmp/Kconfig" |
877 | 883 | source "board/zipitz2/Kconfig" |
arch/arm/Makefile
... | ... | @@ -2,6 +2,38 @@ |
2 | 2 | # SPDX-License-Identifier: GPL-2.0+ |
3 | 3 | # |
4 | 4 | |
5 | +# This selects which instruction set is used. | |
6 | +arch-$(CONFIG_CPU_ARM720T) =-march=armv4 | |
7 | +arch-$(CONFIG_CPU_ARM920T) =-march=armv4 | |
8 | +arch-$(CONFIG_CPU_ARM926EJS) =-march=armv5te | |
9 | +arch-$(CONFIG_CPU_ARM946ES) =-march=armv4 | |
10 | +arch-$(CONFIG_CPU_SA1100) =-march=armv4 | |
11 | +arch-$(CONFIG_CPU_PXA) = | |
12 | +arch-$(CONFIG_CPU_ARM1136) =-march=armv5 | |
13 | +arch-$(CONFIG_CPU_ARM1176) =-march=armv5t | |
14 | +arch-$(CONFIG_CPU_V7) =$(call cc-option, -march=armv7-a, -march=armv5) | |
15 | +arch-$(CONFIG_ARM64) =-march=armv8-a | |
16 | + | |
17 | +# Evaluate arch cc-option calls now | |
18 | +arch-y := $(arch-y) | |
19 | + | |
20 | +# This selects how we optimise for the processor. | |
21 | +tune-$(CONFIG_CPU_ARM720T) =-mtune=arm7tdmi | |
22 | +tune-$(CONFIG_CPU_ARM920T) = | |
23 | +tune-$(CONFIG_CPU_ARM926EJS) = | |
24 | +tune-$(CONFIG_CPU_ARM946ES) = | |
25 | +tune-$(CONFIG_CPU_SA1100) =-mtune=strongarm1100 | |
26 | +tune-$(CONFIG_CPU_PXA) =-mcpu=xscale | |
27 | +tune-$(CONFIG_CPU_ARM1136) = | |
28 | +tune-$(CONFIG_CPU_ARM1176) = | |
29 | +tune-$(CONFIG_CPU_V7) = | |
30 | +tune-$(CONFIG_ARM64) = | |
31 | + | |
32 | +# Evaluate tune cc-option calls now | |
33 | +tune-y := $(tune-y) | |
34 | + | |
35 | +PLATFORM_CPPFLAGS += $(arch-y) $(tune-y) | |
36 | + | |
5 | 37 | # Machine directory name. This list is sorted alphanumerically |
6 | 38 | # by CONFIG_* macro name. |
7 | 39 | machine-$(CONFIG_ARCH_AT91) += at91 |
arch/arm/cpu/arm1136/config.mk
arch/arm/cpu/arm1176/config.mk
arch/arm/cpu/arm720t/config.mk
arch/arm/cpu/arm920t/config.mk
arch/arm/cpu/arm926ejs/config.mk
arch/arm/cpu/arm926ejs/lpc32xx/Makefile
arch/arm/cpu/arm926ejs/lpc32xx/clk.c
... | ... | @@ -98,6 +98,40 @@ |
98 | 98 | return get_hclk_pll_rate() / get_periph_clk_div(); |
99 | 99 | } |
100 | 100 | |
101 | +unsigned int get_sdram_clk_rate(void) | |
102 | +{ | |
103 | + unsigned int src_clk; | |
104 | + | |
105 | + if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) | |
106 | + return get_sys_clk_rate(); | |
107 | + | |
108 | + src_clk = get_hclk_pll_rate(); | |
109 | + | |
110 | + if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) { | |
111 | + /* using DDR */ | |
112 | + switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) { | |
113 | + case CLK_HCLK_DDRAM_HALF: | |
114 | + return src_clk/2; | |
115 | + case CLK_HCLK_DDRAM_NOMINAL: | |
116 | + return src_clk; | |
117 | + default: | |
118 | + return 0; | |
119 | + } | |
120 | + } else { | |
121 | + /* using SDR */ | |
122 | + switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) { | |
123 | + case CLK_HCLK_ARM_PLL_DIV_4: | |
124 | + return src_clk/4; | |
125 | + case CLK_HCLK_ARM_PLL_DIV_2: | |
126 | + return src_clk/2; | |
127 | + case CLK_HCLK_ARM_PLL_DIV_1: | |
128 | + return src_clk; | |
129 | + default: | |
130 | + return 0; | |
131 | + } | |
132 | + } | |
133 | +} | |
134 | + | |
101 | 135 | int get_serial_clock(void) |
102 | 136 | { |
103 | 137 | return get_periph_clk_rate(); |
arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
... | ... | @@ -5,9 +5,11 @@ |
5 | 5 | */ |
6 | 6 | |
7 | 7 | #include <common.h> |
8 | +#include <netdev.h> | |
8 | 9 | #include <asm/arch/cpu.h> |
9 | 10 | #include <asm/arch/clk.h> |
10 | 11 | #include <asm/arch/wdt.h> |
12 | +#include <asm/arch/sys_proto.h> | |
11 | 13 | #include <asm/io.h> |
12 | 14 | |
13 | 15 | static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; |
... | ... | @@ -52,6 +54,14 @@ |
52 | 54 | printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000); |
53 | 55 | printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000); |
54 | 56 | |
57 | + return 0; | |
58 | +} | |
59 | +#endif | |
60 | + | |
61 | +#ifdef CONFIG_LPC32XX_ETH | |
62 | +int cpu_eth_init(bd_t *bis) | |
63 | +{ | |
64 | + lpc32xx_eth_initialize(bis); | |
55 | 65 | return 0; |
56 | 66 | } |
57 | 67 | #endif |
arch/arm/cpu/arm926ejs/lpc32xx/devices.c
... | ... | @@ -8,10 +8,13 @@ |
8 | 8 | #include <asm/arch/cpu.h> |
9 | 9 | #include <asm/arch/clk.h> |
10 | 10 | #include <asm/arch/uart.h> |
11 | +#include <asm/arch/mux.h> | |
11 | 12 | #include <asm/io.h> |
13 | +#include <dm.h> | |
12 | 14 | |
13 | 15 | static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; |
14 | 16 | static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE; |
17 | +static struct mux_regs *mux = (struct mux_regs *)MUX_BASE; | |
15 | 18 | |
16 | 19 | void lpc32xx_uart_init(unsigned int uart_id) |
17 | 20 | { |
... | ... | @@ -36,5 +39,45 @@ |
36 | 39 | /* Bypass pre-divider of UART clock */ |
37 | 40 | writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1), |
38 | 41 | &clk->u3clk + (uart_id - 3)); |
42 | +} | |
43 | + | |
44 | +void lpc32xx_mac_init(void) | |
45 | +{ | |
46 | + /* Enable MAC interface */ | |
47 | + writel(CLK_MAC_REG | CLK_MAC_SLAVE | CLK_MAC_MASTER | |
48 | + | CLK_MAC_MII, &clk->macclk_ctrl); | |
49 | +} | |
50 | + | |
51 | +void lpc32xx_mlc_nand_init(void) | |
52 | +{ | |
53 | + /* Enable NAND interface */ | |
54 | + writel(CLK_NAND_MLC | CLK_NAND_MLC_INT, &clk->flashclk_ctrl); | |
55 | +} | |
56 | + | |
57 | +void lpc32xx_i2c_init(unsigned int devnum) | |
58 | +{ | |
59 | + /* Enable I2C interface */ | |
60 | + uint32_t ctrl = readl(&clk->i2cclk_ctrl); | |
61 | + if (devnum == 1) | |
62 | + ctrl |= CLK_I2C1_ENABLE; | |
63 | + if (devnum == 2) | |
64 | + ctrl |= CLK_I2C2_ENABLE; | |
65 | + writel(ctrl, &clk->i2cclk_ctrl); | |
66 | +} | |
67 | + | |
68 | +U_BOOT_DEVICE(lpc32xx_gpios) = { | |
69 | + .name = "gpio_lpc32xx" | |
70 | +}; | |
71 | + | |
72 | +/* Mux for SCK0, MISO0, MOSI0. We do not use SSEL0. */ | |
73 | + | |
74 | +#define P_MUX_SET_SSP0 0x1600 | |
75 | + | |
76 | +void lpc32xx_ssp_init(void) | |
77 | +{ | |
78 | + /* Enable SSP0 interface */ | |
79 | + writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl); | |
80 | + /* Mux SSP0 pins */ | |
81 | + writel(P_MUX_SET_SSP0, &mux->p_mux_set); | |
39 | 82 | } |
arch/arm/cpu/arm926ejs/lpc32xx/dram.c
1 | +/* | |
2 | + * LPC32xx dram init | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * This is called by SPL to gain access to the SDR DRAM. | |
8 | + * | |
9 | + * This code runs from SRAM. | |
10 | + * | |
11 | + * Actual CONFIG_LPC32XX_SDRAM_* parameters must be provided | |
12 | + * by the board configuration file. | |
13 | + * | |
14 | + * SPDX-License-Identifier: GPL-2.0+ | |
15 | + */ | |
16 | + | |
17 | +#include <common.h> | |
18 | +#include <netdev.h> | |
19 | +#include <asm/arch/cpu.h> | |
20 | +#include <asm/arch/clk.h> | |
21 | +#include <asm/arch/wdt.h> | |
22 | +#include <asm/arch/emc.h> | |
23 | +#include <asm/io.h> | |
24 | + | |
25 | +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; | |
26 | +static struct emc_regs *emc = (struct emc_regs *)EMC_BASE; | |
27 | + | |
28 | +void ddr_init(struct emc_dram_settings *dram) | |
29 | +{ | |
30 | + uint32_t ck; | |
31 | + | |
32 | + /* Enable EMC interface and choose little endian mode */ | |
33 | + writel(1, &emc->ctrl); | |
34 | + writel(0, &emc->config); | |
35 | + /* Select maximum EMC Dynamic Memory Refresh Time */ | |
36 | + writel(0x7FF, &emc->refresh); | |
37 | + /* Determine CLK */ | |
38 | + ck = get_sdram_clk_rate(); | |
39 | + /* Configure SDRAM */ | |
40 | + writel(dram->cmddelay, &clk->sdramclk_ctrl); | |
41 | + writel(dram->config0, &emc->config0); | |
42 | + writel(dram->rascas0, &emc->rascas0); | |
43 | + writel(dram->rdconfig, &emc->read_config); | |
44 | + /* Set timings */ | |
45 | + writel((ck / dram->trp) & 0x0000000F, &emc->t_rp); | |
46 | + writel((ck / dram->tras) & 0x0000000F, &emc->t_ras); | |
47 | + writel((ck / dram->tsrex) & 0x0000007F, &emc->t_srex); | |
48 | + writel((ck / dram->twr) & 0x0000000F, &emc->t_wr); | |
49 | + writel((ck / dram->trc) & 0x0000001F, &emc->t_rc); | |
50 | + writel((ck / dram->trfc) & 0x0000001F, &emc->t_rfc); | |
51 | + writel((ck / dram->txsr) & 0x000000FF, &emc->t_xsr); | |
52 | + writel(dram->trrd, &emc->t_rrd); | |
53 | + writel(dram->tmrd, &emc->t_mrd); | |
54 | + writel(dram->tcdlr, &emc->t_cdlr); | |
55 | + /* Dynamic refresh */ | |
56 | + writel((((ck / dram->refresh) >> 4) & 0x7FF), &emc->refresh); | |
57 | + udelay(10); | |
58 | + /* Force all clocks, enable inverted ck, issue NOP command */ | |
59 | + writel(0x00000193, &emc->control); | |
60 | + udelay(100); | |
61 | + /* Keep all clocks enabled, issue a PRECHARGE ALL command */ | |
62 | + writel(0x00000113, &emc->control); | |
63 | + /* Fast dynamic refresh for at least a few SDRAM ck cycles */ | |
64 | + writel((((128) >> 4) & 0x7FF), &emc->refresh); | |
65 | + udelay(10); | |
66 | + /* set correct dynamic refresh timing */ | |
67 | + writel((((ck / dram->refresh) >> 4) & 0x7FF), &emc->refresh); | |
68 | + udelay(10); | |
69 | + /* set normal mode to CAS=3 */ | |
70 | + writel(0x00000093, &emc->control); | |
71 | + readl(EMC_DYCS0_BASE | dram->mode); | |
72 | + /* set extended mode to all zeroes */ | |
73 | + writel(0x00000093, &emc->control); | |
74 | + readl(EMC_DYCS0_BASE | dram->emode); | |
75 | + /* stop forcing clocks, keep inverted clock, issue normal mode */ | |
76 | + writel(0x00000010, &emc->control); | |
77 | +} |
arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
1 | +/* | |
2 | + * WORK Microwave work_92105 board low level init | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * Low level init is called from SPL to set up the clocks. | |
8 | + * On entry, the LPC3250 is in Direct Run mode with all clocks | |
9 | + * running at 13 MHz; on exit, ARM clock is 208 MHz, HCLK is | |
10 | + * 104 MHz and PCLK is 13 MHz. | |
11 | + * | |
12 | + * This code must run from SRAM so that the clock changes do | |
13 | + * not prevent it from executing. | |
14 | + * | |
15 | + * SPDX-License-Identifier: GPL-2.0+ | |
16 | + */ | |
17 | + | |
18 | +.globl lowlevel_init | |
19 | + | |
20 | +lowlevel_init: | |
21 | + | |
22 | + /* Set ARM, HCLK, PCLK dividers for normal mode */ | |
23 | + ldr r0, =0x0000003D | |
24 | + ldr r1, =0x40004040 | |
25 | + str r0, [r1] | |
26 | + | |
27 | + /* Start HCLK PLL for 208 MHz */ | |
28 | + ldr r0, =0x0001401E | |
29 | + ldr r1, =0x40004058 | |
30 | + str r0, [r1] | |
31 | + | |
32 | + /* wait for HCLK PLL to lock */ | |
33 | +1: | |
34 | + ldr r0, [r1] | |
35 | + ands r0, r0, #1 | |
36 | + beq 1b | |
37 | + | |
38 | + /* switch to normal mode */ | |
39 | + ldr r1, =0x40004044 | |
40 | + ldr r0, [r1] | |
41 | + orr r0, #0x00000004 | |
42 | + str r0, [r1] | |
43 | + | |
44 | + /* Return to U-boot via saved link register */ | |
45 | + mov pc, lr |
arch/arm/cpu/arm946es/config.mk
arch/arm/cpu/armv7/config.mk
... | ... | @@ -5,11 +5,6 @@ |
5 | 5 | # SPDX-License-Identifier: GPL-2.0+ |
6 | 6 | # |
7 | 7 | |
8 | -# If armv7-a is not supported by GCC fall-back to armv5, which is | |
9 | -# supported by more tool-chains | |
10 | -PF_CPPFLAGS_ARMV7 := $(call cc-option, -march=armv7-a, -march=armv5) | |
11 | -PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARMV7) | |
12 | - | |
13 | 8 | # On supported platforms we set the bit which causes us to trap on unaligned |
14 | 9 | # memory access. This is the opposite of what the compiler expects to be |
15 | 10 | # the default so we must pass in -mno-unaligned-access so that it is aware |
arch/arm/cpu/armv8/config.mk
arch/arm/cpu/pxa/config.mk
arch/arm/cpu/sa1100/config.mk
arch/arm/include/asm/arch-lpc32xx/clk.h
... | ... | @@ -71,6 +71,7 @@ |
71 | 71 | }; |
72 | 72 | |
73 | 73 | /* HCLK Divider Control Register bits */ |
74 | +#define CLK_HCLK_DDRAM_MASK (0x3 << 7) | |
74 | 75 | #define CLK_HCLK_DDRAM_HALF (0x2 << 7) |
75 | 76 | #define CLK_HCLK_DDRAM_NOMINAL (0x1 << 7) |
76 | 77 | #define CLK_HCLK_DDRAM_STOPPED (0x0 << 7) |
... | ... | @@ -123,6 +124,10 @@ |
123 | 124 | #define CLK_MAC_SLAVE (1 << 1) |
124 | 125 | #define CLK_MAC_REG (1 << 0) |
125 | 126 | |
127 | +/* I2C Clock Control Register bits */ | |
128 | +#define CLK_I2C2_ENABLE (1 << 1) | |
129 | +#define CLK_I2C1_ENABLE (1 << 0) | |
130 | + | |
126 | 131 | /* Timer Clock Control1 Register bits */ |
127 | 132 | #define CLK_TIMCLK_MOTOR (1 << 6) |
128 | 133 | #define CLK_TIMCLK_TIMER3 (1 << 5) |
129 | 134 | |
... | ... | @@ -147,12 +152,23 @@ |
147 | 152 | /* DMA Clock Control Register bits */ |
148 | 153 | #define CLK_DMA_ENABLE (1 << 0) |
149 | 154 | |
155 | +/* NAND Clock Control Register bits */ | |
156 | +#define CLK_NAND_MLC (1 << 1) | |
157 | +#define CLK_NAND_MLC_INT (1 << 5) | |
158 | + | |
159 | +/* SSP Clock Control Register bits */ | |
160 | +#define CLK_SSP0_ENABLE_CLOCK (1 << 0) | |
161 | + | |
162 | +/* SDRAMCLK register bits */ | |
163 | +#define CLK_SDRAM_DDR_SEL (1 << 1) | |
164 | + | |
150 | 165 | unsigned int get_sys_clk_rate(void); |
151 | 166 | unsigned int get_hclk_pll_rate(void); |
152 | 167 | unsigned int get_hclk_clk_div(void); |
153 | 168 | unsigned int get_hclk_clk_rate(void); |
154 | 169 | unsigned int get_periph_clk_div(void); |
155 | 170 | unsigned int get_periph_clk_rate(void); |
171 | +unsigned int get_sdram_clk_rate(void); | |
156 | 172 | |
157 | 173 | #endif /* _LPC32XX_CLK_H */ |
arch/arm/include/asm/arch-lpc32xx/config.h
... | ... | @@ -52,6 +52,9 @@ |
52 | 52 | #define CONFIG_SYS_BAUDRATE_TABLE \ |
53 | 53 | { 9600, 19200, 38400, 57600, 115200, 230400, 460800 } |
54 | 54 | |
55 | +/* Ethernet */ | |
56 | +#define LPC32XX_ETH_BASE ETHERNET_BASE | |
57 | + | |
55 | 58 | /* NOR Flash */ |
56 | 59 | #if defined(CONFIG_SYS_FLASH_CFI) |
57 | 60 | #define CONFIG_FLASH_CFI_DRIVER |
arch/arm/include/asm/arch-lpc32xx/cpu.h
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | #define HS_UART7_BASE 0x4001C000 /* High speed UART 7 registers base */ |
28 | 28 | #define RTC_BASE 0x40024000 /* RTC registers base */ |
29 | 29 | #define GPIO_BASE 0x40028000 /* GPIO registers base */ |
30 | +#define MUX_BASE 0x40028100 /* MUX registers base */ | |
30 | 31 | #define WDT_BASE 0x4003C000 /* Watchdog timer registers base */ |
31 | 32 | #define TIMER0_BASE 0x40044000 /* Timer0 registers base */ |
32 | 33 | #define TIMER1_BASE 0x4004C000 /* Timer1 registers base */ |
... | ... | @@ -37,6 +38,8 @@ |
37 | 38 | #define UART4_BASE 0x40088000 /* UART 4 registers base */ |
38 | 39 | #define UART5_BASE 0x40090000 /* UART 5 registers base */ |
39 | 40 | #define UART6_BASE 0x40098000 /* UART 6 registers base */ |
41 | +#define I2C1_BASE 0x400A0000 /* I2C 1 registers base */ | |
42 | +#define I2C2_BASE 0x400A8000 /* I2C 2 registers base */ | |
40 | 43 | |
41 | 44 | /* External SDRAM Memory Bank base addresses */ |
42 | 45 | #define EMC_DYCS0_BASE 0x80000000 /* SDRAM DYCS0 base address */ |
arch/arm/include/asm/arch-lpc32xx/emc.h
... | ... | @@ -76,5 +76,26 @@ |
76 | 76 | #define EMC_STAT_WAITWR(n) (((n) - 2) & 0x1F) |
77 | 77 | #define EMC_STAT_WAITTURN(n) (((n) - 1) & 0x0F) |
78 | 78 | |
79 | +/* EMC settings for DRAM */ | |
80 | +struct emc_dram_settings { | |
81 | + u32 cmddelay; | |
82 | + u32 config0; | |
83 | + u32 rascas0; | |
84 | + u32 rdconfig; | |
85 | + u32 trp; | |
86 | + u32 tras; | |
87 | + u32 tsrex; | |
88 | + u32 twr; | |
89 | + u32 trc; | |
90 | + u32 trfc; | |
91 | + u32 txsr; | |
92 | + u32 trrd; | |
93 | + u32 tmrd; | |
94 | + u32 tcdlr; | |
95 | + u32 refresh; | |
96 | + u32 mode; | |
97 | + u32 emode; | |
98 | +}; | |
99 | + | |
79 | 100 | #endif /* _LPC32XX_EMC_H */ |
arch/arm/include/asm/arch-lpc32xx/gpio.h
1 | +/* | |
2 | + * LPC32xx GPIO interface | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +/** | |
11 | + * GPIO Register map for LPC32xx | |
12 | + */ | |
13 | + | |
14 | +struct gpio_regs { | |
15 | + u32 p3_inp_state; | |
16 | + u32 p3_outp_set; | |
17 | + u32 p3_outp_clr; | |
18 | + u32 p3_outp_state; | |
19 | + /* Watch out! the following are shared between p2 and p3 */ | |
20 | + u32 p2_p3_dir_set; | |
21 | + u32 p2_p3_dir_clr; | |
22 | + u32 p2_p3_dir_state; | |
23 | + /* Now back to 'one register for one port' */ | |
24 | + u32 p2_inp_state; | |
25 | + u32 p2_outp_set; | |
26 | + u32 p2_outp_clr; | |
27 | + u32 reserved1[6]; | |
28 | + u32 p0_inp_state; | |
29 | + u32 p0_outp_set; | |
30 | + u32 p0_outp_clr; | |
31 | + u32 p0_outp_state; | |
32 | + u32 p0_dir_set; | |
33 | + u32 p0_dir_clr; | |
34 | + u32 p0_dir_state; | |
35 | + u32 reserved2; | |
36 | + u32 p1_inp_state; | |
37 | + u32 p1_outp_set; | |
38 | + u32 p1_outp_clr; | |
39 | + u32 p1_outp_state; | |
40 | + u32 p1_dir_set; | |
41 | + u32 p1_dir_clr; | |
42 | + u32 p1_dir_state; | |
43 | +}; |
arch/arm/include/asm/arch-lpc32xx/mux.h
1 | +/* | |
2 | + * LPC32xx MUX interface | |
3 | + * | |
4 | + * (C) Copyright 2015 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +/** | |
11 | + * MUX register map for LPC32xx | |
12 | + */ | |
13 | + | |
14 | +struct mux_regs { | |
15 | + u32 p_mux_set; | |
16 | + u32 p_mux_clr; | |
17 | + u32 p_mux_state; | |
18 | +}; |
arch/arm/include/asm/arch-lpc32xx/sys_proto.h
... | ... | @@ -7,7 +7,15 @@ |
7 | 7 | #ifndef _LPC32XX_SYS_PROTO_H |
8 | 8 | #define _LPC32XX_SYS_PROTO_H |
9 | 9 | |
10 | -void lpc32xx_uart_init(unsigned int uart_id); | |
10 | +#include <asm/arch/emc.h> | |
11 | 11 | |
12 | +void lpc32xx_uart_init(unsigned int uart_id); | |
13 | +void lpc32xx_mac_init(void); | |
14 | +void lpc32xx_mlc_nand_init(void); | |
15 | +void lpc32xx_i2c_init(unsigned int devnum); | |
16 | +void lpc32xx_ssp_init(void); | |
17 | +#if defined(CONFIG_SPL_BUILD) | |
18 | +void ddr_init(const struct emc_dram_settings *dram); | |
19 | +#endif | |
12 | 20 | #endif /* _LPC32XX_SYS_PROTO_H */ |
board/work-microwave/work_92105/Kconfig
board/work-microwave/work_92105/MAINTAINERS
board/work-microwave/work_92105/Makefile
board/work-microwave/work_92105/README
1 | +Work_92105 from Work Microwave is an LPC3250- based board with the | |
2 | +following features: | |
3 | + | |
4 | + - 64MB SDR DRAM | |
5 | + - 1 GB SLC NAND, managed through MLC controller. | |
6 | + - Ethernet | |
7 | + - Ethernet + PHY SMSC8710 | |
8 | + - I2C: | |
9 | + - EEPROM (24M01-compatible) | |
10 | + - RTC (DS1374-compatible) | |
11 | + - Temperature sensor (DS620) | |
12 | + - DACs (2 x MAX518) | |
13 | + - SPI (through SSP interface) | |
14 | + - Port expander MAX6957 | |
15 | + - LCD display (HD44780-compatible), controlled | |
16 | + through the port expander and DACs | |
17 | + | |
18 | +Standard SPL and U-Boot binaries | |
19 | +-------------------------------- | |
20 | + | |
21 | +The default 'make' (or the 'make all') command will produce the | |
22 | +following files: | |
23 | + | |
24 | +1. spl/u-boot-spl.bin SPL, intended to run from SRAM at address 0. | |
25 | + This file can be loaded in SRAM through a JTAG | |
26 | + debugger or through the LPC32XX Service Boot | |
27 | + mechanism. | |
28 | + | |
29 | +2. u-boot.bin The raw U-Boot image, which can be loaded in | |
30 | + DDR through a JTAG debugger (for instance by | |
31 | + breaking SPL after DDR init), or by a running | |
32 | + U-Boot through e.g. 'loady' or 'tftp' and then | |
33 | + executed with 'go'. | |
34 | + | |
35 | +3. u-boot.img A U-Boot image with a mkimage header prepended. | |
36 | + SPL assumes (even when loaded through JTAG or | |
37 | + Service Boot) that such an image will be found | |
38 | + at offset 0x00040000 in NAND. | |
39 | + | |
40 | +NAND cold-boot binaries | |
41 | +----------------------- | |
42 | + | |
43 | +The board can boot entirely from power-on with only SPL and U-Boot in | |
44 | +NAND. The LPC32XX-specific 'make lpc32xx-full.bin' command will produce | |
45 | +(in addition to spl/u-boot-spl.bin and u-boot.img if they were not made | |
46 | +already) the following files: | |
47 | + | |
48 | +4. lpc32xx-spl.img spl/u-boot-spl.bin, with a LPC32XX boot header | |
49 | + prepended. This header is required for the ROM | |
50 | + code to load SPL into SRAM and branch into it. | |
51 | + The content of this file is expected to reside | |
52 | + in NAND at addresses 0x00000000 and 0x00020000 | |
53 | + (two copies). | |
54 | + | |
55 | +5. lpc32xx-boot-0.bin lpc32xx-spl.img, padded with 0xFF bytes to a | |
56 | + size of 0x20000 bytes. This file covers exactly | |
57 | + the reserved area for the first bootloader copy | |
58 | + in NAND. | |
59 | + | |
60 | +6. lpc32xx-boot-1.bin Same as lpc32xx-boot-0.bin. This is intended to | |
61 | + be used as the second bootloader copy. | |
62 | + | |
63 | +7. lpc32xx-full.bin lpc32xx-boot-0.bin, lpc32xx-boot-1.bin and | |
64 | + u-boot.img concatenated. This file represents | |
65 | + the content of whole bootloader as present in | |
66 | + NAND at offset 00x00000000. | |
67 | + | |
68 | +Flashing instructions | |
69 | +--------------------- | |
70 | + | |
71 | +The following assumes a working U-Boot on the target, with the ability | |
72 | +to load files into DDR. | |
73 | + | |
74 | +To update the whole bootloader: | |
75 | + | |
76 | + nand erase 0x00000000 0x80000 | |
77 | + (load lpc32xx-full.bin at location $loadaddr) | |
78 | + nand write $loadaddr 0x00000000 $filesize | |
79 | + | |
80 | +To update SPL only (note the double nand write) : | |
81 | + | |
82 | + nand erase 0x00000000 0x40000 | |
83 | + (load lpc32xx-spl.img or lpc32xx-boot-N.bin at location $loadaddr) | |
84 | + nand write $loadaddr 0x00000000 $filesize | |
85 | + nand write $loadaddr 0x00020000 $filesize | |
86 | + | |
87 | +To update U-Boot only: | |
88 | + | |
89 | + nand erase 0x00040000 0x40000 | |
90 | + (load u-boot.img at location $loadaddr) | |
91 | + nand write $loadaddr 0x00040000 $filesize |
board/work-microwave/work_92105/work_92105.c
1 | +/* | |
2 | + * WORK Microwave work_92105 board support | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <asm/io.h> | |
12 | +#include <asm/arch/sys_proto.h> | |
13 | +#include <asm/arch/cpu.h> | |
14 | +#include <asm/arch/clk.h> | |
15 | +#include <asm/arch/emc.h> | |
16 | +#include <asm/arch/wdt.h> | |
17 | +#include <asm/gpio.h> | |
18 | +#include <spl.h> | |
19 | +#include "work_92105_display.h" | |
20 | + | |
21 | +DECLARE_GLOBAL_DATA_PTR; | |
22 | + | |
23 | +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; | |
24 | +static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE; | |
25 | + | |
26 | +void reset_periph(void) | |
27 | +{ | |
28 | + setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); | |
29 | + writel(WDTIM_MCTRL_RESFRC1, &wdt->mctrl); | |
30 | + udelay(150); | |
31 | + writel(0, &wdt->mctrl); | |
32 | + clrbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); | |
33 | +} | |
34 | + | |
35 | +int board_early_init_f(void) | |
36 | +{ | |
37 | + /* initialize serial port for console */ | |
38 | + lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART); | |
39 | + /* enable I2C, SSP, MAC, NAND */ | |
40 | + lpc32xx_i2c_init(1); /* only I2C1 has devices, I2C2 has none */ | |
41 | + lpc32xx_ssp_init(); | |
42 | + lpc32xx_mac_init(); | |
43 | + lpc32xx_mlc_nand_init(); | |
44 | + /* Display must wait until after relocation and devices init */ | |
45 | + return 0; | |
46 | +} | |
47 | + | |
48 | +#define GPO_19 115 | |
49 | + | |
50 | +int board_early_init_r(void) | |
51 | +{ | |
52 | + /* Set NAND !WP to 1 through GPO_19 */ | |
53 | + gpio_request(GPO_19, "NAND_nWP"); | |
54 | + gpio_direction_output(GPO_19, 1); | |
55 | + | |
56 | + /* initialize display */ | |
57 | + work_92105_display_init(); | |
58 | + | |
59 | + return 0; | |
60 | +} | |
61 | + | |
62 | +int board_init(void) | |
63 | +{ | |
64 | + reset_periph(); | |
65 | + /* adress of boot parameters */ | |
66 | + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; | |
67 | + | |
68 | + return 0; | |
69 | +} | |
70 | + | |
71 | +int dram_init(void) | |
72 | +{ | |
73 | + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, | |
74 | + CONFIG_SYS_SDRAM_SIZE); | |
75 | + | |
76 | + return 0; | |
77 | +} |
board/work-microwave/work_92105/work_92105_display.c
1 | +/* | |
2 | + * work_92105 display support | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * The work_92105 display is a HD44780-compatible module | |
8 | + * controlled through a MAX6957AAX SPI port expander, two | |
9 | + * MAX518 I2C DACs and native LPC32xx GPO 15. | |
10 | + * | |
11 | + * SPDX-License-Identifier: GPL-2.0+ | |
12 | + */ | |
13 | + | |
14 | +#include <common.h> | |
15 | +#include <asm/arch/sys_proto.h> | |
16 | +#include <asm/arch/cpu.h> | |
17 | +#include <asm/arch/emc.h> | |
18 | +#include <asm/gpio.h> | |
19 | +#include <spi.h> | |
20 | +#include <i2c.h> | |
21 | +#include <version.h> | |
22 | +#include <vsprintf.h> | |
23 | + | |
24 | +/* | |
25 | + * GPO 15 in port 3 is gpio 3*32+15 = 111 | |
26 | + */ | |
27 | + | |
28 | +#define GPO_15 111 | |
29 | + | |
30 | +/** | |
31 | + * MAX6957AAX registers that we will be using | |
32 | + */ | |
33 | + | |
34 | +#define MAX6957_CONF 0x04 | |
35 | + | |
36 | +#define MAX6957_CONF_08_11 0x0A | |
37 | +#define MAX6957_CONF_12_15 0x0B | |
38 | +#define MAX6957_CONF_16_19 0x0C | |
39 | + | |
40 | +/** | |
41 | + * Individual gpio ports (one per gpio) to HD44780 | |
42 | + */ | |
43 | + | |
44 | +#define MAX6957AAX_HD44780_RS 0x29 | |
45 | +#define MAX6957AAX_HD44780_R_W 0x2A | |
46 | +#define MAX6957AAX_HD44780_EN 0x2B | |
47 | +#define MAX6957AAX_HD44780_DATA 0x4C | |
48 | + | |
49 | +/** | |
50 | + * Display controller instructions | |
51 | + */ | |
52 | + | |
53 | +/* Function set: eight bits, two lines, 8-dot font */ | |
54 | +#define HD44780_FUNCTION_SET 0x38 | |
55 | + | |
56 | +/* Display ON / OFF: turn display on */ | |
57 | +#define HD44780_DISPLAY_ON_OFF_CONTROL 0x0C | |
58 | + | |
59 | +/* Entry mode: increment */ | |
60 | +#define HD44780_ENTRY_MODE_SET 0x06 | |
61 | + | |
62 | +/* Clear */ | |
63 | +#define HD44780_CLEAR_DISPLAY 0x01 | |
64 | + | |
65 | +/* Set DDRAM addr (to be ORed with exact address) */ | |
66 | +#define HD44780_SET_DDRAM_ADDR 0x80 | |
67 | + | |
68 | +/* Set CGRAM addr (to be ORed with exact address) */ | |
69 | +#define HD44780_SET_CGRAM_ADDR 0x40 | |
70 | + | |
71 | +/** | |
72 | + * Default value for contrats | |
73 | + */ | |
74 | + | |
75 | +#define CONTRAST_DEFAULT 25 | |
76 | + | |
77 | +/** | |
78 | + * Define slave as a module-wide local to save passing it around, | |
79 | + * plus we will need it after init for the "hd44780" command. | |
80 | + */ | |
81 | + | |
82 | +static struct spi_slave *slave; | |
83 | + | |
84 | +/* | |
85 | + * Write a value into a MAX6957AAX register. | |
86 | + */ | |
87 | + | |
88 | +static void max6957aax_write(uint8_t reg, uint8_t value) | |
89 | +{ | |
90 | + uint8_t dout[2]; | |
91 | + | |
92 | + dout[0] = reg; | |
93 | + dout[1] = value; | |
94 | + gpio_set_value(GPO_15, 0); | |
95 | + /* do SPI read/write (passing din==dout is OK) */ | |
96 | + spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END); | |
97 | + gpio_set_value(GPO_15, 1); | |
98 | +} | |
99 | + | |
100 | +/* | |
101 | + * Read a value from a MAX6957AAX register. | |
102 | + * | |
103 | + * According to the MAX6957AAX datasheet, we should release the chip | |
104 | + * select halfway through the read sequence, when the actual register | |
105 | + * value is read; but the WORK_92105 hardware prevents the MAX6957AAX | |
106 | + * SPI OUT from reaching the LPC32XX SIP MISO if chip is not selected. | |
107 | + * so let's release the CS an hold it again while reading the result. | |
108 | + */ | |
109 | + | |
110 | +static uint8_t max6957aax_read(uint8_t reg) | |
111 | +{ | |
112 | + uint8_t dout[2], din[2]; | |
113 | + | |
114 | + /* send read command */ | |
115 | + dout[0] = reg | 0x80; /* set bit 7 to indicate read */ | |
116 | + dout[1] = 0; | |
117 | + gpio_set_value(GPO_15, 0); | |
118 | + /* do SPI read/write (passing din==dout is OK) */ | |
119 | + spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END); | |
120 | + /* latch read command */ | |
121 | + gpio_set_value(GPO_15, 1); | |
122 | + /* read register -- din = noop on xmit, din[1] = reg on recv */ | |
123 | + din[0] = 0; | |
124 | + din[1] = 0; | |
125 | + gpio_set_value(GPO_15, 0); | |
126 | + /* do SPI read/write (passing din==dout is OK) */ | |
127 | + spi_xfer(slave, 16, din, din, SPI_XFER_BEGIN | SPI_XFER_END); | |
128 | + /* end of read. */ | |
129 | + gpio_set_value(GPO_15, 1); | |
130 | + return din[1]; | |
131 | +} | |
132 | + | |
133 | +static void hd44780_instruction(unsigned long instruction) | |
134 | +{ | |
135 | + max6957aax_write(MAX6957AAX_HD44780_RS, 0); | |
136 | + max6957aax_write(MAX6957AAX_HD44780_R_W, 0); | |
137 | + max6957aax_write(MAX6957AAX_HD44780_EN, 1); | |
138 | + max6957aax_write(MAX6957AAX_HD44780_DATA, instruction); | |
139 | + max6957aax_write(MAX6957AAX_HD44780_EN, 0); | |
140 | + /* HD44780 takes 37 us for most instructions, 1520 for clear */ | |
141 | + if (instruction == HD44780_CLEAR_DISPLAY) | |
142 | + udelay(2000); | |
143 | + else | |
144 | + udelay(100); | |
145 | +} | |
146 | + | |
147 | +static void hd44780_write_char(char c) | |
148 | +{ | |
149 | + max6957aax_write(MAX6957AAX_HD44780_RS, 1); | |
150 | + max6957aax_write(MAX6957AAX_HD44780_R_W, 0); | |
151 | + max6957aax_write(MAX6957AAX_HD44780_EN, 1); | |
152 | + max6957aax_write(MAX6957AAX_HD44780_DATA, c); | |
153 | + max6957aax_write(MAX6957AAX_HD44780_EN, 0); | |
154 | + /* HD44780 takes 37 us to write to DDRAM or CGRAM */ | |
155 | + udelay(100); | |
156 | +} | |
157 | + | |
158 | +static void hd44780_write_str(char *s) | |
159 | +{ | |
160 | + max6957aax_write(MAX6957AAX_HD44780_RS, 1); | |
161 | + max6957aax_write(MAX6957AAX_HD44780_R_W, 0); | |
162 | + while (*s) { | |
163 | + max6957aax_write(MAX6957AAX_HD44780_EN, 1); | |
164 | + max6957aax_write(MAX6957AAX_HD44780_DATA, *s); | |
165 | + max6957aax_write(MAX6957AAX_HD44780_EN, 0); | |
166 | + s++; | |
167 | + /* HD44780 takes 37 us to write to DDRAM or CGRAM */ | |
168 | + udelay(100); | |
169 | + } | |
170 | +} | |
171 | + | |
172 | +/* | |
173 | + * Existing user code might expect these custom characters to be | |
174 | + * recognized and displayed on the LCD | |
175 | + */ | |
176 | + | |
177 | +static u8 char_gen_chars[] = { | |
178 | + /* #8, empty rectangle */ | |
179 | + 0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F, | |
180 | + /* #9, filled right arrow */ | |
181 | + 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00, | |
182 | + /* #10, filled left arrow */ | |
183 | + 0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, | |
184 | + /* #11, up and down arrow */ | |
185 | + 0x04, 0x0E, 0x1F, 0x00, 0x00, 0x1F, 0x0E, 0x04, | |
186 | + /* #12, plus/minus */ | |
187 | + 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F, 0x00, | |
188 | + /* #13, fat exclamation mark */ | |
189 | + 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, | |
190 | + /* #14, empty square */ | |
191 | + 0x00, 0x1F, 0x11, 0x11, 0x11, 0x1F, 0x00, 0x00, | |
192 | + /* #15, struck out square */ | |
193 | + 0x00, 0x1F, 0x19, 0x15, 0x13, 0x1F, 0x00, 0x00, | |
194 | +}; | |
195 | + | |
196 | +static void hd44780_init_char_gen(void) | |
197 | +{ | |
198 | + int i; | |
199 | + | |
200 | + hd44780_instruction(HD44780_SET_CGRAM_ADDR); | |
201 | + | |
202 | + for (i = 0; i < sizeof(char_gen_chars); i++) | |
203 | + hd44780_write_char(char_gen_chars[i]); | |
204 | + | |
205 | + hd44780_instruction(HD44780_SET_DDRAM_ADDR); | |
206 | +} | |
207 | + | |
208 | +void work_92105_display_init(void) | |
209 | +{ | |
210 | + int claim_err; | |
211 | + char *display_contrast_str; | |
212 | + uint8_t display_contrast = CONTRAST_DEFAULT; | |
213 | + uint8_t enable_backlight = 0x96; | |
214 | + | |
215 | + slave = spi_setup_slave(0, 0, 500000, 0); | |
216 | + | |
217 | + if (!slave) { | |
218 | + printf("Failed to set up SPI slave\n"); | |
219 | + return; | |
220 | + } | |
221 | + | |
222 | + claim_err = spi_claim_bus(slave); | |
223 | + | |
224 | + if (claim_err) | |
225 | + debug("Failed to claim SPI bus: %d\n", claim_err); | |
226 | + | |
227 | + /* enable backlight */ | |
228 | + i2c_write(0x2c, 0x01, 1, &enable_backlight, 1); | |
229 | + | |
230 | + /* set display contrast */ | |
231 | + display_contrast_str = getenv("fwopt_dispcontrast"); | |
232 | + if (display_contrast_str) | |
233 | + display_contrast = simple_strtoul(display_contrast_str, | |
234 | + NULL, 10); | |
235 | + i2c_write(0x2c, 0x00, 1, &display_contrast, 1); | |
236 | + | |
237 | + /* request GPO_15 as an output initially set to 1 */ | |
238 | + gpio_request(GPO_15, "MAX6957_nCS"); | |
239 | + gpio_direction_output(GPO_15, 1); | |
240 | + | |
241 | + /* enable MAX6957 portexpander */ | |
242 | + max6957aax_write(MAX6957_CONF, 0x01); | |
243 | + /* configure pin 8 as input, pins 9..19 as outputs */ | |
244 | + max6957aax_write(MAX6957_CONF_08_11, 0x56); | |
245 | + max6957aax_write(MAX6957_CONF_12_15, 0x55); | |
246 | + max6957aax_write(MAX6957_CONF_16_19, 0x55); | |
247 | + | |
248 | + /* initialize HD44780 */ | |
249 | + max6957aax_write(MAX6957AAX_HD44780_EN, 0); | |
250 | + hd44780_instruction(HD44780_FUNCTION_SET); | |
251 | + hd44780_instruction(HD44780_DISPLAY_ON_OFF_CONTROL); | |
252 | + hd44780_instruction(HD44780_ENTRY_MODE_SET); | |
253 | + | |
254 | + /* write custom character glyphs */ | |
255 | + hd44780_init_char_gen(); | |
256 | + | |
257 | + /* Show U-Boot version, date and time as a sign-of-life */ | |
258 | + hd44780_instruction(HD44780_CLEAR_DISPLAY); | |
259 | + hd44780_instruction(HD44780_SET_DDRAM_ADDR | 0); | |
260 | + hd44780_write_str(U_BOOT_VERSION); | |
261 | + hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64); | |
262 | + hd44780_write_str(U_BOOT_DATE); | |
263 | + hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64 | 20); | |
264 | + hd44780_write_str(U_BOOT_TIME); | |
265 | +} | |
266 | + | |
267 | +#ifdef CONFIG_CMD_MAX6957 | |
268 | + | |
269 | +static int do_max6957aax(cmd_tbl_t *cmdtp, int flag, int argc, | |
270 | + char *const argv[]) | |
271 | +{ | |
272 | + int reg, val; | |
273 | + | |
274 | + if (argc != 3) | |
275 | + return CMD_RET_USAGE; | |
276 | + switch (argv[1][0]) { | |
277 | + case 'r': | |
278 | + case 'R': | |
279 | + reg = simple_strtoul(argv[2], NULL, 0); | |
280 | + val = max6957aax_read(reg); | |
281 | + printf("MAX6957 reg 0x%02x read 0x%02x\n", reg, val); | |
282 | + return 0; | |
283 | + default: | |
284 | + reg = simple_strtoul(argv[1], NULL, 0); | |
285 | + val = simple_strtoul(argv[2], NULL, 0); | |
286 | + max6957aax_write(reg, val); | |
287 | + printf("MAX6957 reg 0x%02x wrote 0x%02x\n", reg, val); | |
288 | + return 0; | |
289 | + } | |
290 | + return 1; | |
291 | +} | |
292 | + | |
293 | +#ifdef CONFIG_SYS_LONGHELP | |
294 | +static char max6957aax_help_text[] = | |
295 | + "max6957aax - write or read display register:\n" | |
296 | + "\tmax6957aax R|r reg - read display register;\n" | |
297 | + "\tmax6957aax reg val - write display register."; | |
298 | +#endif | |
299 | + | |
300 | +U_BOOT_CMD( | |
301 | + max6957aax, 6, 1, do_max6957aax, | |
302 | + "SPI MAX6957 display write/read", | |
303 | + max6957aax_help_text | |
304 | +); | |
305 | +#endif /* CONFIG_CMD_MAX6957 */ | |
306 | + | |
307 | +#ifdef CONFIG_CMD_HD44760 | |
308 | + | |
309 | +/* | |
310 | + * We need the HUSH parser because we need string arguments, and | |
311 | + * only HUSH can understand them. | |
312 | + */ | |
313 | + | |
314 | +#if !defined(CONFIG_SYS_HUSH_PARSER) | |
315 | +#error CONFIG_CMD_HD44760 requires CONFIG_SYS_HUSH_PARSER | |
316 | +#endif | |
317 | + | |
318 | +static int do_hd44780(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) | |
319 | +{ | |
320 | + char *cmd; | |
321 | + | |
322 | + if (argc != 3) | |
323 | + return CMD_RET_USAGE; | |
324 | + | |
325 | + cmd = argv[1]; | |
326 | + | |
327 | + if (strcasecmp(cmd, "cmd") == 0) | |
328 | + hd44780_instruction(simple_strtol(argv[2], NULL, 0)); | |
329 | + else if (strcasecmp(cmd, "data") == 0) | |
330 | + hd44780_write_char(simple_strtol(argv[2], NULL, 0)); | |
331 | + else if (strcasecmp(cmd, "str") == 0) | |
332 | + hd44780_write_str(argv[2]); | |
333 | + return 0; | |
334 | +} | |
335 | + | |
336 | +#ifdef CONFIG_SYS_LONGHELP | |
337 | +static char hd44780_help_text[] = | |
338 | + "hd44780 - control LCD driver:\n" | |
339 | + "\thd44780 cmd <val> - send command <val> to driver;\n" | |
340 | + "\thd44780 data <val> - send data <val> to driver;\n" | |
341 | + "\thd44780 str \"<text>\" - send \"<text>\" to driver."; | |
342 | +#endif | |
343 | + | |
344 | +U_BOOT_CMD( | |
345 | + hd44780, 6, 1, do_hd44780, | |
346 | + "HD44780 LCD driver control", | |
347 | + hd44780_help_text | |
348 | +); | |
349 | +#endif /* CONFIG_CMD_HD44780 */ |
board/work-microwave/work_92105/work_92105_display.h
1 | +/* | |
2 | + * work_92105 display support interface | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * The work_92105 display is a HD44780-compatible module | |
8 | + * controlled through a MAX6957AAX SPI port expander, two | |
9 | + * MAX518 I2C DACs and native LPC32xx GPO 15. | |
10 | + * | |
11 | + * SPDX-License-Identifier: GPL-2.0+ | |
12 | + */ | |
13 | + | |
14 | +void work_92105_display_init(void); |
board/work-microwave/work_92105/work_92105_spl.c
1 | +/* | |
2 | + * WORK Microwave work_92105 board support | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <asm/io.h> | |
12 | +#include <asm/arch/sys_proto.h> | |
13 | +#include <asm/arch/cpu.h> | |
14 | +#include <asm/arch/emc.h> | |
15 | +#include <asm/gpio.h> | |
16 | +#include <spl.h> | |
17 | +#include "work_92105_display.h" | |
18 | + | |
19 | +struct emc_dram_settings dram_64mb = { | |
20 | + .cmddelay = 0x0001C000, | |
21 | + .config0 = 0x00005682, | |
22 | + .rascas0 = 0x00000302, | |
23 | + .rdconfig = 0x00000011, | |
24 | + .trp = 52631578, | |
25 | + .tras = 20833333, | |
26 | + .tsrex = 12500000, | |
27 | + .twr = 66666666, | |
28 | + .trc = 13888888, | |
29 | + .trfc = 10256410, | |
30 | + .txsr = 12500000, | |
31 | + .trrd = 1, | |
32 | + .tmrd = 1, | |
33 | + .tcdlr = 0, | |
34 | + .refresh = 128000, | |
35 | + .mode = 0x00018000, | |
36 | + .emode = 0x02000000 | |
37 | +}; | |
38 | + | |
39 | +const struct emc_dram_settings dram_128mb = { | |
40 | + .cmddelay = 0x0001C000, | |
41 | + .config0 = 0x00005882, | |
42 | + .rascas0 = 0x00000302, | |
43 | + .rdconfig = 0x00000011, | |
44 | + .trp = 52631578, | |
45 | + .tras = 22222222, | |
46 | + .tsrex = 8333333, | |
47 | + .twr = 66666666, | |
48 | + .trc = 14814814, | |
49 | + .trfc = 10256410, | |
50 | + .txsr = 8333333, | |
51 | + .trrd = 1, | |
52 | + .tmrd = 1, | |
53 | + .tcdlr = 0, | |
54 | + .refresh = 128000, | |
55 | + .mode = 0x00030000, | |
56 | + .emode = 0x02000000 | |
57 | +}; | |
58 | + | |
59 | +void spl_board_init(void) | |
60 | +{ | |
61 | + /* initialize serial port for console */ | |
62 | + lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART); | |
63 | + /* initialize console */ | |
64 | + preloader_console_init(); | |
65 | + /* init DDR and NAND to chainload U-Boot */ | |
66 | + ddr_init(&dram_128mb); | |
67 | + /* | |
68 | + * If this is actually a 64MB module, then the highest column | |
69 | + * bit in any address will be ignored, and thus address 0x80000000 | |
70 | + * should be mirrored at address 0x80000800. Test this. | |
71 | + */ | |
72 | + writel(0x31415926, 0x80000000); /* write Pi at 0x80000000 */ | |
73 | + writel(0x16180339, 0x80000800); /* write Phi at 0x80000800 */ | |
74 | + if (readl(0x80000000) == 0x16180339) /* check 0x80000000 */ { | |
75 | + /* actually 64MB mirrored: reconfigure controller */ | |
76 | + ddr_init(&dram_64mb); | |
77 | + } | |
78 | + /* initialize NAND controller to load U-Boot from NAND */ | |
79 | + lpc32xx_mlc_nand_init(); | |
80 | +} | |
81 | + | |
82 | +u32 spl_boot_device(void) | |
83 | +{ | |
84 | + return BOOT_DEVICE_NAND; | |
85 | +} |
common/image.c
... | ... | @@ -149,6 +149,7 @@ |
149 | 149 | { IH_TYPE_MXSIMAGE, "mxsimage", "Freescale MXS Boot Image",}, |
150 | 150 | { IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",}, |
151 | 151 | { IH_TYPE_X86_SETUP, "x86_setup", "x86 setup.bin", }, |
152 | + { IH_TYPE_LPC32XXIMAGE, "lpc32xximage", "LPC32XX Boot Image", }, | |
152 | 153 | { -1, "", "", }, |
153 | 154 | }; |
154 | 155 |
common/spl/spl.c
... | ... | @@ -101,10 +101,22 @@ |
101 | 101 | (int)sizeof(spl_image.name), spl_image.name, |
102 | 102 | spl_image.load_addr, spl_image.size); |
103 | 103 | } else { |
104 | +#ifdef CONFIG_SPL_PANIC_ON_RAW_IMAGE | |
105 | + /* | |
106 | + * CONFIG_SPL_PANIC_ON_RAW_IMAGE is defined when the | |
107 | + * code which loads images in SPL cannot guarantee that | |
108 | + * absolutely all read errors will be reported. | |
109 | + * An example is the LPC32XX MLC NAND driver, which | |
110 | + * will consider that a completely unreadable NAND block | |
111 | + * is bad, and thus should be skipped silently. | |
112 | + */ | |
113 | + panic("** no mkimage signature but raw image not supported"); | |
114 | +#else | |
104 | 115 | /* Signature not found - assume u-boot.bin */ |
105 | 116 | debug("mkimage signature not found - ih_magic = %x\n", |
106 | 117 | header->ih_magic); |
107 | 118 | spl_set_header_raw_uboot(); |
119 | +#endif | |
108 | 120 | } |
109 | 121 | } |
110 | 122 |
configs/work_92105_defconfig
drivers/gpio/Kconfig
... | ... | @@ -7,4 +7,11 @@ |
7 | 7 | the GPIO uclass. Drivers provide methods to query the |
8 | 8 | particular GPIOs that they provide. The uclass interface |
9 | 9 | is defined in include/asm-generic/gpio.h. |
10 | + | |
11 | +config LPC32XX_GPIO | |
12 | + bool "LPC32XX GPIO driver" | |
13 | + depends on DM | |
14 | + default n | |
15 | + help | |
16 | + Support for the LPC32XX GPIO driver. |
drivers/gpio/Makefile
drivers/gpio/lpc32xx_gpio.c
1 | +/* | |
2 | + * LPC32xxGPIO driver | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <asm/io.h> | |
11 | +#include <asm/arch-lpc32xx/cpu.h> | |
12 | +#include <asm/arch-lpc32xx/gpio.h> | |
13 | +#include <asm-generic/gpio.h> | |
14 | +#include <dm.h> | |
15 | + | |
16 | +/** | |
17 | + * LPC32xx GPIOs work in banks but are non-homogeneous: | |
18 | + * - each bank holds a different number of GPIOs | |
19 | + * - some GPIOs are input/ouput, some input only, some output only; | |
20 | + * - some GPIOs have different meanings as an input and as an output; | |
21 | + * - some GPIOs are controlled on a given port and bit index, but | |
22 | + * read on another one. | |
23 | +* | |
24 | + * In order to keep this code simple, GPIOS are considered here as | |
25 | + * homogeneous and linear, from 0 to 127. | |
26 | + * | |
27 | + * ** WARNING #1 ** | |
28 | + * | |
29 | + * Client code is responsible for properly using valid GPIO numbers, | |
30 | + * including cases where a single physical GPIO has differing numbers | |
31 | + * for setting its direction, reading it and/or writing to it. | |
32 | + * | |
33 | + * ** WARNING #2 ** | |
34 | + * | |
35 | + * Please read NOTE in description of lpc32xx_gpio_get_function(). | |
36 | + */ | |
37 | + | |
38 | +#define LPC32XX_GPIOS 128 | |
39 | + | |
40 | +struct lpc32xx_gpio_platdata { | |
41 | + struct gpio_regs *regs; | |
42 | + /* GPIO FUNCTION: SEE WARNING #2 */ | |
43 | + signed char function[LPC32XX_GPIOS]; | |
44 | +}; | |
45 | + | |
46 | +/** | |
47 | + * We have 4 GPIO ports of 32 bits each | |
48 | + */ | |
49 | + | |
50 | +#define MAX_GPIO 128 | |
51 | + | |
52 | +#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3) | |
53 | +#define GPIO_TO_RANK(gpio) (gpio % 32) | |
54 | +#define GPIO_TO_MASK(gpio) (1 << (gpio % 32)) | |
55 | + | |
56 | +/** | |
57 | + * Configure a GPIO number 'offset' as input | |
58 | + */ | |
59 | + | |
60 | +static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset) | |
61 | +{ | |
62 | + int port, mask; | |
63 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
64 | + struct gpio_regs *regs = gpio_platdata->regs; | |
65 | + | |
66 | + port = GPIO_TO_PORT(offset); | |
67 | + mask = GPIO_TO_MASK(offset); | |
68 | + | |
69 | + switch (port) { | |
70 | + case 0: | |
71 | + writel(mask, ®s->p0_dir_clr); | |
72 | + break; | |
73 | + case 1: | |
74 | + writel(mask, ®s->p1_dir_clr); | |
75 | + break; | |
76 | + case 2: | |
77 | + /* ports 2 and 3 share a common direction */ | |
78 | + case 3: | |
79 | + writel(mask, ®s->p2_p3_dir_clr); | |
80 | + break; | |
81 | + default: | |
82 | + return -1; | |
83 | + } | |
84 | + | |
85 | + /* GPIO FUNCTION: SEE WARNING #2 */ | |
86 | + gpio_platdata->function[offset] = GPIOF_INPUT; | |
87 | + | |
88 | + return 0; | |
89 | +} | |
90 | + | |
91 | +/** | |
92 | + * Get the value of a GPIO | |
93 | + */ | |
94 | + | |
95 | +static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset) | |
96 | +{ | |
97 | + int port, rank, mask, value; | |
98 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
99 | + struct gpio_regs *regs = gpio_platdata->regs; | |
100 | + | |
101 | + port = GPIO_TO_PORT(offset); | |
102 | + | |
103 | + switch (port) { | |
104 | + case 0: | |
105 | + value = readl(®s->p0_inp_state); | |
106 | + break; | |
107 | + case 1: | |
108 | + value = readl(®s->p1_inp_state); | |
109 | + break; | |
110 | + case 2: | |
111 | + value = readl(®s->p2_inp_state); | |
112 | + break; | |
113 | + case 3: | |
114 | + value = readl(®s->p3_inp_state); | |
115 | + break; | |
116 | + default: | |
117 | + return -1; | |
118 | + } | |
119 | + | |
120 | + rank = GPIO_TO_RANK(offset); | |
121 | + mask = GPIO_TO_MASK(offset); | |
122 | + | |
123 | + return (value & mask) >> rank; | |
124 | +} | |
125 | + | |
126 | +/** | |
127 | + * Set a GPIO | |
128 | + */ | |
129 | + | |
130 | +static int gpio_set(struct udevice *dev, unsigned gpio) | |
131 | +{ | |
132 | + int port, mask; | |
133 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
134 | + struct gpio_regs *regs = gpio_platdata->regs; | |
135 | + | |
136 | + port = GPIO_TO_PORT(gpio); | |
137 | + mask = GPIO_TO_MASK(gpio); | |
138 | + | |
139 | + switch (port) { | |
140 | + case 0: | |
141 | + writel(mask, ®s->p0_outp_set); | |
142 | + break; | |
143 | + case 1: | |
144 | + writel(mask, ®s->p1_outp_set); | |
145 | + break; | |
146 | + case 2: | |
147 | + writel(mask, ®s->p2_outp_set); | |
148 | + break; | |
149 | + case 3: | |
150 | + writel(mask, ®s->p3_outp_set); | |
151 | + break; | |
152 | + default: | |
153 | + return -1; | |
154 | + } | |
155 | + return 0; | |
156 | +} | |
157 | + | |
158 | +/** | |
159 | + * Clear a GPIO | |
160 | + */ | |
161 | + | |
162 | +static int gpio_clr(struct udevice *dev, unsigned gpio) | |
163 | +{ | |
164 | + int port, mask; | |
165 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
166 | + struct gpio_regs *regs = gpio_platdata->regs; | |
167 | + | |
168 | + port = GPIO_TO_PORT(gpio); | |
169 | + mask = GPIO_TO_MASK(gpio); | |
170 | + | |
171 | + switch (port) { | |
172 | + case 0: | |
173 | + writel(mask, ®s->p0_outp_clr); | |
174 | + break; | |
175 | + case 1: | |
176 | + writel(mask, ®s->p1_outp_clr); | |
177 | + break; | |
178 | + case 2: | |
179 | + writel(mask, ®s->p2_outp_clr); | |
180 | + break; | |
181 | + case 3: | |
182 | + writel(mask, ®s->p3_outp_clr); | |
183 | + break; | |
184 | + default: | |
185 | + return -1; | |
186 | + } | |
187 | + return 0; | |
188 | +} | |
189 | + | |
190 | +/** | |
191 | + * Set the value of a GPIO | |
192 | + */ | |
193 | + | |
194 | +static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset, | |
195 | + int value) | |
196 | +{ | |
197 | + if (value) | |
198 | + return gpio_set(dev, offset); | |
199 | + else | |
200 | + return gpio_clr(dev, offset); | |
201 | +} | |
202 | + | |
203 | +/** | |
204 | + * Configure a GPIO number 'offset' as output with given initial value. | |
205 | + */ | |
206 | + | |
207 | +static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset, | |
208 | + int value) | |
209 | +{ | |
210 | + int port, mask; | |
211 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
212 | + struct gpio_regs *regs = gpio_platdata->regs; | |
213 | + | |
214 | + port = GPIO_TO_PORT(offset); | |
215 | + mask = GPIO_TO_MASK(offset); | |
216 | + | |
217 | + switch (port) { | |
218 | + case 0: | |
219 | + writel(mask, ®s->p0_dir_set); | |
220 | + break; | |
221 | + case 1: | |
222 | + writel(mask, ®s->p1_dir_set); | |
223 | + break; | |
224 | + case 2: | |
225 | + /* ports 2 and 3 share a common direction */ | |
226 | + case 3: | |
227 | + writel(mask, ®s->p2_p3_dir_set); | |
228 | + break; | |
229 | + default: | |
230 | + return -1; | |
231 | + } | |
232 | + | |
233 | + /* GPIO FUNCTION: SEE WARNING #2 */ | |
234 | + gpio_platdata->function[offset] = GPIOF_OUTPUT; | |
235 | + | |
236 | + return lpc32xx_gpio_set_value(dev, offset, value); | |
237 | +} | |
238 | + | |
239 | +/** | |
240 | + * GPIO functions are supposed to be computed from their current | |
241 | + * configuration, but that's way too complicated in LPC32XX. A simpler | |
242 | + * approach is used, where the GPIO functions are cached in an array. | |
243 | + * When the GPIO is in use, its function is either "input" or "output" | |
244 | + * depending on its direction, otherwise its function is "unknown". | |
245 | + * | |
246 | + * ** NOTE ** | |
247 | + * | |
248 | + * THIS APPROACH WAS CHOSEN DU TO THE COMPLEX NATURE OF THE LPC32XX | |
249 | + * GPIOS; DO NOT TAKE THIS AS AN EXAMPLE FOR NEW CODE. | |
250 | + */ | |
251 | + | |
252 | +static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset) | |
253 | +{ | |
254 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
255 | + return gpio_platdata->function[offset]; | |
256 | +} | |
257 | + | |
258 | +static const struct dm_gpio_ops gpio_lpc32xx_ops = { | |
259 | + .direction_input = lpc32xx_gpio_direction_input, | |
260 | + .direction_output = lpc32xx_gpio_direction_output, | |
261 | + .get_value = lpc32xx_gpio_get_value, | |
262 | + .set_value = lpc32xx_gpio_set_value, | |
263 | + .get_function = lpc32xx_gpio_get_function, | |
264 | +}; | |
265 | + | |
266 | +static int lpc32xx_gpio_probe(struct udevice *dev) | |
267 | +{ | |
268 | + struct lpc32xx_gpio_platdata *gpio_platdata = dev_get_platdata(dev); | |
269 | + struct gpio_dev_priv *uc_priv = dev->uclass_priv; | |
270 | + | |
271 | + if (dev->of_offset == -1) { | |
272 | + /* Tell the uclass how many GPIOs we have */ | |
273 | + uc_priv->gpio_count = LPC32XX_GPIOS; | |
274 | + } | |
275 | + | |
276 | + /* set base address for GPIO registers */ | |
277 | + gpio_platdata->regs = (struct gpio_regs *)GPIO_BASE; | |
278 | + | |
279 | + /* all GPIO functions are unknown until requested */ | |
280 | + /* GPIO FUNCTION: SEE WARNING #2 */ | |
281 | + memset(gpio_platdata->function, GPIOF_UNKNOWN, | |
282 | + sizeof(gpio_platdata->function)); | |
283 | + | |
284 | + return 0; | |
285 | +} | |
286 | + | |
287 | +U_BOOT_DRIVER(gpio_lpc32xx) = { | |
288 | + .name = "gpio_lpc32xx", | |
289 | + .id = UCLASS_GPIO, | |
290 | + .ops = &gpio_lpc32xx_ops, | |
291 | + .probe = lpc32xx_gpio_probe, | |
292 | + .priv_auto_alloc_size = sizeof(struct lpc32xx_gpio_platdata), | |
293 | +}; |
drivers/hwmon/Makefile
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | obj-$(CONFIG_DTT_DS1621) += ds1621.o |
16 | 16 | obj-$(CONFIG_DTT_DS1722) += ds1722.o |
17 | 17 | obj-$(CONFIG_DTT_DS1775) += ds1775.o |
18 | +obj-$(CONFIG_DTT_DS620) += ds620.o | |
18 | 19 | obj-$(CONFIG_DTT_LM63) += lm63.o |
19 | 20 | obj-$(CONFIG_DTT_LM73) += lm73.o |
20 | 21 | obj-$(CONFIG_DTT_LM75) += lm75.o |
drivers/hwmon/ds620.c
1 | +/* | |
2 | + * DS620 DTT support | |
3 | + * | |
4 | + * (C) Copyright 2014 3ADEV <http://www.3adev.com> | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +/* | |
11 | + * Dallas Semiconductor's DS1621/1631 Digital Thermometer and Thermostat. | |
12 | + */ | |
13 | + | |
14 | +#include <common.h> | |
15 | +#include <i2c.h> | |
16 | +#include <dtt.h> | |
17 | + | |
18 | +/* | |
19 | + * Device code | |
20 | + */ | |
21 | +#define DTT_I2C_DEV_CODE 0x48 | |
22 | +#define DTT_START_CONVERT 0x51 | |
23 | +#define DTT_TEMP 0xAA | |
24 | +#define DTT_CONFIG 0xAC | |
25 | + | |
26 | +/* | |
27 | + * Config register MSB bits | |
28 | + */ | |
29 | +#define DTT_CONFIG_1SHOT 0x01 | |
30 | +#define DTT_CONFIG_AUTOC 0x02 | |
31 | +#define DTT_CONFIG_R0 0x04 /* always 1 */ | |
32 | +#define DTT_CONFIG_R1 0x08 /* always 1 */ | |
33 | +#define DTT_CONFIG_TLF 0x10 | |
34 | +#define DTT_CONFIG_THF 0x20 | |
35 | +#define DTT_CONFIG_NVB 0x40 | |
36 | +#define DTT_CONFIG_DONE 0x80 | |
37 | + | |
38 | +#define CHIP(sensor) (DTT_I2C_DEV_CODE + (sensor & 0x07)) | |
39 | + | |
40 | +int dtt_init_one(int sensor) | |
41 | +{ | |
42 | + uint8_t config = DTT_CONFIG_1SHOT | |
43 | + | DTT_CONFIG_R0 | |
44 | + | DTT_CONFIG_R1; | |
45 | + return i2c_write(CHIP(sensor), DTT_CONFIG, 1, &config, 1); | |
46 | +} | |
47 | + | |
48 | +int dtt_get_temp(int sensor) | |
49 | +{ | |
50 | + uint8_t status; | |
51 | + uint8_t temp[2]; | |
52 | + | |
53 | + /* Start a conversion, may take up to 1 second. */ | |
54 | + i2c_write(CHIP(sensor), DTT_START_CONVERT, 1, NULL, 0); | |
55 | + do { | |
56 | + if (i2c_read(CHIP(sensor), DTT_CONFIG, 1, &status, 1)) | |
57 | + /* bail out if I2C error */ | |
58 | + status |= DTT_CONFIG_DONE; | |
59 | + } while (!(status & DTT_CONFIG_DONE)); | |
60 | + if (i2c_read(CHIP(sensor), DTT_TEMP, 1, temp, 2)) | |
61 | + /* bail out if I2C error */ | |
62 | + return -274; /* below absolute zero == error */ | |
63 | + | |
64 | + return ((int16_t)(temp[1] | (temp[0] << 8))) >> 7; | |
65 | +} |
drivers/i2c/Makefile
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 | obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o |
21 | 21 | obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o |
22 | 22 | obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o |
23 | +obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o | |
23 | 24 | obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o |
24 | 25 | obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o |
25 | 26 | obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o |
drivers/i2c/lpc32xx_i2c.c
1 | +/* | |
2 | + * LPC32xx I2C interface driver | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <asm/io.h> | |
12 | +#include <i2c.h> | |
13 | +#include <asm/errno.h> | |
14 | +#include <asm/arch/clk.h> | |
15 | + | |
16 | +/* | |
17 | + * Provide default speed and slave if target did not | |
18 | + */ | |
19 | + | |
20 | +#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED) | |
21 | +#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000 | |
22 | +#endif | |
23 | + | |
24 | +#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE) | |
25 | +#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0 | |
26 | +#endif | |
27 | + | |
28 | +/* i2c register set */ | |
29 | +struct lpc32xx_i2c_registers { | |
30 | + union { | |
31 | + u32 rx; | |
32 | + u32 tx; | |
33 | + }; | |
34 | + u32 stat; | |
35 | + u32 ctrl; | |
36 | + u32 clk_hi; | |
37 | + u32 clk_lo; | |
38 | + u32 adr; | |
39 | + u32 rxfl; | |
40 | + u32 txfl; | |
41 | + u32 rxb; | |
42 | + u32 txb; | |
43 | + u32 stx; | |
44 | + u32 stxfl; | |
45 | +}; | |
46 | + | |
47 | +/* TX register fields */ | |
48 | +#define LPC32XX_I2C_TX_START 0x00000100 | |
49 | +#define LPC32XX_I2C_TX_STOP 0x00000200 | |
50 | + | |
51 | +/* Control register values */ | |
52 | +#define LPC32XX_I2C_SOFT_RESET 0x00000100 | |
53 | + | |
54 | +/* Status register values */ | |
55 | +#define LPC32XX_I2C_STAT_TFF 0x00000400 | |
56 | +#define LPC32XX_I2C_STAT_RFE 0x00000200 | |
57 | +#define LPC32XX_I2C_STAT_DRMI 0x00000008 | |
58 | +#define LPC32XX_I2C_STAT_NAI 0x00000004 | |
59 | +#define LPC32XX_I2C_STAT_TDI 0x00000001 | |
60 | + | |
61 | +static struct lpc32xx_i2c_registers *lpc32xx_i2c[] = { | |
62 | + (struct lpc32xx_i2c_registers *)I2C1_BASE, | |
63 | + (struct lpc32xx_i2c_registers *)I2C2_BASE | |
64 | +}; | |
65 | + | |
66 | +/* Set I2C bus speed */ | |
67 | +static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap, | |
68 | + unsigned int speed) | |
69 | +{ | |
70 | + int half_period; | |
71 | + | |
72 | + if (speed == 0) | |
73 | + return -EINVAL; | |
74 | + | |
75 | + half_period = (105000000 / speed) / 2; | |
76 | + | |
77 | + if ((half_period > 255) || (half_period < 0)) | |
78 | + return -EINVAL; | |
79 | + | |
80 | + writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi); | |
81 | + writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo); | |
82 | + return 0; | |
83 | +} | |
84 | + | |
85 | +/* I2C init called by cmd_i2c when doing 'i2c reset'. */ | |
86 | +static void _i2c_init(struct i2c_adapter *adap, | |
87 | + int requested_speed, int slaveadd) | |
88 | +{ | |
89 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
90 | + | |
91 | + /* soft reset (auto-clears) */ | |
92 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
93 | + /* set HI and LO periods for about 350 kHz */ | |
94 | + lpc32xx_i2c_set_bus_speed(adap, requested_speed); | |
95 | +} | |
96 | + | |
97 | +/* I2C probe called by cmd_i2c when doing 'i2c probe'. */ | |
98 | +static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev) | |
99 | +{ | |
100 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
101 | + int stat; | |
102 | + | |
103 | + /* Soft-reset the controller */ | |
104 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
105 | + while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET) | |
106 | + ; | |
107 | + /* Addre slave for write with start before and stop after */ | |
108 | + writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP, | |
109 | + &i2c->tx); | |
110 | + /* wait for end of transation */ | |
111 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
112 | + ; | |
113 | + /* was there no acknowledge? */ | |
114 | + return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0; | |
115 | +} | |
116 | + | |
117 | +/* | |
118 | + * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c | |
119 | + * Begin write, send address byte(s), begin read, receive data bytes, end. | |
120 | + */ | |
121 | +static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, | |
122 | + int alen, u8 *data, int length) | |
123 | +{ | |
124 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
125 | + int stat, wlen; | |
126 | + | |
127 | + /* Soft-reset the controller */ | |
128 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
129 | + while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET) | |
130 | + ; | |
131 | + /* do we need to write an address at all? */ | |
132 | + if (alen) { | |
133 | + /* Address slave in write mode */ | |
134 | + writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx); | |
135 | + /* write address bytes */ | |
136 | + while (alen--) { | |
137 | + /* compute address byte + stop for the last one */ | |
138 | + int a = (addr >> (8 * alen)) & 0xff; | |
139 | + if (!alen) | |
140 | + a |= LPC32XX_I2C_TX_STOP; | |
141 | + /* Send address byte */ | |
142 | + writel(a, &i2c->tx); | |
143 | + } | |
144 | + /* wait for end of transation */ | |
145 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
146 | + ; | |
147 | + /* clear end-of-transaction flag */ | |
148 | + writel(1, &i2c->stat); | |
149 | + } | |
150 | + /* do we have to read data at all? */ | |
151 | + if (length) { | |
152 | + /* Address slave in read mode */ | |
153 | + writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx); | |
154 | + wlen = length; | |
155 | + /* get data */ | |
156 | + while (length | wlen) { | |
157 | + /* read status for TFF and RFE */ | |
158 | + stat = readl(&i2c->stat); | |
159 | + /* must we, can we write a trigger byte? */ | |
160 | + if ((wlen > 0) | |
161 | + & (!(stat & LPC32XX_I2C_STAT_TFF))) { | |
162 | + wlen--; | |
163 | + /* write trigger byte + stop if last */ | |
164 | + writel(wlen ? 0 : | |
165 | + LPC32XX_I2C_TX_STOP, &i2c->tx); | |
166 | + } | |
167 | + /* must we, can we read a data byte? */ | |
168 | + if ((length > 0) | |
169 | + & (!(stat & LPC32XX_I2C_STAT_RFE))) { | |
170 | + length--; | |
171 | + /* read byte */ | |
172 | + *(data++) = readl(&i2c->rx); | |
173 | + } | |
174 | + } | |
175 | + } | |
176 | + /* wait for end of transation */ | |
177 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
178 | + ; | |
179 | + /* clear end-of-transaction flag */ | |
180 | + writel(1, &i2c->stat); | |
181 | + /* success */ | |
182 | + return 0; | |
183 | +} | |
184 | + | |
185 | +/* | |
186 | + * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c | |
187 | + * Begin write, send address byte(s), send data bytes, end. | |
188 | + */ | |
189 | +static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, | |
190 | + int alen, u8 *data, int length) | |
191 | +{ | |
192 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
193 | + int stat; | |
194 | + | |
195 | + /* Soft-reset the controller */ | |
196 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
197 | + while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET) | |
198 | + ; | |
199 | + /* do we need to write anything at all? */ | |
200 | + if (alen | length) | |
201 | + /* Address slave in write mode */ | |
202 | + writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx); | |
203 | + /* write address bytes */ | |
204 | + while (alen) { | |
205 | + /* wait for transmit fifo not full */ | |
206 | + stat = readl(&i2c->stat); | |
207 | + if (!(stat & LPC32XX_I2C_STAT_TFF)) { | |
208 | + alen--; | |
209 | + int a = (addr >> (8 * alen)) & 0xff; | |
210 | + if (!(alen | length)) | |
211 | + a |= LPC32XX_I2C_TX_STOP; | |
212 | + /* Send address byte */ | |
213 | + writel(a, &i2c->tx); | |
214 | + } | |
215 | + } | |
216 | + while (length) { | |
217 | + /* wait for transmit fifo not full */ | |
218 | + stat = readl(&i2c->stat); | |
219 | + if (!(stat & LPC32XX_I2C_STAT_TFF)) { | |
220 | + /* compute data byte, add stop if length==0 */ | |
221 | + length--; | |
222 | + int d = *(data++); | |
223 | + if (!length) | |
224 | + d |= LPC32XX_I2C_TX_STOP; | |
225 | + /* Send data byte */ | |
226 | + writel(d, &i2c->tx); | |
227 | + } | |
228 | + } | |
229 | + /* wait for end of transation */ | |
230 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
231 | + ; | |
232 | + /* clear end-of-transaction flag */ | |
233 | + writel(1, &i2c->stat); | |
234 | + return 0; | |
235 | +} | |
236 | + | |
237 | +U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, _i2c_init, lpc32xx_i2c_probe, | |
238 | + lpc32xx_i2c_read, lpc32xx_i2c_write, | |
239 | + lpc32xx_i2c_set_bus_speed, | |
240 | + CONFIG_SYS_I2C_LPC32XX_SPEED, | |
241 | + CONFIG_SYS_I2C_LPC32XX_SLAVE, | |
242 | + 0) | |
243 | + | |
244 | +U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, _i2c_init, lpc32xx_i2c_probe, | |
245 | + lpc32xx_i2c_read, lpc32xx_i2c_write, | |
246 | + lpc32xx_i2c_set_bus_speed, | |
247 | + CONFIG_SYS_I2C_LPC32XX_SPEED, | |
248 | + CONFIG_SYS_I2C_LPC32XX_SLAVE, | |
249 | + 1) |
drivers/mtd/nand/Makefile
... | ... | @@ -52,6 +52,7 @@ |
52 | 52 | obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o |
53 | 53 | obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o |
54 | 54 | obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o |
55 | +obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o | |
55 | 56 | obj-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o |
56 | 57 | obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o |
57 | 58 | obj-$(CONFIG_NAND_MXC) += mxc_nand.o |
drivers/mtd/nand/lpc32xx_nand_mlc.c
1 | +/* | |
2 | + * LPC32xx MLC NAND flash controller driver | |
3 | + * | |
4 | + * (C) Copyright 2014 3ADEV <http://3adev.com> | |
5 | + * Written by Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + * | |
9 | + * NOTE: | |
10 | + * | |
11 | + * The MLC NAND flash controller provides hardware Reed-Solomon ECC | |
12 | + * covering in- and out-of-band data together. Therefore, in- and out- | |
13 | + * of-band data must be written together in order to have a valid ECC. | |
14 | + * | |
15 | + * Consequently, pages with meaningful in-band data are written with | |
16 | + * blank (all-ones) out-of-band data and a valid ECC, and any later | |
17 | + * out-of-band data write will void the ECC. | |
18 | + * | |
19 | + * Therefore, code which reads such late-written out-of-band data | |
20 | + * should not rely on the ECC validity. | |
21 | + */ | |
22 | + | |
23 | +#include <common.h> | |
24 | +#include <nand.h> | |
25 | +#include <asm/errno.h> | |
26 | +#include <asm/io.h> | |
27 | +#include <nand.h> | |
28 | +#include <asm/arch/clk.h> | |
29 | +#include <asm/arch/sys_proto.h> | |
30 | + | |
31 | +/* | |
32 | + * MLC NAND controller registers. | |
33 | + */ | |
34 | +struct lpc32xx_nand_mlc_registers { | |
35 | + u8 buff[32768]; /* controller's serial data buffer */ | |
36 | + u8 data[32768]; /* NAND's raw data buffer */ | |
37 | + u32 cmd; | |
38 | + u32 addr; | |
39 | + u32 ecc_enc_reg; | |
40 | + u32 ecc_dec_reg; | |
41 | + u32 ecc_auto_enc_reg; | |
42 | + u32 ecc_auto_dec_reg; | |
43 | + u32 rpr; | |
44 | + u32 wpr; | |
45 | + u32 rubp; | |
46 | + u32 robp; | |
47 | + u32 sw_wp_add_low; | |
48 | + u32 sw_wp_add_hig; | |
49 | + u32 icr; | |
50 | + u32 time_reg; | |
51 | + u32 irq_mr; | |
52 | + u32 irq_sr; | |
53 | + u32 lock_pr; | |
54 | + u32 isr; | |
55 | + u32 ceh; | |
56 | +}; | |
57 | + | |
58 | +/* LOCK_PR register defines */ | |
59 | +#define LOCK_PR_UNLOCK_KEY 0x0000A25E /* Magic unlock value */ | |
60 | + | |
61 | +/* ICR defines */ | |
62 | +#define ICR_LARGE_BLOCKS 0x00000004 /* configure for 2KB blocks */ | |
63 | +#define ICR_ADDR4 0x00000002 /* configure for 4-word addrs */ | |
64 | + | |
65 | +/* CEH defines */ | |
66 | +#define CEH_NORMAL_CE 0x00000001 /* do not force CE ON */ | |
67 | + | |
68 | +/* ISR register defines */ | |
69 | +#define ISR_NAND_READY 0x00000001 | |
70 | +#define ISR_CONTROLLER_READY 0x00000002 | |
71 | +#define ISR_ECC_READY 0x00000004 | |
72 | +#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1) | |
73 | +#define ISR_DECODER_FAILURE 0x00000040 | |
74 | +#define ISR_DECODER_ERROR 0x00000008 | |
75 | + | |
76 | +/* time-out for NAND chip / controller loops, in us */ | |
77 | +#define LPC32X_NAND_TIMEOUT 5000 | |
78 | + | |
79 | +/* | |
80 | + * There is a single instance of the NAND MLC controller | |
81 | + */ | |
82 | + | |
83 | +static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers | |
84 | + = (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE; | |
85 | + | |
86 | +#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o) | |
87 | + | |
88 | +/** | |
89 | + * OOB data in each small page are 6 'free' then 10 ECC bytes. | |
90 | + * To make things easier, when reading large pages, the four pages' | |
91 | + * 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer, | |
92 | + * while the the four ECC bytes are groupe in its last 40 bytes. | |
93 | + * | |
94 | + * The struct below represents how free vs ecc oob bytes are stored | |
95 | + * in the buffer. | |
96 | + * | |
97 | + * Note: the OOB bytes contain the bad block marker at offsets 0 and 1. | |
98 | + */ | |
99 | + | |
100 | +struct lpc32xx_oob { | |
101 | + struct { | |
102 | + uint8_t free_oob_bytes[6]; | |
103 | + } free[4]; | |
104 | + struct { | |
105 | + uint8_t ecc_oob_bytes[10]; | |
106 | + } ecc[4]; | |
107 | +}; | |
108 | + | |
109 | +/* | |
110 | + * Initialize the controller | |
111 | + */ | |
112 | + | |
113 | +static void lpc32xx_nand_init(void) | |
114 | +{ | |
115 | + unsigned int clk; | |
116 | + | |
117 | + /* Configure controller for no software write protection, x8 bus | |
118 | + width, large block device, and 4 address words */ | |
119 | + | |
120 | + /* unlock controller registers with magic key */ | |
121 | + writel(LOCK_PR_UNLOCK_KEY, | |
122 | + &lpc32xx_nand_mlc_registers->lock_pr); | |
123 | + | |
124 | + /* enable large blocks and large NANDs */ | |
125 | + writel(ICR_LARGE_BLOCKS | ICR_ADDR4, | |
126 | + &lpc32xx_nand_mlc_registers->icr); | |
127 | + | |
128 | + /* Make sure MLC interrupts are disabled */ | |
129 | + writel(0, &lpc32xx_nand_mlc_registers->irq_mr); | |
130 | + | |
131 | + /* Normal chip enable operation */ | |
132 | + writel(CEH_NORMAL_CE, | |
133 | + &lpc32xx_nand_mlc_registers->ceh); | |
134 | + | |
135 | + /* Setup NAND timing */ | |
136 | + clk = get_hclk_clk_rate(); | |
137 | + | |
138 | + writel( | |
139 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) | | |
140 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) | | |
141 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA, 0x07, 16) | | |
142 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH, 0x0F, 12) | | |
143 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW, 0x0F, 8) | | |
144 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH, 0x0F, 4) | | |
145 | + clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW, 0x0F, 0), | |
146 | + &lpc32xx_nand_mlc_registers->time_reg); | |
147 | +} | |
148 | + | |
149 | +#if !defined(CONFIG_SPL_BUILD) | |
150 | + | |
151 | +/** | |
152 | + * lpc32xx_cmd_ctrl - write command to either cmd or data register | |
153 | + */ | |
154 | + | |
155 | +static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd, | |
156 | + unsigned int ctrl) | |
157 | +{ | |
158 | + if (cmd == NAND_CMD_NONE) | |
159 | + return; | |
160 | + | |
161 | + if (ctrl & NAND_CLE) | |
162 | + writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd); | |
163 | + else if (ctrl & NAND_ALE) | |
164 | + writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr); | |
165 | +} | |
166 | + | |
167 | +/** | |
168 | + * lpc32xx_read_byte - read a byte from the NAND | |
169 | + * @mtd: MTD device structure | |
170 | + */ | |
171 | + | |
172 | +static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) | |
173 | +{ | |
174 | + return readb(&lpc32xx_nand_mlc_registers->data); | |
175 | +} | |
176 | + | |
177 | +/** | |
178 | + * lpc32xx_dev_ready - test if NAND device (actually controller) is ready | |
179 | + * @mtd: MTD device structure | |
180 | + * @mode: mode to set the ECC HW to. | |
181 | + */ | |
182 | + | |
183 | +static int lpc32xx_dev_ready(struct mtd_info *mtd) | |
184 | +{ | |
185 | + /* means *controller* ready for us */ | |
186 | + int status = readl(&lpc32xx_nand_mlc_registers->isr); | |
187 | + return status & ISR_CONTROLLER_READY; | |
188 | +} | |
189 | + | |
190 | +/** | |
191 | + * ECC layout -- this is needed whatever ECC mode we are using. | |
192 | + * In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes. | |
193 | + * To make U-Boot's life easier, we pack 'useable' OOB at the | |
194 | + * front and R/S ECC at the back. | |
195 | + */ | |
196 | + | |
197 | +static struct nand_ecclayout lpc32xx_largepage_ecclayout = { | |
198 | + .eccbytes = 40, | |
199 | + .eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, | |
200 | + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, | |
201 | + 44, 45, 46, 47, 48, 48, 50, 51, 52, 53, | |
202 | + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | |
203 | + }, | |
204 | + .oobfree = { | |
205 | + /* bytes 0 and 1 are used for the bad block marker */ | |
206 | + { | |
207 | + .offset = 2, | |
208 | + .length = 22 | |
209 | + }, | |
210 | + } | |
211 | +}; | |
212 | + | |
213 | +/** | |
214 | + * lpc32xx_read_page_hwecc - read in- and out-of-band data with ECC | |
215 | + * @mtd: mtd info structure | |
216 | + * @chip: nand chip info structure | |
217 | + * @buf: buffer to store read data | |
218 | + * @oob_required: caller requires OOB data read to chip->oob_poi | |
219 | + * @page: page number to read | |
220 | + * | |
221 | + * Use large block Auto Decode Read Mode(1) as described in User Manual | |
222 | + * section 8.6.2.1. | |
223 | + * | |
224 | + * The initial Read Mode and Read Start commands are sent by the caller. | |
225 | + * | |
226 | + * ECC will be false if out-of-band data has been updated since in-band | |
227 | + * data was initially written. | |
228 | + */ | |
229 | + | |
230 | +static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, | |
231 | + struct nand_chip *chip, uint8_t *buf, int oob_required, | |
232 | + int page) | |
233 | +{ | |
234 | + unsigned int i, status, timeout, err, max_bitflips = 0; | |
235 | + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; | |
236 | + | |
237 | + /* go through all four small pages */ | |
238 | + for (i = 0; i < 4; i++) { | |
239 | + /* start auto decode (reads 528 NAND bytes) */ | |
240 | + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); | |
241 | + /* wait for controller to return to ready state */ | |
242 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
243 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
244 | + if (status & ISR_CONTROLLER_READY) | |
245 | + break; | |
246 | + udelay(1); | |
247 | + } | |
248 | + /* if decoder failed, return failure */ | |
249 | + if (status & ISR_DECODER_FAILURE) | |
250 | + return -1; | |
251 | + /* keep count of maximum bitflips performed */ | |
252 | + if (status & ISR_DECODER_ERROR) { | |
253 | + err = ISR_DECODER_ERRORS(status); | |
254 | + if (err > max_bitflips) | |
255 | + max_bitflips = err; | |
256 | + } | |
257 | + /* copy first 512 bytes into buffer */ | |
258 | + memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512); | |
259 | + /* copy next 6 bytes at front of OOB buffer */ | |
260 | + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); | |
261 | + /* copy last 10 bytes (R/S ECC) at back of OOB buffer */ | |
262 | + memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10); | |
263 | + } | |
264 | + return max_bitflips; | |
265 | +} | |
266 | + | |
267 | +/** | |
268 | + * lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data | |
269 | + * @mtd: mtd info structure | |
270 | + * @chip: nand chip info structure | |
271 | + * @buf: buffer to store read data | |
272 | + * @oob_required: caller requires OOB data read to chip->oob_poi | |
273 | + * @page: page number to read | |
274 | + * | |
275 | + * Read NAND directly; can read pages with invalid ECC. | |
276 | + */ | |
277 | + | |
278 | +static int lpc32xx_read_page_raw(struct mtd_info *mtd, | |
279 | + struct nand_chip *chip, uint8_t *buf, int oob_required, | |
280 | + int page) | |
281 | +{ | |
282 | + unsigned int i, status, timeout; | |
283 | + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; | |
284 | + | |
285 | + /* when we get here we've already had the Read Mode(1) */ | |
286 | + | |
287 | + /* go through all four small pages */ | |
288 | + for (i = 0; i < 4; i++) { | |
289 | + /* wait for NAND to return to ready state */ | |
290 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
291 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
292 | + if (status & ISR_NAND_READY) | |
293 | + break; | |
294 | + udelay(1); | |
295 | + } | |
296 | + /* if NAND stalled, return failure */ | |
297 | + if (!(status & ISR_NAND_READY)) | |
298 | + return -1; | |
299 | + /* copy first 512 bytes into buffer */ | |
300 | + memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512); | |
301 | + /* copy next 6 bytes at front of OOB buffer */ | |
302 | + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->data, 6); | |
303 | + /* copy last 10 bytes (R/S ECC) at back of OOB buffer */ | |
304 | + memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->data, 10); | |
305 | + } | |
306 | + return 0; | |
307 | +} | |
308 | + | |
309 | +/** | |
310 | + * lpc32xx_read_oob - read out-of-band data | |
311 | + * @mtd: mtd info structure | |
312 | + * @chip: nand chip info structure | |
313 | + * @page: page number to read | |
314 | + * | |
315 | + * Read out-of-band data. User Manual section 8.6.4 suggests using Read | |
316 | + * Mode(3) which the controller will turn into a Read Mode(1) internally | |
317 | + * but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0) | |
318 | + * directly. | |
319 | + * | |
320 | + * ECC covers in- and out-of-band data and was written when out-of-band | |
321 | + * data was blank. Therefore, if the out-of-band being read here is not | |
322 | + * blank, then the ECC will be false and the read will return bitflips, | |
323 | + * even in case of ECC failure where we will return 5 bitflips. The | |
324 | + * caller should be prepared to handle this. | |
325 | + */ | |
326 | + | |
327 | +static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | |
328 | + int page) | |
329 | +{ | |
330 | + unsigned int i, status, timeout, err, max_bitflips = 0; | |
331 | + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; | |
332 | + | |
333 | + /* No command was sent before calling read_oob() so send one */ | |
334 | + | |
335 | + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); | |
336 | + | |
337 | + /* go through all four small pages */ | |
338 | + for (i = 0; i < 4; i++) { | |
339 | + /* start auto decode (reads 528 NAND bytes) */ | |
340 | + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); | |
341 | + /* wait for controller to return to ready state */ | |
342 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
343 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
344 | + if (status & ISR_CONTROLLER_READY) | |
345 | + break; | |
346 | + udelay(1); | |
347 | + } | |
348 | + /* if decoder failure, count 'one too many' bitflips */ | |
349 | + if (status & ISR_DECODER_FAILURE) | |
350 | + max_bitflips = 5; | |
351 | + /* keep count of maximum bitflips performed */ | |
352 | + if (status & ISR_DECODER_ERROR) { | |
353 | + err = ISR_DECODER_ERRORS(status); | |
354 | + if (err > max_bitflips) | |
355 | + max_bitflips = err; | |
356 | + } | |
357 | + /* set read pointer to OOB area */ | |
358 | + writel(0, &lpc32xx_nand_mlc_registers->robp); | |
359 | + /* copy next 6 bytes at front of OOB buffer */ | |
360 | + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); | |
361 | + /* copy next 10 bytes (R/S ECC) at back of OOB buffer */ | |
362 | + memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10); | |
363 | + } | |
364 | + return max_bitflips; | |
365 | +} | |
366 | + | |
367 | +/** | |
368 | + * lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC | |
369 | + * @mtd: mtd info structure | |
370 | + * @chip: nand chip info structure | |
371 | + * @buf: data buffer | |
372 | + * @oob_required: must write chip->oob_poi to OOB | |
373 | + * | |
374 | + * Use large block Auto Encode as per User Manual section 8.6.4. | |
375 | + * | |
376 | + * The initial Write Serial Input and final Auto Program commands are | |
377 | + * sent by the caller. | |
378 | + */ | |
379 | + | |
380 | +static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, | |
381 | + struct nand_chip *chip, const uint8_t *buf, int oob_required) | |
382 | +{ | |
383 | + unsigned int i, status, timeout; | |
384 | + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; | |
385 | + | |
386 | + /* when we get here we've already had the SEQIN */ | |
387 | + for (i = 0; i < 4; i++) { | |
388 | + /* start encode (expects 518 writes to buff) */ | |
389 | + writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg); | |
390 | + /* copy first 512 bytes from buffer */ | |
391 | + memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512); | |
392 | + /* copy next 6 bytes from OOB buffer -- excluding ECC */ | |
393 | + memcpy(&lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6); | |
394 | + /* wait for ECC to return to ready state */ | |
395 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
396 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
397 | + if (status & ISR_ECC_READY) | |
398 | + break; | |
399 | + udelay(1); | |
400 | + } | |
401 | + /* if ECC stalled, return failure */ | |
402 | + if (!(status & ISR_ECC_READY)) | |
403 | + return -1; | |
404 | + /* Trigger auto encode (writes 528 bytes to NAND) */ | |
405 | + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg); | |
406 | + /* wait for controller to return to ready state */ | |
407 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
408 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
409 | + if (status & ISR_CONTROLLER_READY) | |
410 | + break; | |
411 | + udelay(1); | |
412 | + } | |
413 | + /* if controller stalled, return error */ | |
414 | + if (!(status & ISR_CONTROLLER_READY)) | |
415 | + return -1; | |
416 | + } | |
417 | + return 0; | |
418 | +} | |
419 | + | |
420 | +/** | |
421 | + * lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data | |
422 | + * @mtd: mtd info structure | |
423 | + * @chip: nand chip info structure | |
424 | + * @buf: buffer to store read data | |
425 | + * @oob_required: caller requires OOB data read to chip->oob_poi | |
426 | + * @page: page number to read | |
427 | + * | |
428 | + * Use large block write but without encode. | |
429 | + * | |
430 | + * The initial Write Serial Input and final Auto Program commands are | |
431 | + * sent by the caller. | |
432 | + * | |
433 | + * This function will write the full out-of-band data, including the | |
434 | + * ECC area. Therefore, it can write pages with valid *or* invalid ECC. | |
435 | + */ | |
436 | + | |
437 | +static int lpc32xx_write_page_raw(struct mtd_info *mtd, | |
438 | + struct nand_chip *chip, const uint8_t *buf, int oob_required) | |
439 | +{ | |
440 | + unsigned int i; | |
441 | + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; | |
442 | + | |
443 | + /* when we get here we've already had the Read Mode(1) */ | |
444 | + for (i = 0; i < 4; i++) { | |
445 | + /* copy first 512 bytes from buffer */ | |
446 | + memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512); | |
447 | + /* copy next 6 bytes into OOB buffer -- excluding ECC */ | |
448 | + memcpy(lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6); | |
449 | + /* copy next 10 bytes into OOB buffer -- that is 'ECC' */ | |
450 | + memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[i], 10); | |
451 | + } | |
452 | + return 0; | |
453 | +} | |
454 | + | |
455 | +/** | |
456 | + * lpc32xx_write_oob - write out-of-band data | |
457 | + * @mtd: mtd info structure | |
458 | + * @chip: nand chip info structure | |
459 | + * @page: page number to read | |
460 | + * | |
461 | + * Since ECC covers in- and out-of-band data, writing out-of-band data | |
462 | + * with ECC will render the page ECC wrong -- or, if the page was blank, | |
463 | + * then it will produce a good ECC but a later in-band data write will | |
464 | + * render it wrong. | |
465 | + * | |
466 | + * Therefore, do not compute or write any ECC, and always return success. | |
467 | + * | |
468 | + * This implies that we do four writes, since non-ECC out-of-band data | |
469 | + * are not contiguous in a large page. | |
470 | + */ | |
471 | + | |
472 | +static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, | |
473 | + int page) | |
474 | +{ | |
475 | + /* update oob on all 4 subpages in sequence */ | |
476 | + unsigned int i, status, timeout; | |
477 | + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; | |
478 | + | |
479 | + for (i = 0; i < 4; i++) { | |
480 | + /* start data input */ | |
481 | + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page); | |
482 | + /* copy 6 non-ECC out-of-band bytes directly into NAND */ | |
483 | + memcpy(lpc32xx_nand_mlc_registers->data, &oob->free[i], 6); | |
484 | + /* program page */ | |
485 | + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | |
486 | + /* wait for NAND to return to ready state */ | |
487 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
488 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
489 | + if (status & ISR_NAND_READY) | |
490 | + break; | |
491 | + udelay(1); | |
492 | + } | |
493 | + /* if NAND stalled, return error */ | |
494 | + if (!(status & ISR_NAND_READY)) | |
495 | + return -1; | |
496 | + } | |
497 | + return 0; | |
498 | +} | |
499 | + | |
500 | +/** | |
501 | + * lpc32xx_waitfunc - wait until a command is done | |
502 | + * @mtd: MTD device structure | |
503 | + * @chip: NAND chip structure | |
504 | + * | |
505 | + * Wait for controller and FLASH to both be ready. | |
506 | + */ | |
507 | + | |
508 | +static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) | |
509 | +{ | |
510 | + int status; | |
511 | + unsigned int timeout; | |
512 | + /* wait until both controller and NAND are ready */ | |
513 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
514 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
515 | + if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY)) | |
516 | + == (ISR_CONTROLLER_READY || ISR_NAND_READY)) | |
517 | + break; | |
518 | + udelay(1); | |
519 | + } | |
520 | + /* if controller or NAND stalled, return error */ | |
521 | + if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY)) | |
522 | + != (ISR_CONTROLLER_READY || ISR_NAND_READY)) | |
523 | + return -1; | |
524 | + /* write NAND status command */ | |
525 | + writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd); | |
526 | + /* read back status and return it */ | |
527 | + return readb(&lpc32xx_nand_mlc_registers->data); | |
528 | +} | |
529 | + | |
530 | +/* | |
531 | + * We are self-initializing, so we need our own chip struct | |
532 | + */ | |
533 | + | |
534 | +static struct nand_chip lpc32xx_chip; | |
535 | + | |
536 | +/* | |
537 | + * Initialize the controller | |
538 | + */ | |
539 | + | |
540 | +void board_nand_init(void) | |
541 | +{ | |
542 | + /* we have only one device anyway */ | |
543 | + struct mtd_info *mtd = &nand_info[0]; | |
544 | + /* chip is struct nand_chip, and is now provided by the driver. */ | |
545 | + mtd->priv = &lpc32xx_chip; | |
546 | + /* to store return status in case we need to print it */ | |
547 | + int ret; | |
548 | + | |
549 | + /* Set all BOARDSPECIFIC (actually core-specific) fields */ | |
550 | + | |
551 | + lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff; | |
552 | + lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff; | |
553 | + lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl; | |
554 | + /* do not set init_size: nand_base.c will read sizes from chip */ | |
555 | + lpc32xx_chip.dev_ready = lpc32xx_dev_ready; | |
556 | + /* do not set setup_read_retry: this is NAND-chip-specific */ | |
557 | + /* do not set chip_delay: we have dev_ready defined. */ | |
558 | + lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE; | |
559 | + | |
560 | + /* Set needed ECC fields */ | |
561 | + | |
562 | + lpc32xx_chip.ecc.mode = NAND_ECC_HW; | |
563 | + lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout; | |
564 | + lpc32xx_chip.ecc.size = 512; | |
565 | + lpc32xx_chip.ecc.bytes = 10; | |
566 | + lpc32xx_chip.ecc.strength = 4; | |
567 | + lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc; | |
568 | + lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw; | |
569 | + lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc; | |
570 | + lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw; | |
571 | + lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob; | |
572 | + lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob; | |
573 | + lpc32xx_chip.waitfunc = lpc32xx_waitfunc; | |
574 | + | |
575 | + lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */ | |
576 | + | |
577 | + /* BBT options: read from last two pages */ | |
578 | + lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK | |
579 | + | NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | |
580 | + | NAND_BBT_WRITE; | |
581 | + | |
582 | + /* Initialize NAND interface */ | |
583 | + lpc32xx_nand_init(); | |
584 | + | |
585 | + /* identify chip */ | |
586 | + ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL); | |
587 | + if (ret) { | |
588 | + error("nand_scan_ident returned %i", ret); | |
589 | + return; | |
590 | + } | |
591 | + | |
592 | + /* finish scanning the chip */ | |
593 | + ret = nand_scan_tail(mtd); | |
594 | + if (ret) { | |
595 | + error("nand_scan_tail returned %i", ret); | |
596 | + return; | |
597 | + } | |
598 | + | |
599 | + /* chip is good, register it */ | |
600 | + ret = nand_register(0); | |
601 | + if (ret) | |
602 | + error("nand_register returned %i", ret); | |
603 | +} | |
604 | + | |
605 | +#else /* defined(CONFIG_SPL_BUILD) */ | |
606 | + | |
607 | +void nand_init(void) | |
608 | +{ | |
609 | + /* enable NAND controller */ | |
610 | + lpc32xx_mlc_nand_init(); | |
611 | + /* initialize NAND controller */ | |
612 | + lpc32xx_nand_init(); | |
613 | +} | |
614 | + | |
615 | +void nand_deselect(void) | |
616 | +{ | |
617 | + /* nothing to do, but SPL requires this function */ | |
618 | +} | |
619 | + | |
620 | +static int read_single_page(uint8_t *dest, int page, | |
621 | + struct lpc32xx_oob *oob) | |
622 | +{ | |
623 | + int status, i, timeout, err, max_bitflips = 0; | |
624 | + | |
625 | + /* enter read mode */ | |
626 | + writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd); | |
627 | + /* send column (lsb then MSB) and page (lsb to MSB) */ | |
628 | + writel(0, &lpc32xx_nand_mlc_registers->addr); | |
629 | + writel(0, &lpc32xx_nand_mlc_registers->addr); | |
630 | + writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr); | |
631 | + writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr); | |
632 | + writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr); | |
633 | + /* start reading */ | |
634 | + writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd); | |
635 | + | |
636 | + /* large page auto decode read */ | |
637 | + for (i = 0; i < 4; i++) { | |
638 | + /* start auto decode (reads 528 NAND bytes) */ | |
639 | + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); | |
640 | + /* wait for controller to return to ready state */ | |
641 | + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { | |
642 | + status = readl(&lpc32xx_nand_mlc_registers->isr); | |
643 | + if (status & ISR_CONTROLLER_READY) | |
644 | + break; | |
645 | + udelay(1); | |
646 | + } | |
647 | + /* if controller stalled, return error */ | |
648 | + if (!(status & ISR_CONTROLLER_READY)) | |
649 | + return -1; | |
650 | + /* if decoder failure, return error */ | |
651 | + if (status & ISR_DECODER_FAILURE) | |
652 | + return -1; | |
653 | + /* keep count of maximum bitflips performed */ | |
654 | + if (status & ISR_DECODER_ERROR) { | |
655 | + err = ISR_DECODER_ERRORS(status); | |
656 | + if (err > max_bitflips) | |
657 | + max_bitflips = err; | |
658 | + } | |
659 | + /* copy first 512 bytes into buffer */ | |
660 | + memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512); | |
661 | + /* copy next 6 bytes bytes into OOB buffer */ | |
662 | + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); | |
663 | + } | |
664 | + return max_bitflips; | |
665 | +} | |
666 | + | |
667 | +/* | |
668 | + * Load U-Boot signed image. | |
669 | + * This loads an image from NAND, skipping bad blocks. | |
670 | + * A block is declared bad if at least one of its readable pages has | |
671 | + * a bad block marker in its OOB at position 0. | |
672 | + * If all pages ion a block are unreadable, the block is considered | |
673 | + * bad (i.e., assumed not to be part of the image) and skipped. | |
674 | + * | |
675 | + * IMPORTANT NOTE: | |
676 | + * | |
677 | + * If the first block of the image is fully unreadable, it will be | |
678 | + * ignored and skipped as if it had been marked bad. If it was not | |
679 | + * actually marked bad at the time of writing the image, the resulting | |
680 | + * image loaded will lack a header and magic number. It could thus be | |
681 | + * considered as a raw, headerless, image and SPL might erroneously | |
682 | + * jump into it. | |
683 | + * | |
684 | + * In order to avoid this risk, LPC32XX-based boards which use this | |
685 | + * driver MUST define CONFIG_SPL_PANIC_ON_RAW_IMAGE. | |
686 | + */ | |
687 | + | |
688 | +#define BYTES_PER_PAGE 2048 | |
689 | +#define PAGES_PER_BLOCK 64 | |
690 | +#define BYTES_PER_BLOCK (BYTES_PER_PAGE * PAGES_PER_BLOCK) | |
691 | +#define PAGES_PER_CHIP_MAX 524288 | |
692 | + | |
693 | +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) | |
694 | +{ | |
695 | + int bytes_left = size; | |
696 | + int pages_left = DIV_ROUND_UP(size, BYTES_PER_PAGE); | |
697 | + int blocks_left = DIV_ROUND_UP(size, BYTES_PER_BLOCK); | |
698 | + int block = 0; | |
699 | + int page = offs / BYTES_PER_PAGE; | |
700 | + /* perform reads block by block */ | |
701 | + while (blocks_left) { | |
702 | + /* compute first page number to read */ | |
703 | + void *block_page_dst = dst; | |
704 | + /* read at most one block, possibly less */ | |
705 | + int block_bytes_left = bytes_left; | |
706 | + if (block_bytes_left > BYTES_PER_BLOCK) | |
707 | + block_bytes_left = BYTES_PER_BLOCK; | |
708 | + /* keep track of good, failed, and "bad" pages */ | |
709 | + int block_pages_good = 0; | |
710 | + int block_pages_bad = 0; | |
711 | + int block_pages_err = 0; | |
712 | + /* we shall read a full block of pages, maybe less */ | |
713 | + int block_pages_left = pages_left; | |
714 | + if (block_pages_left > PAGES_PER_BLOCK) | |
715 | + block_pages_left = PAGES_PER_BLOCK; | |
716 | + int block_pages = block_pages_left; | |
717 | + int block_page = page; | |
718 | + /* while pages are left and the block is not known as bad */ | |
719 | + while ((block_pages > 0) && (block_pages_bad == 0)) { | |
720 | + /* we will read OOB, too, for bad block markers */ | |
721 | + struct lpc32xx_oob oob; | |
722 | + /* read page */ | |
723 | + int res = read_single_page(block_page_dst, block_page, | |
724 | + &oob); | |
725 | + /* count readable pages */ | |
726 | + if (res >= 0) { | |
727 | + /* this page is good */ | |
728 | + block_pages_good++; | |
729 | + /* this page is bad */ | |
730 | + if ((oob.free[0].free_oob_bytes[0] != 0xff) | |
731 | + | (oob.free[0].free_oob_bytes[1] != 0xff)) | |
732 | + block_pages_bad++; | |
733 | + } else | |
734 | + /* count errors */ | |
735 | + block_pages_err++; | |
736 | + /* we're done with this page */ | |
737 | + block_page++; | |
738 | + block_page_dst += BYTES_PER_PAGE; | |
739 | + if (block_pages) | |
740 | + block_pages--; | |
741 | + } | |
742 | + /* a fully unreadable block is considered bad */ | |
743 | + if (block_pages_good == 0) | |
744 | + block_pages_bad = block_pages_err; | |
745 | + /* errors are fatal only in good blocks */ | |
746 | + if ((block_pages_err > 0) && (block_pages_bad == 0)) | |
747 | + return -1; | |
748 | + /* we keep reads only of good blocks */ | |
749 | + if (block_pages_bad == 0) { | |
750 | + dst += block_bytes_left; | |
751 | + bytes_left -= block_bytes_left; | |
752 | + pages_left -= block_pages_left; | |
753 | + blocks_left--; | |
754 | + } | |
755 | + /* good or bad, we're done with this block */ | |
756 | + block++; | |
757 | + page += PAGES_PER_BLOCK; | |
758 | + } | |
759 | + | |
760 | + /* report success */ | |
761 | + return 0; | |
762 | +} | |
763 | + | |
764 | +#endif /* CONFIG_SPL_BUILD */ |
drivers/net/Makefile
... | ... | @@ -35,6 +35,7 @@ |
35 | 35 | obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o |
36 | 36 | obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o |
37 | 37 | obj-$(CONFIG_LAN91C96) += lan91c96.o |
38 | +obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o | |
38 | 39 | obj-$(CONFIG_MACB) += macb.o |
39 | 40 | obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o |
40 | 41 | obj-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o |
drivers/net/lpc32xx_eth.c
1 | +/* | |
2 | + * LPC32xx Ethernet MAC interface driver | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <net.h> | |
12 | +#include <malloc.h> | |
13 | +#include <miiphy.h> | |
14 | +#include <asm/io.h> | |
15 | +#include <asm/errno.h> | |
16 | +#include <asm/types.h> | |
17 | +#include <asm/system.h> | |
18 | +#include <asm/byteorder.h> | |
19 | +#include <asm/arch/cpu.h> | |
20 | +#include <asm/arch/config.h> | |
21 | + | |
22 | +/* | |
23 | + * Notes: | |
24 | + * | |
25 | + * 1. Unless specified otherwise, all references to tables or paragraphs | |
26 | + * are to UM10326, "LPC32x0 and LPC32x0/01 User manual". | |
27 | + * | |
28 | + * 2. Only bitfield masks/values which are actually used by the driver | |
29 | + * are defined. | |
30 | + */ | |
31 | + | |
32 | +/* a single RX descriptor. The controller has an array of these */ | |
33 | +struct lpc32xx_eth_rxdesc { | |
34 | + u32 packet; /* Receive packet pointer */ | |
35 | + u32 control; /* Descriptor command status */ | |
36 | +}; | |
37 | + | |
38 | +#define LPC32XX_ETH_RX_DESC_SIZE (sizeof(struct lpc32xx_eth_rxdesc)) | |
39 | + | |
40 | +/* RX control bitfields/masks (see Table 330) */ | |
41 | +#define LPC32XX_ETH_RX_CTRL_SIZE_MASK 0x000007FF | |
42 | +#define LPC32XX_ETH_RX_CTRL_UNUSED 0x7FFFF800 | |
43 | +#define LPC32XX_ETH_RX_CTRL_INTERRUPT 0x80000000 | |
44 | + | |
45 | +/* a single RX status. The controller has an array of these */ | |
46 | +struct lpc32xx_eth_rxstat { | |
47 | + u32 statusinfo; /* Transmit Descriptor status */ | |
48 | + u32 statushashcrc; /* Transmit Descriptor CRCs */ | |
49 | +}; | |
50 | + | |
51 | +#define LPC32XX_ETH_RX_STAT_SIZE (sizeof(struct lpc32xx_eth_rxstat)) | |
52 | + | |
53 | +/* RX statusinfo bitfields/masks (see Table 333) */ | |
54 | +#define RX_STAT_RXSIZE 0x000007FF | |
55 | +/* Helper: OR of all errors except RANGE */ | |
56 | +#define RX_STAT_ERRORS 0x1B800000 | |
57 | + | |
58 | +/* a single TX descriptor. The controller has an array of these */ | |
59 | +struct lpc32xx_eth_txdesc { | |
60 | + u32 packet; /* Transmit packet pointer */ | |
61 | + u32 control; /* Descriptor control */ | |
62 | +}; | |
63 | + | |
64 | +#define LPC32XX_ETH_TX_DESC_SIZE (sizeof(struct lpc32xx_eth_txdesc)) | |
65 | + | |
66 | +/* TX control bitfields/masks (see Table 335) */ | |
67 | +#define TX_CTRL_TXSIZE 0x000007FF | |
68 | +#define TX_CTRL_LAST 0x40000000 | |
69 | + | |
70 | +/* a single TX status. The controller has an array of these */ | |
71 | +struct lpc32xx_eth_txstat { | |
72 | + u32 statusinfo; /* Transmit Descriptor status */ | |
73 | +}; | |
74 | + | |
75 | +#define LPC32XX_ETH_TX_STAT_SIZE (sizeof(struct lpc32xx_eth_txstat)) | |
76 | + | |
77 | +/* Ethernet MAC interface registers (see Table 283) */ | |
78 | +struct lpc32xx_eth_registers { | |
79 | + /* MAC registers - 0x3106_0000 to 0x3106_01FC */ | |
80 | + u32 mac1; /* MAC configuration register 1 */ | |
81 | + u32 mac2; /* MAC configuration register 2 */ | |
82 | + u32 ipgt; /* Back-to-back Inter-Packet Gap reg. */ | |
83 | + u32 ipgr; /* Non-back-to-back IPG register */ | |
84 | + u32 clrt; /* Collision Window / Retry register */ | |
85 | + u32 maxf; /* Maximum Frame register */ | |
86 | + u32 supp; /* Phy Support register */ | |
87 | + u32 test; | |
88 | + u32 mcfg; /* MII management configuration reg. */ | |
89 | + u32 mcmd; /* MII management command register */ | |
90 | + u32 madr; /* MII management address register */ | |
91 | + u32 mwtd; /* MII management wite data register */ | |
92 | + u32 mrdd; /* MII management read data register */ | |
93 | + u32 mind; /* MII management indicators register */ | |
94 | + u32 reserved1[2]; | |
95 | + u32 sa0; /* Station address register 0 */ | |
96 | + u32 sa1; /* Station address register 1 */ | |
97 | + u32 sa2; /* Station address register 2 */ | |
98 | + u32 reserved2[45]; | |
99 | + /* Control registers */ | |
100 | + u32 command; | |
101 | + u32 status; | |
102 | + u32 rxdescriptor; | |
103 | + u32 rxstatus; | |
104 | + u32 rxdescriptornumber; /* actually, number MINUS ONE */ | |
105 | + u32 rxproduceindex; /* head of rx desc fifo */ | |
106 | + u32 rxconsumeindex; /* tail of rx desc fifo */ | |
107 | + u32 txdescriptor; | |
108 | + u32 txstatus; | |
109 | + u32 txdescriptornumber; /* actually, number MINUS ONE */ | |
110 | + u32 txproduceindex; /* head of rx desc fifo */ | |
111 | + u32 txconsumeindex; /* tail of rx desc fifo */ | |
112 | + u32 reserved3[10]; | |
113 | + u32 tsv0; /* Transmit status vector register 0 */ | |
114 | + u32 tsv1; /* Transmit status vector register 1 */ | |
115 | + u32 rsv; /* Receive status vector register */ | |
116 | + u32 reserved4[3]; | |
117 | + u32 flowcontrolcounter; | |
118 | + u32 flowcontrolstatus; | |
119 | + u32 reserved5[34]; | |
120 | + /* RX filter registers - 0x3106_0200 to 0x3106_0FDC */ | |
121 | + u32 rxfilterctrl; | |
122 | + u32 rxfilterwolstatus; | |
123 | + u32 rxfilterwolclear; | |
124 | + u32 reserved6; | |
125 | + u32 hashfilterl; | |
126 | + u32 hashfilterh; | |
127 | + u32 reserved7[882]; | |
128 | + /* Module control registers - 0x3106_0FE0 to 0x3106_0FF8 */ | |
129 | + u32 intstatus; /* Interrupt status register */ | |
130 | + u32 intenable; | |
131 | + u32 intclear; | |
132 | + u32 intset; | |
133 | + u32 reserved8; | |
134 | + u32 powerdown; | |
135 | + u32 reserved9; | |
136 | +}; | |
137 | + | |
138 | +/* MAC1 register bitfields/masks and offsets (see Table 283) */ | |
139 | +#define MAC1_RECV_ENABLE 0x00000001 | |
140 | +#define MAC1_PASS_ALL_RX_FRAMES 0x00000002 | |
141 | +#define MAC1_SOFT_RESET 0x00008000 | |
142 | +/* Helper: general reset */ | |
143 | +#define MAC1_RESETS 0x0000CF00 | |
144 | + | |
145 | +/* MAC2 register bitfields/masks and offsets (see Table 284) */ | |
146 | +#define MAC2_FULL_DUPLEX 0x00000001 | |
147 | +#define MAC2_CRC_ENABLE 0x00000010 | |
148 | +#define MAC2_PAD_CRC_ENABLE 0x00000020 | |
149 | + | |
150 | +/* SUPP register bitfields/masks and offsets (see Table 290) */ | |
151 | +#define SUPP_SPEED 0x00000100 | |
152 | + | |
153 | +/* MCFG register bitfields/masks and offsets (see Table 292) */ | |
154 | +#define MCFG_CLOCK_SELECT_MASK 0x0000001C | |
155 | +/* divide clock by 28 (see Table 293) */ | |
156 | +#define MCFG_CLOCK_SELECT_DIV28 0x0000001C | |
157 | + | |
158 | +/* MADR register bitfields/masks and offsets (see Table 295) */ | |
159 | +#define MADR_REG_MASK 0x0000001F | |
160 | +#define MADR_PHY_MASK 0x00001F00 | |
161 | +#define MADR_REG_OFFSET 0 | |
162 | +#define MADR_PHY_OFFSET 8 | |
163 | + | |
164 | +/* MIND register bitfields/masks (see Table 298) */ | |
165 | +#define MIND_BUSY 0x00000001 | |
166 | + | |
167 | +/* COMMAND register bitfields/masks and offsets (see Table 283) */ | |
168 | +#define COMMAND_RXENABLE 0x00000001 | |
169 | +#define COMMAND_TXENABLE 0x00000002 | |
170 | +#define COMMAND_PASSRUNTFRAME 0x00000040 | |
171 | +#define COMMAND_FULL_DUPLEX 0x00000400 | |
172 | +/* Helper: general reset */ | |
173 | +#define COMMAND_RESETS 0x0000001C | |
174 | + | |
175 | +/* STATUS register bitfields/masks and offsets (see Table 283) */ | |
176 | +#define STATUS_RXSTATUS 0x00000001 | |
177 | +#define STATUS_TXSTATUS 0x00000002 | |
178 | + | |
179 | +/* RXFILTERCTRL register bitfields/masks (see Table 319) */ | |
180 | +#define RXFILTERCTRL_ACCEPTBROADCAST 0x00000002 | |
181 | +#define RXFILTERCTRL_ACCEPTPERFECT 0x00000020 | |
182 | + | |
183 | +/* Buffers and descriptors */ | |
184 | + | |
185 | +#define ATTRS(n) __aligned(n) | |
186 | + | |
187 | +#define TX_BUF_COUNT 4 | |
188 | +#define RX_BUF_COUNT 4 | |
189 | + | |
190 | +struct lpc32xx_eth_buffers { | |
191 | + ATTRS(4) struct lpc32xx_eth_txdesc tx_desc[TX_BUF_COUNT]; | |
192 | + ATTRS(4) struct lpc32xx_eth_txstat tx_stat[TX_BUF_COUNT]; | |
193 | + ATTRS(PKTALIGN) u8 tx_buf[TX_BUF_COUNT*PKTSIZE_ALIGN]; | |
194 | + ATTRS(4) struct lpc32xx_eth_rxdesc rx_desc[RX_BUF_COUNT]; | |
195 | + ATTRS(8) struct lpc32xx_eth_rxstat rx_stat[RX_BUF_COUNT]; | |
196 | + ATTRS(PKTALIGN) u8 rx_buf[RX_BUF_COUNT*PKTSIZE_ALIGN]; | |
197 | +}; | |
198 | + | |
199 | +/* port device data struct */ | |
200 | +struct lpc32xx_eth_device { | |
201 | + struct eth_device dev; | |
202 | + struct lpc32xx_eth_registers *regs; | |
203 | + struct lpc32xx_eth_buffers *bufs; | |
204 | +}; | |
205 | + | |
206 | +#define LPC32XX_ETH_DEVICE_SIZE (sizeof(struct lpc32xx_eth_device)) | |
207 | + | |
208 | +/* generic macros */ | |
209 | +#define to_lpc32xx_eth(_d) container_of(_d, struct lpc32xx_eth_device, dev) | |
210 | + | |
211 | +/* timeout for MII polling */ | |
212 | +#define MII_TIMEOUT 10000000 | |
213 | + | |
214 | +/* limits for PHY and register addresses */ | |
215 | +#define MII_MAX_REG (MADR_REG_MASK >> MADR_REG_OFFSET) | |
216 | + | |
217 | +#define MII_MAX_PHY (MADR_PHY_MASK >> MADR_PHY_OFFSET) | |
218 | + | |
219 | +DECLARE_GLOBAL_DATA_PTR; | |
220 | + | |
221 | +#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | |
222 | +/* | |
223 | + * mii_reg_read - miiphy_read callback function. | |
224 | + * | |
225 | + * Returns 16bit phy register value, or 0xffff on error | |
226 | + */ | |
227 | +static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data) | |
228 | +{ | |
229 | + struct eth_device *dev = eth_get_dev_by_name(devname); | |
230 | + struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev); | |
231 | + struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs; | |
232 | + u32 mind_reg; | |
233 | + u32 timeout; | |
234 | + | |
235 | + /* check parameters */ | |
236 | + if (phy_adr > MII_MAX_PHY) { | |
237 | + printf("%s:%u: Invalid PHY address %d\n", | |
238 | + __func__, __LINE__, phy_adr); | |
239 | + return -EFAULT; | |
240 | + } | |
241 | + if (reg_ofs > MII_MAX_REG) { | |
242 | + printf("%s:%u: Invalid register offset %d\n", | |
243 | + __func__, __LINE__, reg_ofs); | |
244 | + return -EFAULT; | |
245 | + } | |
246 | + | |
247 | + /* write the phy and reg addressse into the MII address reg */ | |
248 | + writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET), | |
249 | + ®s->madr); | |
250 | + | |
251 | + /* write 1 to the MII command register to cause a read */ | |
252 | + writel(1, ®s->mcmd); | |
253 | + | |
254 | + /* wait till the MII is not busy */ | |
255 | + timeout = MII_TIMEOUT; | |
256 | + do { | |
257 | + /* read MII indicators register */ | |
258 | + mind_reg = readl(®s->mind); | |
259 | + if (--timeout == 0) | |
260 | + break; | |
261 | + } while (mind_reg & MIND_BUSY); | |
262 | + | |
263 | + /* write 0 to the MII command register to finish the read */ | |
264 | + writel(0, ®s->mcmd); | |
265 | + | |
266 | + if (timeout == 0) { | |
267 | + printf("%s:%u: MII busy timeout\n", __func__, __LINE__); | |
268 | + return -EFAULT; | |
269 | + } | |
270 | + | |
271 | + *data = (u16) readl(®s->mrdd); | |
272 | + | |
273 | + debug("%s:(adr %d, off %d) => %04x\n", __func__, phy_adr, | |
274 | + reg_ofs, *data); | |
275 | + | |
276 | + return 0; | |
277 | +} | |
278 | + | |
279 | +/* | |
280 | + * mii_reg_write - imiiphy_write callback function. | |
281 | + * | |
282 | + * Returns 0 if write succeed, -EINVAL on bad parameters | |
283 | + * -ETIME on timeout | |
284 | + */ | |
285 | +static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data) | |
286 | +{ | |
287 | + struct eth_device *dev = eth_get_dev_by_name(devname); | |
288 | + struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev); | |
289 | + struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs; | |
290 | + u32 mind_reg; | |
291 | + u32 timeout; | |
292 | + | |
293 | + /* check parameters */ | |
294 | + if (phy_adr > MII_MAX_PHY) { | |
295 | + printf("%s:%u: Invalid PHY address %d\n", | |
296 | + __func__, __LINE__, phy_adr); | |
297 | + return -EFAULT; | |
298 | + } | |
299 | + if (reg_ofs > MII_MAX_REG) { | |
300 | + printf("%s:%u: Invalid register offset %d\n", | |
301 | + __func__, __LINE__, reg_ofs); | |
302 | + return -EFAULT; | |
303 | + } | |
304 | + | |
305 | + /* wait till the MII is not busy */ | |
306 | + timeout = MII_TIMEOUT; | |
307 | + do { | |
308 | + /* read MII indicators register */ | |
309 | + mind_reg = readl(®s->mind); | |
310 | + if (--timeout == 0) | |
311 | + break; | |
312 | + } while (mind_reg & MIND_BUSY); | |
313 | + | |
314 | + if (timeout == 0) { | |
315 | + printf("%s:%u: MII busy timeout\n", __func__, | |
316 | + __LINE__); | |
317 | + return -EFAULT; | |
318 | + } | |
319 | + | |
320 | + /* write the phy and reg addressse into the MII address reg */ | |
321 | + writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET), | |
322 | + ®s->madr); | |
323 | + | |
324 | + /* write data to the MII write register */ | |
325 | + writel(data, ®s->mwtd); | |
326 | + | |
327 | + /*debug("%s:(adr %d, off %d) <= %04x\n", __func__, phy_adr, | |
328 | + reg_ofs, data);*/ | |
329 | + | |
330 | + return 0; | |
331 | +} | |
332 | +#endif | |
333 | + | |
334 | +#if defined(CONFIG_PHYLIB) | |
335 | +int lpc32xx_eth_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr, | |
336 | + int reg_addr) | |
337 | +{ | |
338 | + u16 data; | |
339 | + int ret; | |
340 | + ret = mii_reg_read(bus->name, phy_addr, reg_addr, &data); | |
341 | + if (ret) | |
342 | + return ret; | |
343 | + return data; | |
344 | +} | |
345 | + | |
346 | +int lpc32xx_eth_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr, | |
347 | + int reg_addr, u16 data) | |
348 | +{ | |
349 | + return mii_reg_write(bus->name, phy_addr, reg_addr, data); | |
350 | +} | |
351 | +#endif | |
352 | + | |
353 | +/* | |
354 | + * Locate buffers in SRAM at 0x00001000 to avoid cache issues and | |
355 | + * maximize throughput. | |
356 | + */ | |
357 | + | |
358 | +#define LPC32XX_ETH_BUFS 0x00001000 | |
359 | + | |
360 | +static struct lpc32xx_eth_device lpc32xx_eth = { | |
361 | + .regs = (struct lpc32xx_eth_registers *)LPC32XX_ETH_BASE, | |
362 | + .bufs = (struct lpc32xx_eth_buffers *)LPC32XX_ETH_BUFS | |
363 | +}; | |
364 | + | |
365 | +#define TX_TIMEOUT 10000 | |
366 | + | |
367 | +static int lpc32xx_eth_send(struct eth_device *dev, void *dataptr, int datasize) | |
368 | +{ | |
369 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
370 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
371 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
372 | + struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs; | |
373 | + int timeout, tx_index; | |
374 | + | |
375 | + /* time out if transmit descriptor array remains full too long */ | |
376 | + timeout = TX_TIMEOUT; | |
377 | + while ((readl(®s->status) & STATUS_TXSTATUS) && | |
378 | + (readl(®s->txconsumeindex) | |
379 | + == readl(®s->txproduceindex))) { | |
380 | + if (timeout-- == 0) | |
381 | + return -1; | |
382 | + } | |
383 | + | |
384 | + /* determine next transmit packet index to use */ | |
385 | + tx_index = readl(®s->txproduceindex); | |
386 | + | |
387 | + /* set up transmit packet */ | |
388 | + writel((u32)dataptr, &bufs->tx_desc[tx_index].packet); | |
389 | + writel(TX_CTRL_LAST | ((datasize - 1) & TX_CTRL_TXSIZE), | |
390 | + &bufs->tx_desc[tx_index].control); | |
391 | + writel(0, &bufs->tx_stat[tx_index].statusinfo); | |
392 | + | |
393 | + /* pass transmit packet to DMA engine */ | |
394 | + tx_index = (tx_index + 1) % TX_BUF_COUNT; | |
395 | + writel(tx_index, ®s->txproduceindex); | |
396 | + | |
397 | + /* transmission succeeded */ | |
398 | + return 0; | |
399 | +} | |
400 | + | |
401 | +#define RX_TIMEOUT 1000000 | |
402 | + | |
403 | +static int lpc32xx_eth_recv(struct eth_device *dev) | |
404 | +{ | |
405 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
406 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
407 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
408 | + struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs; | |
409 | + int timeout, rx_index; | |
410 | + | |
411 | + /* time out if receive descriptor array remains empty too long */ | |
412 | + timeout = RX_TIMEOUT; | |
413 | + while (readl(®s->rxproduceindex) == readl(®s->rxconsumeindex)) { | |
414 | + if (timeout-- == 0) | |
415 | + return -1; | |
416 | + } | |
417 | + | |
418 | + /* determine next receive packet index to use */ | |
419 | + rx_index = readl(®s->rxconsumeindex); | |
420 | + | |
421 | + /* if data was valid, pass it on */ | |
422 | + if (!(bufs->rx_stat[rx_index].statusinfo & RX_STAT_ERRORS)) | |
423 | + NetReceive(&(bufs->rx_buf[rx_index*PKTSIZE_ALIGN]), | |
424 | + (bufs->rx_stat[rx_index].statusinfo | |
425 | + & RX_STAT_RXSIZE) + 1); | |
426 | + | |
427 | + /* pass receive slot back to DMA engine */ | |
428 | + rx_index = (rx_index + 1) % RX_BUF_COUNT; | |
429 | + writel(rx_index, ®s->rxconsumeindex); | |
430 | + | |
431 | + /* reception successful */ | |
432 | + return 0; | |
433 | +} | |
434 | + | |
435 | +static int lpc32xx_eth_write_hwaddr(struct eth_device *dev) | |
436 | +{ | |
437 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
438 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
439 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
440 | + | |
441 | + /* Save station address */ | |
442 | + writel((unsigned long) (dev->enetaddr[0] | | |
443 | + (dev->enetaddr[1] << 8)), ®s->sa2); | |
444 | + writel((unsigned long) (dev->enetaddr[2] | | |
445 | + (dev->enetaddr[3] << 8)), ®s->sa1); | |
446 | + writel((unsigned long) (dev->enetaddr[4] | | |
447 | + (dev->enetaddr[5] << 8)), ®s->sa0); | |
448 | + | |
449 | + return 0; | |
450 | +} | |
451 | + | |
452 | +static int lpc32xx_eth_init(struct eth_device *dev) | |
453 | +{ | |
454 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
455 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
456 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
457 | + struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs; | |
458 | + int index; | |
459 | + | |
460 | + /* Release SOFT reset to let MII talk to PHY */ | |
461 | + clrbits_le32(®s->mac1, MAC1_SOFT_RESET); | |
462 | + | |
463 | + /* Configure Full/Half Duplex mode */ | |
464 | + if (miiphy_duplex(dev->name, CONFIG_PHY_ADDR) == FULL) { | |
465 | + setbits_le32(®s->mac2, MAC2_FULL_DUPLEX); | |
466 | + setbits_le32(®s->command, COMMAND_FULL_DUPLEX); | |
467 | + writel(0x15, ®s->ipgt); | |
468 | + } else { | |
469 | + writel(0x12, ®s->ipgt); | |
470 | + } | |
471 | + | |
472 | + /* Configure 100MBit/10MBit mode */ | |
473 | + if (miiphy_speed(dev->name, CONFIG_PHY_ADDR) == _100BASET) | |
474 | + writel(SUPP_SPEED, ®s->supp); | |
475 | + else | |
476 | + writel(0, ®s->supp); | |
477 | + | |
478 | + /* Initial MAC initialization */ | |
479 | + writel(MAC1_PASS_ALL_RX_FRAMES, ®s->mac1); | |
480 | + writel(MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE, ®s->mac2); | |
481 | + writel(PKTSIZE_ALIGN, ®s->maxf); | |
482 | + | |
483 | + /* Retries: 15 (0xF). Collision window: 57 (0x37). */ | |
484 | + writel(0x370F, ®s->clrt); | |
485 | + | |
486 | + /* Set IP gap pt 2 to default 0x12 but pt 1 to non-default 0 */ | |
487 | + writel(0x0012, ®s->ipgr); | |
488 | + | |
489 | + /* pass runt (smaller than 64 bytes) frames */ | |
490 | + writel(COMMAND_PASSRUNTFRAME, ®s->command); | |
491 | + | |
492 | + /* Save station address */ | |
493 | + writel((unsigned long) (dev->enetaddr[0] | | |
494 | + (dev->enetaddr[1] << 8)), ®s->sa2); | |
495 | + writel((unsigned long) (dev->enetaddr[2] | | |
496 | + (dev->enetaddr[3] << 8)), ®s->sa1); | |
497 | + writel((unsigned long) (dev->enetaddr[4] | | |
498 | + (dev->enetaddr[5] << 8)), ®s->sa0); | |
499 | + | |
500 | + /* set up transmit buffers */ | |
501 | + for (index = 0; index < TX_BUF_COUNT; index++) { | |
502 | + bufs->tx_desc[index].control = 0; | |
503 | + bufs->tx_stat[index].statusinfo = 0; | |
504 | + } | |
505 | + writel((u32)(&bufs->tx_desc), (u32 *)®s->txdescriptor); | |
506 | + writel((u32)(&bufs->tx_stat), ®s->txstatus); | |
507 | + writel(TX_BUF_COUNT-1, ®s->txdescriptornumber); | |
508 | + | |
509 | + /* set up receive buffers */ | |
510 | + for (index = 0; index < RX_BUF_COUNT; index++) { | |
511 | + bufs->rx_desc[index].packet = | |
512 | + (u32) (bufs->rx_buf+index*PKTSIZE_ALIGN); | |
513 | + bufs->rx_desc[index].control = PKTSIZE_ALIGN - 1; | |
514 | + bufs->rx_stat[index].statusinfo = 0; | |
515 | + bufs->rx_stat[index].statushashcrc = 0; | |
516 | + } | |
517 | + writel((u32)(&bufs->rx_desc), ®s->rxdescriptor); | |
518 | + writel((u32)(&bufs->rx_stat), ®s->rxstatus); | |
519 | + writel(RX_BUF_COUNT-1, ®s->rxdescriptornumber); | |
520 | + | |
521 | + /* Enable broadcast and matching address packets */ | |
522 | + writel(RXFILTERCTRL_ACCEPTBROADCAST | | |
523 | + RXFILTERCTRL_ACCEPTPERFECT, ®s->rxfilterctrl); | |
524 | + | |
525 | + /* Clear and disable interrupts */ | |
526 | + writel(0xFFFF, ®s->intclear); | |
527 | + writel(0, ®s->intenable); | |
528 | + | |
529 | + /* Enable receive and transmit mode of MAC ethernet core */ | |
530 | + setbits_le32(®s->command, COMMAND_RXENABLE | COMMAND_TXENABLE); | |
531 | + setbits_le32(®s->mac1, MAC1_RECV_ENABLE); | |
532 | + | |
533 | + /* | |
534 | + * Perform a 'dummy' first send to work around Ethernet.1 | |
535 | + * erratum (see ES_LPC3250 rev. 9 dated 1 June 2011). | |
536 | + * Use zeroed "index" variable as the dummy. | |
537 | + */ | |
538 | + | |
539 | + index = 0; | |
540 | + lpc32xx_eth_send(dev, &index, 4); | |
541 | + | |
542 | + return 0; | |
543 | +} | |
544 | + | |
545 | +static int lpc32xx_eth_halt(struct eth_device *dev) | |
546 | +{ | |
547 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
548 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
549 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
550 | + | |
551 | + /* Reset all MAC logic */ | |
552 | + writel(MAC1_RESETS, ®s->mac1); | |
553 | + writel(COMMAND_RESETS, ®s->command); | |
554 | + /* Let reset condition settle */ | |
555 | + udelay(2000); | |
556 | + | |
557 | + return 0; | |
558 | +} | |
559 | + | |
560 | +#if defined(CONFIG_PHYLIB) | |
561 | +int lpc32xx_eth_phylib_init(struct eth_device *dev, int phyid) | |
562 | +{ | |
563 | + struct mii_dev *bus; | |
564 | + struct phy_device *phydev; | |
565 | + int ret; | |
566 | + | |
567 | + bus = mdio_alloc(); | |
568 | + if (!bus) { | |
569 | + printf("mdio_alloc failed\n"); | |
570 | + return -ENOMEM; | |
571 | + } | |
572 | + bus->read = lpc32xx_eth_phy_read; | |
573 | + bus->write = lpc32xx_eth_phy_write; | |
574 | + sprintf(bus->name, dev->name); | |
575 | + | |
576 | + ret = mdio_register(bus); | |
577 | + if (ret) { | |
578 | + printf("mdio_register failed\n"); | |
579 | + free(bus); | |
580 | + return -ENOMEM; | |
581 | + } | |
582 | + | |
583 | + phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_MII); | |
584 | + if (!phydev) { | |
585 | + printf("phy_connect failed\n"); | |
586 | + return -ENODEV; | |
587 | + } | |
588 | + | |
589 | + phy_config(phydev); | |
590 | + phy_startup(phydev); | |
591 | + | |
592 | + return 0; | |
593 | +} | |
594 | +#endif | |
595 | + | |
596 | +int lpc32xx_eth_initialize(bd_t *bis) | |
597 | +{ | |
598 | + struct eth_device *dev = &lpc32xx_eth.dev; | |
599 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth.regs; | |
600 | + | |
601 | + /* | |
602 | + * Set RMII management clock rate. With HCLK at 104 MHz and | |
603 | + * a divider of 28, this will be 3.72 MHz. | |
604 | + */ | |
605 | + | |
606 | + writel(MCFG_CLOCK_SELECT_DIV28, ®s->mcfg); | |
607 | + | |
608 | + /* Reset all MAC logic */ | |
609 | + writel(MAC1_RESETS, ®s->mac1); | |
610 | + writel(COMMAND_RESETS, ®s->command); | |
611 | + | |
612 | + /* wait 10 ms for the whole I/F to reset */ | |
613 | + udelay(10000); | |
614 | + | |
615 | + /* must be less than sizeof(dev->name) */ | |
616 | + strcpy(dev->name, "eth0"); | |
617 | + | |
618 | + dev->init = (void *)lpc32xx_eth_init; | |
619 | + dev->halt = (void *)lpc32xx_eth_halt; | |
620 | + dev->send = (void *)lpc32xx_eth_send; | |
621 | + dev->recv = (void *)lpc32xx_eth_recv; | |
622 | + dev->write_hwaddr = (void *)lpc32xx_eth_write_hwaddr; | |
623 | + | |
624 | + /* Release SOFT reset to let MII talk to PHY */ | |
625 | + clrbits_le32(®s->mac1, MAC1_SOFT_RESET); | |
626 | + | |
627 | + /* register driver before talking to phy */ | |
628 | + eth_register(dev); | |
629 | + | |
630 | +#if defined(CONFIG_PHYLIB) | |
631 | + lpc32xx_eth_phylib_init(dev, 0); | |
632 | +#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | |
633 | + miiphy_register(dev->name, mii_reg_read, mii_reg_write); | |
634 | +#endif | |
635 | + | |
636 | + return 0; | |
637 | +} |
drivers/spi/Makefile
... | ... | @@ -32,6 +32,7 @@ |
32 | 32 | obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o |
33 | 33 | obj-$(CONFIG_ICH_SPI) += ich.o |
34 | 34 | obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o |
35 | +obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o | |
35 | 36 | obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o |
36 | 37 | obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o |
37 | 38 | obj-$(CONFIG_MXC_SPI) += mxc_spi.o |
drivers/spi/lpc32xx_ssp.c
1 | +/* | |
2 | + * LPC32xx SSP interface (SPI mode) | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <linux/compat.h> | |
12 | +#include <asm/io.h> | |
13 | +#include <malloc.h> | |
14 | +#include <spi.h> | |
15 | +#include <asm/arch/clk.h> | |
16 | + | |
17 | +/* SSP chip registers */ | |
18 | +struct ssp_regs { | |
19 | + u32 cr0; | |
20 | + u32 cr1; | |
21 | + u32 data; | |
22 | + u32 sr; | |
23 | + u32 cpsr; | |
24 | + u32 imsc; | |
25 | + u32 ris; | |
26 | + u32 mis; | |
27 | + u32 icr; | |
28 | + u32 dmacr; | |
29 | +}; | |
30 | + | |
31 | +/* CR1 register defines */ | |
32 | +#define SSP_CR1_SSP_ENABLE 0x0002 | |
33 | + | |
34 | +/* SR register defines */ | |
35 | +#define SSP_SR_TNF 0x0002 | |
36 | +/* SSP status RX FIFO not empty bit */ | |
37 | +#define SSP_SR_RNE 0x0004 | |
38 | + | |
39 | +/* lpc32xx spi slave */ | |
40 | +struct lpc32xx_spi_slave { | |
41 | + struct spi_slave slave; | |
42 | + struct ssp_regs *regs; | |
43 | +}; | |
44 | + | |
45 | +static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave( | |
46 | + struct spi_slave *slave) | |
47 | +{ | |
48 | + return container_of(slave, struct lpc32xx_spi_slave, slave); | |
49 | +} | |
50 | + | |
51 | +/* spi_init is called during boot when CONFIG_CMD_SPI is defined */ | |
52 | +void spi_init(void) | |
53 | +{ | |
54 | + /* | |
55 | + * nothing to do: clocking was enabled in lpc32xx_ssp_enable() | |
56 | + * and configuration will be done in spi_setup_slave() | |
57 | + */ | |
58 | +} | |
59 | + | |
60 | +/* the following is called in sequence by do_spi_xfer() */ | |
61 | + | |
62 | +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) | |
63 | +{ | |
64 | + struct lpc32xx_spi_slave *lslave; | |
65 | + | |
66 | + /* we only set up SSP0 for now, so ignore bus */ | |
67 | + | |
68 | + if (mode & SPI_3WIRE) { | |
69 | + error("3-wire mode not supported"); | |
70 | + return NULL; | |
71 | + } | |
72 | + | |
73 | + if (mode & SPI_SLAVE) { | |
74 | + error("slave mode not supported\n"); | |
75 | + return NULL; | |
76 | + } | |
77 | + | |
78 | + if (mode & SPI_PREAMBLE) { | |
79 | + error("preamble byte skipping not supported\n"); | |
80 | + return NULL; | |
81 | + } | |
82 | + | |
83 | + lslave = spi_alloc_slave(struct lpc32xx_spi_slave, bus, cs); | |
84 | + if (!lslave) { | |
85 | + printf("SPI_error: Fail to allocate lpc32xx_spi_slave\n"); | |
86 | + return NULL; | |
87 | + } | |
88 | + | |
89 | + lslave->regs = (struct ssp_regs *)SSP0_BASE; | |
90 | + | |
91 | + /* | |
92 | + * 8 bit frame, SPI fmt, 500kbps -> clock divider is 26. | |
93 | + * Set SCR to 0 and CPSDVSR to 26. | |
94 | + */ | |
95 | + | |
96 | + writel(0x7, &lslave->regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */ | |
97 | + writel(26, &lslave->regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */ | |
98 | + writel(0, &lslave->regs->imsc); /* do not raise any interrupts */ | |
99 | + writel(0, &lslave->regs->icr); /* clear any pending interrupt */ | |
100 | + writel(0, &lslave->regs->dmacr); /* do not do DMAs */ | |
101 | + writel(SSP_CR1_SSP_ENABLE, &lslave->regs->cr1); /* enable SSP0 */ | |
102 | + return &lslave->slave; | |
103 | +} | |
104 | + | |
105 | +void spi_free_slave(struct spi_slave *slave) | |
106 | +{ | |
107 | + struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave); | |
108 | + | |
109 | + debug("(lpc32xx) spi_free_slave: 0x%08x\n", (u32)lslave); | |
110 | + free(lslave); | |
111 | +} | |
112 | + | |
113 | +int spi_claim_bus(struct spi_slave *slave) | |
114 | +{ | |
115 | + /* only one bus and slave so far, always available */ | |
116 | + return 0; | |
117 | +} | |
118 | + | |
119 | +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
120 | + const void *dout, void *din, unsigned long flags) | |
121 | +{ | |
122 | + struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave); | |
123 | + int bytelen = bitlen >> 3; | |
124 | + int idx_out = 0; | |
125 | + int idx_in = 0; | |
126 | + int start_time; | |
127 | + | |
128 | + start_time = get_timer(0); | |
129 | + while ((idx_out < bytelen) || (idx_in < bytelen)) { | |
130 | + int status = readl(&lslave->regs->sr); | |
131 | + if ((idx_out < bytelen) && (status & SSP_SR_TNF)) | |
132 | + writel(((u8 *)dout)[idx_out++], &lslave->regs->data); | |
133 | + if ((idx_in < bytelen) && (status & status & SSP_SR_RNE)) | |
134 | + ((u8 *)din)[idx_in++] = readl(&lslave->regs->data); | |
135 | + if (get_timer(start_time) >= CONFIG_LPC32XX_SSP_TIMEOUT) | |
136 | + return -1; | |
137 | + } | |
138 | + return 0; | |
139 | +} | |
140 | + | |
141 | +void spi_release_bus(struct spi_slave *slave) | |
142 | +{ | |
143 | + /* do nothing */ | |
144 | +} |
include/configs/work_92105.h
1 | +/* | |
2 | + * WORK Microwave work_92105 board configuration file | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#ifndef __CONFIG_WORK_92105_H__ | |
11 | +#define __CONFIG_WORK_92105_H__ | |
12 | + | |
13 | +/* SoC and board defines */ | |
14 | +#include <linux/sizes.h> | |
15 | +#include <asm/arch/cpu.h> | |
16 | + | |
17 | +/* | |
18 | + * Define work_92105 machine type by hand -- done only for compatibility | |
19 | + * with original board code | |
20 | + */ | |
21 | +#define MACH_TYPE_WORK_92105 736 | |
22 | +#define CONFIG_MACH_TYPE MACH_TYPE_WORK_92105 | |
23 | + | |
24 | +#define CONFIG_SYS_ICACHE_OFF | |
25 | +#define CONFIG_SYS_DCACHE_OFF | |
26 | +#if !defined(CONFIG_SPL_BUILD) | |
27 | +#define CONFIG_SKIP_LOWLEVEL_INIT | |
28 | +#endif | |
29 | +#define CONFIG_BOARD_EARLY_INIT_F | |
30 | +#define CONFIG_BOARD_EARLY_INIT_R | |
31 | + | |
32 | +/* generate LPC32XX-specific SPL image */ | |
33 | +#define CONFIG_LPC32XX_SPL | |
34 | + | |
35 | +/* | |
36 | + * Memory configurations | |
37 | + */ | |
38 | +#define CONFIG_NR_DRAM_BANKS 1 | |
39 | +#define CONFIG_SYS_MALLOC_LEN SZ_1M | |
40 | +#define CONFIG_SYS_SDRAM_BASE EMC_DYCS0_BASE | |
41 | +#define CONFIG_SYS_SDRAM_SIZE SZ_128M | |
42 | +#define CONFIG_SYS_TEXT_BASE 0x80100000 | |
43 | +#define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + SZ_32K) | |
44 | +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_TEXT_BASE - SZ_1M) | |
45 | + | |
46 | +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_32K) | |
47 | + | |
48 | +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_512K \ | |
49 | + - GENERATED_GBL_DATA_SIZE) | |
50 | + | |
51 | +/* | |
52 | + * Serial Driver | |
53 | + */ | |
54 | +#define CONFIG_SYS_LPC32XX_UART 5 /* UART5 - NS16550 */ | |
55 | +#define CONFIG_BAUDRATE 115200 | |
56 | + | |
57 | +/* | |
58 | + * Ethernet Driver | |
59 | + */ | |
60 | + | |
61 | +#define CONFIG_PHY_SMSC | |
62 | +#define CONFIG_LPC32XX_ETH | |
63 | +#define CONFIG_PHYLIB | |
64 | +#define CONFIG_PHY_ADDR 0 | |
65 | +#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN | |
66 | +#define CONFIG_CMD_MII | |
67 | +#define CONFIG_CMD_PING | |
68 | +#define CONFIG_CMD_DHCP | |
69 | +/* FIXME: remove "Waiting for PHY auto negotiation to complete..." message */ | |
70 | + | |
71 | +/* | |
72 | + * I2C driver | |
73 | + */ | |
74 | + | |
75 | +#define CONFIG_SYS_I2C_LPC32XX | |
76 | +#define CONFIG_SYS_I2C | |
77 | +#define CONFIG_CMD_I2C | |
78 | +#define CONFIG_SYS_I2C_SPEED 350000 | |
79 | + | |
80 | +/* | |
81 | + * I2C EEPROM | |
82 | + */ | |
83 | + | |
84 | +#define CONFIG_CMD_EEPROM | |
85 | +#define CONFIG_SYS_I2C_EEPROM_ADDR 0x56 | |
86 | +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2 | |
87 | + | |
88 | +/* | |
89 | + * I2C RTC | |
90 | + */ | |
91 | + | |
92 | +#define CONFIG_CMD_DATE | |
93 | +#define CONFIG_RTC_DS1374 | |
94 | + | |
95 | +/* | |
96 | + * I2C Temperature Sensor (DTT) | |
97 | + */ | |
98 | + | |
99 | +#define CONFIG_CMD_DTT | |
100 | +#define CONFIG_DTT_SENSORS { 0, 1 } | |
101 | +#define CONFIG_DTT_DS620 | |
102 | + | |
103 | +/* | |
104 | + * U-Boot General Configurations | |
105 | + */ | |
106 | +#define CONFIG_SYS_GENERIC_BOARD | |
107 | +#define CONFIG_SYS_LONGHELP | |
108 | +#define CONFIG_SYS_CBSIZE 1024 | |
109 | +#define CONFIG_SYS_PBSIZE \ | |
110 | + (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16) | |
111 | +#define CONFIG_SYS_MAXARGS 16 | |
112 | +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE | |
113 | + | |
114 | +#define CONFIG_SYS_HUSH_PARSER | |
115 | + | |
116 | +#define CONFIG_AUTO_COMPLETE | |
117 | +#define CONFIG_CMDLINE_EDITING | |
118 | +#define CONFIG_VERSION_VARIABLE | |
119 | +#define CONFIG_DISPLAY_CPUINFO | |
120 | +#define CONFIG_DOS_PARTITION | |
121 | + | |
122 | +/* | |
123 | + * No NOR | |
124 | + */ | |
125 | + | |
126 | +#define CONFIG_SYS_NO_FLASH | |
127 | + | |
128 | +/* | |
129 | + * NAND chip timings for FIXME: which one? | |
130 | + */ | |
131 | + | |
132 | +#define CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY 333333333 | |
133 | +#define CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY 10000000 | |
134 | +#define CONFIG_LPC32XX_NAND_MLC_NAND_TA 18181818 | |
135 | +#define CONFIG_LPC32XX_NAND_MLC_RD_HIGH 31250000 | |
136 | +#define CONFIG_LPC32XX_NAND_MLC_RD_LOW 45454545 | |
137 | +#define CONFIG_LPC32XX_NAND_MLC_WR_HIGH 40000000 | |
138 | +#define CONFIG_LPC32XX_NAND_MLC_WR_LOW 83333333 | |
139 | + | |
140 | +/* | |
141 | + * NAND | |
142 | + */ | |
143 | + | |
144 | +/* driver configuration */ | |
145 | +#define CONFIG_SYS_NAND_SELF_INIT | |
146 | +#define CONFIG_SYS_MAX_NAND_DEVICE 1 | |
147 | +#define CONFIG_SYS_MAX_NAND_CHIPS 1 | |
148 | +#define CONFIG_SYS_NAND_BASE MLC_NAND_BASE | |
149 | +#define CONFIG_NAND_LPC32XX_MLC | |
150 | + | |
151 | +#define CONFIG_CMD_NAND | |
152 | + | |
153 | +/* | |
154 | + * GPIO | |
155 | + */ | |
156 | + | |
157 | +#define CONFIG_CMD_GPIO | |
158 | +#define CONFIG_LPC32XX_GPIO | |
159 | + | |
160 | +/* | |
161 | + * SSP/SPI/DISPLAY | |
162 | + */ | |
163 | + | |
164 | +#define CONFIG_CMD_SPI | |
165 | +#define CONFIG_LPC32XX_SSP | |
166 | +#define CONFIG_LPC32XX_SSP_TIMEOUT 100000 | |
167 | +#define CONFIG_CMD_MAX6957 | |
168 | +#define CONFIG_CMD_HD44760 | |
169 | +/* | |
170 | + * Environment | |
171 | + */ | |
172 | + | |
173 | +#define CONFIG_ENV_IS_IN_NAND 1 | |
174 | +#define CONFIG_ENV_SIZE 0x00020000 | |
175 | +#define CONFIG_ENV_OFFSET 0x00100000 | |
176 | +#define CONFIG_ENV_OFFSET_REDUND 0x00120000 | |
177 | +#define CONFIG_ENV_ADDR 0x80000100 | |
178 | + | |
179 | +/* | |
180 | + * Provide default ethernet address | |
181 | + * | |
182 | + * THIS IS NORMALLY NOT DONE. HERE WE KEEP WHAT WAS IN THE PORTED | |
183 | + * BOARD CONFIG IN CASE SOME PROVISIONING PROCESS OUT THERE EXPECTS | |
184 | + * THIS MAC ADDRESS WHEN THE DEVICE HAS STILL ITS DEFAULT CONFIG. | |
185 | + */ | |
186 | + | |
187 | +#define CONFIG_ETHADDR 00:12:B4:00:AF:FE | |
188 | +#define CONFIG_OVERWRITE_ETHADDR_ONCE | |
189 | + | |
190 | +/* | |
191 | + * U-Boot Commands | |
192 | + */ | |
193 | +#include <config_cmd_default.h> | |
194 | + | |
195 | +/* | |
196 | + * Boot Linux | |
197 | + */ | |
198 | +#define CONFIG_CMDLINE_TAG | |
199 | +#define CONFIG_SETUP_MEMORY_TAGS | |
200 | +#define CONFIG_INITRD_TAG | |
201 | + | |
202 | +#define CONFIG_ZERO_BOOTDELAY_CHECK | |
203 | +#define CONFIG_BOOTDELAY 3 | |
204 | + | |
205 | +#define CONFIG_BOOTFILE "uImage" | |
206 | +#define CONFIG_BOOTARGS "console=ttyS2,115200n8" | |
207 | +#define CONFIG_LOADADDR 0x80008000 | |
208 | + | |
209 | +/* | |
210 | + * SPL | |
211 | + */ | |
212 | + | |
213 | +/* SPL will be executed at offset 0 */ | |
214 | +#define CONFIG_SPL_TEXT_BASE 0x00000000 | |
215 | +/* SPL will use SRAM as stack */ | |
216 | +#define CONFIG_SPL_STACK 0x0000FFF8 | |
217 | +#define CONFIG_SPL_BOARD_INIT | |
218 | +/* Use the framework and generic lib */ | |
219 | +#define CONFIG_SPL_FRAMEWORK | |
220 | +#define CONFIG_SPL_LIBGENERIC_SUPPORT | |
221 | +#define CONFIG_SPL_LIBCOMMON_SUPPORT | |
222 | +/* SPL will use serial */ | |
223 | +#define CONFIG_SPL_SERIAL_SUPPORT | |
224 | +/* SPL will load U-Boot from NAND offset 0x40000 */ | |
225 | +#define CONFIG_SPL_NAND_SUPPORT | |
226 | +#define CONFIG_SPL_NAND_DRIVERS | |
227 | +#define CONFIG_SPL_NAND_BASE | |
228 | +#define CONFIG_SPL_NAND_BOOT | |
229 | +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x00040000 | |
230 | +#define CONFIG_SPL_PAD_TO 0x20000 | |
231 | +/* U-Boot will be 0x40000 bytes, loaded and run at CONFIG_SYS_TEXT_BASE */ | |
232 | +#define CONFIG_SYS_MONITOR_LEN 0x40000 /* actually, MAX size */ | |
233 | +#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE | |
234 | +#define CONFIG_SYS_NAND_U_BOOT_DST CONFIG_SYS_TEXT_BASE | |
235 | + | |
236 | +/* | |
237 | + * Include SoC specific configuration | |
238 | + */ | |
239 | +#include <asm/arch/config.h> | |
240 | + | |
241 | +#endif /* __CONFIG_WORK_92105_H__*/ |
include/dtt.h
... | ... | @@ -12,13 +12,14 @@ |
12 | 12 | #define _DTT_H_ |
13 | 13 | |
14 | 14 | #if defined(CONFIG_DTT_ADM1021) || \ |
15 | - defined(CONFIG_DTT_ADT7460) || \ | |
16 | - defined(CONFIG_DTT_DS1621) || \ | |
17 | - defined(CONFIG_DTT_DS1775) || \ | |
18 | - defined(CONFIG_DTT_LM63) || \ | |
19 | - defined(CONFIG_DTT_LM73) || \ | |
20 | - defined(CONFIG_DTT_LM75) || \ | |
21 | - defined(CONFIG_DTT_LM81) | |
15 | + defined(CONFIG_DTT_ADT7460) || \ | |
16 | + defined(CONFIG_DTT_DS1621) || \ | |
17 | + defined(CONFIG_DTT_DS1775) || \ | |
18 | + defined(CONFIG_DTT_DS620) || \ | |
19 | + defined(CONFIG_DTT_LM63) || \ | |
20 | + defined(CONFIG_DTT_LM73) || \ | |
21 | + defined(CONFIG_DTT_LM75) || \ | |
22 | + defined(CONFIG_DTT_LM81) | |
22 | 23 | |
23 | 24 | #define CONFIG_DTT /* We have a DTT */ |
24 | 25 |
include/image.h
... | ... | @@ -242,6 +242,7 @@ |
242 | 242 | #define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */ |
243 | 243 | #define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA Preloader */ |
244 | 244 | #define IH_TYPE_X86_SETUP 20 /* x86 setup.bin Image */ |
245 | +#define IH_TYPE_LPC32XXIMAGE 21 /* x86 setup.bin Image */ | |
245 | 246 | |
246 | 247 | /* |
247 | 248 | * Compression Types |
include/netdev.h
... | ... | @@ -57,6 +57,7 @@ |
57 | 57 | void gt6426x_eth_initialize(bd_t *bis); |
58 | 58 | int ks8851_mll_initialize(u8 dev_num, int base_addr); |
59 | 59 | int lan91c96_initialize(u8 dev_num, int base_addr); |
60 | +int lpc32xx_eth_initialize(bd_t *bis); | |
60 | 61 | int macb_eth_initialize(int id, void *regs, unsigned int phy_addr); |
61 | 62 | int mcdmafec_initialize(bd_t *bis); |
62 | 63 | int mcffec_initialize(bd_t *bis); |
tools/Makefile
tools/lpc32xximage.c
1 | +/* | |
2 | + * Image manipulator for LPC32XX SoCs | |
3 | + * | |
4 | + * (C) Copyright 2015 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * Derived from omapimage.c: | |
8 | + * | |
9 | + * (C) Copyright 2010 | |
10 | + * Linaro LTD, www.linaro.org | |
11 | + * Author: John Rigby <john.rigby@linaro.org> | |
12 | + * Based on TI's signGP.c | |
13 | + * | |
14 | + * (C) Copyright 2009 | |
15 | + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. | |
16 | + * | |
17 | + * (C) Copyright 2008 | |
18 | + * Marvell Semiconductor <www.marvell.com> | |
19 | + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> | |
20 | + * | |
21 | + * SPDX-License-Identifier: GPL-2.0+ | |
22 | + */ | |
23 | + | |
24 | +#include "imagetool.h" | |
25 | +#include <compiler.h> | |
26 | +#include <image.h> | |
27 | + | |
28 | +/* | |
29 | + * NAND page 0 boot header | |
30 | + */ | |
31 | + | |
32 | +struct nand_page_0_boot_header { | |
33 | + uint32_t data[129]; | |
34 | + uint32_t pad[383]; | |
35 | +}; | |
36 | + | |
37 | +/* | |
38 | + * Default ICC (interface configuration data [sic]) if none specified | |
39 | + * in board config | |
40 | + */ | |
41 | + | |
42 | +#ifndef LPC32XX_BOOT_ICR | |
43 | +#define LPC32XX_BOOT_ICR 0x00000096 | |
44 | +#endif | |
45 | + | |
46 | +/* | |
47 | + * Default boot NAND page size if none specified in board config | |
48 | + */ | |
49 | + | |
50 | +#ifndef LPC32XX_BOOT_NAND_PAGESIZE | |
51 | +#define LPC32XX_BOOT_NAND_PAGESIZE 2048 | |
52 | +#endif | |
53 | + | |
54 | +/* | |
55 | + * Default boot NAND pages per sector if none specified in board config | |
56 | + */ | |
57 | + | |
58 | +#ifndef LPC32XX_BOOT_NAND_PAGES_PER_SECTOR | |
59 | +#define LPC32XX_BOOT_NAND_PAGES_PER_SECTOR 64 | |
60 | +#endif | |
61 | + | |
62 | +/* | |
63 | + * Maximum size for boot code is 56K unless defined in board config | |
64 | + */ | |
65 | + | |
66 | +#ifndef LPC32XX_BOOT_CODESIZE | |
67 | +#define LPC32XX_BOOT_CODESIZE (56*1024) | |
68 | +#endif | |
69 | + | |
70 | +/* signature byte for a readable block */ | |
71 | + | |
72 | +#define LPC32XX_BOOT_BLOCK_OK 0xaa | |
73 | + | |
74 | +static struct nand_page_0_boot_header lpc32xximage_header; | |
75 | + | |
76 | +static int lpc32xximage_check_image_types(uint8_t type) | |
77 | +{ | |
78 | + if (type == IH_TYPE_LPC32XXIMAGE) | |
79 | + return EXIT_SUCCESS; | |
80 | + return EXIT_FAILURE; | |
81 | +} | |
82 | + | |
83 | +static int lpc32xximage_verify_header(unsigned char *ptr, int image_size, | |
84 | + struct image_tool_params *params) | |
85 | +{ | |
86 | + struct nand_page_0_boot_header *hdr = | |
87 | + (struct nand_page_0_boot_header *)ptr; | |
88 | + | |
89 | + /* turn image size from bytes to NAND pages, page 0 included */ | |
90 | + int image_size_in_pages = ((image_size - 1) | |
91 | + / LPC32XX_BOOT_NAND_PAGESIZE); | |
92 | + | |
93 | + if (hdr->data[0] != (0xff & LPC32XX_BOOT_ICR)) | |
94 | + return -1; | |
95 | + if (hdr->data[1] != (0xff & ~LPC32XX_BOOT_ICR)) | |
96 | + return -1; | |
97 | + if (hdr->data[2] != (0xff & LPC32XX_BOOT_ICR)) | |
98 | + return -1; | |
99 | + if (hdr->data[3] != (0xff & ~LPC32XX_BOOT_ICR)) | |
100 | + return -1; | |
101 | + if (hdr->data[4] != (0xff & image_size_in_pages)) | |
102 | + return -1; | |
103 | + if (hdr->data[5] != (0xff & ~image_size_in_pages)) | |
104 | + return -1; | |
105 | + if (hdr->data[6] != (0xff & image_size_in_pages)) | |
106 | + return -1; | |
107 | + if (hdr->data[7] != (0xff & ~image_size_in_pages)) | |
108 | + return -1; | |
109 | + if (hdr->data[8] != (0xff & image_size_in_pages)) | |
110 | + return -1; | |
111 | + if (hdr->data[9] != (0xff & ~image_size_in_pages)) | |
112 | + return -1; | |
113 | + if (hdr->data[10] != (0xff & image_size_in_pages)) | |
114 | + return -1; | |
115 | + if (hdr->data[11] != (0xff & ~image_size_in_pages)) | |
116 | + return -1; | |
117 | + if (hdr->data[12] != LPC32XX_BOOT_BLOCK_OK) | |
118 | + return -1; | |
119 | + if (hdr->data[128] != LPC32XX_BOOT_BLOCK_OK) | |
120 | + return -1; | |
121 | + return 0; | |
122 | +} | |
123 | + | |
124 | +static void print_hdr_byte(struct nand_page_0_boot_header *hdr, int ofs) | |
125 | +{ | |
126 | + printf("header[%d] = %02x\n", ofs, hdr->data[ofs]); | |
127 | +} | |
128 | + | |
129 | +static void lpc32xximage_print_header(const void *ptr) | |
130 | +{ | |
131 | + struct nand_page_0_boot_header *hdr = | |
132 | + (struct nand_page_0_boot_header *)ptr; | |
133 | + int ofs; | |
134 | + | |
135 | + for (ofs = 0; ofs <= 12; ofs++) | |
136 | + print_hdr_byte(hdr, ofs); | |
137 | + print_hdr_byte(hdr, 128); | |
138 | +} | |
139 | + | |
140 | +static void lpc32xximage_set_header(void *ptr, struct stat *sbuf, int ifd, | |
141 | + struct image_tool_params *params) | |
142 | +{ | |
143 | + struct nand_page_0_boot_header *hdr = | |
144 | + (struct nand_page_0_boot_header *)ptr; | |
145 | + | |
146 | + /* turn image size from bytes to NAND pages, page 0 included */ | |
147 | + int image_size_in_pages = ((sbuf->st_size | |
148 | + + LPC32XX_BOOT_NAND_PAGESIZE - 1) | |
149 | + / LPC32XX_BOOT_NAND_PAGESIZE); | |
150 | + | |
151 | + /* fill header -- default byte value is 0x00, not 0xFF */ | |
152 | + memset((void *)hdr, 0, sizeof(*hdr)); | |
153 | + hdr->data[0] = (hdr->data[2] = 0xff & LPC32XX_BOOT_ICR); | |
154 | + hdr->data[1] = (hdr->data[3] = 0xff & ~LPC32XX_BOOT_ICR); | |
155 | + hdr->data[4] = (hdr->data[6] = (hdr->data[8] | |
156 | + = (hdr->data[10] = 0xff & image_size_in_pages))); | |
157 | + hdr->data[5] = (hdr->data[7] = (hdr->data[9] | |
158 | + = (hdr->data[11] = 0xff & ~image_size_in_pages))); | |
159 | + hdr->data[12] = (hdr->data[128] = LPC32XX_BOOT_BLOCK_OK); | |
160 | +} | |
161 | + | |
162 | +/* | |
163 | + * lpc32xximage parameters | |
164 | + */ | |
165 | +U_BOOT_IMAGE_TYPE( | |
166 | + lpc32xximage, | |
167 | + "LPC32XX Boot Image", | |
168 | + sizeof(lpc32xximage_header), | |
169 | + (void *)&lpc32xximage_header, | |
170 | + NULL, | |
171 | + lpc32xximage_verify_header, | |
172 | + lpc32xximage_print_header, | |
173 | + lpc32xximage_set_header, | |
174 | + NULL, | |
175 | + lpc32xximage_check_image_types, | |
176 | + NULL, | |
177 | + NULL | |
178 | +); |