diff mbox

[U-Boot,v3,5/5] New board support: Nokia RX-51 aka N900

Message ID 1350156720-13387-6-git-send-email-pali.rohar@gmail.com
State Changes Requested
Delegated to: Tom Rini
Headers show

Commit Message

Pali Rohár Oct. 13, 2012, 7:32 p.m. UTC
Based on previous work by: Alistair Buxton <a.j.buxton@gmail.com>

Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
Cc: Ивайло Димитров <freemangordon@abv.bg>
---
Changes since v2:
   - Added documentation in doc/README.nokia_rx51
   - Updated MAINTAINERS
   - Fixed Fix omap_mmc_init
   - Code for errata 430973 workaround
   - Added board specified atag support
   - Generate omap atag table instead reusing from NOLO
   - Load bootmenu.src always
   - Enabled ext4 support
   - Fixed comments
   - Reserve protected RAM for attached kernel
   - Rewritten assembler code in lowlevel_init.S
   - Reset lp5523 led on init

Changes since v1:
   - Set correct configs for Memory Map
   - Enable passing memory tag to kernel atags
   - Use gpio input command for detecting keyboard slide
   - Restore powerbus state after calling twl4030 regulator code
   - Renamed command noloboot to attachboot
   - Atag address must be always 0x80000100, removed code from lowlevel
   - Added usb vendor, product id and product name
   - Enabled command line editing
   - Fixed keymap and cursor keys

Changes since original version:
   - Removed Makefile targets: clean and distclean
   - Rewrited bootcommand and env variables in nokia_rx51.h
   - Removed useless CONFIG defines in nokia_rx51.h
   - Disable L2 cache with CONFIG_SYS_L2CACHE_OFF - fixed battery draining
   - Added onenand support (default disabled due to big u-boot size)
   - Moved inlined asm code to new file lowlevel_init.S
   - Fixed commit message

 MAINTAINERS                      |    4 +
 board/nokia/rx51/Makefile        |   46 +++
 board/nokia/rx51/lowlevel_init.S |  209 ++++++++++++
 board/nokia/rx51/rx51.c          |  673 ++++++++++++++++++++++++++++++++++++++
 board/nokia/rx51/rx51.h          |  389 ++++++++++++++++++++++
 board/nokia/rx51/tag_omap.h      |  311 ++++++++++++++++++
 boards.cfg                       |    1 +
 doc/README.nokia_rx51            |  104 ++++++
 include/configs/nokia_rx51.h     |  452 +++++++++++++++++++++++++
 9 files changed, 2189 insertions(+)
 create mode 100644 board/nokia/rx51/Makefile
 create mode 100644 board/nokia/rx51/lowlevel_init.S
 create mode 100644 board/nokia/rx51/rx51.c
 create mode 100644 board/nokia/rx51/rx51.h
 create mode 100644 board/nokia/rx51/tag_omap.h
 create mode 100644 doc/README.nokia_rx51
 create mode 100644 include/configs/nokia_rx51.h

Comments

Marek Vasut Oct. 14, 2012, 12:06 a.m. UTC | #1
Dear Pali Rohár,

> Based on previous work by: Alistair Buxton <a.j.buxton@gmail.com>
> 
> Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
> Cc: Ивайло Димитров <freemangordon@abv.bg>

Can we please stick to ASCII instead of UTF8?

Cc: Ivaylo Dimitrov (if I'm not mistaken)

> ---
> Changes since v2:
>    - Added documentation in doc/README.nokia_rx51
>    - Updated MAINTAINERS
>    - Fixed Fix omap_mmc_init
>    - Code for errata 430973 workaround
>    - Added board specified atag support
>    - Generate omap atag table instead reusing from NOLO
>    - Load bootmenu.src always
>    - Enabled ext4 support
>    - Fixed comments
>    - Reserve protected RAM for attached kernel
>    - Rewritten assembler code in lowlevel_init.S
>    - Reset lp5523 led on init
> 
> Changes since v1:
>    - Set correct configs for Memory Map
>    - Enable passing memory tag to kernel atags
>    - Use gpio input command for detecting keyboard slide
>    - Restore powerbus state after calling twl4030 regulator code
>    - Renamed command noloboot to attachboot
>    - Atag address must be always 0x80000100, removed code from lowlevel
>    - Added usb vendor, product id and product name
>    - Enabled command line editing
>    - Fixed keymap and cursor keys
> 
> Changes since original version:
>    - Removed Makefile targets: clean and distclean
>    - Rewrited bootcommand and env variables in nokia_rx51.h
>    - Removed useless CONFIG defines in nokia_rx51.h
>    - Disable L2 cache with CONFIG_SYS_L2CACHE_OFF - fixed battery draining
>    - Added onenand support (default disabled due to big u-boot size)
>    - Moved inlined asm code to new file lowlevel_init.S
>    - Fixed commit message
> 
>  MAINTAINERS                      |    4 +
>  board/nokia/rx51/Makefile        |   46 +++
>  board/nokia/rx51/lowlevel_init.S |  209 ++++++++++++
>  board/nokia/rx51/rx51.c          |  673
> ++++++++++++++++++++++++++++++++++++++ board/nokia/rx51/rx51.h          | 
> 389 ++++++++++++++++++++++
>  board/nokia/rx51/tag_omap.h      |  311 ++++++++++++++++++
>  boards.cfg                       |    1 +
>  doc/README.nokia_rx51            |  104 ++++++
>  include/configs/nokia_rx51.h     |  452 +++++++++++++++++++++++++
>  9 files changed, 2189 insertions(+)
>  create mode 100644 board/nokia/rx51/Makefile
>  create mode 100644 board/nokia/rx51/lowlevel_init.S
>  create mode 100644 board/nokia/rx51/rx51.c
>  create mode 100644 board/nokia/rx51/rx51.h
>  create mode 100644 board/nokia/rx51/tag_omap.h
>  create mode 100644 doc/README.nokia_rx51
>  create mode 100644 include/configs/nokia_rx51.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 971235b..613d8cd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1009,6 +1009,10 @@ Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
> 
>  	armadillo-800eva	R8A7740 (RMOBILE SoC)
> 
> +Pali Rohár <pali.rohar@gmail.com>
> +
> +	nokia_rx51	ARM ARMV7 (OMAP3xx SoC)

OMAP3xxx or OMAP34xx

> +
>  -------------------------------------------------------------------------
> 
[..]

> +relocaddr:		/* address of this relocaddr section after coping */
> +	.word .		/* address of section (calculated at compile time) */
> +
> +startaddr:		/* address of u-boot after copying */
> +	.word CONFIG_SYS_TEXT_BASE
> +
> +kernaddr:		/* address of kernel after copying */
> +	.word KERNEL_ADDRESS
> +
> +kernsize:		/* maximal size of kernel image */
> +	.word KERNEL_MAXSIZE
> +
> +kernoffs:		/* offset of kernel image in loaded u-boot */
> +	.word KERNEL_OFFSET
> +
> +imagesize:		/* maximal size of image */
> +	.word IMAGE_MAXSIZE
> +
> +ih_magic:		/* IH_MAGIC in big endian from include/image.h */
> +	.word 0x56190527
> +
> +/*

Try using the new kerneldoc style, the tools are now in.

See eg. here about the annotations:
http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/144173

Also see:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kernel-
doc-nano-HOWTO.txt

> + * Routine: save_boot_params (called after reset from start.S)
> + * Description: Copy attached kernel to address KERNEL_ADDRESS
> + *              Copy u-boot to address CONFIG_SYS_TEXT_BASE
> + *              Return to copied u-boot address
> + */
> +
> +.global save_boot_params
> +save_boot_params:
[...]

How much of the assembler crap can be made C?

[...]

> +static char *boot_reason_ptr;
> +static char *hw_build_ptr;
> +static char *nolo_version_ptr;
> +static char *boot_mode_ptr;
> +
> +/*
> + * Routine: init_omap_tags
> + * Description: Initialize pointers to values in tag_omap
> + */
> +static void init_omap_tags(void)
> +{
> +	char *component;
> +	char *version;
> +	int i = 0;
> +	while (omap[i].hdr.tag) {
> +		switch (omap[i].hdr.tag) {
> +		case OMAP_TAG_BOOT_REASON:
> +			boot_reason_ptr = omap[i].u.boot_reason.reason_str;
> +			break;
> +		case OMAP_TAG_VERSION_STR:
> +			component = omap[i].u.version.component;
> +			version = omap[i].u.version.version;
> +			if (strcmp(component, "hw-build") == 0)
> +				hw_build_ptr = version;
> +			else if (strcmp(component, "nolo") == 0)
> +				nolo_version_ptr = version;
> +			else if (strcmp(component, "boot-mode") == 0)
> +				boot_mode_ptr = version;
> +			break;

default: missing.

> +		}
> +		++i;

i++;

> +	}
> +}

[...]

> +	/* append omap atag only if env setup_omap_atag is set to 1 */
> +	str = getenv("setup_omap_atag");
> +	if (!str || strcmp(str, "1") != 0)

str[0] == '1' ? But still, you only want to check if it's defined, no?

[...]

> +/*
> + * Routine: twl4030_regulator_set_mode
> + * Description: Set twl4030 regulator mode over i2c powerbus.
> + */
> +static void twl4030_regulator_set_mode(u8 id, u8 mode)
> +{
> +	u16 msg = MSG_SINGULAR(DEV_GRP_P1, id, mode);
> +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg >> 8,
> +			TWL4030_PM_MASTER_PB_WORD_MSB);
> +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg & 0xff,
> +			TWL4030_PM_MASTER_PB_WORD_LSB);

Uh, is this somehow special that you can't do longer transfer?

> +}
> +
> +static void omap3_emu_romcode_call(u32 service_id, u32 *parameters)
> +{
> +	u32 i, num_params = *parameters;
> +	u32 *sram_scratch_space = (u32 *)OMAP3_PUBLIC_SRAM_SCRATCH_AREA;
> +
> +	/*
> +	 * copy the parameters to an un-cached area to avoid coherency
> +	 * issues
> +	 */

_WHAT_ ?!

Use dcache_flush(). The Omap3 rom won't cope with cache memory? Actually -- why 
do you even do call into ROM ?

> +	for (i = 0; i < num_params; i++) {
> +		__raw_writel(*parameters, sram_scratch_space);
> +		parameters++;
> +		sram_scratch_space++;
> +	}
> +
> +	/* Now make the PPA call */
> +	do_omap3_emu_romcode_call(service_id, OMAP3_PUBLIC_SRAM_SCRATCH_AREA);
> +}
> +

[...]

> +	/* set env variable attkernaddr for relocated kernel */
> +	sprintf(buf, "%#x", KERNEL_ADDRESS);
> +	setenv("attkernaddr", buf);

Uhhh ? This definitelly isn't right! What are you trying to achieve here?

> +
> +	/* initialize omap tags */
> +	init_omap_tags();
> +
> +	/* reuse atags from previous bootloader */
> +	reuse_atags();
> +
> +	dieid_num_r();
> +	print_cpuinfo();
> +
> +	/*
> +	 * Cortex-A8(r1p0..r1p2) errata 430973 workaround
> +	 * Set IBE bit in Auxiliary Control Register
> +	 */
> +	omap3_update_aux_cr_secure_rx51(1 << 6, 0);
> +
> +	return 0;
> +}
> +
> +/*
> + * Routine: set_muxconf_regs
> + * Description: Setting up the configuration Mux registers specific to the
> + *		hardware. Many pins need to be moved from protect to primary
> + *		mode.
> + */
> +void set_muxconf_regs(void)
> +{
> +	MUX_RX51();
> +}
> +
> +static unsigned long int twl_wd_time; /* last time of watchdog reset */
> +static unsigned long int twl_i2c_lock;

Are you sure you want to use global vars for these? These won't work before 
reloc!

[..]

> +
> +static u8 keys[8];
> +static u8 old_keys[8] = {0, 0, 0, 0, 0, 0, 0, 0};
> +#define KEYBUF_SIZE 32
> +static u8 keybuf[KEYBUF_SIZE];
> +static u8 keybuf_head;
> +static u8 keybuf_tail;

How much of this can be made const ?

> +/*
> + * Routine: rx51_kp_init
> + * Description: Initialize HW keyboard.
> + */
> +int rx51_kp_init(void)
> +{
> +	int ret = 0;
> +	u8 ctrl;
> +	ret = twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD, &ctrl,
> +		TWL4030_KEYPAD_KEYP_CTRL_REG);
> +

if (ret)
	return;

... do the rest here without additional indent ...

