aboutsummaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorAndrew Victor <andrew@sanpeople.com>2007-05-11 21:01:28 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-05-11 22:02:48 +0100
commitc53c9cf60e49119e97d38390849cac5b2f0a0981 (patch)
tree37615dedbbd8980b8357df47d90843eb86d017ff /arch/arm
parentc42dcb3dcfd3a473ab7c79c2ae91fc1c2e4dc5db (diff)
[ARM] 4331/3: Support for Micrel/Kendin KS8695 processor
Add core support for the Kendin/Micrel KS8695 processor family. It is an ARM922-T based SoC with integrated USART, 4-port Ethernet Switch, WAN Ethernet port, and optional PCI Host bridge, etc. http://www.micrel.com/page.do?page=product-info/sys_on_chip.jsp This patch is based on earlier patches from Lennert Buytenhek, Ben Dooks and Greg Ungerer posted to the arm-linux-kernel mailing list in March 2006; and Micrel's 2.6.9 port. Signed-off-by: Andrew Victor <andrew@sanpeople.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig13
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/mach-ks8695/Kconfig8
-rw-r--r--arch/arm/mach-ks8695/Makefile14
-rw-r--r--arch/arm/mach-ks8695/Makefile.boot8
-rw-r--r--arch/arm/mach-ks8695/cpu.c73
-rw-r--r--arch/arm/mach-ks8695/devices.c191
-rw-r--r--arch/arm/mach-ks8695/generic.h15
-rw-r--r--arch/arm/mach-ks8695/irq.c175
-rw-r--r--arch/arm/mach-ks8695/time.c114
-rw-r--r--arch/arm/mm/Kconfig6
11 files changed, 613 insertions, 5 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 52c209ef58b..638f1d8080a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -305,6 +305,12 @@ config ARCH_L7200
If you have any questions or comments about the Linux kernel port
to this board, send e-mail to <sjhill@cotw.com>.
+config ARCH_KS8695
+ bool "Micrel/Kendin KS8695"
+ help
+ Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
+ System-on-Chip devices.
+
config ARCH_NS9XXX
bool "NetSilicon NS9xxx"
help
@@ -451,6 +457,8 @@ source "arch/arm/mach-ns9xxx/Kconfig"
source "arch/arm/mach-davinci/Kconfig"
+source "arch/arm/mach-ks8695/Kconfig"
+
# Definitions to make life easier
config ARCH_ACORN
bool
@@ -511,7 +519,7 @@ config ISA_DMA_API
bool
config PCI
- bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX
+ bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695
help
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
@@ -680,7 +688,8 @@ config LEDS
ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
- ARCH_AT91 || MACH_TRIZEPS4 || ARCH_DAVINCI
+ ARCH_AT91 || MACH_TRIZEPS4 || ARCH_DAVINCI || \
+ ARCH_KS8695
help
If you say Y here, the LEDs on your machine will be used
to provide useful information about your current system status.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index d568d86b072..cbd5010d3bc 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -136,6 +136,7 @@ endif
machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx
textofs-$(CONFIG_ARCH_NS9XXX) := 0x00108000
machine-$(CONFIG_ARCH_DAVINCI) := davinci
+ machine-$(CONFIG_ARCH_KS8695) := ks8695
ifeq ($(CONFIG_ARCH_EBSA110),y)
# This is what happens if you forget the IOCS16 line.
diff --git a/arch/arm/mach-ks8695/Kconfig b/arch/arm/mach-ks8695/Kconfig
new file mode 100644
index 00000000000..44d14aa0baa
--- /dev/null
+++ b/arch/arm/mach-ks8695/Kconfig
@@ -0,0 +1,8 @@
+if ARCH_KS8695
+
+menu "Kendin/Micrel KS8695 Implementations"
+
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile
new file mode 100644
index 00000000000..0a0f496e8cc
--- /dev/null
+++ b/arch/arm/mach-ks8695/Makefile
@@ -0,0 +1,14 @@
+# arch/arm/mach-ks8695/Makefile
+#
+# Makefile for KS8695 architecture support
+#
+
+obj-y := cpu.o irq.o time.o devices.o
+obj-m :=
+obj-n :=
+obj- :=
+
+# PCI support is optional
+#obj-$(CONFIG_PCI) += pci.o
+
+# Board-specific support
diff --git a/arch/arm/mach-ks8695/Makefile.boot b/arch/arm/mach-ks8695/Makefile.boot
new file mode 100644
index 00000000000..48eb2cb3ac7
--- /dev/null
+++ b/arch/arm/mach-ks8695/Makefile.boot
@@ -0,0 +1,8 @@
+# Note: the following conditions must always be true:
+# ZRELADDR == virt_to_phys(TEXTADDR)
+# PARAMS_PHYS must be within 4MB of ZRELADDR
+# INITRD_PHYS must be in RAM
+
+ zreladdr-y := 0x00008000
+params_phys-y := 0x00000100
+initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-ks8695/cpu.c b/arch/arm/mach-ks8695/cpu.c
new file mode 100644
index 00000000000..407d255e42b
--- /dev/null
+++ b/arch/arm/mach-ks8695/cpu.c
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/mach-ks8695/cpu.c
+ *
+ * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
+ * Copyright (C) 2006 Simtec Electronics
+ *
+ * KS8695 CPU support
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/regs-sys.h>
+#include <asm/arch/regs-misc.h>
+
+
+static struct __initdata map_desc ks8695_io_desc[] = {
+ {
+ .virtual = KS8695_IO_VA,
+ .pfn = __phys_to_pfn(KS8695_IO_PA),
+ .length = KS8695_IO_SIZE,
+ .type = MT_DEVICE,
+ }
+};
+
+static void __init ks8695_processor_info(void)
+{
+ unsigned long id, rev;
+
+ id = __raw_readl(KS8695_MISC_VA + KS8695_DID);
+ rev = __raw_readl(KS8695_MISC_VA + KS8695_RID);
+
+ printk("KS8695 ID=%04lx SubID=%02lx Revision=%02lx\n", (id & DID_ID), (rev & RID_SUBID), (rev & RID_REVISION));
+}
+
+static unsigned int sysclk[8] = { 125000000, 100000000, 62500000, 50000000, 41700000, 33300000, 31300000, 25000000 };
+static unsigned int cpuclk[8] = { 166000000, 166000000, 83000000, 83000000, 55300000, 55300000, 41500000, 41500000 };
+
+static void __init ks8695_clock_info(void)
+{
+ unsigned int scdc = __raw_readl(KS8695_SYS_VA + KS8695_CLKCON) & CLKCON_SCDC;
+
+ printk("Clocks: System %u MHz, CPU %u MHz\n",
+ sysclk[scdc] / 1000000, cpuclk[scdc] / 1000000);
+}
+
+void __init ks8695_map_io(void)
+{
+ iotable_init(ks8695_io_desc, ARRAY_SIZE(ks8695_io_desc));
+
+ ks8695_processor_info();
+ ks8695_clock_info();
+}
diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c
new file mode 100644
index 00000000000..386593f8ac6
--- /dev/null
+++ b/arch/arm/mach-ks8695/devices.c
@@ -0,0 +1,191 @@
+/*
+ * arch/arm/mach-ks8695/devices.c
+ *
+ * Copyright (C) 2006 Andrew Victor
+ *
+ * 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.
+ *
+ * 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 <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/platform_device.h>
+
+#include <asm/arch/regs-wan.h>
+#include <asm/arch/regs-lan.h>
+#include <asm/arch/regs-hpna.h>
+
+
+/* --------------------------------------------------------------------
+ * Ethernet
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ARM_KS8695_ETHER) || defined(CONFIG_ARM_KS8695_ETHER_MODULE)
+static u64 eth_dmamask = 0xffffffffUL;
+
+static struct resource ks8695_wan_resources[] = {
+ [0] = {
+ .start = KS8695_WAN_VA,
+ .end = KS8695_WAN_VA + 0x00ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "WAN RX",
+ .start = KS8695_IRQ_WAN_RX_STATUS,
+ .end = KS8695_IRQ_WAN_RX_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .name = "WAN TX",
+ .start = KS8695_IRQ_WAN_TX_STATUS,
+ .end = KS8695_IRQ_WAN_TX_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .name = "WAN Link",
+ .start = KS8695_IRQ_WAN_LINK,
+ .end = KS8695_IRQ_WAN_LINK,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ks8695_wan_device = {
+ .name = "ks8695_ether",
+ .id = 0,
+ .dev = {
+ .dma_mask = &eth_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .resource = ks8695_wan_resources,
+ .num_resources = ARRAY_SIZE(ks8695_wan_resources),
+};
+
+
+static struct resource ks8695_lan_resources[] = {
+ [0] = {
+ .start = KS8695_LAN_VA,
+ .end = KS8695_LAN_VA + 0x00ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "LAN RX",
+ .start = KS8695_IRQ_LAN_RX_STATUS,
+ .end = KS8695_IRQ_LAN_RX_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .name = "LAN TX",
+ .start = KS8695_IRQ_LAN_TX_STATUS,
+ .end = KS8695_IRQ_LAN_TX_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ks8695_lan_device = {
+ .name = "ks8695_ether",
+ .id = 1,
+ .dev = {
+ .dma_mask = &eth_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .resource = ks8695_lan_resources,
+ .num_resources = ARRAY_SIZE(ks8695_lan_resources),
+};
+
+
+static struct resource ks8695_hpna_resources[] = {
+ [0] = {
+ .start = KS8695_HPNA_VA,
+ .end = KS8695_HPNA_VA + 0x00ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "HPNA RX",
+ .start = KS8695_IRQ_HPNA_RX_STATUS,
+ .end = KS8695_IRQ_HPNA_RX_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .name = "HPNA TX",
+ .start = KS8695_IRQ_HPNA_TX_STATUS,
+ .end = KS8695_IRQ_HPNA_TX_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ks8695_hpna_device = {
+ .name = "ks8695_ether",
+ .id = 2,
+ .dev = {
+ .dma_mask = &eth_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .resource = ks8695_hpna_resources,
+ .num_resources = ARRAY_SIZE(ks8695_hpna_resources),
+};
+
+void __init ks8695_add_device_wan(void)
+{
+ platform_device_register(&ks8695_wan_device);
+}
+
+void __init ks8695_add_device_lan(void)
+{
+ platform_device_register(&ks8695_lan_device);
+}
+
+void __init ks8696_add_device_hpna(void)
+{
+ platform_device_register(&ks8695_hpna_device);
+}
+#else
+void __init ks8695_add_device_wan(void) {}
+void __init ks8695_add_device_lan(void) {}
+void __init ks8696_add_device_hpna(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_KS8695_WATCHDOG) || defined(CONFIG_KS8695_WATCHDOG_MODULE)
+static struct platform_device ks8695_wdt_device = {
+ .name = "ks8695_wdt",
+ .id = -1,
+ .num_resources = 0,
+};
+
+static void __init ks8695_add_device_watchdog(void)
+{
+ platform_device_register(&ks8695_wdt_device);
+}
+#else
+static void __init ks8695_add_device_watchdog(void) {}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * These devices are always present and don't need any board-specific
+ * setup.
+ */
+static int __init ks8695_add_standard_devices(void)
+{
+ ks8695_add_device_watchdog();
+ return 0;
+}
+
+arch_initcall(ks8695_add_standard_devices);
diff --git a/arch/arm/mach-ks8695/generic.h b/arch/arm/mach-ks8695/generic.h
new file mode 100644
index 00000000000..2fbfab8d5fa
--- /dev/null
+++ b/arch/arm/mach-ks8695/generic.h
@@ -0,0 +1,15 @@
+/*
+ * arch/arm/mach-ks8695/generic.h
+ *
+ * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
+ * Copyright (C) 2006 Simtec Electronics
+ *
+ * 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.
+*/
+
+extern __init void ks8695_map_io(void);
+extern __init void ks8695_init_irq(void);
+extern struct sys_timer ks8695_timer;
diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c
new file mode 100644
index 00000000000..2407bba0054
--- /dev/null
+++ b/arch/arm/mach-ks8695/irq.c
@@ -0,0 +1,175 @@
+/*
+ * arch/arm/mach-ks8695/irq.c
+ *
+ * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
+ * Copyright (C) 2006 Simtec Electronics
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+static void ks8695_irq_mask(unsigned int irqno)
+{
+ unsigned long inten;
+
+ inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
+ inten &= ~(1 << irqno);
+
+ __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
+}
+
+static void ks8695_irq_unmask(unsigned int irqno)
+{
+ unsigned long inten;
+
+ inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
+ inten |= (1 << irqno);
+
+ __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
+}
+
+static void ks8695_irq_ack(unsigned int irqno)
+{
+ __raw_writel((1 << irqno), KS8695_IRQ_VA + KS8695_INTST);
+}
+
+
+static struct irq_chip ks8695_irq_level_chip;
+static struct irq_chip ks8695_irq_edge_chip;
+
+
+static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
+{
+ unsigned long ctrl, mode;
+ unsigned short level_triggered = 0;
+
+ ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
+
+ switch (type) {
+ case IRQT_HIGH:
+ mode = IOPC_TM_HIGH;
+ level_triggered = 1;
+ break;
+ case IRQT_LOW:
+ mode = IOPC_TM_LOW;
+ level_triggered = 1;
+ break;
+ case IRQT_RISING:
+ mode = IOPC_TM_RISING;
+ break;
+ case IRQT_FALLING:
+ mode = IOPC_TM_FALLING;
+ break;
+ case IRQT_BOTHEDGE:
+ mode = IOPC_TM_EDGE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (irqno) {
+ case KS8695_IRQ_EXTERN0:
+ ctrl &= ~IOPC_IOEINT0TM;
+ ctrl |= IOPC_IOEINT0_MODE(mode);
+ break;
+ case KS8695_IRQ_EXTERN1:
+ ctrl &= ~IOPC_IOEINT1TM;
+ ctrl |= IOPC_IOEINT1_MODE(mode);
+ break;
+ case KS8695_IRQ_EXTERN2:
+ ctrl &= ~IOPC_IOEINT2TM;
+ ctrl |= IOPC_IOEINT2_MODE(mode);
+ break;
+ case KS8695_IRQ_EXTERN3:
+ ctrl &= ~IOPC_IOEINT3TM;
+ ctrl |= IOPC_IOEINT3_MODE(mode);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (level_triggered) {
+ set_irq_chip(irqno, &ks8695_irq_level_chip);
+ set_irq_handler(irqno, handle_level_irq);
+ }
+ else {
+ set_irq_chip(irqno, &ks8695_irq_edge_chip);
+ set_irq_handler(irqno, handle_edge_irq);
+ }
+
+ __raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC);
+ return 0;
+}
+
+static struct irq_chip ks8695_irq_level_chip = {
+ .ack = ks8695_irq_mask,
+ .mask = ks8695_irq_mask,
+ .unmask = ks8695_irq_unmask,
+ .set_type = ks8695_irq_set_type,
+};
+
+static struct irq_chip ks8695_irq_edge_chip = {
+ .ack = ks8695_irq_ack,
+ .mask = ks8695_irq_mask,
+ .unmask = ks8695_irq_unmask,
+ .set_type = ks8695_irq_set_type,
+};
+
+void __init ks8695_init_irq(void)
+{
+ unsigned int irq;
+
+ /* Disable all interrupts initially */
+ __raw_writel(0, KS8695_IRQ_VA + KS8695_INTMC);
+ __raw_writel(0, KS8695_IRQ_VA + KS8695_INTEN);
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ switch (irq) {
+ /* Level-triggered interrupts */
+ case KS8695_IRQ_BUS_ERROR:
+ case KS8695_IRQ_UART_MODEM_STATUS:
+ case KS8695_IRQ_UART_LINE_STATUS:
+ case KS8695_IRQ_UART_RX:
+ case KS8695_IRQ_COMM_TX:
+ case KS8695_IRQ_COMM_RX:
+ set_irq_chip(irq, &ks8695_irq_level_chip);
+ set_irq_handler(irq, handle_level_irq);
+ break;
+
+ /* Edge-triggered interrupts */
+ default:
+ ks8695_irq_ack(irq); /* clear pending bit */
+ set_irq_chip(irq, &ks8695_irq_edge_chip);
+ set_irq_handler(irq, handle_edge_irq);
+ }
+
+ set_irq_flags(irq, IRQF_VALID);
+ }
+}
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
new file mode 100644
index 00000000000..d2c86e4a72e
--- /dev/null
+++ b/arch/arm/mach-ks8695/time.c
@@ -0,0 +1,114 @@
+/*
+ * arch/arm/mach-ks8695/time.c
+ *
+ * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
+ * Copyright (C) 2006 Simtec Electronics
+ *
+ * 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 <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/mach/time.h>
+
+#include <asm/arch/regs-timer.h>
+#include <asm/arch/regs-irq.h>
+
+#include "generic.h"
+
+/*
+ * Returns number of ms since last clock interrupt. Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long ks8695_gettimeoffset (void)
+{
+ unsigned long elapsed, tick2, intpending;
+
+ /*
+ * Get the current number of ticks. Note that there is a race
+ * condition between us reading the timer and checking for an
+ * interrupt. We solve this by ensuring that the counter has not
+ * reloaded between our two reads.
+ */
+ elapsed = __raw_readl(KS8695_TMR_VA + KS8695_T1TC) + __raw_readl(KS8695_TMR_VA + KS8695_T1PD);
+ do {
+ tick2 = elapsed;
+ intpending = __raw_readl(KS8695_IRQ_VA + KS8695_INTST) & (1 << KS8695_IRQ_TIMER1);
+ elapsed = __raw_readl(KS8695_TMR_VA + KS8695_T1TC) + __raw_readl(KS8695_TMR_VA + KS8695_T1PD);
+ } while (elapsed > tick2);
+
+ /* Convert to number of ticks expired (not remaining) */
+ elapsed = (CLOCK_TICK_RATE / HZ) - elapsed;
+
+ /* Is interrupt pending? If so, then timer has been reloaded already. */
+ if (intpending)
+ elapsed += (CLOCK_TICK_RATE / HZ);
+
+ /* Convert ticks to usecs */
+ return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id)
+{
+ write_seqlock(&xtime_lock);
+ timer_tick();
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction ks8695_timer_irq = {
+ .name = "ks8695_tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = ks8695_timer_interrupt,
+};
+
+static void ks8695_timer_setup(void)
+{
+ unsigned long tmout = CLOCK_TICK_RATE / HZ;
+ unsigned long tmcon;
+
+ /* disable timer1 */
+ tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
+ __raw_writel(tmcon & ~TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON);
+
+ __raw_writel(tmout / 2, KS8695_TMR_VA + KS8695_T1TC);
+ __raw_writel(tmout / 2, KS8695_TMR_VA + KS8695_T1PD);
+
+ /* re-enable timer1 */
+ __raw_writel(tmcon | TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON);
+}
+
+static void __init ks8695_timer_init (void)
+{
+ ks8695_timer_setup();
+
+ /* Enable timer interrupts */
+ setup_irq(KS8695_IRQ_TIMER1, &ks8695_timer_irq);
+}
+
+struct sys_timer ks8695_timer = {
+ .init = ks8695_timer_init,
+ .offset = ks8695_gettimeoffset,
+ .resume = ks8695_timer_setup,
+};
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index b8320a12e6b..15f0284010c 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -131,8 +131,8 @@ config CPU_ARM920T
# ARM922T
config CPU_ARM922T
bool "Support ARM922T processor" if ARCH_INTEGRATOR
- depends on ARCH_LH7A40X || ARCH_INTEGRATOR
- default y if ARCH_LH7A40X
+ depends on ARCH_LH7A40X || ARCH_INTEGRATOR || ARCH_KS8695
+ default y if ARCH_LH7A40X || ARCH_KS8695
select CPU_32v4T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -143,7 +143,7 @@ config CPU_ARM922T
help
The ARM922T is a version of the ARM920T, but with smaller
instruction and data caches. It is used in Altera's
- Excalibur XA device family.
+ Excalibur XA device family and Micrel's KS8695 Centaur.
Say Y if you want support for the ARM922T processor.
Otherwise, say N.