aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-iop33x
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-iop33x')
-rw-r--r--arch/arm/mach-iop33x/Kconfig27
-rw-r--r--arch/arm/mach-iop33x/Makefile11
-rw-r--r--arch/arm/mach-iop33x/Makefile.boot3
-rw-r--r--arch/arm/mach-iop33x/common.c22
-rw-r--r--arch/arm/mach-iop33x/iq80331-mm.c35
-rw-r--r--arch/arm/mach-iop33x/iq80331-pci.c119
-rw-r--r--arch/arm/mach-iop33x/iq80332-mm.c35
-rw-r--r--arch/arm/mach-iop33x/iq80332-pci.c125
-rw-r--r--arch/arm/mach-iop33x/irq.c129
-rw-r--r--arch/arm/mach-iop33x/pci.c222
-rw-r--r--arch/arm/mach-iop33x/setup.c221
-rw-r--r--arch/arm/mach-iop33x/time.c106
12 files changed, 1055 insertions, 0 deletions
diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig
new file mode 100644
index 000000000000..410df546e954
--- /dev/null
+++ b/arch/arm/mach-iop33x/Kconfig
@@ -0,0 +1,27 @@
1if ARCH_IOP33X
2
3menu "IOP33x Implementation Options"
4
5comment "IOP33x Platform Types"
6
7config ARCH_IQ80331
8 bool "Enable support for IQ80331"
9 help
10 Say Y here if you want to run your kernel on the Intel IQ80331
11 evaluation kit for the IOP331 chipset.
12
13config MACH_IQ80332
14 bool "Enable support for IQ80332"
15 help
16 Say Y here if you want to run your kernel on the Intel IQ80332
17 evaluation kit for the IOP332 chipset.
18
19config IOP331_STEPD
20 bool "Chip stepping D of the IOP80331 processor or IOP80333"
21 help
22 Say Y here if you have StepD of the IOP80331 or IOP8033
23 based platforms.
24
25endmenu
26
27endif
diff --git a/arch/arm/mach-iop33x/Makefile b/arch/arm/mach-iop33x/Makefile
new file mode 100644
index 000000000000..0f1a8fffe187
--- /dev/null
+++ b/arch/arm/mach-iop33x/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile for the linux kernel.
3#
4
5obj-y := common.o setup.o irq.o pci.o time.o
6obj-m :=
7obj-n :=
8obj- :=
9
10obj-$(CONFIG_ARCH_IQ80331) += iq80331-mm.o iq80331-pci.o
11obj-$(CONFIG_MACH_IQ80332) += iq80332-mm.o iq80332-pci.o
diff --git a/arch/arm/mach-iop33x/Makefile.boot b/arch/arm/mach-iop33x/Makefile.boot
new file mode 100644
index 000000000000..67039c3e0c48
--- /dev/null
+++ b/arch/arm/mach-iop33x/Makefile.boot
@@ -0,0 +1,3 @@
1 zreladdr-y := 0x00008000
2params_phys-y := 0x00000100
3initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-iop33x/common.c b/arch/arm/mach-iop33x/common.c
new file mode 100644
index 000000000000..dd75f2b8e74f
--- /dev/null
+++ b/arch/arm/mach-iop33x/common.c
@@ -0,0 +1,22 @@
1/*
2 * arch/arm/mach-iop33x/common.c
3 *
4 * Common routines shared across all IOP3xx implementations
5 *
6 * Author: Deepak Saxena <dsaxena@mvista.com>
7 *
8 * Copyright 2003 (c) MontaVista, Software, Inc.
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 */
14
15#include <linux/delay.h>
16#include <asm/hardware.h>
17
18/*
19 * Shared variables
20 */
21unsigned long iop3xx_pcibios_min_io = 0;
22unsigned long iop3xx_pcibios_min_mem = 0;
diff --git a/arch/arm/mach-iop33x/iq80331-mm.c b/arch/arm/mach-iop33x/iq80331-mm.c
new file mode 100644
index 000000000000..eb59445a0fca
--- /dev/null
+++ b/arch/arm/mach-iop33x/iq80331-mm.c
@@ -0,0 +1,35 @@
1/*
2 * linux/arch/arm/mach-iop33x/iq80331-mm.c
3 *
4 * Low level memory initialization for iq80331 platform
5 *
6 * Author: Dave Jiang <dave.jiang@intel.com>
7 * Copyright (C) 2003 Intel Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15
16#include <linux/mm.h>
17#include <linux/init.h>
18
19#include <asm/io.h>
20#include <asm/pgtable.h>
21#include <asm/page.h>
22
23#include <asm/mach/map.h>
24
25
26/*
27 * IQ80331 specific IO mappings
28 *
29 * We use RedBoot's setup for the onboard devices.
30 */
31
32void __init iq80331_map_io(void)
33{
34 iop331_map_io();
35}
diff --git a/arch/arm/mach-iop33x/iq80331-pci.c b/arch/arm/mach-iop33x/iq80331-pci.c
new file mode 100644
index 000000000000..71adb12a9421
--- /dev/null
+++ b/arch/arm/mach-iop33x/iq80331-pci.c
@@ -0,0 +1,119 @@
1/*
2 * arch/arm/mach-iop33x/iq80331-pci.c
3 *
4 * PCI support for the Intel IQ80331 reference board
5 *
6 * Author: Dave Jiang <dave.jiang@intel.com>
7 * Copyright (C) 2003, 2004 Intel Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/kernel.h>
14#include <linux/pci.h>
15#include <linux/init.h>
16#include <linux/string.h>
17#include <linux/slab.h>
18
19#include <asm/hardware.h>
20#include <asm/irq.h>
21#include <asm/mach/pci.h>
22#include <asm/mach-types.h>
23
24/*
25 * The following macro is used to lookup irqs in a standard table
26 * format for those systems that do not already have PCI
27 * interrupts properly routed. We assume 1 <= pin <= 4
28 */
29#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
30({ int _ctl_ = -1; \
31 unsigned int _idsel = idsel - minid; \
32 if (_idsel <= maxid) \
33 _ctl_ = pci_irq_table[_idsel][pin-1]; \
34 _ctl_; })
35
36#define INTA IRQ_IQ80331_INTA
37#define INTB IRQ_IQ80331_INTB
38#define INTC IRQ_IQ80331_INTC
39#define INTD IRQ_IQ80331_INTD
40
41//#define INTE IRQ_IQ80331_I82544
42
43static inline int __init
44iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
45{
46 static int pci_irq_table[][4] = {
47 /*
48 * PCI IDSEL/INTPIN->INTLINE
49 * A B C D
50 */
51 {INTB, INTC, INTD, INTA}, /* PCI-X Slot */
52 {INTC, INTC, INTC, INTC}, /* GigE */
53 };
54
55 BUG_ON(pin < 1 || pin > 4);
56
57 return PCI_IRQ_TABLE_LOOKUP(1, 7);
58}
59
60static int iq80331_setup(int nr, struct pci_sys_data *sys)
61{
62 struct resource *res;
63
64 if(nr != 0)
65 return 0;
66
67 res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
68 if (!res)
69 panic("PCI: unable to alloc resources");
70
71 res[0].start = IOP331_PCI_LOWER_IO_VA;
72 res[0].end = IOP331_PCI_UPPER_IO_VA;
73 res[0].name = "IQ80331 PCI I/O Space";
74 res[0].flags = IORESOURCE_IO;
75
76 res[1].start = IOP331_PCI_LOWER_MEM_PA;
77 res[1].end = IOP331_PCI_UPPER_MEM_PA;
78 res[1].name = "IQ80331 PCI Memory Space";
79 res[1].flags = IORESOURCE_MEM;
80
81 request_resource(&ioport_resource, &res[0]);
82 request_resource(&iomem_resource, &res[1]);
83
84 sys->mem_offset = IOP331_PCI_MEM_OFFSET;
85 sys->io_offset = IOP331_PCI_IO_OFFSET;
86
87 sys->resource[0] = &res[0];
88 sys->resource[1] = &res[1];
89 sys->resource[2] = NULL;
90
91 return 1;
92}
93
94static void iq80331_preinit(void)
95{
96 iop331_init();
97}
98
99static struct hw_pci iq80331_pci __initdata = {
100 .swizzle = pci_std_swizzle,
101 .nr_controllers = 1,
102 .setup = iq80331_setup,
103 .scan = iop331_scan_bus,
104 .preinit = iq80331_preinit,
105 .map_irq = iq80331_map_irq
106};
107
108static int __init iq80331_pci_init(void)
109{
110 if (machine_is_iq80331())
111 pci_common_init(&iq80331_pci);
112 return 0;
113}
114
115subsys_initcall(iq80331_pci_init);
116
117
118
119
diff --git a/arch/arm/mach-iop33x/iq80332-mm.c b/arch/arm/mach-iop33x/iq80332-mm.c
new file mode 100644
index 000000000000..f7bc73113ea8
--- /dev/null
+++ b/arch/arm/mach-iop33x/iq80332-mm.c
@@ -0,0 +1,35 @@
1/*
2 * linux/arch/arm/mach-iop33x/iq80332-mm.c
3 *
4 * Low level memory initialization for iq80332 platform
5 *
6 * Author: Dave Jiang <dave.jiang@intel.com>
7 * Copyright (C) 2004 Intel Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15
16#include <linux/mm.h>
17#include <linux/init.h>
18
19#include <asm/io.h>
20#include <asm/pgtable.h>
21#include <asm/page.h>
22
23#include <asm/mach/map.h>
24
25
26/*
27 * IQ80332 specific IO mappings
28 *
29 * We use RedBoot's setup for the onboard devices.
30 */
31
32void __init iq80332_map_io(void)
33{
34 iop331_map_io();
35}
diff --git a/arch/arm/mach-iop33x/iq80332-pci.c b/arch/arm/mach-iop33x/iq80332-pci.c
new file mode 100644
index 000000000000..f3010f85b1a2
--- /dev/null
+++ b/arch/arm/mach-iop33x/iq80332-pci.c
@@ -0,0 +1,125 @@
1/*
2 * arch/arm/mach-iop33x/iq80332-pci.c
3 *
4 * PCI support for the Intel IQ80332 reference board
5 *
6 * Author: Dave Jiang <dave.jiang@intel.com>
7 * Copyright (C) 2004 Intel Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/kernel.h>
14#include <linux/pci.h>
15#include <linux/init.h>
16#include <linux/string.h>
17#include <linux/slab.h>
18
19#include <asm/hardware.h>
20#include <asm/irq.h>
21#include <asm/mach/pci.h>
22#include <asm/mach-types.h>
23
24/*
25 * The following macro is used to lookup irqs in a standard table
26 * format for those systems that do not already have PCI
27 * interrupts properly routed. We assume 1 <= pin <= 4
28 */
29#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
30({ int _ctl_ = -1; \
31 unsigned int _idsel = idsel - minid; \
32 if (_idsel <= maxid) \
33 _ctl_ = pci_irq_table[_idsel][pin-1]; \
34 _ctl_; })
35
36#define INTA IRQ_IQ80332_INTA
37#define INTB IRQ_IQ80332_INTB
38#define INTC IRQ_IQ80332_INTC
39#define INTD IRQ_IQ80332_INTD
40
41//#define INTE IRQ_IQ80332_I82544
42
43static inline int __init
44iq80332_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
45{
46 static int pci_irq_table[][8] = {
47 /*
48 * PCI IDSEL/INTPIN->INTLINE
49 * A B C D
50 */
51 {-1, -1, -1, -1},
52 {-1, -1, -1, -1},
53 {-1, -1, -1, -1},
54 {INTA, INTB, INTC, INTD}, /* PCI-X Slot */
55 {-1, -1, -1, -1},
56 {INTC, INTC, INTC, INTC}, /* GigE */
57 {-1, -1, -1, -1},
58 {-1, -1, -1, -1},
59 };
60
61 BUG_ON(pin < 1 || pin > 4);
62
63 return PCI_IRQ_TABLE_LOOKUP(1, 7);
64}
65
66static int iq80332_setup(int nr, struct pci_sys_data *sys)
67{
68 struct resource *res;
69
70 if(nr != 0)
71 return 0;
72
73 res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
74 if (!res)
75 panic("PCI: unable to alloc resources");
76
77 res[0].start = IOP331_PCI_LOWER_IO_VA;
78 res[0].end = IOP331_PCI_UPPER_IO_VA;
79 res[0].name = "IQ80332 PCI I/O Space";
80 res[0].flags = IORESOURCE_IO;
81
82 res[1].start = IOP331_PCI_LOWER_MEM_PA;
83 res[1].end = IOP331_PCI_UPPER_MEM_PA;
84 res[1].name = "IQ80332 PCI Memory Space";
85 res[1].flags = IORESOURCE_MEM;
86
87 request_resource(&ioport_resource, &res[0]);
88 request_resource(&iomem_resource, &res[1]);
89
90 sys->mem_offset = IOP331_PCI_MEM_OFFSET;
91 sys->io_offset = IOP331_PCI_IO_OFFSET;
92
93 sys->resource[0] = &res[0];
94 sys->resource[1] = &res[1];
95 sys->resource[2] = NULL;
96
97 return 1;
98}
99
100static void iq80332_preinit(void)
101{
102 iop331_init();
103}
104
105static struct hw_pci iq80332_pci __initdata = {
106 .swizzle = pci_std_swizzle,
107 .nr_controllers = 1,
108 .setup = iq80332_setup,
109 .scan = iop331_scan_bus,
110 .preinit = iq80332_preinit,
111 .map_irq = iq80332_map_irq
112};
113
114static int __init iq80332_pci_init(void)
115{
116 if (machine_is_iq80332())
117 pci_common_init(&iq80332_pci);
118 return 0;
119}
120
121subsys_initcall(iq80332_pci_init);
122
123
124
125
diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c
new file mode 100644
index 000000000000..029fa78876a5
--- /dev/null
+++ b/arch/arm/mach-iop33x/irq.c
@@ -0,0 +1,129 @@
1/*
2 * linux/arch/arm/mach-iop33x/irq.c
3 *
4 * Generic IOP331 IRQ handling functionality
5 *
6 * Author: Dave Jiang <dave.jiang@intel.com>
7 * Copyright (C) 2003 Intel Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 *
14 */
15#include <linux/init.h>
16#include <linux/interrupt.h>
17#include <linux/list.h>
18
19#include <asm/mach/irq.h>
20#include <asm/irq.h>
21#include <asm/hardware.h>
22
23#include <asm/mach-types.h>
24
25static u32 iop331_mask0 = 0;
26static u32 iop331_mask1 = 0;
27
28static inline void intctl_write0(u32 val)
29{
30 // INTCTL0
31 asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
32}
33
34static inline void intctl_write1(u32 val)
35{
36 // INTCTL1
37 asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val));
38}
39
40static inline void intstr_write0(u32 val)
41{
42 // INTSTR0
43 asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val));
44}
45
46static inline void intstr_write1(u32 val)
47{
48 // INTSTR1
49 asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val));
50}
51
52static void
53iop331_irq_mask1 (unsigned int irq)
54{
55 iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS));
56 intctl_write0(iop331_mask0);
57}
58
59static void
60iop331_irq_mask2 (unsigned int irq)
61{
62 iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32));
63 intctl_write1(iop331_mask1);
64}
65
66static void
67iop331_irq_unmask1(unsigned int irq)
68{
69 iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS));
70 intctl_write0(iop331_mask0);
71}
72
73static void
74iop331_irq_unmask2(unsigned int irq)
75{
76 iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32));
77 intctl_write1(iop331_mask1);
78}
79
80struct irq_chip iop331_irqchip1 = {
81 .name = "IOP-1",
82 .ack = iop331_irq_mask1,
83 .mask = iop331_irq_mask1,
84 .unmask = iop331_irq_unmask1,
85};
86
87struct irq_chip iop331_irqchip2 = {
88 .name = "IOP-2",
89 .ack = iop331_irq_mask2,
90 .mask = iop331_irq_mask2,
91 .unmask = iop331_irq_unmask2,
92};
93
94void __init iop331_init_irq(void)
95{
96 unsigned int i, tmp;
97
98 /* Enable access to coprocessor 6 for dealing with IRQs.
99 * From RMK:
100 * Basically, the Intel documentation here is poor. It appears that
101 * you need to set the bit to be able to access the coprocessor from
102 * SVC mode. Whether that allows access from user space or not is
103 * unclear.
104 */
105 asm volatile (
106 "mrc p15, 0, %0, c15, c1, 0\n\t"
107 "orr %0, %0, %1\n\t"
108 "mcr p15, 0, %0, c15, c1, 0\n\t"
109 /* The action is delayed, so we have to do this: */
110 "mrc p15, 0, %0, c15, c1, 0\n\t"
111 "mov %0, %0\n\t"
112 "sub pc, pc, #4"
113 : "=r" (tmp) : "i" (1 << 6) );
114
115 intctl_write0(0); // disable all interrupts
116 intctl_write1(0);
117 intstr_write0(0); // treat all as IRQ
118 intstr_write1(0);
119 if(machine_is_iq80331()) // all interrupts are inputs to chip
120 *IOP331_PCIIRSR = 0x0f;
121
122 for(i = IOP331_IRQ_OFS; i < NR_IRQS; i++)
123 {
124 set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2);
125 set_irq_handler(i, do_level_IRQ);
126 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
127 }
128}
129
diff --git a/arch/arm/mach-iop33x/pci.c b/arch/arm/mach-iop33x/pci.c
new file mode 100644
index 000000000000..bf6aba91b47d
--- /dev/null
+++ b/arch/arm/mach-iop33x/pci.c
@@ -0,0 +1,222 @@
1/*
2 * arch/arm/mach-iop33x/pci.c
3 *
4 * PCI support for the Intel IOP331 chipset
5 *
6 * Author: Dave Jiang (dave.jiang@intel.com)
7 * Copyright (C) 2003, 2004 Intel Corp.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14#include <linux/kernel.h>
15#include <linux/pci.h>
16#include <linux/slab.h>
17#include <linux/mm.h>
18#include <linux/init.h>
19#include <linux/ioport.h>
20
21#include <asm/io.h>
22#include <asm/irq.h>
23#include <asm/system.h>
24#include <asm/hardware.h>
25#include <asm/mach/pci.h>
26
27#include <asm/arch/iop331.h>
28
29#undef DEBUG
30#undef DEBUG1
31
32#ifdef DEBUG
33#define DBG(x...) printk(x)
34#else
35#define DBG(x...) do { } while (0)
36#endif
37
38#ifdef DEBUG1
39#define DBG1(x...) printk(x)
40#else
41#define DBG1(x...) do { } while (0)
42#endif
43
44/*
45 * This routine builds either a type0 or type1 configuration command. If the
46 * bus is on the 80331 then a type0 made, else a type1 is created.
47 */
48static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where)
49{
50 struct pci_sys_data *sys = bus->sysdata;
51 u32 addr;
52
53 if (sys->busnr == bus->number)
54 addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
55 else
56 addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
57
58 addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
59
60 return addr;
61}
62
63/*
64 * This routine checks the status of the last configuration cycle. If an error
65 * was detected it returns a 1, else it returns a 0. The errors being checked
66 * are parity, master abort, target abort (master and target). These types of
67 * errors occure during a config cycle where there is no device, like during
68 * the discovery stage.
69 */
70static int iop331_pci_status(void)
71{
72 unsigned int status;
73 int ret = 0;
74
75 /*
76 * Check the status registers.
77 */
78 status = *IOP331_ATUSR;
79 if (status & 0xf900)
80 {
81 DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
82 *IOP331_ATUSR = status & 0xf900;
83 ret = 1;
84 }
85 status = *IOP331_ATUISR;
86 if (status & 0x679f)
87 {
88 DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
89 *IOP331_ATUISR = status & 0x679f;
90 ret = 1;
91 }
92 return ret;
93}
94
95/*
96 * Simply write the address register and read the configuration
97 * data. Note that the 4 nop's ensure that we are able to handle
98 * a delayed abort (in theory.)
99 */
100static inline u32 iop331_read(unsigned long addr)
101{
102 u32 val;
103
104 __asm__ __volatile__(
105 "str %1, [%2]\n\t"
106 "ldr %0, [%3]\n\t"
107 "nop\n\t"
108 "nop\n\t"
109 "nop\n\t"
110 "nop\n\t"
111 : "=r" (val)
112 : "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
113
114 return val;
115}
116
117/*
118 * The read routines must check the error status of the last configuration
119 * cycle. If there was an error, the routine returns all hex f's.
120 */
121static int
122iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where,
123 int size, u32 *value)
124{
125 unsigned long addr = iop331_cfg_address(bus, devfn, where);
126 u32 val = iop331_read(addr) >> ((where & 3) * 8);
127
128 if( iop331_pci_status() )
129 val = 0xffffffff;
130
131 *value = val;
132
133 return PCIBIOS_SUCCESSFUL;
134}
135
136static int
137iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where,
138 int size, u32 value)
139{
140 unsigned long addr = iop331_cfg_address(bus, devfn, where);
141 u32 val;
142
143 if (size != 4) {
144 val = iop331_read(addr);
145 if (!iop331_pci_status() == 0)
146 return PCIBIOS_SUCCESSFUL;
147
148 where = (where & 3) * 8;
149
150 if (size == 1)
151 val &= ~(0xff << where);
152 else
153 val &= ~(0xffff << where);
154
155 *IOP331_OCCDR = val | value << where;
156 } else {
157 asm volatile(
158 "str %1, [%2]\n\t"
159 "str %0, [%3]\n\t"
160 "nop\n\t"
161 "nop\n\t"
162 "nop\n\t"
163 "nop\n\t"
164 :
165 : "r" (value), "r" (addr),
166 "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
167 }
168
169 return PCIBIOS_SUCCESSFUL;
170}
171
172static struct pci_ops iop331_ops = {
173 .read = iop331_read_config,
174 .write = iop331_write_config,
175};
176
177/*
178 * When a PCI device does not exist during config cycles, the XScale gets a
179 * bus error instead of returning 0xffffffff. This handler simply returns.
180 */
181int
182iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
183{
184 DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
185 addr, fsr, regs->ARM_pc, regs->ARM_lr);
186
187 /*
188 * If it was an imprecise abort, then we need to correct the
189 * return address to be _after_ the instruction.
190 */
191 if (fsr & (1 << 10))
192 regs->ARM_pc += 4;
193
194 return 0;
195}
196
197/*
198 * Scan an IOP331 PCI bus. sys->bus defines which bus we scan.
199 */
200struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys)
201{
202 return pci_scan_bus(sys->busnr, &iop331_ops, sys);
203}
204
205void iop331_init(void)
206{
207 DBG1("PCI: Intel 80331 PCI init code.\n");
208 DBG1("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD);
209 DBG1("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n",
210 *IOP331_OMWTVR0,
211 *IOP331_OIOWTVR);
212 DBG1("\tATU: IOP331_OMWTVR1=0x%04x\n", *IOP331_OMWTVR1);
213 DBG1("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR);
214 DBG1("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0);
215 DBG1("\tATU: IOP31_IABAR1=0x%08x IOP331_IALR1=0x%08x\n", *IOP331_IABAR1, *IOP331_IALR1);
216 DBG1("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR);
217 DBG1("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2);
218 DBG1("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3);
219
220 hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort");
221}
222
diff --git a/arch/arm/mach-iop33x/setup.c b/arch/arm/mach-iop33x/setup.c
new file mode 100644
index 000000000000..c14c7da5ec4c
--- /dev/null
+++ b/arch/arm/mach-iop33x/setup.c
@@ -0,0 +1,221 @@
1/*
2 * linux/arch/arm/mach-iop33x/setup.c
3 *
4 * Author: Dave Jiang (dave.jiang@intel.com)
5 * Copyright (C) 2004 Intel Corporation.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/mm.h>
13#include <linux/init.h>
14#include <linux/major.h>
15#include <linux/fs.h>
16#include <linux/platform_device.h>
17#include <linux/serial.h>
18#include <linux/tty.h>
19#include <linux/serial_8250.h>
20
21#include <asm/io.h>
22#include <asm/pgtable.h>
23#include <asm/page.h>
24#include <asm/mach/map.h>
25#include <asm/setup.h>
26#include <asm/system.h>
27#include <asm/memory.h>
28#include <asm/hardware.h>
29#include <asm/mach-types.h>
30#include <asm/mach/arch.h>
31
32#define IOP331_UART_XTAL 33334000
33
34/*
35 * Standard IO mapping for all IOP331 based systems
36 */
37static struct map_desc iop331_std_desc[] __initdata = {
38 { /* mem mapped registers */
39 .virtual = IOP331_VIRT_MEM_BASE,
40 .pfn = __phys_to_pfn(IOP331_PHYS_MEM_BASE),
41 .length = 0x00002000,
42 .type = MT_DEVICE
43 }, { /* PCI IO space */
44 .virtual = IOP331_PCI_LOWER_IO_VA,
45 .pfn = __phys_to_pfn(IOP331_PCI_LOWER_IO_PA),
46 .length = IOP331_PCI_IO_WINDOW_SIZE,
47 .type = MT_DEVICE
48 }
49};
50
51static struct resource iop33x_uart0_resources[] = {
52 [0] = {
53 .start = IOP331_UART0_PHYS,
54 .end = IOP331_UART0_PHYS + 0x3f,
55 .flags = IORESOURCE_MEM,
56 },
57 [1] = {
58 .start = IRQ_IOP331_UART0,
59 .end = IRQ_IOP331_UART0,
60 .flags = IORESOURCE_IRQ
61 }
62};
63
64static struct resource iop33x_uart1_resources[] = {
65 [0] = {
66 .start = IOP331_UART1_PHYS,
67 .end = IOP331_UART1_PHYS + 0x3f,
68 .flags = IORESOURCE_MEM,
69 },
70 [1] = {
71 .start = IRQ_IOP331_UART1,
72 .end = IRQ_IOP331_UART1,
73 .flags = IORESOURCE_IRQ
74 }
75};
76
77static struct plat_serial8250_port iop33x_uart0_data[] = {
78 {
79 .membase = (char*)(IOP331_UART0_VIRT),
80 .mapbase = (IOP331_UART0_PHYS),
81 .irq = IRQ_IOP331_UART0,
82 .uartclk = IOP331_UART_XTAL,
83 .regshift = 2,
84 .iotype = UPIO_MEM,
85 .flags = UPF_SKIP_TEST,
86 },
87 { },
88};
89
90static struct plat_serial8250_port iop33x_uart1_data[] = {
91 {
92 .membase = (char*)(IOP331_UART1_VIRT),
93 .mapbase = (IOP331_UART1_PHYS),
94 .irq = IRQ_IOP331_UART1,
95 .uartclk = IOP331_UART_XTAL,
96 .regshift = 2,
97 .iotype = UPIO_MEM,
98 .flags = UPF_SKIP_TEST,
99 },
100 { },
101};
102
103static struct platform_device iop33x_uart0 = {
104 .name = "serial8250",
105 .id = PLAT8250_DEV_PLATFORM,
106 .dev.platform_data = iop33x_uart0_data,
107 .num_resources = 2,
108 .resource = iop33x_uart0_resources,
109};
110
111static struct platform_device iop33x_uart1 = {
112 .name = "serial8250",
113 .id = PLAT8250_DEV_PLATFORM1,
114 .dev.platform_data = iop33x_uart1_data,
115 .num_resources = 2,
116 .resource = iop33x_uart1_resources,
117};
118
119static struct resource iop33x_i2c_0_resources[] = {
120 [0] = {
121 .start = 0xfffff680,
122 .end = 0xfffff698,
123 .flags = IORESOURCE_MEM,
124 },
125 [1] = {
126 .start = IRQ_IOP331_I2C_0,
127 .end = IRQ_IOP331_I2C_0,
128 .flags = IORESOURCE_IRQ
129 }
130};
131
132static struct resource iop33x_i2c_1_resources[] = {
133 [0] = {
134 .start = 0xfffff6a0,
135 .end = 0xfffff6b8,
136 .flags = IORESOURCE_MEM,
137 },
138 [1] = {
139 .start = IRQ_IOP331_I2C_1,
140 .end = IRQ_IOP331_I2C_1,
141 .flags = IORESOURCE_IRQ
142 }
143};
144
145static struct platform_device iop33x_i2c_0_controller = {
146 .name = "IOP3xx-I2C",
147 .id = 0,
148 .num_resources = 2,
149 .resource = iop33x_i2c_0_resources
150};
151
152static struct platform_device iop33x_i2c_1_controller = {
153 .name = "IOP3xx-I2C",
154 .id = 1,
155 .num_resources = 2,
156 .resource = iop33x_i2c_1_resources
157};
158
159static struct platform_device *iop33x_devices[] __initdata = {
160 &iop33x_uart0,
161 &iop33x_uart1,
162 &iop33x_i2c_0_controller,
163 &iop33x_i2c_1_controller
164};
165
166void __init iop33x_init(void)
167{
168 if(iop_is_331())
169 {
170 platform_add_devices(iop33x_devices,
171 ARRAY_SIZE(iop33x_devices));
172 }
173}
174
175void __init iop331_map_io(void)
176{
177 iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc));
178}
179
180#ifdef CONFIG_ARCH_IOP33X
181extern void iop331_init_irq(void);
182extern struct sys_timer iop331_timer;
183#endif
184
185#ifdef CONFIG_ARCH_IQ80331
186extern void iq80331_map_io(void);
187#endif
188
189#ifdef CONFIG_MACH_IQ80332
190extern void iq80332_map_io(void);
191#endif
192
193#if defined(CONFIG_ARCH_IQ80331)
194MACHINE_START(IQ80331, "Intel IQ80331")
195 /* Maintainer: Intel Corp. */
196 .phys_io = 0xfefff000,
197 .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
198 .map_io = iq80331_map_io,
199 .init_irq = iop331_init_irq,
200 .timer = &iop331_timer,
201 .boot_params = 0x0100,
202 .init_machine = iop33x_init,
203MACHINE_END
204
205#elif defined(CONFIG_MACH_IQ80332)
206MACHINE_START(IQ80332, "Intel IQ80332")
207 /* Maintainer: Intel Corp. */
208 .phys_io = 0xfefff000,
209 .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
210 .map_io = iq80332_map_io,
211 .init_irq = iop331_init_irq,
212 .timer = &iop331_timer,
213 .boot_params = 0x0100,
214 .init_machine = iop33x_init,
215MACHINE_END
216
217#else
218#error No machine descriptor defined for this IOP3XX implementation
219#endif
220
221
diff --git a/arch/arm/mach-iop33x/time.c b/arch/arm/mach-iop33x/time.c
new file mode 100644
index 000000000000..d839cd0d926e
--- /dev/null
+++ b/arch/arm/mach-iop33x/time.c
@@ -0,0 +1,106 @@
1/*
2 * arch/arm/mach-iop33x/time.c
3 *
4 * Timer code for IOP331 based systems
5 *
6 * Author: Dave Jiang <dave.jiang@intel.com>
7 *
8 * Copyright 2003 Intel Corp.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/kernel.h>
17#include <linux/interrupt.h>
18#include <linux/time.h>
19#include <linux/init.h>
20#include <linux/timex.h>
21
22#include <asm/hardware.h>
23#include <asm/io.h>
24#include <asm/irq.h>
25#include <asm/uaccess.h>
26#include <asm/mach/irq.h>
27#include <asm/mach/time.h>
28
29static inline unsigned long get_elapsed(void)
30{
31 return LATCH - *IOP331_TU_TCR0;
32}
33
34static unsigned long iop331_gettimeoffset(void)
35{
36 unsigned long elapsed, usec;
37 u32 tisr1, tisr2;
38
39 /*
40 * If an interrupt was pending before we read the timer,
41 * we've already wrapped. Factor this into the time.
42 * If an interrupt was pending after we read the timer,
43 * it may have wrapped between checking the interrupt
44 * status and reading the timer. Re-read the timer to
45 * be sure its value is after the wrap.
46 */
47
48 asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
49 elapsed = get_elapsed();
50 asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
51
52 if(tisr1 & 1)
53 elapsed += LATCH;
54 else if (tisr2 & 1)
55 elapsed = LATCH + get_elapsed();
56
57 /*
58 * Now convert them to usec.
59 */
60 usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
61
62 return usec;
63}
64
65static irqreturn_t
66iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
67{
68 u32 tisr;
69
70 write_seqlock(&xtime_lock);
71
72 asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
73 tisr |= 1;
74 asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
75
76 timer_tick(regs);
77
78 write_sequnlock(&xtime_lock);
79 return IRQ_HANDLED;
80}
81
82static struct irqaction iop331_timer_irq = {
83 .name = "IOP331 Timer Tick",
84 .handler = iop331_timer_interrupt,
85 .flags = IRQF_DISABLED | IRQF_TIMER,
86};
87
88static void __init iop331_timer_init(void)
89{
90 u32 timer_ctl;
91
92 setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq);
93
94 timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD |
95 IOP331_TMR_RATIO_1_1;
96
97 asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH));
98
99 asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
100
101}
102
103struct sys_timer iop331_timer = {
104 .init = iop331_timer_init,
105 .offset = iop331_gettimeoffset,
106};