From: lhh <lhh@rock-chips.com>
Date: Fri, 22 Oct 2010 13:58:23 +0000 (+0800)
Subject: add rk29 serial and console
X-Git-Tag: firefly_0821_release~11045
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=2d6ca34280be06dfe38c26cf23539a1cd293a9f7;p=firefly-linux-kernel-4.4.55.git

add rk29 serial and console
---

diff --git a/arch/arm/configs/rk29_sdk_defconfig b/arch/arm/configs/rk29_sdk_defconfig
index 3687c8f75a86..b124bcd616aa 100644
--- a/arch/arm/configs/rk29_sdk_defconfig
+++ b/arch/arm/configs/rk29_sdk_defconfig
@@ -67,10 +67,16 @@ CONFIG_RESOURCE_COUNTERS=y
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_RD_GZIP=y
+CONFIG_INITRAMFS_SOURCE="../initramfs"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+# CONFIG_RD_GZIP is not set
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -322,13 +328,50 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
-# CONFIG_UNIX is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
-# CONFIG_INET is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
 CONFIG_ANDROID_PARANOID_NETWORK=y
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_NET_DSA is not set
@@ -339,6 +382,7 @@ CONFIG_ANDROID_PARANOID_NETWORK=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_PHONET is not set
 # CONFIG_IEEE802154 is not set
@@ -353,6 +397,7 @@ CONFIG_ANDROID_PARANOID_NETWORK=y
 # CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
 # CONFIG_WIRELESS is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
@@ -414,6 +459,7 @@ CONFIG_HAVE_IDE=y
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
@@ -490,20 +536,21 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_RK29=y
+# CONFIG_UART0_RK29 is not set
+CONFIG_UART1_RK29=y
+# CONFIG_UART2_RK29 is not set
+# CONFIG_UART3_RK29 is not set
+CONFIG_SERIAL_RK29_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-CONFIG_IPMI_HANDLER=m
-# CONFIG_IPMI_PANIC_EVENT is not set
-CONFIG_IPMI_DEVICE_INTERFACE=m
-CONFIG_IPMI_SI=m
-CONFIG_IPMI_WATCHDOG=m
-CONFIG_IPMI_POWEROFF=m
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
-CONFIG_R3964=y
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=256
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 # CONFIG_DCC_TTY is not set
 # CONFIG_I2C is not set
@@ -585,9 +632,16 @@ CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 # CONFIG_ANDROID_LOGGER is not set
-# CONFIG_ANDROID_RAM_CONSOLE is not set
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE=128
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE=16
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE=8
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d
+# CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set
 # CONFIG_ANDROID_TIMED_OUTPUT is not set
-# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 
 #
 # Qualcomm MSM Camera And Video
@@ -710,6 +764,13 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -756,6 +817,7 @@ CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
 
 #
 # Kernel hacking
@@ -822,8 +884,7 @@ CONFIG_ARM_UNWIND=y
 # CONFIG_DEBUG_USER is not set
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
@@ -943,8 +1004,9 @@ CONFIG_CRC16=y
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_DECOMPRESS_GZIP=y
+CONFIG_REED_SOLOMON=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REED_SOLOMON_DEC8=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
diff --git a/arch/arm/mach-rk29/Makefile b/arch/arm/mach-rk29/Makefile
index ad969989dba7..e9fb9849bdf7 100644
--- a/arch/arm/mach-rk29/Makefile
+++ b/arch/arm/mach-rk29/Makefile
@@ -1,2 +1,2 @@
-obj-y += timer.o io.o
+obj-y += timer.o io.o devices.o iomux.o 
 obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o
diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c
index 231e1327e1a1..234f7415f23e 100644
--- a/arch/arm/mach-rk29/board-rk29sdk.c
+++ b/arch/arm/mach-rk29/board-rk29sdk.c
@@ -38,8 +38,17 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include "devices.h"
+
 extern struct sys_timer rk29_timer;
 
+static struct platform_device *devices[] __initdata = {
+#ifdef CONFIG_UART1_RK29	
+	&rk29_device_uart1,
+#endif	
+
+};
+
 static void __init rk29_gic_init_irq(void)
 {
 	gic_dist_init(0, (void __iomem *)RK29_GICPERI_BASE, 32);
@@ -54,7 +63,7 @@ static void __init machine_rk29_init_irq(void)
 }
 static void __init machine_rk29_board_init(void)
 { 
-	
+	platform_add_devices(devices, ARRAY_SIZE(devices));	
 }
 
 static void __init machine_rk29_mapio(void)