> +	if (!ret) {
> +		/* turn on keyboard and use hardware scanning */
> +		ctrl |= TWL4030_KEYPAD_CTRL_KBD_ON;
[...]

> +static void rx51_kp_fill(u8 k, u8 mods)
> +{

This magic needs at least _some_ documentation.

> +	if (!(mods & 2) && (k == 18 || k == 31 || k == 33 || k == 34)) {
> +		/* cursor keys, without fn */
> +		keybuf[keybuf_tail++] = '\e';

[...]

> +int rx51_kp_tstc(void)
> +{
> +	u8 c, r, dk, i;
> +	u8 intr;
> +	u8 mods;
> +
> +	/* localy lock twl4030 i2c bus */
> +	if (test_and_set_bit(0, &twl_i2c_lock))
> +		return 0;
> +
> +	/* twl4030 remembers up to 2 events */
> +	for (i = 0; i < 2; i++) {
> +
> +		/* check interrupt register for events */
> +		twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD, &intr,
> +				TWL4030_KEYPAD_KEYP_ISR1+(2*i));
> +
> +		if (intr&1) { /* got an event */

I will let you think about how to optimize the indent depth here ...

> +			/* read the key state */
> +			i2c_read(TWL4030_CHIP_KEYPAD,
> +				TWL4030_KEYPAD_FULL_CODE_7_0, 1, keys, 8);
> +
> +			/* cut out modifier keys from the keystate */
> +			mods = keys[4] >> 4;
> +			keys[4] &= 0x0f;
> +
> +			for (c = 0; c < 8; c++) {
> +
> +				/* get newly pressed keys only */
> +				dk = ((keys[c] ^ old_keys[c])&keys[c]);
> +				old_keys[c] = keys[c];
> +
> +				/* fill the keybuf */
> +				for (r = 0; r < 8; r++) {
> +					if (dk&1)

[...]


> +/*
> + * Routine: rx51_kp_getc
> + * Description: Get last pressed key (from buffer).
> + */
> +int rx51_kp_getc(void)
> +{
> +	keybuf_head %= KEYBUF_SIZE;
> +	while (!rx51_kp_tstc()) {
> +		udelay(1);
> +		hw_watchdog_reset();

WATCHDOG_RESET() and drop the udelay();

> +	}
> +	return keybuf[keybuf_head++];
> +}
> +
> +/*
> + * Routine: board_mmc_init
> + * Description: Initialize mmc devices.
> + */
> +int board_mmc_init(bd_t *bis)
> +{
> +	omap_mmc_init(0, 0, 0);
> +	omap_mmc_init(1, 0, 0);
> +	return 0;
> +}

[...]


> +#define tostring(s)		#s
> +#define stringify(s)		tostring(s)

We do have __stringify(), use that!
[...]
Albert ARIBAUD Oct. 14, 2012, 8:31 a.m. UTC | #2
Hi Marek,

On Sun, 14 Oct 2012 02:06:49 +0200, Marek Vasut <marex@denx.de> wrote:

> Dear Pali Rohár,
> 
> > Based on previous work by: Alistair Buxton <a.j.buxton@gmail.com>
> > 
> > Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
> > Cc: Ивайло Димитров <freemangordon@abv.bg>
> 
> Can we please stick to ASCII instead of UTF8?

(cc:ing Wolfgang)

Not to nitpick too much here since for this particular contributor it
will not make a difference, but UTF-8 in e-mail addresses is fine to me
[1] and is useful for people whose roman-alphabet-based names include
diacritics not available in ASCII.

Thus, as far as constraints on e-mail addresses are concerned, I'd
rather allow UTF-8 but impose the use of the roman alphabet (if needed,
by transliterating) as opposed to e.g. using the cyrillic alphabet, or
ideograms, because the common language here is English, so everyone
posting here is at least used to roman, but not necessarily to other
alphabets or writing systems.

[1] if not always to 'pwclient git-am', but then 'pwclient get' + 'git
am' works fine.

Amicalement,
Pali Rohár Oct. 16, 2012, 2:43 p.m. UTC | #3
On Sunday 14 October 2012 02:06:49 Marek Vasut wrote:
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 971235b..613d8cd 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1009,6 +1009,10 @@ Nobuhiro Iwamatsu
> > <nobuhiro.iwamatsu.yj@renesas.com>> 
> >  	armadillo-800eva	R8A7740 (RMOBILE SoC)
> > 
> > +Pali Rohár <pali.rohar@gmail.com>
> > +
> > +	nokia_rx51	ARM ARMV7 (OMAP3xx SoC)
> 
> OMAP3xxx or OMAP34xx
> 

Ok.

> 
> > +relocaddr:		/* address of this relocaddr section after
> > coping */ +	.word .		/* address of section (calculated 
at
> > compile time) */ +
> > +startaddr:		/* address of u-boot after copying */
> > +	.word CONFIG_SYS_TEXT_BASE
> > +
> > +kernaddr:		/* address of kernel after copying */
> > +	.word KERNEL_ADDRESS
> > +
> > +kernsize:		/* maximal size of kernel image */
> > +	.word KERNEL_MAXSIZE
> > +
> > +kernoffs:		/* offset of kernel image in loaded u-boot 
*/
> > +	.word KERNEL_OFFSET
> > +
> > +imagesize:		/* maximal size of image */
> > +	.word IMAGE_MAXSIZE
> > +
> > +ih_magic:		/* IH_MAGIC in big endian from 
include/image.h */
> > +	.word 0x56190527
> > +
> > +/*
> 
> Try using the new kerneldoc style, the tools are now in.
> 
> See eg. here about the annotations:
> http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/14417
> 3
> 
> Also see:
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.gi
> t;a=blob;f=Documentation/kernel- doc-nano-HOWTO.txt
> 

Ok.

> > + * Routine: save_boot_params (called after reset from
> > start.S) + * Description: Copy attached kernel to address
> > KERNEL_ADDRESS + *              Copy u-boot to address
> > CONFIG_SYS_TEXT_BASE + *              Return to copied
> > u-boot address
> > + */
> > +
> > +.global save_boot_params
> 
> > +save_boot_params:
> [...]
> 
> How much of the assembler crap can be made C?
> 

Nothing. This code must be in assembler because stack is not 
initialized. Also we must be sure that U-Boot will not overwrite 
attached kernel (with can be in U-Boot malloc/monitor area...)

> 
> > +static char *boot_reason_ptr;
> > +static char *hw_build_ptr;
> > +static char *nolo_version_ptr;
> > +static char *boot_mode_ptr;
> > +
> > +/*
> > + * Routine: init_omap_tags
> > + * Description: Initialize pointers to values in tag_omap
> > + */
> > +static void init_omap_tags(void)
> > +{
> > +	char *component;
> > +	char *version;
> > +	int i = 0;
> > +	while (omap[i].hdr.tag) {
> > +		switch (omap[i].hdr.tag) {
> > +		case OMAP_TAG_BOOT_REASON:
> > +			boot_reason_ptr = 
omap[i].u.boot_reason.reason_str;
> > +			break;
> > +		case OMAP_TAG_VERSION_STR:
> > +			component = omap[i].u.version.component;
> > +			version = omap[i].u.version.version;
> > +			if (strcmp(component, "hw-build") == 0)
> > +				hw_build_ptr = version;
> > +			else if (strcmp(component, "nolo") == 0)
> > +				nolo_version_ptr = version;
> > +			else if (strcmp(component, "boot-mode") == 0)
> > +				boot_mode_ptr = version;
> > +			break;
> 
> default: missing.
> 

Is really needed? (if yes, I can add default: break;)

> > +		}
> > +		++i;
> 
> i++;
> 

Reason? ++i and i++ are same (for this situation).

> > +	/* append omap atag only if env setup_omap_atag is set to 
1
> > */ +	str = getenv("setup_omap_atag");
> > +	if (!str || strcmp(str, "1") != 0)
> 
> str[0] == '1' ? But still, you only want to check if it's
> defined, no?
> 

Hm, I'm checking if setup_omap_atag is 1. But is it problem?

> 
> > +/*
> > + * Routine: twl4030_regulator_set_mode
> > + * Description: Set twl4030 regulator mode over i2c
> > powerbus.
> > + */
> > +static void twl4030_regulator_set_mode(u8 id, u8 mode)
> > +{
> > +	u16 msg = MSG_SINGULAR(DEV_GRP_P1, id, mode);
> > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg >> 8,
> > +			TWL4030_PM_MASTER_PB_WORD_MSB);
> > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg & 0xff,
> > +			TWL4030_PM_MASTER_PB_WORD_LSB);
> 
> Uh, is this somehow special that you can't do longer transfer?
> 

I do not know how, because registers are different (MSB and LSB).

> 
> > +	/* set env variable attkernaddr for relocated kernel */
> > +	sprintf(buf, "%#x", KERNEL_ADDRESS);
> > +	setenv("attkernaddr", buf);
> 
> Uhhh ? This definitelly isn't right! What are you trying to
> achieve here?

I think it is right. I want to store address of kernel (in hex 
with leading 0x) to env attkernaddr. And %#x is doing it.

> > +
> > +static unsigned long int twl_wd_time; /* last time of
> > watchdog reset */ +static unsigned long int twl_i2c_lock;
> 
> Are you sure you want to use global vars for these? These won't
> work before reloc!
> 

Why it does not work before reloc? U-Boot is on n900 always 
started from RAM.

> 
> > +
> > +static u8 keys[8];
> > +static u8 old_keys[8] = {0, 0, 0, 0, 0, 0, 0, 0};
> > +#define KEYBUF_SIZE 32
> > +static u8 keybuf[KEYBUF_SIZE];
> > +static u8 keybuf_head;
> > +static u8 keybuf_tail;
> 
> How much of this can be made const ?
> 

Nothing. All is for keyboard and is changed by keyboard functions 
(tstc, getc)

> 
> This magic needs at least _some_ documentation.
> 
> > +	if (!(mods & 2) && (k == 18 || k == 31 || k == 33 || k ==
> > 34)) { +		/* cursor keys, without fn */
> > +		keybuf[keybuf_tail++] = '\e';
> 

there is "cursor keys without fn" (fn is "meta" key on n900). So 
this condition check if some cursor key (without fn) was pressed.

> 
> > +int rx51_kp_tstc(void)
> > +{
> > +	u8 c, r, dk, i;
> > +	u8 intr;
> > +	u8 mods;
> > +
> > +	/* localy lock twl4030 i2c bus */
> > +	if (test_and_set_bit(0, &twl_i2c_lock))
> > +		return 0;
> > +
> > +	/* twl4030 remembers up to 2 events */
> > +	for (i = 0; i < 2; i++) {
> > +
> > +		/* check interrupt register for events */
> > +		twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD, &intr,
> > +				TWL4030_KEYPAD_KEYP_ISR1+(2*i));
> > +
> > +		if (intr&1) { /* got an event */
> 
> I will let you think about how to optimize the indent depth
> here ...

Ok, I will optimize indentation. This code (keyboard support) was 
written by Alistair Buxton and I reused it with minimal changes.

> 
> > +#define tostring(s)		#s
> > +#define stringify(s)		tostring(s)
> 
> We do have __stringify(), use that!

Ok, in April (when I wrote this part of code) __stringify was not 
in U-Boot (I checked it).
Marek Vasut Oct. 16, 2012, 2:55 p.m. UTC | #4
Dear Pali Rohár,

[...]

> 
> Nothing. This code must be in assembler because stack is not
> initialized. Also we must be sure that U-Boot will not overwrite
> attached kernel (with can be in U-Boot malloc/monitor area...)

Don't we have something that can reserve a memory area?

> > > +static char *boot_reason_ptr;
> > > +static char *hw_build_ptr;
> > > +static char *nolo_version_ptr;
> > > +static char *boot_mode_ptr;
> > > +
> > > +/*
> > > + * Routine: init_omap_tags
> > > + * Description: Initialize pointers to values in tag_omap
> > > + */
> > > +static void init_omap_tags(void)
> > > +{
> > > +	char *component;
> > > +	char *version;
> > > +	int i = 0;
> > > +	while (omap[i].hdr.tag) {
> > > +		switch (omap[i].hdr.tag) {
> > > +		case OMAP_TAG_BOOT_REASON:
> > > +			boot_reason_ptr =
> 
> omap[i].u.boot_reason.reason_str;
> 
> > > +			break;
> > > +		case OMAP_TAG_VERSION_STR:
> > > +			component = omap[i].u.version.component;
> > > +			version = omap[i].u.version.version;
> > > +			if (strcmp(component, "hw-build") == 0)
> > > +				hw_build_ptr = version;
> > > +			else if (strcmp(component, "nolo") == 0)
> > > +				nolo_version_ptr = version;
> > > +			else if (strcmp(component, "boot-mode") == 0)
> > > +				boot_mode_ptr = version;
> > > +			break;
> > 
> > default: missing.
> 
> Is really needed? (if yes, I can add default: break;)

It's a good practice.

> > > +		}
> > > +		++i;
> > 
> > i++;
> 
> Reason? ++i and i++ are same (for this situation).

On arm, yes, on intel, no in certain cases. Also, to keep the code consistent, 
go with postdecrement.

> > > +	/* append omap atag only if env setup_omap_atag is set to
> 
> 1
> 
> > > */ +	str = getenv("setup_omap_atag");
> > > +	if (!str || strcmp(str, "1") != 0)
> > 
> > str[0] == '1' ? But still, you only want to check if it's
> > defined, no?
> 
> Hm, I'm checking if setup_omap_atag is 1. But is it problem?

Then why not str[0] == '1' ?

> > > +/*
> > > + * Routine: twl4030_regulator_set_mode
> > > + * Description: Set twl4030 regulator mode over i2c
> > > powerbus.
> > > + */
> > > +static void twl4030_regulator_set_mode(u8 id, u8 mode)
> > > +{
> > > +	u16 msg = MSG_SINGULAR(DEV_GRP_P1, id, mode);
> > > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg >> 8,
> > > +			TWL4030_PM_MASTER_PB_WORD_MSB);
> > > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg & 0xff,
> > > +			TWL4030_PM_MASTER_PB_WORD_LSB);
> > 
> > Uh, is this somehow special that you can't do longer transfer?
> 
> I do not know how, because registers are different (MSB and LSB).

Investigate ;-)

> > > +	/* set env variable attkernaddr for relocated kernel */
> > > +	sprintf(buf, "%#x", KERNEL_ADDRESS);
> > > +	setenv("attkernaddr", buf);
> > 
> > Uhhh ? This definitelly isn't right! What are you trying to
> > achieve here?
> 
> I think it is right. I want to store address of kernel (in hex
> with leading 0x) to env attkernaddr. And %#x is doing it.

Ah, now that you mentioned that you don't want kernel to be rewritten, I see the 
point of this variable.

> > > +
> > > +static unsigned long int twl_wd_time; /* last time of
> > > watchdog reset */ +static unsigned long int twl_i2c_lock;
> > 
> > Are you sure you want to use global vars for these? These won't
> > work before reloc!
> 
> Why it does not work before reloc? U-Boot is on n900 always
> started from RAM.

The BSS isn't cleared though.

> > > +
> > > +static u8 keys[8];
> > > +static u8 old_keys[8] = {0, 0, 0, 0, 0, 0, 0, 0};
> > > +#define KEYBUF_SIZE 32
> > > +static u8 keybuf[KEYBUF_SIZE];
> > > +static u8 keybuf_head;
> > > +static u8 keybuf_tail;
> > 
> > How much of this can be made const ?
> 
> Nothing. All is for keyboard and is changed by keyboard functions
> (tstc, getc)
> 
> > This magic needs at least _some_ documentation.
> > 
> > > +	if (!(mods & 2) && (k == 18 || k == 31 || k == 33 || k ==
> > > 34)) { +		/* cursor keys, without fn */
> > > +		keybuf[keybuf_tail++] = '\e';
> 
> there is "cursor keys without fn" (fn is "meta" key on n900). So
> this condition check if some cursor key (without fn) was pressed.

Good, document it.

> > > +int rx51_kp_tstc(void)
> > > +{
> > > +	u8 c, r, dk, i;
> > > +	u8 intr;
> > > +	u8 mods;
> > > +
> > > +	/* localy lock twl4030 i2c bus */
> > > +	if (test_and_set_bit(0, &twl_i2c_lock))
> > > +		return 0;
> > > +
> > > +	/* twl4030 remembers up to 2 events */
> > > +	for (i = 0; i < 2; i++) {
> > > +
> > > +		/* check interrupt register for events */
> > > +		twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD, &intr,
> > > +				TWL4030_KEYPAD_KEYP_ISR1+(2*i));
> > > +
> > > +		if (intr&1) { /* got an event */
> > 
> > I will let you think about how to optimize the indent depth
> > here ...
> 
> Ok, I will optimize indentation. This code (keyboard support) was
> written by Alistair Buxton and I reused it with minimal changes.

That doesn't justify it ;-)

> > > +#define tostring(s)		#s
> > > +#define stringify(s)		tostring(s)
> > 
> > We do have __stringify(), use that!
> 
> Ok, in April (when I wrote this part of code) __stringify was not
> in U-Boot (I checked it).

Yep, time changed.

Best regards,
Marek Vasut
Pali Rohár Oct. 16, 2012, 3:46 p.m. UTC | #5
On Tuesday 16 October 2012 16:55:20 Marek Vasut wrote:
> Dear Pali Rohár,
> 
> [...]
> 
> > Nothing. This code must be in assembler because stack is not
> > initialized. Also we must be sure that U-Boot will not
> > overwrite attached kernel (with can be in U-Boot
> > malloc/monitor area...)
> Don't we have something that can reserve a memory area?
> 

I'm using CONFIG_PRAM and KERNEL_ADDRESS is calculated from 
protected ram. But previous bootloader (NOLO) loading u-boot (+ 
attached kernel) at random address, so it can be in u-boot malloc 
area. That assembler code is called after reset and copy attached 
kernel to protected ram (so U-Boot will not touch it) and U-Boot 
to correct address.

> > > > +		}
> > > > +		++i;
> > > 
> > > i++;
> > 
> > Reason? ++i and i++ are same (for this situation).
> 
> On arm, yes, on intel, no in certain cases. Also, to keep the
> code consistent, go with postdecrement.
> 

What is different on intel (without assigning value of i)?

> > > > +	/* append omap atag only if env setup_omap_atag is set
> > > > to
> > 
> > 1
> > 
> > > > */ +	str = getenv("setup_omap_atag");
> > > > +	if (!str || strcmp(str, "1") != 0)
> > > 
> > > str[0] == '1' ? But still, you only want to check if it's
> > > defined, no?
> > 
> > Hm, I'm checking if setup_omap_atag is 1. But is it problem?
> 
> Then why not str[0] == '1' ?
> 

Ok.

> > > > +/*
> > > > + * Routine: twl4030_regulator_set_mode
> > > > + * Description: Set twl4030 regulator mode over i2c
> > > > powerbus.
> > > > + */
> > > > +static void twl4030_regulator_set_mode(u8 id, u8 mode)
> > > > +{
> > > > +	u16 msg = MSG_SINGULAR(DEV_GRP_P1, id, mode);
> > > > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg >> 8,
> > > > +			TWL4030_PM_MASTER_PB_WORD_MSB);
> > > > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg &
> > > > 0xff,
> > > > +			TWL4030_PM_MASTER_PB_WORD_LSB);
> > > 
> > > Uh, is this somehow special that you can't do longer
> > > transfer?
> > 
> > I do not know how, because registers are different (MSB and
> > LSB).
> Investigate ;-)
> 

I think it is not possible. Registers are in bad order. (So on 
some high endian system it could be possible)

Also in linux twl regulator driver is used two calls see:
https://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=drivers/regulator/twl-
regulator.c;hb=HEAD#l327

> > > > +
> > > > +static unsigned long int twl_wd_time; /* last time of
> > > > watchdog reset */ +static unsigned long int twl_i2c_lock;
> > > 
> > > Are you sure you want to use global vars for these? These
> > > won't work before reloc!
> > 
> > Why it does not work before reloc? U-Boot is on n900 always
> > started from RAM.
> 
> The BSS isn't cleared though.
> 

So how to fix it? I need to share these vars in more functions.

> > > > +
> > > > +static u8 keys[8];
> > > > +static u8 old_keys[8] = {0, 0, 0, 0, 0, 0, 0, 0};
> > > > +#define KEYBUF_SIZE 32
> > > > +static u8 keybuf[KEYBUF_SIZE];
> > > > +static u8 keybuf_head;
> > > > +static u8 keybuf_tail;
> > > 
> > > How much of this can be made const ?
> > 
> > Nothing. All is for keyboard and is changed by keyboard
> > functions (tstc, getc)
> > 
> > > This magic needs at least _some_ documentation.
> > > 
> > > > +	if (!(mods & 2) && (k == 18 || k == 31 || k == 33 || k
> > > > ==
> > > > 34)) { +		/* cursor keys, without fn */
> > > > +		keybuf[keybuf_tail++] = '\e';
> > 
> > there is "cursor keys without fn" (fn is "meta" key on n900).
> > So this condition check if some cursor key (without fn) was
> > pressed.
> Good, document it.
> 

Ok.
Marek Vasut Oct. 16, 2012, 3:57 p.m. UTC | #6
Dear Pali Rohár,

[...]

> > > Reason? ++i and i++ are same (for this situation).
> > 
> > On arm, yes, on intel, no in certain cases. Also, to keep the
> > code consistent, go with postdecrement.
> 
> What is different on intel (without assigning value of i)?

IIRC the prefetch behaves differently. Ccing Graeme, but this might be a 
question to the GCC guys.

> > > > > +	/* append omap atag only if env setup_omap_atag is set
> > > > > to
> > > 
> > > 1
> > > 
> > > > > */ +	str = getenv("setup_omap_atag");
> > > > > +	if (!str || strcmp(str, "1") != 0)
> > > > 
> > > > str[0] == '1' ? But still, you only want to check if it's
> > > > defined, no?
> > > 
> > > Hm, I'm checking if setup_omap_atag is 1. But is it problem?
> > 
> > Then why not str[0] == '1' ?
> 
> Ok.
> 
> > > > > +/*
> > > > > + * Routine: twl4030_regulator_set_mode
> > > > > + * Description: Set twl4030 regulator mode over i2c
> > > > > powerbus.
> > > > > + */
> > > > > +static void twl4030_regulator_set_mode(u8 id, u8 mode)
> > > > > +{
> > > > > +	u16 msg = MSG_SINGULAR(DEV_GRP_P1, id, mode);
> > > > > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg >> 8,
> > > > > +			TWL4030_PM_MASTER_PB_WORD_MSB);
> > > > > +	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg &
> > > > > 0xff,
> > > > > +			TWL4030_PM_MASTER_PB_WORD_LSB);
> > > > 
> > > > Uh, is this somehow special that you can't do longer
> > > > transfer?
> > > 
> > > I do not know how, because registers are different (MSB and
> > > LSB).
> > 
> > Investigate ;-)
> 
> I think it is not possible. Registers are in bad order. (So on
> some high endian system it could be possible)

High endian :-)

> Also in linux twl regulator driver is used two calls see:
> https://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=driv
> ers/regulator/twl- regulator.c;hb=HEAD#l327

ok

> > > > > +
> > > > > +static unsigned long int twl_wd_time; /* last time of
> > > > > watchdog reset */ +static unsigned long int twl_i2c_lock;
> > > > 
> > > > Are you sure you want to use global vars for these? These
> > > > won't work before reloc!
> > > 
> > > Why it does not work before reloc? U-Boot is on n900 always
> > > started from RAM.
> > 
> > The BSS isn't cleared though.
> 
> So how to fix it? I need to share these vars in more functions.

Make a struct and pass it around? Or if it's used only _after_ relocation, these 
will work.

> > > > > +
> > > > > +static u8 keys[8];
> > > > > +static u8 old_keys[8] = {0, 0, 0, 0, 0, 0, 0, 0};
> > > > > +#define KEYBUF_SIZE 32
> > > > > +static u8 keybuf[KEYBUF_SIZE];
> > > > > +static u8 keybuf_head;
> > > > > +static u8 keybuf_tail;
> > > > 
> > > > How much of this can be made const ?
> > > 
> > > Nothing. All is for keyboard and is changed by keyboard
> > > functions (tstc, getc)
> > > 
> > > > This magic needs at least _some_ documentation.
> > > > 
> > > > > +	if (!(mods & 2) && (k == 18 || k == 31 || k == 33 || k
> > > > > ==
> > > > > 34)) { +		/* cursor keys, without fn */
> > > > > +		keybuf[keybuf_tail++] = '\e';
> > > 
> > > there is "cursor keys without fn" (fn is "meta" key on n900).
> > > So this condition check if some cursor key (without fn) was
> > > pressed.
> > 
> > Good, document it.
> 
> Ok.
Pali Rohár Oct. 16, 2012, 4:15 p.m. UTC | #7
On Tuesday 16 October 2012 17:57:09 Marek Vasut wrote:
> 
> > > > > > +
> > > > > > +static unsigned long int twl_wd_time; /* last time
> > > > > > of
> > > > > > watchdog reset */ +static unsigned long int
> > > > > > twl_i2c_lock;
> > > > > 
> > > > > Are you sure you want to use global vars for these?
> > > > > These
> > > > > won't work before reloc!
> > > > 
> > > > Why it does not work before reloc? U-Boot is on n900
> > > > always
> > > > started from RAM.
> > > 
> > > The BSS isn't cleared though.
> > 
> > So how to fix it? I need to share these vars in more
> > functions.
> Make a struct and pass it around? Or if it's used only _after_
> relocation, these will work.
> 

It is used for keyboard input (tstc, getc) and watchdog reset. 
All functions are global for uboot, so parameters are fixed. 
Keyboard input is initialized in console_init_r.

I tested U-Boot on real N900 and in qemu N900 and both watchdog 
kicking & keyboard input worked without problem.
diff mbox

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 971235b..613d8cd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1009,6 +1009,10 @@  Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
 
 	armadillo-800eva	R8A7740 (RMOBILE SoC)
 
+Pali Rohár <pali.rohar@gmail.com>
+
+	nokia_rx51	ARM ARMV7 (OMAP3xx SoC)
+
 -------------------------------------------------------------------------
 
 Unknown / orphaned boards:
diff --git a/board/nokia/rx51/Makefile b/board/nokia/rx51/Makefile
new file mode 100644
index 0000000..86fb48c
--- /dev/null
+++ b/board/nokia/rx51/Makefile
@@ -0,0 +1,46 @@ 
+#
+# (C) Copyright 2000, 2001, 2002
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS-y	:= $(BOARD).o
+SOBJS-y := lowlevel_init.o
+
+COBJS	:= $(sort $(COBJS-y))
+SOBJS	:= $(sort $(SOBJS-y))
+SRCS	:= $(COBJS:.o=.c) $(SOBJS:.o=.S)
+OBJS	:= $(addprefix $(obj),$(COBJS)) $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/nokia/rx51/lowlevel_init.S b/board/nokia/rx51/lowlevel_init.S
new file mode 100644
index 0000000..055b103
--- /dev/null
+++ b/board/nokia/rx51/lowlevel_init.S
@@ -0,0 +1,209 @@ 
+/*
+ * (C) Copyright 2011-2012
+ * Pali Rohár <pali.rohar@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+relocaddr:		/* address of this relocaddr section after coping */
+	.word .		/* address of section (calculated at compile time) */
+
+startaddr:		/* address of u-boot after copying */
+	.word CONFIG_SYS_TEXT_BASE
+
+kernaddr:		/* address of kernel after copying */
+	.word KERNEL_ADDRESS
+
+kernsize:		/* maximal size of kernel image */
+	.word KERNEL_MAXSIZE
+
+kernoffs:		/* offset of kernel image in loaded u-boot */
+	.word KERNEL_OFFSET
+
+imagesize:		/* maximal size of image */
+	.word IMAGE_MAXSIZE
+
+ih_magic:		/* IH_MAGIC in big endian from include/image.h */
+	.word 0x56190527
+
+/*
+ * Routine: save_boot_params (called after reset from start.S)
+ * Description: Copy attached kernel to address KERNEL_ADDRESS
+ *              Copy u-boot to address CONFIG_SYS_TEXT_BASE
+ *              Return to copied u-boot address
+ */
+
+.global save_boot_params
+save_boot_params:
+
+
+/* Copy valid attached kernel to address KERNEL_ADDRESS */
+
+copy_kernel_start:
+	adr	r0, relocaddr	/* r0 - address of section relocaddr */
+	ldr	r1, relocaddr	/* r1 - address of relocaddr after relocation */
+	cmp	r0, r1
+
+	/* r4 - calculated offset */
+	subhi	r4, r0, r1
+	sublo	r4, r1, r0
+
+	/* r0 - start of kernel before */
+	ldr	r0, startaddr
+	addhi	r0, r0, r4
+	sublo	r0, r0, r4
+	ldr	r1, kernoffs
+	add	r0, r0, r1
+
+	/* r3 - start of kernel after */
+	ldr	r3, kernaddr
+
+	/* r2 - end of kernel after */
+	ldr	r1, kernsize
+	add	r2, r3, r1
+
+	/* r1 - end of kernel before */
+	add	r1, r0, r1
+
+	/* remove header in target kernel */
+	mov	r5, #0
+	str	r5, [r3]
+
+	/* check for valid kernel uImage */
+	ldr	r4, [r0]	/* r4 - 4 bytes header of kernel */
+	ldr	r5, ih_magic	/* r5 - IH_MAGIC */
+	cmp	r4, r5
+	bne	copy_kernel_end	/* skip if invalid image */
+
+copy_kernel_loop:
+	ldmdb	r1!, {r3 - r10}
+	stmdb	r2!, {r3 - r10}
+	cmp	r1, r0
+	bhi	copy_kernel_loop
+
+copy_kernel_end:
+	mov	r5, #0
+	str	r5, [r0]	/* remove 4 bytes header of kernel */
+
+
+/* Fix u-boot code */
+
+fix_start:
+	adr	r0, relocaddr	/* r0 - address of section relocaddr */
+	ldr	r1, relocaddr	/* r1 - address of relocaddr after relocation */
+	cmp	r0, r1
+
+	beq	copy_uboot_end	/* skip if u-boot is on correct address */
+
+	/* r5 - calculated offset */
+	subhi	r5, r0, r1
+	sublo	r5, r1, r0
+
+	/* r6 - maximal u-boot size */
+	ldr	r6, imagesize
+
+	/* fix return address */
+	subhi	lr, lr, r5
+	addlo	lr, lr, r5
+
+	/* r1 - start of u-boot after */
+	ldr	r1, startaddr
+
+	/* r0 - start of u-boot before */
+	addhi	r0, r1, r5
+	sublo	r0, r1, r5
+
+	/* check if we need to move uboot copy code before calling it */
+	cmp	r5, r6
+	bhi	copy_uboot_start /* now coping u-boot code directly is safe */
+
+
+copy_code_start:
+	/* r0 - start of u-boot before */
+	/* r1 - start of u-boot after */
+	/* r6 - maximal u-boot size */
+
+	/* r7 - maximal kernel size */
+	ldr	r7, kernsize
+
+	/* r4 - end of kernel before */
+	add	r4, r0, r6
+	add	r4, r4, r7
+
+	/* r5 - end of u-boot after */
+	ldr	r5, startaddr
+	add	r5, r5, r6
+
+	/* r2 - start of loop code after */
+	cmp	r4, r5		/* higher address (r4 or r5) */
+	movhs	r2, r4
+	movlo	r2, r5
+
+	/* r3 - end of loop code before */
+	adr	r3, end
+
+	/* r4 - end of loop code after */
+	adr	r4, copy_uboot_start
+	sub	r4, r3, r4
+	add	r4, r2, r4
+
+copy_code_loop:
+	ldmdb	r3!, {r7 - r10}
+	stmdb	r4!, {r7 - r10}
+	cmp	r4, r2
+	bhi	copy_code_loop
+
+copy_code_end:
+	mov	pc, r2
+
+
+/* Copy u-boot to address CONFIG_SYS_TEXT_BASE */
+
+copy_uboot_start:
+	/* r0 - start of u-boot before */
+	/* r1 - start of u-boot after */
+	/* r6 - maximal u-boot size */
+
+	/* r2 - end of u-boot after */
+	add	r2, r1, r6
+
+	/* condition for copying from left to right */
+	cmp	r0, r1
+	addlo	r1, r0, r6	/* r1 - end of u-boot before */
+	blo	copy_uboot_loop_right
+
+copy_uboot_loop_left:
+	ldmia	r0!, {r3 - r10}
+	stmia	r1!, {r3 - r10}
+	cmp	r1, r2
+	blo	copy_uboot_loop_left
+	b	copy_uboot_end
+
+copy_uboot_loop_right:
+	ldmdb	r1!, {r3 - r10}
+	stmdb	r2!, {r3 - r10}
+	cmp	r1, r0
+	bhi	copy_uboot_loop_right
+
+copy_uboot_end:
+	bx	lr
+
+end:
diff --git a/board/nokia/rx51/rx51.c b/board/nokia/rx51/rx51.c
new file mode 100644
index 0000000..79342eb
--- /dev/null
+++ b/board/nokia/rx51/rx51.c
@@ -0,0 +1,673 @@ 
+/*
+ * (C) Copyright 2012
+ * Ивайло Димитров <freemangordon@abv.bg>
+ *
+ * (C) Copyright 2011-2012
+ * Pali Rohár <pali.rohar@gmail.com>
+ *
+ * (C) Copyright 2010
+ * Alistair Buxton <a.j.buxton@gmail.com>
+ *
+ * Derived from Beagle Board and 3430 SDP code:
+ * (C) Copyright 2004-2008
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author :
+ *	Sunil Kumar <sunilsaini05@gmail.com>
+ *	Shashi Ranjan <shashiranjanmca05@gmail.com>
+ *
+ *	Richard Woodruff <r-woodruff2@ti.com>
+ *	Syed Mohammed Khasim <khasim@ti.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <twl4030.h>
+#include <i2c.h>
+#include <video_fb.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/bitops.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/mmc_host_def.h>
+
+#include "rx51.h"
+#include "tag_omap.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+GraphicDevice gdev;
+
+const omap3_sysinfo sysinfo = {
+	DDR_STACKED,
+	"Nokia RX-51",
+	"OneNAND"
+};
+
+/* This structure contains default omap tags needed for booting Maemo 5 */
+static struct tag_omap omap[] = {
+	OMAP_TAG_UART_CONFIG(0x04),
+	OMAP_TAG_SERIAL_CONSOLE_CONFIG(0x03, 0x01C200),
+	OMAP_TAG_LCD_CONFIG("acx565akm", "internal", 90, 0x18),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cam_focus", 0x44, 0x1, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cam_launch", 0x45, 0x1, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cam_shutter", 0x6e, 0x1, 0x0, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cmt_apeslpx", 0x46, 0x2, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cmt_bsi", 0x9d, 0x2, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cmt_en", 0x4a, 0x2, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cmt_rst", 0x4b, 0x6, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cmt_rst_rq", 0x49, 0x6, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("cmt_wddis", 0x0d, 0x2, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("headphone", 0xb1, 0x1, 0x1, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("kb_lock", 0x71, 0x1, 0x0, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("proximity", 0x59, 0x0, 0x0, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("sleep_ind", 0xa2, 0x2, 0x2, 0x0),
+	OMAP_TAG_GPIO_SWITCH_CONFIG("slide", GPIO_SLIDE, 0x0, 0x0, 0x0),
+	OMAP_TAG_WLAN_CX3110X_CONFIG(0x25, 0xff, 87, 42, -1),
+	OMAP_TAG_PARTITION_CONFIG(PART1_NAME, PART1_SIZE * PART1_MULL,
+			PART1_OFFS, PART1_MASK),
+	OMAP_TAG_PARTITION_CONFIG(PART2_NAME, PART2_SIZE * PART2_MULL,
+			PART2_OFFS, PART2_MASK),
+	OMAP_TAG_PARTITION_CONFIG(PART3_NAME, PART3_SIZE * PART3_MULL,
+			PART3_OFFS, PART3_MASK),
+	OMAP_TAG_PARTITION_CONFIG(PART4_NAME, PART4_SIZE * PART4_MULL,
+			PART4_OFFS, PART4_MASK),
+	OMAP_TAG_PARTITION_CONFIG(PART5_NAME, PART5_SIZE * PART5_MULL,
+			PART5_OFFS, PART5_MASK),
+	OMAP_TAG_PARTITION_CONFIG(PART6_NAME, PART6_SIZE * PART6_MULL,
+			PART6_OFFS, PART6_MASK),
+	OMAP_TAG_BOOT_REASON_CONFIG("pwr_key"),
+	OMAP_TAG_VERSION_STR_CONFIG("product", "RX-51"),
+	OMAP_TAG_VERSION_STR_CONFIG("hw-build", "2101"),
+	OMAP_TAG_VERSION_STR_CONFIG("nolo", "1.4.14"),
+	OMAP_TAG_VERSION_STR_CONFIG("boot-mode", "normal"),
+	{ }
+};
+
+static char *boot_reason_ptr;
+static char *hw_build_ptr;
+static char *nolo_version_ptr;
+static char *boot_mode_ptr;
+
+/*
+ * Routine: init_omap_tags
+ * Description: Initialize pointers to values in tag_omap
+ */
+static void init_omap_tags(void)
+{
+	char *component;
+	char *version;
+	int i = 0;
+	while (omap[i].hdr.tag) {
+		switch (omap[i].hdr.tag) {
+		case OMAP_TAG_BOOT_REASON:
+			boot_reason_ptr = omap[i].u.boot_reason.reason_str;
+			break;
+		case OMAP_TAG_VERSION_STR:
+			component = omap[i].u.version.component;
+			version = omap[i].u.version.version;
+			if (strcmp(component, "hw-build") == 0)
+				hw_build_ptr = version;
+			else if (strcmp(component, "nolo") == 0)
+				nolo_version_ptr = version;
+			else if (strcmp(component, "boot-mode") == 0)
+				boot_mode_ptr = version;
+			break;
+		}
+		++i;
+	}
+}
+
+static void reuse_omap_atags(struct tag_omap *t)
+{
+	char *component;
+	char *version;
+	while (t->hdr.tag) {
+		switch (t->hdr.tag) {
+		case OMAP_TAG_BOOT_REASON:
+			memset(boot_reason_ptr, 0, 12);
+			strcpy(boot_reason_ptr, t->u.boot_reason.reason_str);
+			break;
+		case OMAP_TAG_VERSION_STR:
+			component = t->u.version.component;
+			version = t->u.version.version;
+			if (strcmp(component, "hw-build") == 0) {
+				memset(hw_build_ptr, 0, 12);
+				strcpy(hw_build_ptr, version);
+			} else if (strcmp(component, "nolo") == 0) {
+				memset(nolo_version_ptr, 0, 12);
+				strcpy(nolo_version_ptr, version);
+			} else if (strcmp(component, "boot-mode") == 0) {
+				memset(boot_mode_ptr, 0, 12);
+				strcpy(boot_mode_ptr, version);
+			}
+			break;
+		}
+		t = tag_omap_next(t);
+	}
+}
+
+/*
+ * Routine: reuse_atags
+ * Description: Reuse atags from previous bootloader.
+ *              Reuse only only HW build, boot reason, boot mode and nolo
+ */
+static void reuse_atags(void)
+{
+	struct tag *t = (struct tag *)gd->bd->bi_boot_params;
+
+	/* First tag must be ATAG_CORE */
+	if (t->hdr.tag != ATAG_CORE)
+		return;
+
+	if (!boot_reason_ptr || !hw_build_ptr)
+		return;
+
+	/* Last tag must be ATAG_NONE */
+	while (t->hdr.tag != ATAG_NONE) {
+		switch (t->hdr.tag) {
+		case ATAG_REVISION:
+			memset(hw_build_ptr, 0, 12);
+			sprintf(hw_build_ptr, "%x", t->u.revision.rev);
+			break;
+		case ATAG_BOARD:
+			reuse_omap_atags((struct tag_omap *)&t->u);
+			break;
+		}
+		t = tag_next(t);
+	}
+}
+
+/*
+ * Routine: board_init
+ * Description: Early hardware init.
+ */
+int board_init(void)
+{
+	gpmc_init(); /* in SRAM or SDRAM, finish GPMC */
+	/* board id for Linux */
+	gd->bd->bi_arch_number = MACH_TYPE_NOKIA_RX51;
+	/* boot param addr */
+	gd->bd->bi_boot_params = OMAP34XX_SDRC_CS0 + 0x100;
+
+	return 0;
+}
+
+/*
+ * Routine: get_board_revision
+ * Description: Return board revision.
+ */
+u32 get_board_rev(void)
+{
+	return simple_strtol(hw_build_ptr, NULL, 16);
+}
+
+/*
+ * Routine: setup_board_tags
+ * Description: Append board specific boot tags.
+ */
+void setup_board_tags(struct tag **in_params)
+{
+	int setup_console_atag;
+	char *setup_boot_reason_atag;
+	char *setup_boot_mode_atag;
+	char *str;
+	int i;
+	int size;
+	int total_size;
+	struct tag *params;
+	struct tag_omap *t;
+
+	params = (struct tag *)gd->bd->bi_boot_params;
+
+	params->u.core.flags = 0x0;
+	params->u.core.pagesize = 0x1000;
+	params->u.core.rootdev = 0x0;
+
+	/* append omap atag only if env setup_omap_atag is set to 1 */
+	str = getenv("setup_omap_atag");
+	if (!str || strcmp(str, "1") != 0)
+		return;
+
+	str = getenv("setup_console_atag");
+	if (str && strcmp(str, "1") == 0)
+		setup_console_atag = 1;
+	else
+		setup_console_atag = 0;
+
+	setup_boot_reason_atag = getenv("setup_boot_reason_atag");
+	setup_boot_mode_atag = getenv("setup_boot_mode_atag");
+
+	params = *in_params;
+	t = (struct tag_omap *)&params->u;
+	total_size = sizeof(struct tag_header);
+
+	for (i = 0; omap[i].hdr.tag; ++i) {
+
+		/* skip serial console tag */
+		if (!setup_console_atag &&
+			omap[i].hdr.tag == OMAP_TAG_SERIAL_CONSOLE)
+			continue;
+
+		size = omap[i].hdr.size + sizeof(struct tag_omap_header);
+		memcpy(t, &omap[i], size);
+
+		/* set uart tag to 0 - disable serial console */
+		if (!setup_console_atag && omap[i].hdr.tag == OMAP_TAG_UART)
+			t->u.uart.enabled_uarts = 0;
+
+		/* change boot reason */
+		if (setup_boot_reason_atag &&
+			omap[i].hdr.tag == OMAP_TAG_BOOT_REASON) {
+			memset(t->u.boot_reason.reason_str, 0, 12);
+			strcpy(t->u.boot_reason.reason_str,
+				setup_boot_reason_atag);
+		}
+
+		/* change boot mode */
+		if (setup_boot_mode_atag &&
+			omap[i].hdr.tag == OMAP_TAG_VERSION_STR &&
+			strcmp(omap[i].u.version.component, "boot-mode") == 0) {
+			memset(t->u.version.version, 0, 12);
+			strcpy(t->u.version.version, setup_boot_mode_atag);
+		}
+
+		total_size += size;
+		t = tag_omap_next(t);
+
+	}
+
+	params->hdr.tag = ATAG_BOARD;
+	params->hdr.size = total_size >> 2;
+	params = tag_next(params);
+
+	*in_params = params;
+}
+
+/*
+ * Routine: video_hw_init
+ * Description: Set up the GraphicDevice depending on sys_boot.
+ */
+void *video_hw_init(void)
+{
+	/* fill in Graphic Device */
+	gdev.frameAdrs = 0x8f9c0000;
+	gdev.winSizeX = 800;
+	gdev.winSizeY = 480;
+	gdev.gdfBytesPP = 2;
+	gdev.gdfIndex = GDF_16BIT_565RGB;
+	memset((void *)gdev.frameAdrs, 0, 0xbb800);
+	return (void *) &gdev;
+}
+
+/*
+ * Routine: twl4030_regulator_set_mode
+ * Description: Set twl4030 regulator mode over i2c powerbus.
+ */
+static void twl4030_regulator_set_mode(u8 id, u8 mode)
+{
+	u16 msg = MSG_SINGULAR(DEV_GRP_P1, id, mode);
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg >> 8,
+			TWL4030_PM_MASTER_PB_WORD_MSB);
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, msg & 0xff,
+			TWL4030_PM_MASTER_PB_WORD_LSB);
+}
+
+static void omap3_emu_romcode_call(u32 service_id, u32 *parameters)
+{
+	u32 i, num_params = *parameters;
+	u32 *sram_scratch_space = (u32 *)OMAP3_PUBLIC_SRAM_SCRATCH_AREA;
+
+	/*
+	 * copy the parameters to an un-cached area to avoid coherency
+	 * issues
+	 */
+	for (i = 0; i < num_params; i++) {
+		__raw_writel(*parameters, sram_scratch_space);
+		parameters++;
+		sram_scratch_space++;
+	}
+
+	/* Now make the PPA call */
+	do_omap3_emu_romcode_call(service_id, OMAP3_PUBLIC_SRAM_SCRATCH_AREA);
+}
+
+/*
+ * Routine: omap3_update_aux_cr_secure_rx51
+ * Description: Modify the contents Auxiliary Control Register.
+ * Parameters:
+ *   set_bits - bits to set in ACR
+ *   clr_bits - bits to clear in ACR
+ */
+static void omap3_update_aux_cr_secure_rx51(u32 set_bits, u32 clear_bits)
+{
+	struct emu_hal_params_rx51 emu_romcode_params = { 0, };
+	u32 acr;
+
+	/* Read ACR */
+	asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr));
+	acr &= ~clear_bits;
+	acr |= set_bits;
+
+	emu_romcode_params.num_params = 2;
+	emu_romcode_params.param1 = acr;
+
+	omap3_emu_romcode_call(OMAP3_EMU_HAL_API_WRITE_ACR,
+				(u32 *)&emu_romcode_params);
+}
+
+/*
+ * Routine: misc_init_r
+ * Description: Configure board specific parts.
+ */
+int misc_init_r(void)
+{
+	char buf[12];
+	u8 state;
+
+	/* reset lp5523 led */
+	i2c_set_bus_num(1);
+	state = 0xff;
+	i2c_write(0x32, 0x3d, 1, &state, 1);
+	i2c_set_bus_num(0);
+
+	/* initialize twl4030 power managment */
+	twl4030_power_init();
+
+	/* set VSIM to 1.8V */
+	twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VSIM_DEDICATED,
+				TWL4030_PM_RECEIVER_VSIM_VSEL_18,
+				TWL4030_PM_RECEIVER_VSIM_DEV_GRP,
+				TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+	/* store I2C access state */
+	twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER, &state,
+			TWL4030_PM_MASTER_PB_CFG);
+
+	/* enable I2C access to powerbus (needed for twl4030 regulator) */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0x02,
+			TWL4030_PM_MASTER_PB_CFG);
+
+	/* set VAUX3, VSIM and VMMC1 state to active - enable eMMC memory */
+	twl4030_regulator_set_mode(RES_VAUX3, RES_STATE_ACTIVE);
+	twl4030_regulator_set_mode(RES_VSIM, RES_STATE_ACTIVE);
+	twl4030_regulator_set_mode(RES_VMMC1, RES_STATE_ACTIVE);
+
+	/* restore I2C access state */
+	twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, state,
+			TWL4030_PM_MASTER_PB_CFG);
+
+	/* set env variable attkernaddr for relocated kernel */
+	sprintf(buf, "%#x", KERNEL_ADDRESS);
+	setenv("attkernaddr", buf);
+
+	/* initialize omap tags */
+	init_omap_tags();
+
+	/* reuse atags from previous bootloader */
+	reuse_atags();
+
+	dieid_num_r();
+	print_cpuinfo();
+
+	/*
+	 * Cortex-A8(r1p0..r1p2) errata 430973 workaround
+	 * Set IBE bit in Auxiliary Control Register
+	 */
+	omap3_update_aux_cr_secure_rx51(1 << 6, 0);
+
+	return 0;
+}
+
+/*
+ * Routine: set_muxconf_regs
+ * Description: Setting up the configuration Mux registers specific to the
+ *		hardware. Many pins need to be moved from protect to primary
+ *		mode.
+ */
+void set_muxconf_regs(void)
+{
+	MUX_RX51();
+}
+
+static unsigned long int twl_wd_time; /* last time of watchdog reset */
+static unsigned long int twl_i2c_lock;
+
+/*
+ * Routine: hw_watchdog_reset
+ * Description: Reset timeout of twl4030 watchdog.
+ */
+void hw_watchdog_reset(void)
+{
+	u8 timeout = 0;
+
+	/* do not reset watchdog too often - max every 4s */
+	if (get_timer(twl_wd_time) < 4 * CONFIG_SYS_HZ)
+		return;
+
+	/* localy lock twl4030 i2c bus */
+	if (test_and_set_bit(0, &twl_i2c_lock))
+		return;
+
+	/* read actual watchdog timeout */
+	twl4030_i2c_read_u8(TWL4030_CHIP_PM_RECEIVER, &timeout,
+			TWL4030_PM_RECEIVER_WATCHDOG_CFG);
+
+	/* timeout 0 means watchdog is disabled */
+	/* reset watchdog timeout to 31s (maximum) */
+	if (timeout != 0)
+		twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 31,
+				TWL4030_PM_RECEIVER_WATCHDOG_CFG);
+
+	/* store last watchdog reset time */
+	twl_wd_time = get_timer(0);
+
+	/* localy unlock twl4030 i2c bus */
+	test_and_clear_bit(0, &twl_i2c_lock);
+}
+
+/*
+ * TWL4030 keypad handler for cfb_console
+ */
+
+static const char keymap[] = {
+	/* normal */
+	'q',  'o',  'p',  ',', '\b',    0,  'a',  's',
+	'w',  'd',  'f',  'g',  'h',  'j',  'k',  'l',
+	'e',  '.',    0,  '\r',   0,  'z',  'x',  'c',
+	'r',  'v',  'b',  'n',  'm',  ' ',  ' ',    0,
+	't',    0,    0,    0,    0,    0,    0,    0,
+	'y',    0,    0,    0,    0,    0,    0,    0,
+	'u',    0,    0,    0,    0,    0,    0,    0,
+	'i',    5,    6,    0,    0,    0,    0,    0,
+	/* fn */
+	'1',  '9',  '0',  '=', '\b',    0,  '*',  '+',
+	'2',  '#',  '-',  '_',  '(',  ')',  '&',  '!',
+	'3',  '?',  '^', '\r',    0,  156,  '$',  238,
+	'4',  '/', '\\',  '"', '\'',  '@',    0,  '<',
+	'5',  '|',  '>',    0,    0,    0,    0,    0,
+	'6',    0,    0,    0,    0,    0,    0,    0,
+	'7',    0,    0,    0,    0,    0,    0,    0,
+	'8',   16,   17,    0,    0,    0,    0,    0,
+};
+
+static u8 keys[8];
+static u8 old_keys[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+#define KEYBUF_SIZE 32
+static u8 keybuf[KEYBUF_SIZE];
+static u8 keybuf_head;
+static u8 keybuf_tail;
+
+/*
+ * Routine: rx51_kp_init
+ * Description: Initialize HW keyboard.
+ */
+int rx51_kp_init(void)
+{
+	int ret = 0;
+	u8 ctrl;
+	ret = twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD, &ctrl,
+		TWL4030_KEYPAD_KEYP_CTRL_REG);
+
+	if (!ret) {
+		/* turn on keyboard and use hardware scanning */
+		ctrl |= TWL4030_KEYPAD_CTRL_KBD_ON;
+		ctrl |= TWL4030_KEYPAD_CTRL_SOFT_NRST;
+		ctrl |= TWL4030_KEYPAD_CTRL_SOFTMODEN;
+		ret |= twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD, ctrl,
+					TWL4030_KEYPAD_KEYP_CTRL_REG);
+		/* enable key event status */
+		ret |= twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD, 0xfe,
+					TWL4030_KEYPAD_KEYP_IMR1);
+		/* enable interrupt generation on rising and falling */
+		/* this is a workaround for qemu twl4030 emulation */
+		ret |= twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD, 0x57,
+					TWL4030_KEYPAD_KEYP_EDR);
+		/* enable ISR clear on read */
+		ret |= twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD, 0x05,
+					TWL4030_KEYPAD_KEYP_SIH_CTRL);
+	}
+	return ret;
+}
+
+static void rx51_kp_fill(u8 k, u8 mods)
+{
+	if (!(mods & 2) && (k == 18 || k == 31 || k == 33 || k == 34)) {
+		/* cursor keys, without fn */
+		keybuf[keybuf_tail++] = '\e';
+		keybuf_tail %= KEYBUF_SIZE;
+		keybuf[keybuf_tail++] = '[';
+		keybuf_tail %= KEYBUF_SIZE;
+		if (k == 18) /* up */
+			keybuf[keybuf_tail++] = 'A';
+		else if (k == 31) /* left */
+			keybuf[keybuf_tail++] = 'D';
+		else if (k == 33) /* down */
+			keybuf[keybuf_tail++] = 'B';
+		else if (k == 34) /* right */
+			keybuf[keybuf_tail++] = 'C';
+		keybuf_tail %= KEYBUF_SIZE;
+		return;
+	}
+
+	if (mods & 2) { /* fn */
+		k = keymap[k+64];
+	} else {
+		k = keymap[k];
+		if (mods & 1) { /* ctrl */
+			if (k >= 'a' && k <= 'z')
+				k -= 'a' - 1;
+		}
+		if (mods & 4) { /* shift */
+			if (k >= 'a' && k <= 'z')
+				k += 'A' - 'a';
+			else if (k == '.')
+				k = ':';
+			else if (k == ',')
+				k = ';';
+		}
+	}
+	keybuf[keybuf_tail++] = k;
+	keybuf_tail %= KEYBUF_SIZE;
+}
+
+/*
+ * Routine: rx51_kp_tstc
+ * Description: Test if key was pressed (from buffer).
+ */
+int rx51_kp_tstc(void)
+{
+	u8 c, r, dk, i;
+	u8 intr;
+	u8 mods;
+
+	/* localy lock twl4030 i2c bus */
+	if (test_and_set_bit(0, &twl_i2c_lock))
+		return 0;
+
+	/* twl4030 remembers up to 2 events */
+	for (i = 0; i < 2; i++) {
+
+		/* check interrupt register for events */
+		twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD, &intr,
+				TWL4030_KEYPAD_KEYP_ISR1+(2*i));
+
+		if (intr&1) { /* got an event */
+
+			/* read the key state */
+			i2c_read(TWL4030_CHIP_KEYPAD,
+				TWL4030_KEYPAD_FULL_CODE_7_0, 1, keys, 8);
+
+			/* cut out modifier keys from the keystate */
+			mods = keys[4] >> 4;
+			keys[4] &= 0x0f;
+
+			for (c = 0; c < 8; c++) {
+
+				/* get newly pressed keys only */
+				dk = ((keys[c] ^ old_keys[c])&keys[c]);
+				old_keys[c] = keys[c];
+
+				/* fill the keybuf */
+				for (r = 0; r < 8; r++) {
+					if (dk&1)
+						rx51_kp_fill((c*8)+r, mods);
+					dk = dk >> 1;
+				}
+
+			}
+
+		}
+
+	}
+
+	/* localy unlock twl4030 i2c bus */
+	test_and_clear_bit(0, &twl_i2c_lock);
+
+	return (KEYBUF_SIZE + keybuf_tail - keybuf_head)%KEYBUF_SIZE;
+}
+
+/*
+ * Routine: rx51_kp_getc
+ * Description: Get last pressed key (from buffer).
+ */
+int rx51_kp_getc(void)
+{
+	keybuf_head %= KEYBUF_SIZE;
+	while (!rx51_kp_tstc()) {
+		udelay(1);
+		hw_watchdog_reset();
+	}
+	return keybuf[keybuf_head++];
+}
+
+/*
+ * Routine: board_mmc_init
+ * Description: Initialize mmc devices.
+ */
+int board_mmc_init(bd_t *bis)
+{
+	omap_mmc_init(0, 0, 0);
+	omap_mmc_init(1, 0, 0);
+	return 0;
+}
diff --git a/board/nokia/rx51/rx51.h b/board/nokia/rx51/rx51.h
new file mode 100644
index 0000000..e66e241
--- /dev/null
+++ b/board/nokia/rx51/rx51.h
@@ -0,0 +1,389 @@ 
+/*
+ * (C) Copyright 2012
+ * Ивайло Димитров <freemangordon@abv.bg>
+ *
+ * (C) Copyright 2011-2012
+ * Pali Rohár <pali.rohar@gmail.com>
+ *
+ * (C) Copyright 2008
+ * Dirk Behme <dirk.behme@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef _RX51_H_
+#define _RX51_H_
+
+/* Needed for ROM SMC call */
+struct emu_hal_params_rx51 {
+	u32 num_params;
+	u32 param1;
+	u32 param2;
+	u32 param3;
+	u32 param4;
+};
+
+int print_cpuinfo(void);
+
+/*
+ * IEN  - Input Enable
+ * IDIS - Input Disable
+ * PTD  - Pull type Down
+ * PTU  - Pull type Up
+ * DIS  - Pull type selection is inactive
+ * EN   - Pull type selection is active
+ * M0   - Mode 0
+ * The commented string gives the final mux configuration for that pin
+ */
+#define MUX_RX51() \
+/* SDRC */\
+	MUX_VAL(CP(SDRC_D0),		(IEN  | PTD | DIS | M0)) /*SDRC_D0*/\
+	MUX_VAL(CP(SDRC_D1),		(IEN  | PTD | DIS | M0)) /*SDRC_D1*/\
+	MUX_VAL(CP(SDRC_D2),		(IEN  | PTD | DIS | M0)) /*SDRC_D2*/\
+	MUX_VAL(CP(SDRC_D3),		(IEN  | PTD | DIS | M0)) /*SDRC_D3*/\
+	MUX_VAL(CP(SDRC_D4),		(IEN  | PTD | DIS | M0)) /*SDRC_D4*/\
+	MUX_VAL(CP(SDRC_D5),		(IEN  | PTD | DIS | M0)) /*SDRC_D5*/\
+	MUX_VAL(CP(SDRC_D6),		(IEN  | PTD | DIS | M0)) /*SDRC_D6*/\
+	MUX_VAL(CP(SDRC_D7),		(IEN  | PTD | DIS | M0)) /*SDRC_D7*/\
+	MUX_VAL(CP(SDRC_D8),		(IEN  | PTD | DIS | M0)) /*SDRC_D8*/\
+	MUX_VAL(CP(SDRC_D9),		(IEN  | PTD | DIS | M0)) /*SDRC_D9*/\
+	MUX_VAL(CP(SDRC_D10),		(IEN  | PTD | DIS | M0)) /*SDRC_D10*/\
+	MUX_VAL(CP(SDRC_D11),		(IEN  | PTD | DIS | M0)) /*SDRC_D11*/\
+	MUX_VAL(CP(SDRC_D12),		(IEN  | PTD | DIS | M0)) /*SDRC_D12*/\
+	MUX_VAL(CP(SDRC_D13),		(IEN  | PTD | DIS | M0)) /*SDRC_D13*/\
+	MUX_VAL(CP(SDRC_D14),		(IEN  | PTD | DIS | M0)) /*SDRC_D14*/\
+	MUX_VAL(CP(SDRC_D15),		(IEN  | PTD | DIS | M0)) /*SDRC_D15*/\
+	MUX_VAL(CP(SDRC_D16),		(IEN  | PTD | DIS | M0)) /*SDRC_D16*/\
+	MUX_VAL(CP(SDRC_D17),		(IEN  | PTD | DIS | M0)) /*SDRC_D17*/\
+	MUX_VAL(CP(SDRC_D18),		(IEN  | PTD | DIS | M0)) /*SDRC_D18*/\
+	MUX_VAL(CP(SDRC_D19),		(IEN  | PTD | DIS | M0)) /*SDRC_D19*/\
+	MUX_VAL(CP(SDRC_D20),		(IEN  | PTD | DIS | M0)) /*SDRC_D20*/\
+	MUX_VAL(CP(SDRC_D21),		(IEN  | PTD | DIS | M0)) /*SDRC_D21*/\
+	MUX_VAL(CP(SDRC_D22),		(IEN  | PTD | DIS | M0)) /*SDRC_D22*/\
+	MUX_VAL(CP(SDRC_D23),		(IEN  | PTD | DIS | M0)) /*SDRC_D23*/\
+	MUX_VAL(CP(SDRC_D24),		(IEN  | PTD | DIS | M0)) /*SDRC_D24*/\
+	MUX_VAL(CP(SDRC_D25),		(IEN  | PTD | DIS | M0)) /*SDRC_D25*/\
+	MUX_VAL(CP(SDRC_D26),		(IEN  | PTD | DIS | M0)) /*SDRC_D26*/\
+	MUX_VAL(CP(SDRC_D27),		(IEN  | PTD | DIS | M0)) /*SDRC_D27*/\
+	MUX_VAL(CP(SDRC_D28),		(IEN  | PTD | DIS | M0)) /*SDRC_D28*/\
+	MUX_VAL(CP(SDRC_D29),		(IEN  | PTD | DIS | M0)) /*SDRC_D29*/\
+	MUX_VAL(CP(SDRC_D30),		(IEN  | PTD | DIS | M0)) /*SDRC_D30*/\
+	MUX_VAL(CP(SDRC_D31),		(IEN  | PTD | DIS | M0)) /*SDRC_D31*/\
+	MUX_VAL(CP(SDRC_CLK),		(IEN  | PTD | DIS | M0)) /*SDRC_CLK*/\
+	MUX_VAL(CP(SDRC_DQS0),		(IEN  | PTD | DIS | M0)) /*SDRC_DQS0*/\
+	MUX_VAL(CP(SDRC_DQS1),		(IEN  | PTD | DIS | M0)) /*SDRC_DQS1*/\
+	MUX_VAL(CP(SDRC_DQS2),		(IEN  | PTD | DIS | M0)) /*SDRC_DQS2*/\
+	MUX_VAL(CP(SDRC_DQS3),		(IEN  | PTD | DIS | M0)) /*SDRC_DQS3*/\
+/* GPMC */\
+	MUX_VAL(CP(GPMC_A1),		(IDIS | PTD | DIS | M0)) /*GPMC_A1*/\
+	MUX_VAL(CP(GPMC_A2),		(IDIS | PTD | DIS | M0)) /*GPMC_A2*/\
+	MUX_VAL(CP(GPMC_A3),		(IDIS | PTD | DIS | M0)) /*GPMC_A3*/\
+	MUX_VAL(CP(GPMC_A4),		(IDIS | PTD | DIS | M0)) /*GPMC_A4*/\
+	MUX_VAL(CP(GPMC_A5),		(IDIS | PTD | DIS | M0)) /*GPMC_A5*/\
+	MUX_VAL(CP(GPMC_A6),		(IDIS | PTD | DIS | M0)) /*GPMC_A6*/\
+	MUX_VAL(CP(GPMC_A7),		(IDIS | PTD | DIS | M0)) /*GPMC_A7*/\
+	MUX_VAL(CP(GPMC_A8),		(IDIS | PTD | DIS | M0)) /*GPMC_A8*/\
+	MUX_VAL(CP(GPMC_A9),		(IDIS | PTD | DIS | M0)) /*GPMC_A9*/\
+	MUX_VAL(CP(GPMC_A10),		(IDIS | PTD | DIS | M0)) /*GPMC_A10*/\
+	MUX_VAL(CP(GPMC_D0),		(IEN  | PTD | DIS | M0)) /*GPMC_D0*/\
+	MUX_VAL(CP(GPMC_D1),		(IEN  | PTD | DIS | M0)) /*GPMC_D1*/\
+	MUX_VAL(CP(GPMC_D2),		(IEN  | PTD | DIS | M0)) /*GPMC_D2*/\
+	MUX_VAL(CP(GPMC_D3),		(IEN  | PTD | DIS | M0)) /*GPMC_D3*/\
+	MUX_VAL(CP(GPMC_D4),		(IEN  | PTD | DIS | M0)) /*GPMC_D4*/\
+	MUX_VAL(CP(GPMC_D5),		(IEN  | PTD | DIS | M0)) /*GPMC_D5*/\
+	MUX_VAL(CP(GPMC_D6),		(IEN  | PTD | DIS | M0)) /*GPMC_D6*/\
+	MUX_VAL(CP(GPMC_D7),		(IEN  | PTD | DIS | M0)) /*GPMC_D7*/\
+	MUX_VAL(CP(GPMC_D8),		(IEN  | PTD | DIS | M0)) /*GPMC_D8*/\
+	MUX_VAL(CP(GPMC_D9),		(IEN  | PTD | DIS | M0)) /*GPMC_D9*/\
+	MUX_VAL(CP(GPMC_D10),		(IEN  | PTD | DIS | M0)) /*GPMC_D10*/\
+	MUX_VAL(CP(GPMC_D11),		(IEN  | PTD | DIS | M0)) /*GPMC_D11*/\
+	MUX_VAL(CP(GPMC_D12),		(IEN  | PTD | DIS | M0)) /*GPMC_D12*/\
+	MUX_VAL(CP(GPMC_D13),		(IEN  | PTD | DIS | M0)) /*GPMC_D13*/\
+	MUX_VAL(CP(GPMC_D14),		(IEN  | PTD | DIS | M0)) /*GPMC_D14*/\
+	MUX_VAL(CP(GPMC_D15),		(IEN  | PTD | DIS | M0)) /*GPMC_D15*/\
+	MUX_VAL(CP(GPMC_NCS0),		(IDIS | PTU | EN  | M0)) /*GPMC_nCS0*/\
+	MUX_VAL(CP(GPMC_NCS1),		(IDIS | PTU | EN  | M0)) /*GPMC_nCS1*/\
+	MUX_VAL(CP(GPMC_NCS2),		(IDIS | PTU | EN  | M0)) /*GPMC_nCS2*/\
+	MUX_VAL(CP(GPMC_NCS3),		(IDIS | PTU | EN  | M0)) /*GPMC_nCS3*/\
+	MUX_VAL(CP(GPMC_NCS4),		(IDIS | PTU | EN  | M0)) /*GPMC_nCS4*/\
+	MUX_VAL(CP(GPMC_NCS5),		(IDIS | PTD | DIS | M0)) /*GPMC_nCS5*/\
+	MUX_VAL(CP(GPMC_NCS6),		(IEN  | PTD | DIS | M1)) /*nDMA_REQ2*/\
+	MUX_VAL(CP(GPMC_NCS7),		(IEN  | PTU | EN  | M1)) /*nDMA_REQ3*/\
+	MUX_VAL(CP(GPMC_NBE1),		(IEN  | PTD | DIS | M0)) /*GPMC_nBE1*/\
+	MUX_VAL(CP(GPMC_WAIT2),		(IEN  | PTU | EN  | M0)) /*GPMC_WAIT2*/\
+	MUX_VAL(CP(GPMC_WAIT3),		(IEN  | PTU | EN  | M0)) /*GPMC_WAIT3*/\
+	MUX_VAL(CP(GPMC_CLK),		(IDIS | PTD | DIS | M0)) /*GPMC_CLK*/\
+	MUX_VAL(CP(GPMC_NADV_ALE),	(IDIS | PTD | DIS | M0)) /*GPMC_nADV*/\
+	MUX_VAL(CP(GPMC_NOE),		(IDIS | PTD | DIS | M0)) /*GPMC_nOE*/\
+	MUX_VAL(CP(GPMC_NWE),		(IDIS | PTD | DIS | M0)) /*GPMC_nWE*/\
+	MUX_VAL(CP(GPMC_NBE0_CLE),	(IDIS | PTD | DIS | M0)) /*GPMC_nBE0*/\
+	MUX_VAL(CP(GPMC_NWP),		(IEN  | PTD | DIS | M0)) /*GPMC_nWP*/\
+	MUX_VAL(CP(GPMC_WAIT0),		(IEN  | PTU | EN  | M0)) /*GPMC_WAIT0*/\
+	MUX_VAL(CP(GPMC_WAIT1),		(IEN  | PTU | EN  | M0)) /*GPMC_WAIT1*/\
+/* DSS */\
+	MUX_VAL(CP(DSS_PCLK),		(IDIS | PTD | DIS | M0)) /*DSS_PCLK*/\
+	MUX_VAL(CP(DSS_HSYNC),		(IDIS | PTD | DIS | M0)) /*DSS_HSYNC*/\
+	MUX_VAL(CP(DSS_VSYNC),		(IDIS | PTD | DIS | M0)) /*DSS_VSYNC*/\
+	MUX_VAL(CP(DSS_ACBIAS),		(IDIS | PTD | DIS | M0)) /*DSS_ACBIAS*/\
+	MUX_VAL(CP(DSS_DATA0),		(IDIS | PTD | DIS | M0)) /*DSS_DATA0*/\
+	MUX_VAL(CP(DSS_DATA1),		(IDIS | PTD | DIS | M0)) /*DSS_DATA1*/\
+	MUX_VAL(CP(DSS_DATA2),		(IDIS | PTD | DIS | M0)) /*DSS_DATA2*/\
+	MUX_VAL(CP(DSS_DATA3),		(IDIS | PTD | DIS | M0)) /*DSS_DATA3*/\
+	MUX_VAL(CP(DSS_DATA4),		(IDIS | PTD | DIS | M0)) /*DSS_DATA4*/\
+	MUX_VAL(CP(DSS_DATA5),		(IDIS | PTD | DIS | M0)) /*DSS_DATA5*/\
+	MUX_VAL(CP(DSS_DATA6),		(IDIS | PTD | DIS | M0)) /*DSS_DATA6*/\
+	MUX_VAL(CP(DSS_DATA7),		(IDIS | PTD | DIS | M0)) /*DSS_DATA7*/\
+	MUX_VAL(CP(DSS_DATA8),		(IDIS | PTD | DIS | M0)) /*DSS_DATA8*/\
+	MUX_VAL(CP(DSS_DATA9),		(IDIS | PTD | DIS | M0)) /*DSS_DATA9*/\
+	MUX_VAL(CP(DSS_DATA10),		(IDIS | PTD | DIS | M0)) /*DSS_DATA10*/\
+	MUX_VAL(CP(DSS_DATA11),		(IDIS | PTD | DIS | M0)) /*DSS_DATA11*/\
+	MUX_VAL(CP(DSS_DATA12),		(IDIS | PTD | DIS | M0)) /*DSS_DATA12*/\
+	MUX_VAL(CP(DSS_DATA13),		(IDIS | PTD | DIS | M0)) /*DSS_DATA13*/\
+	MUX_VAL(CP(DSS_DATA14),		(IDIS | PTD | DIS | M0)) /*DSS_DATA14*/\
+	MUX_VAL(CP(DSS_DATA15),		(IDIS | PTD | DIS | M0)) /*DSS_DATA15*/\
+	MUX_VAL(CP(DSS_DATA16),		(IDIS | PTD | DIS | M0)) /*DSS_DATA16*/\
+	MUX_VAL(CP(DSS_DATA17),		(IDIS | PTD | DIS | M0)) /*DSS_DATA17*/\
+	MUX_VAL(CP(DSS_DATA18),		(IDIS | PTD | DIS | M0)) /*DSS_DATA18*/\
+	MUX_VAL(CP(DSS_DATA19),		(IDIS | PTD | DIS | M0)) /*DSS_DATA19*/\
+	MUX_VAL(CP(DSS_DATA20),		(IDIS | PTD | DIS | M0)) /*DSS_DATA20*/\
+	MUX_VAL(CP(DSS_DATA21),		(IDIS | PTD | DIS | M0)) /*DSS_DATA21*/\
+	MUX_VAL(CP(DSS_DATA22),		(IDIS | PTD | DIS | M0)) /*DSS_DATA22*/\
+	MUX_VAL(CP(DSS_DATA23),		(IDIS | PTD | DIS | M0)) /*DSS_DATA23*/\
+/* CAMERA */\
+	MUX_VAL(CP(CAM_HS),		(IEN  | PTU | EN  | M0)) /*CAM_HS*/\
+	MUX_VAL(CP(CAM_VS),		(IEN  | PTU | EN  | M0)) /*CAM_VS*/\
+	MUX_VAL(CP(CAM_XCLKA),		(IDIS | PTD | DIS | M0)) /*CAM_XCLKA*/\
+	MUX_VAL(CP(CAM_PCLK),		(IEN  | PTU | EN  | M0)) /*CAM_PCLK*/\
+	MUX_VAL(CP(CAM_FLD),		(IDIS | PTD | DIS | M4)) /*GPIO_98*/\
+	MUX_VAL(CP(CAM_D0),		(IEN  | PTD | DIS | M0)) /*CAM_D0*/\
+	MUX_VAL(CP(CAM_D1),		(IEN  | PTD | DIS | M0)) /*CAM_D1*/\
+	MUX_VAL(CP(CAM_D2),		(IEN  | PTD | DIS | M0)) /*CAM_D2*/\
+	MUX_VAL(CP(CAM_D3),		(IEN  | PTD | DIS | M0)) /*CAM_D3*/\
+	MUX_VAL(CP(CAM_D4),		(IEN  | PTD | DIS | M0)) /*CAM_D4*/\
+	MUX_VAL(CP(CAM_D5),		(IEN  | PTD | DIS | M0)) /*CAM_D5*/\
+	MUX_VAL(CP(CAM_D6),		(IEN  | PTD | DIS | M0)) /*CAM_D6*/\
+	MUX_VAL(CP(CAM_D7),		(IEN  | PTD | DIS | M0)) /*CAM_D7*/\
+	MUX_VAL(CP(CAM_D8),		(IEN  | PTD | DIS | M0)) /*CAM_D8*/\
+	MUX_VAL(CP(CAM_D9),		(IEN  | PTD | DIS | M0)) /*CAM_D9*/\
+	MUX_VAL(CP(CAM_D10),		(IEN  | PTD | DIS | M0)) /*CAM_D10*/\
+	MUX_VAL(CP(CAM_D11),		(IEN  | PTD | DIS | M0)) /*CAM_D11*/\
+	MUX_VAL(CP(CAM_XCLKB),		(IDIS | PTD | DIS | M0)) /*CAM_XCLKB*/\
+	MUX_VAL(CP(CAM_WEN),		(IEN  | PTD | DIS | M4)) /*GPIO_167*/\
+	MUX_VAL(CP(CAM_STROBE),		(IDIS | PTD | DIS | M0)) /*CAM_STROBE*/\
+	MUX_VAL(CP(CSI2_DX0),		(IEN  | PTD | DIS | M0)) /*CSI2_DX0*/\
+	MUX_VAL(CP(CSI2_DY0),		(IEN  | PTD | DIS | M0)) /*CSI2_DY0*/\
+	MUX_VAL(CP(CSI2_DX1),		(IEN  | PTD | DIS | M0)) /*CSI2_DX1*/\
+	MUX_VAL(CP(CSI2_DY1),		(IEN  | PTD | DIS | M0)) /*CSI2_DY1*/\
+/* Audio Interface */\
+	MUX_VAL(CP(MCBSP2_FSX),		(IEN  | PTD | DIS | M0)) /*McBSP2_FSX*/\
+	MUX_VAL(CP(MCBSP2_CLKX),	(IEN  | PTD | DIS | M0)) /*McBSP2_CLK*/\
+	MUX_VAL(CP(MCBSP2_DR),		(IEN  | PTD | DIS | M0)) /*McBSP2_DR*/\
+	MUX_VAL(CP(MCBSP2_DX),		(IDIS | PTD | DIS | M0)) /*McBSP2_DX*/\
+/* Expansion card */\
+	MUX_VAL(CP(MMC1_CLK),		(IDIS | PTU | EN  | M0)) /*MMC1_CLK*/\
+	MUX_VAL(CP(MMC1_CMD),		(IEN  | PTU | EN  | M0)) /*MMC1_CMD*/\
+	MUX_VAL(CP(MMC1_DAT0),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT0*/\
+	MUX_VAL(CP(MMC1_DAT1),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT1*/\
+	MUX_VAL(CP(MMC1_DAT2),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT2*/\
+	MUX_VAL(CP(MMC1_DAT3),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT3*/\
+	MUX_VAL(CP(MMC1_DAT4),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT4*/\
+	MUX_VAL(CP(MMC1_DAT5),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT5*/\
+	MUX_VAL(CP(MMC1_DAT6),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT6*/\
+	MUX_VAL(CP(MMC1_DAT7),		(IEN  | PTU | EN  | M0)) /*MMC1_DAT7*/\
+/* Wireless LAN */\
+	MUX_VAL(CP(MMC2_CLK),		(IEN  | PTU | EN  | M4)) /*GPIO_130*/\
+	MUX_VAL(CP(MMC2_CMD),		(IEN  | PTU | EN  | M4)) /*GPIO_131*/\
+	MUX_VAL(CP(MMC2_DAT0),		(IEN  | PTU | EN  | M4)) /*GPIO_132*/\
+	MUX_VAL(CP(MMC2_DAT1),		(IEN  | PTU | EN  | M4)) /*GPIO_133*/\
+	MUX_VAL(CP(MMC2_DAT2),		(IEN  | PTU | EN  | M4)) /*GPIO_134*/\
+	MUX_VAL(CP(MMC2_DAT3),		(IEN  | PTU | EN  | M4)) /*GPIO_135*/\
+	MUX_VAL(CP(MMC2_DAT4),		(IEN  | PTU | EN  | M4)) /*GPIO_136*/\
+	MUX_VAL(CP(MMC2_DAT5),		(IEN  | PTU | EN  | M4)) /*GPIO_137*/\
+	MUX_VAL(CP(MMC2_DAT6),		(IEN  | PTU | EN  | M4)) /*GPIO_138*/\
+	MUX_VAL(CP(MMC2_DAT7),		(IEN  | PTU | EN  | M4)) /*GPIO_139*/\
+/* Bluetooth */\
+	MUX_VAL(CP(MCBSP3_DX),		(IEN  | PTD | DIS | M1)) /*UART2_CTS*/\
+	MUX_VAL(CP(MCBSP3_DR),		(IDIS | PTD | DIS | M1)) /*UART2_RTS*/\
+	MUX_VAL(CP(MCBSP3_CLKX),	(IDIS | PTD | DIS | M1)) /*UART2_TX*/\
+	MUX_VAL(CP(MCBSP3_FSX),		(IEN  | PTD | DIS | M1)) /*UART2_RX*/\
+	MUX_VAL(CP(UART2_CTS),		(IEN  | PTD | DIS | M4)) /*GPIO_144*/\
+	MUX_VAL(CP(UART2_RTS),		(IEN  | PTD | DIS | M4)) /*GPIO_145*/\
+	MUX_VAL(CP(UART2_TX),		(IEN  | PTD | DIS | M4)) /*GPIO_146*/\
+	MUX_VAL(CP(UART2_RX),		(IEN  | PTD | DIS | M4)) /*GPIO_147*/\
+/* Modem Interface */\
+	MUX_VAL(CP(UART1_TX),		(IDIS | PTD | DIS | M0)) /*UART1_TX*/\
+	MUX_VAL(CP(UART1_RTS),		(IDIS | PTD | DIS | M4)) /*GPIO_149*/\
+	MUX_VAL(CP(UART1_CTS),		(IDIS | PTD | DIS | M4)) /*GPIO_150*/\
+	MUX_VAL(CP(UART1_RX),		(IEN  | PTD | DIS | M0)) /*UART1_RX*/\
+	MUX_VAL(CP(MCBSP4_CLKX),	(IEN  | PTD | DIS | M1)) /*SSI1_DAT*/\
+	MUX_VAL(CP(MCBSP4_DR),		(IEN  | PTD | DIS | M1)) /*SSI1_FLAG*/\
+	MUX_VAL(CP(MCBSP4_DX),		(IEN  | PTD | DIS | M1)) /*SSI1_RDY*/\
+	MUX_VAL(CP(MCBSP4_FSX),		(IEN  | PTD | DIS | M1)) /*SSI1_WAKE*/\
+	MUX_VAL(CP(MCBSP1_CLKR),	(IDIS | PTD | DIS | M4)) /*GPIO_156*/\
+	MUX_VAL(CP(MCBSP1_FSR),		(IDIS | PTU | EN  | M4)) /*GPIO_157*/\
+	MUX_VAL(CP(MCBSP1_DX),		(IDIS | PTD | DIS | M4)) /*GPIO_158*/\
+	MUX_VAL(CP(MCBSP1_DR),		(IDIS | PTD | DIS | M4)) /*GPIO_159*/\
+	MUX_VAL(CP(MCBSP_CLKS),		(IEN  | PTU | DIS | M0)) /*McBSP_CLKS*/\
+	MUX_VAL(CP(MCBSP1_FSX),		(IDIS | PTD | DIS | M4)) /*GPIO_161*/\
+	MUX_VAL(CP(MCBSP1_CLKX),	(IDIS | PTD | DIS | M4)) /*GPIO_162*/\
+/* Serial Interface */\
+	MUX_VAL(CP(UART3_CTS_RCTX),	(IEN  | PTD | EN  | M0)) /*UART3_CTS*/\
+	MUX_VAL(CP(UART3_RTS_SD),	(IDIS | PTD | DIS | M0)) /*UART3_RTS*/\
+	MUX_VAL(CP(UART3_RX_IRRX),	(IEN  | PTD | DIS | M0)) /*UART3_RX*/\
+	MUX_VAL(CP(UART3_TX_IRTX),	(IDIS | PTD | DIS | M0)) /*UART3_TX*/\
+	MUX_VAL(CP(HSUSB0_CLK),		(IEN  | PTD | DIS | M0)) /*HSUSB0_CLK*/\
+	MUX_VAL(CP(HSUSB0_STP),		(IDIS | PTU | EN  | M0)) /*HSUSB0_STP*/\
+	MUX_VAL(CP(HSUSB0_DIR),		(IEN  | PTD | DIS | M0)) /*HSUSB0_DIR*/\
+	MUX_VAL(CP(HSUSB0_NXT),		(IEN  | PTD | DIS | M0)) /*HSUSB0_NXT*/\
+	MUX_VAL(CP(HSUSB0_DATA0),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA0*/\
+	MUX_VAL(CP(HSUSB0_DATA1),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA1*/\
+	MUX_VAL(CP(HSUSB0_DATA2),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA2*/\
+	MUX_VAL(CP(HSUSB0_DATA3),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA3*/\
+	MUX_VAL(CP(HSUSB0_DATA4),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA4*/\
+	MUX_VAL(CP(HSUSB0_DATA5),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA5*/\
+	MUX_VAL(CP(HSUSB0_DATA6),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA6*/\
+	MUX_VAL(CP(HSUSB0_DATA7),	(IEN  | PTD | DIS | M0)) /*HSUSB0_DA7*/\
+	MUX_VAL(CP(I2C1_SCL),		(IEN  | PTU | EN  | M0)) /*I2C1_SCL*/\
+	MUX_VAL(CP(I2C1_SDA),		(IEN  | PTU | EN  | M0)) /*I2C1_SDA*/\
+	MUX_VAL(CP(I2C2_SCL),		(IEN  | PTU | EN  | M4)) /*GPIO_168*/\
+	MUX_VAL(CP(I2C2_SDA),		(IEN  | PTU | EN  | M4)) /*GPIO_183*/\
+	MUX_VAL(CP(I2C3_SCL),		(IEN  | PTU | EN  | M0)) /*I2C3_SCL*/\
+	MUX_VAL(CP(I2C3_SDA),		(IEN  | PTU | EN  | M0)) /*I2C3_SDA*/\
+	MUX_VAL(CP(I2C4_SCL),		(IEN  | PTU | EN  | M0)) /*I2C4_SCL*/\
+	MUX_VAL(CP(I2C4_SDA),		(IEN  | PTU | EN  | M0)) /*I2C4_SDA*/\
+	MUX_VAL(CP(HDQ_SIO),		(IDIS | PTU | EN  | M4)) /*GPIO_170*/\
+	MUX_VAL(CP(MCSPI1_CLK),		(IEN  | PTU | EN  | M4)) /*GPIO_171*/\
+	MUX_VAL(CP(MCSPI1_SIMO),	(IEN  | PTU | EN  | M4)) /*GPIO_172*/\
+	MUX_VAL(CP(MCSPI1_SOMI),	(IEN  | PTD | DIS | M0)) /*McSPI1_SOM*/\
+	MUX_VAL(CP(MCSPI1_CS0),		(IEN  | PTD | EN  | M0)) /*McSPI1_CS0*/\
+	MUX_VAL(CP(MCSPI1_CS1),		(IDIS | PTD | EN  | M0)) /*McSPI1_CS1*/\
+	MUX_VAL(CP(MCSPI1_CS2),		(IDIS | PTD | DIS | M4)) /*GPIO_176*/\
+/* USB EHCI (port 2) */\
+	MUX_VAL(CP(MCSPI1_CS3),		(IEN  | PTU | DIS | M3)) /*HSUSB2_DA2*/\
+	MUX_VAL(CP(MCSPI2_CLK),		(IEN  | PTU | DIS | M3)) /*HSUSB2_DA7*/\
+	MUX_VAL(CP(MCSPI2_SIMO),	(IEN  | PTU | DIS | M3)) /*HSUSB2_DA4*/\
+	MUX_VAL(CP(MCSPI2_SOMI),	(IEN  | PTU | DIS | M3)) /*HSUSB2_DA5*/\
+	MUX_VAL(CP(MCSPI2_CS0),		(IEN  | PTU | DIS | M3)) /*HSUSB2_DA6*/\
+	MUX_VAL(CP(MCSPI2_CS1),		(IEN  | PTU | DIS | M3)) /*HSUSB2_DA3*/\
+	MUX_VAL(CP(ETK_D10_ES2),	(IDIS | PTU | DIS | M3)) /*HSUSB2_CLK*/\
+	MUX_VAL(CP(ETK_D11_ES2),	(IDIS | PTU | DIS | M3)) /*HSUSB2_STP*/\
+	MUX_VAL(CP(ETK_D12_ES2),	(IEN  | PTU | DIS | M3)) /*HSUSB2_DIR*/\
+	MUX_VAL(CP(ETK_D13_ES2),	(IEN  | PTU | DIS | M3)) /*HSUSB2_NXT*/\
+	MUX_VAL(CP(ETK_D14_ES2),	(IEN  | PTU | DIS | M3)) /*HSUSB2_DA0*/\
+	MUX_VAL(CP(ETK_D15_ES2),	(IEN  | PTU | DIS | M3)) /*HSUSB2_DA1*/\
+/* Control and debug */\
+	MUX_VAL(CP(SYS_32K),		(IEN  | PTD | DIS | M0)) /*SYS_32K*/\
+	MUX_VAL(CP(SYS_CLKREQ),		(IEN  | PTD | DIS | M0)) /*SYS_CLKREQ*/\
+	MUX_VAL(CP(SYS_NIRQ),		(IEN  | PTU | EN  | M0)) /*SYS_nIRQ*/\
+	MUX_VAL(CP(SYS_BOOT0),		(IEN  | PTD | DIS | M4)) /*GPIO_2*/\
+	MUX_VAL(CP(SYS_BOOT1),		(IEN  | PTD | DIS | M4)) /*GPIO_3*/\
+	MUX_VAL(CP(SYS_BOOT2),		(IEN  | PTD | DIS | M4)) /*MMC1_WP*/\
+	MUX_VAL(CP(SYS_BOOT3),		(IEN  | PTD | DIS | M4)) /*GPIO_5*/\
+	MUX_VAL(CP(SYS_BOOT4),		(IEN  | PTD | DIS | M4)) /*GPIO_6*/\
+	MUX_VAL(CP(SYS_BOOT5),		(IEN  | PTD | DIS | M4)) /*GPIO_7*/\
+	MUX_VAL(CP(SYS_BOOT6),		(IDIS | PTD | DIS | M4)) /*GPIO_8*/\
+	MUX_VAL(CP(SYS_OFF_MODE),	(IEN  | PTD | DIS | M0)) /*SYS_OFF_MD*/\
+	MUX_VAL(CP(SYS_CLKOUT1),	(IEN  | PTD | DIS | M0)) /*SYS_CLKOUT*/\
+	MUX_VAL(CP(SYS_CLKOUT2),	(IEN  | PTU | EN  | M4)) /*GPIO_186*/\
+	MUX_VAL(CP(ETK_CLK_ES2),	(IDIS | PTU | EN  | M3)) /*HSUSB1_STP*/\
+	MUX_VAL(CP(ETK_CTL_ES2),	(IDIS | PTU | DIS | M3)) /*HSUSB1_CLK*/\
+	MUX_VAL(CP(ETK_D0_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA0*/\
+	MUX_VAL(CP(ETK_D1_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA1*/\
+	MUX_VAL(CP(ETK_D2_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA2*/\
+	MUX_VAL(CP(ETK_D3_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA7*/\
+	MUX_VAL(CP(ETK_D4_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA4*/\
+	MUX_VAL(CP(ETK_D5_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA5*/\
+	MUX_VAL(CP(ETK_D6_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA6*/\
+	MUX_VAL(CP(ETK_D7_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DA3*/\
+	MUX_VAL(CP(ETK_D8_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_DIR*/\
+	MUX_VAL(CP(ETK_D9_ES2),		(IEN  | PTU | DIS | M3)) /*HSUSB1_NXT*/\
+	MUX_VAL(CP(D2D_MCAD1),		(IEN  | PTD | EN  | M0)) /*d2d_mcad1*/\
+	MUX_VAL(CP(D2D_MCAD2),		(IEN  | PTD | EN  | M0)) /*d2d_mcad2*/\
+	MUX_VAL(CP(D2D_MCAD3),		(IEN  | PTD | EN  | M0)) /*d2d_mcad3*/\
+	MUX_VAL(CP(D2D_MCAD4),		(IEN  | PTD | EN  | M0)) /*d2d_mcad4*/\
+	MUX_VAL(CP(D2D_MCAD5),		(IEN  | PTD | EN  | M0)) /*d2d_mcad5*/\
+	MUX_VAL(CP(D2D_MCAD6),		(IEN  | PTD | EN  | M0)) /*d2d_mcad6*/\
+	MUX_VAL(CP(D2D_MCAD7),		(IEN  | PTD | EN  | M0)) /*d2d_mcad7*/\
+	MUX_VAL(CP(D2D_MCAD8),		(IEN  | PTD | EN  | M0)) /*d2d_mcad8*/\
+	MUX_VAL(CP(D2D_MCAD9),		(IEN  | PTD | EN  | M0)) /*d2d_mcad9*/\
+	MUX_VAL(CP(D2D_MCAD10),		(IEN  | PTD | EN  | M0)) /*d2d_mcad10*/\
+	MUX_VAL(CP(D2D_MCAD11),		(IEN  | PTD | EN  | M0)) /*d2d_mcad11*/\
+	MUX_VAL(CP(D2D_MCAD12),		(IEN  | PTD | EN  | M0)) /*d2d_mcad12*/\
+	MUX_VAL(CP(D2D_MCAD13),		(IEN  | PTD | EN  | M0)) /*d2d_mcad13*/\
+	MUX_VAL(CP(D2D_MCAD14),		(IEN  | PTD | EN  | M0)) /*d2d_mcad14*/\
+	MUX_VAL(CP(D2D_MCAD15),		(IEN  | PTD | EN  | M0)) /*d2d_mcad15*/\
+	MUX_VAL(CP(D2D_MCAD16),		(IEN  | PTD | EN  | M0)) /*d2d_mcad16*/\
+	MUX_VAL(CP(D2D_MCAD17),		(IEN  | PTD | EN  | M0)) /*d2d_mcad17*/\
+	MUX_VAL(CP(D2D_MCAD18),		(IEN  | PTD | EN  | M0)) /*d2d_mcad18*/\
+	MUX_VAL(CP(D2D_MCAD19),		(IEN  | PTD | EN  | M0)) /*d2d_mcad19*/\
+	MUX_VAL(CP(D2D_MCAD20),		(IEN  | PTD | EN  | M0)) /*d2d_mcad20*/\
+	MUX_VAL(CP(D2D_MCAD21),		(IEN  | PTD | EN  | M0)) /*d2d_mcad21*/\
+	MUX_VAL(CP(D2D_MCAD22),		(IEN  | PTD | EN  | M0)) /*d2d_mcad22*/\
+	MUX_VAL(CP(D2D_MCAD23),		(IEN  | PTD | EN  | M0)) /*d2d_mcad23*/\
+	MUX_VAL(CP(D2D_MCAD24),		(IEN  | PTD | EN  | M0)) /*d2d_mcad24*/\
+	MUX_VAL(CP(D2D_MCAD25),		(IEN  | PTD | EN  | M0)) /*d2d_mcad25*/\
+	MUX_VAL(CP(D2D_MCAD26),		(IEN  | PTD | EN  | M0)) /*d2d_mcad26*/\
+	MUX_VAL(CP(D2D_MCAD27),		(IEN  | PTD | EN  | M0)) /*d2d_mcad27*/\
+	MUX_VAL(CP(D2D_MCAD28),		(IEN  | PTD | EN  | M0)) /*d2d_mcad28*/\
+	MUX_VAL(CP(D2D_MCAD29),		(IEN  | PTD | EN  | M0)) /*d2d_mcad29*/\
+	MUX_VAL(CP(D2D_MCAD30),		(IEN  | PTD | EN  | M0)) /*d2d_mcad30*/\
+	MUX_VAL(CP(D2D_MCAD31),		(IEN  | PTD | EN  | M0)) /*d2d_mcad31*/\
+	MUX_VAL(CP(D2D_MCAD32),		(IEN  | PTD | EN  | M0)) /*d2d_mcad32*/\
+	MUX_VAL(CP(D2D_MCAD33),		(IEN  | PTD | EN  | M0)) /*d2d_mcad33*/\
+	MUX_VAL(CP(D2D_MCAD34),		(IEN  | PTD | EN  | M0)) /*d2d_mcad34*/\
+	MUX_VAL(CP(D2D_MCAD35),		(IEN  | PTD | EN  | M0)) /*d2d_mcad35*/\
+	MUX_VAL(CP(D2D_MCAD36),		(IEN  | PTD | EN  | M0)) /*d2d_mcad36*/\
+	MUX_VAL(CP(D2D_CLK26MI),	(IEN  | PTD | DIS | M0)) /*d2d_clk26m*/\
+	MUX_VAL(CP(D2D_NRESPWRON),	(IEN  | PTD | EN  | M0)) /*d2d_nrespw*/\
+	MUX_VAL(CP(D2D_NRESWARM),	(IEN  | PTU | EN  | M0)) /*d2d_nreswa*/\
+	MUX_VAL(CP(D2D_ARM9NIRQ),	(IEN  | PTD | DIS | M0)) /*d2d_arm9ni*/\
+	MUX_VAL(CP(D2D_UMA2P6FIQ),	(IEN  | PTD | DIS | M0)) /*d2d_uma2p6*/\
+	MUX_VAL(CP(D2D_SPINT),		(IEN  | PTD | EN  | M0)) /*d2d_spint*/\
+	MUX_VAL(CP(D2D_FRINT),		(IEN  | PTD | EN  | M0)) /*d2d_frint*/\
+	MUX_VAL(CP(D2D_DMAREQ0),	(IEN  | PTD | DIS | M0)) /*d2d_dmare0*/\
+	MUX_VAL(CP(D2D_DMAREQ1),	(IEN  | PTD | DIS | M0)) /*d2d_dmare1*/\
+	MUX_VAL(CP(D2D_DMAREQ2),	(IEN  | PTD | DIS | M0)) /*d2d_dmare2*/\
+	MUX_VAL(CP(D2D_DMAREQ3),	(IEN  | PTD | DIS | M0)) /*d2d_dmare3*/\
+	MUX_VAL(CP(D2D_N3GTRST),	(IEN  | PTD | DIS | M0)) /*d2d_n3gtrs*/\
+	MUX_VAL(CP(D2D_N3GTDI),		(IEN  | PTD | DIS | M0)) /*d2d_n3gtdi*/\
+	MUX_VAL(CP(D2D_N3GTDO),		(IEN  | PTD | DIS | M0)) /*d2d_n3gtdo*/\
+	MUX_VAL(CP(D2D_N3GTMS),		(IEN  | PTD | DIS | M0)) /*d2d_n3gtms*/\
+	MUX_VAL(CP(D2D_N3GTCK),		(IEN  | PTD | DIS | M0)) /*d2d_n3gtck*/\
+	MUX_VAL(CP(D2D_N3GRTCK),	(IEN  | PTD | DIS | M0)) /*d2d_n3grtc*/\
+	MUX_VAL(CP(D2D_MSTDBY),		(IEN  | PTU | EN  | M0)) /*d2d_mstdby*/\
+	MUX_VAL(CP(D2D_SWAKEUP),	(IEN  | PTD | EN  | M0)) /*d2d_swakeu*/\
+	MUX_VAL(CP(D2D_IDLEREQ),	(IEN  | PTD | DIS | M0)) /*d2d_idlere*/\
+	MUX_VAL(CP(D2D_IDLEACK),	(IEN  | PTU | EN  | M0)) /*d2d_idleac*/\
+	MUX_VAL(CP(D2D_MWRITE),		(IEN  | PTD | DIS | M0)) /*d2d_mwrite*/\
+	MUX_VAL(CP(D2D_SWRITE),		(IEN  | PTD | DIS | M0)) /*d2d_swrite*/\
+	MUX_VAL(CP(D2D_MREAD),		(IEN  | PTD | DIS | M0)) /*d2d_mread*/\
+	MUX_VAL(CP(D2D_SREAD),		(IEN  | PTD | DIS | M0)) /*d2d_sread*/\
+	MUX_VAL(CP(D2D_MBUSFLAG),	(IEN  | PTD | DIS | M0)) /*d2d_mbusfl*/\
+	MUX_VAL(CP(D2D_SBUSFLAG),	(IEN  | PTD | DIS | M0)) /*d2d_sbusfl*/\
+	MUX_VAL(CP(SDRC_CKE0),		(IDIS | PTU | EN  | M0)) /*sdrc_cke0*/\
+	MUX_VAL(CP(SDRC_CKE1),		(IDIS | PTU | EN  | M0)) /*sdrc_cke1*/
+
+#define MUX_RX51_C() \
+	MUX_VAL(CP(MCBSP3_DX),		(IEN | PTD | DIS | M4)) /*GPIO_140*/\
+	MUX_VAL(CP(MCBSP3_DR),		(IEN | PTD | DIS | M4)) /*GPIO_142*/\
+	MUX_VAL(CP(MCBSP3_CLKX),	(IEN | PTD | DIS | M4)) /*GPIO_141*/\
+	MUX_VAL(CP(UART2_CTS),		(IEN  | PTU | EN  | M0)) /*UART2_CTS*/\
+	MUX_VAL(CP(UART2_RTS),		(IDIS | PTD | DIS | M0)) /*UART2_RTS*/\
+	MUX_VAL(CP(UART2_TX),		(IDIS | PTD | DIS | M0)) /*UART2_TX*/
+
+#endif
diff --git a/board/nokia/rx51/tag_omap.h b/board/nokia/rx51/tag_omap.h
new file mode 100644
index 0000000..60fa26f
--- /dev/null
+++ b/board/nokia/rx51/tag_omap.h
@@ -0,0 +1,311 @@ 
+/*
+ * (C) Copyright 2011-2012
+ * Pali Rohár <pali.rohar@gmail.com>
+ *
+ * (C) Copyright 2011
+ * marcel@mesa.nl, Mesa Consulting B.V.
+ *
+ * (C) Copyright 2004-2005
+ * Nokia Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+/*
+ *  Code copied from maemo kernel 2.6.28 file
+ *  arch/arm/plat-omap/include/mach/board.h
+ *
+ *  Information structures for board-specific data
+ *
+ *  Copyright (C) 2004	Nokia Corporation
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ */
+
+/* Different peripheral ids */
+#define OMAP_TAG_CLOCK		0x4f01
+#define OMAP_TAG_SERIAL_CONSOLE	0x4f03
+#define OMAP_TAG_USB		0x4f04
+#define OMAP_TAG_LCD		0x4f05
+#define OMAP_TAG_GPIO_SWITCH	0x4f06
+#define OMAP_TAG_UART		0x4f07
+#define OMAP_TAG_FBMEM		0x4f08
+#define OMAP_TAG_STI_CONSOLE	0x4f09
+#define OMAP_TAG_CAMERA_SENSOR	0x4f0a
+#define OMAP_TAG_PARTITION	0x4f0b
+#define OMAP_TAG_TEA5761	0x4f10
+#define OMAP_TAG_TMP105		0x4f11
+
+#define OMAP_TAG_BOOT_REASON	0x4f80
+#define OMAP_TAG_FLASH_PART_STR	0x4f81
+#define OMAP_TAG_VERSION_STR	0x4f82
+
+#define OMAP_TAG_NOKIA_BT	0x4e01
+#define OMAP_TAG_WLAN_CX3110X	0x4e02
+#define OMAP_TAG_CBUS		0x4e03
+#define OMAP_TAG_EM_ASIC_BB5	0x4e04
+
+
+struct omap_clock_config {
+	/* 0 for 12 MHz, 1 for 13 MHz and 2 for 19.2 MHz */
+	u8 system_clock_type;
+};
+
+struct omap_serial_console_config {
+	u8 console_uart;
+	u32 console_speed;
+};
+
+struct omap_sti_console_config {
+	unsigned enable:1;
+	u8 channel;
+};
+
+struct omap_usb_config {
+	/* Configure drivers according to the connectors on your board:
+	 *  - "A" connector (rectagular)
+	 *	... for host/OHCI use, set "register_host".
+	 *  - "B" connector (squarish) or "Mini-B"
+	 *	... for device/gadget use, set "register_dev".
+	 *  - "Mini-AB" connector (very similar to Mini-B)
+	 *	... for OTG use as device OR host, initialize "otg"
+	 */
+	unsigned	register_host:1;
+	unsigned	register_dev:1;
+	u8		otg;	/* port number, 1-based:  usb1 == 2 */
+
+	u8		hmc_mode;
+
+	/* implicitly true if otg:  host supports remote wakeup? */
+	u8		rwc;
+
+	/* signaling pins used to talk to transceiver on usbN:
+	 *  0 == usbN unused
+	 *  2 == usb0-only, using internal transceiver
+	 *  3 == 3 wire bidirectional
+	 *  4 == 4 wire bidirectional
+	 *  6 == 6 wire unidirectional (or TLL)
+	 */
+	u8		pins[3];
+};
+
+struct omap_lcd_config {
+	char panel_name[16];
+	char ctrl_name[16];
+	s16  nreset_gpio;
+	u8   data_lines;
+};
+
+struct omap_fbmem_config {
+	u32 start;
+	u32 size;
+};
+
+struct omap_gpio_switch_config {
+	char name[12];
+	u16 gpio;
+	u8 flags:4;
+	u8 type:4;
+	unsigned int key_code:24; /* Linux key code */
+};
+
+struct omap_uart_config {
+	/* Bit field of UARTs present; bit 0 --> UART1 */
+	unsigned int enabled_uarts;
+};
+
+struct omap_tea5761_config {
+	u16 enable_gpio;
+};
+
+struct omap_partition_config {
+	char name[16];
+	unsigned int size;
+	unsigned int offset;
+	/* same as in include/linux/mtd/partitions.h */
+	unsigned int mask_flags;
+};
+
+struct omap_flash_part_str_config {
+	char part_table[0];
+};
+
+struct omap_boot_reason_config {
+	char reason_str[12];
+};
+
+struct omap_version_config {
+	char component[12];
+	char version[12];
+};
+
+/*
+ *  Code copied from maemo kernel 2.6.28 file
+ *  arch/arm/plat-omap/include/mach/board-nokia.h
+ *
+ *  Information structures for Nokia-specific board config data
+ *
+ *  Copyright (C) 2005  Nokia Corporation
+ */
+
+struct omap_bluetooth_config {
+	u8 chip_type;
+	u8 bt_wakeup_gpio;
+	u8 host_wakeup_gpio;
+	u8 reset_gpio;
+	u8 bt_uart;
+	u8 bd_addr[6];
+	u8 bt_sysclk;
+};
+
+struct omap_wlan_cx3110x_config {
+	u8 chip_type;
+	u8 reserverd;
+	s16 power_gpio;
+	s16 irq_gpio;
+	s16 spi_cs_gpio;
+};
+
+struct omap_cbus_config {
+	s16 clk_gpio;
+	s16 dat_gpio;
+	s16 sel_gpio;
+};
+
+struct omap_em_asic_bb5_config {
+	s16 retu_irq_gpio;
+	s16 tahvo_irq_gpio;
+};
+
+/*
+ *  omap_tag handling
+ *
+ *  processing omap tag structures
+ *
+ *  Copyright (C) 2011  marcel@mesa.nl, Mesa Consulting B.V.
+ *  Copyright (C) 2012  Pali Rohár <pali.rohar@gmail.com>
+ */
+
+/* TI OMAP specific information */
+#define ATAG_BOARD	0x414f4d50
+
+struct tag_omap_header {
+	u16 tag;
+	u16 size;
+};
+
+struct tag_omap {
+	struct tag_omap_header hdr;
+	union {
+		struct omap_clock_config clock;
+		struct omap_serial_console_config serial_console;
+		struct omap_sti_console_config sti_console;
+		struct omap_usb_config usb;
+		struct omap_lcd_config lcd;
+		struct omap_fbmem_config fbmem;
+		struct omap_gpio_switch_config gpio_switch;
+		struct omap_uart_config uart;
+		struct omap_tea5761_config tea5761;
+		struct omap_partition_config partition;
+		struct omap_flash_part_str_config flash_part_str;
+		struct omap_boot_reason_config boot_reason;
+		struct omap_version_config version;
+		struct omap_bluetooth_config bluetooth;
+		struct omap_wlan_cx3110x_config wlan_cx3110x;
+		struct omap_cbus_config cbus;
+		struct omap_em_asic_bb5_config em_asic_bb5;
+	} u;
+};
+
+#define tag_omap_next(t)	((struct tag_omap *)((u8 *)(t) + \
+				(t)->hdr.size + sizeof(struct tag_omap_header)))
+
+#define OMAP_TAG_HEADER_CONFIG(config, type) \
+	.hdr.tag = config, \
+	.hdr.size = sizeof(struct type)
+
+#define OMAP_TAG_UART_CONFIG(p1) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_UART, omap_uart_config), \
+		.u.uart.enabled_uarts = p1, \
+	}
+
+#define OMAP_TAG_SERIAL_CONSOLE_CONFIG(p1, p2) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_SERIAL_CONSOLE, \
+			omap_serial_console_config), \
+		.u.serial_console.console_uart = p1, \
+		.u.serial_console.console_speed = p2, \
+	}
+
+#define OMAP_TAG_LCD_CONFIG(p1, p2, p3, p4) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_LCD, omap_lcd_config), \
+		.u.lcd.panel_name = p1, \
+		.u.lcd.ctrl_name = p2, \
+		.u.lcd.nreset_gpio = p3, \
+		.u.lcd.data_lines = p4, \
+	}
+
+#define OMAP_TAG_GPIO_SWITCH_CONFIG(p1, p2, p3, p4, p5) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_GPIO_SWITCH, \
+			omap_gpio_switch_config), \
+		.u.gpio_switch.name = p1, \
+		.u.gpio_switch.gpio = p2, \
+		.u.gpio_switch.flags = p3, \
+		.u.gpio_switch.type = p4, \
+		.u.gpio_switch.key_code = p5, \
+	}
+
+#define OMAP_TAG_WLAN_CX3110X_CONFIG(p1, p2, p3, p4, p5) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_WLAN_CX3110X, \
+			omap_wlan_cx3110x_config), \
+		.u.wlan_cx3110x.chip_type = p1, \
+		.u.wlan_cx3110x.reserverd = p2, \
+		.u.wlan_cx3110x.power_gpio = p3, \
+		.u.wlan_cx3110x.irq_gpio = p4, \
+		.u.wlan_cx3110x.spi_cs_gpio = p5, \
+	}
+
+#define OMAP_TAG_PARTITION_CONFIG(p1, p2, p3, p4) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_PARTITION, \
+			omap_partition_config), \
+		.u.partition.name = p1, \
+		.u.partition.size = p2, \
+		.u.partition.offset = p3, \
+		.u.partition.mask_flags = p4, \
+	}
+
+#define OMAP_TAG_BOOT_REASON_CONFIG(p1) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_BOOT_REASON, \
+			omap_boot_reason_config), \
+		.u.boot_reason.reason_str = p1, \
+	}
+
+#define OMAP_TAG_VERSION_STR_CONFIG(p1, p2) \
+	{ \
+		OMAP_TAG_HEADER_CONFIG(OMAP_TAG_VERSION_STR, \
+			omap_version_config), \
+		.u.version.component = p1, \
+		.u.version.version = p2, \
+	}
diff --git a/boards.cfg b/boards.cfg
index 4b17289..0647b3e 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -264,6 +264,7 @@  devkit8000                   arm         armv7       devkit8000          timll
 mcx                          arm         armv7       mcx                 htkw           omap3
 tricorder                    arm         armv7       tricorder           corscience     omap3
 twister                      arm         armv7       twister             technexion     omap3
+nokia_rx51                   arm         armv7       rx51                nokia          omap3
 omap4_panda                  arm         armv7       panda               ti             omap4
 omap4_sdp4430                arm         armv7       sdp4430             ti             omap4
 omap5_evm                    arm         armv7       omap5_evm           ti		omap5
diff --git a/doc/README.nokia_rx51 b/doc/README.nokia_rx51
new file mode 100644
index 0000000..a8fdfcd
--- /dev/null
+++ b/doc/README.nokia_rx51
@@ -0,0 +1,104 @@ 
+Board: Nokia RX-51 aka N900
+
+This board definition results in a u-boot.bin which can be chainloaded
+from NOLO in qemu or on a real N900. It does very little hardware config
+because NOLO has already configured the board. Only needed is enabling
+internal eMMC memory via twl4030 regulator which is not enabled by NOLO.
+
+NOLO is expecting a kernel image and will treat any image it finds in
+onenand as such. This u-boot is intended to be flashed to the N900 like
+a kernel. In order to transparently boot the original kernel, it will be
+appended to u-boot.bin at 0x40000. NOLO will load the entire image into
+(random) memory and execute u-boot, which saves hw revision, boot reason
+and boot mode ATAGs set by NOLO. Then the bootscripts will attempt to load
+uImage or boot.scr from a fat, ext2/ext3 or ext4 filesystem in external
+SD card or internal eMMC memory. If this fails or keyboard is closed then
+the appended kernel image will be booted using some generated and some
+stored ATAGs (see boot order).
+
+There is support for hardware watchdog. Hardware watchdog is started by
+NOLO so u-boot must kick watchdog to prevent reboot device (but not very
+often, max every 2 seconds). There is also support for framebuffer display
+output with ANSI espace codes and the N900 HW keyboard input. USB tty works
+but is disabled because it prevents the current Maemo kernel from booting.
+
+When U-Boot is starting it enable IBE bit in Auxiliary Control Register,
+which is needed for Thumb-2 ISA support. It is workaround for errata 430973.
+
+Default boot order:
+
+ * 0. if keyboard is closed boot automatically attached kernel image
+ * 1. try boot from external SD card
+ * 2. try boot from internal eMMC memory
+ * 3. try boot from attached kernel image
+
+Boot from SD or eMMC in this order:
+
+ * 1.
+   * 1.1 find boot.scr on first fat partition
+   * 1.2 find uImage on first fat parition
+   * 1.3 same order for 2. - 4. fat partition
+ * 2. same as 1. but for ext2/3 partition
+ * 3. same as 1. but for ext4 partition
+
+
+Available additional commands/variables:
+
+ * run sercon - Use serial port for control
+ * run usbcon - Use usbtty for control
+ * run vgacon - Use framebuffer and HW keyboard for control (default)
+
+ * run sdboot - Boot from external SD card (see boot order)
+ * run emmcboot - Boot from internal eMMC memory (see boot order)
+ * run attachboot - Boot attached kernel image (attached to U-Boot binary)
+
+ * run scriptload - Load boot script ${mmcscriptfile}
+ * run scriptboot - Run loaded boot script
+ * run kernload - Load kernel image ${mmckernfile}
+ * run initrdload - Load initrd image ${mmcinitrdfile}
+ * run kernboot - Boot loaded kernel image
+ * run kerninitrdboot - Boot loaded kernel image with loaded initrd image
+
+ * run trymmcscriptboot - Try to load and boot script ${mmcscriptfile}
+ * run trymmckernboot - Try to load and boot kernel image ${mmckernfile}
+ * run trymmckerninitrdboot - Try to load and boot kernel image ${mmckernfile}
+                              with initrd image ${mmcinitrdfile}
+
+Additional variables for loading files from mmc:
+
+ * mmc ${mmcnum} (0 - external, 1 - internal)
+ * partition number ${mmcpart} (1 - 4)
+ * parition type ${mmctype} (fat, ext2)
+
+Additional varuables for booting kernel:
+
+ * setup_omap_atag - Add OMAP table into atags structure (needs maemo kernel)
+ * setup_console_atag - Enable serial console in OMAP table
+ * setup_boot_reason_atag - Change boot reason in OMAP table
+ * setup_boot_mode_atag - Change boot mode in OMAP table
+
+USB TTY:
+
+ Maemo kernel 2.6.28 will crash if u-boot enable usb tty. So USB TTY is disabled.
+ For enabling USB TTY just add this line to file include/configs/nokia_rx51.h
+
+ #define CONFIG_USB_TTY
+
+
+ONENAND support:
+
+ ONENAND support is disabled because not working yet and cause linux kernel to
+ crash or no access to mtd. For enabling ONENAND support add this line at begin
+ of file include/configs/nokia_rx51.h
+
+ #define ONENAND_SUPPORT
+
+
+UBIFS support:
+
+ UBIFS support is disabled, because U-Boot image is too big and cannot be
+ flashed with attached zImage to RX-51 kernel nand area. For enabling UBIFS
+ support first enable ONENAND support and then add this line at begin of file
+ include/configs/nokia_rx51.h
+
+ #define UBIFS_SUPPORT
diff --git a/include/configs/nokia_rx51.h b/include/configs/nokia_rx51.h
new file mode 100644
index 0000000..ba4662d
--- /dev/null
+++ b/include/configs/nokia_rx51.h
@@ -0,0 +1,452 @@ 
+/*
+ * (C) Copyright 2011-2012
+ * Pali Rohár <pali.rohar@gmail.com>
+ *
+ * (C) Copyright 2010
+ * Alistair Buxton <a.j.buxton@gmail.com>
+ *
+ * Derived from Beagle Board code:
+ * (C) Copyright 2006-2008
+ * Texas Instruments.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Configuration settings for the Nokia RX-51 aka N900.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ */
+
+#define CONFIG_OMAP			/* in a TI OMAP core */
+#define CONFIG_OMAP34XX			/* which is a 34XX */
+#define CONFIG_OMAP3430			/* which is in a 3430 */
+#define CONFIG_OMAP3_RX51		/* working with RX51 */
+#define CONFIG_SYS_L2CACHE_OFF		/* pretend there is no L2 CACHE */
+
+/*
+ * Nokia X-Loader loading secondary image to address 0x80400000
+ * NOLO loading boot image to random place, so it doesn't really
+ * matter what we set this to. We have to copy u-boot to this address
+ */
+#define CONFIG_SYS_TEXT_BASE	0x80008000
+
+#define CONFIG_SDRC			/* The chip has SDRC controller */
+
+#include <asm/arch/cpu.h>		/* get chip and board defs */
+#include <asm/arch/omap3.h>
+#include <asm/arch/mem.h>
+
+#define tostring(s)		#s
+#define stringify(s)		tostring(s)
+
+/*
+ * Display CPU and Board information
+ */
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+
+/* Clock Defines */
+#define V_OSCK			26000000	/* Clock output from T2 */
+#define V_SCLK			(V_OSCK >> 1)
+
+#undef CONFIG_USE_IRQ				/* no support for IRQs */
+#define CONFIG_MISC_INIT_R
+#define CONFIG_SKIP_LOWLEVEL_INIT		/* X-Loader set everything up */
+
+#define CONFIG_CMDLINE_TAG	/* enable passing kernel command line string */
+#define CONFIG_INITRD_TAG			/* enable passing initrd */
+#define CONFIG_REVISION_TAG			/* enable passing revision tag*/
+#define CONFIG_SETUP_MEMORY_TAGS		/* enable memory tag */
+
+/*
+ * Size of malloc() pool
+ */
+#define CONFIG_ENV_SIZE			(128 << 10)
+#define CONFIG_UBI_SIZE			(512 << 10)
+#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + CONFIG_UBI_SIZE + \
+					(128 << 10))
+
+/*
+ * Hardware drivers
+ */
+
+/*
+ * NS16550 Configuration
+ */
+#define V_NS16550_CLK		48000000		/* 48MHz (APLL96/2) */
+
+#define CONFIG_SYS_NS16550
+#define CONFIG_SYS_NS16550_SERIAL
+#define CONFIG_SYS_NS16550_REG_SIZE	(-4)
+#define CONFIG_SYS_NS16550_CLK		V_NS16550_CLK
+
+/*
+ * select serial console configuration
+ */
+#define CONFIG_CONS_INDEX		3
+#define CONFIG_SYS_NS16550_COM3		OMAP34XX_UART3
+#define CONFIG_SERIAL3			3		/* UART3 on RX-51 */
+
+/* allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+#define CONFIG_BAUDRATE			115200
+#define CONFIG_SYS_BAUDRATE_TABLE { 4800, 9600, 19200, 38400, 57600, 115200 }
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_OMAP_HSMMC
+#define CONFIG_DOS_PARTITION
+
+/* USB */
+#define CONFIG_MUSB_UDC
+#define CONFIG_MUSB_HDC
+#define CONFIG_USB_OMAP3
+#define CONFIG_TWL4030_USB
+
+/* USB device configuration */
+#define CONFIG_USB_DEVICE
+#define CONFIG_USBD_VENDORID		0x0421
+#define CONFIG_USBD_PRODUCTID		0x01c8
+#define CONFIG_USBD_MANUFACTURER	"Nokia"
+#define CONFIG_USBD_PRODUCT_NAME	"N900"
+
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
+#define CONFIG_SYS_NO_FLASH
+
+/* commands to include */
+#include <config_cmd_default.h>
+
+#define CONFIG_CMD_EXT2			/* EXT2 Support */
+#define CONFIG_CMD_EXT4			/* EXT4 Support */
+#define CONFIG_CMD_FAT			/* FAT support */
+
+#define CONFIG_CMD_I2C			/* I2C serial bus support */
+#define CONFIG_CMD_MMC			/* MMC support */
+#define CONFIG_CMD_GPIO			/* Enable gpio command */
+
+#define CONFIG_CMDLINE_EDITING		/* add command line history */
+#define CONFIG_AUTO_COMPLETE		/* add autocompletion support */
+
+#define CONFIG_CMD_CLEAR		/* ANSI terminal clear screen command */
+
+#ifdef ONENAND_SUPPORT
+
+#define CONFIG_CMD_ONENAND		/* ONENAND support */
+#define CONFIG_CMD_MTDPARTS		/* mtd parts support */
+
+#ifdef UBIFS_SUPPORT
+#define CONFIG_CMD_UBI			/* UBI Support */
+#define CONFIG_CMD_UBIFS		/* UBIFS Support */
+#endif
+
+#endif
+
+/* commands not needed from config_cmd_default.h */
+#undef CONFIG_CMD_FPGA			/* FPGA configuration Support */
+#undef CONFIG_CMD_IMI			/* iminfo */
+#undef CONFIG_CMD_NET			/* bootp, tftpboot, rarpboot */
+#undef CONFIG_CMD_NFS			/* NFS support */
+#undef CONFIG_CMD_SAVEENV		/* saveenv */
+#undef CONFIG_CMD_SETGETDCR		/* DCR support on 4xx */
+
+#define CONFIG_OMAP3_SPI
+#define CONFIG_HARD_I2C
+#define CONFIG_SYS_I2C_SPEED		100000
+#define CONFIG_SYS_I2C_SLAVE		1
+#define CONFIG_DRIVER_OMAP34XX_I2C
+
+/*
+ * TWL4030
+ */
+#define CONFIG_TWL4030_POWER
+#define CONFIG_TWL4030_LED
+#define CONFIG_TWL4030_KEYPAD
+
+#define CONFIG_OMAP_GPIO
+#define GPIO_SLIDE			71
+
+/*
+ * Board ONENAND Info.
+ */
+
+#define PART1_NAME			"bootloader"
+#define PART1_SIZE			128
+#define PART1_MULL			1024
+#define PART1_SUFF			"k"
+#define PART1_OFFS			0x00000000
+#define PART1_MASK			0x00000003
+
+#define PART2_NAME			"config"
+#define PART2_SIZE			384
+#define PART2_MULL			1024
+#define PART2_SUFF			"k"
+#define PART2_OFFS			0x00020000
+#define PART2_MASK			0x00000000
+
+#define PART3_NAME			"log"
+#define PART3_SIZE			256
+#define PART3_MULL			1024
+#define PART3_SUFF			"k"
+#define PART3_OFFS			0x00080000
+#define PART3_MASK			0x00000000
+
+#define PART4_NAME			"kernel"
+#define PART4_SIZE			2
+#define PART4_MULL			1024*1024
+#define PART4_SUFF			"m"
+#define PART4_OFFS			0x000c0000
+#define PART4_MASK			0x00000000
+
+#define PART5_NAME			"initfs"
+#define PART5_SIZE			2
+#define PART5_MULL			1024*1024
+#define PART5_SUFF			"m"
+#define PART5_OFFS			0x002c0000
+#define PART5_MASK			0x00000000
+
+#define PART6_NAME			"rootfs"
+#define PART6_SIZE			257280
+#define PART6_MULL			1024
+#define PART6_SUFF			"k"
+#define PART6_OFFS			0x004c0000
+#define PART6_MASK			0x00000000
+
+#ifdef ONENAND_SUPPORT
+
+#define PISMO1_NAND_SIZE		GPMC_SIZE_128M
+#define PISMO1_ONEN_SIZE		GPMC_SIZE_128M
+#define CONFIG_SYS_ONENAND_BASE		ONENAND_MAP
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
+
+#ifdef UBIFS_SUPPORT
+#define CONFIG_RBTREE
+#define CONFIG_LZO
+#endif
+
+#define MTDIDS_DEFAULT			"onenand0=onenand"
+#define MTDPARTS_DEFAULT		"mtdparts=onenand:" \
+			stringify(PART1_SIZE) PART1_SUFF "(" PART1_NAME ")ro," \
+			stringify(PART2_SIZE) PART2_SUFF "(" PART2_NAME ")," \
+			stringify(PART3_SIZE) PART3_SUFF "(" PART3_NAME ")," \
+			stringify(PART4_SIZE) PART4_SUFF "(" PART4_NAME ")," \
+			stringify(PART5_SIZE) PART5_SUFF "(" PART5_NAME ")," \
+			"-(" PART6_NAME ")"
+
+#endif
+
+/* Watchdog support */
+#define CONFIG_HW_WATCHDOG
+
+/*
+ * Framebuffer
+ */
+/* Video console */
+#define CONFIG_VIDEO
+#define CONFIG_CFB_CONSOLE
+#define CONFIG_CFB_CONSOLE_ANSI	/* Enable ANSI escape codes in framebuffer */
+#define CONFIG_VIDEO_LOGO
+#define VIDEO_FB_16BPP_PIXEL_SWAP
+#define VIDEO_FB_16BPP_WORD_SWAP
+#define CONFIG_VIDEO_SW_CURSOR
+#define CONFIG_SPLASH_SCREEN
+
+/* functions for cfb_console */
+#define VIDEO_KBD_INIT_FCT		rx51_kp_init()
+#define VIDEO_TSTC_FCT			rx51_kp_tstc
+#define VIDEO_GETC_FCT			rx51_kp_getc
+#ifndef __ASSEMBLY__
+int rx51_kp_init(void);
+int rx51_kp_tstc(void);
+int rx51_kp_getc(void);
+#endif
+
+#ifndef MTDPARTS_DEFAULT
+#define MTDPARTS_DEFAULT
+#endif
+
+/* Environment information */
+#define CONFIG_BOOTDELAY		3
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	"mtdparts=" MTDPARTS_DEFAULT "\0" \
+	"usbtty=cdc_acm\0" \
+	"stdin=vga\0" \
+	"stdout=vga\0" \
+	"stderr=vga\0" \
+	"setcon=setenv stdin ${con};" \
+		"setenv stdout ${con};" \
+		"setenv stderr ${con}\0" \
+	"sercon=setenv con serial; run setcon\0" \
+	"usbcon=setenv con usbtty; run setcon\0" \
+	"vgacon=setenv con vga; run setcon\0" \
+	"slide=gpio input " stringify(GPIO_SLIDE) "\0" \
+	"switchmmc=mmc dev ${mmcnum}\0" \
+	"kernaddr=0x82008000\0" \
+	"initrdaddr=0x84008000\0" \
+	"scriptaddr=0x86008000\0" \
+	"fileload=${mmctype}load mmc ${mmcnum}:${mmcpart} " \
+		"${loadaddr} ${mmcfile}\0" \
+	"kernload=setenv loadaddr ${kernaddr};" \
+		"setenv mmcfile ${mmckernfile};" \
+		"run fileload\0" \
+	"initrdload=setenv loadaddr ${initrdaddr};" \
+		"setenv mmcfile ${mmcinitrdfile};" \
+		"run fileload\0" \
+	"scriptload=setenv loadaddr ${scriptaddr};" \
+		"setenv mmcfile ${mmcscriptfile};" \
+		"run fileload\0" \
+	"scriptboot=echo Running ${mmcscriptfile} from mmc " \
+		"${mmcnum}:${mmcpart} ...; source ${scriptaddr}\0" \
+	"kernboot=echo Booting ${mmckernfile} from mmc " \
+		"${mmcnum}:${mmcpart} ...; bootm ${kernaddr}\0" \
+	"kerninitrdboot=echo Booting ${mmckernfile} ${mmcinitrdfile} from mmc "\
+		"${mmcnum}:${mmcpart} ...; bootm ${kernaddr} ${initrdaddr}\0" \
+	"attachboot=echo Booting attached kernel image ...;" \
+		"setenv setup_omap_atag 1;" \
+		"bootm ${attkernaddr};" \
+		"setenv setup_omap_atag\0" \
+	"trymmcscriptboot=if run switchmmc; then " \
+			"if run scriptload; then " \
+				"run scriptboot;" \
+			"fi;" \
+		"fi\0" \
+	"trymmckernboot=if run switchmmc; then " \
+			"if run kernload; then " \
+				"run kernboot;" \
+			"fi;" \
+		"fi\0" \
+	"trymmckerninitrdboot=if run switchmmc; then " \
+			"if run initrdload; then " \
+				"if run kernload; then " \
+					"run kerninitrdboot;" \
+				"fi;" \
+			"fi; " \
+		"fi\0" \
+	"trymmcpartboot=setenv mmcscriptfile boot.scr; run trymmcscriptboot;" \
+		"setenv mmckernfile uImage; run trymmckernboot\0" \
+	"trymmcallpartboot=setenv mmcpart 1; run trymmcpartboot;" \
+		"setenv mmcpart 2; run trymmcpartboot;" \
+		"setenv mmcpart 3; run trymmcpartboot;" \
+		"setenv mmcpart 4; run trymmcpartboot\0" \
+	"trymmcboot=if run switchmmc; then " \
+			"setenv mmctype fat;" \
+			"run trymmcallpartboot;" \
+			"setenv mmctype ext2;" \
+			"run trymmcallpartboot;" \
+			"setenv mmctype ext4;" \
+			"run trymmcallpartboot;" \
+		"fi\0" \
+	"emmcboot=setenv mmcnum 1; run trymmcboot\0" \
+	"sdboot=setenv mmcnum 0; run trymmcboot\0" \
+	""
+
+#define CONFIG_PREBOOT \
+	"if run slide; then true; else run attachboot; fi;" \
+	"echo Extra commands:;" \
+	"echo run sercon - Use serial port for control.;" \
+	"echo run usbcon - Use usbtty for control.;" \
+	"echo run vgacon - Use framebuffer/keyboard.;" \
+	"echo run sdboot - Boot from SD card slot.;" \
+	"echo run emmcboot - Boot internal eMMC memory.;" \
+	"echo run attachboot - Boot attached kernel image.;" \
+	"echo"
+
+#define CONFIG_BOOTCOMMAND \
+	"run sdboot;" \
+	"run emmcboot;" \
+	"run attachboot;" \
+	"echo"
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_LONGHELP			/* undef to save memory */
+#define CONFIG_SYS_HUSH_PARSER			/* use "hush" command parser */
+#define CONFIG_SYS_PROMPT_HUSH_PS2	"> "
+#define CONFIG_SYS_PROMPT		"Nokia RX-51 # "
+#define CONFIG_SYS_CBSIZE		256	/* Console I/O Buffer Size */
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + \
+						sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS		16	/* max number of command args */
+/* Boot Argument Buffer Size */
+#define CONFIG_SYS_BARGSIZE		(CONFIG_SYS_CBSIZE)
+
+#define CONFIG_SYS_MEMTEST_START	(OMAP34XX_SDRC_CS0)
+#define CONFIG_SYS_MEMTEST_END		(OMAP34XX_SDRC_CS0 + 0x01F00000)/*31MB*/
+
+/* default load address */
+#define CONFIG_SYS_LOAD_ADDR		(OMAP34XX_SDRC_CS0)
+
+/*
+ * OMAP3 has 12 GP timers, they can be driven by the system clock
+ * (12/13/16.8/19.2/38.4MHz) or by 32KHz clock. We use 13MHz (V_SCLK).
+ * This rate is divided by a local divisor.
+ */
+#define CONFIG_SYS_TIMERBASE		(OMAP34XX_GPT2)
+#define CONFIG_SYS_PTV			2	/* Divisor: 2^(PTV+1) => 8 */
+#define CONFIG_SYS_HZ			1000
+
+/*
+ * Stack sizes
+ *
+ * The stack sizes are set up in start.S using the settings below
+ */
+#define CONFIG_STACKSIZE		(128 << 10) /* regular stack 128 KiB */
+
+/*
+ * Physical Memory Map
+ */
+#define CONFIG_NR_DRAM_BANKS		2
+#define PHYS_SDRAM_1			OMAP34XX_SDRC_CS0
+
+/*
+ * FLASH and environment organization
+ */
+
+#define CONFIG_ENV_IS_NOWHERE
+
+#define CONFIG_SYS_SDRAM_BASE		PHYS_SDRAM_1
+#define CONFIG_SYS_INIT_RAM_ADDR	0x4020f800
+#define CONFIG_SYS_INIT_RAM_SIZE	0x800
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_INIT_RAM_ADDR + \
+			CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
+
+/*
+ * Attached kernel image
+ */
+
+#define SDRAM_SIZE			0x10000000	/* 256 MB */
+#define SDRAM_END			(CONFIG_SYS_SDRAM_BASE + SDRAM_SIZE)
+
+#define IMAGE_MAXSIZE			0x1FF800	/* 2 MB - 2 kB */
+#define KERNEL_OFFSET			0x40000		/* 256 kB */
+#define KERNEL_MAXSIZE			(IMAGE_MAXSIZE-KERNEL_OFFSET)
+#define KERNEL_ADDRESS			(SDRAM_END-KERNEL_MAXSIZE)
+
+/* Reserve protected RAM for attached kernel */
+#define CONFIG_PRAM			((KERNEL_MAXSIZE >> 10)+1)
+
+#endif /* __CONFIG_H */