diff --git a/arch/arm/mach-rk29/devices.c b/arch/arm/mach-rk29/devices.c
new file mode 100644
index 000000000000..940f651cd4de
--- /dev/null
+++ b/arch/arm/mach-rk29/devices.c
@@ -0,0 +1,117 @@
+/* arch/arm/mach-rk29/devices.c
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+ 
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <mach/irqs.h>
+#include <mach/rk29_iomap.h>
+ 
+ 
+/*
+ * rk29 4 uarts device
+ */
+#ifdef CONFIG_UART0_RK29
+static struct resource resources_uart0[] = {
+	{
+		.start	= IRQ_UART0,
+		.end	= IRQ_UART0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RK29_UART0_PHYS,
+		.end	= RK29_UART0_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+#endif
+#ifdef CONFIG_UART1_RK29
+static struct resource resources_uart1[] = {
+	{
+		.start	= IRQ_UART1,
+		.end	= IRQ_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RK29_UART1_PHYS,
+		.end	= RK29_UART1_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+#endif
+#ifdef CONFIG_UART2_RK29
+static struct resource resources_uart2[] = {
+	{
+		.start	= IRQ_UART2,
+		.end	= IRQ_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RK29_UART2_PHYS,
+		.end	= RK29_UART2_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+#endif
+#ifdef CONFIG_UART3_RK29
+static struct resource resources_uart3[] = {
+	{
+		.start	= IRQ_UART3,
+		.end	= IRQ_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RK29_UART3_PHYS,
+		.end	= RK29_UART3_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+#endif
+#ifdef CONFIG_UART0_RK29
+struct platform_device rk29_device_uart0 = {
+	.name	= "rk29_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart0),
+	.resource	= resources_uart0,
+	.dev = {
+		.platform_data = &rk2818_serial0_platdata,
+	},
+};
+#endif
+#ifdef CONFIG_UART1_RK29
+struct platform_device rk29_device_uart1 = {
+	.name	= "rk29_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+#endif
+#ifdef CONFIG_UART2_RK29
+struct platform_device rk29_device_uart2 = {
+	.name	= "rk29_serial",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+#endif
+#ifdef CONFIG_UART3_RK29
+struct platform_device rk29_device_uart3 = {
+	.name	= "rk29_serial",
+	.id	= 3,
+	.num_resources	= ARRAY_SIZE(resources_uart3),
+	.resource	= resources_uart3,
+};
+#endif
\ No newline at end of file
diff --git a/arch/arm/mach-rk29/devices.h b/arch/arm/mach-rk29/devices.h
new file mode 100644
index 000000000000..44766c99c214
--- /dev/null
+++ b/arch/arm/mach-rk29/devices.h
@@ -0,0 +1,25 @@
+/* /arch/arm/mach-rk29/devices.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_RK29_DEVICES_H
+#define __ARCH_ARM_MACH_RK29_DEVICES_H
+
+
+extern struct platform_device rk29_device_uart0;
+extern struct platform_device rk29_device_uart1;
+extern struct platform_device rk29_device_uart2;
+extern struct platform_device rk29_device_uart3;
+
+#endif
\ No newline at end of file
diff --git a/arch/arm/mach-rk29/include/mach/gpio.h b/arch/arm/mach-rk29/include/mach/gpio.h
new file mode 100644
index 000000000000..23263b155d6c
--- /dev/null
+++ b/arch/arm/mach-rk29/include/mach/gpio.h
@@ -0,0 +1,19 @@
+/* arch/arm/mach-rk29/include/mach/gpio.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#ifndef __ARCH_ARM_MACH_RK29_GPIO_H
+#define __ARCH_ARM_MACH_RK29_GPIO_H
+
+
+#endif
diff --git a/arch/arm/mach-rk29/include/mach/iomux.h b/arch/arm/mach-rk29/include/mach/iomux.h
new file mode 100644
index 000000000000..9b8d0e78e75d
--- /dev/null
+++ b/arch/arm/mach-rk29/include/mach/iomux.h
@@ -0,0 +1,57 @@
+/*
+ * arch/arm/mach-rk29/include/mach/iomux.h
+ *
+ *Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef __RK29_IOMUX_H__
+#define __RK29_IOMUX_H__
+
+#include "rk29_iomap.h"
+
+#define RK29_IOMUX_GPIO0L_CON			RK29_GRF_BASE+0x48
+#define RK29_IOMUX_GPIO0H_CON			RK29_GRF_BASE+0x4c
+#define RK29_IOMUX_GPIO1L_CON			RK29_GRF_BASE+0x50
+#define RK29_IOMUX_GPIO1H_CON			RK29_GRF_BASE+0x54
+#define RK29_IOMUX_GPIO2L_CON			RK29_GRF_BASE+0x58
+#define RK29_IOMUX_GPIO2H_CON			RK29_GRF_BASE+0x5c
+#define RK29_IOMUX_GPIO3L_CON			RK29_GRF_BASE+0x60
+#define RK29_IOMUX_GPIO3H_CON			RK29_GRF_BASE+0x64
+#define RK29_IOMUX_GPIO4L_CON			RK29_GRF_BASE+0x68
+#define RK29_IOMUX_GPIO4H_CON			RK29_GRF_BASE+0x6c
+#define RK29_IOMUX_GPIO5L_CON			RK29_GRF_BASE+0x70
+#define RK29_IOMUX_GPIO5H_CON			RK29_GRF_BASE+0x74
+
+
+#define MUX_CFG(desc,reg,off,interl,mux_mode,bflags)	\
+{						  	\
+        .name = desc,                                   \
+        .offset = off,                               	\
+        .interleave = interl,                       	\
+        .mux_reg = RK29_IOMUX_##reg##_CON,          \
+        .mode = mux_mode,                               \
+        .premode = mux_mode,                            \
+        .flags = bflags,				\
+},
+
+struct mux_config {
+	char *name;
+	const unsigned int offset;
+	unsigned int mode;
+	unsigned int premode;
+	const unsigned int mux_reg;
+	const unsigned int interleave;
+	unsigned int flags;
+};
+
+
+#endif
\ No newline at end of file
diff --git a/arch/arm/mach-rk29/include/mach/rk29_iomap.h b/arch/arm/mach-rk29/include/mach/rk29_iomap.h
index c38977d1d299..49c90cc63450 100644
--- a/arch/arm/mach-rk29/include/mach/rk29_iomap.h
+++ b/arch/arm/mach-rk29/include/mach/rk29_iomap.h
@@ -103,6 +103,7 @@
 #define RK29_CRU_SIZE				SZ_16K
 #define RK29_PMU_PHYS          		0x20004000
 #define RK29_PMU_SIZE				SZ_16K
+#define RK29_GRF_BASE				(RK29_ADDR_BASE1+0x8000)
 #define RK29_GRF_PHYS          		0x20008000
 #define RK29_GRF_SIZE				SZ_16K
 #define RK29_RTC_PHYS          		0x2000C000
diff --git a/arch/arm/mach-rk29/io.c b/arch/arm/mach-rk29/io.c
index 8fd8840c44b5..d8db9973e8c4 100644
--- a/arch/arm/mach-rk29/io.c
+++ b/arch/arm/mach-rk29/io.c
@@ -36,6 +36,7 @@ static struct map_desc rk29_io_desc[] __initdata = {
 	RK29_DEVICE(TIMER1),
 	RK29_DEVICE(DDRC),
 	RK29_DEVICE(UART1),
+	RK29_DEVICE(GRF),
 };
 
 void __init rk29_map_common_io(void)
diff --git a/arch/arm/mach-rk29/iomux.c b/arch/arm/mach-rk29/iomux.c
new file mode 100644
index 000000000000..5000c548b1e6
--- /dev/null
+++ b/arch/arm/mach-rk29/iomux.c
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/mach-rk29/iomux.c
+ *
+ *Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+
+#include <mach/rk29_iomap.h>  
+#include <mach/iomux.h>
+
+
+static struct mux_config rk29_muxs[] = {
+/*
+ *	 description				mux  mode   mux	  mux  
+ *						reg  offset inter mode
+ */
+//MUX_CFG(GPIOE_I2C0_SEL_NAME,		 	GPIO0L,   30,    2,	  0,	DEFAULT)	 
+
+};
\ No newline at end of file
diff --git a/arch/arm/mach-rk29/timer.c b/arch/arm/mach-rk29/timer.c
index 4826186b82e4..5f3d4364184e 100644
--- a/arch/arm/mach-rk29/timer.c
+++ b/arch/arm/mach-rk29/timer.c
@@ -56,19 +56,12 @@
 #define TIMER_CLKSRC_NAME		"timer1"
 
 //static struct clk *timer_clk;
-static volatile unsigned long timer_mult; /* timer count = cycle * timer_mult */
 
-void rk29_timer_update_mult(void)
-{
-	//if (timer_clk)
-	//	timer_mult = clk_get_rate(timer_clk) / 1000000;
-	timer_mult = 24000000 / 1000000;
-}
 
 static int rk29_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt)
 {
 	RK_TIMER_DISABLE(TIMER_CLKEVT);
-	RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles * timer_mult);
+	RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles );
 	RK_TIMER_ENABLE(TIMER_CLKEVT);
 
 	return 0;
@@ -117,41 +110,17 @@ static struct irqaction rk29_timer_clockevent_irq = {
 	.dev_id		= &rk29_timer_clockevent,
 };
 
-static int rk29_timer_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
-{
-	if (val == CPUFREQ_POSTCHANGE) {
-		rk29_timer_update_mult();
-	}
-
-	return 0;
-}
-
-static struct notifier_block rk29_timer_cpufreq_notifier_block = {
-	.notifier_call	= rk29_timer_cpufreq_notifier,
-	.priority	= 0x7ffffff,
-};
-
-static __init int rk29_timer_init_cpufreq(void)
-{
-	cpufreq_register_notifier(&rk29_timer_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
-	return 0;
-}
-
-arch_initcall_sync(rk29_timer_init_cpufreq);
-
 static __init int rk29_timer_init_clockevent(void)
 {
 	struct clock_event_device *ce = &rk29_timer_clockevent;
 
 	//timer_clk = clk_get(NULL, "timer");
-	rk29_timer_update_mult();
-
 	RK_TIMER_DISABLE(TIMER_CLKEVT);
 
 	setup_irq(rk29_timer_clockevent_irq.irq, &rk29_timer_clockevent_irq);
 
-	ce->mult = div_sc(1000000, NSEC_PER_SEC, ce->shift);
-	ce->max_delta_ns = clockevent_delta2ns(0xFFFFFFFFUL / 256, ce); // max pclk < 256MHz
+	ce->mult = div_sc(24000000, NSEC_PER_SEC, ce->shift);
+	ce->max_delta_ns = clockevent_delta2ns(0xFFFFFFFFUL, ce); // max pclk < 256MHz
 	ce->min_delta_ns = clockevent_delta2ns(1, ce) + 1;
 
 	ce->cpumask = cpumask_of(0);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 040967f243a1..326b5c9f6171 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1502,6 +1502,30 @@ config SERIAL_RK2818_CONSOLE
 	bool "Rockchip rk2818 serial console support"
 	depends on SERIAL_RK2818=y
 	select SERIAL_CORE_CONSOLE
+	
+config SERIAL_RK29
+	bool "RockChip rk29 serial port support"
+	depends on ARM && ARCH_RK29
+	select SERIAL_CORE
+	
+config UART0_RK29
+	bool "RockChip rk29 serial port 0 support"
+	depends on SERIAL_RK29
+	
+config UART1_RK29
+	bool "RockChip rk29 serial port 1 support"
+	depends on SERIAL_RK29
+	
+config UART2_RK29
+	bool "RockChip rk29 serial port 2 support"
+	depends on SERIAL_RK29
+	
+config UART3_RK29
+	bool "RockChip rk29 serial port 3 support"
+	depends on SERIAL_RK29
 
-
+config SERIAL_RK29_CONSOLE
+	bool "Rockchip rk29 serial console support"
+	depends on SERIAL_RK29=y
+	select SERIAL_CORE_CONSOLE
 endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 10e42a48d962..5e8f87950019 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -81,5 +81,5 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
 obj-$(CONFIG_SERIAL_RK2818) += rk2818_serial.o
-
+obj-$(CONFIG_SERIAL_RK29) += rk29_serial.o
 obj-$(CONFIG_SERIAL_TIMBERDALE)	+= timbuart.o
diff --git a/drivers/serial/rk29_serial.c b/drivers/serial/rk29_serial.c
new file mode 100644
index 000000000000..0fd57bfd70ad
--- /dev/null
+++ b/drivers/serial/rk29_serial.c
@@ -0,0 +1,710 @@
+/*
+ * drivers/serial/rk29_serial.c - driver for rk29 serial device and console
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+
+#if defined(CONFIG_SERIAL_RK29_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <mach/iomux.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include "rk2818_serial.h"
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct rk29_port {
+	struct uart_port	uart;
+	char			name[16];
+	struct clk		*clk;
+	unsigned int		imr;
+};
+
+#define UART_TO_RK29(uart_port)	((struct rk29_port *) uart_port)
+#define RK29_SERIAL_MAJOR	 TTY_MAJOR
+#define RK29_SERIAL_MINOR	 64      
+
+
+static inline void rk29_uart_write(struct uart_port *port, unsigned int val,
+			     unsigned int off)
+{
+	__raw_writel(val, port->membase + off);
+}
+
+static inline unsigned int rk29_uart_read(struct uart_port *port, unsigned int off)
+{
+	return __raw_readl(port->membase + off);
+}
+
+static int rk29_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+	unsigned int uartTemp;
+	
+	rk29_uart_write(port,rk29_uart_read(port,UART_LCR) | LCR_DLA_EN,UART_LCR);
+    uartTemp = port->uartclk / (16 * baud);
+    rk29_uart_write(port,uartTemp & 0xff,UART_DLL);
+    rk29_uart_write(port,(uartTemp>>8) & 0xff,UART_DLH);
+    rk29_uart_write(port,rk29_uart_read(port,UART_LCR) & (~LCR_DLA_EN),UART_LCR);
+	return baud;
+}
+
+/*
+ * ÅжϷ¢ËÍ»º³åÇøÊÇ·ñΪ¿Õ
+ *ÏÈÒÔFIFO´ò¿ª×ö£¬ºóÃæ¿ÉÒÔ×ö³ÉFIFO¹Ø»òFIFO¿ª¡£
+ */
+static u_int rk29_serial_tx_empty(struct uart_port *port)
+{
+    while(!(rk29_uart_read(port,UART_USR)&UART_TRANSMIT_FIFO_EMPTY))
+        cpu_relax();
+	if(rk29_uart_read(port,UART_USR)&UART_TRANSMIT_FIFO_EMPTY)
+	{
+        return (1);///1£º¿Õ
+	}else{
+        return (0);///0:·Ç¿Õ
+	}
+}
+
+/*
+ * Power / Clock management.
+ */
+static void rk29_serial_pm(struct uart_port *port, unsigned int state,
+			    unsigned int oldstate)
+{
+	struct rk29_port *rk29_port = UART_TO_RK29(port);
+
+	switch (state) {
+	case 0:
+		/*
+		 * Enable the peripheral clock for this serial port.
+		 * This is called on uart_open() or a resume event.
+		 */
+		//clk_enable(rk29_port->clk);
+		break;
+	case 3:
+		/*
+		 * Disable the peripheral clock for this serial port.
+		 * This is called on uart_close() or a suspend event.
+		 */
+		//clk_disable(rk29_port->clk);
+		break;
+	default:
+		printk(KERN_ERR "rk29_serial: unknown pm %d\n", state);
+	}
+}
+
+/*
+ * Return string describing the specified port
+ */
+static const char *rk29_serial_type(struct uart_port *port)
+{
+	return (port->type == PORT_RK29) ? "RK29_SERIAL" : NULL;
+}
+
+static void rk29_serial_enable_ms(struct uart_port *port)
+{
+  #ifdef DEBUG_LHH
+  printk("Enter::%s\n",__FUNCTION__);
+  #endif
+}
+
+/* no modem control lines */
+static unsigned int rk29_serial_get_mctrl(struct uart_port *port)
+{
+	unsigned int result = 0;
+	unsigned int status;
+	
+	status = rk29_uart_read(port,UART_MSR);
+	if (status & UART_MSR_URCTS)
+	{			
+		result = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+		printk("UART_GET_MSR:0x%x\n",result);
+	}else{			
+		result = TIOCM_CAR | TIOCM_DSR;
+		printk("UART_GET_MSR:0x%x\n",result);
+	}
+	return result;
+}
+
+static void rk29_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{        
+	#ifdef DEBUG_LHH
+	printk("Enter::%s\n",__FUNCTION__);
+	#endif 
+}
+
+/*
+ * Stop transmitting.
+ */
+static void rk29_serial_stop_tx(struct uart_port *port)
+{
+	#ifdef DEBUG_LHH
+	printk("Enter::%s\n",__FUNCTION__);
+	#endif
+}
+
+/*
+ * Start transmitting.
+ */
+static void rk29_serial_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	while(!(uart_circ_empty(xmit)))
+	{
+		while (!(rk29_uart_read(port,UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL)){
+            rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE|UART_IER_SEND_EMPTY_INT_ENABLE,UART_IER);
+            return;
+        }
+        rk29_uart_write(port,xmit->buf[xmit->tail],UART_THR);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+	if((uart_circ_empty(xmit)))
+		rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE,UART_IER);
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);	
+}
+
+/*
+ * Stop receiving - port is in process of being closed.
+ */
+static void rk29_serial_stop_rx(struct uart_port *port)
+{
+    #ifdef DEBUG_LHH
+    printk("Enter::%s\n",__FUNCTION__);
+    #endif
+}
+
+/*
+ * Control the transmission of a break signal
+ */
+static void rk29_serial_break_ctl(struct uart_port *port, int break_state)
+{
+    unsigned int temp;
+    temp = rk29_uart_read(port,UART_LCR);
+    if (break_state != 0)       
+        temp = temp & (~BREAK_CONTROL_BIT);/* start break */
+	else
+        temp = temp | BREAK_CONTROL_BIT; /* stop break */
+    rk29_uart_write(port,temp,UART_LCR);	
+}
+
+
+/*
+ * Characters received (called from interrupt handler)
+ */
+static void rk29_rx_chars(struct uart_port *port)
+{
+	unsigned int ch, flag;
+	while((rk29_uart_read(port,UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY)
+	{
+		u32 lsr = rk29_uart_read(port, UART_LSR);
+	    ch = rk29_uart_read(port,UART_RBR);
+	    flag = TTY_NORMAL;
+		port->icount.rx++;
+		if (lsr & UART_BREAK_INT_BIT) {
+			port->icount.brk++;
+			if (uart_handle_break(port))
+				continue;
+		}
+		if (uart_handle_sysrq_char(port, ch))
+		{
+			continue;
+		} 
+		uart_insert_char(port, 0, 0, ch, flag);
+	}
+	tty_flip_buffer_push(port->state->port.tty);
+	
+}
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t rk29_uart_interrupt(int irq, void *dev_id)
+{	
+	struct uart_port *port = dev_id;
+	unsigned int status, pending;
+	
+	status = rk29_uart_read(port,UART_IIR); 
+	pending = status & 0x0f;
+    if((pending == UART_IIR_RECV_AVAILABLE) || (pending == UART_IIR_CHAR_TIMEOUT))
+		rk29_rx_chars(port);
+	if(pending == UART_IIR_THR_EMPTY)
+		rk29_serial_start_tx(port);		
+	return IRQ_HANDLED;	
+}
+
+/*
+ * Disable the port
+ */
+static void rk29_serial_shutdown(struct uart_port *port)
+{
+   struct rk29_port *rk29_port = UART_TO_RK29(port);
+   rk29_uart_write(port,0x00,UART_IER);
+   //clk_disable(rk29_port->clk);
+   free_irq(port->irq, port);
+}
+/*
+ * Perform initialization and enable port for reception
+ */
+static int rk29_serial_startup(struct uart_port *port)
+{
+	struct rk29_port *rk29_port = UART_TO_RK29(port);
+	struct tty_struct *tty = port->state->port.tty;	
+	int retval;	
+		
+	retval = request_irq(port->irq,rk29_uart_interrupt,IRQF_SHARED,
+		     tty ? tty->name : "rk29_serial",port);
+	if(retval)
+	{
+		printk("\nrk29_serial_startup err \n");	
+		rk29_serial_shutdown(port);
+		return 	retval;
+	}	
+	//clk_enable(rk29_port->clk);
+	rk29_uart_write(port,0xf1,UART_FCR);
+	rk29_uart_write(port,0x01,UART_SFE);///enable fifo
+    rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE,UART_IER);  //enable uart recevice IRQ
+	return 0;
+}
+
+/*
+ * Change the port parameters
+ */
+static void rk29_serial_set_termios(struct uart_port *port, struct ktermios *termios,
+			      struct ktermios *old)
+{
+    unsigned long flags;
+    unsigned int mode, baud;
+	unsigned int umcon,fcr;
+    /* Get current mode register */
+    mode = rk29_uart_read(port,UART_LCR) & (BREAK_CONTROL_BIT | EVEN_PARITY_SELECT | PARITY_ENABLED
+                       | ONE_HALF_OR_TWO_BIT | UART_DATABIT_MASK);  
+    
+    baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+    /* byte size */
+    switch (termios->c_cflag & CSIZE) {
+    case CS5:
+        mode |= LCR_WLS_5;
+        break;
+    case CS6:
+        mode |= LCR_WLS_6;
+        break;
+    case CS7:
+        mode |= LCR_WLS_7;
+        break;
+    default:
+        mode |= LCR_WLS_8;
+        break;
+    }
+    
+    /* stop bits */
+    if (termios->c_cflag & CSTOPB)
+        mode |= ONE_STOP_BIT;
+    
+    /* parity */
+    if (termios->c_cflag & PARENB) 
+    {
+        mode |= PARITY_ENABLED;
+        if (termios->c_cflag & PARODD)
+            mode |= ODD_PARITY;
+        else
+            mode |= EVEN_PARITY;
+    }
+    spin_lock_irqsave(&port->lock, flags);
+	if(termios->c_cflag & CRTSCTS)                               
+	{        
+			/*¿ªÆôuart0Ó²¼þÁ÷¿Ø*/
+		printk("start CRTSCTS control and baudrate is %d\n",baud);
+		umcon=rk29_uart_read(port,UART_MCR);
+		printk("UART_GET_MCR umcon=0x%x\n",umcon);
+		umcon |= UART_MCR_AFCEN;
+		umcon |= UART_MCR_URRTS;
+		umcon &=~UART_SIR_ENABLE;
+		rk29_uart_write(port,umcon,UART_MCR);
+		printk("UART_GET_MCR umcon=0x%x\n",umcon);
+		fcr=rk29_uart_read(port,UART_FCR);
+		printk("UART_GET_MCR fcr=0x%x\n",fcr);
+		fcr |= UART_FCR_FIFO_ENABLE;
+		rk29_uart_write(port,fcr,UART_FCR);		
+		printk("UART_GET_MCR fcr=0x%x\n",fcr);
+	}
+    mode = mode | LCR_DLA_EN;
+    while(rk29_uart_read(port,UART_USR)&UART_USR_BUSY)
+    	cpu_relax(); 
+    rk29_uart_write(port,mode,UART_LCR);
+    baud = rk29_set_baud_rate(port, baud);
+    uart_update_timeout(port, termios->c_cflag, baud);
+    spin_unlock_irqrestore(&port->lock, flags);
+}
+
+
+static void rk29_serial_release_port(struct uart_port *port)
+{
+    struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *resource;
+	resource_size_t size;
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return;
+	size = resource->end - resource->start + 1;
+
+	release_mem_region(port->mapbase, size);
+	iounmap(port->membase);
+	port->membase = NULL;
+}
+
+static int rk29_serial_request_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *resource;
+	resource_size_t size;
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return -ENXIO;
+	size = resource->end - resource->start + 1;
+
+	if (unlikely(!request_mem_region(port->mapbase, size, "rk29_serial")))
+		return -EBUSY;
+
+	port->membase = ioremap(port->mapbase, size);
+	if (!port->membase) {
+		release_mem_region(port->mapbase, size);
+		return -EBUSY;
+	}
+
+	return 0;
+}		      
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void rk29_serial_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_RK29;
+		rk29_serial_request_port(port);
+	}
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int rk29_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_RK29)
+		ret = -EINVAL;
+	if (port->irq != ser->irq)
+		ret = -EINVAL;
+	if (ser->io_type != SERIAL_IO_MEM)
+		ret = -EINVAL;
+	if (port->uartclk / 16 != ser->baud_base)
+		ret = -EINVAL;
+	if ((void *)port->mapbase != ser->iomem_base)
+		ret = -EINVAL;
+	if (port->iobase != ser->port)
+		ret = -EINVAL;
+	if (ser->hub6 != 0)
+		ret = -EINVAL;
+	return ret;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int rk29_serial_poll_get_char(struct uart_port *port)
+{
+	while (!((rk29_uart_read(port, UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY))
+		barrier();
+	return rk29_uart_read(port, UART_RBR);
+}
+
+static void rk29_serial_poll_put_char(struct uart_port *port, unsigned char c)
+{
+	while (!(rk29_uart_read(port, UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL))
+		barrier();
+	rk29_uart_write(port, c, UART_THR);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops rk29_uart_pops = {
+	.tx_empty = rk29_serial_tx_empty,
+	.set_mctrl = rk29_serial_set_mctrl,
+	.get_mctrl = rk29_serial_get_mctrl,
+	.stop_tx = rk29_serial_stop_tx,
+	.start_tx = rk29_serial_start_tx,
+	.stop_rx = rk29_serial_stop_rx,
+	.enable_ms = rk29_serial_enable_ms,
+	.break_ctl = rk29_serial_break_ctl,
+	.startup = rk29_serial_startup,
+	.shutdown = rk29_serial_shutdown,
+	.set_termios = rk29_serial_set_termios,
+	.type = rk29_serial_type,
+	.release_port = rk29_serial_release_port,
+	.request_port = rk29_serial_request_port,
+	.config_port = rk29_serial_config_port,
+	.verify_port = rk29_serial_verify_port,
+	.pm = rk29_serial_pm,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char = rk29_serial_poll_get_char,
+	.poll_put_char = rk29_serial_poll_put_char,
+#endif
+};
+
+
+static struct rk29_port rk29_uart_ports[] = {
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &rk29_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 32,
+			.line = 0,
+		},
+	},
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &rk29_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 32,
+			.line = 1,
+		},
+	},
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &rk29_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 32,
+			.line = 2,
+		},
+	},
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &rk29_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 32,
+			.line = 3,
+		},
+	},
+};
+
+#define UART_NR	ARRAY_SIZE(rk29_uart_ports)
+
+static inline struct uart_port *get_port_from_line(unsigned int line)
+{
+	return &rk29_uart_ports[line].uart;
+}
+
+#ifdef CONFIG_SERIAL_RK29_CONSOLE
+static void rk29_console_putchar(struct uart_port *port, int ch)
+{
+    while (!(rk29_uart_read(port,UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL))
+		cpu_relax();
+	rk29_uart_write(port,ch,UART_THR);	
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void rk29_console_write(struct console *co, const char *s, u_int count)
+{
+	struct uart_port *port;
+	struct rk29_port *rk29_port;
+
+	BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+	port = get_port_from_line(co->index);
+	rk29_port = UART_TO_RK29(port);
+
+	spin_lock(&port->lock);
+	uart_console_write(port, s, count, rk29_console_putchar);
+	spin_unlock(&port->lock);
+}
+
+static int __init rk29_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud, flow, bits, parity;
+	
+	if (unlikely(co->index >= UART_NR || co->index < 0))
+		return -ENXIO;
+
+	port = get_port_from_line(co->index);
+
+	if (unlikely(!port->membase))
+		return -ENXIO;
+
+	port->cons = co;
+
+	//rk29_init_clock(port);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	bits = 8;
+	parity = 'n';
+	flow = 'n';	
+	rk29_uart_write(port,rk29_uart_read(port,UART_LCR) | LCR_WLS_8 | PARITY_DISABLED | ONE_STOP_BIT,UART_LCR);	/* 8N1 */
+	if (baud < 300 || baud > 115200)
+		baud = 115200;
+	rk29_set_baud_rate(port, baud);
+
+	printk(KERN_INFO "rk29_serial: console setup on port %d\n", port->line);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);	
+}
+
+static struct uart_driver rk29_uart_driver;
+
+static struct console rk29_console = {
+	.name = "ttyS",
+	.write = rk29_console_write,
+	.device = uart_console_device,
+	.setup = rk29_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = 1,  
+	.data = &rk29_uart_driver,
+};
+
+#define RK29_CONSOLE	(&rk29_console)
+
+#else
+#define RK29_CONSOLE	NULL
+#endif
+
+static struct uart_driver rk29_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "rk29_serial",
+	.dev_name = "ttyS",
+	.nr = UART_NR,
+	.cons = RK29_CONSOLE,
+	.major		= RK29_SERIAL_MAJOR,	
+	.minor		= RK29_SERIAL_MINOR,
+};
+
+static int __devinit rk29_serial_probe(struct platform_device *pdev)
+{
+	struct rk29_port *rk29_port;
+	struct resource *resource;
+	struct uart_port *port;
+    //struct rk29_serial_platform_data *pdata = pdev->dev.platform_data;
+		
+	if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+		return -ENXIO;
+
+	printk(KERN_INFO "rk29_serial: detected port %d\n", pdev->id);
+
+	//if (pdata && pdata->io_init)
+		//pdata->io_init();
+    
+	port = get_port_from_line(pdev->id);
+	port->dev = &pdev->dev;
+	rk29_port = UART_TO_RK29(port);
+
+	///rk29_port->clk = clk_get(&pdev->dev, "uart");
+	if (unlikely(IS_ERR(rk29_port->clk)))
+		return PTR_ERR(rk29_port->clk);
+	port->uartclk = 24000000; ///clk_get_rate(rk29_port->clk);
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return -ENXIO;
+	port->mapbase = resource->start;
+
+	port->irq = platform_get_irq(pdev, 0);
+	if (unlikely(port->irq < 0))
+		return -ENXIO;
+
+	platform_set_drvdata(pdev, port);
+
+	return uart_add_one_port(&rk29_uart_driver, port);	
+}
+
+static int __devexit rk29_serial_remove(struct platform_device *pdev)
+{
+	struct rk29_port *rk29_port = platform_get_drvdata(pdev);
+
+	///clk_put(rk29_port->clk);
+
+	return 0;
+}
+
+static struct platform_driver rk29_platform_driver = {
+	.remove = rk29_serial_remove,
+	.driver = {
+		.name = "rk29_serial",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init rk29_serial_init(void)
+{
+	int ret;
+	ret = uart_register_driver(&rk29_uart_driver);
+	if (unlikely(ret))
+		return ret;
+
+	ret = platform_driver_probe(&rk29_platform_driver, rk29_serial_probe);
+	if (unlikely(ret))
+		uart_unregister_driver(&rk29_uart_driver);
+
+	printk(KERN_INFO "rk29_serial: driver initialized\n");
+
+	return ret;
+}
+
+static void __exit rk29_serial_exit(void)
+{
+	#ifdef CONFIG_SERIAL_RK29_CONSOLE
+	unregister_console(&rk29_console);
+	#endif
+	platform_driver_unregister(&rk29_platform_driver);
+	uart_unregister_driver(&rk29_uart_driver);
+}
+
+/*
+ * While this can be a module, if builtin it's most likely the console
+ * So let's leave module_exit but move module_init to an earlier place
+ */
+arch_initcall(rk29_serial_init);
+module_exit(rk29_serial_exit);
+
+MODULE_AUTHOR("lhh lhh@rock-chips.com");
+MODULE_DESCRIPTION("Rockchip rk29 Serial port driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 1f9fa0e1561b..8bdb2548ae3d 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -179,8 +179,9 @@
 /* BCM63xx family SoCs */
 #define PORT_BCM63XX	89
 
-#define PORT_RK2818	90
+#define PORT_RK2818		90
 
+#define PORT_RK29		90
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>