diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh/boards |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/sh/boards')
121 files changed, 11783 insertions, 0 deletions
diff --git a/arch/sh/boards/adx/Makefile b/arch/sh/boards/adx/Makefile new file mode 100644 index 000000000000..5b1c531b3991 --- /dev/null +++ b/arch/sh/boards/adx/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for ADX boards | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o irq.o irq_maskreq.o | ||
6 | |||
diff --git a/arch/sh/boards/adx/irq.c b/arch/sh/boards/adx/irq.c new file mode 100644 index 000000000000..c6ca409dff98 --- /dev/null +++ b/arch/sh/boards/adx/irq.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/adx/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2001 A&D Co., Ltd. | ||
5 | * | ||
6 | * I/O routine and setup routines for A&D ADX Board | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <asm/irq.h> | ||
15 | |||
16 | void init_adx_IRQ(void) | ||
17 | { | ||
18 | int i; | ||
19 | |||
20 | /* printk("init_adx_IRQ()\n");*/ | ||
21 | /* setup irq_mask_register */ | ||
22 | irq_mask_register = (unsigned short *)0xa6000008; | ||
23 | |||
24 | /* cover all external interrupt area by maskreg_irq_type | ||
25 | * (Actually, irq15 doesn't exist) | ||
26 | */ | ||
27 | for (i = 0; i < 16; i++) { | ||
28 | make_maskreg_irq(i); | ||
29 | disable_irq(i); | ||
30 | } | ||
31 | } | ||
diff --git a/arch/sh/boards/adx/irq_maskreg.c b/arch/sh/boards/adx/irq_maskreg.c new file mode 100644 index 000000000000..ca91bb0f1f5c --- /dev/null +++ b/arch/sh/boards/adx/irq_maskreg.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/irq_maskreg.c | ||
3 | * | ||
4 | * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp> | ||
5 | * | ||
6 | * This file may be copied or modified under the terms of the GNU | ||
7 | * General Public License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Interrupt handling for Simple external interrupt mask register | ||
10 | * | ||
11 | * This is for the machine which have single 16 bit register | ||
12 | * for masking external IRQ individually. | ||
13 | * Each bit of the register is for masking each interrupt. | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/irq.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/machvec.h> | ||
24 | |||
25 | /* address of external interrupt mask register | ||
26 | * address must be set prior to use these (maybe in init_XXX_irq()) | ||
27 | * XXX : is it better to use .config than specifying it in code? */ | ||
28 | unsigned short *irq_mask_register = 0; | ||
29 | |||
30 | /* forward declaration */ | ||
31 | static unsigned int startup_maskreg_irq(unsigned int irq); | ||
32 | static void shutdown_maskreg_irq(unsigned int irq); | ||
33 | static void enable_maskreg_irq(unsigned int irq); | ||
34 | static void disable_maskreg_irq(unsigned int irq); | ||
35 | static void mask_and_ack_maskreg(unsigned int); | ||
36 | static void end_maskreg_irq(unsigned int irq); | ||
37 | |||
38 | /* hw_interrupt_type */ | ||
39 | static struct hw_interrupt_type maskreg_irq_type = { | ||
40 | " Mask Register", | ||
41 | startup_maskreg_irq, | ||
42 | shutdown_maskreg_irq, | ||
43 | enable_maskreg_irq, | ||
44 | disable_maskreg_irq, | ||
45 | mask_and_ack_maskreg, | ||
46 | end_maskreg_irq | ||
47 | }; | ||
48 | |||
49 | /* actual implementatin */ | ||
50 | static unsigned int startup_maskreg_irq(unsigned int irq) | ||
51 | { | ||
52 | enable_maskreg_irq(irq); | ||
53 | return 0; /* never anything pending */ | ||
54 | } | ||
55 | |||
56 | static void shutdown_maskreg_irq(unsigned int irq) | ||
57 | { | ||
58 | disable_maskreg_irq(irq); | ||
59 | } | ||
60 | |||
61 | static void disable_maskreg_irq(unsigned int irq) | ||
62 | { | ||
63 | if (irq_mask_register) { | ||
64 | unsigned long flags; | ||
65 | unsigned short val, mask = 0x01 << irq; | ||
66 | |||
67 | /* Set "irq"th bit */ | ||
68 | local_irq_save(flags); | ||
69 | val = ctrl_inw((unsigned long)irq_mask_register); | ||
70 | val |= mask; | ||
71 | ctrl_outw(val, (unsigned long)irq_mask_register); | ||
72 | local_irq_restore(flags); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void enable_maskreg_irq(unsigned int irq) | ||
77 | { | ||
78 | if (irq_mask_register) { | ||
79 | unsigned long flags; | ||
80 | unsigned short val, mask = ~(0x01 << irq); | ||
81 | |||
82 | /* Clear "irq"th bit */ | ||
83 | local_irq_save(flags); | ||
84 | val = ctrl_inw((unsigned long)irq_mask_register); | ||
85 | val &= mask; | ||
86 | ctrl_outw(val, (unsigned long)irq_mask_register); | ||
87 | local_irq_restore(flags); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void mask_and_ack_maskreg(unsigned int irq) | ||
92 | { | ||
93 | disable_maskreg_irq(irq); | ||
94 | } | ||
95 | |||
96 | static void end_maskreg_irq(unsigned int irq) | ||
97 | { | ||
98 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
99 | enable_maskreg_irq(irq); | ||
100 | } | ||
101 | |||
102 | void make_maskreg_irq(unsigned int irq) | ||
103 | { | ||
104 | disable_irq_nosync(irq); | ||
105 | irq_desc[irq].handler = &maskreg_irq_type; | ||
106 | disable_maskreg_irq(irq); | ||
107 | } | ||
diff --git a/arch/sh/boards/adx/setup.c b/arch/sh/boards/adx/setup.c new file mode 100644 index 000000000000..4938d9592343 --- /dev/null +++ b/arch/sh/boards/adx/setup.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/board/adx/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2001 A&D Co., Ltd. | ||
5 | * | ||
6 | * I/O routine and setup routines for A&D ADX Board | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | extern void init_adx_IRQ(void); | ||
18 | extern void *cf_io_base; | ||
19 | |||
20 | const char *get_system_type(void) | ||
21 | { | ||
22 | return "A&D ADX"; | ||
23 | } | ||
24 | |||
25 | unsigned long adx_isa_port2addr(unsigned long offset) | ||
26 | { | ||
27 | /* CompactFlash (IDE) */ | ||
28 | if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset == 0x3f6)) { | ||
29 | return (unsigned long)cf_io_base + offset; | ||
30 | } | ||
31 | |||
32 | /* eth0 */ | ||
33 | if ((offset >= 0x300) && (offset <= 0x30f)) { | ||
34 | return 0xa5000000 + offset; /* COMM BOARD (AREA1) */ | ||
35 | } | ||
36 | |||
37 | return offset + 0xb0000000; /* IOBUS (AREA 4)*/ | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * The Machine Vector | ||
42 | */ | ||
43 | |||
44 | struct sh_machine_vector mv_adx __initmv = { | ||
45 | .mv_nr_irqs = 48, | ||
46 | .mv_isa_port2addr = adx_isa_port2addr, | ||
47 | .mv_init_irq = init_adx_IRQ, | ||
48 | }; | ||
49 | ALIAS_MV(adx) | ||
50 | |||
51 | int __init platform_setup(void) | ||
52 | { | ||
53 | /* Nothing to see here .. */ | ||
54 | return 0; | ||
55 | } | ||
56 | |||
diff --git a/arch/sh/boards/bigsur/Makefile b/arch/sh/boards/bigsur/Makefile new file mode 100644 index 000000000000..0ff9497ac58e --- /dev/null +++ b/arch/sh/boards/bigsur/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the BigSur specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o io.o irq.o led.o | ||
6 | |||
diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c new file mode 100644 index 000000000000..697144de7419 --- /dev/null +++ b/arch/sh/boards/bigsur/io.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * include/asm-sh/io_bigsur.c | ||
3 | * | ||
4 | * By Dustin McIntire (dustin@sensoria.com) (c)2001 | ||
5 | * Derived from io_hd64465.h, which bore the message: | ||
6 | * By Greg Banks <gbanks@pocketpenguins.com> | ||
7 | * (c) 2000 PocketPenguins Inc. | ||
8 | * and from io_hd64461.h, which bore the message: | ||
9 | * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) | ||
10 | * | ||
11 | * May be copied or modified under the terms of the GNU General Public | ||
12 | * License. See linux/COPYING for more information. | ||
13 | * | ||
14 | * IO functions for a Hitachi Big Sur Evaluation Board. | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <asm/machvec.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/bigsur/bigsur.h> | ||
23 | |||
24 | /* Low iomap maps port 0-1K to addresses in 8byte chunks */ | ||
25 | #define BIGSUR_IOMAP_LO_THRESH 0x400 | ||
26 | #define BIGSUR_IOMAP_LO_SHIFT 3 | ||
27 | #define BIGSUR_IOMAP_LO_MASK ((1<<BIGSUR_IOMAP_LO_SHIFT)-1) | ||
28 | #define BIGSUR_IOMAP_LO_NMAP (BIGSUR_IOMAP_LO_THRESH>>BIGSUR_IOMAP_LO_SHIFT) | ||
29 | static u32 bigsur_iomap_lo[BIGSUR_IOMAP_LO_NMAP]; | ||
30 | static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP]; | ||
31 | |||
32 | /* High iomap maps port 1K-64K to addresses in 1K chunks */ | ||
33 | #define BIGSUR_IOMAP_HI_THRESH 0x10000 | ||
34 | #define BIGSUR_IOMAP_HI_SHIFT 10 | ||
35 | #define BIGSUR_IOMAP_HI_MASK ((1<<BIGSUR_IOMAP_HI_SHIFT)-1) | ||
36 | #define BIGSUR_IOMAP_HI_NMAP (BIGSUR_IOMAP_HI_THRESH>>BIGSUR_IOMAP_HI_SHIFT) | ||
37 | static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP]; | ||
38 | static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP]; | ||
39 | |||
40 | #ifndef MAX | ||
41 | #define MAX(a,b) ((a)>(b)?(a):(b)) | ||
42 | #endif | ||
43 | |||
44 | void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift) | ||
45 | { | ||
46 | u32 port, endport = baseport + nports; | ||
47 | |||
48 | pr_debug("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n", | ||
49 | baseport, nports, addr); | ||
50 | |||
51 | for (port = baseport ; | ||
52 | port < endport && port < BIGSUR_IOMAP_LO_THRESH ; | ||
53 | port += (1<<BIGSUR_IOMAP_LO_SHIFT)) { | ||
54 | pr_debug(" maplo[0x%x] = 0x%08x\n", port, addr); | ||
55 | bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = addr; | ||
56 | bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift; | ||
57 | addr += (1<<(BIGSUR_IOMAP_LO_SHIFT)); | ||
58 | } | ||
59 | |||
60 | for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ; | ||
61 | port < endport && port < BIGSUR_IOMAP_HI_THRESH ; | ||
62 | port += (1<<BIGSUR_IOMAP_HI_SHIFT)) { | ||
63 | pr_debug(" maphi[0x%x] = 0x%08x\n", port, addr); | ||
64 | bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = addr; | ||
65 | bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift; | ||
66 | addr += (1<<(BIGSUR_IOMAP_HI_SHIFT)); | ||
67 | } | ||
68 | } | ||
69 | EXPORT_SYMBOL(bigsur_port_map); | ||
70 | |||
71 | void bigsur_port_unmap(u32 baseport, u32 nports) | ||
72 | { | ||
73 | u32 port, endport = baseport + nports; | ||
74 | |||
75 | pr_debug("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports); | ||
76 | |||
77 | for (port = baseport ; | ||
78 | port < endport && port < BIGSUR_IOMAP_LO_THRESH ; | ||
79 | port += (1<<BIGSUR_IOMAP_LO_SHIFT)) { | ||
80 | bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0; | ||
81 | } | ||
82 | |||
83 | for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ; | ||
84 | port < endport && port < BIGSUR_IOMAP_HI_THRESH ; | ||
85 | port += (1<<BIGSUR_IOMAP_HI_SHIFT)) { | ||
86 | bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0; | ||
87 | } | ||
88 | } | ||
89 | EXPORT_SYMBOL(bigsur_port_unmap); | ||
90 | |||
91 | unsigned long bigsur_isa_port2addr(unsigned long port) | ||
92 | { | ||
93 | unsigned long addr = 0; | ||
94 | unsigned char shift; | ||
95 | |||
96 | /* Physical address not in P0, do nothing */ | ||
97 | if (PXSEG(port)) { | ||
98 | addr = port; | ||
99 | /* physical address in P0, map to P2 */ | ||
100 | } else if (port >= 0x30000) { | ||
101 | addr = P2SEGADDR(port); | ||
102 | /* Big Sur I/O + HD64465 registers 0x10000-0x30000 */ | ||
103 | } else if (port >= BIGSUR_IOMAP_HI_THRESH) { | ||
104 | addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH); | ||
105 | /* Handle remapping of high IO/PCI IO ports */ | ||
106 | } else if (port >= BIGSUR_IOMAP_LO_THRESH) { | ||
107 | addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT]; | ||
108 | shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT]; | ||
109 | |||
110 | if (addr != 0) | ||
111 | addr += (port & BIGSUR_IOMAP_HI_MASK) << shift; | ||
112 | } else { | ||
113 | /* Handle remapping of low IO ports */ | ||
114 | addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT]; | ||
115 | shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT]; | ||
116 | |||
117 | if (addr != 0) | ||
118 | addr += (port & BIGSUR_IOMAP_LO_MASK) << shift; | ||
119 | } | ||
120 | |||
121 | pr_debug("%s(0x%08lx) = 0x%08lx\n", __FUNCTION__, port, addr); | ||
122 | |||
123 | return addr; | ||
124 | } | ||
125 | |||
diff --git a/arch/sh/boards/bigsur/irq.c b/arch/sh/boards/bigsur/irq.c new file mode 100644 index 000000000000..c188fc32dc9a --- /dev/null +++ b/arch/sh/boards/bigsur/irq.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * | ||
3 | * By Dustin McIntire (dustin@sensoria.com) (c)2001 | ||
4 | * | ||
5 | * Setup and IRQ handling code for the HD64465 companion chip. | ||
6 | * by Greg Banks <gbanks@pocketpenguins.com> | ||
7 | * Copyright (c) 2000 PocketPenguins Inc | ||
8 | * | ||
9 | * Derived from setup_hd64465.c which bore the message: | ||
10 | * Greg Banks <gbanks@pocketpenguins.com> | ||
11 | * Copyright (c) 2000 PocketPenguins Inc and | ||
12 | * Copyright (C) 2000 YAEGASHI Takeshi | ||
13 | * and setup_cqreek.c which bore message: | ||
14 | * Copyright (C) 2000 Niibe Yutaka | ||
15 | * | ||
16 | * May be copied or modified under the terms of the GNU General Public | ||
17 | * License. See linux/COPYING for more information. | ||
18 | * | ||
19 | * IRQ functions for a Hitachi Big Sur Evaluation Board. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/param.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/irq.h> | ||
32 | #include <linux/bitops.h> | ||
33 | |||
34 | #include <asm/io.h> | ||
35 | #include <asm/irq.h> | ||
36 | |||
37 | #include <asm/bigsur/io.h> | ||
38 | #include <asm/hd64465/hd64465.h> | ||
39 | #include <asm/bigsur/bigsur.h> | ||
40 | |||
41 | //#define BIGSUR_DEBUG 3 | ||
42 | #undef BIGSUR_DEBUG | ||
43 | |||
44 | #ifdef BIGSUR_DEBUG | ||
45 | #define DPRINTK(args...) printk(args) | ||
46 | #define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args) | ||
47 | #else | ||
48 | #define DPRINTK(args...) | ||
49 | #define DIPRINTK(n, args...) | ||
50 | #endif /* BIGSUR_DEBUG */ | ||
51 | |||
52 | #ifdef CONFIG_HD64465 | ||
53 | extern int hd64465_irq_demux(int irq); | ||
54 | #endif /* CONFIG_HD64465 */ | ||
55 | |||
56 | |||
57 | /*===========================================================*/ | ||
58 | // Big Sur CPLD IRQ Routines | ||
59 | /*===========================================================*/ | ||
60 | |||
61 | /* Level 1 IRQ routines */ | ||
62 | static void disable_bigsur_l1irq(unsigned int irq) | ||
63 | { | ||
64 | unsigned long flags; | ||
65 | unsigned char mask; | ||
66 | unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0; | ||
67 | unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) ); | ||
68 | |||
69 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { | ||
70 | DPRINTK("Disable L1 IRQ %d\n", irq); | ||
71 | DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", | ||
72 | mask_port, bit); | ||
73 | local_irq_save(flags); | ||
74 | |||
75 | /* Disable IRQ - set mask bit */ | ||
76 | mask = inb(mask_port) | bit; | ||
77 | outb(mask, mask_port); | ||
78 | local_irq_restore(flags); | ||
79 | return; | ||
80 | } | ||
81 | DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq); | ||
82 | } | ||
83 | |||
84 | static void enable_bigsur_l1irq(unsigned int irq) | ||
85 | { | ||
86 | unsigned long flags; | ||
87 | unsigned char mask; | ||
88 | unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0; | ||
89 | unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) ); | ||
90 | |||
91 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { | ||
92 | DPRINTK("Enable L1 IRQ %d\n", irq); | ||
93 | DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", | ||
94 | mask_port, bit); | ||
95 | local_irq_save(flags); | ||
96 | /* Enable L1 IRQ - clear mask bit */ | ||
97 | mask = inb(mask_port) & ~bit; | ||
98 | outb(mask, mask_port); | ||
99 | local_irq_restore(flags); | ||
100 | return; | ||
101 | } | ||
102 | DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq); | ||
103 | } | ||
104 | |||
105 | |||
106 | /* Level 2 irq masks and registers for L2 decoding */ | ||
107 | /* Level2 bitmasks for each level 1 IRQ */ | ||
108 | const u32 bigsur_l2irq_mask[] = | ||
109 | {0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03}; | ||
110 | /* Level2 to ISR[n] map for each level 1 IRQ */ | ||
111 | const u32 bigsur_l2irq_reg[] = | ||
112 | { 2, 2, 3, 3, 1, 2, 1, 0, 1, 1, 3, 2}; | ||
113 | /* Level2 to Level 1 IRQ map */ | ||
114 | const u32 bigsur_l2_l1_map[] = | ||
115 | {7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1}; | ||
116 | /* IRQ inactive level (high or low) */ | ||
117 | const u32 bigsur_l2_inactv_state[] = {0x00, 0xBE, 0xFC, 0xF7}; | ||
118 | |||
119 | /* CPLD external status and mask registers base and offsets */ | ||
120 | static const u32 isr_base = BIGSUR_IRQ0; | ||
121 | static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1; | ||
122 | static const u32 imr_base = BIGSUR_IMR0; | ||
123 | static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1; | ||
124 | |||
125 | #define REG_NUM(irq) ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 ) | ||
126 | |||
127 | /* Level 2 IRQ routines */ | ||
128 | static void disable_bigsur_l2irq(unsigned int irq) | ||
129 | { | ||
130 | unsigned long flags; | ||
131 | unsigned char mask; | ||
132 | unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8); | ||
133 | unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset; | ||
134 | |||
135 | if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) { | ||
136 | DPRINTK("Disable L2 IRQ %d\n", irq); | ||
137 | DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", | ||
138 | mask_port, bit); | ||
139 | local_irq_save(flags); | ||
140 | |||
141 | /* Disable L2 IRQ - set mask bit */ | ||
142 | mask = inb(mask_port) | bit; | ||
143 | outb(mask, mask_port); | ||
144 | local_irq_restore(flags); | ||
145 | return; | ||
146 | } | ||
147 | DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq); | ||
148 | } | ||
149 | |||
150 | static void enable_bigsur_l2irq(unsigned int irq) | ||
151 | { | ||
152 | unsigned long flags; | ||
153 | unsigned char mask; | ||
154 | unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8); | ||
155 | unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset; | ||
156 | |||
157 | if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) { | ||
158 | DPRINTK("Enable L2 IRQ %d\n", irq); | ||
159 | DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", | ||
160 | mask_port, bit); | ||
161 | local_irq_save(flags); | ||
162 | |||
163 | /* Enable L2 IRQ - clear mask bit */ | ||
164 | mask = inb(mask_port) & ~bit; | ||
165 | outb(mask, mask_port); | ||
166 | local_irq_restore(flags); | ||
167 | return; | ||
168 | } | ||
169 | DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq); | ||
170 | } | ||
171 | |||
172 | static void mask_and_ack_bigsur(unsigned int irq) | ||
173 | { | ||
174 | DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq); | ||
175 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) | ||
176 | disable_bigsur_l1irq(irq); | ||
177 | else | ||
178 | disable_bigsur_l2irq(irq); | ||
179 | } | ||
180 | |||
181 | static void end_bigsur_irq(unsigned int irq) | ||
182 | { | ||
183 | DPRINTK("end_bigsur_irq IRQ %d\n", irq); | ||
184 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { | ||
185 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) | ||
186 | enable_bigsur_l1irq(irq); | ||
187 | else | ||
188 | enable_bigsur_l2irq(irq); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static unsigned int startup_bigsur_irq(unsigned int irq) | ||
193 | { | ||
194 | u8 mask; | ||
195 | u32 reg; | ||
196 | |||
197 | DPRINTK("startup_bigsur_irq IRQ %d\n", irq); | ||
198 | |||
199 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { | ||
200 | /* Enable the L1 IRQ */ | ||
201 | enable_bigsur_l1irq(irq); | ||
202 | /* Enable all L2 IRQs in this L1 IRQ */ | ||
203 | mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]); | ||
204 | reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset; | ||
205 | mask &= inb(reg); | ||
206 | outb(mask,reg); | ||
207 | DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg)); | ||
208 | } | ||
209 | else { | ||
210 | /* Enable the L2 IRQ - clear mask bit */ | ||
211 | enable_bigsur_l2irq(irq); | ||
212 | /* Enable the L1 bit masking this L2 IRQ */ | ||
213 | enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]); | ||
214 | DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n", | ||
215 | bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq); | ||
216 | } | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static void shutdown_bigsur_irq(unsigned int irq) | ||
221 | { | ||
222 | DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq); | ||
223 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) | ||
224 | disable_bigsur_l1irq(irq); | ||
225 | else | ||
226 | disable_bigsur_l2irq(irq); | ||
227 | } | ||
228 | |||
229 | /* Define the IRQ structures for the L1 and L2 IRQ types */ | ||
230 | static struct hw_interrupt_type bigsur_l1irq_type = { | ||
231 | "BigSur-CPLD-Level1-IRQ", | ||
232 | startup_bigsur_irq, | ||
233 | shutdown_bigsur_irq, | ||
234 | enable_bigsur_l1irq, | ||
235 | disable_bigsur_l1irq, | ||
236 | mask_and_ack_bigsur, | ||
237 | end_bigsur_irq | ||
238 | }; | ||
239 | |||
240 | static struct hw_interrupt_type bigsur_l2irq_type = { | ||
241 | "BigSur-CPLD-Level2-IRQ", | ||
242 | startup_bigsur_irq, | ||
243 | shutdown_bigsur_irq, | ||
244 | enable_bigsur_l2irq, | ||
245 | disable_bigsur_l2irq, | ||
246 | mask_and_ack_bigsur, | ||
247 | end_bigsur_irq | ||
248 | }; | ||
249 | |||
250 | |||
251 | static void make_bigsur_l1isr(unsigned int irq) { | ||
252 | |||
253 | /* sanity check first */ | ||
254 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { | ||
255 | /* save the handler in the main description table */ | ||
256 | irq_desc[irq].handler = &bigsur_l1irq_type; | ||
257 | irq_desc[irq].status = IRQ_DISABLED; | ||
258 | irq_desc[irq].action = 0; | ||
259 | irq_desc[irq].depth = 1; | ||
260 | |||
261 | disable_bigsur_l1irq(irq); | ||
262 | return; | ||
263 | } | ||
264 | DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq); | ||
265 | return; | ||
266 | } | ||
267 | |||
268 | static void make_bigsur_l2isr(unsigned int irq) { | ||
269 | |||
270 | /* sanity check first */ | ||
271 | if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) { | ||
272 | /* save the handler in the main description table */ | ||
273 | irq_desc[irq].handler = &bigsur_l2irq_type; | ||
274 | irq_desc[irq].status = IRQ_DISABLED; | ||
275 | irq_desc[irq].action = 0; | ||
276 | irq_desc[irq].depth = 1; | ||
277 | |||
278 | disable_bigsur_l2irq(irq); | ||
279 | return; | ||
280 | } | ||
281 | DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq); | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | /* The IRQ's will be decoded as follows: | ||
286 | * If a level 2 handler exists and there is an unmasked active | ||
287 | * IRQ, the 2nd level handler will be called. | ||
288 | * If a level 2 handler does not exist for the active IRQ | ||
289 | * the 1st level handler will be called. | ||
290 | */ | ||
291 | |||
292 | int bigsur_irq_demux(int irq) | ||
293 | { | ||
294 | int dmux_irq = irq; | ||
295 | u8 mask, actv_irqs; | ||
296 | u32 reg_num; | ||
297 | |||
298 | DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq); | ||
299 | /* decode the 1st level IRQ */ | ||
300 | if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { | ||
301 | /* Get corresponding L2 ISR bitmask and ISR number */ | ||
302 | mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]; | ||
303 | reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW]; | ||
304 | /* find the active IRQ's (XOR with inactive level)*/ | ||
305 | actv_irqs = inb(isr_base-reg_num*isr_offset) ^ | ||
306 | bigsur_l2_inactv_state[reg_num]; | ||
307 | /* decode active IRQ's */ | ||
308 | actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset)); | ||
309 | /* if NEZ then we have an active L2 IRQ */ | ||
310 | if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW; | ||
311 | /* if no 2nd level IRQ action, but has 1st level, use 1st level handler */ | ||
312 | if(!irq_desc[dmux_irq].action && irq_desc[irq].action) | ||
313 | dmux_irq = irq; | ||
314 | DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n", | ||
315 | irq, dmux_irq, mask, reg_num); | ||
316 | } | ||
317 | #ifdef CONFIG_HD64465 | ||
318 | dmux_irq = hd64465_irq_demux(dmux_irq); | ||
319 | #endif /* CONFIG_HD64465 */ | ||
320 | DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq); | ||
321 | |||
322 | return dmux_irq; | ||
323 | } | ||
324 | |||
325 | /*===========================================================*/ | ||
326 | // Big Sur Init Routines | ||
327 | /*===========================================================*/ | ||
328 | void __init init_bigsur_IRQ(void) | ||
329 | { | ||
330 | int i; | ||
331 | |||
332 | if (!MACH_BIGSUR) return; | ||
333 | |||
334 | /* Create ISR's for Big Sur CPLD IRQ's */ | ||
335 | /*==============================================================*/ | ||
336 | for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++) | ||
337 | make_bigsur_l1isr(i); | ||
338 | |||
339 | printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n", | ||
340 | BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH); | ||
341 | |||
342 | for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++) | ||
343 | make_bigsur_l2isr(i); | ||
344 | |||
345 | printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n", | ||
346 | BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH); | ||
347 | |||
348 | } | ||
diff --git a/arch/sh/boards/bigsur/led.c b/arch/sh/boards/bigsur/led.c new file mode 100644 index 000000000000..0a2339c69440 --- /dev/null +++ b/arch/sh/boards/bigsur/led.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/led_bigsur.c | ||
3 | * | ||
4 | * By Dustin McIntire (dustin@sensoria.com) (c)2001 | ||
5 | * Derived from led_se.c and led.c, which bore the message: | ||
6 | * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * This file contains Big Sur specific LED code. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/bigsur/bigsur.h> | ||
17 | |||
18 | static void mach_led(int position, int value) | ||
19 | { | ||
20 | int word; | ||
21 | |||
22 | word = bigsur_inl(BIGSUR_CSLR); | ||
23 | if (value) { | ||
24 | bigsur_outl(word & ~BIGSUR_LED, BIGSUR_CSLR); | ||
25 | } else { | ||
26 | bigsur_outl(word | BIGSUR_LED, BIGSUR_CSLR); | ||
27 | } | ||
28 | } | ||
29 | |||
30 | #ifdef CONFIG_HEARTBEAT | ||
31 | |||
32 | #include <linux/sched.h> | ||
33 | |||
34 | /* Cycle the LED on/off */ | ||
35 | void heartbeat_bigsur(void) | ||
36 | { | ||
37 | static unsigned cnt = 0, period = 0, dist = 0; | ||
38 | |||
39 | if (cnt == 0 || cnt == dist) | ||
40 | mach_led( -1, 1); | ||
41 | else if (cnt == 7 || cnt == dist+7) | ||
42 | mach_led( -1, 0); | ||
43 | |||
44 | if (++cnt > period) { | ||
45 | cnt = 0; | ||
46 | /* The hyperbolic function below modifies the heartbeat period | ||
47 | * length in dependency of the current (5min) load. It goes | ||
48 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
49 | * f(inf)->30. */ | ||
50 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
51 | dist = period / 4; | ||
52 | } | ||
53 | } | ||
54 | #endif /* CONFIG_HEARTBEAT */ | ||
55 | |||
diff --git a/arch/sh/boards/bigsur/setup.c b/arch/sh/boards/bigsur/setup.c new file mode 100644 index 000000000000..e69be05195f5 --- /dev/null +++ b/arch/sh/boards/bigsur/setup.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * | ||
3 | * By Dustin McIntire (dustin@sensoria.com) (c)2001 | ||
4 | * | ||
5 | * Setup and IRQ handling code for the HD64465 companion chip. | ||
6 | * by Greg Banks <gbanks@pocketpenguins.com> | ||
7 | * Copyright (c) 2000 PocketPenguins Inc | ||
8 | * | ||
9 | * Derived from setup_hd64465.c which bore the message: | ||
10 | * Greg Banks <gbanks@pocketpenguins.com> | ||
11 | * Copyright (c) 2000 PocketPenguins Inc and | ||
12 | * Copyright (C) 2000 YAEGASHI Takeshi | ||
13 | * and setup_cqreek.c which bore message: | ||
14 | * Copyright (C) 2000 Niibe Yutaka | ||
15 | * | ||
16 | * May be copied or modified under the terms of the GNU General Public | ||
17 | * License. See linux/COPYING for more information. | ||
18 | * | ||
19 | * Setup functions for a Hitachi Big Sur Evaluation Board. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/param.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/irq.h> | ||
32 | #include <linux/bitops.h> | ||
33 | |||
34 | #include <asm/io.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/machvec.h> | ||
37 | #include <asm/bigsur/io.h> | ||
38 | #include <asm/hd64465/hd64465.h> | ||
39 | #include <asm/bigsur/bigsur.h> | ||
40 | |||
41 | /*===========================================================*/ | ||
42 | // Big Sur Init Routines | ||
43 | /*===========================================================*/ | ||
44 | |||
45 | const char *get_system_type(void) | ||
46 | { | ||
47 | return "Big Sur"; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * The Machine Vector | ||
52 | */ | ||
53 | extern void heartbeat_bigsur(void); | ||
54 | extern void init_bigsur_IRQ(void); | ||
55 | |||
56 | struct sh_machine_vector mv_bigsur __initmv = { | ||
57 | .mv_nr_irqs = NR_IRQS, // Defined in <asm/irq.h> | ||
58 | |||
59 | .mv_isa_port2addr = bigsur_isa_port2addr, | ||
60 | .mv_irq_demux = bigsur_irq_demux, | ||
61 | |||
62 | .mv_init_irq = init_bigsur_IRQ, | ||
63 | #ifdef CONFIG_HEARTBEAT | ||
64 | .mv_heartbeat = heartbeat_bigsur, | ||
65 | #endif | ||
66 | }; | ||
67 | ALIAS_MV(bigsur) | ||
68 | |||
69 | int __init platform_setup(void) | ||
70 | { | ||
71 | /* Mask all 2nd level IRQ's */ | ||
72 | outb(-1,BIGSUR_IMR0); | ||
73 | outb(-1,BIGSUR_IMR1); | ||
74 | outb(-1,BIGSUR_IMR2); | ||
75 | outb(-1,BIGSUR_IMR3); | ||
76 | |||
77 | /* Mask 1st level interrupts */ | ||
78 | outb(-1,BIGSUR_IRLMR0); | ||
79 | outb(-1,BIGSUR_IRLMR1); | ||
80 | |||
81 | #if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL) | ||
82 | /* remap IO ports for first ISA serial port to HD64465 UART */ | ||
83 | bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1); | ||
84 | #endif /* CONFIG_HD64465 && CONFIG_SERIAL */ | ||
85 | /* TODO: setup IDE registers */ | ||
86 | bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8); | ||
87 | /* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */ | ||
88 | bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0); | ||
89 | /* set page to 1 */ | ||
90 | outw(1, BIGSUR_ETHR+0xe); | ||
91 | /* set the IO port to BIGSUR_ETHER_IOPORT */ | ||
92 | outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
diff --git a/arch/sh/boards/cat68701/Makefile b/arch/sh/boards/cat68701/Makefile new file mode 100644 index 000000000000..52c1de0a6dfd --- /dev/null +++ b/arch/sh/boards/cat68701/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the CAT-68701 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o irq.o | ||
6 | |||
diff --git a/arch/sh/boards/cat68701/irq.c b/arch/sh/boards/cat68701/irq.c new file mode 100644 index 000000000000..f9a6d185fb8b --- /dev/null +++ b/arch/sh/boards/cat68701/irq.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/cat68701/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Niibe Yutaka | ||
5 | * 2001 Yutaro Ebihara | ||
6 | * | ||
7 | * Setup routines for A-ONE Corp CAT-68701 SH7708 Board | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <asm/irq.h> | ||
16 | |||
17 | int cat68701_irq_demux(int irq) | ||
18 | { | ||
19 | if(irq==13) return 14; | ||
20 | if(irq==7) return 10; | ||
21 | return irq; | ||
22 | } | ||
23 | |||
24 | void init_cat68701_IRQ() | ||
25 | { | ||
26 | make_imask_irq(10); | ||
27 | make_imask_irq(14); | ||
28 | } | ||
diff --git a/arch/sh/boards/cat68701/setup.c b/arch/sh/boards/cat68701/setup.c new file mode 100644 index 000000000000..ae8a350ade53 --- /dev/null +++ b/arch/sh/boards/cat68701/setup.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/cat68701/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Niibe Yutaka | ||
5 | * 2001 Yutaro Ebihara | ||
6 | * | ||
7 | * Setup routines for A-ONE Corp CAT-68701 SH7708 Board | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <asm/io.h> | ||
16 | #include <asm/machvec.h> | ||
17 | #include <asm/mach/io.h> | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/sched.h> | ||
22 | |||
23 | const char *get_system_type(void) | ||
24 | { | ||
25 | return "CAT-68701"; | ||
26 | } | ||
27 | |||
28 | #ifdef CONFIG_HEARTBEAT | ||
29 | void heartbeat_cat68701() | ||
30 | { | ||
31 | static unsigned int cnt = 0, period = 0 , bit = 0; | ||
32 | cnt += 1; | ||
33 | if (cnt < period) { | ||
34 | return; | ||
35 | } | ||
36 | cnt = 0; | ||
37 | |||
38 | /* Go through the points (roughly!): | ||
39 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
40 | */ | ||
41 | period = 110 - ( (300<<FSHIFT)/ | ||
42 | ((avenrun[0]/5) + (3<<FSHIFT)) ); | ||
43 | |||
44 | if(bit){ bit=0; }else{ bit=1; } | ||
45 | outw(bit<<15,0x3fe); | ||
46 | } | ||
47 | #endif /* CONFIG_HEARTBEAT */ | ||
48 | |||
49 | unsigned long cat68701_isa_port2addr(unsigned long offset) | ||
50 | { | ||
51 | /* CompactFlash (IDE) */ | ||
52 | if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6)) | ||
53 | return 0xba000000 + offset; | ||
54 | |||
55 | /* INPUT PORT */ | ||
56 | if ((offset >= 0x3fc) && (offset <= 0x3fd)) | ||
57 | return 0xb4007000 + offset; | ||
58 | |||
59 | /* OUTPUT PORT */ | ||
60 | if ((offset >= 0x3fe) && (offset <= 0x3ff)) | ||
61 | return 0xb4007400 + offset; | ||
62 | |||
63 | return offset + 0xb4000000; /* other I/O (EREA 5)*/ | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * The Machine Vector | ||
68 | */ | ||
69 | |||
70 | struct sh_machine_vector mv_cat68701 __initmv = { | ||
71 | .mv_nr_irqs = 32, | ||
72 | .mv_isa_port2addr = cat68701_isa_port2addr, | ||
73 | .mv_irq_demux = cat68701_irq_demux, | ||
74 | |||
75 | .mv_init_irq = init_cat68701_IRQ, | ||
76 | #ifdef CONFIG_HEARTBEAT | ||
77 | .mv_heartbeat = heartbeat_cat68701, | ||
78 | #endif | ||
79 | }; | ||
80 | ALIAS_MV(cat68701) | ||
81 | |||
82 | int __init platform_setup(void) | ||
83 | { | ||
84 | /* dummy read erea5 (CS8900A) */ | ||
85 | } | ||
86 | |||
diff --git a/arch/sh/boards/cqreek/Makefile b/arch/sh/boards/cqreek/Makefile new file mode 100644 index 000000000000..1a788a85eba3 --- /dev/null +++ b/arch/sh/boards/cqreek/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the CqREEK specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o irq.o | ||
6 | |||
diff --git a/arch/sh/boards/cqreek/irq.c b/arch/sh/boards/cqreek/irq.c new file mode 100644 index 000000000000..fa6cfe5a20a7 --- /dev/null +++ b/arch/sh/boards/cqreek/irq.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* $Id: irq.c,v 1.1.2.4 2002/11/04 20:33:56 lethal Exp $ | ||
2 | * | ||
3 | * arch/sh/boards/cqreek/irq.c | ||
4 | * | ||
5 | * Copyright (C) 2000 Niibe Yutaka | ||
6 | * | ||
7 | * CqREEK IDE/ISA Bridge Support. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/irq.h> | ||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/cqreek/cqreek.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/io_generic.h> | ||
17 | #include <asm/irq.h> | ||
18 | #include <asm/machvec.h> | ||
19 | #include <asm/machvec_init.h> | ||
20 | #include <asm/rtc.h> | ||
21 | |||
22 | struct cqreek_irq_data { | ||
23 | unsigned short mask_port; /* Port of Interrupt Mask Register */ | ||
24 | unsigned short stat_port; /* Port of Interrupt Status Register */ | ||
25 | unsigned short bit; /* Value of the bit */ | ||
26 | }; | ||
27 | static struct cqreek_irq_data cqreek_irq_data[NR_IRQS]; | ||
28 | |||
29 | static void disable_cqreek_irq(unsigned int irq) | ||
30 | { | ||
31 | unsigned long flags; | ||
32 | unsigned short mask; | ||
33 | unsigned short mask_port = cqreek_irq_data[irq].mask_port; | ||
34 | unsigned short bit = cqreek_irq_data[irq].bit; | ||
35 | |||
36 | local_irq_save(flags); | ||
37 | /* Disable IRQ */ | ||
38 | mask = inw(mask_port) & ~bit; | ||
39 | outw_p(mask, mask_port); | ||
40 | local_irq_restore(flags); | ||
41 | } | ||
42 | |||
43 | static void enable_cqreek_irq(unsigned int irq) | ||
44 | { | ||
45 | unsigned long flags; | ||
46 | unsigned short mask; | ||
47 | unsigned short mask_port = cqreek_irq_data[irq].mask_port; | ||
48 | unsigned short bit = cqreek_irq_data[irq].bit; | ||
49 | |||
50 | local_irq_save(flags); | ||
51 | /* Enable IRQ */ | ||
52 | mask = inw(mask_port) | bit; | ||
53 | outw_p(mask, mask_port); | ||
54 | local_irq_restore(flags); | ||
55 | } | ||
56 | |||
57 | static void mask_and_ack_cqreek(unsigned int irq) | ||
58 | { | ||
59 | unsigned short stat_port = cqreek_irq_data[irq].stat_port; | ||
60 | unsigned short bit = cqreek_irq_data[irq].bit; | ||
61 | |||
62 | disable_cqreek_irq(irq); | ||
63 | /* Clear IRQ (it might be edge IRQ) */ | ||
64 | inw(stat_port); | ||
65 | outw_p(bit, stat_port); | ||
66 | } | ||
67 | |||
68 | static void end_cqreek_irq(unsigned int irq) | ||
69 | { | ||
70 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
71 | enable_cqreek_irq(irq); | ||
72 | } | ||
73 | |||
74 | static unsigned int startup_cqreek_irq(unsigned int irq) | ||
75 | { | ||
76 | enable_cqreek_irq(irq); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static void shutdown_cqreek_irq(unsigned int irq) | ||
81 | { | ||
82 | disable_cqreek_irq(irq); | ||
83 | } | ||
84 | |||
85 | static struct hw_interrupt_type cqreek_irq_type = { | ||
86 | "CqREEK-IRQ", | ||
87 | startup_cqreek_irq, | ||
88 | shutdown_cqreek_irq, | ||
89 | enable_cqreek_irq, | ||
90 | disable_cqreek_irq, | ||
91 | mask_and_ack_cqreek, | ||
92 | end_cqreek_irq | ||
93 | }; | ||
94 | |||
95 | int cqreek_has_ide, cqreek_has_isa; | ||
96 | |||
97 | /* XXX: This is just for test for my NE2000 ISA board | ||
98 | What we really need is virtualized IRQ and demultiplexer like HP600 port */ | ||
99 | void __init init_cqreek_IRQ(void) | ||
100 | { | ||
101 | if (cqreek_has_ide) { | ||
102 | cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK; | ||
103 | cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT; | ||
104 | cqreek_irq_data[14].bit = 1; | ||
105 | |||
106 | irq_desc[14].handler = &cqreek_irq_type; | ||
107 | irq_desc[14].status = IRQ_DISABLED; | ||
108 | irq_desc[14].action = 0; | ||
109 | irq_desc[14].depth = 1; | ||
110 | |||
111 | disable_cqreek_irq(14); | ||
112 | } | ||
113 | |||
114 | if (cqreek_has_isa) { | ||
115 | cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK; | ||
116 | cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT; | ||
117 | cqreek_irq_data[10].bit = (1 << 10); | ||
118 | |||
119 | /* XXX: Err... we may need demultiplexer for ISA irq... */ | ||
120 | irq_desc[10].handler = &cqreek_irq_type; | ||
121 | irq_desc[10].status = IRQ_DISABLED; | ||
122 | irq_desc[10].action = 0; | ||
123 | irq_desc[10].depth = 1; | ||
124 | |||
125 | disable_cqreek_irq(10); | ||
126 | } | ||
127 | } | ||
128 | |||
diff --git a/arch/sh/boards/cqreek/setup.c b/arch/sh/boards/cqreek/setup.c new file mode 100644 index 000000000000..29b537cd6546 --- /dev/null +++ b/arch/sh/boards/cqreek/setup.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* $Id: setup.c,v 1.5 2003/08/04 01:51:58 lethal Exp $ | ||
2 | * | ||
3 | * arch/sh/kernel/setup_cqreek.c | ||
4 | * | ||
5 | * Copyright (C) 2000 Niibe Yutaka | ||
6 | * | ||
7 | * CqREEK IDE/ISA Bridge Support. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <asm/mach/cqreek.h> | ||
17 | #include <asm/machvec.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/io_generic.h> | ||
20 | #include <asm/irq.h> | ||
21 | #include <asm/rtc.h> | ||
22 | |||
23 | #define IDE_OFFSET 0xA4000000UL | ||
24 | #define ISA_OFFSET 0xA4A00000UL | ||
25 | |||
26 | const char *get_system_type(void) | ||
27 | { | ||
28 | return "CqREEK"; | ||
29 | } | ||
30 | |||
31 | static unsigned long cqreek_port2addr(unsigned long port) | ||
32 | { | ||
33 | if (0x0000<=port && port<=0x0040) | ||
34 | return IDE_OFFSET + port; | ||
35 | if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6) | ||
36 | return IDE_OFFSET + port; | ||
37 | |||
38 | return ISA_OFFSET + port; | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * The Machine Vector | ||
43 | */ | ||
44 | struct sh_machine_vector mv_cqreek __initmv = { | ||
45 | #if defined(CONFIG_CPU_SH4) | ||
46 | .mv_nr_irqs = 48, | ||
47 | #elif defined(CONFIG_CPU_SUBTYPE_SH7708) | ||
48 | .mv_nr_irqs = 32, | ||
49 | #elif defined(CONFIG_CPU_SUBTYPE_SH7709) | ||
50 | .mv_nr_irqs = 61, | ||
51 | #endif | ||
52 | |||
53 | .mv_init_irq = init_cqreek_IRQ, | ||
54 | |||
55 | .mv_isa_port2addr = cqreek_port2addr, | ||
56 | }; | ||
57 | ALIAS_MV(cqreek) | ||
58 | |||
59 | /* | ||
60 | * Initialize the board | ||
61 | */ | ||
62 | void __init platform_setup(void) | ||
63 | { | ||
64 | int i; | ||
65 | /* udelay is not available at setup time yet... */ | ||
66 | #define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0) | ||
67 | |||
68 | if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */ | ||
69 | outw_p(0, BRIDGE_IDE_INTR_LVL); | ||
70 | outw_p(0, BRIDGE_IDE_INTR_MASK); | ||
71 | |||
72 | outw_p(0, BRIDGE_IDE_CTRL); | ||
73 | DELAY(); | ||
74 | |||
75 | outw_p(0x8000, BRIDGE_IDE_CTRL); | ||
76 | DELAY(); | ||
77 | |||
78 | outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */ | ||
79 | outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */ | ||
80 | outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */ | ||
81 | cqreek_has_ide=1; | ||
82 | } | ||
83 | |||
84 | if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */ | ||
85 | outw_p(0, BRIDGE_ISA_INTR_LVL); | ||
86 | outw_p(0, BRIDGE_ISA_INTR_MASK); | ||
87 | |||
88 | outw_p(0, BRIDGE_ISA_CTRL); | ||
89 | DELAY(); | ||
90 | outw_p(0x8000, BRIDGE_ISA_CTRL); | ||
91 | DELAY(); | ||
92 | |||
93 | outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */ | ||
94 | outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */ | ||
95 | outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */ | ||
96 | cqreek_has_isa=1; | ||
97 | } | ||
98 | |||
99 | printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", cqreek_has_ide, cqreek_has_isa); | ||
100 | } | ||
101 | |||
diff --git a/arch/sh/boards/dmida/Makefile b/arch/sh/boards/dmida/Makefile new file mode 100644 index 000000000000..75999aa0a2d9 --- /dev/null +++ b/arch/sh/boards/dmida/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the DataMyte Industrial Digital Assistant(tm) specific parts | ||
3 | # of the kernel | ||
4 | # | ||
5 | |||
6 | obj-y := mach.o | ||
7 | |||
diff --git a/arch/sh/boards/dmida/mach.c b/arch/sh/boards/dmida/mach.c new file mode 100644 index 000000000000..d03a25f989c2 --- /dev/null +++ b/arch/sh/boards/dmida/mach.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/dmida/mach.c | ||
3 | * | ||
4 | * by Greg Banks <gbanks@pocketpenguins.com> | ||
5 | * (c) 2000 PocketPenguins Inc | ||
6 | * | ||
7 | * Derived from mach_hp600.c, which bore the message: | ||
8 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
9 | * | ||
10 | * May be copied or modified under the terms of the GNU General Public | ||
11 | * License. See linux/COPYING for more information. | ||
12 | * | ||
13 | * Machine vector for the DataMyte Industrial Digital Assistant(tm). | ||
14 | * See http://www.dmida.com | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | |||
20 | #include <asm/machvec.h> | ||
21 | #include <asm/rtc.h> | ||
22 | #include <asm/machvec_init.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | #include <asm/hd64465/hd64465.h> | ||
26 | #include <asm/irq.h> | ||
27 | |||
28 | /* | ||
29 | * The Machine Vector | ||
30 | */ | ||
31 | |||
32 | struct sh_machine_vector mv_dmida __initmv = { | ||
33 | .mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM, | ||
34 | |||
35 | .mv_inb = hd64465_inb, | ||
36 | .mv_inw = hd64465_inw, | ||
37 | .mv_inl = hd64465_inl, | ||
38 | .mv_outb = hd64465_outb, | ||
39 | .mv_outw = hd64465_outw, | ||
40 | .mv_outl = hd64465_outl, | ||
41 | |||
42 | .mv_inb_p = hd64465_inb_p, | ||
43 | .mv_inw_p = hd64465_inw, | ||
44 | .mv_inl_p = hd64465_inl, | ||
45 | .mv_outb_p = hd64465_outb_p, | ||
46 | .mv_outw_p = hd64465_outw, | ||
47 | .mv_outl_p = hd64465_outl, | ||
48 | |||
49 | .mv_insb = hd64465_insb, | ||
50 | .mv_insw = hd64465_insw, | ||
51 | .mv_insl = hd64465_insl, | ||
52 | .mv_outsb = hd64465_outsb, | ||
53 | .mv_outsw = hd64465_outsw, | ||
54 | .mv_outsl = hd64465_outsl, | ||
55 | |||
56 | .mv_irq_demux = hd64465_irq_demux, | ||
57 | }; | ||
58 | ALIAS_MV(dmida) | ||
59 | |||
diff --git a/arch/sh/boards/dreamcast/Makefile b/arch/sh/boards/dreamcast/Makefile new file mode 100644 index 000000000000..7b97546c7e5f --- /dev/null +++ b/arch/sh/boards/dreamcast/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the Sega Dreamcast specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o irq.o rtc.o | ||
6 | |||
diff --git a/arch/sh/boards/dreamcast/irq.c b/arch/sh/boards/dreamcast/irq.c new file mode 100644 index 000000000000..b10a6b11c034 --- /dev/null +++ b/arch/sh/boards/dreamcast/irq.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/dreamcast/irq.c | ||
3 | * | ||
4 | * Holly IRQ support for the Sega Dreamcast. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org> | ||
7 | * | ||
8 | * This file is part of the LinuxDC project (www.linuxdc.org) | ||
9 | * Released under the terms of the GNU GPL v2.0 | ||
10 | */ | ||
11 | |||
12 | #include <linux/irq.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | #include <asm/irq.h> | ||
16 | #include <asm/dreamcast/sysasic.h> | ||
17 | |||
18 | /* Dreamcast System ASIC Hardware Events - | ||
19 | |||
20 | The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving | ||
21 | hardware events from system peripherals and triggering an SH7750 IRQ. | ||
22 | Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are | ||
23 | set in the Event Mask Registers (EMRs). When a hardware event is | ||
24 | triggered, it's corresponding bit in the Event Status Registers (ESRs) | ||
25 | is set, and that bit should be rewritten to the ESR to acknowledge that | ||
26 | event. | ||
27 | |||
28 | There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event | ||
29 | types can be found in include/asm-sh/dc_sysasic.h. There are three groups | ||
30 | of EMRs that parallel the ESRs. Each EMR group corresponds to an IRQ, so | ||
31 | 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers | ||
32 | IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9. | ||
33 | |||
34 | In the kernel, these events are mapped to virtual IRQs so that drivers can | ||
35 | respond to them as they would a normal interrupt. In order to keep this | ||
36 | mapping simple, the events are mapped as: | ||
37 | |||
38 | 6900/6910 - Events 0-31, IRQ 13 | ||
39 | 6904/6924 - Events 32-63, IRQ 11 | ||
40 | 6908/6938 - Events 64-95, IRQ 9 | ||
41 | |||
42 | */ | ||
43 | |||
44 | #define ESR_BASE 0x005f6900 /* Base event status register */ | ||
45 | #define EMR_BASE 0x005f6910 /* Base event mask register */ | ||
46 | |||
47 | /* Helps us determine the EMR group that this event belongs to: 0 = 0x6910, | ||
48 | 1 = 0x6920, 2 = 0x6930; also determine the event offset */ | ||
49 | #define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32) | ||
50 | |||
51 | /* Return the hardware event's bit positon within the EMR/ESR */ | ||
52 | #define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31) | ||
53 | |||
54 | /* For each of these *_irq routines, the IRQ passed in is the virtual IRQ | ||
55 | (logically mapped to the corresponding bit for the hardware event). */ | ||
56 | |||
57 | /* Disable the hardware event by masking its bit in its EMR */ | ||
58 | static inline void disable_systemasic_irq(unsigned int irq) | ||
59 | { | ||
60 | unsigned long flags; | ||
61 | __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2); | ||
62 | __u32 mask; | ||
63 | |||
64 | local_irq_save(flags); | ||
65 | mask = inl(emr); | ||
66 | mask &= ~(1 << EVENT_BIT(irq)); | ||
67 | outl(mask, emr); | ||
68 | local_irq_restore(flags); | ||
69 | } | ||
70 | |||
71 | /* Enable the hardware event by setting its bit in its EMR */ | ||
72 | static inline void enable_systemasic_irq(unsigned int irq) | ||
73 | { | ||
74 | unsigned long flags; | ||
75 | __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2); | ||
76 | __u32 mask; | ||
77 | |||
78 | local_irq_save(flags); | ||
79 | mask = inl(emr); | ||
80 | mask |= (1 << EVENT_BIT(irq)); | ||
81 | outl(mask, emr); | ||
82 | local_irq_restore(flags); | ||
83 | } | ||
84 | |||
85 | /* Acknowledge a hardware event by writing its bit back to its ESR */ | ||
86 | static void ack_systemasic_irq(unsigned int irq) | ||
87 | { | ||
88 | __u32 esr = ESR_BASE + (LEVEL(irq) << 2); | ||
89 | disable_systemasic_irq(irq); | ||
90 | outl((1 << EVENT_BIT(irq)), esr); | ||
91 | } | ||
92 | |||
93 | /* After a IRQ has been ack'd and responded to, it needs to be renabled */ | ||
94 | static void end_systemasic_irq(unsigned int irq) | ||
95 | { | ||
96 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
97 | enable_systemasic_irq(irq); | ||
98 | } | ||
99 | |||
100 | static unsigned int startup_systemasic_irq(unsigned int irq) | ||
101 | { | ||
102 | enable_systemasic_irq(irq); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static void shutdown_systemasic_irq(unsigned int irq) | ||
108 | { | ||
109 | disable_systemasic_irq(irq); | ||
110 | } | ||
111 | |||
112 | struct hw_interrupt_type systemasic_int = { | ||
113 | .typename = "System ASIC", | ||
114 | .startup = startup_systemasic_irq, | ||
115 | .shutdown = shutdown_systemasic_irq, | ||
116 | .enable = enable_systemasic_irq, | ||
117 | .disable = disable_systemasic_irq, | ||
118 | .ack = ack_systemasic_irq, | ||
119 | .end = end_systemasic_irq, | ||
120 | }; | ||
121 | |||
122 | /* | ||
123 | * Map the hardware event indicated by the processor IRQ to a virtual IRQ. | ||
124 | */ | ||
125 | int systemasic_irq_demux(int irq) | ||
126 | { | ||
127 | __u32 emr, esr, status, level; | ||
128 | __u32 j, bit; | ||
129 | |||
130 | switch (irq) { | ||
131 | case 13: | ||
132 | level = 0; | ||
133 | break; | ||
134 | case 11: | ||
135 | level = 1; | ||
136 | break; | ||
137 | case 9: | ||
138 | level = 2; | ||
139 | break; | ||
140 | default: | ||
141 | return irq; | ||
142 | } | ||
143 | emr = EMR_BASE + (level << 4) + (level << 2); | ||
144 | esr = ESR_BASE + (level << 2); | ||
145 | |||
146 | /* Mask the ESR to filter any spurious, unwanted interrtupts */ | ||
147 | status = inl(esr); | ||
148 | status &= inl(emr); | ||
149 | |||
150 | /* Now scan and find the first set bit as the event to map */ | ||
151 | for (bit = 1, j = 0; j < 32; bit <<= 1, j++) { | ||
152 | if (status & bit) { | ||
153 | irq = HW_EVENT_IRQ_BASE + j + (level << 5); | ||
154 | return irq; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* Not reached */ | ||
159 | return irq; | ||
160 | } | ||
diff --git a/arch/sh/boards/dreamcast/rtc.c b/arch/sh/boards/dreamcast/rtc.c new file mode 100644 index 000000000000..379de1629134 --- /dev/null +++ b/arch/sh/boards/dreamcast/rtc.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* arch/sh/kernel/rtc-aica.c | ||
2 | * | ||
3 | * Dreamcast AICA RTC routines. | ||
4 | * | ||
5 | * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org> | ||
6 | * Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org> | ||
7 | * | ||
8 | * Released under the terms of the GNU GPL v2.0. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/time.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | |||
16 | extern void (*rtc_get_time)(struct timespec *); | ||
17 | extern int (*rtc_set_time)(const time_t); | ||
18 | |||
19 | /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in | ||
20 | seconds to get the standard Unix Epoch when getting the time, and add 20 | ||
21 | years when setting the time. */ | ||
22 | #define TWENTY_YEARS ((20 * 365LU + 5) * 86400) | ||
23 | |||
24 | /* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit | ||
25 | registers.*/ | ||
26 | #define AICA_RTC_SECS_H 0xa0710000 | ||
27 | #define AICA_RTC_SECS_L 0xa0710004 | ||
28 | |||
29 | /** | ||
30 | * aica_rtc_gettimeofday - Get the time from the AICA RTC | ||
31 | * @ts: pointer to resulting timespec | ||
32 | * | ||
33 | * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch. | ||
34 | */ | ||
35 | void aica_rtc_gettimeofday(struct timespec *ts) { | ||
36 | unsigned long val1, val2; | ||
37 | |||
38 | do { | ||
39 | val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | | ||
40 | (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); | ||
41 | |||
42 | val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | | ||
43 | (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); | ||
44 | } while (val1 != val2); | ||
45 | |||
46 | ts->tv_sec = val1 - TWENTY_YEARS; | ||
47 | |||
48 | /* Can't get nanoseconds with just a seconds counter. */ | ||
49 | ts->tv_nsec = 0; | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * aica_rtc_settimeofday - Set the AICA RTC to the current time | ||
54 | * @secs: contains the time_t to set | ||
55 | * | ||
56 | * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter. | ||
57 | */ | ||
58 | int aica_rtc_settimeofday(const time_t secs) { | ||
59 | unsigned long val1, val2; | ||
60 | unsigned long adj = secs + TWENTY_YEARS; | ||
61 | |||
62 | do { | ||
63 | ctrl_outl((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H); | ||
64 | ctrl_outl((adj & 0xffff), AICA_RTC_SECS_L); | ||
65 | |||
66 | val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | | ||
67 | (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); | ||
68 | |||
69 | val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | | ||
70 | (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); | ||
71 | } while (val1 != val2); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | void aica_time_init(void) | ||
77 | { | ||
78 | rtc_get_time = aica_rtc_gettimeofday; | ||
79 | rtc_set_time = aica_rtc_settimeofday; | ||
80 | } | ||
81 | |||
diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c new file mode 100644 index 000000000000..55dece35cde5 --- /dev/null +++ b/arch/sh/boards/dreamcast/setup.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/dreamcast/setup.c | ||
3 | * | ||
4 | * Hardware support for the Sega Dreamcast. | ||
5 | * | ||
6 | * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@linuxdc.org> | ||
7 | * Copyright (c) 2002, 2003, 2004 Paul Mundt <lethal@linux-sh.org> | ||
8 | * | ||
9 | * This file is part of the LinuxDC project (www.linuxdc.org) | ||
10 | * | ||
11 | * Released under the terms of the GNU GPL v2.0. | ||
12 | * | ||
13 | * This file originally bore the message (with enclosed-$): | ||
14 | * Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp | ||
15 | * SEGA Dreamcast support | ||
16 | */ | ||
17 | |||
18 | #include <linux/sched.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/param.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/device.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/machvec.h> | ||
29 | #include <asm/machvec_init.h> | ||
30 | #include <asm/mach/sysasic.h> | ||
31 | |||
32 | extern struct hw_interrupt_type systemasic_int; | ||
33 | /* XXX: Move this into it's proper header. */ | ||
34 | extern void (*board_time_init)(void); | ||
35 | extern void aica_time_init(void); | ||
36 | extern int gapspci_init(void); | ||
37 | extern int systemasic_irq_demux(int); | ||
38 | |||
39 | void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, int); | ||
40 | int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t); | ||
41 | |||
42 | const char *get_system_type(void) | ||
43 | { | ||
44 | return "Sega Dreamcast"; | ||
45 | } | ||
46 | |||
47 | struct sh_machine_vector mv_dreamcast __initmv = { | ||
48 | .mv_nr_irqs = NR_IRQS, | ||
49 | |||
50 | .mv_irq_demux = systemasic_irq_demux, | ||
51 | |||
52 | #ifdef CONFIG_PCI | ||
53 | .mv_consistent_alloc = dreamcast_consistent_alloc, | ||
54 | .mv_consistent_free = dreamcast_consistent_free, | ||
55 | #endif | ||
56 | }; | ||
57 | ALIAS_MV(dreamcast) | ||
58 | |||
59 | int __init platform_setup(void) | ||
60 | { | ||
61 | int i; | ||
62 | |||
63 | /* Mask all hardware events */ | ||
64 | /* XXX */ | ||
65 | |||
66 | /* Acknowledge any previous events */ | ||
67 | /* XXX */ | ||
68 | |||
69 | __set_io_port_base(0xa0000000); | ||
70 | |||
71 | /* Assign all virtual IRQs to the System ASIC int. handler */ | ||
72 | for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) | ||
73 | irq_desc[i].handler = &systemasic_int; | ||
74 | |||
75 | board_time_init = aica_time_init; | ||
76 | |||
77 | #ifdef CONFIG_PCI | ||
78 | if (gapspci_init() < 0) | ||
79 | printk(KERN_WARNING "GAPSPCI was not detected.\n"); | ||
80 | #endif | ||
81 | |||
82 | return 0; | ||
83 | } | ||
diff --git a/arch/sh/boards/ec3104/Makefile b/arch/sh/boards/ec3104/Makefile new file mode 100644 index 000000000000..178891534b67 --- /dev/null +++ b/arch/sh/boards/ec3104/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the EC3104 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o io.o irq.o | ||
6 | |||
diff --git a/arch/sh/boards/ec3104/io.c b/arch/sh/boards/ec3104/io.c new file mode 100644 index 000000000000..a70928c44753 --- /dev/null +++ b/arch/sh/boards/ec3104/io.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_ec3104.c | ||
3 | * EC3104 companion chip support | ||
4 | * | ||
5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
6 | * | ||
7 | */ | ||
8 | /* EC3104 note: | ||
9 | * This code was written without any documentation about the EC3104 chip. While | ||
10 | * I hope I got most of the basic functionality right, the register names I use | ||
11 | * are most likely completely different from those in the chip documentation. | ||
12 | * | ||
13 | * If you have any further information about the EC3104, please tell me | ||
14 | * (prumpf@tux.org). | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/ec3104/ec3104.h> | ||
22 | |||
23 | /* | ||
24 | * EC3104 has a real ISA bus which we redirect low port accesses to (the | ||
25 | * actual device on mine is a ESS 1868, and I don't want to hack the driver | ||
26 | * more than strictly necessary). I am not going to duplicate the | ||
27 | * hard coding of PC addresses (for the 16550s aso) here though; it's just | ||
28 | * too ugly. | ||
29 | */ | ||
30 | |||
31 | #define low_port(port) ((port) < 0x10000) | ||
32 | |||
33 | static inline unsigned long port2addr(unsigned long port) | ||
34 | { | ||
35 | switch(port >> 16) { | ||
36 | case 0: | ||
37 | return EC3104_ISA_BASE + port * 2; | ||
38 | |||
39 | /* XXX hack. it's unclear what to do about the serial ports */ | ||
40 | case 1: | ||
41 | return EC3104_BASE + (port&0xffff) * 4; | ||
42 | |||
43 | default: | ||
44 | /* XXX PCMCIA */ | ||
45 | return 0; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | unsigned char ec3104_inb(unsigned long port) | ||
50 | { | ||
51 | u8 ret; | ||
52 | |||
53 | ret = *(volatile u8 *)port2addr(port); | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | unsigned short ec3104_inw(unsigned long port) | ||
59 | { | ||
60 | BUG(); | ||
61 | } | ||
62 | |||
63 | unsigned long ec3104_inl(unsigned long port) | ||
64 | { | ||
65 | BUG(); | ||
66 | } | ||
67 | |||
68 | void ec3104_outb(unsigned char data, unsigned long port) | ||
69 | { | ||
70 | *(volatile u8 *)port2addr(port) = data; | ||
71 | } | ||
72 | |||
73 | void ec3104_outw(unsigned short data, unsigned long port) | ||
74 | { | ||
75 | BUG(); | ||
76 | } | ||
77 | |||
78 | void ec3104_outl(unsigned long data, unsigned long port) | ||
79 | { | ||
80 | BUG(); | ||
81 | } | ||
diff --git a/arch/sh/boards/ec3104/irq.c b/arch/sh/boards/ec3104/irq.c new file mode 100644 index 000000000000..ffa4ff1f090f --- /dev/null +++ b/arch/sh/boards/ec3104/irq.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/ec3104/irq.c | ||
3 | * EC3104 companion chip support | ||
4 | * | ||
5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <asm/io.h> | ||
10 | #include <asm/irq.h> | ||
11 | #include <asm/ec3104/ec3104.h> | ||
12 | |||
13 | /* This is for debugging mostly; here's the table that I intend to keep | ||
14 | * in here: | ||
15 | * | ||
16 | * index function base addr power interrupt bit | ||
17 | * 0 power b0ec0000 --- 00000001 (unused) | ||
18 | * 1 irqs b0ec1000 --- 00000002 (unused) | ||
19 | * 2 ?? b0ec2000 b0ec0008 00000004 | ||
20 | * 3 PS2 (1) b0ec3000 b0ec000c 00000008 | ||
21 | * 4 PS2 (2) b0ec4000 b0ec0010 00000010 | ||
22 | * 5 ?? b0ec5000 b0ec0014 00000020 | ||
23 | * 6 I2C b0ec6000 b0ec0018 00000040 | ||
24 | * 7 serial (1) b0ec7000 b0ec001c 00000080 | ||
25 | * 8 serial (2) b0ec8000 b0ec0020 00000100 | ||
26 | * 9 serial (3) b0ec9000 b0ec0024 00000200 | ||
27 | * 10 serial (4) b0eca000 b0ec0028 00000400 | ||
28 | * 12 GPIO (1) b0ecc000 b0ec0030 | ||
29 | * 13 GPIO (2) b0ecc000 b0ec0030 | ||
30 | * 16 pcmcia (1) b0ed0000 b0ec0040 00010000 | ||
31 | * 17 pcmcia (2) b0ed1000 b0ec0044 00020000 | ||
32 | */ | ||
33 | |||
34 | /* I used the register names from another interrupt controller I worked with, | ||
35 | * since it seems to be identical to the ec3104 except that all bits are | ||
36 | * inverted: | ||
37 | * | ||
38 | * IRR: Interrupt Request Register (pending and enabled interrupts) | ||
39 | * IMR: Interrupt Mask Register (which interrupts are enabled) | ||
40 | * IPR: Interrupt Pending Register (pending interrupts, even disabled ones) | ||
41 | * | ||
42 | * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all | ||
43 | * IRQs seem to be level-triggered. | ||
44 | */ | ||
45 | |||
46 | #define EC3104_IRR (EC3104_BASE + 0x1000) | ||
47 | #define EC3104_IMR (EC3104_BASE + 0x1004) | ||
48 | #define EC3104_IPR (EC3104_BASE + 0x1008) | ||
49 | |||
50 | #define ctrl_readl(addr) (*(volatile u32 *)(addr)) | ||
51 | #define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data)) | ||
52 | #define ctrl_readb(addr) (*(volatile u8 *)(addr)) | ||
53 | |||
54 | static char *ec3104_name(unsigned index) | ||
55 | { | ||
56 | switch(index) { | ||
57 | case 0: | ||
58 | return "power management"; | ||
59 | case 1: | ||
60 | return "interrupts"; | ||
61 | case 3: | ||
62 | return "PS2 (1)"; | ||
63 | case 4: | ||
64 | return "PS2 (2)"; | ||
65 | case 5: | ||
66 | return "I2C (1)"; | ||
67 | case 6: | ||
68 | return "I2C (2)"; | ||
69 | case 7: | ||
70 | return "serial (1)"; | ||
71 | case 8: | ||
72 | return "serial (2)"; | ||
73 | case 9: | ||
74 | return "serial (3)"; | ||
75 | case 10: | ||
76 | return "serial (4)"; | ||
77 | case 16: | ||
78 | return "pcmcia (1)"; | ||
79 | case 17: | ||
80 | return "pcmcia (2)"; | ||
81 | default: { | ||
82 | static char buf[32]; | ||
83 | |||
84 | sprintf(buf, "unknown (%d)", index); | ||
85 | |||
86 | return buf; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | int get_pending_interrupts(char *buf) | ||
92 | { | ||
93 | u32 ipr; | ||
94 | u32 bit; | ||
95 | char *p = buf; | ||
96 | |||
97 | p += sprintf(p, "pending: ("); | ||
98 | |||
99 | ipr = ctrl_inl(EC3104_IPR); | ||
100 | |||
101 | for (bit = 1; bit < 32; bit++) | ||
102 | if (!(ipr & (1<<bit))) | ||
103 | p += sprintf(p, "%s ", ec3104_name(bit)); | ||
104 | |||
105 | p += sprintf(p, ")\n"); | ||
106 | |||
107 | return p - buf; | ||
108 | } | ||
109 | |||
110 | static inline u32 ec3104_irq2mask(unsigned int irq) | ||
111 | { | ||
112 | return (1 << (irq - EC3104_IRQBASE)); | ||
113 | } | ||
114 | |||
115 | static inline void mask_ec3104_irq(unsigned int irq) | ||
116 | { | ||
117 | u32 mask; | ||
118 | |||
119 | mask = ctrl_readl(EC3104_IMR); | ||
120 | |||
121 | mask |= ec3104_irq2mask(irq); | ||
122 | |||
123 | ctrl_writel(mask, EC3104_IMR); | ||
124 | } | ||
125 | |||
126 | static inline void unmask_ec3104_irq(unsigned int irq) | ||
127 | { | ||
128 | u32 mask; | ||
129 | |||
130 | mask = ctrl_readl(EC3104_IMR); | ||
131 | |||
132 | mask &= ~ec3104_irq2mask(irq); | ||
133 | |||
134 | ctrl_writel(mask, EC3104_IMR); | ||
135 | } | ||
136 | |||
137 | static void disable_ec3104_irq(unsigned int irq) | ||
138 | { | ||
139 | mask_ec3104_irq(irq); | ||
140 | } | ||
141 | |||
142 | static void enable_ec3104_irq(unsigned int irq) | ||
143 | { | ||
144 | unmask_ec3104_irq(irq); | ||
145 | } | ||
146 | |||
147 | static void mask_and_ack_ec3104_irq(unsigned int irq) | ||
148 | { | ||
149 | mask_ec3104_irq(irq); | ||
150 | } | ||
151 | |||
152 | static void end_ec3104_irq(unsigned int irq) | ||
153 | { | ||
154 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
155 | unmask_ec3104_irq(irq); | ||
156 | } | ||
157 | |||
158 | static unsigned int startup_ec3104_irq(unsigned int irq) | ||
159 | { | ||
160 | unmask_ec3104_irq(irq); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static void shutdown_ec3104_irq(unsigned int irq) | ||
166 | { | ||
167 | mask_ec3104_irq(irq); | ||
168 | |||
169 | } | ||
170 | |||
171 | static struct hw_interrupt_type ec3104_int = { | ||
172 | .typename = "EC3104", | ||
173 | .enable = enable_ec3104_irq, | ||
174 | .disable = disable_ec3104_irq, | ||
175 | .ack = mask_and_ack_ec3104_irq, | ||
176 | .end = end_ec3104_irq, | ||
177 | .startup = startup_ec3104_irq, | ||
178 | .shutdown = shutdown_ec3104_irq, | ||
179 | }; | ||
180 | |||
181 | /* Yuck. the _demux API is ugly */ | ||
182 | int ec3104_irq_demux(int irq) | ||
183 | { | ||
184 | if (irq == EC3104_IRQ) { | ||
185 | unsigned int mask; | ||
186 | |||
187 | mask = ctrl_readl(EC3104_IRR); | ||
188 | |||
189 | if (mask == 0xffffffff) | ||
190 | return EC3104_IRQ; | ||
191 | else | ||
192 | return EC3104_IRQBASE + ffz(mask); | ||
193 | } | ||
194 | |||
195 | return irq; | ||
196 | } | ||
diff --git a/arch/sh/boards/ec3104/setup.c b/arch/sh/boards/ec3104/setup.c new file mode 100644 index 000000000000..5130ba2b6ff1 --- /dev/null +++ b/arch/sh/boards/ec3104/setup.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/ec3104/setup.c | ||
3 | * EC3104 companion chip support | ||
4 | * | ||
5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
6 | * | ||
7 | */ | ||
8 | /* EC3104 note: | ||
9 | * This code was written without any documentation about the EC3104 chip. While | ||
10 | * I hope I got most of the basic functionality right, the register names I use | ||
11 | * are most likely completely different from those in the chip documentation. | ||
12 | * | ||
13 | * If you have any further information about the EC3104, please tell me | ||
14 | * (prumpf@tux.org). | ||
15 | */ | ||
16 | |||
17 | #include <linux/sched.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/param.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include <asm/io.h> | ||
26 | #include <asm/irq.h> | ||
27 | #include <asm/machvec.h> | ||
28 | #include <asm/mach/ec3104.h> | ||
29 | |||
30 | const char *get_system_type(void) | ||
31 | { | ||
32 | return "EC3104"; | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * The Machine Vector | ||
37 | */ | ||
38 | |||
39 | struct sh_machine_vector mv_ec3104 __initmv = { | ||
40 | .mv_nr_irqs = 96, | ||
41 | |||
42 | .mv_inb = ec3104_inb, | ||
43 | .mv_inw = ec3104_inw, | ||
44 | .mv_inl = ec3104_inl, | ||
45 | .mv_outb = ec3104_outb, | ||
46 | .mv_outw = ec3104_outw, | ||
47 | .mv_outl = ec3104_outl, | ||
48 | |||
49 | .mv_irq_demux = ec3104_irq_demux, | ||
50 | }; | ||
51 | |||
52 | ALIAS_MV(ec3104) | ||
53 | |||
54 | int __init platform_setup(void) | ||
55 | { | ||
56 | char str[8]; | ||
57 | int i; | ||
58 | |||
59 | if (0) | ||
60 | return 0; | ||
61 | |||
62 | for (i=0; i<8; i++) | ||
63 | str[i] = ctrl_readb(EC3104_BASE + i); | ||
64 | |||
65 | for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++) | ||
66 | irq_desc[i].handler = &ec3104_int; | ||
67 | |||
68 | printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n", | ||
69 | str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE); | ||
70 | |||
71 | |||
72 | /* mask all interrupts. this should have been done by the boot | ||
73 | * loader for us but we want to be sure ... */ | ||
74 | ctrl_writel(0xffffffff, EC3104_IMR); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
diff --git a/arch/sh/boards/harp/Makefile b/arch/sh/boards/harp/Makefile new file mode 100644 index 000000000000..eb753d31812e --- /dev/null +++ b/arch/sh/boards/harp/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for STMicroelectronics board specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := irq.o setup.o mach.o led.o | ||
6 | |||
7 | obj-$(CONFIG_PCI) += pcidma.o | ||
8 | |||
diff --git a/arch/sh/boards/harp/irq.c b/arch/sh/boards/harp/irq.c new file mode 100644 index 000000000000..acd58489970f --- /dev/null +++ b/arch/sh/boards/harp/irq.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Looks after interrupts on the HARP board. | ||
8 | * | ||
9 | * Bases on the IPR irq system | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <asm/system.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/harp/harp.h> | ||
19 | |||
20 | |||
21 | #define NUM_EXTERNAL_IRQS 16 | ||
22 | |||
23 | // Early versions of the STB1 Overdrive required this nasty frig | ||
24 | //#define INVERT_INTMASK_WRITES | ||
25 | |||
26 | static void enable_harp_irq(unsigned int irq); | ||
27 | static void disable_harp_irq(unsigned int irq); | ||
28 | |||
29 | /* shutdown is same as "disable" */ | ||
30 | #define shutdown_harp_irq disable_harp_irq | ||
31 | |||
32 | static void mask_and_ack_harp(unsigned int); | ||
33 | static void end_harp_irq(unsigned int irq); | ||
34 | |||
35 | static unsigned int startup_harp_irq(unsigned int irq) | ||
36 | { | ||
37 | enable_harp_irq(irq); | ||
38 | return 0; /* never anything pending */ | ||
39 | } | ||
40 | |||
41 | static struct hw_interrupt_type harp_irq_type = { | ||
42 | "Harp-IRQ", | ||
43 | startup_harp_irq, | ||
44 | shutdown_harp_irq, | ||
45 | enable_harp_irq, | ||
46 | disable_harp_irq, | ||
47 | mask_and_ack_harp, | ||
48 | end_harp_irq | ||
49 | }; | ||
50 | |||
51 | static void disable_harp_irq(unsigned int irq) | ||
52 | { | ||
53 | unsigned val, flags; | ||
54 | unsigned maskReg; | ||
55 | unsigned mask; | ||
56 | int pri; | ||
57 | |||
58 | if (irq < 0 || irq >= NUM_EXTERNAL_IRQS) | ||
59 | return; | ||
60 | |||
61 | pri = 15 - irq; | ||
62 | |||
63 | if (pri < 8) { | ||
64 | maskReg = EPLD_INTMASK0; | ||
65 | } else { | ||
66 | maskReg = EPLD_INTMASK1; | ||
67 | pri -= 8; | ||
68 | } | ||
69 | |||
70 | local_irq_save(flags); | ||
71 | mask = ctrl_inl(maskReg); | ||
72 | mask &= (~(1 << pri)); | ||
73 | #if defined(INVERT_INTMASK_WRITES) | ||
74 | mask ^= 0xff; | ||
75 | #endif | ||
76 | ctrl_outl(mask, maskReg); | ||
77 | local_irq_restore(flags); | ||
78 | } | ||
79 | |||
80 | static void enable_harp_irq(unsigned int irq) | ||
81 | { | ||
82 | unsigned flags; | ||
83 | unsigned maskReg; | ||
84 | unsigned mask; | ||
85 | int pri; | ||
86 | |||
87 | if (irq < 0 || irq >= NUM_EXTERNAL_IRQS) | ||
88 | return; | ||
89 | |||
90 | pri = 15 - irq; | ||
91 | |||
92 | if (pri < 8) { | ||
93 | maskReg = EPLD_INTMASK0; | ||
94 | } else { | ||
95 | maskReg = EPLD_INTMASK1; | ||
96 | pri -= 8; | ||
97 | } | ||
98 | |||
99 | local_irq_save(flags); | ||
100 | mask = ctrl_inl(maskReg); | ||
101 | |||
102 | |||
103 | mask |= (1 << pri); | ||
104 | |||
105 | #if defined(INVERT_INTMASK_WRITES) | ||
106 | mask ^= 0xff; | ||
107 | #endif | ||
108 | ctrl_outl(mask, maskReg); | ||
109 | |||
110 | local_irq_restore(flags); | ||
111 | } | ||
112 | |||
113 | /* This functions sets the desired irq handler to be an overdrive type */ | ||
114 | static void __init make_harp_irq(unsigned int irq) | ||
115 | { | ||
116 | disable_irq_nosync(irq); | ||
117 | irq_desc[irq].handler = &harp_irq_type; | ||
118 | disable_harp_irq(irq); | ||
119 | } | ||
120 | |||
121 | static void mask_and_ack_harp(unsigned int irq) | ||
122 | { | ||
123 | disable_harp_irq(irq); | ||
124 | } | ||
125 | |||
126 | static void end_harp_irq(unsigned int irq) | ||
127 | { | ||
128 | enable_harp_irq(irq); | ||
129 | } | ||
130 | |||
131 | void __init init_harp_irq(void) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | #if !defined(INVERT_INTMASK_WRITES) | ||
136 | // On the harp these are set to enable an interrupt | ||
137 | ctrl_outl(0x00, EPLD_INTMASK0); | ||
138 | ctrl_outl(0x00, EPLD_INTMASK1); | ||
139 | #else | ||
140 | // On the Overdrive the data is inverted before being stored in the reg | ||
141 | ctrl_outl(0xff, EPLD_INTMASK0); | ||
142 | ctrl_outl(0xff, EPLD_INTMASK1); | ||
143 | #endif | ||
144 | |||
145 | for (i = 0; i < NUM_EXTERNAL_IRQS; i++) { | ||
146 | make_harp_irq(i); | ||
147 | } | ||
148 | } | ||
diff --git a/arch/sh/boards/harp/led.c b/arch/sh/boards/harp/led.c new file mode 100644 index 000000000000..76ca4ccac703 --- /dev/null +++ b/arch/sh/boards/harp/led.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/stboards/led.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * This file contains ST40STB1 HARP and compatible code. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/harp/harp.h> | ||
15 | |||
16 | /* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */ | ||
17 | /* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */ | ||
18 | /* Works for HARP and overdrive */ | ||
19 | static void mach_led(int position, int value) | ||
20 | { | ||
21 | if (value) { | ||
22 | ctrl_outl(EPLD_LED_ON, EPLD_LED); | ||
23 | } else { | ||
24 | ctrl_outl(EPLD_LED_OFF, EPLD_LED); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | #ifdef CONFIG_HEARTBEAT | ||
29 | |||
30 | #include <linux/sched.h> | ||
31 | |||
32 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
33 | void heartbeat_harp(void) | ||
34 | { | ||
35 | static unsigned cnt = 0, period = 0, dist = 0; | ||
36 | |||
37 | if (cnt == 0 || cnt == dist) | ||
38 | mach_led( -1, 1); | ||
39 | else if (cnt == 7 || cnt == dist+7) | ||
40 | mach_led( -1, 0); | ||
41 | |||
42 | if (++cnt > period) { | ||
43 | cnt = 0; | ||
44 | /* The hyperbolic function below modifies the heartbeat period | ||
45 | * length in dependency of the current (5min) load. It goes | ||
46 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
47 | * f(inf)->30. */ | ||
48 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
49 | dist = period / 4; | ||
50 | } | ||
51 | } | ||
52 | #endif | ||
diff --git a/arch/sh/boards/harp/mach.c b/arch/sh/boards/harp/mach.c new file mode 100644 index 000000000000..a946dd1674ca --- /dev/null +++ b/arch/sh/boards/harp/mach.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/harp/mach.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the STMicroelectronics STB1 HARP and compatible boards | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/rtc.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | #include <asm/hd64465/io.h> | ||
18 | #include <asm/hd64465/hd64465.h> | ||
19 | |||
20 | void setup_harp(void); | ||
21 | void init_harp_irq(void); | ||
22 | void heartbeat_harp(void); | ||
23 | |||
24 | /* | ||
25 | * The Machine Vector | ||
26 | */ | ||
27 | |||
28 | struct sh_machine_vector mv_harp __initmv = { | ||
29 | .mv_nr_irqs = 89 + HD64465_IRQ_NUM, | ||
30 | |||
31 | .mv_inb = hd64465_inb, | ||
32 | .mv_inw = hd64465_inw, | ||
33 | .mv_inl = hd64465_inl, | ||
34 | .mv_outb = hd64465_outb, | ||
35 | .mv_outw = hd64465_outw, | ||
36 | .mv_outl = hd64465_outl, | ||
37 | |||
38 | .mv_inb_p = hd64465_inb_p, | ||
39 | .mv_inw_p = hd64465_inw, | ||
40 | .mv_inl_p = hd64465_inl, | ||
41 | .mv_outb_p = hd64465_outb_p, | ||
42 | .mv_outw_p = hd64465_outw, | ||
43 | .mv_outl_p = hd64465_outl, | ||
44 | |||
45 | .mv_insb = hd64465_insb, | ||
46 | .mv_insw = hd64465_insw, | ||
47 | .mv_insl = hd64465_insl, | ||
48 | .mv_outsb = hd64465_outsb, | ||
49 | .mv_outsw = hd64465_outsw, | ||
50 | .mv_outsl = hd64465_outsl, | ||
51 | |||
52 | .mv_isa_port2addr = hd64465_isa_port2addr, | ||
53 | |||
54 | #ifdef CONFIG_PCI | ||
55 | .mv_init_irq = init_harp_irq, | ||
56 | #endif | ||
57 | #ifdef CONFIG_HEARTBEAT | ||
58 | .mv_heartbeat = heartbeat_harp, | ||
59 | #endif | ||
60 | }; | ||
61 | |||
62 | ALIAS_MV(harp) | ||
diff --git a/arch/sh/boards/harp/pcidma.c b/arch/sh/boards/harp/pcidma.c new file mode 100644 index 000000000000..475311390fd6 --- /dev/null +++ b/arch/sh/boards/harp/pcidma.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Dynamic DMA mapping support. | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/addrspace.h> | ||
16 | |||
17 | |||
18 | void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, | ||
19 | dma_addr_t * dma_handle) | ||
20 | { | ||
21 | void *ret; | ||
22 | int gfp = GFP_ATOMIC; | ||
23 | |||
24 | ret = (void *) __get_free_pages(gfp, get_order(size)); | ||
25 | |||
26 | if (ret != NULL) { | ||
27 | /* Is it neccessary to do the memset? */ | ||
28 | memset(ret, 0, size); | ||
29 | *dma_handle = virt_to_bus(ret); | ||
30 | } | ||
31 | /* We must flush the cache before we pass it on to the device */ | ||
32 | flush_cache_all(); | ||
33 | return P2SEGADDR(ret); | ||
34 | } | ||
35 | |||
36 | void pci_free_consistent(struct pci_dev *hwdev, size_t size, | ||
37 | void *vaddr, dma_addr_t dma_handle) | ||
38 | { | ||
39 | unsigned long p1addr=P1SEGADDR((unsigned long)vaddr); | ||
40 | |||
41 | free_pages(p1addr, get_order(size)); | ||
42 | } | ||
diff --git a/arch/sh/boards/harp/setup.c b/arch/sh/boards/harp/setup.c new file mode 100644 index 000000000000..05b01b8f40aa --- /dev/null +++ b/arch/sh/boards/harp/setup.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * arch/sh/stboard/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * STMicroelectronics ST40STB1 HARP and compatible support. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/harp/harp.h> | ||
17 | |||
18 | const char *get_system_type(void) | ||
19 | { | ||
20 | return "STB1 Harp"; | ||
21 | } | ||
22 | |||
23 | /* | ||
24 | * Initialize the board | ||
25 | */ | ||
26 | int __init platform_setup(void) | ||
27 | { | ||
28 | #ifdef CONFIG_SH_STB1_HARP | ||
29 | unsigned long ic8_version, ic36_version; | ||
30 | |||
31 | ic8_version = ctrl_inl(EPLD_REVID2); | ||
32 | ic36_version = ctrl_inl(EPLD_REVID1); | ||
33 | |||
34 | printk("STMicroelectronics STB1 HARP initialisaton\n"); | ||
35 | printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n", | ||
36 | (ic8_version >> 4) & 0xf, ic8_version & 0xf, | ||
37 | (ic36_version >> 4) & 0xf, ic36_version & 0xf); | ||
38 | #elif defined(CONFIG_SH_STB1_OVERDRIVE) | ||
39 | unsigned long version; | ||
40 | |||
41 | version = ctrl_inl(EPLD_REVID); | ||
42 | |||
43 | printk("STMicroelectronics STB1 Overdrive initialisaton\n"); | ||
44 | printk("EPLD version: %d.%02d\n", | ||
45 | (version >> 4) & 0xf, version & 0xf); | ||
46 | #else | ||
47 | #error Undefined machine | ||
48 | #endif | ||
49 | |||
50 | /* Currently all STB1 chips have problems with the sleep instruction, | ||
51 | * so disable it here. | ||
52 | */ | ||
53 | disable_hlt(); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * pcibios_map_platform_irq | ||
60 | * | ||
61 | * This is board specific and returns the IRQ for a given PCI device. | ||
62 | * It is used by the PCI code (arch/sh/kernel/st40_pci*) | ||
63 | * | ||
64 | */ | ||
65 | |||
66 | #define HARP_PCI_IRQ 1 | ||
67 | #define HARP_BRIDGE_IRQ 2 | ||
68 | #define OVERDRIVE_SLOT0_IRQ 0 | ||
69 | |||
70 | |||
71 | int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
72 | { | ||
73 | switch (slot) { | ||
74 | #ifdef CONFIG_SH_STB1_HARP | ||
75 | case 2: /*This is the PCI slot on the */ | ||
76 | return HARP_PCI_IRQ; | ||
77 | case 1: /* this is the bridge */ | ||
78 | return HARP_BRIDGE_IRQ; | ||
79 | #elif defined(CONFIG_SH_STB1_OVERDRIVE) | ||
80 | case 1: | ||
81 | case 2: | ||
82 | case 3: | ||
83 | return slot - 1; | ||
84 | #else | ||
85 | #error Unknown board | ||
86 | #endif | ||
87 | default: | ||
88 | return -1; | ||
89 | } | ||
90 | } | ||
91 | |||
diff --git a/arch/sh/boards/hp6xx/hp620/Makefile b/arch/sh/boards/hp6xx/hp620/Makefile new file mode 100644 index 000000000000..20691dbce347 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp620/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the HP620 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o setup.o | ||
6 | |||
diff --git a/arch/sh/boards/hp6xx/hp620/mach.c b/arch/sh/boards/hp6xx/hp620/mach.c new file mode 100644 index 000000000000..0392d82b4a7b --- /dev/null +++ b/arch/sh/boards/hp6xx/hp620/mach.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/hp6xx/hp620/mach.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the HP620 | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/rtc.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | |||
18 | #include <asm/io.h> | ||
19 | #include <asm/hd64461/hd64461.h> | ||
20 | #include <asm/irq.h> | ||
21 | |||
22 | /* | ||
23 | * The Machine Vector | ||
24 | */ | ||
25 | |||
26 | struct sh_machine_vector mv_hp620 __initmv = { | ||
27 | .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM, | ||
28 | |||
29 | .mv_inb = hd64461_inb, | ||
30 | .mv_inw = hd64461_inw, | ||
31 | .mv_inl = hd64461_inl, | ||
32 | .mv_outb = hd64461_outb, | ||
33 | .mv_outw = hd64461_outw, | ||
34 | .mv_outl = hd64461_outl, | ||
35 | |||
36 | .mv_inb_p = hd64461_inb_p, | ||
37 | .mv_inw_p = hd64461_inw, | ||
38 | .mv_inl_p = hd64461_inl, | ||
39 | .mv_outb_p = hd64461_outb_p, | ||
40 | .mv_outw_p = hd64461_outw, | ||
41 | .mv_outl_p = hd64461_outl, | ||
42 | |||
43 | .mv_insb = hd64461_insb, | ||
44 | .mv_insw = hd64461_insw, | ||
45 | .mv_insl = hd64461_insl, | ||
46 | .mv_outsb = hd64461_outsb, | ||
47 | .mv_outsw = hd64461_outsw, | ||
48 | .mv_outsl = hd64461_outsl, | ||
49 | |||
50 | .mv_irq_demux = hd64461_irq_demux, | ||
51 | }; | ||
52 | ALIAS_MV(hp620) | ||
diff --git a/arch/sh/boards/hp6xx/hp620/setup.c b/arch/sh/boards/hp6xx/hp620/setup.c new file mode 100644 index 000000000000..045fc5da7274 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp620/setup.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/hp6xx/hp620/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Andriy Skulysh, 2005 Kristoffer Ericson | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See Linux/COPYING for more information. | ||
8 | * | ||
9 | * Setup code for an HP620. | ||
10 | * Due to similiarity with hp680/hp690 same inits are done (for now) | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/hd64461/hd64461.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/hp6xx/hp6xx.h> | ||
18 | #include <asm/cpu/dac.h> | ||
19 | |||
20 | const char *get_system_type(void) | ||
21 | { | ||
22 | return "HP620"; | ||
23 | } | ||
24 | |||
25 | int __init platform_setup(void) | ||
26 | { | ||
27 | u16 v; | ||
28 | |||
29 | v = inw(HD64461_STBCR); | ||
30 | v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST | | ||
31 | HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST | | ||
32 | HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST | | ||
33 | HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST | | ||
34 | HD64461_STBCR_SAFECKE_IST; | ||
35 | outw(v, HD64461_STBCR); | ||
36 | |||
37 | v = inw(HD64461_GPADR); | ||
38 | v |= HD64461_GPADR_SPEAKER | HD64461_GPADR_PCMCIA0; | ||
39 | outw(v, HD64461_GPADR); | ||
40 | |||
41 | sh_dac_disable(DAC_SPEAKER_VOLUME); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
diff --git a/arch/sh/boards/hp6xx/hp680/Makefile b/arch/sh/boards/hp6xx/hp680/Makefile new file mode 100644 index 000000000000..0beef11d9b11 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp680/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the HP680 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o setup.o | ||
6 | |||
diff --git a/arch/sh/boards/hp6xx/hp680/mach.c b/arch/sh/boards/hp6xx/hp680/mach.c new file mode 100644 index 000000000000..d73486136045 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp680/mach.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/hp6xx/hp680/mach.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the HP680 | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/rtc.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | |||
18 | #include <asm/io.h> | ||
19 | #include <asm/hd64461/hd64461.h> | ||
20 | #include <asm/hp6xx/io.h> | ||
21 | #include <asm/irq.h> | ||
22 | |||
23 | struct sh_machine_vector mv_hp680 __initmv = { | ||
24 | .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM, | ||
25 | |||
26 | .mv_inb = hd64461_inb, | ||
27 | .mv_inw = hd64461_inw, | ||
28 | .mv_inl = hd64461_inl, | ||
29 | .mv_outb = hd64461_outb, | ||
30 | .mv_outw = hd64461_outw, | ||
31 | .mv_outl = hd64461_outl, | ||
32 | |||
33 | .mv_inb_p = hd64461_inb_p, | ||
34 | .mv_inw_p = hd64461_inw, | ||
35 | .mv_inl_p = hd64461_inl, | ||
36 | .mv_outb_p = hd64461_outb_p, | ||
37 | .mv_outw_p = hd64461_outw, | ||
38 | .mv_outl_p = hd64461_outl, | ||
39 | |||
40 | .mv_insb = hd64461_insb, | ||
41 | .mv_insw = hd64461_insw, | ||
42 | .mv_insl = hd64461_insl, | ||
43 | .mv_outsb = hd64461_outsb, | ||
44 | .mv_outsw = hd64461_outsw, | ||
45 | .mv_outsl = hd64461_outsl, | ||
46 | |||
47 | .mv_readw = hd64461_readw, | ||
48 | .mv_writew = hd64461_writew, | ||
49 | |||
50 | .mv_irq_demux = hd64461_irq_demux, | ||
51 | }; | ||
52 | |||
53 | ALIAS_MV(hp680) | ||
diff --git a/arch/sh/boards/hp6xx/hp680/setup.c b/arch/sh/boards/hp6xx/hp680/setup.c new file mode 100644 index 000000000000..4170190f2644 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp680/setup.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/hp6xx/hp680/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Andriy Skulysh | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Setup code for an HP680 (internal peripherials only) | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <asm/hd64461/hd64461.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/hp6xx/hp6xx.h> | ||
17 | #include <asm/cpu/dac.h> | ||
18 | |||
19 | const char *get_system_type(void) | ||
20 | { | ||
21 | return "HP680"; | ||
22 | } | ||
23 | |||
24 | int __init platform_setup(void) | ||
25 | { | ||
26 | u16 v; | ||
27 | v = inw(HD64461_STBCR); | ||
28 | v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST | | ||
29 | HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST | | ||
30 | HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST | | ||
31 | HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST | | ||
32 | HD64461_STBCR_SAFECKE_IST; | ||
33 | outw(v, HD64461_STBCR); | ||
34 | v = inw(HD64461_GPADR); | ||
35 | v |= HD64461_GPADR_SPEAKER | HD64461_GPADR_PCMCIA0; | ||
36 | outw(v, HD64461_GPADR); | ||
37 | |||
38 | sh_dac_disable(DAC_SPEAKER_VOLUME); | ||
39 | |||
40 | return 0; | ||
41 | } | ||
diff --git a/arch/sh/boards/hp6xx/hp690/Makefile b/arch/sh/boards/hp6xx/hp690/Makefile new file mode 100644 index 000000000000..fbbe95e75f83 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp690/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the HP690 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o | ||
6 | |||
diff --git a/arch/sh/boards/hp6xx/hp690/mach.c b/arch/sh/boards/hp6xx/hp690/mach.c new file mode 100644 index 000000000000..2a4c68783cd6 --- /dev/null +++ b/arch/sh/boards/hp6xx/hp690/mach.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/hp6xx/hp690/mach.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the HP690 | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/rtc.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | |||
18 | #include <asm/io.h> | ||
19 | #include <asm/hd64461/hd64461.h> | ||
20 | #include <asm/irq.h> | ||
21 | |||
22 | struct sh_machine_vector mv_hp690 __initmv = { | ||
23 | .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM, | ||
24 | |||
25 | .mv_inb = hd64461_inb, | ||
26 | .mv_inw = hd64461_inw, | ||
27 | .mv_inl = hd64461_inl, | ||
28 | .mv_outb = hd64461_outb, | ||
29 | .mv_outw = hd64461_outw, | ||
30 | .mv_outl = hd64461_outl, | ||
31 | |||
32 | .mv_inb_p = hd64461_inb_p, | ||
33 | .mv_inw_p = hd64461_inw, | ||
34 | .mv_inl_p = hd64461_inl, | ||
35 | .mv_outb_p = hd64461_outb_p, | ||
36 | .mv_outw_p = hd64461_outw, | ||
37 | .mv_outl_p = hd64461_outl, | ||
38 | |||
39 | .mv_insb = hd64461_insb, | ||
40 | .mv_insw = hd64461_insw, | ||
41 | .mv_insl = hd64461_insl, | ||
42 | .mv_outsb = hd64461_outsb, | ||
43 | .mv_outsw = hd64461_outsw, | ||
44 | .mv_outsl = hd64461_outsl, | ||
45 | |||
46 | .mv_irq_demux = hd64461_irq_demux, | ||
47 | }; | ||
48 | ALIAS_MV(hp690) | ||
diff --git a/arch/sh/boards/mpc1211/Makefile b/arch/sh/boards/mpc1211/Makefile new file mode 100644 index 000000000000..1644ebed78cb --- /dev/null +++ b/arch/sh/boards/mpc1211/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the Interface (CTP/PCI/MPC-SH02) specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o rtc.o led.o | ||
6 | |||
7 | obj-$(CONFIG_PCI) += pci.o | ||
8 | |||
diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c new file mode 100644 index 000000000000..0a31beec3465 --- /dev/null +++ b/arch/sh/boards/mpc1211/led.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/led_mpc1211.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Saito.K & Jeanne | ||
5 | * | ||
6 | * This file contains Interface MPC-1211 specific LED code. | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | |||
11 | static void mach_led(int position, int value) | ||
12 | { | ||
13 | volatile unsigned char* p = (volatile unsigned char*)0xa2000000; | ||
14 | |||
15 | if (value) { | ||
16 | *p |= 1; | ||
17 | } else { | ||
18 | *p &= ~1; | ||
19 | } | ||
20 | } | ||
21 | |||
22 | #ifdef CONFIG_HEARTBEAT | ||
23 | |||
24 | #include <linux/sched.h> | ||
25 | |||
26 | /* Cycle the LED's in the clasic Knightrider/Sun pattern */ | ||
27 | void heartbeat_mpc1211(void) | ||
28 | { | ||
29 | static unsigned int cnt = 0, period = 0; | ||
30 | volatile unsigned char* p = (volatile unsigned char*)0xa2000000; | ||
31 | static unsigned bit = 0, up = 1; | ||
32 | |||
33 | cnt += 1; | ||
34 | if (cnt < period) { | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | cnt = 0; | ||
39 | |||
40 | /* Go through the points (roughly!): | ||
41 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
42 | */ | ||
43 | period = 110 - ( (300<<FSHIFT)/ | ||
44 | ((avenrun[0]/5) + (3<<FSHIFT)) ); | ||
45 | |||
46 | if (up) { | ||
47 | if (bit == 7) { | ||
48 | bit--; | ||
49 | up=0; | ||
50 | } else { | ||
51 | bit ++; | ||
52 | } | ||
53 | } else { | ||
54 | if (bit == 0) { | ||
55 | bit++; | ||
56 | up=1; | ||
57 | } else { | ||
58 | bit--; | ||
59 | } | ||
60 | } | ||
61 | *p = 1<<bit; | ||
62 | |||
63 | } | ||
64 | #endif /* CONFIG_HEARTBEAT */ | ||
diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c new file mode 100644 index 000000000000..ba3a65439752 --- /dev/null +++ b/arch/sh/boards/mpc1211/pci.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * Low-Level PCI Support for the MPC-1211(CTP/PCI/MPC-SH02) | ||
3 | * | ||
4 | * (c) 2002-2003 Saito.K & Jeanne | ||
5 | * | ||
6 | * Dustin McIntire (dustin@sensoria.com) | ||
7 | * Derived from arch/i386/kernel/pci-*.c which bore the message: | ||
8 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> | ||
9 | * | ||
10 | * May be copied or modified under the terms of the GNU General Public | ||
11 | * License. See linux/COPYING for more information. | ||
12 | * | ||
13 | */ | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | |||
26 | #include <asm/machvec.h> | ||
27 | #include <asm/io.h> | ||
28 | #include <asm/mpc1211/pci.h> | ||
29 | |||
30 | static struct resource mpcpci_io_resource = { | ||
31 | "MPCPCI IO", | ||
32 | 0x00000000, | ||
33 | 0xffffffff, | ||
34 | IORESOURCE_IO | ||
35 | }; | ||
36 | |||
37 | static struct resource mpcpci_mem_resource = { | ||
38 | "MPCPCI mem", | ||
39 | 0x00000000, | ||
40 | 0xffffffff, | ||
41 | IORESOURCE_MEM | ||
42 | }; | ||
43 | |||
44 | static struct pci_ops pci_direct_conf1; | ||
45 | struct pci_channel board_pci_channels[] = { | ||
46 | {&pci_direct_conf1, &mpcpci_io_resource, &mpcpci_mem_resource, 0, 256}, | ||
47 | {NULL, NULL, NULL, 0, 0}, | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * Direct access to PCI hardware... | ||
52 | */ | ||
53 | |||
54 | |||
55 | #define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
56 | |||
57 | /* | ||
58 | * Functions for accessing PCI configuration space with type 1 accesses | ||
59 | */ | ||
60 | static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) | ||
61 | { | ||
62 | u32 word; | ||
63 | unsigned long flags; | ||
64 | |||
65 | /* | ||
66 | * PCIPDR may only be accessed as 32 bit words, | ||
67 | * so we must do byte alignment by hand | ||
68 | */ | ||
69 | local_irq_save(flags); | ||
70 | writel(CONFIG_CMD(bus,devfn,where), PCIPAR); | ||
71 | word = readl(PCIPDR); | ||
72 | local_irq_restore(flags); | ||
73 | |||
74 | switch (size) { | ||
75 | case 1: | ||
76 | switch (where & 0x3) { | ||
77 | case 3: | ||
78 | *value = (u8)(word >> 24); | ||
79 | break; | ||
80 | case 2: | ||
81 | *value = (u8)(word >> 16); | ||
82 | break; | ||
83 | case 1: | ||
84 | *value = (u8)(word >> 8); | ||
85 | break; | ||
86 | default: | ||
87 | *value = (u8)word; | ||
88 | break; | ||
89 | } | ||
90 | break; | ||
91 | case 2: | ||
92 | switch (where & 0x3) { | ||
93 | case 3: | ||
94 | *value = (u16)(word >> 24); | ||
95 | local_irq_save(flags); | ||
96 | writel(CONFIG_CMD(bus,devfn,(where+1)), PCIPAR); | ||
97 | word = readl(PCIPDR); | ||
98 | local_irq_restore(flags); | ||
99 | *value |= ((word & 0xff) << 8); | ||
100 | break; | ||
101 | case 2: | ||
102 | *value = (u16)(word >> 16); | ||
103 | break; | ||
104 | case 1: | ||
105 | *value = (u16)(word >> 8); | ||
106 | break; | ||
107 | default: | ||
108 | *value = (u16)word; | ||
109 | break; | ||
110 | } | ||
111 | break; | ||
112 | case 4: | ||
113 | *value = word; | ||
114 | break; | ||
115 | } | ||
116 | PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value); | ||
117 | return PCIBIOS_SUCCESSFUL; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Since MPC-1211 only does 32bit access we'll have to do a read,mask,write operation. | ||
122 | * We'll allow an odd byte offset, though it should be illegal. | ||
123 | */ | ||
124 | static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) | ||
125 | { | ||
126 | u32 word,mask = 0; | ||
127 | unsigned long flags; | ||
128 | u32 shift = (where & 3) * 8; | ||
129 | |||
130 | if(size == 1) { | ||
131 | mask = ((1 << 8) - 1) << shift; // create the byte mask | ||
132 | } else if(size == 2){ | ||
133 | if(shift == 24) | ||
134 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
135 | mask = ((1 << 16) - 1) << shift; // create the word mask | ||
136 | } | ||
137 | local_irq_save(flags); | ||
138 | writel(CONFIG_CMD(bus,devfn,where), PCIPAR); | ||
139 | if(size == 4){ | ||
140 | writel(value, PCIPDR); | ||
141 | local_irq_restore(flags); | ||
142 | PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value); | ||
143 | return PCIBIOS_SUCCESSFUL; | ||
144 | } | ||
145 | word = readl(PCIPDR); | ||
146 | word &= ~mask; | ||
147 | word |= ((value << shift) & mask); | ||
148 | writel(word, PCIPDR); | ||
149 | local_irq_restore(flags); | ||
150 | PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word); | ||
151 | return PCIBIOS_SUCCESSFUL; | ||
152 | } | ||
153 | |||
154 | #undef CONFIG_CMD | ||
155 | |||
156 | static struct pci_ops pci_direct_conf1 = { | ||
157 | .read = pci_conf1_read, | ||
158 | .write = pci_conf1_write, | ||
159 | }; | ||
160 | |||
161 | static void __devinit quirk_ali_ide_ports(struct pci_dev *dev) | ||
162 | { | ||
163 | dev->resource[0].start = 0x1f0; | ||
164 | dev->resource[0].end = 0x1f7; | ||
165 | dev->resource[0].flags = IORESOURCE_IO; | ||
166 | dev->resource[1].start = 0x3f6; | ||
167 | dev->resource[1].end = 0x3f6; | ||
168 | dev->resource[1].flags = IORESOURCE_IO; | ||
169 | dev->resource[2].start = 0x170; | ||
170 | dev->resource[2].end = 0x177; | ||
171 | dev->resource[2].flags = IORESOURCE_IO; | ||
172 | dev->resource[3].start = 0x376; | ||
173 | dev->resource[3].end = 0x376; | ||
174 | dev->resource[3].flags = IORESOURCE_IO; | ||
175 | dev->resource[4].start = 0xf000; | ||
176 | dev->resource[4].end = 0xf00f; | ||
177 | dev->resource[4].flags = IORESOURCE_IO; | ||
178 | } | ||
179 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports); | ||
180 | |||
181 | char * __devinit pcibios_setup(char *str) | ||
182 | { | ||
183 | return str; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Called after each bus is probed, but before its children | ||
188 | * are examined. | ||
189 | */ | ||
190 | |||
191 | void __init pcibios_fixup_bus(struct pci_bus *b) | ||
192 | { | ||
193 | pci_read_bridge_bases(b); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * IRQ functions | ||
198 | */ | ||
199 | static inline u8 bridge_swizzle(u8 pin, u8 slot) | ||
200 | { | ||
201 | return (((pin-1) + slot) % 4) + 1; | ||
202 | } | ||
203 | |||
204 | static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot) | ||
205 | { | ||
206 | return (((pin-1) - slot) & 3) + 1; | ||
207 | } | ||
208 | |||
209 | static u8 __init mpc1211_swizzle(struct pci_dev *dev, u8 *pinp) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | u8 pin = *pinp; | ||
213 | u32 word; | ||
214 | |||
215 | for ( ; dev->bus->self; dev = dev->bus->self) { | ||
216 | if (!pin) | ||
217 | continue; | ||
218 | |||
219 | if (dev->bus->number == 1) { | ||
220 | local_irq_save(flags); | ||
221 | writel(0x80000000 | 0x2c, PCIPAR); | ||
222 | word = readl(PCIPDR); | ||
223 | local_irq_restore(flags); | ||
224 | word >>= 16; | ||
225 | |||
226 | if (word == 0x0001) | ||
227 | pin = bridge_swizzle_pci_1(pin, PCI_SLOT(dev->devfn)); | ||
228 | else | ||
229 | pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); | ||
230 | } else | ||
231 | pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); | ||
232 | } | ||
233 | |||
234 | *pinp = pin; | ||
235 | |||
236 | return PCI_SLOT(dev->devfn); | ||
237 | } | ||
238 | |||
239 | static int __init map_mpc1211_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
240 | { | ||
241 | int irq = -1; | ||
242 | |||
243 | /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ | ||
244 | if (dev->bus->number == 0) { | ||
245 | switch (slot) { | ||
246 | case 13: irq = 9; break; /* USB */ | ||
247 | case 22: irq = 10; break; /* LAN */ | ||
248 | default: irq = 0; break; | ||
249 | } | ||
250 | } else { | ||
251 | switch (pin) { | ||
252 | case 0: irq = 0; break; | ||
253 | case 1: irq = 7; break; | ||
254 | case 2: irq = 9; break; | ||
255 | case 3: irq = 10; break; | ||
256 | case 4: irq = 11; break; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if( irq < 0 ) { | ||
261 | PCIDBG(3, "PCI: Error mapping IRQ on device %s\n", pci_name(dev)); | ||
262 | return irq; | ||
263 | } | ||
264 | |||
265 | PCIDBG(2, "Setting IRQ for slot %s to %d\n", pci_name(dev), irq); | ||
266 | |||
267 | return irq; | ||
268 | } | ||
269 | |||
270 | void __init pcibios_fixup_irqs(void) | ||
271 | { | ||
272 | pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq); | ||
273 | } | ||
274 | |||
275 | void pcibios_align_resource(void *data, struct resource *res, | ||
276 | unsigned long size, unsigned long align) | ||
277 | { | ||
278 | unsigned long start = res->start; | ||
279 | |||
280 | if (res->flags & IORESOURCE_IO) { | ||
281 | if (start >= 0x10000UL) { | ||
282 | if ((start & 0xffffUL) < 0x4000UL) { | ||
283 | start = (start & 0xffff0000UL) + 0x4000UL; | ||
284 | } else if ((start & 0xffffUL) >= 0xf000UL) { | ||
285 | start = (start & 0xffff0000UL) + 0x10000UL; | ||
286 | } | ||
287 | res->start = start; | ||
288 | } else { | ||
289 | if (start & 0x300) { | ||
290 | start = (start + 0x3ff) & ~0x3ff; | ||
291 | res->start = start; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c new file mode 100644 index 000000000000..4d100f048072 --- /dev/null +++ b/arch/sh/boards/mpc1211/rtc.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/rtc-mpc1211.c -- MPC-1211 on-chip RTC support | ||
3 | * | ||
4 | * Copyright (C) 2002 Saito.K & Jeanne | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/time.h> | ||
12 | #include <linux/mc146818rtc.h> | ||
13 | |||
14 | #ifndef BCD_TO_BIN | ||
15 | #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) | ||
16 | #endif | ||
17 | |||
18 | #ifndef BIN_TO_BCD | ||
19 | #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) | ||
20 | #endif | ||
21 | |||
22 | /* arc/i386/kernel/time.c */ | ||
23 | unsigned long get_cmos_time(void) | ||
24 | { | ||
25 | unsigned int year, mon, day, hour, min, sec; | ||
26 | int i; | ||
27 | |||
28 | spin_lock(&rtc_lock); | ||
29 | /* The Linux interpretation of the CMOS clock register contents: | ||
30 | * When the Update-In-Progress (UIP) flag goes from 1 to 0, the | ||
31 | * RTC registers show the second which has precisely just started. | ||
32 | * Let's hope other operating systems interpret the RTC the same way. | ||
33 | */ | ||
34 | /* read RTC exactly on falling edge of update flag */ | ||
35 | for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ | ||
36 | if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) | ||
37 | break; | ||
38 | for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ | ||
39 | if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) | ||
40 | break; | ||
41 | do { /* Isn't this overkill ? UIP above should guarantee consistency */ | ||
42 | sec = CMOS_READ(RTC_SECONDS); | ||
43 | min = CMOS_READ(RTC_MINUTES); | ||
44 | hour = CMOS_READ(RTC_HOURS); | ||
45 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
46 | mon = CMOS_READ(RTC_MONTH); | ||
47 | year = CMOS_READ(RTC_YEAR); | ||
48 | } while (sec != CMOS_READ(RTC_SECONDS)); | ||
49 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
50 | { | ||
51 | BCD_TO_BIN(sec); | ||
52 | BCD_TO_BIN(min); | ||
53 | BCD_TO_BIN(hour); | ||
54 | BCD_TO_BIN(day); | ||
55 | BCD_TO_BIN(mon); | ||
56 | BCD_TO_BIN(year); | ||
57 | } | ||
58 | spin_unlock(&rtc_lock); | ||
59 | if ((year += 1900) < 1970) | ||
60 | year += 100; | ||
61 | return mktime(year, mon, day, hour, min, sec); | ||
62 | } | ||
63 | |||
64 | void mpc1211_rtc_gettimeofday(struct timeval *tv) | ||
65 | { | ||
66 | |||
67 | tv->tv_sec = get_cmos_time(); | ||
68 | tv->tv_usec = 0; | ||
69 | } | ||
70 | |||
71 | /* arc/i386/kernel/time.c */ | ||
72 | /* | ||
73 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | ||
74 | * called 500 ms after the second nowtime has started, because when | ||
75 | * nowtime is written into the registers of the CMOS clock, it will | ||
76 | * jump to the next second precisely 500 ms later. Check the Motorola | ||
77 | * MC146818A or Dallas DS12887 data sheet for details. | ||
78 | * | ||
79 | * BUG: This routine does not handle hour overflow properly; it just | ||
80 | * sets the minutes. Usually you'll only notice that after reboot! | ||
81 | */ | ||
82 | static int set_rtc_mmss(unsigned long nowtime) | ||
83 | { | ||
84 | int retval = 0; | ||
85 | int real_seconds, real_minutes, cmos_minutes; | ||
86 | unsigned char save_control, save_freq_select; | ||
87 | |||
88 | /* gets recalled with irq locally disabled */ | ||
89 | spin_lock(&rtc_lock); | ||
90 | save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ | ||
91 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
92 | |||
93 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ | ||
94 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
95 | |||
96 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
97 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
98 | BCD_TO_BIN(cmos_minutes); | ||
99 | |||
100 | /* | ||
101 | * since we're only adjusting minutes and seconds, | ||
102 | * don't interfere with hour overflow. This avoids | ||
103 | * messing with unknown time zones but requires your | ||
104 | * RTC not to be off by more than 15 minutes | ||
105 | */ | ||
106 | real_seconds = nowtime % 60; | ||
107 | real_minutes = nowtime / 60; | ||
108 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
109 | real_minutes += 30; /* correct for half hour time zone */ | ||
110 | real_minutes %= 60; | ||
111 | |||
112 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
113 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
114 | BIN_TO_BCD(real_seconds); | ||
115 | BIN_TO_BCD(real_minutes); | ||
116 | } | ||
117 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
118 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
119 | } else { | ||
120 | printk(KERN_WARNING | ||
121 | "set_rtc_mmss: can't update from %d to %d\n", | ||
122 | cmos_minutes, real_minutes); | ||
123 | retval = -1; | ||
124 | } | ||
125 | |||
126 | /* The following flags have to be released exactly in this order, | ||
127 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
128 | * battery and quartz) will not reset the oscillator and will not | ||
129 | * update precisely 500 ms later. You won't find this mentioned in | ||
130 | * the Dallas Semiconductor data sheets, but who believes data | ||
131 | * sheets anyway ... -- Markus Kuhn | ||
132 | */ | ||
133 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
134 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
135 | spin_unlock(&rtc_lock); | ||
136 | |||
137 | return retval; | ||
138 | } | ||
139 | |||
140 | int mpc1211_rtc_settimeofday(const struct timeval *tv) | ||
141 | { | ||
142 | unsigned long nowtime = tv->tv_sec; | ||
143 | |||
144 | return set_rtc_mmss(nowtime); | ||
145 | } | ||
146 | |||
147 | void mpc1211_time_init(void) | ||
148 | { | ||
149 | rtc_get_time = mpc1211_rtc_gettimeofday; | ||
150 | rtc_set_time = mpc1211_rtc_settimeofday; | ||
151 | } | ||
152 | |||
diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c new file mode 100644 index 000000000000..2bb581b91683 --- /dev/null +++ b/arch/sh/boards/mpc1211/setup.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/board/mpc1211/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <linux/hdreg.h> | ||
12 | #include <linux/ide.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | |||
15 | #include <asm/io.h> | ||
16 | #include <asm/machvec.h> | ||
17 | #include <asm/mpc1211/mpc1211.h> | ||
18 | #include <asm/mpc1211/pci.h> | ||
19 | #include <asm/mpc1211/m1543c.h> | ||
20 | |||
21 | |||
22 | /* ALI15X3 SMBus address offsets */ | ||
23 | #define SMBHSTSTS (0 + 0x3100) | ||
24 | #define SMBHSTCNT (1 + 0x3100) | ||
25 | #define SMBHSTSTART (2 + 0x3100) | ||
26 | #define SMBHSTCMD (7 + 0x3100) | ||
27 | #define SMBHSTADD (3 + 0x3100) | ||
28 | #define SMBHSTDAT0 (4 + 0x3100) | ||
29 | #define SMBHSTDAT1 (5 + 0x3100) | ||
30 | #define SMBBLKDAT (6 + 0x3100) | ||
31 | |||
32 | /* Other settings */ | ||
33 | #define MAX_TIMEOUT 500 /* times 1/100 sec */ | ||
34 | |||
35 | /* ALI15X3 command constants */ | ||
36 | #define ALI15X3_ABORT 0x04 | ||
37 | #define ALI15X3_T_OUT 0x08 | ||
38 | #define ALI15X3_QUICK 0x00 | ||
39 | #define ALI15X3_BYTE 0x10 | ||
40 | #define ALI15X3_BYTE_DATA 0x20 | ||
41 | #define ALI15X3_WORD_DATA 0x30 | ||
42 | #define ALI15X3_BLOCK_DATA 0x40 | ||
43 | #define ALI15X3_BLOCK_CLR 0x80 | ||
44 | |||
45 | /* ALI15X3 status register bits */ | ||
46 | #define ALI15X3_STS_IDLE 0x04 | ||
47 | #define ALI15X3_STS_BUSY 0x08 | ||
48 | #define ALI15X3_STS_DONE 0x10 | ||
49 | #define ALI15X3_STS_DEV 0x20 /* device error */ | ||
50 | #define ALI15X3_STS_COLL 0x40 /* collision or no response */ | ||
51 | #define ALI15X3_STS_TERM 0x80 /* terminated by abort */ | ||
52 | #define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */ | ||
53 | |||
54 | const char *get_system_type(void) | ||
55 | { | ||
56 | return "Interface MPC-1211(CTP/PCI/MPC-SH02)"; | ||
57 | } | ||
58 | |||
59 | static void __init pci_write_config(unsigned long busNo, | ||
60 | unsigned long devNo, | ||
61 | unsigned long fncNo, | ||
62 | unsigned long cnfAdd, | ||
63 | unsigned long cnfData) | ||
64 | { | ||
65 | ctrl_outl((0x80000000 | ||
66 | + ((busNo & 0xff) << 16) | ||
67 | + ((devNo & 0x1f) << 11) | ||
68 | + ((fncNo & 0x07) << 8) | ||
69 | + (cnfAdd & 0xfc)), PCIPAR); | ||
70 | |||
71 | ctrl_outl(cnfData, PCIPDR); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | Initialize IRQ setting | ||
76 | */ | ||
77 | |||
78 | static unsigned char m_irq_mask = 0xfb; | ||
79 | static unsigned char s_irq_mask = 0xff; | ||
80 | volatile unsigned long irq_err_count; | ||
81 | |||
82 | static void disable_mpc1211_irq(unsigned int irq) | ||
83 | { | ||
84 | unsigned long flags; | ||
85 | |||
86 | save_and_cli(flags); | ||
87 | if( irq < 8) { | ||
88 | m_irq_mask |= (1 << irq); | ||
89 | outb(m_irq_mask,I8259_M_MR); | ||
90 | } else { | ||
91 | s_irq_mask |= (1 << (irq - 8)); | ||
92 | outb(s_irq_mask,I8259_S_MR); | ||
93 | } | ||
94 | restore_flags(flags); | ||
95 | |||
96 | } | ||
97 | |||
98 | static void enable_mpc1211_irq(unsigned int irq) | ||
99 | { | ||
100 | unsigned long flags; | ||
101 | |||
102 | save_and_cli(flags); | ||
103 | |||
104 | if( irq < 8) { | ||
105 | m_irq_mask &= ~(1 << irq); | ||
106 | outb(m_irq_mask,I8259_M_MR); | ||
107 | } else { | ||
108 | s_irq_mask &= ~(1 << (irq - 8)); | ||
109 | outb(s_irq_mask,I8259_S_MR); | ||
110 | } | ||
111 | restore_flags(flags); | ||
112 | } | ||
113 | |||
114 | static inline int mpc1211_irq_real(unsigned int irq) | ||
115 | { | ||
116 | int value; | ||
117 | int irqmask; | ||
118 | |||
119 | if ( irq < 8) { | ||
120 | irqmask = 1<<irq; | ||
121 | outb(0x0b,I8259_M_CR); /* ISR register */ | ||
122 | value = inb(I8259_M_CR) & irqmask; | ||
123 | outb(0x0a,I8259_M_CR); /* back ro the IPR reg */ | ||
124 | return value; | ||
125 | } | ||
126 | irqmask = 1<<(irq - 8); | ||
127 | outb(0x0b,I8259_S_CR); /* ISR register */ | ||
128 | value = inb(I8259_S_CR) & irqmask; | ||
129 | outb(0x0a,I8259_S_CR); /* back ro the IPR reg */ | ||
130 | return value; | ||
131 | } | ||
132 | |||
133 | static void mask_and_ack_mpc1211(unsigned int irq) | ||
134 | { | ||
135 | unsigned long flags; | ||
136 | |||
137 | save_and_cli(flags); | ||
138 | |||
139 | if(irq < 8) { | ||
140 | if(m_irq_mask & (1<<irq)){ | ||
141 | if(!mpc1211_irq_real(irq)){ | ||
142 | irq_err_count++; | ||
143 | printk("spurious 8259A interrupt: IRQ %x\n",irq); | ||
144 | } | ||
145 | } else { | ||
146 | m_irq_mask |= (1<<irq); | ||
147 | } | ||
148 | inb(I8259_M_MR); /* DUMMY */ | ||
149 | outb(m_irq_mask,I8259_M_MR); /* disable */ | ||
150 | outb(0x60+irq,I8259_M_CR); /* EOI */ | ||
151 | |||
152 | } else { | ||
153 | if(s_irq_mask & (1<<(irq - 8))){ | ||
154 | if(!mpc1211_irq_real(irq)){ | ||
155 | irq_err_count++; | ||
156 | printk("spurious 8259A interrupt: IRQ %x\n",irq); | ||
157 | } | ||
158 | } else { | ||
159 | s_irq_mask |= (1<<(irq - 8)); | ||
160 | } | ||
161 | inb(I8259_S_MR); /* DUMMY */ | ||
162 | outb(s_irq_mask,I8259_S_MR); /* disable */ | ||
163 | outb(0x60+(irq-8),I8259_S_CR); /* EOI */ | ||
164 | outb(0x60+2,I8259_M_CR); | ||
165 | } | ||
166 | restore_flags(flags); | ||
167 | } | ||
168 | |||
169 | static void end_mpc1211_irq(unsigned int irq) | ||
170 | { | ||
171 | enable_mpc1211_irq(irq); | ||
172 | } | ||
173 | |||
174 | static unsigned int startup_mpc1211_irq(unsigned int irq) | ||
175 | { | ||
176 | enable_mpc1211_irq(irq); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static void shutdown_mpc1211_irq(unsigned int irq) | ||
181 | { | ||
182 | disable_mpc1211_irq(irq); | ||
183 | } | ||
184 | |||
185 | static struct hw_interrupt_type mpc1211_irq_type = { | ||
186 | .typename = "MPC1211-IRQ", | ||
187 | .startup = startup_mpc1211_irq, | ||
188 | .shutdown = shutdown_mpc1211_irq, | ||
189 | .enable = enable_mpc1211_irq, | ||
190 | .disable = disable_mpc1211_irq, | ||
191 | .ack = mask_and_ack_mpc1211, | ||
192 | .end = end_mpc1211_irq | ||
193 | }; | ||
194 | |||
195 | static void make_mpc1211_irq(unsigned int irq) | ||
196 | { | ||
197 | irq_desc[irq].handler = &mpc1211_irq_type; | ||
198 | irq_desc[irq].status = IRQ_DISABLED; | ||
199 | irq_desc[irq].action = 0; | ||
200 | irq_desc[irq].depth = 1; | ||
201 | disable_mpc1211_irq(irq); | ||
202 | } | ||
203 | |||
204 | int mpc1211_irq_demux(int irq) | ||
205 | { | ||
206 | unsigned int poll; | ||
207 | |||
208 | if( irq == 2 ) { | ||
209 | outb(0x0c,I8259_M_CR); | ||
210 | poll = inb(I8259_M_CR); | ||
211 | if(poll & 0x80) { | ||
212 | irq = (poll & 0x07); | ||
213 | } | ||
214 | if( irq == 2) { | ||
215 | outb(0x0c,I8259_S_CR); | ||
216 | poll = inb(I8259_S_CR); | ||
217 | irq = (poll & 0x07) + 8; | ||
218 | } | ||
219 | } | ||
220 | return irq; | ||
221 | } | ||
222 | |||
223 | void __init init_mpc1211_IRQ(void) | ||
224 | { | ||
225 | int i; | ||
226 | /* | ||
227 | * Super I/O (Just mimic PC): | ||
228 | * 1: keyboard | ||
229 | * 3: serial 1 | ||
230 | * 4: serial 0 | ||
231 | * 5: printer | ||
232 | * 6: floppy | ||
233 | * 8: rtc | ||
234 | * 10: lan | ||
235 | * 12: mouse | ||
236 | * 14: ide0 | ||
237 | * 15: ide1 | ||
238 | */ | ||
239 | |||
240 | pci_write_config(0,0,0,0x54, 0xb0b0002d); | ||
241 | outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */ | ||
242 | outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */ | ||
243 | outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */ | ||
244 | outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */ | ||
245 | outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */ | ||
246 | outb(0x02, I8259_S_MR); /* s icw3 slave id */ | ||
247 | outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/ | ||
248 | outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/ | ||
249 | outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */ | ||
250 | outb(0xff, I8259_S_MR); /* disable irq8--irq15 */ | ||
251 | |||
252 | for ( i=0; i < 16; i++) { | ||
253 | if(i != 2) { | ||
254 | make_mpc1211_irq(i); | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | Initialize the board | ||
261 | */ | ||
262 | |||
263 | |||
264 | static void delay (void) | ||
265 | { | ||
266 | volatile unsigned short tmp; | ||
267 | tmp = *(volatile unsigned short *) 0xa0000000; | ||
268 | } | ||
269 | |||
270 | static void delay1000 (void) | ||
271 | { | ||
272 | int i; | ||
273 | |||
274 | for (i=0; i<1000; i++) | ||
275 | delay (); | ||
276 | } | ||
277 | |||
278 | static int put_smb_blk(unsigned char *p, int address, int command, int no) | ||
279 | { | ||
280 | int temp; | ||
281 | int timeout; | ||
282 | int i; | ||
283 | |||
284 | outb(0xff, SMBHSTSTS); | ||
285 | temp = inb(SMBHSTSTS); | ||
286 | for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) { | ||
287 | delay1000(); | ||
288 | temp = inb(SMBHSTSTS); | ||
289 | } | ||
290 | if (timeout >= MAX_TIMEOUT){ | ||
291 | return -1; | ||
292 | } | ||
293 | |||
294 | outb(((address & 0x7f) << 1), SMBHSTADD); | ||
295 | outb(0xc0, SMBHSTCNT); | ||
296 | outb(command & 0xff, SMBHSTCMD); | ||
297 | outb(no & 0x1f, SMBHSTDAT0); | ||
298 | |||
299 | for(i = 1; i <= no; i++) { | ||
300 | outb(*p++, SMBBLKDAT); | ||
301 | } | ||
302 | outb(0xff, SMBHSTSTART); | ||
303 | |||
304 | temp = inb(SMBHSTSTS); | ||
305 | for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) { | ||
306 | delay1000(); | ||
307 | temp = inb(SMBHSTSTS); | ||
308 | } | ||
309 | if (timeout >= MAX_TIMEOUT) { | ||
310 | return -2; | ||
311 | } | ||
312 | if ( temp & ALI15X3_STS_ERR ){ | ||
313 | return -3; | ||
314 | } | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * The Machine Vector | ||
320 | */ | ||
321 | |||
322 | struct sh_machine_vector mv_mpc1211 __initmv = { | ||
323 | .mv_nr_irqs = 48, | ||
324 | .mv_irq_demux = mpc1211_irq_demux, | ||
325 | .mv_init_irq = init_mpc1211_IRQ, | ||
326 | |||
327 | #ifdef CONFIG_HEARTBEAT | ||
328 | .mv_heartbeat = heartbeat_mpc1211, | ||
329 | #endif | ||
330 | }; | ||
331 | |||
332 | ALIAS_MV(mpc1211) | ||
333 | |||
334 | /* arch/sh/boards/mpc1211/rtc.c */ | ||
335 | void mpc1211_time_init(void); | ||
336 | |||
337 | int __init platform_setup(void) | ||
338 | { | ||
339 | unsigned char spd_buf[128]; | ||
340 | |||
341 | __set_io_port_base(PA_PCI_IO); | ||
342 | |||
343 | pci_write_config(0,0,0,0x54, 0xb0b00000); | ||
344 | |||
345 | do { | ||
346 | outb(ALI15X3_ABORT, SMBHSTCNT); | ||
347 | spd_buf[0] = 0x0c; | ||
348 | spd_buf[1] = 0x43; | ||
349 | spd_buf[2] = 0x7f; | ||
350 | spd_buf[3] = 0x03; | ||
351 | spd_buf[4] = 0x00; | ||
352 | spd_buf[5] = 0x03; | ||
353 | spd_buf[6] = 0x00; | ||
354 | } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0); | ||
355 | |||
356 | board_time_init = mpc1211_time_init; | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
diff --git a/arch/sh/boards/overdrive/Makefile b/arch/sh/boards/overdrive/Makefile new file mode 100644 index 000000000000..1762b59e9279 --- /dev/null +++ b/arch/sh/boards/overdrive/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the STMicroelectronics Overdrive specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o setup.o io.o irq.o led.o time.o | ||
6 | |||
7 | obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o | ||
8 | |||
diff --git a/arch/sh/boards/overdrive/fpga.c b/arch/sh/boards/overdrive/fpga.c new file mode 100644 index 000000000000..3a1ec9403441 --- /dev/null +++ b/arch/sh/boards/overdrive/fpga.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * This file handles programming up the Altera Flex10K that interfaces to | ||
8 | * the Galileo, and does the PS/2 keyboard and mouse | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/smp.h> | ||
16 | #include <linux/smp_lock.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/delay.h> | ||
21 | |||
22 | |||
23 | #include <asm/overdriver/gt64111.h> | ||
24 | #include <asm/overdrive/overdrive.h> | ||
25 | #include <asm/overdrive/fpga.h> | ||
26 | |||
27 | #define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT | ||
28 | #define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK | ||
29 | |||
30 | /* I need to find out what (if any) the real delay factor here is */ | ||
31 | /* The delay is definately not critical */ | ||
32 | #define long_delay() {int i;for(i=0;i<10000;i++);} | ||
33 | #define short_delay() {int i;for(i=0;i<100;i++);} | ||
34 | |||
35 | static void __init program_overdrive_fpga(const unsigned char *fpgacode, | ||
36 | int size) | ||
37 | { | ||
38 | int timeout = 0; | ||
39 | int i, j; | ||
40 | unsigned char b; | ||
41 | static volatile unsigned char *FPGA_ControlReg = | ||
42 | (volatile unsigned char *) (OVERDRIVE_CTRL); | ||
43 | static volatile unsigned char *FPGA_ProgramReg = | ||
44 | (volatile unsigned char *) (FPGA_DCLK_ADDRESS); | ||
45 | |||
46 | printk("FPGA: Commencing FPGA Programming\n"); | ||
47 | |||
48 | /* The PCI reset but MUST be low when programming the FPGA !!! */ | ||
49 | b = (*FPGA_ControlReg) & RESET_PCI_MASK; | ||
50 | |||
51 | (*FPGA_ControlReg) = b; | ||
52 | |||
53 | /* Prepare FPGA to program */ | ||
54 | |||
55 | FPGA_NotConfigHigh(); | ||
56 | long_delay(); | ||
57 | |||
58 | FPGA_NotConfigLow(); | ||
59 | short_delay(); | ||
60 | |||
61 | while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) { | ||
62 | printk("FPGA: Waiting for NotStatus to go Low ... \n"); | ||
63 | } | ||
64 | |||
65 | FPGA_NotConfigHigh(); | ||
66 | |||
67 | /* Wait for FPGA "ready to be programmed" signal */ | ||
68 | printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n"); | ||
69 | |||
70 | for (timeout = 0; | ||
71 | (((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0) | ||
72 | && (timeout < FPGA_TIMEOUT)); timeout++); | ||
73 | |||
74 | /* Check if timeout condition occured - i.e. an error */ | ||
75 | |||
76 | if (timeout == FPGA_TIMEOUT) { | ||
77 | printk | ||
78 | ("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | printk("FPGA: Copying data to FPGA ... %d bytes\n", size); | ||
83 | |||
84 | /* Copy array to FPGA - bit at a time */ | ||
85 | |||
86 | for (i = 0; i < size; i++) { | ||
87 | volatile unsigned w = 0; | ||
88 | |||
89 | for (j = 0; j < 8; j++) { | ||
90 | *FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01; | ||
91 | short_delay(); | ||
92 | } | ||
93 | if ((i & 0x3ff) == 0) { | ||
94 | printk("."); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /* Waiting for CONFDONE to go high - means the program is complete */ | ||
99 | |||
100 | for (timeout = 0; | ||
101 | (((*FPGA_ProgramReg & FPGA_CONFDONE) == 0) | ||
102 | && (timeout < FPGA_TIMEOUT)); timeout++) { | ||
103 | |||
104 | *FPGA_ProgramReg = 0x0; | ||
105 | long_delay(); | ||
106 | } | ||
107 | |||
108 | if (timeout == FPGA_TIMEOUT) { | ||
109 | printk | ||
110 | ("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n"); | ||
111 | return; | ||
112 | } else { /* Clock another 10 times - gets the device into a working state */ | ||
113 | for (i = 0; i < 10; i++) { | ||
114 | *FPGA_ProgramReg = 0x0; | ||
115 | short_delay(); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | printk("FPGA: Programming complete\n"); | ||
120 | } | ||
121 | |||
122 | |||
123 | static const unsigned char __init fpgacode[] = { | ||
124 | #include "./overdrive.ttf" /* Code from maxplus2 compiler */ | ||
125 | , 0, 0 | ||
126 | }; | ||
127 | |||
128 | |||
129 | int __init init_overdrive_fpga(void) | ||
130 | { | ||
131 | program_overdrive_fpga(fpgacode, sizeof(fpgacode)); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
diff --git a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c new file mode 100644 index 000000000000..276fa11ee4ce --- /dev/null +++ b/arch/sh/boards/overdrive/galileo.c | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * This file contains the PCI routines required for the Galileo GT6411 | ||
8 | * PCI bridge as used on the Orion and Overdrive boards. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/ioport.h> | ||
22 | |||
23 | #include <asm/overdrive/overdrive.h> | ||
24 | #include <asm/overdrive/gt64111.h> | ||
25 | |||
26 | |||
27 | /* After boot, we shift the Galileo registers so that they appear | ||
28 | * in BANK6, along with IO space. This means we can have one contingous | ||
29 | * lump of PCI address space without these registers appearing in the | ||
30 | * middle of them | ||
31 | */ | ||
32 | |||
33 | #define GT64111_BASE_ADDRESS 0xbb000000 | ||
34 | #define GT64111_IO_BASE_ADDRESS 0x1000 | ||
35 | /* The GT64111 registers appear at this address to the SH4 after reset */ | ||
36 | #define RESET_GT64111_BASE_ADDRESS 0xb4000000 | ||
37 | |||
38 | /* Macros used to access the Galileo registers */ | ||
39 | #define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x) | ||
40 | #define GT64111_REG(x) (GT64111_BASE_ADDRESS+x) | ||
41 | |||
42 | #define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x)) | ||
43 | |||
44 | #define RESET_GT_READ(x) readl(RESET_GT64111_REG(x)) | ||
45 | |||
46 | #define GT_WRITE(x,v) writel((v),GT64111_REG(x)) | ||
47 | #define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x)) | ||
48 | #define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x)) | ||
49 | |||
50 | #define GT_READ(x) readl(GT64111_REG(x)) | ||
51 | #define GT_READ_BYTE(x) readb(GT64111_REG(x)) | ||
52 | #define GT_READ_SHORT(x) readw(GT64111_REG(x)) | ||
53 | |||
54 | |||
55 | /* Where the various SH banks start at */ | ||
56 | #define SH_BANK4_ADR 0xb0000000 | ||
57 | #define SH_BANK5_ADR 0xb4000000 | ||
58 | #define SH_BANK6_ADR 0xb8000000 | ||
59 | |||
60 | /* Masks out everything but lines 28,27,26 */ | ||
61 | #define BANK_SELECT_MASK 0x1c000000 | ||
62 | |||
63 | #define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK) | ||
64 | |||
65 | /* | ||
66 | * Masks used for address conversaion. Bank 6 is used for IO and | ||
67 | * has all the address bits zeroed by the FPGA. Special case this | ||
68 | */ | ||
69 | #define MEMORY_BANK_MASK 0x1fffffff | ||
70 | #define IO_BANK_MASK 0x03ffffff | ||
71 | |||
72 | /* Mark bank 6 as the bank used for IO. You can change this in the FPGA code | ||
73 | * if you want | ||
74 | */ | ||
75 | #define IO_BANK_ADR PCI_GTIO_BASE | ||
76 | |||
77 | /* Will select the correct mask to apply depending on the SH$ address */ | ||
78 | #define SELECT_BANK_MASK(x) \ | ||
79 | ( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK) | ||
80 | |||
81 | /* Converts between PCI space and P2 region */ | ||
82 | #define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x)) | ||
83 | |||
84 | /* Various macros for figuring out what to stick in the Galileo registers. | ||
85 | * You *really* don't want to figure this stuff out by hand, you always get | ||
86 | * it wrong | ||
87 | */ | ||
88 | #define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff) | ||
89 | #define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f) | ||
90 | #define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff) | ||
91 | |||
92 | #define PROGRAM_HI_LO(block,a,s) \ | ||
93 | GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\ | ||
94 | GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1)) | ||
95 | |||
96 | #define PROGRAM_SUB_HI_LO(block,a,s) \ | ||
97 | GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\ | ||
98 | GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1)) | ||
99 | |||
100 | /* We need to set the size, and the offset register */ | ||
101 | |||
102 | #define GT_BAR_MASK(x) ((x)&~0xfff) | ||
103 | |||
104 | /* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */ | ||
105 | #define PROGRAM_GT_BAR(block,a,s) \ | ||
106 | GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\ | ||
107 | write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\ | ||
108 | GT_BAR_MASK(a)) | ||
109 | |||
110 | #define DISABLE_GT_BAR(block) \ | ||
111 | GT_WRITE(PCI_##block##_BANK_SIZE,0),\ | ||
112 | GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\ | ||
113 | 0x80000000) | ||
114 | |||
115 | /* Macros to disable things we are not going to use */ | ||
116 | #define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\ | ||
117 | GT_WRITE(x##_HI_DEC_ADR,0x00) | ||
118 | |||
119 | #define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\ | ||
120 | GT_WRITE(x##_HI_DEC_ADR,0x00) | ||
121 | |||
122 | static void __init reset_pci(void) | ||
123 | { | ||
124 | /* Set RESET_PCI bit high */ | ||
125 | writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL); | ||
126 | udelay(250); | ||
127 | |||
128 | /* Set RESET_PCI bit low */ | ||
129 | writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL); | ||
130 | udelay(250); | ||
131 | |||
132 | writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL); | ||
133 | udelay(250); | ||
134 | } | ||
135 | |||
136 | static int write_config_to_galileo(int where, u32 val); | ||
137 | #define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val) | ||
138 | |||
139 | #define ENABLE_PCI_DRAM | ||
140 | |||
141 | |||
142 | #ifdef TEST_DRAM | ||
143 | /* Test function to check out if the PCI DRAM is working OK */ | ||
144 | static int /* __init */ test_dram(unsigned *base, unsigned size) | ||
145 | { | ||
146 | unsigned *p = base; | ||
147 | unsigned *end = (unsigned *) (((unsigned) base) + size); | ||
148 | unsigned w; | ||
149 | |||
150 | for (p = base; p < end; p++) { | ||
151 | *p = 0xffffffff; | ||
152 | if (*p != 0xffffffff) { | ||
153 | printk("AAARGH -write failed!!! at %p is %x\n", p, | ||
154 | *p); | ||
155 | return 0; | ||
156 | } | ||
157 | *p = 0x0; | ||
158 | if (*p != 0x0) { | ||
159 | printk("AAARGH -write failed!!!\n"); | ||
160 | return 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | for (p = base; p < end; p++) { | ||
165 | *p = (unsigned) p; | ||
166 | if (*p != (unsigned) p) { | ||
167 | printk("Failed at 0x%p, actually is 0x%x\n", p, | ||
168 | *p); | ||
169 | return 0; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | for (p = base; p < end; p++) { | ||
174 | w = ((unsigned) p & 0xffff0000); | ||
175 | *p = w | (w >> 16); | ||
176 | } | ||
177 | |||
178 | for (p = base; p < end; p++) { | ||
179 | w = ((unsigned) p & 0xffff0000); | ||
180 | w |= (w >> 16); | ||
181 | if (*p != w) { | ||
182 | printk | ||
183 | ("Failed at 0x%p, should be 0x%x actually is 0x%x\n", | ||
184 | p, w, *p); | ||
185 | return 0; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | return 1; | ||
190 | } | ||
191 | #endif | ||
192 | |||
193 | |||
194 | /* Function to set up and initialise the galileo. This sets up the BARS, | ||
195 | * maps the DRAM into the address space etc,etc | ||
196 | */ | ||
197 | int __init galileo_init(void) | ||
198 | { | ||
199 | reset_pci(); | ||
200 | |||
201 | /* Now shift the galileo regs into this block */ | ||
202 | RESET_GT_WRITE(INTERNAL_SPACE_DEC, | ||
203 | GT_MEM_LO_ADR(GT64111_BASE_ADDRESS)); | ||
204 | |||
205 | /* Should have a sanity check here, that you can read back at the new | ||
206 | * address what you just wrote | ||
207 | */ | ||
208 | |||
209 | /* Disable decode for all regions */ | ||
210 | DISABLE_DECODE(RAS10); | ||
211 | DISABLE_DECODE(RAS32); | ||
212 | DISABLE_DECODE(CS20); | ||
213 | DISABLE_DECODE(CS3); | ||
214 | DISABLE_DECODE(PCI_IO); | ||
215 | DISABLE_DECODE(PCI_MEM0); | ||
216 | DISABLE_DECODE(PCI_MEM1); | ||
217 | |||
218 | /* Disable all BARS */ | ||
219 | GT_WRITE(BAR_ENABLE_ADR, 0x1ff); | ||
220 | DISABLE_GT_BAR(RAS10); | ||
221 | DISABLE_GT_BAR(RAS32); | ||
222 | DISABLE_GT_BAR(CS20); | ||
223 | DISABLE_GT_BAR(CS3); | ||
224 | |||
225 | /* Tell the BAR where the IO registers now are */ | ||
226 | GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK( | ||
227 | (GT64111_IO_BASE_ADDRESS & | ||
228 | IO_BANK_MASK))); | ||
229 | /* set up a 112 Mb decode */ | ||
230 | PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024); | ||
231 | |||
232 | /* Set up a 32 MB io space decode */ | ||
233 | PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024); | ||
234 | |||
235 | #ifdef ENABLE_PCI_DRAM | ||
236 | /* Program up the DRAM configuration - there is DRAM only in bank 0 */ | ||
237 | /* Now set up the DRAM decode */ | ||
238 | PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE); | ||
239 | /* And the sub decode */ | ||
240 | PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE); | ||
241 | |||
242 | DISABLE_SUB_DECODE(RAS1); | ||
243 | |||
244 | /* Set refresh rate */ | ||
245 | GT_WRITE(DRAM_BANK0_PARMS, 0x3f); | ||
246 | GT_WRITE(DRAM_CFG, 0x100); | ||
247 | |||
248 | /* we have to lob off the top bits rememeber!! */ | ||
249 | PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE); | ||
250 | |||
251 | #endif | ||
252 | |||
253 | /* We are only interested in decoding RAS10 and the Galileo's internal | ||
254 | * registers (as IO) on the PCI bus | ||
255 | */ | ||
256 | #ifdef ENABLE_PCI_DRAM | ||
257 | GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff); | ||
258 | #else | ||
259 | GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff); | ||
260 | #endif | ||
261 | |||
262 | /* Change the class code to host bridge, it actually powers up | ||
263 | * as a memory controller | ||
264 | */ | ||
265 | GT_CONFIG_WRITE(8, 0x06000011); | ||
266 | |||
267 | /* Allow the galileo to master the PCI bus */ | ||
268 | GT_CONFIG_WRITE(PCI_COMMAND, | ||
269 | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | ||
270 | PCI_COMMAND_IO); | ||
271 | |||
272 | |||
273 | #if 0 | ||
274 | printk("Testing PCI DRAM - "); | ||
275 | if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) { | ||
276 | printk("Passed\n"); | ||
277 | }else { | ||
278 | printk("FAILED\n"); | ||
279 | } | ||
280 | #endif | ||
281 | return 0; | ||
282 | |||
283 | } | ||
284 | |||
285 | |||
286 | #define SET_CONFIG_BITS(bus,devfn,where)\ | ||
287 | ((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3)) | ||
288 | |||
289 | #define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where) | ||
290 | |||
291 | /* This write to the galileo config registers, unlike the functions below, can | ||
292 | * be used before the PCI subsystem has started up | ||
293 | */ | ||
294 | static int __init write_config_to_galileo(int where, u32 val) | ||
295 | { | ||
296 | GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where)); | ||
297 | |||
298 | GT_WRITE(PCI_CFG_DATA, val); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* We exclude the galileo and slot 31, the galileo because I don't know how to stop | ||
303 | * the setup code shagging up the setup I have done on it, and 31 because the whole | ||
304 | * thing locks up if you try to access that slot (which doesn't exist of course anyway | ||
305 | */ | ||
306 | |||
307 | #define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31))) | ||
308 | |||
309 | static int galileo_read_config_byte(struct pci_dev *dev, int where, | ||
310 | u8 * val) | ||
311 | { | ||
312 | |||
313 | |||
314 | /* I suspect this doesn't work because this drives a special cycle ? */ | ||
315 | if (EXCLUDED_DEV(dev)) { | ||
316 | *val = 0xff; | ||
317 | return PCIBIOS_SUCCESSFUL; | ||
318 | } | ||
319 | /* Start the config cycle */ | ||
320 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
321 | /* Read back the result */ | ||
322 | *val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3)); | ||
323 | |||
324 | return PCIBIOS_SUCCESSFUL; | ||
325 | } | ||
326 | |||
327 | |||
328 | static int galileo_read_config_word(struct pci_dev *dev, int where, | ||
329 | u16 * val) | ||
330 | { | ||
331 | |||
332 | if (EXCLUDED_DEV(dev)) { | ||
333 | *val = 0xffff; | ||
334 | return PCIBIOS_SUCCESSFUL; | ||
335 | } | ||
336 | |||
337 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
338 | *val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2)); | ||
339 | |||
340 | return PCIBIOS_SUCCESSFUL; | ||
341 | } | ||
342 | |||
343 | |||
344 | static int galileo_read_config_dword(struct pci_dev *dev, int where, | ||
345 | u32 * val) | ||
346 | { | ||
347 | if (EXCLUDED_DEV(dev)) { | ||
348 | *val = 0xffffffff; | ||
349 | return PCIBIOS_SUCCESSFUL; | ||
350 | } | ||
351 | |||
352 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
353 | *val = GT_READ(PCI_CFG_DATA); | ||
354 | |||
355 | return PCIBIOS_SUCCESSFUL; | ||
356 | } | ||
357 | |||
358 | static int galileo_write_config_byte(struct pci_dev *dev, int where, | ||
359 | u8 val) | ||
360 | { | ||
361 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
362 | |||
363 | GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val); | ||
364 | |||
365 | return PCIBIOS_SUCCESSFUL; | ||
366 | } | ||
367 | |||
368 | |||
369 | static int galileo_write_config_word(struct pci_dev *dev, int where, | ||
370 | u16 val) | ||
371 | { | ||
372 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
373 | |||
374 | GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val); | ||
375 | |||
376 | return PCIBIOS_SUCCESSFUL; | ||
377 | } | ||
378 | |||
379 | static int galileo_write_config_dword(struct pci_dev *dev, int where, | ||
380 | u32 val) | ||
381 | { | ||
382 | GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where)); | ||
383 | |||
384 | GT_WRITE(PCI_CFG_DATA, val); | ||
385 | |||
386 | return PCIBIOS_SUCCESSFUL; | ||
387 | } | ||
388 | |||
389 | static struct pci_ops pci_config_ops = { | ||
390 | galileo_read_config_byte, | ||
391 | galileo_read_config_word, | ||
392 | galileo_read_config_dword, | ||
393 | galileo_write_config_byte, | ||
394 | galileo_write_config_word, | ||
395 | galileo_write_config_dword | ||
396 | }; | ||
397 | |||
398 | |||
399 | /* Everything hangs off this */ | ||
400 | static struct pci_bus *pci_root_bus; | ||
401 | |||
402 | |||
403 | static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) | ||
404 | { | ||
405 | return PCI_SLOT(dev->devfn); | ||
406 | } | ||
407 | |||
408 | static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
409 | { | ||
410 | /* Slot 1: Galileo | ||
411 | * Slot 2: PCI Slot 1 | ||
412 | * Slot 3: PCI Slot 2 | ||
413 | * Slot 4: ESS | ||
414 | */ | ||
415 | switch (slot) { | ||
416 | case 2: | ||
417 | return OVERDRIVE_PCI_IRQ1; | ||
418 | case 3: | ||
419 | /* Note this assumes you have a hacked card in slot 2 */ | ||
420 | return OVERDRIVE_PCI_IRQ2; | ||
421 | case 4: | ||
422 | return OVERDRIVE_ESS_IRQ; | ||
423 | default: | ||
424 | /* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */ | ||
425 | return -1; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | |||
430 | |||
431 | void __init | ||
432 | pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) | ||
433 | { | ||
434 | ranges->io_start -= bus->resource[0]->start; | ||
435 | ranges->io_end -= bus->resource[0]->start; | ||
436 | ranges->mem_start -= bus->resource[1]->start; | ||
437 | ranges->mem_end -= bus->resource[1]->start; | ||
438 | } | ||
439 | |||
440 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | ||
441 | { | ||
442 | int i; | ||
443 | |||
444 | /* | ||
445 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | ||
446 | */ | ||
447 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
448 | return; | ||
449 | printk("PCI: IDE base address fixup for %s\n", pci_name(d)); | ||
450 | for(i=0; i<4; i++) { | ||
451 | struct resource *r = &d->resource[i]; | ||
452 | if ((r->start & ~0x80) == 0x374) { | ||
453 | r->start |= 2; | ||
454 | r->end = r->start; | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | ||
459 | |||
460 | void __init pcibios_init(void) | ||
461 | { | ||
462 | static struct resource galio,galmem; | ||
463 | |||
464 | /* Allocate the registers used by the Galileo */ | ||
465 | galio.flags = IORESOURCE_IO; | ||
466 | galio.name = "Galileo GT64011"; | ||
467 | galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH; | ||
468 | galmem.name = "Galileo GT64011 DRAM"; | ||
469 | |||
470 | allocate_resource(&ioport_resource, &galio, 256, | ||
471 | GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL); | ||
472 | allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE, | ||
473 | PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE, | ||
474 | PCI_DRAM_SIZE, NULL, NULL); | ||
475 | |||
476 | /* ok, do the scan man */ | ||
477 | pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL); | ||
478 | |||
479 | pci_assign_unassigned_resources(); | ||
480 | pci_fixup_irqs(no_swizzle, map_od_irq); | ||
481 | |||
482 | #ifdef TEST_DRAM | ||
483 | printk("Testing PCI DRAM - "); | ||
484 | if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) { | ||
485 | printk("Passed\n"); | ||
486 | }else { | ||
487 | printk("FAILED\n"); | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | } | ||
492 | |||
493 | char * __init pcibios_setup(char *str) | ||
494 | { | ||
495 | return str; | ||
496 | } | ||
497 | |||
498 | |||
499 | |||
500 | int pcibios_enable_device(struct pci_dev *dev) | ||
501 | { | ||
502 | |||
503 | u16 cmd, old_cmd; | ||
504 | int idx; | ||
505 | struct resource *r; | ||
506 | |||
507 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
508 | old_cmd = cmd; | ||
509 | for (idx = 0; idx < 6; idx++) { | ||
510 | r = dev->resource + idx; | ||
511 | if (!r->start && r->end) { | ||
512 | printk(KERN_ERR | ||
513 | "PCI: Device %s not available because" | ||
514 | " of resource collisions\n", | ||
515 | pci_name(dev)); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | if (r->flags & IORESOURCE_IO) | ||
519 | cmd |= PCI_COMMAND_IO; | ||
520 | if (r->flags & IORESOURCE_MEM) | ||
521 | cmd |= PCI_COMMAND_MEMORY; | ||
522 | } | ||
523 | if (cmd != old_cmd) { | ||
524 | printk("PCI: enabling device %s (%04x -> %04x)\n", | ||
525 | pci_name(dev), old_cmd, cmd); | ||
526 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
527 | } | ||
528 | return 0; | ||
529 | |||
530 | } | ||
531 | |||
532 | /* We should do some optimisation work here I think. Ok for now though */ | ||
533 | void __init pcibios_fixup_bus(struct pci_bus *bus) | ||
534 | { | ||
535 | |||
536 | } | ||
537 | |||
538 | void pcibios_align_resource(void *data, struct resource *res, | ||
539 | unsigned long size) | ||
540 | { | ||
541 | } | ||
542 | |||
543 | void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, | ||
544 | struct resource *res, int resource) | ||
545 | { | ||
546 | |||
547 | unsigned long where, size; | ||
548 | u32 reg; | ||
549 | |||
550 | |||
551 | printk("PCI: Assigning %3s %08lx to %s\n", | ||
552 | res->flags & IORESOURCE_IO ? "IO" : "MEM", | ||
553 | res->start, dev->name); | ||
554 | |||
555 | where = PCI_BASE_ADDRESS_0 + resource * 4; | ||
556 | size = res->end - res->start; | ||
557 | |||
558 | pci_read_config_dword(dev, where, ®); | ||
559 | reg = (reg & size) | (((u32) (res->start - root->start)) & ~size); | ||
560 | pci_write_config_dword(dev, where, reg); | ||
561 | } | ||
562 | |||
563 | |||
564 | void __init pcibios_update_irq(struct pci_dev *dev, int irq) | ||
565 | { | ||
566 | printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); | ||
567 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * If we set up a device for bus mastering, we need to check the latency | ||
572 | * timer as certain crappy BIOSes forget to set it properly. | ||
573 | */ | ||
574 | unsigned int pcibios_max_latency = 255; | ||
575 | |||
576 | void pcibios_set_master(struct pci_dev *dev) | ||
577 | { | ||
578 | u8 lat; | ||
579 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | ||
580 | if (lat < 16) | ||
581 | lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; | ||
582 | else if (lat > pcibios_max_latency) | ||
583 | lat = pcibios_max_latency; | ||
584 | else | ||
585 | return; | ||
586 | printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); | ||
587 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
588 | } | ||
diff --git a/arch/sh/boards/overdrive/io.c b/arch/sh/boards/overdrive/io.c new file mode 100644 index 000000000000..65f3fd0563d3 --- /dev/null +++ b/arch/sh/boards/overdrive/io.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * This file contains the I/O routines for use on the overdrive board | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <asm/processor.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/addrspace.h> | ||
17 | |||
18 | #include <asm/overdrive/overdrive.h> | ||
19 | |||
20 | /* | ||
21 | * readX/writeX() are used to access memory mapped devices. On some | ||
22 | * architectures the memory mapped IO stuff needs to be accessed | ||
23 | * differently. On the SuperH architecture, we just read/write the | ||
24 | * memory location directly. | ||
25 | */ | ||
26 | |||
27 | #define dprintk(x...) | ||
28 | |||
29 | /* Translates an IO address to where it is mapped in memory */ | ||
30 | |||
31 | #define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE) | ||
32 | |||
33 | unsigned char od_inb(unsigned long port) | ||
34 | { | ||
35 | dprintk("od_inb(%x)\n", port); | ||
36 | return readb(io_addr(port)) & 0xff; | ||
37 | } | ||
38 | |||
39 | |||
40 | unsigned short od_inw(unsigned long port) | ||
41 | { | ||
42 | dprintk("od_inw(%x)\n", port); | ||
43 | return readw(io_addr(port)) & 0xffff; | ||
44 | } | ||
45 | |||
46 | unsigned int od_inl(unsigned long port) | ||
47 | { | ||
48 | dprintk("od_inl(%x)\n", port); | ||
49 | return readl(io_addr(port)); | ||
50 | } | ||
51 | |||
52 | void od_outb(unsigned char value, unsigned long port) | ||
53 | { | ||
54 | dprintk("od_outb(%x, %x)\n", value, port); | ||
55 | writeb(value, io_addr(port)); | ||
56 | } | ||
57 | |||
58 | void od_outw(unsigned short value, unsigned long port) | ||
59 | { | ||
60 | dprintk("od_outw(%x, %x)\n", value, port); | ||
61 | writew(value, io_addr(port)); | ||
62 | } | ||
63 | |||
64 | void od_outl(unsigned int value, unsigned long port) | ||
65 | { | ||
66 | dprintk("od_outl(%x, %x)\n", value, port); | ||
67 | writel(value, io_addr(port)); | ||
68 | } | ||
69 | |||
70 | /* This is horrible at the moment - needs more work to do something sensible */ | ||
71 | #define IO_DELAY() udelay(10) | ||
72 | |||
73 | #define OUT_DELAY(x,type) \ | ||
74 | void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();} | ||
75 | |||
76 | #define IN_DELAY(x,type) \ | ||
77 | unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;} | ||
78 | |||
79 | |||
80 | OUT_DELAY(b,char) | ||
81 | OUT_DELAY(w,short) | ||
82 | OUT_DELAY(l,int) | ||
83 | |||
84 | IN_DELAY(b,char) | ||
85 | IN_DELAY(w,short) | ||
86 | IN_DELAY(l,int) | ||
87 | |||
88 | |||
89 | /* Now for the string version of these functions */ | ||
90 | void od_outsb(unsigned long port, const void *addr, unsigned long count) | ||
91 | { | ||
92 | int i; | ||
93 | unsigned char *p = (unsigned char *) addr; | ||
94 | |||
95 | for (i = 0; i < count; i++, p++) { | ||
96 | outb(*p, port); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | void od_insb(unsigned long port, void *addr, unsigned long count) | ||
102 | { | ||
103 | int i; | ||
104 | unsigned char *p = (unsigned char *) addr; | ||
105 | |||
106 | for (i = 0; i < count; i++, p++) { | ||
107 | *p = inb(port); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* For the 16 and 32 bit string functions, we have to worry about alignment. | ||
112 | * The SH does not do unaligned accesses, so we have to read as bytes and | ||
113 | * then write as a word or dword. | ||
114 | * This can be optimised a lot more, especially in the case where the data | ||
115 | * is aligned | ||
116 | */ | ||
117 | |||
118 | void od_outsw(unsigned long port, const void *addr, unsigned long count) | ||
119 | { | ||
120 | int i; | ||
121 | unsigned short tmp; | ||
122 | unsigned char *p = (unsigned char *) addr; | ||
123 | |||
124 | for (i = 0; i < count; i++, p += 2) { | ||
125 | tmp = (*p) | ((*(p + 1)) << 8); | ||
126 | outw(tmp, port); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | |||
131 | void od_insw(unsigned long port, void *addr, unsigned long count) | ||
132 | { | ||
133 | int i; | ||
134 | unsigned short tmp; | ||
135 | unsigned char *p = (unsigned char *) addr; | ||
136 | |||
137 | for (i = 0; i < count; i++, p += 2) { | ||
138 | tmp = inw(port); | ||
139 | p[0] = tmp & 0xff; | ||
140 | p[1] = (tmp >> 8) & 0xff; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | void od_outsl(unsigned long port, const void *addr, unsigned long count) | ||
146 | { | ||
147 | int i; | ||
148 | unsigned tmp; | ||
149 | unsigned char *p = (unsigned char *) addr; | ||
150 | |||
151 | for (i = 0; i < count; i++, p += 4) { | ||
152 | tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) | | ||
153 | ((*(p + 3)) << 24); | ||
154 | outl(tmp, port); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | |||
159 | void od_insl(unsigned long port, void *addr, unsigned long count) | ||
160 | { | ||
161 | int i; | ||
162 | unsigned tmp; | ||
163 | unsigned char *p = (unsigned char *) addr; | ||
164 | |||
165 | for (i = 0; i < count; i++, p += 4) { | ||
166 | tmp = inl(port); | ||
167 | p[0] = tmp & 0xff; | ||
168 | p[1] = (tmp >> 8) & 0xff; | ||
169 | p[2] = (tmp >> 16) & 0xff; | ||
170 | p[3] = (tmp >> 24) & 0xff; | ||
171 | |||
172 | } | ||
173 | } | ||
diff --git a/arch/sh/boards/overdrive/irq.c b/arch/sh/boards/overdrive/irq.c new file mode 100644 index 000000000000..23adc6be71e7 --- /dev/null +++ b/arch/sh/boards/overdrive/irq.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Looks after interrupts on the overdrive board. | ||
8 | * | ||
9 | * Bases on the IPR irq system | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <asm/system.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #include <asm/overdrive/overdrive.h> | ||
20 | |||
21 | struct od_data { | ||
22 | int overdrive_irq; | ||
23 | int irq_mask; | ||
24 | }; | ||
25 | |||
26 | #define NUM_EXTERNAL_IRQS 16 | ||
27 | #define EXTERNAL_IRQ_NOT_IN_USE (-1) | ||
28 | #define EXTERNAL_IRQ_NOT_ASSIGNED (-1) | ||
29 | |||
30 | /* | ||
31 | * This table is used to determine what to program into the FPGA's CT register | ||
32 | * for the specified Linux IRQ. | ||
33 | * | ||
34 | * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0)) | ||
35 | * but is one greater than that because the because the FPGA treats 0 | ||
36 | * as disabled, a value of 1 asserts PCI_Int0, and so on. | ||
37 | * | ||
38 | * The overdrive_irq specifies which of the eight interrupt sources generates | ||
39 | * that interrupt, and but is multiplied by four to give the bit offset into | ||
40 | * the CT register. | ||
41 | * | ||
42 | * The seven interrupts levels (SH4 IRL's) we have available here is hardwired | ||
43 | * by the EPLD. The assignments here of which PCI interrupt generates each | ||
44 | * level is arbitary. | ||
45 | */ | ||
46 | static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = { | ||
47 | /* overdrive_irq , irq_mask */ | ||
48 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */ | ||
49 | {EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */ | ||
50 | {EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */ | ||
51 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */ | ||
52 | {EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */ | ||
53 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */ | ||
54 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */ | ||
55 | {EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */ | ||
56 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */ | ||
57 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */ | ||
58 | {EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */ | ||
59 | {EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */ | ||
60 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */ | ||
61 | {EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */ | ||
62 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */ | ||
63 | {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */ | ||
64 | }; | ||
65 | |||
66 | static void set_od_data(int overdrive_irq, int irq) | ||
67 | { | ||
68 | if (irq >= NUM_EXTERNAL_IRQS || irq < 0) | ||
69 | return; | ||
70 | od_data_table[irq].overdrive_irq = overdrive_irq << 2; | ||
71 | } | ||
72 | |||
73 | static void enable_od_irq(unsigned int irq); | ||
74 | void disable_od_irq(unsigned int irq); | ||
75 | |||
76 | /* shutdown is same as "disable" */ | ||
77 | #define shutdown_od_irq disable_od_irq | ||
78 | |||
79 | static void mask_and_ack_od(unsigned int); | ||
80 | static void end_od_irq(unsigned int irq); | ||
81 | |||
82 | static unsigned int startup_od_irq(unsigned int irq) | ||
83 | { | ||
84 | enable_od_irq(irq); | ||
85 | return 0; /* never anything pending */ | ||
86 | } | ||
87 | |||
88 | static struct hw_interrupt_type od_irq_type = { | ||
89 | "Overdrive-IRQ", | ||
90 | startup_od_irq, | ||
91 | shutdown_od_irq, | ||
92 | enable_od_irq, | ||
93 | disable_od_irq, | ||
94 | mask_and_ack_od, | ||
95 | end_od_irq | ||
96 | }; | ||
97 | |||
98 | static void disable_od_irq(unsigned int irq) | ||
99 | { | ||
100 | unsigned val, flags; | ||
101 | int overdrive_irq; | ||
102 | unsigned mask; | ||
103 | |||
104 | /* Not a valid interrupt */ | ||
105 | if (irq < 0 || irq >= NUM_EXTERNAL_IRQS) | ||
106 | return; | ||
107 | |||
108 | /* Is is necessary to use a cli here? Would a spinlock not be | ||
109 | * mroe efficient? | ||
110 | */ | ||
111 | local_irq_save(flags); | ||
112 | overdrive_irq = od_data_table[irq].overdrive_irq; | ||
113 | if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) { | ||
114 | mask = ~(0x7 << overdrive_irq); | ||
115 | val = ctrl_inl(OVERDRIVE_INT_CT); | ||
116 | val &= mask; | ||
117 | ctrl_outl(val, OVERDRIVE_INT_CT); | ||
118 | } | ||
119 | local_irq_restore(flags); | ||
120 | } | ||
121 | |||
122 | static void enable_od_irq(unsigned int irq) | ||
123 | { | ||
124 | unsigned val, flags; | ||
125 | int overdrive_irq; | ||
126 | unsigned mask; | ||
127 | |||
128 | /* Not a valid interrupt */ | ||
129 | if (irq < 0 || irq >= NUM_EXTERNAL_IRQS) | ||
130 | return; | ||
131 | |||
132 | /* Set priority in OD back to original value */ | ||
133 | local_irq_save(flags); | ||
134 | /* This one is not in use currently */ | ||
135 | overdrive_irq = od_data_table[irq].overdrive_irq; | ||
136 | if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) { | ||
137 | val = ctrl_inl(OVERDRIVE_INT_CT); | ||
138 | mask = ~(0x7 << overdrive_irq); | ||
139 | val &= mask; | ||
140 | mask = od_data_table[irq].irq_mask << overdrive_irq; | ||
141 | val |= mask; | ||
142 | ctrl_outl(val, OVERDRIVE_INT_CT); | ||
143 | } | ||
144 | local_irq_restore(flags); | ||
145 | } | ||
146 | |||
147 | |||
148 | |||
149 | /* this functions sets the desired irq handler to be an overdrive type */ | ||
150 | static void __init make_od_irq(unsigned int irq) | ||
151 | { | ||
152 | disable_irq_nosync(irq); | ||
153 | irq_desc[irq].handler = &od_irq_type; | ||
154 | disable_od_irq(irq); | ||
155 | } | ||
156 | |||
157 | |||
158 | static void mask_and_ack_od(unsigned int irq) | ||
159 | { | ||
160 | disable_od_irq(irq); | ||
161 | } | ||
162 | |||
163 | static void end_od_irq(unsigned int irq) | ||
164 | { | ||
165 | enable_od_irq(irq); | ||
166 | } | ||
167 | |||
168 | void __init init_overdrive_irq(void) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | /* Disable all interrupts */ | ||
173 | ctrl_outl(0, OVERDRIVE_INT_CT); | ||
174 | |||
175 | /* Update interrupt pin mode to use encoded interrupts */ | ||
176 | i = ctrl_inw(INTC_ICR); | ||
177 | i &= ~INTC_ICR_IRLM; | ||
178 | ctrl_outw(i, INTC_ICR); | ||
179 | |||
180 | for (i = 0; i < NUM_EXTERNAL_IRQS; i++) { | ||
181 | if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) { | ||
182 | make_od_irq(i); | ||
183 | } else if (i != 15) { // Cannot use imask on level 15 | ||
184 | make_imask_irq(i); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /* Set up the interrupts */ | ||
189 | set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1); | ||
190 | set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2); | ||
191 | set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ); | ||
192 | } | ||
diff --git a/arch/sh/boards/overdrive/led.c b/arch/sh/boards/overdrive/led.c new file mode 100644 index 000000000000..734742e92279 --- /dev/null +++ b/arch/sh/boards/overdrive/led.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/overdrive/led.c | ||
3 | * | ||
4 | * Copyright (C) 1999 Stuart Menefy <stuart.menefy@st.com> | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * This file contains an Overdrive specific LED feature. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/system.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/overdrive/overdrive.h> | ||
16 | |||
17 | static void mach_led(int position, int value) | ||
18 | { | ||
19 | unsigned long flags; | ||
20 | unsigned long reg; | ||
21 | |||
22 | local_irq_save(flags); | ||
23 | |||
24 | reg = readl(OVERDRIVE_CTRL); | ||
25 | if (value) { | ||
26 | reg |= (1<<3); | ||
27 | } else { | ||
28 | reg &= ~(1<<3); | ||
29 | } | ||
30 | writel(reg, OVERDRIVE_CTRL); | ||
31 | |||
32 | local_irq_restore(flags); | ||
33 | } | ||
34 | |||
35 | #ifdef CONFIG_HEARTBEAT | ||
36 | |||
37 | #include <linux/sched.h> | ||
38 | |||
39 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
40 | void heartbeat_od(void) | ||
41 | { | ||
42 | static unsigned cnt = 0, period = 0, dist = 0; | ||
43 | |||
44 | if (cnt == 0 || cnt == dist) | ||
45 | mach_led( -1, 1); | ||
46 | else if (cnt == 7 || cnt == dist+7) | ||
47 | mach_led( -1, 0); | ||
48 | |||
49 | if (++cnt > period) { | ||
50 | cnt = 0; | ||
51 | /* The hyperbolic function below modifies the heartbeat period | ||
52 | * length in dependency of the current (5min) load. It goes | ||
53 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
54 | * f(inf)->30. */ | ||
55 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
56 | dist = period / 4; | ||
57 | } | ||
58 | } | ||
59 | #endif /* CONFIG_HEARTBEAT */ | ||
diff --git a/arch/sh/boards/overdrive/mach.c b/arch/sh/boards/overdrive/mach.c new file mode 100644 index 000000000000..2834a03ae477 --- /dev/null +++ b/arch/sh/boards/overdrive/mach.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/overdrive/mach.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the STMicroelectronics Overdrive | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/rtc.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | |||
18 | #include <asm/io_unknown.h> | ||
19 | #include <asm/io_generic.h> | ||
20 | #include <asm/overdrive/io.h> | ||
21 | |||
22 | void heartbeat_od(void); | ||
23 | void init_overdrive_irq(void); | ||
24 | void galileo_pcibios_init(void); | ||
25 | |||
26 | /* | ||
27 | * The Machine Vector | ||
28 | */ | ||
29 | |||
30 | struct sh_machine_vector mv_od __initmv = { | ||
31 | .mv_nr_irqs = 48, | ||
32 | |||
33 | .mv_inb = od_inb, | ||
34 | .mv_inw = od_inw, | ||
35 | .mv_inl = od_inl, | ||
36 | .mv_outb = od_outb, | ||
37 | .mv_outw = od_outw, | ||
38 | .mv_outl = od_outl, | ||
39 | |||
40 | .mv_inb_p = od_inb_p, | ||
41 | .mv_inw_p = od_inw_p, | ||
42 | .mv_inl_p = od_inl_p, | ||
43 | .mv_outb_p = od_outb_p, | ||
44 | .mv_outw_p = od_outw_p, | ||
45 | .mv_outl_p = od_outl_p, | ||
46 | |||
47 | .mv_insb = od_insb, | ||
48 | .mv_insw = od_insw, | ||
49 | .mv_insl = od_insl, | ||
50 | .mv_outsb = od_outsb, | ||
51 | .mv_outsw = od_outsw, | ||
52 | .mv_outsl = od_outsl, | ||
53 | |||
54 | #ifdef CONFIG_PCI | ||
55 | .mv_init_irq = init_overdrive_irq, | ||
56 | #endif | ||
57 | #ifdef CONFIG_HEARTBEAT | ||
58 | .mv_heartbeat = heartbeat_od, | ||
59 | #endif | ||
60 | }; | ||
61 | |||
62 | ALIAS_MV(od) | ||
diff --git a/arch/sh/boards/overdrive/pcidma.c b/arch/sh/boards/overdrive/pcidma.c new file mode 100644 index 000000000000..1c9bfeda00b7 --- /dev/null +++ b/arch/sh/boards/overdrive/pcidma.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Dynamic DMA mapping support. | ||
8 | * | ||
9 | * On the overdrive, we can only DMA from memory behind the PCI bus! | ||
10 | * this means that all DMA'able memory must come from there. | ||
11 | * this restriction will not apply to later boards. | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, | ||
21 | dma_addr_t * dma_handle) | ||
22 | { | ||
23 | void *ret; | ||
24 | int gfp = GFP_ATOMIC; | ||
25 | |||
26 | printk("BUG: pci_alloc_consistent() called - not yet supported\n"); | ||
27 | /* We ALWAYS need DMA memory on the overdrive hardware, | ||
28 | * due to it's extreme weirdness | ||
29 | * Need to flush the cache here as well, since the memory | ||
30 | * can still be seen through the cache! | ||
31 | */ | ||
32 | gfp |= GFP_DMA; | ||
33 | ret = (void *) __get_free_pages(gfp, get_order(size)); | ||
34 | |||
35 | if (ret != NULL) { | ||
36 | memset(ret, 0, size); | ||
37 | *dma_handle = virt_to_bus(ret); | ||
38 | } | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | void pci_free_consistent(struct pci_dev *hwdev, size_t size, | ||
43 | void *vaddr, dma_addr_t dma_handle) | ||
44 | { | ||
45 | free_pages((unsigned long) vaddr, get_order(size)); | ||
46 | } | ||
diff --git a/arch/sh/boards/overdrive/setup.c b/arch/sh/boards/overdrive/setup.c new file mode 100644 index 000000000000..a36ce0284ed3 --- /dev/null +++ b/arch/sh/boards/overdrive/setup.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * arch/sh/overdrive/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * STMicroelectronics Overdrive Support. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/io.h> | ||
16 | |||
17 | #include <asm/overdrive/overdrive.h> | ||
18 | #include <asm/overdrive/fpga.h> | ||
19 | |||
20 | extern void od_time_init(void); | ||
21 | |||
22 | const char *get_system_type(void) | ||
23 | { | ||
24 | return "SH7750 Overdrive"; | ||
25 | } | ||
26 | |||
27 | /* | ||
28 | * Initialize the board | ||
29 | */ | ||
30 | int __init platform_setup(void) | ||
31 | { | ||
32 | #ifdef CONFIG_PCI | ||
33 | init_overdrive_fpga(); | ||
34 | galileo_init(); | ||
35 | #endif | ||
36 | |||
37 | board_time_init = od_time_init; | ||
38 | |||
39 | /* Enable RS232 receive buffers */ | ||
40 | writel(0x1e, OVERDRIVE_CTRL); | ||
41 | } | ||
diff --git a/arch/sh/boards/overdrive/time.c b/arch/sh/boards/overdrive/time.c new file mode 100644 index 000000000000..68533690e097 --- /dev/null +++ b/arch/sh/boards/overdrive/time.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/overdrive/time.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org) | ||
6 | * | ||
7 | * May be copied or modified under the terms of the GNU General Public | ||
8 | * License. See linux/COPYING for more information. | ||
9 | * | ||
10 | * STMicroelectronics Overdrive Support. | ||
11 | */ | ||
12 | |||
13 | void od_time_init(void) | ||
14 | { | ||
15 | struct frqcr_data { | ||
16 | unsigned short frqcr; | ||
17 | struct { | ||
18 | unsigned char multiplier; | ||
19 | unsigned char divisor; | ||
20 | } factor[3]; | ||
21 | }; | ||
22 | |||
23 | static struct frqcr_data st40_frqcr_table[] = { | ||
24 | { 0x000, {{1,1}, {1,1}, {1,2}}}, | ||
25 | { 0x002, {{1,1}, {1,1}, {1,4}}}, | ||
26 | { 0x004, {{1,1}, {1,1}, {1,8}}}, | ||
27 | { 0x008, {{1,1}, {1,2}, {1,2}}}, | ||
28 | { 0x00A, {{1,1}, {1,2}, {1,4}}}, | ||
29 | { 0x00C, {{1,1}, {1,2}, {1,8}}}, | ||
30 | { 0x011, {{1,1}, {2,3}, {1,6}}}, | ||
31 | { 0x013, {{1,1}, {2,3}, {1,3}}}, | ||
32 | { 0x01A, {{1,1}, {1,2}, {1,4}}}, | ||
33 | { 0x01C, {{1,1}, {1,2}, {1,8}}}, | ||
34 | { 0x023, {{1,1}, {2,3}, {1,3}}}, | ||
35 | { 0x02C, {{1,1}, {1,2}, {1,8}}}, | ||
36 | { 0x048, {{1,2}, {1,2}, {1,4}}}, | ||
37 | { 0x04A, {{1,2}, {1,2}, {1,6}}}, | ||
38 | { 0x04C, {{1,2}, {1,2}, {1,8}}}, | ||
39 | { 0x05A, {{1,2}, {1,3}, {1,6}}}, | ||
40 | { 0x05C, {{1,2}, {1,3}, {1,6}}}, | ||
41 | { 0x063, {{1,2}, {1,4}, {1,4}}}, | ||
42 | { 0x06C, {{1,2}, {1,4}, {1,8}}}, | ||
43 | { 0x091, {{1,3}, {1,3}, {1,6}}}, | ||
44 | { 0x093, {{1,3}, {1,3}, {1,6}}}, | ||
45 | { 0x0A3, {{1,3}, {1,6}, {1,6}}}, | ||
46 | { 0x0DA, {{1,4}, {1,4}, {1,8}}}, | ||
47 | { 0x0DC, {{1,4}, {1,4}, {1,8}}}, | ||
48 | { 0x0EC, {{1,4}, {1,8}, {1,8}}}, | ||
49 | { 0x123, {{1,4}, {1,4}, {1,8}}}, | ||
50 | { 0x16C, {{1,4}, {1,8}, {1,8}}}, | ||
51 | }; | ||
52 | |||
53 | struct memclk_data { | ||
54 | unsigned char multiplier; | ||
55 | unsigned char divisor; | ||
56 | }; | ||
57 | static struct memclk_data st40_memclk_table[8] = { | ||
58 | {1,1}, // 000 | ||
59 | {1,2}, // 001 | ||
60 | {1,3}, // 010 | ||
61 | {2,3}, // 011 | ||
62 | {1,4}, // 100 | ||
63 | {1,6}, // 101 | ||
64 | {1,8}, // 110 | ||
65 | {1,8} // 111 | ||
66 | }; | ||
67 | |||
68 | unsigned long pvr; | ||
69 | |||
70 | /* | ||
71 | * This should probably be moved into the SH3 probing code, and then | ||
72 | * use the processor structure to determine which CPU we are running | ||
73 | * on. | ||
74 | */ | ||
75 | pvr = ctrl_inl(CCN_PVR); | ||
76 | printk("PVR %08x\n", pvr); | ||
77 | |||
78 | if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { | ||
79 | /* | ||
80 | * Unfortunatly the STB1 FRQCR values are different from the | ||
81 | * 7750 ones. | ||
82 | */ | ||
83 | struct frqcr_data *d; | ||
84 | int a; | ||
85 | unsigned long memclkcr; | ||
86 | struct memclk_data *e; | ||
87 | |||
88 | for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { | ||
89 | d = &st40_frqcr_table[a]; | ||
90 | if (d->frqcr == (frqcr & 0x1ff)) | ||
91 | break; | ||
92 | } | ||
93 | if (a == ARRAY_SIZE(st40_frqcr_table)) { | ||
94 | d = st40_frqcr_table; | ||
95 | printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); | ||
96 | } | ||
97 | |||
98 | memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); | ||
99 | e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; | ||
100 | |||
101 | printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n", | ||
102 | d->factor[0].multiplier, d->factor[0].divisor, | ||
103 | d->factor[1].multiplier, d->factor[1].divisor, | ||
104 | e->multiplier, e->divisor, | ||
105 | d->factor[2].multiplier, d->factor[2].divisor); | ||
106 | |||
107 | current_cpu_data.master_clock = current_cpu_data.module_clock * | ||
108 | d->factor[2].divisor / | ||
109 | d->factor[2].multiplier; | ||
110 | current_cpu_data.bus_clock = current_cpu_data.master_clock * | ||
111 | d->factor[1].multiplier / | ||
112 | d->factor[1].divisor; | ||
113 | current_cpu_data.memory_clock = current_cpu_data.master_clock * | ||
114 | e->multiplier / e->divisor; | ||
115 | current_cpu_data.cpu_clock = current_cpu_data.master_clock * | ||
116 | d->factor[0].multiplier / | ||
117 | d->factor[0].divisor; | ||
118 | } | ||
119 | |||
diff --git a/arch/sh/boards/renesas/edosk7705/Makefile b/arch/sh/boards/renesas/edosk7705/Makefile new file mode 100644 index 000000000000..7fccbf2e4a1d --- /dev/null +++ b/arch/sh/boards/renesas/edosk7705/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for the EDOSK7705 specific parts of the kernel | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | obj-y := setup.o io.o | ||
10 | |||
diff --git a/arch/sh/boards/renesas/edosk7705/io.c b/arch/sh/boards/renesas/edosk7705/io.c new file mode 100644 index 000000000000..541cea2a652f --- /dev/null +++ b/arch/sh/boards/renesas/edosk7705/io.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/renesas/edosk7705/io.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Ian da Silva, Jeremy Siegel | ||
5 | * Based largely on io_se.c. | ||
6 | * | ||
7 | * I/O routines for Hitachi EDOSK7705 board. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/edosk7705/io.h> | ||
15 | #include <asm/addrspace.h> | ||
16 | |||
17 | #define SMC_IOADDR 0xA2000000 | ||
18 | |||
19 | #define maybebadio(name,port) \ | ||
20 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
21 | #name, (port), (__u32) __builtin_return_address(0)) | ||
22 | |||
23 | /* Map the Ethernet addresses as if it is at 0x300 - 0x320 */ | ||
24 | unsigned long sh_edosk7705_isa_port2addr(unsigned long port) | ||
25 | { | ||
26 | if (port >= 0x300 && port < 0x320) { | ||
27 | /* SMC91C96 registers are 4 byte aligned rather than the | ||
28 | * usual 2 byte! | ||
29 | */ | ||
30 | return SMC_IOADDR + ( (port - 0x300) * 2); | ||
31 | } | ||
32 | |||
33 | maybebadio(sh_edosk7705_isa_port2addr, port); | ||
34 | return port; | ||
35 | } | ||
36 | |||
37 | /* Trying to read / write bytes on odd-byte boundaries to the Ethernet | ||
38 | * registers causes problems. So we bit-shift the value and read / write | ||
39 | * in 2 byte chunks. Setting the low byte to 0 does not cause problems | ||
40 | * now as odd byte writes are only made on the bit mask / interrupt | ||
41 | * register. This may not be the case in future Mar-2003 SJD | ||
42 | */ | ||
43 | unsigned char sh_edosk7705_inb(unsigned long port) | ||
44 | { | ||
45 | if (port >= 0x300 && port < 0x320 && port & 0x01) { | ||
46 | return (volatile unsigned char)(generic_inw(port -1) >> 8); | ||
47 | } | ||
48 | return *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port); | ||
49 | } | ||
50 | |||
51 | unsigned int sh_edosk7705_inl(unsigned long port) | ||
52 | { | ||
53 | return *(volatile unsigned long *)port; | ||
54 | } | ||
55 | |||
56 | void sh_edosk7705_outb(unsigned char value, unsigned long port) | ||
57 | { | ||
58 | if (port >= 0x300 && port < 0x320 && port & 0x01) { | ||
59 | generic_outw(((unsigned short)value << 8), port -1); | ||
60 | return; | ||
61 | } | ||
62 | *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port) = value; | ||
63 | } | ||
64 | |||
65 | void sh_edosk7705_outl(unsigned int value, unsigned long port) | ||
66 | { | ||
67 | *(volatile unsigned long *)port = value; | ||
68 | } | ||
69 | |||
70 | void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count) | ||
71 | { | ||
72 | unsigned char *p = addr; | ||
73 | while (count--) *p++ = sh_edosk7705_inb(port); | ||
74 | } | ||
75 | |||
76 | void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count) | ||
77 | { | ||
78 | unsigned long *p = (unsigned long*)addr; | ||
79 | while (count--) | ||
80 | *p++ = *(volatile unsigned long *)port; | ||
81 | } | ||
82 | |||
83 | void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count) | ||
84 | { | ||
85 | unsigned char *p = (unsigned char*)addr; | ||
86 | while (count--) sh_edosk7705_outb(*p++, port); | ||
87 | } | ||
88 | |||
89 | void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count) | ||
90 | { | ||
91 | unsigned long *p = (unsigned long*)addr; | ||
92 | while (count--) sh_edosk7705_outl(*p++, port); | ||
93 | } | ||
94 | |||
diff --git a/arch/sh/boards/renesas/edosk7705/setup.c b/arch/sh/boards/renesas/edosk7705/setup.c new file mode 100644 index 000000000000..8b6f0c2af092 --- /dev/null +++ b/arch/sh/boards/renesas/edosk7705/setup.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/renesas/edosk7705/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Hitachi SolutionEngine Support. | ||
7 | * | ||
8 | * Modified for edosk7705 development | ||
9 | * board by S. Dunn, 2003. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/machvec_init.h> | ||
16 | #include <asm/edosk7705/io.h> | ||
17 | |||
18 | static void init_edosk7705(void); | ||
19 | |||
20 | /* | ||
21 | * The Machine Vector | ||
22 | */ | ||
23 | |||
24 | struct sh_machine_vector mv_edosk7705 __initmv = { | ||
25 | .mv_nr_irqs = 80, | ||
26 | |||
27 | .mv_inb = sh_edosk7705_inb, | ||
28 | .mv_inl = sh_edosk7705_inl, | ||
29 | .mv_outb = sh_edosk7705_outb, | ||
30 | .mv_outl = sh_edosk7705_outl, | ||
31 | |||
32 | .mv_inl_p = sh_edosk7705_inl, | ||
33 | .mv_outl_p = sh_edosk7705_outl, | ||
34 | |||
35 | .mv_insb = sh_edosk7705_insb, | ||
36 | .mv_insl = sh_edosk7705_insl, | ||
37 | .mv_outsb = sh_edosk7705_outsb, | ||
38 | .mv_outsl = sh_edosk7705_outsl, | ||
39 | |||
40 | .mv_isa_port2addr = sh_edosk7705_isa_port2addr, | ||
41 | .mv_init_irq = init_edosk7705, | ||
42 | }; | ||
43 | ALIAS_MV(edosk7705) | ||
44 | |||
45 | static void __init init_edosk7705(void) | ||
46 | { | ||
47 | /* This is the Ethernet interrupt */ | ||
48 | make_imask_irq(0x09); | ||
49 | } | ||
50 | |||
51 | const char *get_system_type(void) | ||
52 | { | ||
53 | return "EDOSK7705"; | ||
54 | } | ||
55 | |||
56 | void __init platform_setup(void) | ||
57 | { | ||
58 | /* Nothing .. */ | ||
59 | } | ||
60 | |||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/Makefile b/arch/sh/boards/renesas/hs7751rvoip/Makefile new file mode 100644 index 000000000000..e8b4109ace11 --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for the HS7751RVoIP specific parts of the kernel | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | obj-y := mach.o setup.o io.o irq.o led.o | ||
10 | |||
11 | obj-$(CONFIG_PCI) += pci.o | ||
12 | |||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c new file mode 100644 index 000000000000..456753d2649c --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/io.c | |||
@@ -0,0 +1,310 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_hs7751rvoip.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Ian da Silva, Jeremy Siegel | ||
5 | * Based largely on io_se.c. | ||
6 | * | ||
7 | * I/O routine for Renesas Technology sales HS7751RVoIP | ||
8 | * | ||
9 | * Initial version only to support LAN access; some | ||
10 | * placeholder code from io_hs7751rvoip.c left in with the | ||
11 | * expectation of later SuperIO and PCMCIA access. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/hs7751rvoip/hs7751rvoip.h> | ||
19 | #include <asm/addrspace.h> | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include "../../../drivers/pci/pci-sh7751.h" | ||
24 | |||
25 | extern void *area5_io8_base; /* Area 5 8bit I/O Base address */ | ||
26 | extern void *area6_io8_base; /* Area 6 8bit I/O Base address */ | ||
27 | extern void *area5_io16_base; /* Area 5 16bit I/O Base address */ | ||
28 | extern void *area6_io16_base; /* Area 6 16bit I/O Base address */ | ||
29 | |||
30 | /* | ||
31 | * The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC) | ||
32 | * of the 7751R processor, and has a SuperIO accessible via the PCI. | ||
33 | * The board also includes a PCMCIA controller on its memory bus, | ||
34 | * like the other Solution Engine boards. | ||
35 | */ | ||
36 | |||
37 | #define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR) | ||
38 | #define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR) | ||
39 | #define PCI_IO_AREA SH7751_PCI_IO_BASE | ||
40 | #define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE | ||
41 | |||
42 | #define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK)) | ||
43 | |||
44 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
45 | #define CODEC_IO_BASE 0x1000 | ||
46 | #endif | ||
47 | |||
48 | #define maybebadio(name,port) \ | ||
49 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
50 | #name, (port), (__u32) __builtin_return_address(0)) | ||
51 | |||
52 | static inline void delay(void) | ||
53 | { | ||
54 | ctrl_inw(0xa0000000); | ||
55 | } | ||
56 | |||
57 | static inline unsigned long port2adr(unsigned int port) | ||
58 | { | ||
59 | if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) | ||
60 | if (port == 0x3f6) | ||
61 | return ((unsigned long)area5_io16_base + 0x0c); | ||
62 | else | ||
63 | return ((unsigned long)area5_io16_base + 0x800 + ((port-0x1f0) << 1)); | ||
64 | else | ||
65 | maybebadio(port2adr, (unsigned long)port); | ||
66 | return port; | ||
67 | } | ||
68 | |||
69 | /* The 7751R HS7751RVoIP seems to have everything hooked */ | ||
70 | /* up pretty normally (nothing on high-bytes only...) so this */ | ||
71 | /* shouldn't be needed */ | ||
72 | static inline int shifted_port(unsigned long port) | ||
73 | { | ||
74 | /* For IDE registers, value is not shifted */ | ||
75 | if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) | ||
76 | return 0; | ||
77 | else | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
82 | static inline int | ||
83 | codec_port(unsigned long port) | ||
84 | { | ||
85 | if (CODEC_IO_BASE <= port && port < (CODEC_IO_BASE+0x20)) | ||
86 | return 1; | ||
87 | else | ||
88 | return 0; | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | /* In case someone configures the kernel w/o PCI support: in that */ | ||
93 | /* scenario, don't ever bother to check for PCI-window addresses */ | ||
94 | |||
95 | /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */ | ||
96 | #if defined(CONFIG_PCI) | ||
97 | #define CHECK_SH7751_PCIIO(port) \ | ||
98 | ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE))) | ||
99 | #else | ||
100 | #define CHECK_SH7751_PCIIO(port) (0) | ||
101 | #endif | ||
102 | |||
103 | /* | ||
104 | * General outline: remap really low stuff [eventually] to SuperIO, | ||
105 | * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) | ||
106 | * is mapped through the PCI IO window. Stuff with high bits (PXSEG) | ||
107 | * should be way beyond the window, and is used w/o translation for | ||
108 | * compatibility. | ||
109 | */ | ||
110 | unsigned char hs7751rvoip_inb(unsigned long port) | ||
111 | { | ||
112 | if (PXSEG(port)) | ||
113 | return *(volatile unsigned char *)port; | ||
114 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
115 | else if (codec_port(port)) | ||
116 | return *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)); | ||
117 | #endif | ||
118 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
119 | return *(volatile unsigned char *)PCI_IOMAP(port); | ||
120 | else | ||
121 | return (*(volatile unsigned short *)port2adr(port) & 0xff); | ||
122 | } | ||
123 | |||
124 | unsigned char hs7751rvoip_inb_p(unsigned long port) | ||
125 | { | ||
126 | unsigned char v; | ||
127 | |||
128 | if (PXSEG(port)) | ||
129 | v = *(volatile unsigned char *)port; | ||
130 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
131 | else if (codec_port(port)) | ||
132 | v = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)); | ||
133 | #endif | ||
134 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
135 | v = *(volatile unsigned char *)PCI_IOMAP(port); | ||
136 | else | ||
137 | v = (*(volatile unsigned short *)port2adr(port) & 0xff); | ||
138 | delay(); | ||
139 | return v; | ||
140 | } | ||
141 | |||
142 | unsigned short hs7751rvoip_inw(unsigned long port) | ||
143 | { | ||
144 | if (PXSEG(port)) | ||
145 | return *(volatile unsigned short *)port; | ||
146 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
147 | return *(volatile unsigned short *)PCI_IOMAP(port); | ||
148 | else | ||
149 | maybebadio(inw, port); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | unsigned int hs7751rvoip_inl(unsigned long port) | ||
154 | { | ||
155 | if (PXSEG(port)) | ||
156 | return *(volatile unsigned long *)port; | ||
157 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
158 | return *(volatile unsigned long *)PCI_IOMAP(port); | ||
159 | else | ||
160 | maybebadio(inl, port); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | void hs7751rvoip_outb(unsigned char value, unsigned long port) | ||
165 | { | ||
166 | |||
167 | if (PXSEG(port)) | ||
168 | *(volatile unsigned char *)port = value; | ||
169 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
170 | else if (codec_port(port)) | ||
171 | *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value; | ||
172 | #endif | ||
173 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
174 | *(unsigned char *)PCI_IOMAP(port) = value; | ||
175 | else | ||
176 | *(volatile unsigned short *)port2adr(port) = value; | ||
177 | } | ||
178 | |||
179 | void hs7751rvoip_outb_p(unsigned char value, unsigned long port) | ||
180 | { | ||
181 | if (PXSEG(port)) | ||
182 | *(volatile unsigned char *)port = value; | ||
183 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
184 | else if (codec_port(port)) | ||
185 | *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value; | ||
186 | #endif | ||
187 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
188 | *(unsigned char *)PCI_IOMAP(port) = value; | ||
189 | else | ||
190 | *(volatile unsigned short *)port2adr(port) = value; | ||
191 | delay(); | ||
192 | } | ||
193 | |||
194 | void hs7751rvoip_outw(unsigned short value, unsigned long port) | ||
195 | { | ||
196 | if (PXSEG(port)) | ||
197 | *(volatile unsigned short *)port = value; | ||
198 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
199 | *(unsigned short *)PCI_IOMAP(port) = value; | ||
200 | else | ||
201 | maybebadio(outw, port); | ||
202 | } | ||
203 | |||
204 | void hs7751rvoip_outl(unsigned int value, unsigned long port) | ||
205 | { | ||
206 | if (PXSEG(port)) | ||
207 | *(volatile unsigned long *)port = value; | ||
208 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
209 | *((unsigned long *)PCI_IOMAP(port)) = value; | ||
210 | else | ||
211 | maybebadio(outl, port); | ||
212 | } | ||
213 | |||
214 | void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count) | ||
215 | { | ||
216 | if (PXSEG(port)) | ||
217 | while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port; | ||
218 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
219 | else if (codec_port(port)) | ||
220 | while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)); | ||
221 | #endif | ||
222 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
223 | volatile __u8 *bp = (__u8 *)PCI_IOMAP(port); | ||
224 | |||
225 | while (count--) *((volatile unsigned char *) addr)++ = *bp; | ||
226 | } else { | ||
227 | volatile __u16 *p = (volatile unsigned short *)port2adr(port); | ||
228 | |||
229 | while (count--) *((unsigned char *) addr)++ = *p & 0xff; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count) | ||
234 | { | ||
235 | volatile __u16 *p; | ||
236 | |||
237 | if (PXSEG(port)) | ||
238 | p = (volatile unsigned short *)port; | ||
239 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
240 | p = (volatile unsigned short *)PCI_IOMAP(port); | ||
241 | else | ||
242 | p = (volatile unsigned short *)port2adr(port); | ||
243 | while (count--) *((__u16 *) addr)++ = *p; | ||
244 | } | ||
245 | |||
246 | void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count) | ||
247 | { | ||
248 | if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
249 | volatile __u32 *p = (__u32 *)PCI_IOMAP(port); | ||
250 | |||
251 | while (count--) *((__u32 *) addr)++ = *p; | ||
252 | } else | ||
253 | maybebadio(insl, port); | ||
254 | } | ||
255 | |||
256 | void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count) | ||
257 | { | ||
258 | if (PXSEG(port)) | ||
259 | while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++; | ||
260 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
261 | else if (codec_port(port)) | ||
262 | while (count--) *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = *((unsigned char *) addr)++; | ||
263 | #endif | ||
264 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
265 | volatile __u8 *bp = (__u8 *)PCI_IOMAP(port); | ||
266 | |||
267 | while (count--) *bp = *((volatile unsigned char *) addr)++; | ||
268 | } else { | ||
269 | volatile __u16 *p = (volatile unsigned short *)port2adr(port); | ||
270 | |||
271 | while (count--) *p = *((unsigned char *) addr)++; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count) | ||
276 | { | ||
277 | volatile __u16 *p; | ||
278 | |||
279 | if (PXSEG(port)) | ||
280 | p = (volatile unsigned short *)port; | ||
281 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
282 | p = (volatile unsigned short *)PCI_IOMAP(port); | ||
283 | else | ||
284 | p = (volatile unsigned short *)port2adr(port); | ||
285 | while (count--) *p = *((__u16 *) addr)++; | ||
286 | } | ||
287 | |||
288 | void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count) | ||
289 | { | ||
290 | if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
291 | volatile __u32 *p = (__u32 *)PCI_IOMAP(port); | ||
292 | |||
293 | while (count--) *p = *((__u32 *) addr)++; | ||
294 | } else | ||
295 | maybebadio(outsl, port); | ||
296 | } | ||
297 | |||
298 | void *hs7751rvoip_ioremap(unsigned long offset, unsigned long size) | ||
299 | { | ||
300 | if (offset >= 0xfd000000) | ||
301 | return (void *)offset; | ||
302 | else | ||
303 | return (void *)P2SEGADDR(offset); | ||
304 | } | ||
305 | EXPORT_SYMBOL(hs7751rvoip_ioremap); | ||
306 | |||
307 | unsigned long hs7751rvoip_isa_port2addr(unsigned long offset) | ||
308 | { | ||
309 | return port2adr(offset); | ||
310 | } | ||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c new file mode 100644 index 000000000000..a7921f67a35f --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/irq.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/renesas/hs7751rvoip/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Renesas Technology Sales HS7751RVoIP Support. | ||
7 | * | ||
8 | * Modified for HS7751RVoIP by | ||
9 | * Atom Create Engineering Co., Ltd. 2002. | ||
10 | * Lineo uSolutions, Inc. 2003. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/irq.h> | ||
18 | #include <asm/hs7751rvoip/hs7751rvoip.h> | ||
19 | |||
20 | static int mask_pos[] = {8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7}; | ||
21 | |||
22 | static void enable_hs7751rvoip_irq(unsigned int irq); | ||
23 | static void disable_hs7751rvoip_irq(unsigned int irq); | ||
24 | |||
25 | /* shutdown is same as "disable" */ | ||
26 | #define shutdown_hs7751rvoip_irq disable_hs7751rvoip_irq | ||
27 | |||
28 | static void ack_hs7751rvoip_irq(unsigned int irq); | ||
29 | static void end_hs7751rvoip_irq(unsigned int irq); | ||
30 | |||
31 | static unsigned int startup_hs7751rvoip_irq(unsigned int irq) | ||
32 | { | ||
33 | enable_hs7751rvoip_irq(irq); | ||
34 | return 0; /* never anything pending */ | ||
35 | } | ||
36 | |||
37 | static void disable_hs7751rvoip_irq(unsigned int irq) | ||
38 | { | ||
39 | unsigned long flags; | ||
40 | unsigned short val; | ||
41 | unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]); | ||
42 | |||
43 | /* Set the priority in IPR to 0 */ | ||
44 | local_irq_save(flags); | ||
45 | val = ctrl_inw(IRLCNTR3); | ||
46 | val &= mask; | ||
47 | ctrl_outw(val, IRLCNTR3); | ||
48 | local_irq_restore(flags); | ||
49 | } | ||
50 | |||
51 | static void enable_hs7751rvoip_irq(unsigned int irq) | ||
52 | { | ||
53 | unsigned long flags; | ||
54 | unsigned short val; | ||
55 | unsigned short value = (0x0001 << mask_pos[irq]); | ||
56 | |||
57 | /* Set priority in IPR back to original value */ | ||
58 | local_irq_save(flags); | ||
59 | val = ctrl_inw(IRLCNTR3); | ||
60 | val |= value; | ||
61 | ctrl_outw(val, IRLCNTR3); | ||
62 | local_irq_restore(flags); | ||
63 | } | ||
64 | |||
65 | static void ack_hs7751rvoip_irq(unsigned int irq) | ||
66 | { | ||
67 | disable_hs7751rvoip_irq(irq); | ||
68 | } | ||
69 | |||
70 | static void end_hs7751rvoip_irq(unsigned int irq) | ||
71 | { | ||
72 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
73 | enable_hs7751rvoip_irq(irq); | ||
74 | } | ||
75 | |||
76 | static struct hw_interrupt_type hs7751rvoip_irq_type = { | ||
77 | "HS7751RVoIP IRQ", | ||
78 | startup_hs7751rvoip_irq, | ||
79 | shutdown_hs7751rvoip_irq, | ||
80 | enable_hs7751rvoip_irq, | ||
81 | disable_hs7751rvoip_irq, | ||
82 | ack_hs7751rvoip_irq, | ||
83 | end_hs7751rvoip_irq, | ||
84 | }; | ||
85 | |||
86 | static void make_hs7751rvoip_irq(unsigned int irq) | ||
87 | { | ||
88 | disable_irq_nosync(irq); | ||
89 | irq_desc[irq].handler = &hs7751rvoip_irq_type; | ||
90 | disable_hs7751rvoip_irq(irq); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Initialize IRQ setting | ||
95 | */ | ||
96 | void __init init_hs7751rvoip_IRQ(void) | ||
97 | { | ||
98 | int i; | ||
99 | |||
100 | /* IRL0=ON HOOK1 | ||
101 | * IRL1=OFF HOOK1 | ||
102 | * IRL2=ON HOOK2 | ||
103 | * IRL3=OFF HOOK2 | ||
104 | * IRL4=Ringing Detection | ||
105 | * IRL5=CODEC | ||
106 | * IRL6=Ethernet | ||
107 | * IRL7=Ethernet Hub | ||
108 | * IRL8=USB Communication | ||
109 | * IRL9=USB Connection | ||
110 | * IRL10=USB DMA | ||
111 | * IRL11=CF Card | ||
112 | * IRL12=PCMCIA | ||
113 | * IRL13=PCI Slot | ||
114 | */ | ||
115 | ctrl_outw(0x9876, IRLCNTR1); | ||
116 | ctrl_outw(0xdcba, IRLCNTR2); | ||
117 | ctrl_outw(0x0050, IRLCNTR4); | ||
118 | ctrl_outw(0x4321, IRLCNTR5); | ||
119 | |||
120 | for (i=0; i<14; i++) | ||
121 | make_hs7751rvoip_irq(i); | ||
122 | } | ||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/led.c b/arch/sh/boards/renesas/hs7751rvoip/led.c new file mode 100644 index 000000000000..18a13c8da8a4 --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/led.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/setup_hs7751rvoip.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Renesas Technology Sales HS7751RVoIP Support. | ||
7 | * | ||
8 | * Modified for HS7751RVoIP by | ||
9 | * Atom Create Engineering Co., Ltd. 2002. | ||
10 | * Lineo uSolutions, Inc. 2003. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/hs7751rvoip/hs7751rvoip.h> | ||
16 | |||
17 | extern unsigned int debug_counter; | ||
18 | |||
19 | void debug_led_disp(void) | ||
20 | { | ||
21 | unsigned short value; | ||
22 | |||
23 | value = (unsigned char)debug_counter++; | ||
24 | ctrl_outb((0xf0|value), PA_OUTPORTR); | ||
25 | if (value == 0x0f) | ||
26 | debug_counter = 0; | ||
27 | } | ||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/mach.c b/arch/sh/boards/renesas/hs7751rvoip/mach.c new file mode 100644 index 000000000000..8bbed60220ca --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/mach.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/mach_hs7751rvoip.c | ||
3 | * | ||
4 | * Minor tweak of mach_se.c file to reference hs7751rvoip-specific items. | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the Renesas Technology sales HS7751RVoIP | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/machvec.h> | ||
16 | #include <asm/rtc.h> | ||
17 | #include <asm/irq.h> | ||
18 | #include <asm/hs7751rvoip/io.h> | ||
19 | |||
20 | extern void init_hs7751rvoip_IRQ(void); | ||
21 | extern void *hs7751rvoip_ioremap(unsigned long, unsigned long); | ||
22 | |||
23 | /* | ||
24 | * The Machine Vector | ||
25 | */ | ||
26 | |||
27 | struct sh_machine_vector mv_hs7751rvoip __initmv = { | ||
28 | .mv_nr_irqs = 72, | ||
29 | |||
30 | .mv_inb = hs7751rvoip_inb, | ||
31 | .mv_inw = hs7751rvoip_inw, | ||
32 | .mv_inl = hs7751rvoip_inl, | ||
33 | .mv_outb = hs7751rvoip_outb, | ||
34 | .mv_outw = hs7751rvoip_outw, | ||
35 | .mv_outl = hs7751rvoip_outl, | ||
36 | |||
37 | .mv_inb_p = hs7751rvoip_inb_p, | ||
38 | .mv_inw_p = hs7751rvoip_inw, | ||
39 | .mv_inl_p = hs7751rvoip_inl, | ||
40 | .mv_outb_p = hs7751rvoip_outb_p, | ||
41 | .mv_outw_p = hs7751rvoip_outw, | ||
42 | .mv_outl_p = hs7751rvoip_outl, | ||
43 | |||
44 | .mv_insb = hs7751rvoip_insb, | ||
45 | .mv_insw = hs7751rvoip_insw, | ||
46 | .mv_insl = hs7751rvoip_insl, | ||
47 | .mv_outsb = hs7751rvoip_outsb, | ||
48 | .mv_outsw = hs7751rvoip_outsw, | ||
49 | .mv_outsl = hs7751rvoip_outsl, | ||
50 | |||
51 | .mv_ioremap = hs7751rvoip_ioremap, | ||
52 | .mv_isa_port2addr = hs7751rvoip_isa_port2addr, | ||
53 | .mv_init_irq = init_hs7751rvoip_IRQ, | ||
54 | }; | ||
55 | ALIAS_MV(hs7751rvoip) | ||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c new file mode 100644 index 000000000000..7a442d1eca46 --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/pci.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/pci-hs7751rvoip.c | ||
3 | * | ||
4 | * Author: Ian DaSilva (idasilva@mvista.com) | ||
5 | * | ||
6 | * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * PCI initialization for the Renesas SH7751R HS7751RVoIP board | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/module.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include "../../../drivers/pci/pci-sh7751.h" | ||
24 | #include <asm/hs7751rvoip/hs7751rvoip.h> | ||
25 | |||
26 | #define PCIMCR_MRSET_OFF 0xBFFFFFFF | ||
27 | #define PCIMCR_RFSH_OFF 0xFFFFFFFB | ||
28 | |||
29 | /* | ||
30 | * Only long word accesses of the PCIC's internal local registers and the | ||
31 | * configuration registers from the CPU is supported. | ||
32 | */ | ||
33 | #define PCIC_WRITE(x,v) writel((v), PCI_REG(x)) | ||
34 | #define PCIC_READ(x) readl(PCI_REG(x)) | ||
35 | |||
36 | /* | ||
37 | * Description: This function sets up and initializes the pcic, sets | ||
38 | * up the BARS, maps the DRAM into the address space etc, etc. | ||
39 | */ | ||
40 | int __init pcibios_init_platform(void) | ||
41 | { | ||
42 | unsigned long bcr1, wcr1, wcr2, wcr3, mcr; | ||
43 | unsigned short bcr2, bcr3; | ||
44 | |||
45 | /* | ||
46 | * Initialize the slave bus controller on the pcic. The values used | ||
47 | * here should not be hardcoded, but they should be taken from the bsc | ||
48 | * on the processor, to make this function as generic as possible. | ||
49 | * (i.e. Another sbc may usr different SDRAM timing settings -- in order | ||
50 | * for the pcic to work, its settings need to be exactly the same.) | ||
51 | */ | ||
52 | bcr1 = (*(volatile unsigned long *)(SH7751_BCR1)); | ||
53 | bcr2 = (*(volatile unsigned short *)(SH7751_BCR2)); | ||
54 | bcr3 = (*(volatile unsigned short *)(SH7751_BCR3)); | ||
55 | wcr1 = (*(volatile unsigned long *)(SH7751_WCR1)); | ||
56 | wcr2 = (*(volatile unsigned long *)(SH7751_WCR2)); | ||
57 | wcr3 = (*(volatile unsigned long *)(SH7751_WCR3)); | ||
58 | mcr = (*(volatile unsigned long *)(SH7751_MCR)); | ||
59 | |||
60 | bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */ | ||
61 | (*(volatile unsigned long *)(SH7751_BCR1)) = bcr1; | ||
62 | |||
63 | bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ | ||
64 | PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */ | ||
65 | PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */ | ||
66 | PCIC_WRITE(SH7751_PCIBCR3, bcr3); /* PCIC BCR3 */ | ||
67 | PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */ | ||
68 | PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */ | ||
69 | PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */ | ||
70 | mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; | ||
71 | PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */ | ||
72 | |||
73 | /* Enable all interrupts, so we know what to fix */ | ||
74 | PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff); | ||
75 | PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f); | ||
76 | |||
77 | /* Set up standard PCI config registers */ | ||
78 | PCIC_WRITE(SH7751_PCICONF1, 0xFB900047); /* Bus Master, Mem & I/O access */ | ||
79 | PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */ | ||
80 | PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */ | ||
81 | PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM) */ | ||
82 | PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */ | ||
83 | PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */ | ||
84 | PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* MEM (full 64M exposed) */ | ||
85 | PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */ | ||
86 | PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */ | ||
87 | PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */ | ||
88 | |||
89 | /* Now turn it on... */ | ||
90 | PCIC_WRITE(SH7751_PCICR, 0xa5000001); | ||
91 | |||
92 | /* | ||
93 | * Set PCIMBR and PCIIOBR here, assuming a single window | ||
94 | * (16M MEM, 256K IO) is enough. If a larger space is | ||
95 | * needed, the readx/writex and inx/outx functions will | ||
96 | * have to do more (e.g. setting registers for each call). | ||
97 | */ | ||
98 | |||
99 | /* | ||
100 | * Set the MBR so PCI address is one-to-one with window, | ||
101 | * meaning all calls go straight through... use ifdef to | ||
102 | * catch erroneous assumption. | ||
103 | */ | ||
104 | BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE); | ||
105 | |||
106 | PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM); | ||
107 | |||
108 | /* Set IOBR for window containing area specified in pci.h */ | ||
109 | PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK)); | ||
110 | |||
111 | /* All done, may as well say so... */ | ||
112 | printk("SH7751R PCI: Finished initialization of the PCI controller\n"); | ||
113 | |||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | int __init pcibios_map_platform_irq(u8 slot, u8 pin) | ||
118 | { | ||
119 | switch (slot) { | ||
120 | case 0: return IRQ_PCISLOT; /* PCI Extend slot */ | ||
121 | case 1: return IRQ_PCMCIA; /* PCI Cardbus Bridge */ | ||
122 | case 2: return IRQ_PCIETH; /* Realtek Ethernet controller */ | ||
123 | case 3: return IRQ_PCIHUB; /* Realtek Ethernet Hub controller */ | ||
124 | default: | ||
125 | printk("PCI: Bad IRQ mapping request for slot %d\n", slot); | ||
126 | return -1; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static struct resource sh7751_io_resource = { | ||
131 | .name = "SH7751_IO", | ||
132 | .start = 0x4000, | ||
133 | .end = 0x4000 + SH7751_PCI_IO_SIZE - 1, | ||
134 | .flags = IORESOURCE_IO | ||
135 | }; | ||
136 | |||
137 | static struct resource sh7751_mem_resource = { | ||
138 | .name = "SH7751_mem", | ||
139 | .start = SH7751_PCI_MEMORY_BASE, | ||
140 | .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, | ||
141 | .flags = IORESOURCE_MEM | ||
142 | }; | ||
143 | |||
144 | extern struct pci_ops sh7751_pci_ops; | ||
145 | |||
146 | struct pci_channel board_pci_channels[] = { | ||
147 | { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, | ||
148 | { NULL, NULL, NULL, 0, 0 }, | ||
149 | }; | ||
150 | EXPORT_SYMBOL(board_pci_channels); | ||
diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c new file mode 100644 index 000000000000..f1a78b6c714c --- /dev/null +++ b/arch/sh/boards/renesas/hs7751rvoip/setup.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/setup_hs7751rvoip.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Renesas Technology Sales HS7751RVoIP Support. | ||
7 | * | ||
8 | * Modified for HS7751RVoIP by | ||
9 | * Atom Create Engineering Co., Ltd. 2002. | ||
10 | * Lineo uSolutions, Inc. 2003. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/irq.h> | ||
16 | |||
17 | #include <linux/hdreg.h> | ||
18 | #include <linux/ide.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/hs7751rvoip/hs7751rvoip.h> | ||
21 | |||
22 | #include <linux/mm.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | |||
25 | /* defined in mm/ioremap.c */ | ||
26 | extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); | ||
27 | |||
28 | unsigned int debug_counter; | ||
29 | |||
30 | const char *get_system_type(void) | ||
31 | { | ||
32 | return "HS7751RVoIP"; | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * Initialize the board | ||
37 | */ | ||
38 | void __init platform_setup(void) | ||
39 | { | ||
40 | printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n"); | ||
41 | ctrl_outb(0xf0, PA_OUTPORTR); | ||
42 | debug_counter = 0; | ||
43 | } | ||
44 | |||
45 | void *area5_io8_base; | ||
46 | void *area6_io8_base; | ||
47 | void *area5_io16_base; | ||
48 | void *area6_io16_base; | ||
49 | |||
50 | int __init cf_init(void) | ||
51 | { | ||
52 | pgprot_t prot; | ||
53 | unsigned long paddrbase, psize; | ||
54 | |||
55 | /* open I/O area window */ | ||
56 | paddrbase = virt_to_phys((void *)(PA_AREA5_IO+0x00000800)); | ||
57 | psize = PAGE_SIZE; | ||
58 | prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_COM16); | ||
59 | area5_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot); | ||
60 | if (!area5_io16_base) { | ||
61 | printk("allocate_cf_area : can't open CF I/O window!\n"); | ||
62 | return -ENOMEM; | ||
63 | } | ||
64 | |||
65 | /* XXX : do we need attribute and common-memory area also? */ | ||
66 | |||
67 | paddrbase = virt_to_phys((void *)PA_AREA6_IO); | ||
68 | psize = PAGE_SIZE; | ||
69 | #if defined(CONFIG_HS7751RVOIP_CODEC) | ||
70 | prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_COM8); | ||
71 | #else | ||
72 | prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO8); | ||
73 | #endif | ||
74 | area6_io8_base = p3_ioremap(paddrbase, psize, prot.pgprot); | ||
75 | if (!area6_io8_base) { | ||
76 | printk("allocate_cf_area : can't open CODEC I/O 8bit window!\n"); | ||
77 | return -ENOMEM; | ||
78 | } | ||
79 | prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16); | ||
80 | area6_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot); | ||
81 | if (!area6_io16_base) { | ||
82 | printk("allocate_cf_area : can't open CODEC I/O 16bit window!\n"); | ||
83 | return -ENOMEM; | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | __initcall (cf_init); | ||
diff --git a/arch/sh/boards/renesas/rts7751r2d/Makefile b/arch/sh/boards/renesas/rts7751r2d/Makefile new file mode 100644 index 000000000000..daa53334bdc3 --- /dev/null +++ b/arch/sh/boards/renesas/rts7751r2d/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for the RTS7751R2D specific parts of the kernel | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | obj-y := mach.o setup.o io.o irq.o led.o | ||
10 | |||
diff --git a/arch/sh/boards/renesas/rts7751r2d/io.c b/arch/sh/boards/renesas/rts7751r2d/io.c new file mode 100644 index 000000000000..c46f9154cfd5 --- /dev/null +++ b/arch/sh/boards/renesas/rts7751r2d/io.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_rts7751r2d.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Ian da Silva, Jeremy Siegel | ||
5 | * Based largely on io_se.c. | ||
6 | * | ||
7 | * I/O routine for Renesas Technology sales RTS7751R2D. | ||
8 | * | ||
9 | * Initial version only to support LAN access; some | ||
10 | * placeholder code from io_rts7751r2d.c left in with the | ||
11 | * expectation of later SuperIO and PCMCIA access. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/rts7751r2d/rts7751r2d.h> | ||
18 | #include <asm/addrspace.h> | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include "../../../drivers/pci/pci-sh7751.h" | ||
23 | |||
24 | /* | ||
25 | * The 7751R RTS7751R2D uses the built-in PCI controller (PCIC) | ||
26 | * of the 7751R processor, and has a SuperIO accessible via the PCI. | ||
27 | * The board also includes a PCMCIA controller on its memory bus, | ||
28 | * like the other Solution Engine boards. | ||
29 | */ | ||
30 | |||
31 | #define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR) | ||
32 | #define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR) | ||
33 | #define PCI_IO_AREA SH7751_PCI_IO_BASE | ||
34 | #define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE | ||
35 | |||
36 | #define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK)) | ||
37 | |||
38 | #define maybebadio(name,port) \ | ||
39 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
40 | #name, (port), (__u32) __builtin_return_address(0)) | ||
41 | |||
42 | static inline void delay(void) | ||
43 | { | ||
44 | ctrl_inw(0xa0000000); | ||
45 | } | ||
46 | |||
47 | static inline unsigned long port2adr(unsigned int port) | ||
48 | { | ||
49 | if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) | ||
50 | if (port == 0x3f6) | ||
51 | return (PA_AREA5_IO + 0x80c); | ||
52 | else | ||
53 | return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1)); | ||
54 | else | ||
55 | maybebadio(port2adr, (unsigned long)port); | ||
56 | |||
57 | return port; | ||
58 | } | ||
59 | |||
60 | static inline unsigned long port88796l(unsigned int port, int flag) | ||
61 | { | ||
62 | unsigned long addr; | ||
63 | |||
64 | if (flag) | ||
65 | addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1); | ||
66 | else | ||
67 | addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1) + 0x1000; | ||
68 | |||
69 | return addr; | ||
70 | } | ||
71 | |||
72 | /* The 7751R RTS7751R2D seems to have everything hooked */ | ||
73 | /* up pretty normally (nothing on high-bytes only...) so this */ | ||
74 | /* shouldn't be needed */ | ||
75 | static inline int shifted_port(unsigned long port) | ||
76 | { | ||
77 | /* For IDE registers, value is not shifted */ | ||
78 | if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) | ||
79 | return 0; | ||
80 | else | ||
81 | return 1; | ||
82 | } | ||
83 | |||
84 | /* In case someone configures the kernel w/o PCI support: in that */ | ||
85 | /* scenario, don't ever bother to check for PCI-window addresses */ | ||
86 | |||
87 | /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */ | ||
88 | #if defined(CONFIG_PCI) | ||
89 | #define CHECK_SH7751_PCIIO(port) \ | ||
90 | ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE))) | ||
91 | #else | ||
92 | #define CHECK_SH7751_PCIIO(port) (0) | ||
93 | #endif | ||
94 | |||
95 | #if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE) | ||
96 | #define CHECK_AX88796L_PORT(port) \ | ||
97 | ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20))) | ||
98 | #else | ||
99 | #define CHECK_AX88796L_PORT(port) (0) | ||
100 | #endif | ||
101 | |||
102 | /* | ||
103 | * General outline: remap really low stuff [eventually] to SuperIO, | ||
104 | * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) | ||
105 | * is mapped through the PCI IO window. Stuff with high bits (PXSEG) | ||
106 | * should be way beyond the window, and is used w/o translation for | ||
107 | * compatibility. | ||
108 | */ | ||
109 | unsigned char rts7751r2d_inb(unsigned long port) | ||
110 | { | ||
111 | if (CHECK_AX88796L_PORT(port)) | ||
112 | return (*(volatile unsigned short *)port88796l(port, 0)) & 0xff; | ||
113 | else if (PXSEG(port)) | ||
114 | return *(volatile unsigned char *)port; | ||
115 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
116 | return *(volatile unsigned char *)PCI_IOMAP(port); | ||
117 | else | ||
118 | return (*(volatile unsigned short *)port2adr(port) & 0xff); | ||
119 | } | ||
120 | |||
121 | unsigned char rts7751r2d_inb_p(unsigned long port) | ||
122 | { | ||
123 | unsigned char v; | ||
124 | |||
125 | if (CHECK_AX88796L_PORT(port)) | ||
126 | v = (*(volatile unsigned short *)port88796l(port, 0)) & 0xff; | ||
127 | else if (PXSEG(port)) | ||
128 | v = *(volatile unsigned char *)port; | ||
129 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
130 | v = *(volatile unsigned char *)PCI_IOMAP(port); | ||
131 | else | ||
132 | v = (*(volatile unsigned short *)port2adr(port) & 0xff); | ||
133 | delay(); | ||
134 | |||
135 | return v; | ||
136 | } | ||
137 | |||
138 | unsigned short rts7751r2d_inw(unsigned long port) | ||
139 | { | ||
140 | if (CHECK_AX88796L_PORT(port)) | ||
141 | maybebadio(inw, port); | ||
142 | else if (PXSEG(port)) | ||
143 | return *(volatile unsigned short *)port; | ||
144 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
145 | return *(volatile unsigned short *)PCI_IOMAP(port); | ||
146 | else | ||
147 | maybebadio(inw, port); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | unsigned int rts7751r2d_inl(unsigned long port) | ||
153 | { | ||
154 | if (CHECK_AX88796L_PORT(port)) | ||
155 | maybebadio(inl, port); | ||
156 | else if (PXSEG(port)) | ||
157 | return *(volatile unsigned long *)port; | ||
158 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
159 | return *(volatile unsigned long *)PCI_IOMAP(port); | ||
160 | else | ||
161 | maybebadio(inl, port); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | void rts7751r2d_outb(unsigned char value, unsigned long port) | ||
167 | { | ||
168 | if (CHECK_AX88796L_PORT(port)) | ||
169 | *((volatile unsigned short *)port88796l(port, 0)) = value; | ||
170 | else if (PXSEG(port)) | ||
171 | *(volatile unsigned char *)port = value; | ||
172 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
173 | *(volatile unsigned char *)PCI_IOMAP(port) = value; | ||
174 | else | ||
175 | *(volatile unsigned short *)port2adr(port) = value; | ||
176 | } | ||
177 | |||
178 | void rts7751r2d_outb_p(unsigned char value, unsigned long port) | ||
179 | { | ||
180 | if (CHECK_AX88796L_PORT(port)) | ||
181 | *((volatile unsigned short *)port88796l(port, 0)) = value; | ||
182 | else if (PXSEG(port)) | ||
183 | *(volatile unsigned char *)port = value; | ||
184 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
185 | *(volatile unsigned char *)PCI_IOMAP(port) = value; | ||
186 | else | ||
187 | *(volatile unsigned short *)port2adr(port) = value; | ||
188 | delay(); | ||
189 | } | ||
190 | |||
191 | void rts7751r2d_outw(unsigned short value, unsigned long port) | ||
192 | { | ||
193 | if (CHECK_AX88796L_PORT(port)) | ||
194 | maybebadio(outw, port); | ||
195 | else if (PXSEG(port)) | ||
196 | *(volatile unsigned short *)port = value; | ||
197 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
198 | *(volatile unsigned short *)PCI_IOMAP(port) = value; | ||
199 | else | ||
200 | maybebadio(outw, port); | ||
201 | } | ||
202 | |||
203 | void rts7751r2d_outl(unsigned int value, unsigned long port) | ||
204 | { | ||
205 | if (CHECK_AX88796L_PORT(port)) | ||
206 | maybebadio(outl, port); | ||
207 | else if (PXSEG(port)) | ||
208 | *(volatile unsigned long *)port = value; | ||
209 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
210 | *(volatile unsigned long *)PCI_IOMAP(port) = value; | ||
211 | else | ||
212 | maybebadio(outl, port); | ||
213 | } | ||
214 | |||
215 | void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count) | ||
216 | { | ||
217 | volatile __u8 *bp; | ||
218 | volatile __u16 *p; | ||
219 | |||
220 | if (CHECK_AX88796L_PORT(port)) { | ||
221 | p = (volatile unsigned short *)port88796l(port, 0); | ||
222 | while (count--) *((unsigned char *) addr)++ = *p & 0xff; | ||
223 | } else if (PXSEG(port)) | ||
224 | while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port; | ||
225 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
226 | bp = (__u8 *)PCI_IOMAP(port); | ||
227 | while (count--) *((volatile unsigned char *) addr)++ = *bp; | ||
228 | } else { | ||
229 | p = (volatile unsigned short *)port2adr(port); | ||
230 | while (count--) *((unsigned char *) addr)++ = *p & 0xff; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count) | ||
235 | { | ||
236 | volatile __u16 *p; | ||
237 | |||
238 | if (CHECK_AX88796L_PORT(port)) | ||
239 | p = (volatile unsigned short *)port88796l(port, 1); | ||
240 | else if (PXSEG(port)) | ||
241 | p = (volatile unsigned short *)port; | ||
242 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
243 | p = (volatile unsigned short *)PCI_IOMAP(port); | ||
244 | else | ||
245 | p = (volatile unsigned short *)port2adr(port); | ||
246 | while (count--) *((__u16 *) addr)++ = *p; | ||
247 | } | ||
248 | |||
249 | void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count) | ||
250 | { | ||
251 | if (CHECK_AX88796L_PORT(port)) | ||
252 | maybebadio(insl, port); | ||
253 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
254 | volatile __u32 *p = (__u32 *)PCI_IOMAP(port); | ||
255 | |||
256 | while (count--) *((__u32 *) addr)++ = *p; | ||
257 | } else | ||
258 | maybebadio(insl, port); | ||
259 | } | ||
260 | |||
261 | void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count) | ||
262 | { | ||
263 | volatile __u8 *bp; | ||
264 | volatile __u16 *p; | ||
265 | |||
266 | if (CHECK_AX88796L_PORT(port)) { | ||
267 | p = (volatile unsigned short *)port88796l(port, 0); | ||
268 | while (count--) *p = *((unsigned char *) addr)++; | ||
269 | } else if (PXSEG(port)) | ||
270 | while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++; | ||
271 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
272 | bp = (__u8 *)PCI_IOMAP(port); | ||
273 | while (count--) *bp = *((volatile unsigned char *) addr)++; | ||
274 | } else { | ||
275 | p = (volatile unsigned short *)port2adr(port); | ||
276 | while (count--) *p = *((unsigned char *) addr)++; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count) | ||
281 | { | ||
282 | volatile __u16 *p; | ||
283 | |||
284 | if (CHECK_AX88796L_PORT(port)) | ||
285 | p = (volatile unsigned short *)port88796l(port, 1); | ||
286 | else if (PXSEG(port)) | ||
287 | p = (volatile unsigned short *)port; | ||
288 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) | ||
289 | p = (volatile unsigned short *)PCI_IOMAP(port); | ||
290 | else | ||
291 | p = (volatile unsigned short *)port2adr(port); | ||
292 | while (count--) *p = *((__u16 *) addr)++; | ||
293 | } | ||
294 | |||
295 | void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count) | ||
296 | { | ||
297 | if (CHECK_AX88796L_PORT(port)) | ||
298 | maybebadio(outsl, port); | ||
299 | else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) { | ||
300 | volatile __u32 *p = (__u32 *)PCI_IOMAP(port); | ||
301 | |||
302 | while (count--) *p = *((__u32 *) addr)++; | ||
303 | } else | ||
304 | maybebadio(outsl, port); | ||
305 | } | ||
306 | |||
307 | void *rts7751r2d_ioremap(unsigned long offset, unsigned long size) | ||
308 | { | ||
309 | if (offset >= 0xfd000000) | ||
310 | return (void *)offset; | ||
311 | else | ||
312 | return (void *)P2SEGADDR(offset); | ||
313 | } | ||
314 | EXPORT_SYMBOL(rts7751r2d_ioremap); | ||
315 | |||
316 | unsigned long rts7751r2d_isa_port2addr(unsigned long offset) | ||
317 | { | ||
318 | return port2adr(offset); | ||
319 | } | ||
diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c new file mode 100644 index 000000000000..95717f4f1e2d --- /dev/null +++ b/arch/sh/boards/renesas/rts7751r2d/irq.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/renesas/rts7751r2d/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Renesas Technology Sales RTS7751R2D Support. | ||
7 | * | ||
8 | * Modified for RTS7751R2D by | ||
9 | * Atom Create Engineering Co., Ltd. 2002. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/irq.h> | ||
17 | #include <asm/rts7751r2d/rts7751r2d.h> | ||
18 | |||
19 | #if defined(CONFIG_RTS7751R2D_REV11) | ||
20 | static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0}; | ||
21 | #else | ||
22 | static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0}; | ||
23 | #endif | ||
24 | |||
25 | extern int voyagergx_irq_demux(int irq); | ||
26 | extern void setup_voyagergx_irq(void); | ||
27 | |||
28 | static void enable_rts7751r2d_irq(unsigned int irq); | ||
29 | static void disable_rts7751r2d_irq(unsigned int irq); | ||
30 | |||
31 | /* shutdown is same as "disable" */ | ||
32 | #define shutdown_rts7751r2d_irq disable_rts7751r2d_irq | ||
33 | |||
34 | static void ack_rts7751r2d_irq(unsigned int irq); | ||
35 | static void end_rts7751r2d_irq(unsigned int irq); | ||
36 | |||
37 | static unsigned int startup_rts7751r2d_irq(unsigned int irq) | ||
38 | { | ||
39 | enable_rts7751r2d_irq(irq); | ||
40 | return 0; /* never anything pending */ | ||
41 | } | ||
42 | |||
43 | static void disable_rts7751r2d_irq(unsigned int irq) | ||
44 | { | ||
45 | unsigned long flags; | ||
46 | unsigned short val; | ||
47 | unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]); | ||
48 | |||
49 | /* Set the priority in IPR to 0 */ | ||
50 | local_irq_save(flags); | ||
51 | val = ctrl_inw(IRLCNTR1); | ||
52 | val &= mask; | ||
53 | ctrl_outw(val, IRLCNTR1); | ||
54 | local_irq_restore(flags); | ||
55 | } | ||
56 | |||
57 | static void enable_rts7751r2d_irq(unsigned int irq) | ||
58 | { | ||
59 | unsigned long flags; | ||
60 | unsigned short val; | ||
61 | unsigned short value = (0x0001 << mask_pos[irq]); | ||
62 | |||
63 | /* Set priority in IPR back to original value */ | ||
64 | local_irq_save(flags); | ||
65 | val = ctrl_inw(IRLCNTR1); | ||
66 | val |= value; | ||
67 | ctrl_outw(val, IRLCNTR1); | ||
68 | local_irq_restore(flags); | ||
69 | } | ||
70 | |||
71 | int rts7751r2d_irq_demux(int irq) | ||
72 | { | ||
73 | int demux_irq; | ||
74 | |||
75 | demux_irq = voyagergx_irq_demux(irq); | ||
76 | return demux_irq; | ||
77 | } | ||
78 | |||
79 | static void ack_rts7751r2d_irq(unsigned int irq) | ||
80 | { | ||
81 | disable_rts7751r2d_irq(irq); | ||
82 | } | ||
83 | |||
84 | static void end_rts7751r2d_irq(unsigned int irq) | ||
85 | { | ||
86 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
87 | enable_rts7751r2d_irq(irq); | ||
88 | } | ||
89 | |||
90 | static struct hw_interrupt_type rts7751r2d_irq_type = { | ||
91 | "RTS7751R2D IRQ", | ||
92 | startup_rts7751r2d_irq, | ||
93 | shutdown_rts7751r2d_irq, | ||
94 | enable_rts7751r2d_irq, | ||
95 | disable_rts7751r2d_irq, | ||
96 | ack_rts7751r2d_irq, | ||
97 | end_rts7751r2d_irq, | ||
98 | }; | ||
99 | |||
100 | static void make_rts7751r2d_irq(unsigned int irq) | ||
101 | { | ||
102 | disable_irq_nosync(irq); | ||
103 | irq_desc[irq].handler = &rts7751r2d_irq_type; | ||
104 | disable_rts7751r2d_irq(irq); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Initialize IRQ setting | ||
109 | */ | ||
110 | void __init init_rts7751r2d_IRQ(void) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | /* IRL0=KEY Input | ||
115 | * IRL1=Ethernet | ||
116 | * IRL2=CF Card | ||
117 | * IRL3=CF Card Insert | ||
118 | * IRL4=PCMCIA | ||
119 | * IRL5=VOYAGER | ||
120 | * IRL6=RTC Alarm | ||
121 | * IRL7=RTC Timer | ||
122 | * IRL8=SD Card | ||
123 | * IRL9=PCI Slot #1 | ||
124 | * IRL10=PCI Slot #2 | ||
125 | * IRL11=Extention #0 | ||
126 | * IRL12=Extention #1 | ||
127 | * IRL13=Extention #2 | ||
128 | * IRL14=Extention #3 | ||
129 | */ | ||
130 | |||
131 | for (i=0; i<15; i++) | ||
132 | make_rts7751r2d_irq(i); | ||
133 | |||
134 | setup_voyagergx_irq(); | ||
135 | } | ||
diff --git a/arch/sh/boards/renesas/rts7751r2d/led.c b/arch/sh/boards/renesas/rts7751r2d/led.c new file mode 100644 index 000000000000..9993259a894f --- /dev/null +++ b/arch/sh/boards/renesas/rts7751r2d/led.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/led_rts7751r2d.c | ||
3 | * | ||
4 | * Copyright (C) Atom Create Engineering Co., Ltd. | ||
5 | * | ||
6 | * May be copied or modified under the terms of GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * This file contains Renesas Technology Sales RTS7751R2D specific LED code. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/rts7751r2d/rts7751r2d.h> | ||
15 | |||
16 | extern unsigned int debug_counter; | ||
17 | |||
18 | #ifdef CONFIG_HEARTBEAT | ||
19 | |||
20 | #include <linux/sched.h> | ||
21 | |||
22 | /* Cycle the LED's in the clasic Knightriger/Sun pattern */ | ||
23 | void heartbeat_rts7751r2d(void) | ||
24 | { | ||
25 | static unsigned int cnt = 0, period = 0; | ||
26 | volatile unsigned short *p = (volatile unsigned short *)PA_OUTPORT; | ||
27 | static unsigned bit = 0, up = 1; | ||
28 | |||
29 | cnt += 1; | ||
30 | if (cnt < period) | ||
31 | return; | ||
32 | |||
33 | cnt = 0; | ||
34 | |||
35 | /* Go through the points (roughly!): | ||
36 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35, f(int)->110 | ||
37 | */ | ||
38 | period = 110 - ((300 << FSHIFT)/((avenrun[0]/5) + (3<<FSHIFT))); | ||
39 | |||
40 | *p = 1 << bit; | ||
41 | if (up) | ||
42 | if (bit == 7) { | ||
43 | bit--; | ||
44 | up = 0; | ||
45 | } else | ||
46 | bit++; | ||
47 | else if (bit == 0) | ||
48 | up = 1; | ||
49 | else | ||
50 | bit--; | ||
51 | } | ||
52 | #endif /* CONFIG_HEARTBEAT */ | ||
53 | |||
54 | void rts7751r2d_led(unsigned short value) | ||
55 | { | ||
56 | ctrl_outw(value, PA_OUTPORT); | ||
57 | } | ||
58 | |||
59 | void debug_led_disp(void) | ||
60 | { | ||
61 | unsigned short value; | ||
62 | |||
63 | value = (unsigned short)debug_counter++; | ||
64 | rts7751r2d_led(value); | ||
65 | if (value == 0xff) | ||
66 | debug_counter = 0; | ||
67 | } | ||
diff --git a/arch/sh/boards/renesas/rts7751r2d/mach.c b/arch/sh/boards/renesas/rts7751r2d/mach.c new file mode 100644 index 000000000000..1efc18e786d5 --- /dev/null +++ b/arch/sh/boards/renesas/rts7751r2d/mach.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/mach_rts7751r2d.c | ||
3 | * | ||
4 | * Minor tweak of mach_se.c file to reference rts7751r2d-specific items. | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the Renesas Technology sales RTS7751R2D | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/types.h> | ||
15 | |||
16 | #include <asm/machvec.h> | ||
17 | #include <asm/rtc.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/rts7751r2d/io.h> | ||
20 | |||
21 | extern void heartbeat_rts7751r2d(void); | ||
22 | extern void init_rts7751r2d_IRQ(void); | ||
23 | extern void *rts7751r2d_ioremap(unsigned long, unsigned long); | ||
24 | extern int rts7751r2d_irq_demux(int irq); | ||
25 | |||
26 | extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, int); | ||
27 | extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t); | ||
28 | |||
29 | /* | ||
30 | * The Machine Vector | ||
31 | */ | ||
32 | |||
33 | struct sh_machine_vector mv_rts7751r2d __initmv = { | ||
34 | .mv_nr_irqs = 72, | ||
35 | |||
36 | .mv_inb = rts7751r2d_inb, | ||
37 | .mv_inw = rts7751r2d_inw, | ||
38 | .mv_inl = rts7751r2d_inl, | ||
39 | .mv_outb = rts7751r2d_outb, | ||
40 | .mv_outw = rts7751r2d_outw, | ||
41 | .mv_outl = rts7751r2d_outl, | ||
42 | |||
43 | .mv_inb_p = rts7751r2d_inb_p, | ||
44 | .mv_inw_p = rts7751r2d_inw, | ||
45 | .mv_inl_p = rts7751r2d_inl, | ||
46 | .mv_outb_p = rts7751r2d_outb_p, | ||
47 | .mv_outw_p = rts7751r2d_outw, | ||
48 | .mv_outl_p = rts7751r2d_outl, | ||
49 | |||
50 | .mv_insb = rts7751r2d_insb, | ||
51 | .mv_insw = rts7751r2d_insw, | ||
52 | .mv_insl = rts7751r2d_insl, | ||
53 | .mv_outsb = rts7751r2d_outsb, | ||
54 | .mv_outsw = rts7751r2d_outsw, | ||
55 | .mv_outsl = rts7751r2d_outsl, | ||
56 | |||
57 | .mv_ioremap = rts7751r2d_ioremap, | ||
58 | .mv_isa_port2addr = rts7751r2d_isa_port2addr, | ||
59 | .mv_init_irq = init_rts7751r2d_IRQ, | ||
60 | #ifdef CONFIG_HEARTBEAT | ||
61 | .mv_heartbeat = heartbeat_rts7751r2d, | ||
62 | #endif | ||
63 | .mv_irq_demux = rts7751r2d_irq_demux, | ||
64 | |||
65 | #ifdef CONFIG_USB_OHCI_HCD | ||
66 | .mv_consistent_alloc = voyagergx_consistent_alloc, | ||
67 | .mv_consistent_free = voyagergx_consistent_free, | ||
68 | #endif | ||
69 | }; | ||
70 | ALIAS_MV(rts7751r2d) | ||
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c new file mode 100644 index 000000000000..2587fd1a0240 --- /dev/null +++ b/arch/sh/boards/renesas/rts7751r2d/setup.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/setup_rts7751r2d.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Renesas Technology Sales RTS7751R2D Support. | ||
7 | * | ||
8 | * Modified for RTS7751R2D by | ||
9 | * Atom Create Engineering Co., Ltd. 2002. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/rts7751r2d/rts7751r2d.h> | ||
15 | |||
16 | unsigned int debug_counter; | ||
17 | |||
18 | const char *get_system_type(void) | ||
19 | { | ||
20 | return "RTS7751R2D"; | ||
21 | } | ||
22 | |||
23 | /* | ||
24 | * Initialize the board | ||
25 | */ | ||
26 | void __init platform_setup(void) | ||
27 | { | ||
28 | printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n"); | ||
29 | ctrl_outw(0x0000, PA_OUTPORT); | ||
30 | debug_counter = 0; | ||
31 | } | ||
diff --git a/arch/sh/boards/renesas/systemh/Makefile b/arch/sh/boards/renesas/systemh/Makefile new file mode 100644 index 000000000000..2cc6a23d9d39 --- /dev/null +++ b/arch/sh/boards/renesas/systemh/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the SystemH specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o irq.o io.o | ||
6 | |||
7 | # XXX: This wants to be consolidated in arch/sh/drivers/pci, and more | ||
8 | # importantly, with the generic sh7751_pcic_init() code. For now, we'll | ||
9 | # just abuse the hell out of kbuild, because we can.. | ||
10 | |||
11 | obj-$(CONFIG_PCI) += pci.o | ||
12 | pci-y := ../../se/7751/pci.o | ||
13 | |||
diff --git a/arch/sh/boards/renesas/systemh/io.c b/arch/sh/boards/renesas/systemh/io.c new file mode 100644 index 000000000000..cf979011aa94 --- /dev/null +++ b/arch/sh/boards/renesas/systemh/io.c | |||
@@ -0,0 +1,283 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/systemh/io.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Ian da Silva, Jeremy Siegel | ||
5 | * Based largely on io_se.c. | ||
6 | * | ||
7 | * I/O routine for Hitachi 7751 Systemh. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <asm/systemh/7751systemh.h> | ||
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/io.h> | ||
16 | |||
17 | #include <linux/pci.h> | ||
18 | #include "../../drivers/pci/pci-sh7751.h" | ||
19 | |||
20 | /* | ||
21 | * The 7751 SystemH Engine uses the built-in PCI controller (PCIC) | ||
22 | * of the 7751 processor, and has a SuperIO accessible on its memory | ||
23 | * bus. | ||
24 | */ | ||
25 | |||
26 | #define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR) | ||
27 | #define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR) | ||
28 | #define PCI_IO_AREA SH7751_PCI_IO_BASE | ||
29 | #define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE | ||
30 | |||
31 | #define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK)) | ||
32 | #define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area | ||
33 | of smc lan chip*/ | ||
34 | |||
35 | #define maybebadio(name,port) \ | ||
36 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
37 | #name, (port), (__u32) __builtin_return_address(0)) | ||
38 | |||
39 | static inline void delay(void) | ||
40 | { | ||
41 | ctrl_inw(0xa0000000); | ||
42 | } | ||
43 | |||
44 | static inline volatile __u16 * | ||
45 | port2adr(unsigned int port) | ||
46 | { | ||
47 | if (port >= 0x2000) | ||
48 | return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); | ||
49 | #if 0 | ||
50 | else | ||
51 | return (volatile __u16 *) (PA_SUPERIO + (port << 1)); | ||
52 | #endif | ||
53 | maybebadio(name,(unsigned long)port); | ||
54 | return (volatile __u16*)port; | ||
55 | } | ||
56 | |||
57 | /* In case someone configures the kernel w/o PCI support: in that */ | ||
58 | /* scenario, don't ever bother to check for PCI-window addresses */ | ||
59 | |||
60 | /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */ | ||
61 | #if defined(CONFIG_PCI) | ||
62 | #define CHECK_SH7751_PCIIO(port) \ | ||
63 | ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE))) | ||
64 | #else | ||
65 | #define CHECK_SH7751_PCIIO(port) (0) | ||
66 | #endif | ||
67 | |||
68 | /* | ||
69 | * General outline: remap really low stuff [eventually] to SuperIO, | ||
70 | * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) | ||
71 | * is mapped through the PCI IO window. Stuff with high bits (PXSEG) | ||
72 | * should be way beyond the window, and is used w/o translation for | ||
73 | * compatibility. | ||
74 | */ | ||
75 | unsigned char sh7751systemh_inb(unsigned long port) | ||
76 | { | ||
77 | if (PXSEG(port)) | ||
78 | return *(volatile unsigned char *)port; | ||
79 | else if (CHECK_SH7751_PCIIO(port)) | ||
80 | return *(volatile unsigned char *)PCI_IOMAP(port); | ||
81 | else if (port <= 0x3F1) | ||
82 | return *(volatile unsigned char *)ETHER_IOMAP(port); | ||
83 | else | ||
84 | return (*port2adr(port))&0xff; | ||
85 | } | ||
86 | |||
87 | unsigned char sh7751systemh_inb_p(unsigned long port) | ||
88 | { | ||
89 | unsigned char v; | ||
90 | |||
91 | if (PXSEG(port)) | ||
92 | v = *(volatile unsigned char *)port; | ||
93 | else if (CHECK_SH7751_PCIIO(port)) | ||
94 | v = *(volatile unsigned char *)PCI_IOMAP(port); | ||
95 | else if (port <= 0x3F1) | ||
96 | v = *(volatile unsigned char *)ETHER_IOMAP(port); | ||
97 | else | ||
98 | v = (*port2adr(port))&0xff; | ||
99 | delay(); | ||
100 | return v; | ||
101 | } | ||
102 | |||
103 | unsigned short sh7751systemh_inw(unsigned long port) | ||
104 | { | ||
105 | if (PXSEG(port)) | ||
106 | return *(volatile unsigned short *)port; | ||
107 | else if (CHECK_SH7751_PCIIO(port)) | ||
108 | return *(volatile unsigned short *)PCI_IOMAP(port); | ||
109 | else if (port >= 0x2000) | ||
110 | return *port2adr(port); | ||
111 | else if (port <= 0x3F1) | ||
112 | return *(volatile unsigned int *)ETHER_IOMAP(port); | ||
113 | else | ||
114 | maybebadio(inw, port); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | unsigned int sh7751systemh_inl(unsigned long port) | ||
119 | { | ||
120 | if (PXSEG(port)) | ||
121 | return *(volatile unsigned long *)port; | ||
122 | else if (CHECK_SH7751_PCIIO(port)) | ||
123 | return *(volatile unsigned int *)PCI_IOMAP(port); | ||
124 | else if (port >= 0x2000) | ||
125 | return *port2adr(port); | ||
126 | else if (port <= 0x3F1) | ||
127 | return *(volatile unsigned int *)ETHER_IOMAP(port); | ||
128 | else | ||
129 | maybebadio(inl, port); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | void sh7751systemh_outb(unsigned char value, unsigned long port) | ||
134 | { | ||
135 | |||
136 | if (PXSEG(port)) | ||
137 | *(volatile unsigned char *)port = value; | ||
138 | else if (CHECK_SH7751_PCIIO(port)) | ||
139 | *((unsigned char*)PCI_IOMAP(port)) = value; | ||
140 | else if (port <= 0x3F1) | ||
141 | *(volatile unsigned char *)ETHER_IOMAP(port) = value; | ||
142 | else | ||
143 | *(port2adr(port)) = value; | ||
144 | } | ||
145 | |||
146 | void sh7751systemh_outb_p(unsigned char value, unsigned long port) | ||
147 | { | ||
148 | if (PXSEG(port)) | ||
149 | *(volatile unsigned char *)port = value; | ||
150 | else if (CHECK_SH7751_PCIIO(port)) | ||
151 | *((unsigned char*)PCI_IOMAP(port)) = value; | ||
152 | else if (port <= 0x3F1) | ||
153 | *(volatile unsigned char *)ETHER_IOMAP(port) = value; | ||
154 | else | ||
155 | *(port2adr(port)) = value; | ||
156 | delay(); | ||
157 | } | ||
158 | |||
159 | void sh7751systemh_outw(unsigned short value, unsigned long port) | ||
160 | { | ||
161 | if (PXSEG(port)) | ||
162 | *(volatile unsigned short *)port = value; | ||
163 | else if (CHECK_SH7751_PCIIO(port)) | ||
164 | *((unsigned short *)PCI_IOMAP(port)) = value; | ||
165 | else if (port >= 0x2000) | ||
166 | *port2adr(port) = value; | ||
167 | else if (port <= 0x3F1) | ||
168 | *(volatile unsigned short *)ETHER_IOMAP(port) = value; | ||
169 | else | ||
170 | maybebadio(outw, port); | ||
171 | } | ||
172 | |||
173 | void sh7751systemh_outl(unsigned int value, unsigned long port) | ||
174 | { | ||
175 | if (PXSEG(port)) | ||
176 | *(volatile unsigned long *)port = value; | ||
177 | else if (CHECK_SH7751_PCIIO(port)) | ||
178 | *((unsigned long*)PCI_IOMAP(port)) = value; | ||
179 | else | ||
180 | maybebadio(outl, port); | ||
181 | } | ||
182 | |||
183 | void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count) | ||
184 | { | ||
185 | unsigned char *p = addr; | ||
186 | while (count--) *p++ = sh7751systemh_inb(port); | ||
187 | } | ||
188 | |||
189 | void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count) | ||
190 | { | ||
191 | unsigned short *p = addr; | ||
192 | while (count--) *p++ = sh7751systemh_inw(port); | ||
193 | } | ||
194 | |||
195 | void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count) | ||
196 | { | ||
197 | maybebadio(insl, port); | ||
198 | } | ||
199 | |||
200 | void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count) | ||
201 | { | ||
202 | unsigned char *p = (unsigned char*)addr; | ||
203 | while (count--) sh7751systemh_outb(*p++, port); | ||
204 | } | ||
205 | |||
206 | void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count) | ||
207 | { | ||
208 | unsigned short *p = (unsigned short*)addr; | ||
209 | while (count--) sh7751systemh_outw(*p++, port); | ||
210 | } | ||
211 | |||
212 | void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count) | ||
213 | { | ||
214 | maybebadio(outsw, port); | ||
215 | } | ||
216 | |||
217 | /* For read/write calls, just copy generic (pass-thru); PCIMBR is */ | ||
218 | /* already set up. For a larger memory space, these would need to */ | ||
219 | /* reset PCIMBR as needed on a per-call basis... */ | ||
220 | |||
221 | unsigned char sh7751systemh_readb(unsigned long addr) | ||
222 | { | ||
223 | return *(volatile unsigned char*)addr; | ||
224 | } | ||
225 | |||
226 | unsigned short sh7751systemh_readw(unsigned long addr) | ||
227 | { | ||
228 | return *(volatile unsigned short*)addr; | ||
229 | } | ||
230 | |||
231 | unsigned int sh7751systemh_readl(unsigned long addr) | ||
232 | { | ||
233 | return *(volatile unsigned long*)addr; | ||
234 | } | ||
235 | |||
236 | void sh7751systemh_writeb(unsigned char b, unsigned long addr) | ||
237 | { | ||
238 | *(volatile unsigned char*)addr = b; | ||
239 | } | ||
240 | |||
241 | void sh7751systemh_writew(unsigned short b, unsigned long addr) | ||
242 | { | ||
243 | *(volatile unsigned short*)addr = b; | ||
244 | } | ||
245 | |||
246 | void sh7751systemh_writel(unsigned int b, unsigned long addr) | ||
247 | { | ||
248 | *(volatile unsigned long*)addr = b; | ||
249 | } | ||
250 | |||
251 | |||
252 | |||
253 | /* Map ISA bus address to the real address. Only for PCMCIA. */ | ||
254 | |||
255 | /* ISA page descriptor. */ | ||
256 | static __u32 sh_isa_memmap[256]; | ||
257 | |||
258 | #if 0 | ||
259 | static int | ||
260 | sh_isa_mmap(__u32 start, __u32 length, __u32 offset) | ||
261 | { | ||
262 | int idx; | ||
263 | |||
264 | if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000)) | ||
265 | return -1; | ||
266 | |||
267 | idx = start >> 12; | ||
268 | sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff); | ||
269 | printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n", | ||
270 | start, length, offset, idx, sh_isa_memmap[idx]); | ||
271 | return 0; | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | unsigned long | ||
276 | sh7751systemh_isa_port2addr(unsigned long offset) | ||
277 | { | ||
278 | int idx; | ||
279 | |||
280 | idx = (offset >> 12) & 0xff; | ||
281 | offset &= 0xfff; | ||
282 | return sh_isa_memmap[idx] + offset; | ||
283 | } | ||
diff --git a/arch/sh/boards/renesas/systemh/irq.c b/arch/sh/boards/renesas/systemh/irq.c new file mode 100644 index 000000000000..5675a4134eee --- /dev/null +++ b/arch/sh/boards/renesas/systemh/irq.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/systemh/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Hitachi SystemH Support. | ||
7 | * | ||
8 | * Modified for 7751 SystemH by | ||
9 | * Jonathan Short. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <linux/hdreg.h> | ||
17 | #include <linux/ide.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/mach/7751systemh.h> | ||
20 | #include <asm/smc37c93x.h> | ||
21 | |||
22 | /* address of external interrupt mask register | ||
23 | * address must be set prior to use these (maybe in init_XXX_irq()) | ||
24 | * XXX : is it better to use .config than specifying it in code? */ | ||
25 | static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004; | ||
26 | static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000; | ||
27 | |||
28 | /* forward declaration */ | ||
29 | static unsigned int startup_systemh_irq(unsigned int irq); | ||
30 | static void shutdown_systemh_irq(unsigned int irq); | ||
31 | static void enable_systemh_irq(unsigned int irq); | ||
32 | static void disable_systemh_irq(unsigned int irq); | ||
33 | static void mask_and_ack_systemh(unsigned int); | ||
34 | static void end_systemh_irq(unsigned int irq); | ||
35 | |||
36 | /* hw_interrupt_type */ | ||
37 | static struct hw_interrupt_type systemh_irq_type = { | ||
38 | " SystemH Register", | ||
39 | startup_systemh_irq, | ||
40 | shutdown_systemh_irq, | ||
41 | enable_systemh_irq, | ||
42 | disable_systemh_irq, | ||
43 | mask_and_ack_systemh, | ||
44 | end_systemh_irq | ||
45 | }; | ||
46 | |||
47 | static unsigned int startup_systemh_irq(unsigned int irq) | ||
48 | { | ||
49 | enable_systemh_irq(irq); | ||
50 | return 0; /* never anything pending */ | ||
51 | } | ||
52 | |||
53 | static void shutdown_systemh_irq(unsigned int irq) | ||
54 | { | ||
55 | disable_systemh_irq(irq); | ||
56 | } | ||
57 | |||
58 | static void disable_systemh_irq(unsigned int irq) | ||
59 | { | ||
60 | if (systemh_irq_mask_register) { | ||
61 | unsigned long flags; | ||
62 | unsigned long val, mask = 0x01 << 1; | ||
63 | |||
64 | /* Clear the "irq"th bit in the mask and set it in the request */ | ||
65 | local_irq_save(flags); | ||
66 | |||
67 | val = ctrl_inl((unsigned long)systemh_irq_mask_register); | ||
68 | val &= ~mask; | ||
69 | ctrl_outl(val, (unsigned long)systemh_irq_mask_register); | ||
70 | |||
71 | val = ctrl_inl((unsigned long)systemh_irq_request_register); | ||
72 | val |= mask; | ||
73 | ctrl_outl(val, (unsigned long)systemh_irq_request_register); | ||
74 | |||
75 | local_irq_restore(flags); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static void enable_systemh_irq(unsigned int irq) | ||
80 | { | ||
81 | if (systemh_irq_mask_register) { | ||
82 | unsigned long flags; | ||
83 | unsigned long val, mask = 0x01 << 1; | ||
84 | |||
85 | /* Set "irq"th bit in the mask register */ | ||
86 | local_irq_save(flags); | ||
87 | val = ctrl_inl((unsigned long)systemh_irq_mask_register); | ||
88 | val |= mask; | ||
89 | ctrl_outl(val, (unsigned long)systemh_irq_mask_register); | ||
90 | local_irq_restore(flags); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static void mask_and_ack_systemh(unsigned int irq) | ||
95 | { | ||
96 | disable_systemh_irq(irq); | ||
97 | } | ||
98 | |||
99 | static void end_systemh_irq(unsigned int irq) | ||
100 | { | ||
101 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
102 | enable_systemh_irq(irq); | ||
103 | } | ||
104 | |||
105 | void make_systemh_irq(unsigned int irq) | ||
106 | { | ||
107 | disable_irq_nosync(irq); | ||
108 | irq_desc[irq].handler = &systemh_irq_type; | ||
109 | disable_systemh_irq(irq); | ||
110 | } | ||
111 | |||
diff --git a/arch/sh/boards/renesas/systemh/setup.c b/arch/sh/boards/renesas/systemh/setup.c new file mode 100644 index 000000000000..826fa3d7669c --- /dev/null +++ b/arch/sh/boards/renesas/systemh/setup.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/systemh/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * Copyright (C) 2003 Paul Mundt | ||
6 | * | ||
7 | * Hitachi SystemH Support. | ||
8 | * | ||
9 | * Modified for 7751 SystemH by Jonathan Short. | ||
10 | * | ||
11 | * Rewritten for 2.6 by Paul Mundt. | ||
12 | * | ||
13 | * This file is subject to the terms and conditions of the GNU General Public | ||
14 | * License. See the file "COPYING" in the main directory of this archive | ||
15 | * for more details. | ||
16 | */ | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/mach/7751systemh.h> | ||
19 | #include <asm/mach/io.h> | ||
20 | #include <asm/machvec.h> | ||
21 | |||
22 | extern void make_systemh_irq(unsigned int irq); | ||
23 | |||
24 | const char *get_system_type(void) | ||
25 | { | ||
26 | return "7751 SystemH"; | ||
27 | } | ||
28 | |||
29 | /* | ||
30 | * Initialize IRQ setting | ||
31 | */ | ||
32 | void __init init_7751systemh_IRQ(void) | ||
33 | { | ||
34 | /* make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); LAN */ | ||
35 | /* make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-4); */ | ||
36 | make_systemh_irq(0xb); /* Ethernet interrupt */ | ||
37 | } | ||
38 | |||
39 | struct sh_machine_vector mv_7751systemh __initmv = { | ||
40 | .mv_nr_irqs = 72, | ||
41 | |||
42 | .mv_inb = sh7751systemh_inb, | ||
43 | .mv_inw = sh7751systemh_inw, | ||
44 | .mv_inl = sh7751systemh_inl, | ||
45 | .mv_outb = sh7751systemh_outb, | ||
46 | .mv_outw = sh7751systemh_outw, | ||
47 | .mv_outl = sh7751systemh_outl, | ||
48 | |||
49 | .mv_inb_p = sh7751systemh_inb_p, | ||
50 | .mv_inw_p = sh7751systemh_inw, | ||
51 | .mv_inl_p = sh7751systemh_inl, | ||
52 | .mv_outb_p = sh7751systemh_outb_p, | ||
53 | .mv_outw_p = sh7751systemh_outw, | ||
54 | .mv_outl_p = sh7751systemh_outl, | ||
55 | |||
56 | .mv_insb = sh7751systemh_insb, | ||
57 | .mv_insw = sh7751systemh_insw, | ||
58 | .mv_insl = sh7751systemh_insl, | ||
59 | .mv_outsb = sh7751systemh_outsb, | ||
60 | .mv_outsw = sh7751systemh_outsw, | ||
61 | .mv_outsl = sh7751systemh_outsl, | ||
62 | |||
63 | .mv_readb = sh7751systemh_readb, | ||
64 | .mv_readw = sh7751systemh_readw, | ||
65 | .mv_readl = sh7751systemh_readl, | ||
66 | .mv_writeb = sh7751systemh_writeb, | ||
67 | .mv_writew = sh7751systemh_writew, | ||
68 | .mv_writel = sh7751systemh_writel, | ||
69 | |||
70 | .mv_isa_port2addr = sh7751systemh_isa_port2addr, | ||
71 | |||
72 | .mv_init_irq = init_7751systemh_IRQ, | ||
73 | }; | ||
74 | ALIAS_MV(7751systemh) | ||
75 | |||
76 | int __init platform_setup(void) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | |||
diff --git a/arch/sh/boards/saturn/Makefile b/arch/sh/boards/saturn/Makefile new file mode 100644 index 000000000000..75a3042e252e --- /dev/null +++ b/arch/sh/boards/saturn/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the Sega Saturn specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o io.o irq.o | ||
6 | |||
7 | obj-$(CONFIG_SMP) += smp.o | ||
8 | |||
diff --git a/arch/sh/boards/saturn/io.c b/arch/sh/boards/saturn/io.c new file mode 100644 index 000000000000..c6e4f7f2e686 --- /dev/null +++ b/arch/sh/boards/saturn/io.c | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/saturn/io.c | ||
3 | * | ||
4 | * I/O routines for the Sega Saturn. | ||
5 | * | ||
6 | * Copyright (C) 2002 Paul Mundt | ||
7 | * | ||
8 | * Released under the terms of the GNU GPL v2.0. | ||
9 | */ | ||
10 | #include <asm/saturn/io.h> | ||
11 | #include <asm/machvec.h> | ||
12 | |||
13 | unsigned long saturn_isa_port2addr(unsigned long offset) | ||
14 | { | ||
15 | return offset; | ||
16 | } | ||
17 | |||
18 | void *saturn_ioremap(unsigned long offset, unsigned long size) | ||
19 | { | ||
20 | return (void *)offset; | ||
21 | } | ||
22 | |||
23 | void saturn_iounmap(void *addr) | ||
24 | { | ||
25 | } | ||
26 | |||
diff --git a/arch/sh/boards/saturn/irq.c b/arch/sh/boards/saturn/irq.c new file mode 100644 index 000000000000..15d1d3f0f787 --- /dev/null +++ b/arch/sh/boards/saturn/irq.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/saturn/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Paul Mundt | ||
5 | * | ||
6 | * Released under the terms of the GNU GPL v2.0. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <asm/irq.h> | ||
12 | #include <asm/io.h> | ||
13 | |||
14 | /* | ||
15 | * Interrupts map out as follows: | ||
16 | * | ||
17 | * Vector Name Mask | ||
18 | * | ||
19 | * 64 VBLANKIN 0x0001 | ||
20 | * 65 VBLANKOUT 0x0002 | ||
21 | * 66 HBLANKIN 0x0004 | ||
22 | * 67 TIMER0 0x0008 | ||
23 | * 68 TIMER1 0x0010 | ||
24 | * 69 DSPEND 0x0020 | ||
25 | * 70 SOUNDREQUEST 0x0040 | ||
26 | * 71 SYSTEMMANAGER 0x0080 | ||
27 | * 72 PAD 0x0100 | ||
28 | * 73 LEVEL2DMAEND 0x0200 | ||
29 | * 74 LEVEL1DMAEND 0x0400 | ||
30 | * 75 LEVEL0DMAEND 0x0800 | ||
31 | * 76 DMAILLEGAL 0x1000 | ||
32 | * 77 SRITEDRAWEND 0x2000 | ||
33 | * 78 ABUS 0x8000 | ||
34 | * | ||
35 | */ | ||
36 | #define SATURN_IRQ_MIN 64 /* VBLANKIN */ | ||
37 | #define SATURN_IRQ_MAX 78 /* ABUS */ | ||
38 | |||
39 | #define SATURN_IRQ_MASK 0xbfff | ||
40 | |||
41 | static inline u32 saturn_irq_mask(unsigned int irq_nr) | ||
42 | { | ||
43 | u32 mask; | ||
44 | |||
45 | mask = (1 << (irq_nr - SATURN_IRQ_MIN)); | ||
46 | mask <<= (irq_nr == SATURN_IRQ_MAX); | ||
47 | mask &= SATURN_IRQ_MASK; | ||
48 | |||
49 | return mask; | ||
50 | } | ||
51 | |||
52 | static inline void mask_saturn_irq(unsigned int irq_nr) | ||
53 | { | ||
54 | u32 mask; | ||
55 | |||
56 | mask = ctrl_inl(SATURN_IMR); | ||
57 | mask |= saturn_irq_mask(irq_nr); | ||
58 | ctrl_outl(mask, SATURN_IMR); | ||
59 | } | ||
60 | |||
61 | static inline void unmask_saturn_irq(unsigned int irq_nr) | ||
62 | { | ||
63 | u32 mask; | ||
64 | |||
65 | mask = ctrl_inl(SATURN_IMR); | ||
66 | mask &= ~saturn_irq_mask(irq_nr); | ||
67 | ctrl_outl(mask, SATURN_IMR); | ||
68 | } | ||
69 | |||
70 | static void disable_saturn_irq(unsigned int irq_nr) | ||
71 | { | ||
72 | mask_saturn_irq(irq_nr); | ||
73 | } | ||
74 | |||
75 | static void enable_saturn_irq(unsigned int irq_nr) | ||
76 | { | ||
77 | unmask_saturn_irq(irq_nr); | ||
78 | } | ||
79 | |||
80 | static void mask_and_ack_saturn_irq(unsigned int irq_nr) | ||
81 | { | ||
82 | mask_saturn_irq(irq_nr); | ||
83 | } | ||
84 | |||
85 | static void end_saturn_irq(unsigned int irq_nr) | ||
86 | { | ||
87 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
88 | unmask_saturn_irq(irq_nr); | ||
89 | } | ||
90 | |||
91 | static unsigned int startup_saturn_irq(unsigned int irq_nr) | ||
92 | { | ||
93 | unmask_saturn_irq(irq_nr); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void shutdown_saturn_irq(unsigned int irq_nr) | ||
99 | { | ||
100 | mask_saturn_irq(irq_nr); | ||
101 | } | ||
102 | |||
103 | static struct hw_interrupt_type saturn_int = { | ||
104 | .typename = "Saturn", | ||
105 | .enable = enable_saturn_irq, | ||
106 | .disable = disable_saturn_irq, | ||
107 | .ack = mask_and_ack_saturn_irq, | ||
108 | .end = end_saturn_irq, | ||
109 | .startup = startup_saturn_irq, | ||
110 | .shutdown = shutdown_saturn_irq, | ||
111 | }; | ||
112 | |||
113 | int saturn_irq_demux(int irq_nr) | ||
114 | { | ||
115 | /* FIXME */ | ||
116 | return irq_nr; | ||
117 | } | ||
118 | |||
diff --git a/arch/sh/boards/saturn/setup.c b/arch/sh/boards/saturn/setup.c new file mode 100644 index 000000000000..bea6c572ad82 --- /dev/null +++ b/arch/sh/boards/saturn/setup.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/saturn/setup.c | ||
3 | * | ||
4 | * Hardware support for the Sega Saturn. | ||
5 | * | ||
6 | * Copyright (c) 2002 Paul Mundt | ||
7 | * | ||
8 | * Released under the terms of the GNU GPL v2.0. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/io.h> | ||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/mach/io.h> | ||
16 | |||
17 | extern int saturn_irq_demux(int irq_nr); | ||
18 | |||
19 | const char *get_system_type(void) | ||
20 | { | ||
21 | return "Sega Saturn"; | ||
22 | } | ||
23 | |||
24 | /* | ||
25 | * The Machine Vector | ||
26 | */ | ||
27 | struct sh_machine_vector mv_saturn __initmv = { | ||
28 | .mv_nr_irqs = 80, /* Fix this later */ | ||
29 | |||
30 | .mv_isa_port2addr = saturn_isa_port2addr, | ||
31 | .mv_irq_demux = saturn_irq_demux, | ||
32 | |||
33 | .mv_ioremap = saturn_ioremap, | ||
34 | .mv_iounmap = saturn_iounmap, | ||
35 | }; | ||
36 | |||
37 | ALIAS_MV(saturn) | ||
38 | |||
39 | int __init platform_setup(void) | ||
40 | { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
diff --git a/arch/sh/boards/saturn/smp.c b/arch/sh/boards/saturn/smp.c new file mode 100644 index 000000000000..76460918c9cd --- /dev/null +++ b/arch/sh/boards/saturn/smp.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/saturn/smp.c | ||
3 | * | ||
4 | * SMP support for the Sega Saturn. | ||
5 | * | ||
6 | * Copyright (c) 2002 Paul Mundt | ||
7 | * | ||
8 | * Released under the terms of the GNU GPL v2.0. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/smp.h> | ||
13 | |||
14 | #include <asm/saturn/smpc.h> | ||
15 | |||
16 | extern void start_secondary(void); | ||
17 | |||
18 | void __smp_send_ipi(unsigned int cpu, unsigned int action) | ||
19 | { | ||
20 | /* Nothing here yet .. */ | ||
21 | } | ||
22 | |||
23 | unsigned int __smp_probe_cpus(void) | ||
24 | { | ||
25 | /* | ||
26 | * This is just a straightforward master/slave configuration, | ||
27 | * and probing isn't really supported.. | ||
28 | */ | ||
29 | return 2; | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * We're only allowed to do byte-access to SMPC registers. In | ||
34 | * addition to which, we treat them as write-only, since | ||
35 | * reading from them will return undefined data. | ||
36 | */ | ||
37 | static inline void smpc_slave_stop(unsigned int cpu) | ||
38 | { | ||
39 | smpc_barrier(); | ||
40 | ctrl_outb(1, SMPC_STATUS); | ||
41 | |||
42 | ctrl_outb(SMPC_CMD_SSHOFF, SMPC_COMMAND); | ||
43 | smpc_barrier(); | ||
44 | } | ||
45 | |||
46 | static inline void smpc_slave_start(unsigned int cpu) | ||
47 | { | ||
48 | ctrl_outb(1, SMPC_STATUS); | ||
49 | ctrl_outb(SMPC_CMD_SSHON, SMPC_COMMAND); | ||
50 | |||
51 | smpc_barrier(); | ||
52 | } | ||
53 | |||
54 | void __smp_slave_init(unsigned int cpu) | ||
55 | { | ||
56 | register unsigned long vbr; | ||
57 | void **entry; | ||
58 | |||
59 | __asm__ __volatile__ ("stc vbr, %0\n\t" : "=r" (vbr)); | ||
60 | entry = (void **)(vbr + 0x310 + 0x94); | ||
61 | |||
62 | smpc_slave_stop(cpu); | ||
63 | |||
64 | *(void **)entry = (void *)start_secondary; | ||
65 | |||
66 | smpc_slave_start(cpu); | ||
67 | } | ||
68 | |||
diff --git a/arch/sh/boards/se/7300/Makefile b/arch/sh/boards/se/7300/Makefile new file mode 100644 index 000000000000..0fbd4f47815c --- /dev/null +++ b/arch/sh/boards/se/7300/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the 7300 SolutionEngine specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o io.o irq.o | ||
6 | |||
7 | obj-$(CONFIG_HEARTBEAT) += led.o | ||
diff --git a/arch/sh/boards/se/7300/io.c b/arch/sh/boards/se/7300/io.c new file mode 100644 index 000000000000..3c89def46480 --- /dev/null +++ b/arch/sh/boards/se/7300/io.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/se/7300/io.c | ||
3 | * | ||
4 | * Copyright (C) 2003 YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp> | ||
5 | * Based on arch/sh/kernel/io_shmse.c | ||
6 | * | ||
7 | * I/O routine for SH-Mobile3 73180 SolutionEngine. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/mach/se7300.h> | ||
14 | #include <asm/io.h> | ||
15 | |||
16 | #define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a) | ||
17 | |||
18 | struct iop { | ||
19 | unsigned long start, end; | ||
20 | unsigned long base; | ||
21 | struct iop *(*check) (struct iop * p, unsigned long port); | ||
22 | unsigned char (*inb) (struct iop * p, unsigned long port); | ||
23 | unsigned short (*inw) (struct iop * p, unsigned long port); | ||
24 | void (*outb) (struct iop * p, unsigned char value, unsigned long port); | ||
25 | void (*outw) (struct iop * p, unsigned short value, unsigned long port); | ||
26 | }; | ||
27 | |||
28 | struct iop * | ||
29 | simple_check(struct iop *p, unsigned long port) | ||
30 | { | ||
31 | if ((p->start <= port) && (port <= p->end)) | ||
32 | return p; | ||
33 | else | ||
34 | badio(check, port); | ||
35 | } | ||
36 | |||
37 | struct iop * | ||
38 | ide_check(struct iop *p, unsigned long port) | ||
39 | { | ||
40 | if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7)) | ||
41 | return p; | ||
42 | return NULL; | ||
43 | } | ||
44 | |||
45 | unsigned char | ||
46 | simple_inb(struct iop *p, unsigned long port) | ||
47 | { | ||
48 | return *(unsigned char *) (p->base + port); | ||
49 | } | ||
50 | |||
51 | unsigned short | ||
52 | simple_inw(struct iop *p, unsigned long port) | ||
53 | { | ||
54 | return *(unsigned short *) (p->base + port); | ||
55 | } | ||
56 | |||
57 | void | ||
58 | simple_outb(struct iop *p, unsigned char value, unsigned long port) | ||
59 | { | ||
60 | *(unsigned char *) (p->base + port) = value; | ||
61 | } | ||
62 | |||
63 | void | ||
64 | simple_outw(struct iop *p, unsigned short value, unsigned long port) | ||
65 | { | ||
66 | *(unsigned short *) (p->base + port) = value; | ||
67 | } | ||
68 | |||
69 | unsigned char | ||
70 | pcc_inb(struct iop *p, unsigned long port) | ||
71 | { | ||
72 | unsigned long addr = p->base + port + 0x40000; | ||
73 | unsigned long v; | ||
74 | |||
75 | if (port & 1) | ||
76 | addr += 0x00400000; | ||
77 | v = *(volatile unsigned char *) addr; | ||
78 | return v; | ||
79 | } | ||
80 | |||
81 | void | ||
82 | pcc_outb(struct iop *p, unsigned char value, unsigned long port) | ||
83 | { | ||
84 | unsigned long addr = p->base + port + 0x40000; | ||
85 | |||
86 | if (port & 1) | ||
87 | addr += 0x00400000; | ||
88 | *(volatile unsigned char *) addr = value; | ||
89 | } | ||
90 | |||
91 | unsigned char | ||
92 | bad_inb(struct iop *p, unsigned long port) | ||
93 | { | ||
94 | badio(inb, port); | ||
95 | } | ||
96 | |||
97 | void | ||
98 | bad_outb(struct iop *p, unsigned char value, unsigned long port) | ||
99 | { | ||
100 | badio(inw, port); | ||
101 | } | ||
102 | |||
103 | /* MSTLANEX01 LAN at 0xb400:0000 */ | ||
104 | static struct iop laniop = { | ||
105 | .start = 0x300, | ||
106 | .end = 0x30f, | ||
107 | .base = 0xb4000000, | ||
108 | .check = simple_check, | ||
109 | .inb = simple_inb, | ||
110 | .inw = simple_inw, | ||
111 | .outb = simple_outb, | ||
112 | .outw = simple_outw, | ||
113 | }; | ||
114 | |||
115 | /* NE2000 pc card NIC */ | ||
116 | static struct iop neiop = { | ||
117 | .start = 0x280, | ||
118 | .end = 0x29f, | ||
119 | .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */ | ||
120 | .check = simple_check, | ||
121 | .inb = pcc_inb, | ||
122 | .inw = simple_inw, | ||
123 | .outb = pcc_outb, | ||
124 | .outw = simple_outw, | ||
125 | }; | ||
126 | |||
127 | /* CF in CF slot */ | ||
128 | static struct iop cfiop = { | ||
129 | .base = 0xb0600000, | ||
130 | .check = ide_check, | ||
131 | .inb = pcc_inb, | ||
132 | .inw = simple_inw, | ||
133 | .outb = pcc_outb, | ||
134 | .outw = simple_outw, | ||
135 | }; | ||
136 | |||
137 | static __inline__ struct iop * | ||
138 | port2iop(unsigned long port) | ||
139 | { | ||
140 | if (0) ; | ||
141 | #if defined(CONFIG_SMC91111) | ||
142 | else if (laniop.check(&laniop, port)) | ||
143 | return &laniop; | ||
144 | #endif | ||
145 | #if defined(CONFIG_NE2000) | ||
146 | else if (neiop.check(&neiop, port)) | ||
147 | return &neiop; | ||
148 | #endif | ||
149 | #if defined(CONFIG_IDE) | ||
150 | else if (cfiop.check(&cfiop, port)) | ||
151 | return &cfiop; | ||
152 | #endif | ||
153 | else | ||
154 | return &neiop; /* fallback */ | ||
155 | } | ||
156 | |||
157 | static inline void | ||
158 | delay(void) | ||
159 | { | ||
160 | ctrl_inw(0xac000000); | ||
161 | ctrl_inw(0xac000000); | ||
162 | } | ||
163 | |||
164 | unsigned char | ||
165 | sh7300se_inb(unsigned long port) | ||
166 | { | ||
167 | struct iop *p = port2iop(port); | ||
168 | return (p->inb) (p, port); | ||
169 | } | ||
170 | |||
171 | unsigned char | ||
172 | sh7300se_inb_p(unsigned long port) | ||
173 | { | ||
174 | unsigned char v = sh7300se_inb(port); | ||
175 | delay(); | ||
176 | return v; | ||
177 | } | ||
178 | |||
179 | unsigned short | ||
180 | sh7300se_inw(unsigned long port) | ||
181 | { | ||
182 | struct iop *p = port2iop(port); | ||
183 | return (p->inw) (p, port); | ||
184 | } | ||
185 | |||
186 | unsigned int | ||
187 | sh7300se_inl(unsigned long port) | ||
188 | { | ||
189 | badio(inl, port); | ||
190 | } | ||
191 | |||
192 | void | ||
193 | sh7300se_outb(unsigned char value, unsigned long port) | ||
194 | { | ||
195 | struct iop *p = port2iop(port); | ||
196 | (p->outb) (p, value, port); | ||
197 | } | ||
198 | |||
199 | void | ||
200 | sh7300se_outb_p(unsigned char value, unsigned long port) | ||
201 | { | ||
202 | sh7300se_outb(value, port); | ||
203 | delay(); | ||
204 | } | ||
205 | |||
206 | void | ||
207 | sh7300se_outw(unsigned short value, unsigned long port) | ||
208 | { | ||
209 | struct iop *p = port2iop(port); | ||
210 | (p->outw) (p, value, port); | ||
211 | } | ||
212 | |||
213 | void | ||
214 | sh7300se_outl(unsigned int value, unsigned long port) | ||
215 | { | ||
216 | badio(outl, port); | ||
217 | } | ||
218 | |||
219 | void | ||
220 | sh7300se_insb(unsigned long port, void *addr, unsigned long count) | ||
221 | { | ||
222 | unsigned char *a = addr; | ||
223 | struct iop *p = port2iop(port); | ||
224 | while (count--) | ||
225 | *a++ = (p->inb) (p, port); | ||
226 | } | ||
227 | |||
228 | void | ||
229 | sh7300se_insw(unsigned long port, void *addr, unsigned long count) | ||
230 | { | ||
231 | unsigned short *a = addr; | ||
232 | struct iop *p = port2iop(port); | ||
233 | while (count--) | ||
234 | *a++ = (p->inw) (p, port); | ||
235 | } | ||
236 | |||
237 | void | ||
238 | sh7300se_insl(unsigned long port, void *addr, unsigned long count) | ||
239 | { | ||
240 | badio(insl, port); | ||
241 | } | ||
242 | |||
243 | void | ||
244 | sh7300se_outsb(unsigned long port, const void *addr, unsigned long count) | ||
245 | { | ||
246 | unsigned char *a = (unsigned char *) addr; | ||
247 | struct iop *p = port2iop(port); | ||
248 | while (count--) | ||
249 | (p->outb) (p, *a++, port); | ||
250 | } | ||
251 | |||
252 | void | ||
253 | sh7300se_outsw(unsigned long port, const void *addr, unsigned long count) | ||
254 | { | ||
255 | unsigned short *a = (unsigned short *) addr; | ||
256 | struct iop *p = port2iop(port); | ||
257 | while (count--) | ||
258 | (p->outw) (p, *a++, port); | ||
259 | } | ||
260 | |||
261 | void | ||
262 | sh7300se_outsl(unsigned long port, const void *addr, unsigned long count) | ||
263 | { | ||
264 | badio(outsw, port); | ||
265 | } | ||
diff --git a/arch/sh/boards/se/7300/irq.c b/arch/sh/boards/se/7300/irq.c new file mode 100644 index 000000000000..96c8c23d6c93 --- /dev/null +++ b/arch/sh/boards/se/7300/irq.c | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/se/7300/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> | ||
5 | * | ||
6 | * SH-Mobile SolutionEngine 7300 Support. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/irq.h> | ||
13 | #include <asm/irq.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/mach/se7300.h> | ||
16 | |||
17 | /* | ||
18 | * Initialize IRQ setting | ||
19 | */ | ||
20 | void __init | ||
21 | init_7300se_IRQ(void) | ||
22 | { | ||
23 | ctrl_outw(0x0028, PA_EPLD_MODESET); /* mode set IRQ0,1 active low. */ | ||
24 | ctrl_outw(0xa000, INTC_ICR1); /* IRQ mode; IRQ0,1 enable. */ | ||
25 | ctrl_outw(0x0000, PORT_PFCR); /* use F for IRQ[3:0] and SIU. */ | ||
26 | |||
27 | /* PC_IRQ[0-3] -> IRQ0 (32) */ | ||
28 | make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, 0x0f - IRQ0_IRQ); | ||
29 | /* A_IRQ[0-3] -> IRQ1 (33) */ | ||
30 | make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, 0x0f - IRQ1_IRQ); | ||
31 | make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY); | ||
32 | make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | ||
33 | make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | ||
34 | make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | ||
35 | |||
36 | ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */ | ||
37 | } | ||
diff --git a/arch/sh/boards/se/7300/led.c b/arch/sh/boards/se/7300/led.c new file mode 100644 index 000000000000..02c7f846c84c --- /dev/null +++ b/arch/sh/boards/se/7300/led.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/se/7300/led.c | ||
3 | * | ||
4 | * Derived from linux/arch/sh/boards/se/770x/led.c | ||
5 | * | ||
6 | * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * This file contains Solution Engine specific LED code. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <asm/mach/se7300.h> | ||
17 | |||
18 | static void | ||
19 | mach_led(int position, int value) | ||
20 | { | ||
21 | volatile unsigned short *p = (volatile unsigned short *) PA_LED; | ||
22 | |||
23 | if (value) { | ||
24 | *p |= (1 << 8); | ||
25 | } else { | ||
26 | *p &= ~(1 << 8); | ||
27 | } | ||
28 | } | ||
29 | |||
30 | |||
31 | /* Cycle the LED's in the clasic Knightrider/Sun pattern */ | ||
32 | void | ||
33 | heartbeat_7300se(void) | ||
34 | { | ||
35 | static unsigned int cnt = 0, period = 0; | ||
36 | volatile unsigned short *p = (volatile unsigned short *) PA_LED; | ||
37 | static unsigned bit = 0, up = 1; | ||
38 | |||
39 | cnt += 1; | ||
40 | if (cnt < period) { | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | cnt = 0; | ||
45 | |||
46 | /* Go through the points (roughly!): | ||
47 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
48 | */ | ||
49 | period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT))); | ||
50 | |||
51 | if (up) { | ||
52 | if (bit == 7) { | ||
53 | bit--; | ||
54 | up = 0; | ||
55 | } else { | ||
56 | bit++; | ||
57 | } | ||
58 | } else { | ||
59 | if (bit == 0) { | ||
60 | bit++; | ||
61 | up = 1; | ||
62 | } else { | ||
63 | bit--; | ||
64 | } | ||
65 | } | ||
66 | *p = 1 << (bit + 8); | ||
67 | |||
68 | } | ||
69 | |||
diff --git a/arch/sh/boards/se/7300/setup.c b/arch/sh/boards/se/7300/setup.c new file mode 100644 index 000000000000..08536bc224dc --- /dev/null +++ b/arch/sh/boards/se/7300/setup.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/se/7300/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> | ||
5 | * | ||
6 | * SH-Mobile SolutionEngine 7300 Support. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <asm/machvec.h> | ||
13 | #include <asm/machvec_init.h> | ||
14 | #include <asm/mach/io.h> | ||
15 | |||
16 | void heartbeat_7300se(void); | ||
17 | void init_7300se_IRQ(void); | ||
18 | |||
19 | const char * | ||
20 | get_system_type(void) | ||
21 | { | ||
22 | return "SolutionEngine 7300"; | ||
23 | } | ||
24 | |||
25 | /* | ||
26 | * The Machine Vector | ||
27 | */ | ||
28 | |||
29 | struct sh_machine_vector mv_7300se __initmv = { | ||
30 | .mv_nr_irqs = 109, | ||
31 | .mv_inb = sh7300se_inb, | ||
32 | .mv_inw = sh7300se_inw, | ||
33 | .mv_inl = sh7300se_inl, | ||
34 | .mv_outb = sh7300se_outb, | ||
35 | .mv_outw = sh7300se_outw, | ||
36 | .mv_outl = sh7300se_outl, | ||
37 | |||
38 | .mv_inb_p = sh7300se_inb_p, | ||
39 | .mv_inw_p = sh7300se_inw, | ||
40 | .mv_inl_p = sh7300se_inl, | ||
41 | .mv_outb_p = sh7300se_outb_p, | ||
42 | .mv_outw_p = sh7300se_outw, | ||
43 | .mv_outl_p = sh7300se_outl, | ||
44 | |||
45 | .mv_insb = sh7300se_insb, | ||
46 | .mv_insw = sh7300se_insw, | ||
47 | .mv_insl = sh7300se_insl, | ||
48 | .mv_outsb = sh7300se_outsb, | ||
49 | .mv_outsw = sh7300se_outsw, | ||
50 | .mv_outsl = sh7300se_outsl, | ||
51 | |||
52 | .mv_init_irq = init_7300se_IRQ, | ||
53 | #ifdef CONFIG_HEARTBEAT | ||
54 | .mv_heartbeat = heartbeat_7300se, | ||
55 | #endif | ||
56 | }; | ||
57 | |||
58 | ALIAS_MV(7300se) | ||
59 | /* | ||
60 | * Initialize the board | ||
61 | */ | ||
62 | void __init | ||
63 | platform_setup(void) | ||
64 | { | ||
65 | |||
66 | } | ||
diff --git a/arch/sh/boards/se/73180/Makefile b/arch/sh/boards/se/73180/Makefile new file mode 100644 index 000000000000..8f63886a0f3f --- /dev/null +++ b/arch/sh/boards/se/73180/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the 73180 SolutionEngine specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o io.o irq.o | ||
6 | |||
7 | obj-$(CONFIG_HEARTBEAT) += led.o | ||
diff --git a/arch/sh/boards/se/73180/io.c b/arch/sh/boards/se/73180/io.c new file mode 100644 index 000000000000..73648cbe3678 --- /dev/null +++ b/arch/sh/boards/se/73180/io.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/se/73180/io.c | ||
3 | * | ||
4 | * Copyright (C) 2003 YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp> | ||
5 | * Based on arch/sh/boards/se/7300/io.c | ||
6 | * | ||
7 | * I/O routine for SH-Mobile3 73180 SolutionEngine. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/mach/se73180.h> | ||
14 | #include <asm/io.h> | ||
15 | |||
16 | #define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a) | ||
17 | |||
18 | struct iop { | ||
19 | unsigned long start, end; | ||
20 | unsigned long base; | ||
21 | struct iop *(*check) (struct iop * p, unsigned long port); | ||
22 | unsigned char (*inb) (struct iop * p, unsigned long port); | ||
23 | unsigned short (*inw) (struct iop * p, unsigned long port); | ||
24 | void (*outb) (struct iop * p, unsigned char value, unsigned long port); | ||
25 | void (*outw) (struct iop * p, unsigned short value, unsigned long port); | ||
26 | }; | ||
27 | |||
28 | struct iop * | ||
29 | simple_check(struct iop *p, unsigned long port) | ||
30 | { | ||
31 | if ((p->start <= port) && (port <= p->end)) | ||
32 | return p; | ||
33 | else | ||
34 | badio(check, port); | ||
35 | } | ||
36 | |||
37 | struct iop * | ||
38 | ide_check(struct iop *p, unsigned long port) | ||
39 | { | ||
40 | if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7)) | ||
41 | return p; | ||
42 | return NULL; | ||
43 | } | ||
44 | |||
45 | unsigned char | ||
46 | simple_inb(struct iop *p, unsigned long port) | ||
47 | { | ||
48 | return *(unsigned char *) (p->base + port); | ||
49 | } | ||
50 | |||
51 | unsigned short | ||
52 | simple_inw(struct iop *p, unsigned long port) | ||
53 | { | ||
54 | return *(unsigned short *) (p->base + port); | ||
55 | } | ||
56 | |||
57 | void | ||
58 | simple_outb(struct iop *p, unsigned char value, unsigned long port) | ||
59 | { | ||
60 | *(unsigned char *) (p->base + port) = value; | ||
61 | } | ||
62 | |||
63 | void | ||
64 | simple_outw(struct iop *p, unsigned short value, unsigned long port) | ||
65 | { | ||
66 | *(unsigned short *) (p->base + port) = value; | ||
67 | } | ||
68 | |||
69 | unsigned char | ||
70 | pcc_inb(struct iop *p, unsigned long port) | ||
71 | { | ||
72 | unsigned long addr = p->base + port + 0x40000; | ||
73 | unsigned long v; | ||
74 | |||
75 | if (port & 1) | ||
76 | addr += 0x00400000; | ||
77 | v = *(volatile unsigned char *) addr; | ||
78 | return v; | ||
79 | } | ||
80 | |||
81 | void | ||
82 | pcc_outb(struct iop *p, unsigned char value, unsigned long port) | ||
83 | { | ||
84 | unsigned long addr = p->base + port + 0x40000; | ||
85 | |||
86 | if (port & 1) | ||
87 | addr += 0x00400000; | ||
88 | *(volatile unsigned char *) addr = value; | ||
89 | } | ||
90 | |||
91 | unsigned char | ||
92 | bad_inb(struct iop *p, unsigned long port) | ||
93 | { | ||
94 | badio(inb, port); | ||
95 | } | ||
96 | |||
97 | void | ||
98 | bad_outb(struct iop *p, unsigned char value, unsigned long port) | ||
99 | { | ||
100 | badio(inw, port); | ||
101 | } | ||
102 | |||
103 | /* MSTLANEX01 LAN at 0xb400:0000 */ | ||
104 | static struct iop laniop = { | ||
105 | .start = 0x300, | ||
106 | .end = 0x30f, | ||
107 | .base = 0xb4000000, | ||
108 | .check = simple_check, | ||
109 | .inb = simple_inb, | ||
110 | .inw = simple_inw, | ||
111 | .outb = simple_outb, | ||
112 | .outw = simple_outw, | ||
113 | }; | ||
114 | |||
115 | /* NE2000 pc card NIC */ | ||
116 | static struct iop neiop = { | ||
117 | .start = 0x280, | ||
118 | .end = 0x29f, | ||
119 | .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */ | ||
120 | .check = simple_check, | ||
121 | .inb = pcc_inb, | ||
122 | .inw = simple_inw, | ||
123 | .outb = pcc_outb, | ||
124 | .outw = simple_outw, | ||
125 | }; | ||
126 | |||
127 | /* CF in CF slot */ | ||
128 | static struct iop cfiop = { | ||
129 | .base = 0xb0600000, | ||
130 | .check = ide_check, | ||
131 | .inb = pcc_inb, | ||
132 | .inw = simple_inw, | ||
133 | .outb = pcc_outb, | ||
134 | .outw = simple_outw, | ||
135 | }; | ||
136 | |||
137 | static __inline__ struct iop * | ||
138 | port2iop(unsigned long port) | ||
139 | { | ||
140 | if (0) ; | ||
141 | #if defined(CONFIG_SMC91111) | ||
142 | else if (laniop.check(&laniop, port)) | ||
143 | return &laniop; | ||
144 | #endif | ||
145 | #if defined(CONFIG_NE2000) | ||
146 | else if (neiop.check(&neiop, port)) | ||
147 | return &neiop; | ||
148 | #endif | ||
149 | #if defined(CONFIG_IDE) | ||
150 | else if (cfiop.check(&cfiop, port)) | ||
151 | return &cfiop; | ||
152 | #endif | ||
153 | else | ||
154 | return &neiop; /* fallback */ | ||
155 | } | ||
156 | |||
157 | static inline void | ||
158 | delay(void) | ||
159 | { | ||
160 | ctrl_inw(0xac000000); | ||
161 | ctrl_inw(0xac000000); | ||
162 | } | ||
163 | |||
164 | unsigned char | ||
165 | sh73180se_inb(unsigned long port) | ||
166 | { | ||
167 | struct iop *p = port2iop(port); | ||
168 | return (p->inb) (p, port); | ||
169 | } | ||
170 | |||
171 | unsigned char | ||
172 | sh73180se_inb_p(unsigned long port) | ||
173 | { | ||
174 | unsigned char v = sh73180se_inb(port); | ||
175 | delay(); | ||
176 | return v; | ||
177 | } | ||
178 | |||
179 | unsigned short | ||
180 | sh73180se_inw(unsigned long port) | ||
181 | { | ||
182 | struct iop *p = port2iop(port); | ||
183 | return (p->inw) (p, port); | ||
184 | } | ||
185 | |||
186 | unsigned int | ||
187 | sh73180se_inl(unsigned long port) | ||
188 | { | ||
189 | badio(inl, port); | ||
190 | } | ||
191 | |||
192 | void | ||
193 | sh73180se_outb(unsigned char value, unsigned long port) | ||
194 | { | ||
195 | struct iop *p = port2iop(port); | ||
196 | (p->outb) (p, value, port); | ||
197 | } | ||
198 | |||
199 | void | ||
200 | sh73180se_outb_p(unsigned char value, unsigned long port) | ||
201 | { | ||
202 | sh73180se_outb(value, port); | ||
203 | delay(); | ||
204 | } | ||
205 | |||
206 | void | ||
207 | sh73180se_outw(unsigned short value, unsigned long port) | ||
208 | { | ||
209 | struct iop *p = port2iop(port); | ||
210 | (p->outw) (p, value, port); | ||
211 | } | ||
212 | |||
213 | void | ||
214 | sh73180se_outl(unsigned int value, unsigned long port) | ||
215 | { | ||
216 | badio(outl, port); | ||
217 | } | ||
218 | |||
219 | void | ||
220 | sh73180se_insb(unsigned long port, void *addr, unsigned long count) | ||
221 | { | ||
222 | unsigned char *a = addr; | ||
223 | struct iop *p = port2iop(port); | ||
224 | while (count--) | ||
225 | *a++ = (p->inb) (p, port); | ||
226 | } | ||
227 | |||
228 | void | ||
229 | sh73180se_insw(unsigned long port, void *addr, unsigned long count) | ||
230 | { | ||
231 | unsigned short *a = addr; | ||
232 | struct iop *p = port2iop(port); | ||
233 | while (count--) | ||
234 | *a++ = (p->inw) (p, port); | ||
235 | } | ||
236 | |||
237 | void | ||
238 | sh73180se_insl(unsigned long port, void *addr, unsigned long count) | ||
239 | { | ||
240 | badio(insl, port); | ||
241 | } | ||
242 | |||
243 | void | ||
244 | sh73180se_outsb(unsigned long port, const void *addr, unsigned long count) | ||
245 | { | ||
246 | unsigned char *a = (unsigned char *) addr; | ||
247 | struct iop *p = port2iop(port); | ||
248 | while (count--) | ||
249 | (p->outb) (p, *a++, port); | ||
250 | } | ||
251 | |||
252 | void | ||
253 | sh73180se_outsw(unsigned long port, const void *addr, unsigned long count) | ||
254 | { | ||
255 | unsigned short *a = (unsigned short *) addr; | ||
256 | struct iop *p = port2iop(port); | ||
257 | while (count--) | ||
258 | (p->outw) (p, *a++, port); | ||
259 | } | ||
260 | |||
261 | void | ||
262 | sh73180se_outsl(unsigned long port, const void *addr, unsigned long count) | ||
263 | { | ||
264 | badio(outsw, port); | ||
265 | } | ||
diff --git a/arch/sh/boards/se/73180/irq.c b/arch/sh/boards/se/73180/irq.c new file mode 100644 index 000000000000..70f04caad9a4 --- /dev/null +++ b/arch/sh/boards/se/73180/irq.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/se/73180/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> | ||
5 | * Based on arch/sh/boards/se/7300/irq.c | ||
6 | * | ||
7 | * Modified for SH-Mobile SolutionEngine 73180 Support | ||
8 | * by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp> | ||
9 | * | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <asm/irq.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/mach/se73180.h> | ||
19 | |||
20 | static int | ||
21 | intreq2irq(int i) | ||
22 | { | ||
23 | if (i == 5) | ||
24 | return 10; | ||
25 | return 32 + 7 - i; | ||
26 | } | ||
27 | |||
28 | static int | ||
29 | irq2intreq(int irq) | ||
30 | { | ||
31 | if (irq == 10) | ||
32 | return 5; | ||
33 | return 7 - (irq - 32); | ||
34 | } | ||
35 | |||
36 | static void | ||
37 | disable_intreq_irq(unsigned int irq) | ||
38 | { | ||
39 | ctrl_outb(1 << (7 - irq2intreq(irq)), INTMSK0); | ||
40 | } | ||
41 | |||
42 | static void | ||
43 | enable_intreq_irq(unsigned int irq) | ||
44 | { | ||
45 | ctrl_outb(1 << (7 - irq2intreq(irq)), INTMSKCLR0); | ||
46 | } | ||
47 | |||
48 | static void | ||
49 | mask_and_ack_intreq_irq(unsigned int irq) | ||
50 | { | ||
51 | disable_intreq_irq(irq); | ||
52 | } | ||
53 | |||
54 | static unsigned int | ||
55 | startup_intreq_irq(unsigned int irq) | ||
56 | { | ||
57 | enable_intreq_irq(irq); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | shutdown_intreq_irq(unsigned int irq) | ||
63 | { | ||
64 | disable_intreq_irq(irq); | ||
65 | } | ||
66 | |||
67 | static void | ||
68 | end_intreq_irq(unsigned int irq) | ||
69 | { | ||
70 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
71 | enable_intreq_irq(irq); | ||
72 | } | ||
73 | |||
74 | static struct hw_interrupt_type intreq_irq_type = { | ||
75 | .typename = "intreq", | ||
76 | .startup = startup_intreq_irq, | ||
77 | .shutdown = shutdown_intreq_irq, | ||
78 | .enable = enable_intreq_irq, | ||
79 | .disable = disable_intreq_irq, | ||
80 | .ack = mask_and_ack_intreq_irq, | ||
81 | .end = end_intreq_irq | ||
82 | }; | ||
83 | |||
84 | void | ||
85 | make_intreq_irq(unsigned int irq) | ||
86 | { | ||
87 | disable_irq_nosync(irq); | ||
88 | irq_desc[irq].handler = &intreq_irq_type; | ||
89 | disable_intreq_irq(irq); | ||
90 | } | ||
91 | |||
92 | int | ||
93 | shmse_irq_demux(int irq) | ||
94 | { | ||
95 | if (irq == IRQ5_IRQ) | ||
96 | return 10; | ||
97 | return irq; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Initialize IRQ setting | ||
102 | */ | ||
103 | void __init | ||
104 | init_73180se_IRQ(void) | ||
105 | { | ||
106 | make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY); | ||
107 | |||
108 | ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ | ||
109 | ctrl_outw(0x2000, 0xb07fffec); /* mrshpc irq enable */ | ||
110 | ctrl_outl(3 << ((7 - 5) * 4), INTC_INTPRI0); /* irq5 pri=3 */ | ||
111 | ctrl_outw(2 << ((7 - 5) * 2), INTC_ICR1); /* low-level irq */ | ||
112 | make_intreq_irq(10); | ||
113 | |||
114 | make_ipr_irq(VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8); | ||
115 | |||
116 | ctrl_outb(0x0f, INTC_IMCR5); /* enable SCIF IRQ */ | ||
117 | |||
118 | make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | ||
119 | make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | ||
120 | make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY); | ||
121 | make_ipr_irq(IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY); | ||
122 | make_ipr_irq(IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, | ||
123 | IIC0_PRIORITY); | ||
124 | make_ipr_irq(IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, | ||
125 | IIC0_PRIORITY); | ||
126 | make_ipr_irq(IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY); | ||
127 | make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY); | ||
128 | make_ipr_irq(SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY); | ||
129 | |||
130 | /* VIO interrupt */ | ||
131 | make_ipr_irq(CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | ||
132 | make_ipr_irq(BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | ||
133 | make_ipr_irq(VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | ||
134 | |||
135 | make_ipr_irq(LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY); | ||
136 | ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */ | ||
137 | } | ||
diff --git a/arch/sh/boards/se/73180/led.c b/arch/sh/boards/se/73180/led.c new file mode 100644 index 000000000000..1e8f1cf3e10f --- /dev/null +++ b/arch/sh/boards/se/73180/led.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/se/73180/led.c | ||
3 | * | ||
4 | * Derived from arch/sh/boards/se/770x/led.c | ||
5 | * | ||
6 | * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * This file contains Solution Engine specific LED code. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <asm/mach/se73180.h> | ||
17 | |||
18 | static void | ||
19 | mach_led(int position, int value) | ||
20 | { | ||
21 | volatile unsigned short *p = (volatile unsigned short *) PA_LED; | ||
22 | |||
23 | if (value) { | ||
24 | *p |= (1 << LED_SHIFT); | ||
25 | } else { | ||
26 | *p &= ~(1 << LED_SHIFT); | ||
27 | } | ||
28 | } | ||
29 | |||
30 | /* Cycle the LED's in the clasic Knightrider/Sun pattern */ | ||
31 | void | ||
32 | heartbeat_73180se(void) | ||
33 | { | ||
34 | static unsigned int cnt = 0, period = 0; | ||
35 | volatile unsigned short *p = (volatile unsigned short *) PA_LED; | ||
36 | static unsigned bit = 0, up = 1; | ||
37 | |||
38 | cnt += 1; | ||
39 | if (cnt < period) { | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | cnt = 0; | ||
44 | |||
45 | /* Go through the points (roughly!): | ||
46 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
47 | */ | ||
48 | period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT))); | ||
49 | |||
50 | if (up) { | ||
51 | if (bit == 7) { | ||
52 | bit--; | ||
53 | up = 0; | ||
54 | } else { | ||
55 | bit++; | ||
56 | } | ||
57 | } else { | ||
58 | if (bit == 0) { | ||
59 | bit++; | ||
60 | up = 1; | ||
61 | } else { | ||
62 | bit--; | ||
63 | } | ||
64 | } | ||
65 | *p = 1 << (bit + LED_SHIFT); | ||
66 | |||
67 | } | ||
diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c new file mode 100644 index 000000000000..07fa90c38a06 --- /dev/null +++ b/arch/sh/boards/se/73180/setup.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/se/73180/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> | ||
5 | * Based on arch/sh/setup_shmse.c | ||
6 | * | ||
7 | * Modified for 73180 SolutionEngine | ||
8 | * by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <asm/machvec.h> | ||
15 | #include <asm/machvec_init.h> | ||
16 | #include <asm/mach/io.h> | ||
17 | |||
18 | void heartbeat_73180se(void); | ||
19 | void init_73180se_IRQ(void); | ||
20 | |||
21 | const char * | ||
22 | get_system_type(void) | ||
23 | { | ||
24 | return "SolutionEngine 73180"; | ||
25 | } | ||
26 | |||
27 | /* | ||
28 | * The Machine Vector | ||
29 | */ | ||
30 | |||
31 | struct sh_machine_vector mv_73180se __initmv = { | ||
32 | .mv_nr_irqs = 108, | ||
33 | .mv_inb = sh73180se_inb, | ||
34 | .mv_inw = sh73180se_inw, | ||
35 | .mv_inl = sh73180se_inl, | ||
36 | .mv_outb = sh73180se_outb, | ||
37 | .mv_outw = sh73180se_outw, | ||
38 | .mv_outl = sh73180se_outl, | ||
39 | |||
40 | .mv_inb_p = sh73180se_inb_p, | ||
41 | .mv_inw_p = sh73180se_inw, | ||
42 | .mv_inl_p = sh73180se_inl, | ||
43 | .mv_outb_p = sh73180se_outb_p, | ||
44 | .mv_outw_p = sh73180se_outw, | ||
45 | .mv_outl_p = sh73180se_outl, | ||
46 | |||
47 | .mv_insb = sh73180se_insb, | ||
48 | .mv_insw = sh73180se_insw, | ||
49 | .mv_insl = sh73180se_insl, | ||
50 | .mv_outsb = sh73180se_outsb, | ||
51 | .mv_outsw = sh73180se_outsw, | ||
52 | .mv_outsl = sh73180se_outsl, | ||
53 | |||
54 | .mv_init_irq = init_73180se_IRQ, | ||
55 | #ifdef CONFIG_HEARTBEAT | ||
56 | .mv_heartbeat = heartbeat_73180se, | ||
57 | #endif | ||
58 | }; | ||
59 | |||
60 | ALIAS_MV(73180se) | ||
61 | /* | ||
62 | * Initialize the board | ||
63 | */ | ||
64 | void __init | ||
65 | platform_setup(void) | ||
66 | { | ||
67 | |||
68 | } | ||
diff --git a/arch/sh/boards/se/770x/Makefile b/arch/sh/boards/se/770x/Makefile new file mode 100644 index 000000000000..be89a73cc418 --- /dev/null +++ b/arch/sh/boards/se/770x/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the 770x SolutionEngine specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o setup.o io.o irq.o led.o | ||
6 | |||
diff --git a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c new file mode 100644 index 000000000000..9a39ee963143 --- /dev/null +++ b/arch/sh/boards/se/770x/io.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $ | ||
2 | * | ||
3 | * linux/arch/sh/kernel/io_se.c | ||
4 | * | ||
5 | * Copyright (C) 2000 Kazumoto Kojima | ||
6 | * | ||
7 | * I/O routine for Hitachi SolutionEngine. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/se/se.h> | ||
15 | |||
16 | /* SH pcmcia io window base, start and end. */ | ||
17 | int sh_pcic_io_wbase = 0xb8400000; | ||
18 | int sh_pcic_io_start; | ||
19 | int sh_pcic_io_stop; | ||
20 | int sh_pcic_io_type; | ||
21 | int sh_pcic_io_dummy; | ||
22 | |||
23 | static inline void delay(void) | ||
24 | { | ||
25 | ctrl_inw(0xa0000000); | ||
26 | } | ||
27 | |||
28 | /* MS7750 requires special versions of in*, out* routines, since | ||
29 | PC-like io ports are located at upper half byte of 16-bit word which | ||
30 | can be accessed only with 16-bit wide. */ | ||
31 | |||
32 | static inline volatile __u16 * | ||
33 | port2adr(unsigned int port) | ||
34 | { | ||
35 | if (port >= 0x2000) | ||
36 | return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); | ||
37 | else if (port >= 0x1000) | ||
38 | return (volatile __u16 *) (PA_83902 + (port << 1)); | ||
39 | else if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) | ||
40 | return (volatile __u16 *) (sh_pcic_io_wbase + (port &~ 1)); | ||
41 | else | ||
42 | return (volatile __u16 *) (PA_SUPERIO + (port << 1)); | ||
43 | } | ||
44 | |||
45 | static inline int | ||
46 | shifted_port(unsigned long port) | ||
47 | { | ||
48 | /* For IDE registers, value is not shifted */ | ||
49 | if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) | ||
50 | return 0; | ||
51 | else | ||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | #define maybebadio(name,port) \ | ||
56 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
57 | #name, (port), (__u32) __builtin_return_address(0)) | ||
58 | |||
59 | unsigned char se_inb(unsigned long port) | ||
60 | { | ||
61 | if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) | ||
62 | return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); | ||
63 | else if (shifted_port(port)) | ||
64 | return (*port2adr(port) >> 8); | ||
65 | else | ||
66 | return (*port2adr(port))&0xff; | ||
67 | } | ||
68 | |||
69 | unsigned char se_inb_p(unsigned long port) | ||
70 | { | ||
71 | unsigned long v; | ||
72 | |||
73 | if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) | ||
74 | v = *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); | ||
75 | else if (shifted_port(port)) | ||
76 | v = (*port2adr(port) >> 8); | ||
77 | else | ||
78 | v = (*port2adr(port))&0xff; | ||
79 | delay(); | ||
80 | return v; | ||
81 | } | ||
82 | |||
83 | unsigned short se_inw(unsigned long port) | ||
84 | { | ||
85 | if (port >= 0x2000 || | ||
86 | (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) | ||
87 | return *port2adr(port); | ||
88 | else | ||
89 | maybebadio(inw, port); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | unsigned int se_inl(unsigned long port) | ||
94 | { | ||
95 | maybebadio(inl, port); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | void se_outb(unsigned char value, unsigned long port) | ||
100 | { | ||
101 | if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) | ||
102 | *(__u8 *)(sh_pcic_io_wbase + port) = value; | ||
103 | else if (shifted_port(port)) | ||
104 | *(port2adr(port)) = value << 8; | ||
105 | else | ||
106 | *(port2adr(port)) = value; | ||
107 | } | ||
108 | |||
109 | void se_outb_p(unsigned char value, unsigned long port) | ||
110 | { | ||
111 | if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) | ||
112 | *(__u8 *)(sh_pcic_io_wbase + port) = value; | ||
113 | else if (shifted_port(port)) | ||
114 | *(port2adr(port)) = value << 8; | ||
115 | else | ||
116 | *(port2adr(port)) = value; | ||
117 | delay(); | ||
118 | } | ||
119 | |||
120 | void se_outw(unsigned short value, unsigned long port) | ||
121 | { | ||
122 | if (port >= 0x2000 || | ||
123 | (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) | ||
124 | *port2adr(port) = value; | ||
125 | else | ||
126 | maybebadio(outw, port); | ||
127 | } | ||
128 | |||
129 | void se_outl(unsigned int value, unsigned long port) | ||
130 | { | ||
131 | maybebadio(outl, port); | ||
132 | } | ||
133 | |||
134 | void se_insb(unsigned long port, void *addr, unsigned long count) | ||
135 | { | ||
136 | volatile __u16 *p = port2adr(port); | ||
137 | __u8 *ap = addr; | ||
138 | |||
139 | if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) { | ||
140 | volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + 0x40000 + port); | ||
141 | while (count--) | ||
142 | *ap++ = *bp; | ||
143 | } else if (shifted_port(port)) { | ||
144 | while (count--) | ||
145 | *ap++ = *p >> 8; | ||
146 | } else { | ||
147 | while (count--) | ||
148 | *ap++ = *p; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | void se_insw(unsigned long port, void *addr, unsigned long count) | ||
153 | { | ||
154 | volatile __u16 *p = port2adr(port); | ||
155 | __u16 *ap = addr; | ||
156 | while (count--) | ||
157 | *ap++ = *p; | ||
158 | } | ||
159 | |||
160 | void se_insl(unsigned long port, void *addr, unsigned long count) | ||
161 | { | ||
162 | maybebadio(insl, port); | ||
163 | } | ||
164 | |||
165 | void se_outsb(unsigned long port, const void *addr, unsigned long count) | ||
166 | { | ||
167 | volatile __u16 *p = port2adr(port); | ||
168 | const __u8 *ap = addr; | ||
169 | |||
170 | if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) { | ||
171 | volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + port); | ||
172 | while (count--) | ||
173 | *bp = *ap++; | ||
174 | } else if (shifted_port(port)) { | ||
175 | while (count--) | ||
176 | *p = *ap++ << 8; | ||
177 | } else { | ||
178 | while (count--) | ||
179 | *p = *ap++; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | void se_outsw(unsigned long port, const void *addr, unsigned long count) | ||
184 | { | ||
185 | volatile __u16 *p = port2adr(port); | ||
186 | const __u16 *ap = addr; | ||
187 | while (count--) | ||
188 | *p = *ap++; | ||
189 | } | ||
190 | |||
191 | void se_outsl(unsigned long port, const void *addr, unsigned long count) | ||
192 | { | ||
193 | maybebadio(outsw, port); | ||
194 | } | ||
195 | |||
196 | /* Map ISA bus address to the real address. Only for PCMCIA. */ | ||
197 | |||
198 | /* ISA page descriptor. */ | ||
199 | static __u32 sh_isa_memmap[256]; | ||
200 | |||
201 | static int | ||
202 | sh_isa_mmap(__u32 start, __u32 length, __u32 offset) | ||
203 | { | ||
204 | int idx; | ||
205 | |||
206 | if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000)) | ||
207 | return -1; | ||
208 | |||
209 | idx = start >> 12; | ||
210 | sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff); | ||
211 | #if 0 | ||
212 | printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n", | ||
213 | start, length, offset, idx, sh_isa_memmap[idx]); | ||
214 | #endif | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | unsigned long | ||
219 | se_isa_port2addr(unsigned long offset) | ||
220 | { | ||
221 | int idx; | ||
222 | |||
223 | idx = (offset >> 12) & 0xff; | ||
224 | offset &= 0xfff; | ||
225 | return sh_isa_memmap[idx] + offset; | ||
226 | } | ||
diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c new file mode 100644 index 000000000000..210897b315f4 --- /dev/null +++ b/arch/sh/boards/se/770x/irq.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/se/770x/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Hitachi SolutionEngine Support. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/irq.h> | ||
13 | #include <asm/irq.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/se/se.h> | ||
16 | |||
17 | /* | ||
18 | * Initialize IRQ setting | ||
19 | */ | ||
20 | void __init init_se_IRQ(void) | ||
21 | { | ||
22 | /* | ||
23 | * Super I/O (Just mimic PC): | ||
24 | * 1: keyboard | ||
25 | * 3: serial 0 | ||
26 | * 4: serial 1 | ||
27 | * 5: printer | ||
28 | * 6: floppy | ||
29 | * 8: rtc | ||
30 | * 12: mouse | ||
31 | * 14: ide0 | ||
32 | */ | ||
33 | #if defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
34 | /* Disable all interrupts */ | ||
35 | ctrl_outw(0, BCR_ILCRA); | ||
36 | ctrl_outw(0, BCR_ILCRB); | ||
37 | ctrl_outw(0, BCR_ILCRC); | ||
38 | ctrl_outw(0, BCR_ILCRD); | ||
39 | ctrl_outw(0, BCR_ILCRE); | ||
40 | ctrl_outw(0, BCR_ILCRF); | ||
41 | ctrl_outw(0, BCR_ILCRG); | ||
42 | /* This is default value */ | ||
43 | make_ipr_irq(0xf-0x2, BCR_ILCRA, 2, 0x2); | ||
44 | make_ipr_irq(0xf-0xa, BCR_ILCRA, 1, 0xa); | ||
45 | make_ipr_irq(0xf-0x5, BCR_ILCRB, 0, 0x5); | ||
46 | make_ipr_irq(0xf-0x8, BCR_ILCRC, 1, 0x8); | ||
47 | make_ipr_irq(0xf-0xc, BCR_ILCRC, 0, 0xc); | ||
48 | make_ipr_irq(0xf-0xe, BCR_ILCRD, 3, 0xe); | ||
49 | make_ipr_irq(0xf-0x3, BCR_ILCRD, 1, 0x3); /* LAN */ | ||
50 | make_ipr_irq(0xf-0xd, BCR_ILCRE, 2, 0xd); | ||
51 | make_ipr_irq(0xf-0x9, BCR_ILCRE, 1, 0x9); | ||
52 | make_ipr_irq(0xf-0x1, BCR_ILCRE, 0, 0x1); | ||
53 | make_ipr_irq(0xf-0xf, BCR_ILCRF, 3, 0xf); | ||
54 | make_ipr_irq(0xf-0xb, BCR_ILCRF, 1, 0xb); | ||
55 | make_ipr_irq(0xf-0x7, BCR_ILCRG, 3, 0x7); | ||
56 | make_ipr_irq(0xf-0x6, BCR_ILCRG, 2, 0x6); | ||
57 | make_ipr_irq(0xf-0x4, BCR_ILCRG, 1, 0x4); | ||
58 | #else | ||
59 | make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14); | ||
60 | make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12); | ||
61 | make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8); | ||
62 | make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6); | ||
63 | make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5); | ||
64 | make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4); | ||
65 | make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3); | ||
66 | make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1); | ||
67 | |||
68 | make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */ | ||
69 | |||
70 | make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */ | ||
71 | make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */ | ||
72 | make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */ | ||
73 | make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */ | ||
74 | |||
75 | /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */ | ||
76 | /* NOTE: #2 and #13 are not used on PC */ | ||
77 | make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */ | ||
78 | make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */ | ||
79 | #endif | ||
80 | } | ||
diff --git a/arch/sh/boards/se/770x/led.c b/arch/sh/boards/se/770x/led.c new file mode 100644 index 000000000000..5c64e8ab2cfb --- /dev/null +++ b/arch/sh/boards/se/770x/led.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/led_se.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * This file contains Solution Engine specific LED code. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/se/se.h> | ||
14 | |||
15 | static void mach_led(int position, int value) | ||
16 | { | ||
17 | volatile unsigned short* p = (volatile unsigned short*)PA_LED; | ||
18 | |||
19 | if (value) { | ||
20 | *p |= (1<<8); | ||
21 | } else { | ||
22 | *p &= ~(1<<8); | ||
23 | } | ||
24 | } | ||
25 | |||
26 | #ifdef CONFIG_HEARTBEAT | ||
27 | |||
28 | #include <linux/sched.h> | ||
29 | |||
30 | /* Cycle the LED's in the clasic Knightrider/Sun pattern */ | ||
31 | void heartbeat_se(void) | ||
32 | { | ||
33 | static unsigned int cnt = 0, period = 0; | ||
34 | volatile unsigned short* p = (volatile unsigned short*)PA_LED; | ||
35 | static unsigned bit = 0, up = 1; | ||
36 | |||
37 | cnt += 1; | ||
38 | if (cnt < period) { | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | cnt = 0; | ||
43 | |||
44 | /* Go through the points (roughly!): | ||
45 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
46 | */ | ||
47 | period = 110 - ( (300<<FSHIFT)/ | ||
48 | ((avenrun[0]/5) + (3<<FSHIFT)) ); | ||
49 | |||
50 | if (up) { | ||
51 | if (bit == 7) { | ||
52 | bit--; | ||
53 | up=0; | ||
54 | } else { | ||
55 | bit ++; | ||
56 | } | ||
57 | } else { | ||
58 | if (bit == 0) { | ||
59 | bit++; | ||
60 | up=1; | ||
61 | } else { | ||
62 | bit--; | ||
63 | } | ||
64 | } | ||
65 | *p = 1<<(bit+8); | ||
66 | |||
67 | } | ||
68 | #endif /* CONFIG_HEARTBEAT */ | ||
diff --git a/arch/sh/boards/se/770x/mach.c b/arch/sh/boards/se/770x/mach.c new file mode 100644 index 000000000000..f9b4c56cc47e --- /dev/null +++ b/arch/sh/boards/se/770x/mach.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/mach_se.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the Hitachi SolutionEngine | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/machvec.h> | ||
16 | #include <asm/rtc.h> | ||
17 | #include <asm/machvec_init.h> | ||
18 | |||
19 | #include <asm/se/io.h> | ||
20 | |||
21 | void heartbeat_se(void); | ||
22 | void setup_se(void); | ||
23 | void init_se_IRQ(void); | ||
24 | |||
25 | /* | ||
26 | * The Machine Vector | ||
27 | */ | ||
28 | |||
29 | struct sh_machine_vector mv_se __initmv = { | ||
30 | #if defined(CONFIG_CPU_SH4) | ||
31 | .mv_nr_irqs = 48, | ||
32 | #elif defined(CONFIG_CPU_SUBTYPE_SH7708) | ||
33 | .mv_nr_irqs = 32, | ||
34 | #elif defined(CONFIG_CPU_SUBTYPE_SH7709) | ||
35 | .mv_nr_irqs = 61, | ||
36 | #elif defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
37 | .mv_nr_irqs = 86, | ||
38 | #endif | ||
39 | |||
40 | .mv_inb = se_inb, | ||
41 | .mv_inw = se_inw, | ||
42 | .mv_inl = se_inl, | ||
43 | .mv_outb = se_outb, | ||
44 | .mv_outw = se_outw, | ||
45 | .mv_outl = se_outl, | ||
46 | |||
47 | .mv_inb_p = se_inb_p, | ||
48 | .mv_inw_p = se_inw, | ||
49 | .mv_inl_p = se_inl, | ||
50 | .mv_outb_p = se_outb_p, | ||
51 | .mv_outw_p = se_outw, | ||
52 | .mv_outl_p = se_outl, | ||
53 | |||
54 | .mv_insb = se_insb, | ||
55 | .mv_insw = se_insw, | ||
56 | .mv_insl = se_insl, | ||
57 | .mv_outsb = se_outsb, | ||
58 | .mv_outsw = se_outsw, | ||
59 | .mv_outsl = se_outsl, | ||
60 | |||
61 | .mv_isa_port2addr = se_isa_port2addr, | ||
62 | |||
63 | .mv_init_irq = init_se_IRQ, | ||
64 | #ifdef CONFIG_HEARTBEAT | ||
65 | .mv_heartbeat = heartbeat_se, | ||
66 | #endif | ||
67 | }; | ||
68 | ALIAS_MV(se) | ||
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c new file mode 100644 index 000000000000..2bed46fb607d --- /dev/null +++ b/arch/sh/boards/se/770x/setup.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* $Id: setup.c,v 1.1.2.4 2002/03/02 21:57:07 lethal Exp $ | ||
2 | * | ||
3 | * linux/arch/sh/boards/se/770x/setup.c | ||
4 | * | ||
5 | * Copyright (C) 2000 Kazumoto Kojima | ||
6 | * | ||
7 | * Hitachi SolutionEngine Support. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/irq.h> | ||
14 | |||
15 | #include <linux/hdreg.h> | ||
16 | #include <linux/ide.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/se/se.h> | ||
19 | #include <asm/se/smc37c93x.h> | ||
20 | |||
21 | /* | ||
22 | * Configure the Super I/O chip | ||
23 | */ | ||
24 | static void __init smsc_config(int index, int data) | ||
25 | { | ||
26 | outb_p(index, INDEX_PORT); | ||
27 | outb_p(data, DATA_PORT); | ||
28 | } | ||
29 | |||
30 | static void __init init_smsc(void) | ||
31 | { | ||
32 | outb_p(CONFIG_ENTER, CONFIG_PORT); | ||
33 | outb_p(CONFIG_ENTER, CONFIG_PORT); | ||
34 | |||
35 | /* FDC */ | ||
36 | smsc_config(CURRENT_LDN_INDEX, LDN_FDC); | ||
37 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
38 | smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */ | ||
39 | |||
40 | /* IDE1 */ | ||
41 | smsc_config(CURRENT_LDN_INDEX, LDN_IDE1); | ||
42 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
43 | smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */ | ||
44 | |||
45 | /* AUXIO (GPIO): to use IDE1 */ | ||
46 | smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO); | ||
47 | smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */ | ||
48 | smsc_config(GPIO47_INDEX, 0x00); /* nIOWOP */ | ||
49 | |||
50 | /* COM1 */ | ||
51 | smsc_config(CURRENT_LDN_INDEX, LDN_COM1); | ||
52 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
53 | smsc_config(IO_BASE_HI_INDEX, 0x03); | ||
54 | smsc_config(IO_BASE_LO_INDEX, 0xf8); | ||
55 | smsc_config(IRQ_SELECT_INDEX, 4); /* IRQ4 */ | ||
56 | |||
57 | /* COM2 */ | ||
58 | smsc_config(CURRENT_LDN_INDEX, LDN_COM2); | ||
59 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
60 | smsc_config(IO_BASE_HI_INDEX, 0x02); | ||
61 | smsc_config(IO_BASE_LO_INDEX, 0xf8); | ||
62 | smsc_config(IRQ_SELECT_INDEX, 3); /* IRQ3 */ | ||
63 | |||
64 | /* RTC */ | ||
65 | smsc_config(CURRENT_LDN_INDEX, LDN_RTC); | ||
66 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
67 | smsc_config(IRQ_SELECT_INDEX, 8); /* IRQ8 */ | ||
68 | |||
69 | /* XXX: PARPORT, KBD, and MOUSE will come here... */ | ||
70 | outb_p(CONFIG_EXIT, CONFIG_PORT); | ||
71 | } | ||
72 | |||
73 | const char *get_system_type(void) | ||
74 | { | ||
75 | return "SolutionEngine"; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Initialize the board | ||
80 | */ | ||
81 | void __init platform_setup(void) | ||
82 | { | ||
83 | init_smsc(); | ||
84 | /* XXX: RTC setting comes here */ | ||
85 | } | ||
diff --git a/arch/sh/boards/se/7751/Makefile b/arch/sh/boards/se/7751/Makefile new file mode 100644 index 000000000000..ce7ca247f84d --- /dev/null +++ b/arch/sh/boards/se/7751/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the 7751 SolutionEngine specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o setup.o io.o irq.o led.o | ||
6 | |||
7 | obj-$(CONFIG_PCI) += pci.o | ||
8 | |||
diff --git a/arch/sh/boards/se/7751/io.c b/arch/sh/boards/se/7751/io.c new file mode 100644 index 000000000000..99041b269261 --- /dev/null +++ b/arch/sh/boards/se/7751/io.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_7751se.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Ian da Silva, Jeremy Siegel | ||
5 | * Based largely on io_se.c. | ||
6 | * | ||
7 | * I/O routine for Hitachi 7751 SolutionEngine. | ||
8 | * | ||
9 | * Initial version only to support LAN access; some | ||
10 | * placeholder code from io_se.c left in with the | ||
11 | * expectation of later SuperIO and PCMCIA access. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/se7751/se7751.h> | ||
18 | #include <asm/addrspace.h> | ||
19 | |||
20 | #include <linux/pci.h> | ||
21 | #include "../../../drivers/pci/pci-sh7751.h" | ||
22 | |||
23 | #if 0 | ||
24 | /****************************************************************** | ||
25 | * Variables from io_se.c, related to PCMCIA (not PCI); we're not | ||
26 | * compiling them in, and have removed references from functions | ||
27 | * which follow. [Many checked for IO ports in the range bounded | ||
28 | * by sh_pcic_io_start/stop, and used sh_pcic_io_wbase as offset. | ||
29 | * As start/stop are uninitialized, only port 0x0 would match?] | ||
30 | * When used, remember to adjust names to avoid clash with io_se? | ||
31 | *****************************************************************/ | ||
32 | /* SH pcmcia io window base, start and end. */ | ||
33 | int sh_pcic_io_wbase = 0xb8400000; | ||
34 | int sh_pcic_io_start; | ||
35 | int sh_pcic_io_stop; | ||
36 | int sh_pcic_io_type; | ||
37 | int sh_pcic_io_dummy; | ||
38 | /*************************************************************/ | ||
39 | #endif | ||
40 | |||
41 | /* | ||
42 | * The 7751 Solution Engine uses the built-in PCI controller (PCIC) | ||
43 | * of the 7751 processor, and has a SuperIO accessible via the PCI. | ||
44 | * The board also includes a PCMCIA controller on its memory bus, | ||
45 | * like the other Solution Engine boards. | ||
46 | */ | ||
47 | |||
48 | #define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR) | ||
49 | #define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR) | ||
50 | #define PCI_IO_AREA SH7751_PCI_IO_BASE | ||
51 | #define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE | ||
52 | |||
53 | #define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK)) | ||
54 | |||
55 | #define maybebadio(name,port) \ | ||
56 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
57 | #name, (port), (__u32) __builtin_return_address(0)) | ||
58 | |||
59 | static inline void delay(void) | ||
60 | { | ||
61 | ctrl_inw(0xa0000000); | ||
62 | } | ||
63 | |||
64 | static inline volatile __u16 * | ||
65 | port2adr(unsigned int port) | ||
66 | { | ||
67 | if (port >= 0x2000) | ||
68 | return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); | ||
69 | #if 0 | ||
70 | else | ||
71 | return (volatile __u16 *) (PA_SUPERIO + (port << 1)); | ||
72 | #endif | ||
73 | maybebadio(name,(unsigned long)port); | ||
74 | return (volatile __u16*)port; | ||
75 | } | ||
76 | |||
77 | #if 0 | ||
78 | /* The 7751 Solution Engine seems to have everything hooked */ | ||
79 | /* up pretty normally (nothing on high-bytes only...) so this */ | ||
80 | /* shouldn't be needed */ | ||
81 | static inline int | ||
82 | shifted_port(unsigned long port) | ||
83 | { | ||
84 | /* For IDE registers, value is not shifted */ | ||
85 | if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) | ||
86 | return 0; | ||
87 | else | ||
88 | return 1; | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | /* In case someone configures the kernel w/o PCI support: in that */ | ||
93 | /* scenario, don't ever bother to check for PCI-window addresses */ | ||
94 | |||
95 | /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */ | ||
96 | #if defined(CONFIG_PCI) | ||
97 | #define CHECK_SH7751_PCIIO(port) \ | ||
98 | ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE))) | ||
99 | #else | ||
100 | #define CHECK_SH7751_PCIIO(port) (0) | ||
101 | #endif | ||
102 | |||
103 | /* | ||
104 | * General outline: remap really low stuff [eventually] to SuperIO, | ||
105 | * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) | ||
106 | * is mapped through the PCI IO window. Stuff with high bits (PXSEG) | ||
107 | * should be way beyond the window, and is used w/o translation for | ||
108 | * compatibility. | ||
109 | */ | ||
110 | unsigned char sh7751se_inb(unsigned long port) | ||
111 | { | ||
112 | if (PXSEG(port)) | ||
113 | return *(volatile unsigned char *)port; | ||
114 | else if (CHECK_SH7751_PCIIO(port)) | ||
115 | return *(volatile unsigned char *)PCI_IOMAP(port); | ||
116 | else | ||
117 | return (*port2adr(port))&0xff; | ||
118 | } | ||
119 | |||
120 | unsigned char sh7751se_inb_p(unsigned long port) | ||
121 | { | ||
122 | unsigned char v; | ||
123 | |||
124 | if (PXSEG(port)) | ||
125 | v = *(volatile unsigned char *)port; | ||
126 | else if (CHECK_SH7751_PCIIO(port)) | ||
127 | v = *(volatile unsigned char *)PCI_IOMAP(port); | ||
128 | else | ||
129 | v = (*port2adr(port))&0xff; | ||
130 | delay(); | ||
131 | return v; | ||
132 | } | ||
133 | |||
134 | unsigned short sh7751se_inw(unsigned long port) | ||
135 | { | ||
136 | if (PXSEG(port)) | ||
137 | return *(volatile unsigned short *)port; | ||
138 | else if (CHECK_SH7751_PCIIO(port)) | ||
139 | return *(volatile unsigned short *)PCI_IOMAP(port); | ||
140 | else if (port >= 0x2000) | ||
141 | return *port2adr(port); | ||
142 | else | ||
143 | maybebadio(inw, port); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | unsigned int sh7751se_inl(unsigned long port) | ||
148 | { | ||
149 | if (PXSEG(port)) | ||
150 | return *(volatile unsigned long *)port; | ||
151 | else if (CHECK_SH7751_PCIIO(port)) | ||
152 | return *(volatile unsigned int *)PCI_IOMAP(port); | ||
153 | else if (port >= 0x2000) | ||
154 | return *port2adr(port); | ||
155 | else | ||
156 | maybebadio(inl, port); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | void sh7751se_outb(unsigned char value, unsigned long port) | ||
161 | { | ||
162 | |||
163 | if (PXSEG(port)) | ||
164 | *(volatile unsigned char *)port = value; | ||
165 | else if (CHECK_SH7751_PCIIO(port)) | ||
166 | *((unsigned char*)PCI_IOMAP(port)) = value; | ||
167 | else | ||
168 | *(port2adr(port)) = value; | ||
169 | } | ||
170 | |||
171 | void sh7751se_outb_p(unsigned char value, unsigned long port) | ||
172 | { | ||
173 | if (PXSEG(port)) | ||
174 | *(volatile unsigned char *)port = value; | ||
175 | else if (CHECK_SH7751_PCIIO(port)) | ||
176 | *((unsigned char*)PCI_IOMAP(port)) = value; | ||
177 | else | ||
178 | *(port2adr(port)) = value; | ||
179 | delay(); | ||
180 | } | ||
181 | |||
182 | void sh7751se_outw(unsigned short value, unsigned long port) | ||
183 | { | ||
184 | if (PXSEG(port)) | ||
185 | *(volatile unsigned short *)port = value; | ||
186 | else if (CHECK_SH7751_PCIIO(port)) | ||
187 | *((unsigned short *)PCI_IOMAP(port)) = value; | ||
188 | else if (port >= 0x2000) | ||
189 | *port2adr(port) = value; | ||
190 | else | ||
191 | maybebadio(outw, port); | ||
192 | } | ||
193 | |||
194 | void sh7751se_outl(unsigned int value, unsigned long port) | ||
195 | { | ||
196 | if (PXSEG(port)) | ||
197 | *(volatile unsigned long *)port = value; | ||
198 | else if (CHECK_SH7751_PCIIO(port)) | ||
199 | *((unsigned long*)PCI_IOMAP(port)) = value; | ||
200 | else | ||
201 | maybebadio(outl, port); | ||
202 | } | ||
203 | |||
204 | void sh7751se_insl(unsigned long port, void *addr, unsigned long count) | ||
205 | { | ||
206 | maybebadio(insl, port); | ||
207 | } | ||
208 | |||
209 | void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count) | ||
210 | { | ||
211 | maybebadio(outsw, port); | ||
212 | } | ||
213 | |||
214 | /* Map ISA bus address to the real address. Only for PCMCIA. */ | ||
215 | |||
216 | /* ISA page descriptor. */ | ||
217 | static __u32 sh_isa_memmap[256]; | ||
218 | |||
219 | #if 0 | ||
220 | static int | ||
221 | sh_isa_mmap(__u32 start, __u32 length, __u32 offset) | ||
222 | { | ||
223 | int idx; | ||
224 | |||
225 | if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000)) | ||
226 | return -1; | ||
227 | |||
228 | idx = start >> 12; | ||
229 | sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff); | ||
230 | printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n", | ||
231 | start, length, offset, idx, sh_isa_memmap[idx]); | ||
232 | return 0; | ||
233 | } | ||
234 | #endif | ||
235 | |||
236 | unsigned long | ||
237 | sh7751se_isa_port2addr(unsigned long offset) | ||
238 | { | ||
239 | int idx; | ||
240 | |||
241 | idx = (offset >> 12) & 0xff; | ||
242 | offset &= 0xfff; | ||
243 | return sh_isa_memmap[idx] + offset; | ||
244 | } | ||
diff --git a/arch/sh/boards/se/7751/irq.c b/arch/sh/boards/se/7751/irq.c new file mode 100644 index 000000000000..ad71f3e66c11 --- /dev/null +++ b/arch/sh/boards/se/7751/irq.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/se/7751/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Hitachi SolutionEngine Support. | ||
7 | * | ||
8 | * Modified for 7751 Solution Engine by | ||
9 | * Ian da Silva and Jeremy Siegel, 2001. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <asm/irq.h> | ||
16 | #include <asm/se7751/se7751.h> | ||
17 | |||
18 | /* | ||
19 | * Initialize IRQ setting | ||
20 | */ | ||
21 | void __init init_7751se_IRQ(void) | ||
22 | { | ||
23 | |||
24 | /* Leave old Solution Engine code in for reference. */ | ||
25 | #if defined(CONFIG_SH_SOLUTION_ENGINE) | ||
26 | /* | ||
27 | * Super I/O (Just mimic PC): | ||
28 | * 1: keyboard | ||
29 | * 3: serial 0 | ||
30 | * 4: serial 1 | ||
31 | * 5: printer | ||
32 | * 6: floppy | ||
33 | * 8: rtc | ||
34 | * 12: mouse | ||
35 | * 14: ide0 | ||
36 | */ | ||
37 | make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14); | ||
38 | make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12); | ||
39 | make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8); | ||
40 | make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6); | ||
41 | make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5); | ||
42 | make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4); | ||
43 | make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3); | ||
44 | make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1); | ||
45 | |||
46 | make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */ | ||
47 | |||
48 | make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */ | ||
49 | make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */ | ||
50 | make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */ | ||
51 | make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */ | ||
52 | |||
53 | /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */ | ||
54 | /* NOTE: #2 and #13 are not used on PC */ | ||
55 | make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */ | ||
56 | make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */ | ||
57 | |||
58 | #elif defined(CONFIG_SH_7751_SOLUTION_ENGINE) | ||
59 | |||
60 | make_ipr_irq(13, BCR_ILCRD, 3, 2); | ||
61 | |||
62 | /* Add additional calls to make_ipr_irq() as drivers are added | ||
63 | * and tested. | ||
64 | */ | ||
65 | #endif | ||
66 | |||
67 | } | ||
diff --git a/arch/sh/boards/se/7751/led.c b/arch/sh/boards/se/7751/led.c new file mode 100644 index 000000000000..0c788230cf8f --- /dev/null +++ b/arch/sh/boards/se/7751/led.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/led_se.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com> | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * This file contains Solution Engine specific LED code. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/se7751/se7751.h> | ||
14 | |||
15 | static void mach_led(int position, int value) | ||
16 | { | ||
17 | volatile unsigned short* p = (volatile unsigned short*)PA_LED; | ||
18 | |||
19 | if (value) { | ||
20 | *p |= (1<<8); | ||
21 | } else { | ||
22 | *p &= ~(1<<8); | ||
23 | } | ||
24 | } | ||
25 | |||
26 | #ifdef CONFIG_HEARTBEAT | ||
27 | |||
28 | #include <linux/sched.h> | ||
29 | |||
30 | /* Cycle the LED's in the clasic Knightrider/Sun pattern */ | ||
31 | void heartbeat_7751se(void) | ||
32 | { | ||
33 | static unsigned int cnt = 0, period = 0; | ||
34 | volatile unsigned short* p = (volatile unsigned short*)PA_LED; | ||
35 | static unsigned bit = 0, up = 1; | ||
36 | |||
37 | cnt += 1; | ||
38 | if (cnt < period) { | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | cnt = 0; | ||
43 | |||
44 | /* Go through the points (roughly!): | ||
45 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
46 | */ | ||
47 | period = 110 - ( (300<<FSHIFT)/ | ||
48 | ((avenrun[0]/5) + (3<<FSHIFT)) ); | ||
49 | |||
50 | if (up) { | ||
51 | if (bit == 7) { | ||
52 | bit--; | ||
53 | up=0; | ||
54 | } else { | ||
55 | bit ++; | ||
56 | } | ||
57 | } else { | ||
58 | if (bit == 0) { | ||
59 | bit++; | ||
60 | up=1; | ||
61 | } else { | ||
62 | bit--; | ||
63 | } | ||
64 | } | ||
65 | *p = 1<<(bit+8); | ||
66 | |||
67 | } | ||
68 | #endif /* CONFIG_HEARTBEAT */ | ||
diff --git a/arch/sh/boards/se/7751/mach.c b/arch/sh/boards/se/7751/mach.c new file mode 100644 index 000000000000..16d386b7e3bf --- /dev/null +++ b/arch/sh/boards/se/7751/mach.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/mach_7751se.c | ||
3 | * | ||
4 | * Minor tweak of mach_se.c file to reference 7751se-specific items. | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine vector for the Hitachi 7751 SolutionEngine | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/machvec.h> | ||
16 | #include <asm/rtc.h> | ||
17 | #include <asm/machvec_init.h> | ||
18 | |||
19 | #include <asm/se7751/io.h> | ||
20 | |||
21 | void heartbeat_7751se(void); | ||
22 | void init_7751se_IRQ(void); | ||
23 | |||
24 | /* | ||
25 | * The Machine Vector | ||
26 | */ | ||
27 | |||
28 | struct sh_machine_vector mv_7751se __initmv = { | ||
29 | .mv_nr_irqs = 72, | ||
30 | |||
31 | .mv_inb = sh7751se_inb, | ||
32 | .mv_inw = sh7751se_inw, | ||
33 | .mv_inl = sh7751se_inl, | ||
34 | .mv_outb = sh7751se_outb, | ||
35 | .mv_outw = sh7751se_outw, | ||
36 | .mv_outl = sh7751se_outl, | ||
37 | |||
38 | .mv_inb_p = sh7751se_inb_p, | ||
39 | .mv_inw_p = sh7751se_inw, | ||
40 | .mv_inl_p = sh7751se_inl, | ||
41 | .mv_outb_p = sh7751se_outb_p, | ||
42 | .mv_outw_p = sh7751se_outw, | ||
43 | .mv_outl_p = sh7751se_outl, | ||
44 | |||
45 | .mv_insl = sh7751se_insl, | ||
46 | .mv_outsl = sh7751se_outsl, | ||
47 | |||
48 | .mv_isa_port2addr = sh7751se_isa_port2addr, | ||
49 | |||
50 | .mv_init_irq = init_7751se_IRQ, | ||
51 | #ifdef CONFIG_HEARTBEAT | ||
52 | .mv_heartbeat = heartbeat_7751se, | ||
53 | #endif | ||
54 | }; | ||
55 | ALIAS_MV(7751se) | ||
diff --git a/arch/sh/boards/se/7751/pci.c b/arch/sh/boards/se/7751/pci.c new file mode 100644 index 000000000000..1f273efd2cf5 --- /dev/null +++ b/arch/sh/boards/se/7751/pci.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/pci-7751se.c | ||
3 | * | ||
4 | * Author: Ian DaSilva (idasilva@mvista.com) | ||
5 | * | ||
6 | * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * PCI initialization for the Hitachi SH7751 Solution Engine board (MS7751SE01) | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pci.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include "../../../drivers/pci/pci-sh7751.h" | ||
23 | |||
24 | #define PCIMCR_MRSET_OFF 0xBFFFFFFF | ||
25 | #define PCIMCR_RFSH_OFF 0xFFFFFFFB | ||
26 | |||
27 | /* | ||
28 | * Only long word accesses of the PCIC's internal local registers and the | ||
29 | * configuration registers from the CPU is supported. | ||
30 | */ | ||
31 | #define PCIC_WRITE(x,v) writel((v), PCI_REG(x)) | ||
32 | #define PCIC_READ(x) readl(PCI_REG(x)) | ||
33 | |||
34 | /* | ||
35 | * Description: This function sets up and initializes the pcic, sets | ||
36 | * up the BARS, maps the DRAM into the address space etc, etc. | ||
37 | */ | ||
38 | int __init pcibios_init_platform(void) | ||
39 | { | ||
40 | unsigned long bcr1, wcr1, wcr2, wcr3, mcr; | ||
41 | unsigned short bcr2; | ||
42 | |||
43 | /* | ||
44 | * Initialize the slave bus controller on the pcic. The values used | ||
45 | * here should not be hardcoded, but they should be taken from the bsc | ||
46 | * on the processor, to make this function as generic as possible. | ||
47 | * (i.e. Another sbc may usr different SDRAM timing settings -- in order | ||
48 | * for the pcic to work, its settings need to be exactly the same.) | ||
49 | */ | ||
50 | bcr1 = (*(volatile unsigned long*)(SH7751_BCR1)); | ||
51 | bcr2 = (*(volatile unsigned short*)(SH7751_BCR2)); | ||
52 | wcr1 = (*(volatile unsigned long*)(SH7751_WCR1)); | ||
53 | wcr2 = (*(volatile unsigned long*)(SH7751_WCR2)); | ||
54 | wcr3 = (*(volatile unsigned long*)(SH7751_WCR3)); | ||
55 | mcr = (*(volatile unsigned long*)(SH7751_MCR)); | ||
56 | |||
57 | bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */ | ||
58 | (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1; | ||
59 | |||
60 | bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ | ||
61 | PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */ | ||
62 | PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */ | ||
63 | PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */ | ||
64 | PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */ | ||
65 | PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */ | ||
66 | mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; | ||
67 | PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */ | ||
68 | |||
69 | |||
70 | /* Enable all interrupts, so we know what to fix */ | ||
71 | PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff); | ||
72 | PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f); | ||
73 | |||
74 | /* Set up standard PCI config registers */ | ||
75 | PCIC_WRITE(SH7751_PCICONF1, 0xF39000C7); /* Bus Master, Mem & I/O access */ | ||
76 | PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */ | ||
77 | PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */ | ||
78 | PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM) */ | ||
79 | PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */ | ||
80 | PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */ | ||
81 | PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* MEM (full 64M exposed) */ | ||
82 | PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */ | ||
83 | PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */ | ||
84 | PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */ | ||
85 | |||
86 | /* Now turn it on... */ | ||
87 | PCIC_WRITE(SH7751_PCICR, 0xa5000001); | ||
88 | |||
89 | /* | ||
90 | * Set PCIMBR and PCIIOBR here, assuming a single window | ||
91 | * (16M MEM, 256K IO) is enough. If a larger space is | ||
92 | * needed, the readx/writex and inx/outx functions will | ||
93 | * have to do more (e.g. setting registers for each call). | ||
94 | */ | ||
95 | |||
96 | /* | ||
97 | * Set the MBR so PCI address is one-to-one with window, | ||
98 | * meaning all calls go straight through... use BUG_ON to | ||
99 | * catch erroneous assumption. | ||
100 | */ | ||
101 | BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE); | ||
102 | |||
103 | PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM); | ||
104 | |||
105 | /* Set IOBR for window containing area specified in pci.h */ | ||
106 | PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK)); | ||
107 | |||
108 | /* All done, may as well say so... */ | ||
109 | printk("SH7751 PCI: Finished initialization of the PCI controller\n"); | ||
110 | |||
111 | return 1; | ||
112 | } | ||
113 | |||
114 | int __init pcibios_map_platform_irq(u8 slot, u8 pin) | ||
115 | { | ||
116 | switch (slot) { | ||
117 | case 0: return 13; | ||
118 | case 1: return 13; /* AMD Ethernet controller */ | ||
119 | case 2: return -1; | ||
120 | case 3: return -1; | ||
121 | case 4: return -1; | ||
122 | default: | ||
123 | printk("PCI: Bad IRQ mapping request for slot %d\n", slot); | ||
124 | return -1; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | static struct resource sh7751_io_resource = { | ||
129 | .name = "SH7751 IO", | ||
130 | .start = SH7751_PCI_IO_BASE, | ||
131 | .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, | ||
132 | .flags = IORESOURCE_IO | ||
133 | }; | ||
134 | |||
135 | static struct resource sh7751_mem_resource = { | ||
136 | .name = "SH7751 mem", | ||
137 | .start = SH7751_PCI_MEMORY_BASE, | ||
138 | .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, | ||
139 | .flags = IORESOURCE_MEM | ||
140 | }; | ||
141 | |||
142 | extern struct pci_ops sh7751_pci_ops; | ||
143 | |||
144 | struct pci_channel board_pci_channels[] = { | ||
145 | { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, | ||
146 | { NULL, NULL, NULL, 0, 0 }, | ||
147 | }; | ||
148 | |||
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c new file mode 100644 index 000000000000..9d111bb884f9 --- /dev/null +++ b/arch/sh/boards/se/7751/setup.c | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/setup_7751se.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Kazumoto Kojima | ||
5 | * | ||
6 | * Hitachi SolutionEngine Support. | ||
7 | * | ||
8 | * Modified for 7751 Solution Engine by | ||
9 | * Ian da Silva and Jeremy Siegel, 2001. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <linux/hdreg.h> | ||
17 | #include <linux/ide.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/se7751/se7751.h> | ||
20 | |||
21 | #ifdef CONFIG_SH_KGDB | ||
22 | #include <asm/kgdb.h> | ||
23 | #endif | ||
24 | |||
25 | /* | ||
26 | * Configure the Super I/O chip | ||
27 | */ | ||
28 | #if 0 | ||
29 | /* Leftover code from regular Solution Engine, for reference. */ | ||
30 | /* The SH7751 Solution Engine has a different SuperIO. */ | ||
31 | static void __init smsc_config(int index, int data) | ||
32 | { | ||
33 | outb_p(index, INDEX_PORT); | ||
34 | outb_p(data, DATA_PORT); | ||
35 | } | ||
36 | |||
37 | static void __init init_smsc(void) | ||
38 | { | ||
39 | outb_p(CONFIG_ENTER, CONFIG_PORT); | ||
40 | outb_p(CONFIG_ENTER, CONFIG_PORT); | ||
41 | |||
42 | /* FDC */ | ||
43 | smsc_config(CURRENT_LDN_INDEX, LDN_FDC); | ||
44 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
45 | smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */ | ||
46 | |||
47 | /* IDE1 */ | ||
48 | smsc_config(CURRENT_LDN_INDEX, LDN_IDE1); | ||
49 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
50 | smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */ | ||
51 | |||
52 | /* AUXIO (GPIO): to use IDE1 */ | ||
53 | smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO); | ||
54 | smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */ | ||
55 | smsc_config(GPIO47_INDEX, 0x00); /* nIOWOP */ | ||
56 | |||
57 | /* COM1 */ | ||
58 | smsc_config(CURRENT_LDN_INDEX, LDN_COM1); | ||
59 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
60 | smsc_config(IO_BASE_HI_INDEX, 0x03); | ||
61 | smsc_config(IO_BASE_LO_INDEX, 0xf8); | ||
62 | smsc_config(IRQ_SELECT_INDEX, 4); /* IRQ4 */ | ||
63 | |||
64 | /* COM2 */ | ||
65 | smsc_config(CURRENT_LDN_INDEX, LDN_COM2); | ||
66 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
67 | smsc_config(IO_BASE_HI_INDEX, 0x02); | ||
68 | smsc_config(IO_BASE_LO_INDEX, 0xf8); | ||
69 | smsc_config(IRQ_SELECT_INDEX, 3); /* IRQ3 */ | ||
70 | |||
71 | /* RTC */ | ||
72 | smsc_config(CURRENT_LDN_INDEX, LDN_RTC); | ||
73 | smsc_config(ACTIVATE_INDEX, 0x01); | ||
74 | smsc_config(IRQ_SELECT_INDEX, 8); /* IRQ8 */ | ||
75 | |||
76 | /* XXX: PARPORT, KBD, and MOUSE will come here... */ | ||
77 | outb_p(CONFIG_EXIT, CONFIG_PORT); | ||
78 | } | ||
79 | #endif | ||
80 | |||
81 | const char *get_system_type(void) | ||
82 | { | ||
83 | return "7751 SolutionEngine"; | ||
84 | } | ||
85 | |||
86 | #ifdef CONFIG_SH_KGDB | ||
87 | static int kgdb_uart_setup(void); | ||
88 | static struct kgdb_sermap kgdb_uart_sermap = | ||
89 | { "ttyS", 0, kgdb_uart_setup, NULL }; | ||
90 | #endif | ||
91 | |||
92 | /* | ||
93 | * Initialize the board | ||
94 | */ | ||
95 | void __init platform_setup(void) | ||
96 | { | ||
97 | /* Call init_smsc() replacement to set up SuperIO. */ | ||
98 | /* XXX: RTC setting comes here */ | ||
99 | #ifdef CONFIG_SH_KGDB | ||
100 | kgdb_register_sermap(&kgdb_uart_sermap); | ||
101 | #endif | ||
102 | } | ||
103 | |||
104 | /********************************************************************* | ||
105 | * Currently a hack (e.g. does not interact well w/serial.c, lots of * | ||
106 | * hardcoded stuff) but may be useful if SCI/F needs debugging. * | ||
107 | * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and * | ||
108 | * arch/i386/lib/kgdb_serial.c). * | ||
109 | *********************************************************************/ | ||
110 | |||
111 | #ifdef CONFIG_SH_KGDB | ||
112 | #include <linux/types.h> | ||
113 | #include <linux/serial.h> | ||
114 | #include <linux/serialP.h> | ||
115 | #include <linux/serial_reg.h> | ||
116 | |||
117 | #define COM1_PORT 0x3f8 /* Base I/O address */ | ||
118 | #define COM1_IRQ 4 /* IRQ not used yet */ | ||
119 | #define COM2_PORT 0x2f8 /* Base I/O address */ | ||
120 | #define COM2_IRQ 3 /* IRQ not used yet */ | ||
121 | |||
122 | #define SB_CLOCK 1843200 /* Serial baud clock */ | ||
123 | #define SB_BASE (SB_CLOCK/16) | ||
124 | #define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS | ||
125 | |||
126 | struct uart_port { | ||
127 | int base; | ||
128 | }; | ||
129 | #define UART_NPORTS 2 | ||
130 | struct uart_port uart_ports[] = { | ||
131 | { COM1_PORT }, | ||
132 | { COM2_PORT }, | ||
133 | }; | ||
134 | struct uart_port *kgdb_uart_port; | ||
135 | |||
136 | #define UART_IN(reg) inb_p(kgdb_uart_port->base + reg) | ||
137 | #define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg) | ||
138 | |||
139 | /* Basic read/write functions for the UART */ | ||
140 | #define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE) | ||
141 | static int kgdb_uart_getchar(void) | ||
142 | { | ||
143 | int lsr; | ||
144 | int c = -1; | ||
145 | |||
146 | while (c == -1) { | ||
147 | lsr = UART_IN(UART_LSR); | ||
148 | if (lsr & UART_LSR_DR) | ||
149 | c = UART_IN(UART_RX); | ||
150 | if ((lsr & UART_LSR_RXCERR)) | ||
151 | c = -1; | ||
152 | } | ||
153 | return c; | ||
154 | } | ||
155 | |||
156 | static void kgdb_uart_putchar(int c) | ||
157 | { | ||
158 | while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0) | ||
159 | ; | ||
160 | UART_OUT(UART_TX, c); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Initialize UART to configured/requested values. | ||
165 | * (But we don't interrupts yet, or interact w/serial.c) | ||
166 | */ | ||
167 | static int kgdb_uart_setup(void) | ||
168 | { | ||
169 | int port; | ||
170 | int lcr = 0; | ||
171 | int bdiv = 0; | ||
172 | |||
173 | if (kgdb_portnum >= UART_NPORTS) { | ||
174 | KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum); | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | kgdb_uart_port = &uart_ports[kgdb_portnum]; | ||
179 | |||
180 | /* Init sequence from gdb_hook_interrupt */ | ||
181 | UART_IN(UART_RX); | ||
182 | UART_OUT(UART_IER, 0); | ||
183 | |||
184 | UART_IN(UART_RX); /* Serial driver comments say */ | ||
185 | UART_IN(UART_IIR); /* this clears interrupt regs */ | ||
186 | UART_IN(UART_MSR); | ||
187 | |||
188 | /* Figure basic LCR values */ | ||
189 | switch (kgdb_bits) { | ||
190 | case '7': | ||
191 | lcr |= UART_LCR_WLEN7; | ||
192 | break; | ||
193 | default: case '8': | ||
194 | lcr |= UART_LCR_WLEN8; | ||
195 | break; | ||
196 | } | ||
197 | switch (kgdb_parity) { | ||
198 | case 'O': | ||
199 | lcr |= UART_LCR_PARITY; | ||
200 | break; | ||
201 | case 'E': | ||
202 | lcr |= (UART_LCR_PARITY | UART_LCR_EPAR); | ||
203 | break; | ||
204 | default: break; | ||
205 | } | ||
206 | |||
207 | /* Figure the baud rate divisor */ | ||
208 | bdiv = (SB_BASE/kgdb_baud); | ||
209 | |||
210 | /* Set the baud rate and LCR values */ | ||
211 | UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB)); | ||
212 | UART_OUT(UART_DLL, (bdiv & 0xff)); | ||
213 | UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff)); | ||
214 | UART_OUT(UART_LCR, lcr); | ||
215 | |||
216 | /* Set the MCR */ | ||
217 | UART_OUT(UART_MCR, SB_MCR); | ||
218 | |||
219 | /* Turn off FIFOs for now */ | ||
220 | UART_OUT(UART_FCR, 0); | ||
221 | |||
222 | /* Setup complete: initialize function pointers */ | ||
223 | kgdb_getchar = kgdb_uart_getchar; | ||
224 | kgdb_putchar = kgdb_uart_putchar; | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | #endif /* CONFIG_SH_KGDB */ | ||
diff --git a/arch/sh/boards/sh03/Makefile b/arch/sh/boards/sh03/Makefile new file mode 100644 index 000000000000..321be50e36a5 --- /dev/null +++ b/arch/sh/boards/sh03/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the Interface (CTP/PCI-SH03) specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o rtc.o | ||
6 | obj-$(CONFIG_HEARTBEAT) += led.o | ||
diff --git a/arch/sh/boards/sh03/led.c b/arch/sh/boards/sh03/led.c new file mode 100644 index 000000000000..c851b0bec80f --- /dev/null +++ b/arch/sh/boards/sh03/led.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/sh03/led.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Saito.K Interface Corporation. | ||
5 | * | ||
6 | * This file contains Interface CTP/PCI-SH03 specific LED code. | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #include <linux/sched.h> | ||
11 | |||
12 | /* Cycle the LED's in the clasic Knightrider/Sun pattern */ | ||
13 | void heartbeat_sh03(void) | ||
14 | { | ||
15 | static unsigned int cnt = 0, period = 0; | ||
16 | volatile unsigned char* p = (volatile unsigned char*)0xa0800000; | ||
17 | static unsigned bit = 0, up = 1; | ||
18 | |||
19 | cnt += 1; | ||
20 | if (cnt < period) { | ||
21 | return; | ||
22 | } | ||
23 | |||
24 | cnt = 0; | ||
25 | |||
26 | /* Go through the points (roughly!): | ||
27 | * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 | ||
28 | */ | ||
29 | period = 110 - ( (300<<FSHIFT)/ | ||
30 | ((avenrun[0]/5) + (3<<FSHIFT)) ); | ||
31 | |||
32 | if (up) { | ||
33 | if (bit == 7) { | ||
34 | bit--; | ||
35 | up=0; | ||
36 | } else { | ||
37 | bit ++; | ||
38 | } | ||
39 | } else { | ||
40 | if (bit == 0) { | ||
41 | bit++; | ||
42 | up=1; | ||
43 | } else { | ||
44 | bit--; | ||
45 | } | ||
46 | } | ||
47 | *p = 1<<bit; | ||
48 | |||
49 | } | ||
diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c new file mode 100644 index 000000000000..cbeca7037ba5 --- /dev/null +++ b/arch/sh/boards/sh03/rtc.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/sh03/rtc.c -- CTP/PCI-SH03 on-chip RTC support | ||
3 | * | ||
4 | * Copyright (C) 2004 Saito.K & Jeanne(ksaito@interface.co.jp) | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/time.h> | ||
12 | #include <asm/io.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | |||
16 | #define RTC_BASE 0xb0000000 | ||
17 | #define RTC_SEC1 (RTC_BASE + 0) | ||
18 | #define RTC_SEC10 (RTC_BASE + 1) | ||
19 | #define RTC_MIN1 (RTC_BASE + 2) | ||
20 | #define RTC_MIN10 (RTC_BASE + 3) | ||
21 | #define RTC_HOU1 (RTC_BASE + 4) | ||
22 | #define RTC_HOU10 (RTC_BASE + 5) | ||
23 | #define RTC_WEE1 (RTC_BASE + 6) | ||
24 | #define RTC_DAY1 (RTC_BASE + 7) | ||
25 | #define RTC_DAY10 (RTC_BASE + 8) | ||
26 | #define RTC_MON1 (RTC_BASE + 9) | ||
27 | #define RTC_MON10 (RTC_BASE + 10) | ||
28 | #define RTC_YEA1 (RTC_BASE + 11) | ||
29 | #define RTC_YEA10 (RTC_BASE + 12) | ||
30 | #define RTC_YEA100 (RTC_BASE + 13) | ||
31 | #define RTC_YEA1000 (RTC_BASE + 14) | ||
32 | #define RTC_CTL (RTC_BASE + 15) | ||
33 | #define RTC_BUSY 1 | ||
34 | #define RTC_STOP 2 | ||
35 | |||
36 | #ifndef BCD_TO_BIN | ||
37 | #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) | ||
38 | #endif | ||
39 | |||
40 | #ifndef BIN_TO_BCD | ||
41 | #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) | ||
42 | #endif | ||
43 | |||
44 | extern void (*rtc_get_time)(struct timespec *); | ||
45 | extern int (*rtc_set_time)(const time_t); | ||
46 | extern spinlock_t rtc_lock; | ||
47 | |||
48 | unsigned long get_cmos_time(void) | ||
49 | { | ||
50 | unsigned int year, mon, day, hour, min, sec; | ||
51 | int i; | ||
52 | |||
53 | spin_lock(&rtc_lock); | ||
54 | again: | ||
55 | for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ | ||
56 | if (!(ctrl_inb(RTC_CTL) & RTC_BUSY)) | ||
57 | break; | ||
58 | do { | ||
59 | sec = (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10; | ||
60 | min = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10; | ||
61 | hour = (ctrl_inb(RTC_HOU1) & 0xf) + (ctrl_inb(RTC_HOU10) & 0xf) * 10; | ||
62 | day = (ctrl_inb(RTC_DAY1) & 0xf) + (ctrl_inb(RTC_DAY10) & 0xf) * 10; | ||
63 | mon = (ctrl_inb(RTC_MON1) & 0xf) + (ctrl_inb(RTC_MON10) & 0xf) * 10; | ||
64 | year = (ctrl_inb(RTC_YEA1) & 0xf) + (ctrl_inb(RTC_YEA10) & 0xf) * 10 | ||
65 | + (ctrl_inb(RTC_YEA100 ) & 0xf) * 100 | ||
66 | + (ctrl_inb(RTC_YEA1000) & 0xf) * 1000; | ||
67 | } while (sec != (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10); | ||
68 | if (year == 0 || mon < 1 || mon > 12 || day > 31 || day < 1 || | ||
69 | hour > 23 || min > 59 || sec > 59) { | ||
70 | printk(KERN_ERR | ||
71 | "SH-03 RTC: invalid value, resetting to 1 Jan 2000\n"); | ||
72 | printk("year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n", | ||
73 | year, mon, day, hour, min, sec); | ||
74 | |||
75 | ctrl_outb(0, RTC_SEC1); ctrl_outb(0, RTC_SEC10); | ||
76 | ctrl_outb(0, RTC_MIN1); ctrl_outb(0, RTC_MIN10); | ||
77 | ctrl_outb(0, RTC_HOU1); ctrl_outb(0, RTC_HOU10); | ||
78 | ctrl_outb(6, RTC_WEE1); | ||
79 | ctrl_outb(1, RTC_DAY1); ctrl_outb(0, RTC_DAY10); | ||
80 | ctrl_outb(1, RTC_MON1); ctrl_outb(0, RTC_MON10); | ||
81 | ctrl_outb(0, RTC_YEA1); ctrl_outb(0, RTC_YEA10); | ||
82 | ctrl_outb(0, RTC_YEA100); | ||
83 | ctrl_outb(2, RTC_YEA1000); | ||
84 | ctrl_outb(0, RTC_CTL); | ||
85 | goto again; | ||
86 | } | ||
87 | |||
88 | spin_unlock(&rtc_lock); | ||
89 | return mktime(year, mon, day, hour, min, sec); | ||
90 | } | ||
91 | |||
92 | void sh03_rtc_gettimeofday(struct timespec *tv) | ||
93 | { | ||
94 | |||
95 | tv->tv_sec = get_cmos_time(); | ||
96 | tv->tv_nsec = 0; | ||
97 | } | ||
98 | |||
99 | static int set_rtc_mmss(unsigned long nowtime) | ||
100 | { | ||
101 | int retval = 0; | ||
102 | int real_seconds, real_minutes, cmos_minutes; | ||
103 | int i; | ||
104 | |||
105 | /* gets recalled with irq locally disabled */ | ||
106 | spin_lock(&rtc_lock); | ||
107 | for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ | ||
108 | if (!(ctrl_inb(RTC_CTL) & RTC_BUSY)) | ||
109 | break; | ||
110 | cmos_minutes = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10; | ||
111 | real_seconds = nowtime % 60; | ||
112 | real_minutes = nowtime / 60; | ||
113 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
114 | real_minutes += 30; /* correct for half hour time zone */ | ||
115 | real_minutes %= 60; | ||
116 | |||
117 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
118 | ctrl_outb(real_seconds % 10, RTC_SEC1); | ||
119 | ctrl_outb(real_seconds / 10, RTC_SEC10); | ||
120 | ctrl_outb(real_minutes % 10, RTC_MIN1); | ||
121 | ctrl_outb(real_minutes / 10, RTC_MIN10); | ||
122 | } else { | ||
123 | printk(KERN_WARNING | ||
124 | "set_rtc_mmss: can't update from %d to %d\n", | ||
125 | cmos_minutes, real_minutes); | ||
126 | retval = -1; | ||
127 | } | ||
128 | spin_unlock(&rtc_lock); | ||
129 | |||
130 | return retval; | ||
131 | } | ||
132 | |||
133 | int sh03_rtc_settimeofday(const time_t secs) | ||
134 | { | ||
135 | unsigned long nowtime = secs; | ||
136 | |||
137 | return set_rtc_mmss(nowtime); | ||
138 | } | ||
139 | |||
140 | void sh03_time_init(void) | ||
141 | { | ||
142 | rtc_get_time = sh03_rtc_gettimeofday; | ||
143 | rtc_set_time = sh03_rtc_settimeofday; | ||
144 | } | ||
diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c new file mode 100644 index 000000000000..d2a08ca5eb85 --- /dev/null +++ b/arch/sh/boards/sh03/setup.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/sh03/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Interface Co.,Ltd. Saito.K | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <linux/hdreg.h> | ||
12 | #include <linux/ide.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/sh03/io.h> | ||
15 | #include <asm/sh03/sh03.h> | ||
16 | #include <asm/addrspace.h> | ||
17 | #include "../../drivers/pci/pci-sh7751.h" | ||
18 | |||
19 | extern void (*board_time_init)(void); | ||
20 | |||
21 | const char *get_system_type(void) | ||
22 | { | ||
23 | return "Interface CTP/PCI-SH03)"; | ||
24 | } | ||
25 | |||
26 | void init_sh03_IRQ(void) | ||
27 | { | ||
28 | ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); | ||
29 | |||
30 | make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY); | ||
31 | make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY); | ||
32 | make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY); | ||
33 | make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY); | ||
34 | } | ||
35 | |||
36 | extern void *cf_io_base; | ||
37 | |||
38 | unsigned long sh03_isa_port2addr(unsigned long port) | ||
39 | { | ||
40 | if (PXSEG(port)) | ||
41 | return port; | ||
42 | /* CompactFlash (IDE) */ | ||
43 | if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6)) { | ||
44 | return (unsigned long)cf_io_base + port; | ||
45 | } | ||
46 | return port + SH7751_PCI_IO_BASE; | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * The Machine Vector | ||
51 | */ | ||
52 | |||
53 | struct sh_machine_vector mv_sh03 __initmv = { | ||
54 | .mv_nr_irqs = 48, | ||
55 | .mv_isa_port2addr = sh03_isa_port2addr, | ||
56 | .mv_init_irq = init_sh03_IRQ, | ||
57 | |||
58 | #ifdef CONFIG_HEARTBEAT | ||
59 | .mv_heartbeat = heartbeat_sh03, | ||
60 | #endif | ||
61 | }; | ||
62 | |||
63 | ALIAS_MV(sh03) | ||
64 | |||
65 | /* arch/sh/boards/sh03/rtc.c */ | ||
66 | void sh03_time_init(void); | ||
67 | |||
68 | int __init platform_setup(void) | ||
69 | { | ||
70 | board_time_init = sh03_time_init; | ||
71 | return 0; | ||
72 | } | ||
diff --git a/arch/sh/boards/sh2000/Makefile b/arch/sh/boards/sh2000/Makefile new file mode 100644 index 000000000000..05d390c3599c --- /dev/null +++ b/arch/sh/boards/sh2000/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the SH2000 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o | ||
6 | |||
diff --git a/arch/sh/boards/sh2000/setup.c b/arch/sh/boards/sh2000/setup.c new file mode 100644 index 000000000000..a290b1d09fb2 --- /dev/null +++ b/arch/sh/boards/sh2000/setup.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/setup_sh2000.c | ||
3 | * | ||
4 | * Copyright (C) 2001 SUGIOKA Tochinobu | ||
5 | * | ||
6 | * SH-2000 Support. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/irq.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | #include <asm/machvec.h> | ||
16 | #include <asm/mach/sh2000.h> | ||
17 | |||
18 | #define CF_CIS_BASE 0xb4200000 | ||
19 | |||
20 | #define PORT_PECR 0xa4000108 | ||
21 | #define PORT_PHCR 0xa400010E | ||
22 | #define PORT_ICR1 0xa4000010 | ||
23 | #define PORT_IRR0 0xa4000004 | ||
24 | |||
25 | #define IDE_OFFSET 0xb6200000 | ||
26 | #define NIC_OFFSET 0xb6000000 | ||
27 | #define EXTBUS_OFFSET 0xba000000 | ||
28 | |||
29 | |||
30 | const char *get_system_type(void) | ||
31 | { | ||
32 | return "sh2000"; | ||
33 | } | ||
34 | |||
35 | static unsigned long sh2000_isa_port2addr(unsigned long offset) | ||
36 | { | ||
37 | if((offset & ~7) == 0x1f0 || offset == 0x3f6) | ||
38 | return IDE_OFFSET + offset; | ||
39 | else if((offset & ~0x1f) == 0x300) | ||
40 | return NIC_OFFSET + offset; | ||
41 | return EXTBUS_OFFSET + offset; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * The Machine Vector | ||
46 | */ | ||
47 | struct sh_machine_vector mv_sh2000 __initmv = { | ||
48 | .mv_nr_irqs = 80, | ||
49 | .mv_isa_port2addr = sh2000_isa_port2addr, | ||
50 | }; | ||
51 | ALIAS_MV(sh2000) | ||
52 | |||
53 | /* | ||
54 | * Initialize the board | ||
55 | */ | ||
56 | int __init platform_setup(void) | ||
57 | { | ||
58 | /* XXX: RTC setting comes here */ | ||
59 | |||
60 | /* These should be done by BIOS/IPL ... */ | ||
61 | /* Enable nCE2A, nCE2B output */ | ||
62 | ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR); | ||
63 | /* Enable the Compact Flash card, and set the level interrupt */ | ||
64 | ctrl_outw(0x0042, CF_CIS_BASE+0x0200); | ||
65 | /* Enable interrupt */ | ||
66 | ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR); | ||
67 | ctrl_outw(1, PORT_ICR1); | ||
68 | ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0); | ||
69 | printk(KERN_INFO "SH-2000 Setup...done\n"); | ||
70 | return 0; | ||
71 | } | ||
diff --git a/arch/sh/boards/snapgear/Makefile b/arch/sh/boards/snapgear/Makefile new file mode 100644 index 000000000000..59fc976bfc2f --- /dev/null +++ b/arch/sh/boards/snapgear/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the SnapGear specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o io.o rtc.o | ||
6 | |||
diff --git a/arch/sh/boards/snapgear/io.c b/arch/sh/boards/snapgear/io.c new file mode 100644 index 000000000000..e2eb78fc381d --- /dev/null +++ b/arch/sh/boards/snapgear/io.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_7751se.c | ||
3 | * | ||
4 | * Copyright (C) 2002 David McCullough <davidm@snapgear.com> | ||
5 | * Copyright (C) 2001 Ian da Silva, Jeremy Siegel | ||
6 | * Based largely on io_se.c. | ||
7 | * | ||
8 | * I/O routine for Hitachi 7751 SolutionEngine. | ||
9 | * | ||
10 | * Initial version only to support LAN access; some | ||
11 | * placeholder code from io_se.c left in with the | ||
12 | * expectation of later SuperIO and PCMCIA access. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/addrspace.h> | ||
20 | |||
21 | #include <asm/pci.h> | ||
22 | #include "../../drivers/pci/pci-sh7751.h" | ||
23 | |||
24 | #ifdef CONFIG_SH_SECUREEDGE5410 | ||
25 | unsigned short secureedge5410_ioport; | ||
26 | #endif | ||
27 | |||
28 | /* | ||
29 | * The SnapGear uses the built-in PCI controller (PCIC) | ||
30 | * of the 7751 processor | ||
31 | */ | ||
32 | |||
33 | #define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR) | ||
34 | #define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR) | ||
35 | #define PCI_IO_AREA SH7751_PCI_IO_BASE | ||
36 | #define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE | ||
37 | |||
38 | |||
39 | #define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK)) | ||
40 | |||
41 | |||
42 | #define maybebadio(name,port) \ | ||
43 | printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ | ||
44 | #name, (port), (__u32) __builtin_return_address(0)) | ||
45 | |||
46 | |||
47 | static inline void delay(void) | ||
48 | { | ||
49 | ctrl_inw(0xa0000000); | ||
50 | } | ||
51 | |||
52 | |||
53 | static inline volatile __u16 *port2adr(unsigned int port) | ||
54 | { | ||
55 | #if 0 | ||
56 | if (port >= 0x2000) | ||
57 | return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); | ||
58 | #endif | ||
59 | maybebadio(name,(unsigned long)port); | ||
60 | return (volatile __u16*)port; | ||
61 | } | ||
62 | |||
63 | |||
64 | /* In case someone configures the kernel w/o PCI support: in that */ | ||
65 | /* scenario, don't ever bother to check for PCI-window addresses */ | ||
66 | |||
67 | /* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */ | ||
68 | #if defined(CONFIG_PCI) | ||
69 | #define CHECK_SH7751_PCIIO(port) \ | ||
70 | ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE))) | ||
71 | #else | ||
72 | #define CHECK_SH7751_PCIIO(port) (0) | ||
73 | #endif | ||
74 | |||
75 | /* | ||
76 | * General outline: remap really low stuff [eventually] to SuperIO, | ||
77 | * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) | ||
78 | * is mapped through the PCI IO window. Stuff with high bits (PXSEG) | ||
79 | * should be way beyond the window, and is used w/o translation for | ||
80 | * compatibility. | ||
81 | */ | ||
82 | |||
83 | unsigned char snapgear_inb(unsigned long port) | ||
84 | { | ||
85 | if (PXSEG(port)) | ||
86 | return *(volatile unsigned char *)port; | ||
87 | else if (CHECK_SH7751_PCIIO(port)) | ||
88 | return *(volatile unsigned char *)PCI_IOMAP(port); | ||
89 | else | ||
90 | return (*port2adr(port))&0xff; | ||
91 | } | ||
92 | |||
93 | |||
94 | unsigned char snapgear_inb_p(unsigned long port) | ||
95 | { | ||
96 | unsigned char v; | ||
97 | |||
98 | if (PXSEG(port)) | ||
99 | v = *(volatile unsigned char *)port; | ||
100 | else if (CHECK_SH7751_PCIIO(port)) | ||
101 | v = *(volatile unsigned char *)PCI_IOMAP(port); | ||
102 | else | ||
103 | v = (*port2adr(port))&0xff; | ||
104 | delay(); | ||
105 | return v; | ||
106 | } | ||
107 | |||
108 | |||
109 | unsigned short snapgear_inw(unsigned long port) | ||
110 | { | ||
111 | if (PXSEG(port)) | ||
112 | return *(volatile unsigned short *)port; | ||
113 | else if (CHECK_SH7751_PCIIO(port)) | ||
114 | return *(volatile unsigned short *)PCI_IOMAP(port); | ||
115 | else if (port >= 0x2000) | ||
116 | return *port2adr(port); | ||
117 | else | ||
118 | maybebadio(inw, port); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | |||
123 | unsigned int snapgear_inl(unsigned long port) | ||
124 | { | ||
125 | if (PXSEG(port)) | ||
126 | return *(volatile unsigned long *)port; | ||
127 | else if (CHECK_SH7751_PCIIO(port)) | ||
128 | return *(volatile unsigned int *)PCI_IOMAP(port); | ||
129 | else if (port >= 0x2000) | ||
130 | return *port2adr(port); | ||
131 | else | ||
132 | maybebadio(inl, port); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | |||
137 | void snapgear_outb(unsigned char value, unsigned long port) | ||
138 | { | ||
139 | |||
140 | if (PXSEG(port)) | ||
141 | *(volatile unsigned char *)port = value; | ||
142 | else if (CHECK_SH7751_PCIIO(port)) | ||
143 | *((unsigned char*)PCI_IOMAP(port)) = value; | ||
144 | else | ||
145 | *(port2adr(port)) = value; | ||
146 | } | ||
147 | |||
148 | |||
149 | void snapgear_outb_p(unsigned char value, unsigned long port) | ||
150 | { | ||
151 | if (PXSEG(port)) | ||
152 | *(volatile unsigned char *)port = value; | ||
153 | else if (CHECK_SH7751_PCIIO(port)) | ||
154 | *((unsigned char*)PCI_IOMAP(port)) = value; | ||
155 | else | ||
156 | *(port2adr(port)) = value; | ||
157 | delay(); | ||
158 | } | ||
159 | |||
160 | |||
161 | void snapgear_outw(unsigned short value, unsigned long port) | ||
162 | { | ||
163 | if (PXSEG(port)) | ||
164 | *(volatile unsigned short *)port = value; | ||
165 | else if (CHECK_SH7751_PCIIO(port)) | ||
166 | *((unsigned short *)PCI_IOMAP(port)) = value; | ||
167 | else if (port >= 0x2000) | ||
168 | *port2adr(port) = value; | ||
169 | else | ||
170 | maybebadio(outw, port); | ||
171 | } | ||
172 | |||
173 | |||
174 | void snapgear_outl(unsigned int value, unsigned long port) | ||
175 | { | ||
176 | if (PXSEG(port)) | ||
177 | *(volatile unsigned long *)port = value; | ||
178 | else if (CHECK_SH7751_PCIIO(port)) | ||
179 | *((unsigned long*)PCI_IOMAP(port)) = value; | ||
180 | else | ||
181 | maybebadio(outl, port); | ||
182 | } | ||
183 | |||
184 | void snapgear_insl(unsigned long port, void *addr, unsigned long count) | ||
185 | { | ||
186 | maybebadio(insl, port); | ||
187 | } | ||
188 | |||
189 | void snapgear_outsl(unsigned long port, const void *addr, unsigned long count) | ||
190 | { | ||
191 | maybebadio(outsw, port); | ||
192 | } | ||
193 | |||
194 | /* Map ISA bus address to the real address. Only for PCMCIA. */ | ||
195 | |||
196 | |||
197 | /* ISA page descriptor. */ | ||
198 | static __u32 sh_isa_memmap[256]; | ||
199 | |||
200 | |||
201 | #if 0 | ||
202 | static int sh_isa_mmap(__u32 start, __u32 length, __u32 offset) | ||
203 | { | ||
204 | int idx; | ||
205 | |||
206 | if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000)) | ||
207 | return -1; | ||
208 | |||
209 | idx = start >> 12; | ||
210 | sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff); | ||
211 | #if 0 | ||
212 | printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n", | ||
213 | start, length, offset, idx, sh_isa_memmap[idx]); | ||
214 | #endif | ||
215 | return 0; | ||
216 | } | ||
217 | #endif | ||
218 | |||
219 | unsigned long snapgear_isa_port2addr(unsigned long offset) | ||
220 | { | ||
221 | int idx; | ||
222 | |||
223 | idx = (offset >> 12) & 0xff; | ||
224 | offset &= 0xfff; | ||
225 | return sh_isa_memmap[idx] + offset; | ||
226 | } | ||
diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c new file mode 100644 index 000000000000..b71e009da35c --- /dev/null +++ b/arch/sh/boards/snapgear/rtc.c | |||
@@ -0,0 +1,333 @@ | |||
1 | /****************************************************************************/ | ||
2 | /* | ||
3 | * linux/arch/sh/boards/snapgear/rtc.c -- Secureedge5410 RTC code | ||
4 | * | ||
5 | * Copyright (C) 2002 David McCullough <davidm@snapgear.com> | ||
6 | * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org> | ||
7 | * | ||
8 | * The SecureEdge5410 can have one of 2 real time clocks, the SH | ||
9 | * built in version or the preferred external DS1302. Here we work out | ||
10 | * each to see what we have and then run with it. | ||
11 | */ | ||
12 | /****************************************************************************/ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/time.h> | ||
18 | #include <linux/rtc.h> | ||
19 | #include <linux/mc146818rtc.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include <asm/rtc.h> | ||
23 | #include <asm/mc146818rtc.h> | ||
24 | |||
25 | /****************************************************************************/ | ||
26 | |||
27 | static int use_ds1302 = 0; | ||
28 | |||
29 | /****************************************************************************/ | ||
30 | /* | ||
31 | * we need to implement a DS1302 driver here that can operate in | ||
32 | * conjunction with the builtin rtc driver which is already quite friendly | ||
33 | */ | ||
34 | /*****************************************************************************/ | ||
35 | |||
36 | #define RTC_CMD_READ 0x81 /* Read command */ | ||
37 | #define RTC_CMD_WRITE 0x80 /* Write command */ | ||
38 | |||
39 | #define RTC_ADDR_YEAR 0x06 /* Address of year register */ | ||
40 | #define RTC_ADDR_DAY 0x05 /* Address of day of week register */ | ||
41 | #define RTC_ADDR_MON 0x04 /* Address of month register */ | ||
42 | #define RTC_ADDR_DATE 0x03 /* Address of day of month register */ | ||
43 | #define RTC_ADDR_HOUR 0x02 /* Address of hour register */ | ||
44 | #define RTC_ADDR_MIN 0x01 /* Address of minute register */ | ||
45 | #define RTC_ADDR_SEC 0x00 /* Address of second register */ | ||
46 | |||
47 | #define RTC_RESET 0x1000 | ||
48 | #define RTC_IODATA 0x0800 | ||
49 | #define RTC_SCLK 0x0400 | ||
50 | |||
51 | #define set_dirp(x) | ||
52 | #define get_dirp(x) 0 | ||
53 | #define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00) | ||
54 | #define get_dp(x) SECUREEDGE_READ_IOPORT() | ||
55 | |||
56 | static void ds1302_sendbits(unsigned int val) | ||
57 | { | ||
58 | int i; | ||
59 | |||
60 | for (i = 8; (i); i--, val >>= 1) { | ||
61 | set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ? RTC_IODATA : 0)); | ||
62 | set_dp(get_dp() | RTC_SCLK); // clock high | ||
63 | set_dp(get_dp() & ~RTC_SCLK); // clock low | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static unsigned int ds1302_recvbits(void) | ||
68 | { | ||
69 | unsigned int val; | ||
70 | int i; | ||
71 | |||
72 | for (i = 0, val = 0; (i < 8); i++) { | ||
73 | val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i); | ||
74 | set_dp(get_dp() | RTC_SCLK); // clock high | ||
75 | set_dp(get_dp() & ~RTC_SCLK); // clock low | ||
76 | } | ||
77 | return(val); | ||
78 | } | ||
79 | |||
80 | static unsigned int ds1302_readbyte(unsigned int addr) | ||
81 | { | ||
82 | unsigned int val; | ||
83 | unsigned long flags; | ||
84 | |||
85 | #if 0 | ||
86 | printk("SnapGear RTC: ds1302_readbyte(addr=%x)\n", addr); | ||
87 | #endif | ||
88 | |||
89 | local_irq_save(flags); | ||
90 | set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); | ||
91 | set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); | ||
92 | |||
93 | set_dp(get_dp() | RTC_RESET); | ||
94 | ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ); | ||
95 | set_dirp(get_dirp() & ~RTC_IODATA); | ||
96 | val = ds1302_recvbits(); | ||
97 | set_dp(get_dp() & ~RTC_RESET); | ||
98 | local_irq_restore(flags); | ||
99 | |||
100 | return(val); | ||
101 | } | ||
102 | |||
103 | static void ds1302_writebyte(unsigned int addr, unsigned int val) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | |||
107 | #if 0 | ||
108 | printk("SnapGear RTC: ds1302_writebyte(addr=%x)\n", addr); | ||
109 | #endif | ||
110 | |||
111 | local_irq_save(flags); | ||
112 | set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); | ||
113 | set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); | ||
114 | set_dp(get_dp() | RTC_RESET); | ||
115 | ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE); | ||
116 | ds1302_sendbits(val); | ||
117 | set_dp(get_dp() & ~RTC_RESET); | ||
118 | local_irq_restore(flags); | ||
119 | } | ||
120 | |||
121 | static void ds1302_reset(void) | ||
122 | { | ||
123 | unsigned long flags; | ||
124 | /* Hardware dependant reset/init */ | ||
125 | local_irq_save(flags); | ||
126 | set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); | ||
127 | set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); | ||
128 | local_irq_restore(flags); | ||
129 | } | ||
130 | |||
131 | /*****************************************************************************/ | ||
132 | |||
133 | static inline int bcd2int(int val) | ||
134 | { | ||
135 | return((((val & 0xf0) >> 4) * 10) + (val & 0xf)); | ||
136 | } | ||
137 | |||
138 | static inline int int2bcd(int val) | ||
139 | { | ||
140 | return(((val / 10) << 4) + (val % 10)); | ||
141 | } | ||
142 | |||
143 | /*****************************************************************************/ | ||
144 | /* | ||
145 | * Write and Read some RAM in the DS1302, if it works assume it's there | ||
146 | * Otherwise use the SH4 internal RTC | ||
147 | */ | ||
148 | |||
149 | void snapgear_rtc_gettimeofday(struct timespec *); | ||
150 | int snapgear_rtc_settimeofday(const time_t); | ||
151 | |||
152 | void __init secureedge5410_rtc_init(void) | ||
153 | { | ||
154 | unsigned char *test = "snapgear"; | ||
155 | int i; | ||
156 | |||
157 | ds1302_reset(); | ||
158 | |||
159 | use_ds1302 = 1; | ||
160 | |||
161 | for (i = 0; test[i]; i++) | ||
162 | ds1302_writebyte(32 + i, test[i]); | ||
163 | |||
164 | for (i = 0; test[i]; i++) | ||
165 | if (ds1302_readbyte(32 + i) != test[i]) { | ||
166 | use_ds1302 = 0; | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | if (use_ds1302) { | ||
171 | rtc_get_time = snapgear_rtc_gettimeofday; | ||
172 | rtc_set_time = snapgear_rtc_settimeofday; | ||
173 | } else { | ||
174 | rtc_get_time = sh_rtc_gettimeofday; | ||
175 | rtc_set_time = sh_rtc_settimeofday; | ||
176 | } | ||
177 | |||
178 | printk("SnapGear RTC: using %s rtc.\n", use_ds1302 ? "ds1302" : "internal"); | ||
179 | } | ||
180 | |||
181 | /****************************************************************************/ | ||
182 | /* | ||
183 | * our generic interface that chooses the correct code to use | ||
184 | */ | ||
185 | |||
186 | void snapgear_rtc_gettimeofday(struct timespec *ts) | ||
187 | { | ||
188 | unsigned int sec, min, hr, day, mon, yr; | ||
189 | |||
190 | if (!use_ds1302) { | ||
191 | sh_rtc_gettimeofday(ts); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | sec = bcd2int(ds1302_readbyte(RTC_ADDR_SEC)); | ||
196 | min = bcd2int(ds1302_readbyte(RTC_ADDR_MIN)); | ||
197 | hr = bcd2int(ds1302_readbyte(RTC_ADDR_HOUR)); | ||
198 | day = bcd2int(ds1302_readbyte(RTC_ADDR_DATE)); | ||
199 | mon = bcd2int(ds1302_readbyte(RTC_ADDR_MON)); | ||
200 | yr = bcd2int(ds1302_readbyte(RTC_ADDR_YEAR)); | ||
201 | |||
202 | bad_time: | ||
203 | if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 || | ||
204 | hr > 23 || min > 59 || sec > 59) { | ||
205 | printk(KERN_ERR | ||
206 | "SnapGear RTC: invalid value, resetting to 1 Jan 2000\n"); | ||
207 | ds1302_writebyte(RTC_ADDR_MIN, min = 0); | ||
208 | ds1302_writebyte(RTC_ADDR_HOUR, hr = 0); | ||
209 | ds1302_writebyte(RTC_ADDR_DAY, 7); | ||
210 | ds1302_writebyte(RTC_ADDR_DATE, day = 1); | ||
211 | ds1302_writebyte(RTC_ADDR_MON, mon = 1); | ||
212 | ds1302_writebyte(RTC_ADDR_YEAR, yr = 0); | ||
213 | ds1302_writebyte(RTC_ADDR_SEC, sec = 0); | ||
214 | } | ||
215 | |||
216 | ts->tv_sec = mktime(2000 + yr, mon, day, hr, min, sec); | ||
217 | if (ts->tv_sec < 0) { | ||
218 | #if 0 | ||
219 | printk("BAD TIME %d %d %d %d %d %d\n", yr, mon, day, hr, min, sec); | ||
220 | #endif | ||
221 | yr = 100; | ||
222 | goto bad_time; | ||
223 | } | ||
224 | ts->tv_nsec = 0; | ||
225 | } | ||
226 | |||
227 | int snapgear_rtc_settimeofday(const time_t secs) | ||
228 | { | ||
229 | int retval = 0; | ||
230 | int real_seconds, real_minutes, cmos_minutes; | ||
231 | unsigned long nowtime; | ||
232 | |||
233 | if (!use_ds1302) | ||
234 | return sh_rtc_settimeofday(secs); | ||
235 | |||
236 | /* | ||
237 | * This is called direct from the kernel timer handling code. | ||
238 | * It is supposed to synchronize the kernel clock to the RTC. | ||
239 | */ | ||
240 | |||
241 | nowtime = secs; | ||
242 | |||
243 | #if 1 | ||
244 | printk("SnapGear RTC: snapgear_rtc_settimeofday(nowtime=%ld)\n", nowtime); | ||
245 | #endif | ||
246 | |||
247 | /* STOP RTC */ | ||
248 | ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80); | ||
249 | |||
250 | cmos_minutes = bcd2int(ds1302_readbyte(RTC_ADDR_MIN)); | ||
251 | |||
252 | /* | ||
253 | * since we're only adjusting minutes and seconds, | ||
254 | * don't interfere with hour overflow. This avoids | ||
255 | * messing with unknown time zones but requires your | ||
256 | * RTC not to be off by more than 15 minutes | ||
257 | */ | ||
258 | real_seconds = nowtime % 60; | ||
259 | real_minutes = nowtime / 60; | ||
260 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
261 | real_minutes += 30; /* correct for half hour time zone */ | ||
262 | real_minutes %= 60; | ||
263 | |||
264 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
265 | ds1302_writebyte(RTC_ADDR_MIN, int2bcd(real_minutes)); | ||
266 | ds1302_writebyte(RTC_ADDR_SEC, int2bcd(real_seconds)); | ||
267 | } else { | ||
268 | printk(KERN_WARNING | ||
269 | "SnapGear RTC: can't update from %d to %d\n", | ||
270 | cmos_minutes, real_minutes); | ||
271 | retval = -1; | ||
272 | } | ||
273 | |||
274 | /* START RTC */ | ||
275 | ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80); | ||
276 | return(0); | ||
277 | } | ||
278 | |||
279 | unsigned char secureedge5410_cmos_read(int addr) | ||
280 | { | ||
281 | unsigned char val = 0; | ||
282 | |||
283 | if (!use_ds1302) | ||
284 | return(__CMOS_READ(addr, w)); | ||
285 | |||
286 | switch(addr) { | ||
287 | case RTC_SECONDS: val = ds1302_readbyte(RTC_ADDR_SEC); break; | ||
288 | case RTC_SECONDS_ALARM: break; | ||
289 | case RTC_MINUTES: val = ds1302_readbyte(RTC_ADDR_MIN); break; | ||
290 | case RTC_MINUTES_ALARM: break; | ||
291 | case RTC_HOURS: val = ds1302_readbyte(RTC_ADDR_HOUR); break; | ||
292 | case RTC_HOURS_ALARM: break; | ||
293 | case RTC_DAY_OF_WEEK: val = ds1302_readbyte(RTC_ADDR_DAY); break; | ||
294 | case RTC_DAY_OF_MONTH: val = ds1302_readbyte(RTC_ADDR_DATE); break; | ||
295 | case RTC_MONTH: val = ds1302_readbyte(RTC_ADDR_MON); break; | ||
296 | case RTC_YEAR: val = ds1302_readbyte(RTC_ADDR_YEAR); break; | ||
297 | case RTC_REG_A: /* RTC_FREQ_SELECT */ break; | ||
298 | case RTC_REG_B: /* RTC_CONTROL */ break; | ||
299 | case RTC_REG_C: /* RTC_INTR_FLAGS */ break; | ||
300 | case RTC_REG_D: val = RTC_VRT /* RTC_VALID */; break; | ||
301 | default: break; | ||
302 | } | ||
303 | |||
304 | return(val); | ||
305 | } | ||
306 | |||
307 | void secureedge5410_cmos_write(unsigned char val, int addr) | ||
308 | { | ||
309 | if (!use_ds1302) { | ||
310 | __CMOS_WRITE(val, addr, w); | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | switch(addr) { | ||
315 | case RTC_SECONDS: ds1302_writebyte(RTC_ADDR_SEC, val); break; | ||
316 | case RTC_SECONDS_ALARM: break; | ||
317 | case RTC_MINUTES: ds1302_writebyte(RTC_ADDR_MIN, val); break; | ||
318 | case RTC_MINUTES_ALARM: break; | ||
319 | case RTC_HOURS: ds1302_writebyte(RTC_ADDR_HOUR, val); break; | ||
320 | case RTC_HOURS_ALARM: break; | ||
321 | case RTC_DAY_OF_WEEK: ds1302_writebyte(RTC_ADDR_DAY, val); break; | ||
322 | case RTC_DAY_OF_MONTH: ds1302_writebyte(RTC_ADDR_DATE, val); break; | ||
323 | case RTC_MONTH: ds1302_writebyte(RTC_ADDR_MON, val); break; | ||
324 | case RTC_YEAR: ds1302_writebyte(RTC_ADDR_YEAR, val); break; | ||
325 | case RTC_REG_A: /* RTC_FREQ_SELECT */ break; | ||
326 | case RTC_REG_B: /* RTC_CONTROL */ break; | ||
327 | case RTC_REG_C: /* RTC_INTR_FLAGS */ break; | ||
328 | case RTC_REG_D: /* RTC_VALID */ break; | ||
329 | default: break; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /****************************************************************************/ | ||
diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c new file mode 100644 index 000000000000..08fc98342a0b --- /dev/null +++ b/arch/sh/boards/snapgear/setup.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /****************************************************************************/ | ||
2 | /* | ||
3 | * linux/arch/sh/boards/snapgear/setup.c | ||
4 | * | ||
5 | * Copyright (C) 2002 David McCullough <davidm@snapgear.com> | ||
6 | * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org> | ||
7 | * | ||
8 | * Based on files with the following comments: | ||
9 | * | ||
10 | * Copyright (C) 2000 Kazumoto Kojima | ||
11 | * | ||
12 | * Modified for 7751 Solution Engine by | ||
13 | * Ian da Silva and Jeremy Siegel, 2001. | ||
14 | */ | ||
15 | /****************************************************************************/ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/sched.h> | ||
25 | |||
26 | #include <asm/machvec.h> | ||
27 | #include <asm/mach/io.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/cpu/timer.h> | ||
31 | |||
32 | extern void (*board_time_init)(void); | ||
33 | extern void secureedge5410_rtc_init(void); | ||
34 | extern void pcibios_init(void); | ||
35 | |||
36 | /****************************************************************************/ | ||
37 | /* | ||
38 | * EraseConfig handling functions | ||
39 | */ | ||
40 | |||
41 | static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
42 | { | ||
43 | volatile char dummy __attribute__((unused)) = * (volatile char *) 0xb8000000; | ||
44 | |||
45 | printk("SnapGear: erase switch interrupt!\n"); | ||
46 | |||
47 | return IRQ_HANDLED; | ||
48 | } | ||
49 | |||
50 | static int __init eraseconfig_init(void) | ||
51 | { | ||
52 | printk("SnapGear: EraseConfig init\n"); | ||
53 | /* Setup "EraseConfig" switch on external IRQ 0 */ | ||
54 | if (request_irq(IRL0_IRQ, eraseconfig_interrupt, SA_INTERRUPT, | ||
55 | "Erase Config", NULL)) | ||
56 | printk("SnapGear: failed to register IRQ%d for Reset witch\n", | ||
57 | IRL0_IRQ); | ||
58 | else | ||
59 | printk("SnapGear: registered EraseConfig switch on IRQ%d\n", | ||
60 | IRL0_IRQ); | ||
61 | return(0); | ||
62 | } | ||
63 | |||
64 | module_init(eraseconfig_init); | ||
65 | |||
66 | /****************************************************************************/ | ||
67 | /* | ||
68 | * Initialize IRQ setting | ||
69 | * | ||
70 | * IRL0 = erase switch | ||
71 | * IRL1 = eth0 | ||
72 | * IRL2 = eth1 | ||
73 | * IRL3 = crypto | ||
74 | */ | ||
75 | |||
76 | static void __init init_snapgear_IRQ(void) | ||
77 | { | ||
78 | /* enable individual interrupt mode for externals */ | ||
79 | ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); | ||
80 | |||
81 | printk("Setup SnapGear IRQ/IPR ...\n"); | ||
82 | |||
83 | make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY); | ||
84 | make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY); | ||
85 | make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY); | ||
86 | make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY); | ||
87 | } | ||
88 | |||
89 | /****************************************************************************/ | ||
90 | /* | ||
91 | * Fast poll interrupt simulator. | ||
92 | */ | ||
93 | |||
94 | /* | ||
95 | * Leave all of the fast timer/fast poll stuff commented out for now, since | ||
96 | * it's not clear whether it actually works or not. Since it wasn't being used | ||
97 | * at all in 2.4, we'll assume it's not sane for 2.6 either.. -- PFM | ||
98 | */ | ||
99 | #if 0 | ||
100 | #define FAST_POLL 1000 | ||
101 | //#define FAST_POLL_INTR | ||
102 | |||
103 | #define FASTTIMER_IRQ 17 | ||
104 | #define FASTTIMER_IPR_ADDR INTC_IPRA | ||
105 | #define FASTTIMER_IPR_POS 2 | ||
106 | #define FASTTIMER_PRIORITY 3 | ||
107 | |||
108 | #ifdef FAST_POLL_INTR | ||
109 | #define TMU1_TCR_INIT 0x0020 | ||
110 | #else | ||
111 | #define TMU1_TCR_INIT 0 | ||
112 | #endif | ||
113 | #define TMU_TSTR_INIT 1 | ||
114 | #define TMU1_TCR_CALIB 0x0000 | ||
115 | |||
116 | |||
117 | #ifdef FAST_POLL_INTR | ||
118 | static void fast_timer_irq(int irq, void *dev_instance, struct pt_regs *regs) | ||
119 | { | ||
120 | unsigned long timer_status; | ||
121 | timer_status = ctrl_inw(TMU1_TCR); | ||
122 | timer_status &= ~0x100; | ||
123 | ctrl_outw(timer_status, TMU1_TCR); | ||
124 | } | ||
125 | #endif | ||
126 | |||
127 | /* | ||
128 | * return the current ticks on the fast timer | ||
129 | */ | ||
130 | |||
131 | unsigned long fast_timer_count(void) | ||
132 | { | ||
133 | return(ctrl_inl(TMU1_TCNT)); | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * setup a fast timer for profiling etc etc | ||
138 | */ | ||
139 | |||
140 | static void setup_fast_timer() | ||
141 | { | ||
142 | unsigned long interval; | ||
143 | |||
144 | #ifdef FAST_POLL_INTR | ||
145 | interval = (current_cpu_data.module_clock/4 + FAST_POLL/2) / FAST_POLL; | ||
146 | |||
147 | make_ipr_irq(FASTTIMER_IRQ, FASTTIMER_IPR_ADDR, FASTTIMER_IPR_POS, | ||
148 | FASTTIMER_PRIORITY); | ||
149 | |||
150 | printk("SnapGear: %dHz fast timer on IRQ %d\n",FAST_POLL,FASTTIMER_IRQ); | ||
151 | |||
152 | if (request_irq(FASTTIMER_IRQ, fast_timer_irq, 0, "SnapGear fast timer", | ||
153 | NULL) != 0) | ||
154 | printk("%s(%d): request_irq() failed?\n", __FILE__, __LINE__); | ||
155 | #else | ||
156 | printk("SnapGear: fast timer running\n",FAST_POLL,FASTTIMER_IRQ); | ||
157 | interval = 0xffffffff; | ||
158 | #endif | ||
159 | |||
160 | ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */ | ||
161 | ctrl_outw(TMU1_TCR_INIT, TMU1_TCR); | ||
162 | ctrl_outl(interval, TMU1_TCOR); | ||
163 | ctrl_outl(interval, TMU1_TCNT); | ||
164 | ctrl_outb(ctrl_inb(TMU_TSTR) | 0x2, TMU_TSTR); /* enable timer 1 */ | ||
165 | |||
166 | printk("Timer count 1 = 0x%x\n", fast_timer_count()); | ||
167 | udelay(1000); | ||
168 | printk("Timer count 2 = 0x%x\n", fast_timer_count()); | ||
169 | } | ||
170 | #endif | ||
171 | |||
172 | /****************************************************************************/ | ||
173 | |||
174 | const char *get_system_type(void) | ||
175 | { | ||
176 | return "SnapGear SecureEdge5410"; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * The Machine Vector | ||
181 | */ | ||
182 | |||
183 | struct sh_machine_vector mv_snapgear __initmv = { | ||
184 | .mv_nr_irqs = 72, | ||
185 | |||
186 | .mv_inb = snapgear_inb, | ||
187 | .mv_inw = snapgear_inw, | ||
188 | .mv_inl = snapgear_inl, | ||
189 | .mv_outb = snapgear_outb, | ||
190 | .mv_outw = snapgear_outw, | ||
191 | .mv_outl = snapgear_outl, | ||
192 | |||
193 | .mv_inb_p = snapgear_inb_p, | ||
194 | .mv_inw_p = snapgear_inw, | ||
195 | .mv_inl_p = snapgear_inl, | ||
196 | .mv_outb_p = snapgear_outb_p, | ||
197 | .mv_outw_p = snapgear_outw, | ||
198 | .mv_outl_p = snapgear_outl, | ||
199 | |||
200 | .mv_isa_port2addr = snapgear_isa_port2addr, | ||
201 | |||
202 | .mv_init_irq = init_snapgear_IRQ, | ||
203 | }; | ||
204 | ALIAS_MV(snapgear) | ||
205 | |||
206 | /* | ||
207 | * Initialize the board | ||
208 | */ | ||
209 | |||
210 | int __init platform_setup(void) | ||
211 | { | ||
212 | board_time_init = secureedge5410_rtc_init; | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
diff --git a/arch/sh/boards/superh/microdev/Makefile b/arch/sh/boards/superh/microdev/Makefile new file mode 100644 index 000000000000..1387dd6c85eb --- /dev/null +++ b/arch/sh/boards/superh/microdev/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the SuperH MicroDev specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o irq.o io.o | ||
6 | |||
7 | obj-$(CONFIG_HEARTBEAT) += led.o | ||
8 | |||
diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c new file mode 100644 index 000000000000..fe83b2c03076 --- /dev/null +++ b/arch/sh/boards/superh/microdev/io.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_microdev.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com) | ||
5 | * Copyright (C) 2003, 2004 SuperH, Inc. | ||
6 | * Copyright (C) 2004 Paul Mundt | ||
7 | * | ||
8 | * SuperH SH4-202 MicroDev board support. | ||
9 | * | ||
10 | * May be copied or modified under the terms of the GNU General Public | ||
11 | * License. See linux/COPYING for more information. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/mach/io.h> | ||
20 | |||
21 | /* | ||
22 | * we need to have a 'safe' address to re-direct all I/O requests | ||
23 | * that we do not explicitly wish to handle. This safe address | ||
24 | * must have the following properies: | ||
25 | * | ||
26 | * * writes are ignored (no exception) | ||
27 | * * reads are benign (no side-effects) | ||
28 | * * accesses of width 1, 2 and 4-bytes are all valid. | ||
29 | * | ||
30 | * The Processor Version Register (PVR) has these properties. | ||
31 | */ | ||
32 | #define PVR 0xff000030 /* Processor Version Register */ | ||
33 | |||
34 | |||
35 | #define IO_IDE2_BASE 0x170ul /* I/O base for SMSC FDC37C93xAPM IDE #2 */ | ||
36 | #define IO_IDE1_BASE 0x1f0ul /* I/O base for SMSC FDC37C93xAPM IDE #1 */ | ||
37 | #define IO_ISP1161_BASE 0x290ul /* I/O port for Philips ISP1161x USB chip */ | ||
38 | #define IO_SERIAL2_BASE 0x2f8ul /* I/O base for SMSC FDC37C93xAPM Serial #2 */ | ||
39 | #define IO_LAN91C111_BASE 0x300ul /* I/O base for SMSC LAN91C111 Ethernet chip */ | ||
40 | #define IO_IDE2_MISC 0x376ul /* I/O misc for SMSC FDC37C93xAPM IDE #2 */ | ||
41 | #define IO_SUPERIO_BASE 0x3f0ul /* I/O base for SMSC FDC37C93xAPM SuperIO chip */ | ||
42 | #define IO_IDE1_MISC 0x3f6ul /* I/O misc for SMSC FDC37C93xAPM IDE #1 */ | ||
43 | #define IO_SERIAL1_BASE 0x3f8ul /* I/O base for SMSC FDC37C93xAPM Serial #1 */ | ||
44 | |||
45 | #define IO_ISP1161_EXTENT 0x04ul /* I/O extent for Philips ISP1161x USB chip */ | ||
46 | #define IO_LAN91C111_EXTENT 0x10ul /* I/O extent for SMSC LAN91C111 Ethernet chip */ | ||
47 | #define IO_SUPERIO_EXTENT 0x02ul /* I/O extent for SMSC FDC37C93xAPM SuperIO chip */ | ||
48 | #define IO_IDE_EXTENT 0x08ul /* I/O extent for IDE Task Register set */ | ||
49 | #define IO_SERIAL_EXTENT 0x10ul | ||
50 | |||
51 | #define IO_LAN91C111_PHYS 0xa7500000ul /* Physical address of SMSC LAN91C111 Ethernet chip */ | ||
52 | #define IO_ISP1161_PHYS 0xa7700000ul /* Physical address of Philips ISP1161x USB chip */ | ||
53 | #define IO_SUPERIO_PHYS 0xa7800000ul /* Physical address of SMSC FDC37C93xAPM SuperIO chip */ | ||
54 | |||
55 | #define PORT2ADDR(x) (microdev_isa_port2addr(x)) | ||
56 | |||
57 | |||
58 | static inline void delay(void) | ||
59 | { | ||
60 | #if defined(CONFIG_PCI) | ||
61 | /* System board present, just make a dummy SRAM access. (CS0 will be | ||
62 | mapped to PCI memory, probably good to avoid it.) */ | ||
63 | ctrl_inw(0xa6800000); | ||
64 | #else | ||
65 | /* CS0 will be mapped to flash, ROM etc so safe to access it. */ | ||
66 | ctrl_inw(0xa0000000); | ||
67 | #endif | ||
68 | } | ||
69 | |||
70 | unsigned char microdev_inb(unsigned long port) | ||
71 | { | ||
72 | #ifdef CONFIG_PCI | ||
73 | if (port >= PCIBIOS_MIN_IO) | ||
74 | return microdev_pci_inb(port); | ||
75 | #endif | ||
76 | return *(volatile unsigned char*)PORT2ADDR(port); | ||
77 | } | ||
78 | |||
79 | unsigned short microdev_inw(unsigned long port) | ||
80 | { | ||
81 | #ifdef CONFIG_PCI | ||
82 | if (port >= PCIBIOS_MIN_IO) | ||
83 | return microdev_pci_inw(port); | ||
84 | #endif | ||
85 | return *(volatile unsigned short*)PORT2ADDR(port); | ||
86 | } | ||
87 | |||
88 | unsigned int microdev_inl(unsigned long port) | ||
89 | { | ||
90 | #ifdef CONFIG_PCI | ||
91 | if (port >= PCIBIOS_MIN_IO) | ||
92 | return microdev_pci_inl(port); | ||
93 | #endif | ||
94 | return *(volatile unsigned int*)PORT2ADDR(port); | ||
95 | } | ||
96 | |||
97 | void microdev_outb(unsigned char b, unsigned long port) | ||
98 | { | ||
99 | #ifdef CONFIG_PCI | ||
100 | if (port >= PCIBIOS_MIN_IO) { | ||
101 | microdev_pci_outb(b, port); | ||
102 | return; | ||
103 | } | ||
104 | #endif | ||
105 | |||
106 | /* | ||
107 | * There is a board feature with the current SH4-202 MicroDev in | ||
108 | * that the 2 byte enables (nBE0 and nBE1) are tied together (and | ||
109 | * to the Chip Select Line (Ethernet_CS)). Due to this conectivity, | ||
110 | * it is not possible to safely perform 8-bit writes to the | ||
111 | * Ethernet registers, as 16-bits will be consumed from the Data | ||
112 | * lines (corrupting the other byte). Hence, this function is | ||
113 | * written to impliment 16-bit read/modify/write for all byte-wide | ||
114 | * acceses. | ||
115 | * | ||
116 | * Note: there is no problem with byte READS (even or odd). | ||
117 | * | ||
118 | * Sean McGoogan - 16th June 2003. | ||
119 | */ | ||
120 | if ((port >= IO_LAN91C111_BASE) && | ||
121 | (port < IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) { | ||
122 | /* | ||
123 | * Then are trying to perform a byte-write to the | ||
124 | * LAN91C111. This needs special care. | ||
125 | */ | ||
126 | if (port % 2 == 1) { /* is the port odd ? */ | ||
127 | /* unset bit-0, i.e. make even */ | ||
128 | const unsigned long evenPort = port-1; | ||
129 | unsigned short word; | ||
130 | |||
131 | /* | ||
132 | * do a 16-bit read/write to write to 'port', | ||
133 | * preserving even byte. | ||
134 | * | ||
135 | * Even addresses are bits 0-7 | ||
136 | * Odd addresses are bits 8-15 | ||
137 | */ | ||
138 | word = microdev_inw(evenPort); | ||
139 | word = (word & 0xffu) | (b << 8); | ||
140 | microdev_outw(word, evenPort); | ||
141 | } else { | ||
142 | /* else, we are trying to do an even byte write */ | ||
143 | unsigned short word; | ||
144 | |||
145 | /* | ||
146 | * do a 16-bit read/write to write to 'port', | ||
147 | * preserving odd byte. | ||
148 | * | ||
149 | * Even addresses are bits 0-7 | ||
150 | * Odd addresses are bits 8-15 | ||
151 | */ | ||
152 | word = microdev_inw(port); | ||
153 | word = (word & 0xff00u) | (b); | ||
154 | microdev_outw(word, port); | ||
155 | } | ||
156 | } else { | ||
157 | *(volatile unsigned char*)PORT2ADDR(port) = b; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | void microdev_outw(unsigned short b, unsigned long port) | ||
162 | { | ||
163 | #ifdef CONFIG_PCI | ||
164 | if (port >= PCIBIOS_MIN_IO) { | ||
165 | microdev_pci_outw(b, port); | ||
166 | return; | ||
167 | } | ||
168 | #endif | ||
169 | *(volatile unsigned short*)PORT2ADDR(port) = b; | ||
170 | } | ||
171 | |||
172 | void microdev_outl(unsigned int b, unsigned long port) | ||
173 | { | ||
174 | #ifdef CONFIG_PCI | ||
175 | if (port >= PCIBIOS_MIN_IO) { | ||
176 | microdev_pci_outl(b, port); | ||
177 | return; | ||
178 | } | ||
179 | #endif | ||
180 | *(volatile unsigned int*)PORT2ADDR(port) = b; | ||
181 | } | ||
182 | |||
183 | unsigned char microdev_inb_p(unsigned long port) | ||
184 | { | ||
185 | unsigned char v = microdev_inb(port); | ||
186 | delay(); | ||
187 | return v; | ||
188 | } | ||
189 | |||
190 | unsigned short microdev_inw_p(unsigned long port) | ||
191 | { | ||
192 | unsigned short v = microdev_inw(port); | ||
193 | delay(); | ||
194 | return v; | ||
195 | } | ||
196 | |||
197 | unsigned int microdev_inl_p(unsigned long port) | ||
198 | { | ||
199 | unsigned int v = microdev_inl(port); | ||
200 | delay(); | ||
201 | return v; | ||
202 | } | ||
203 | |||
204 | void microdev_outb_p(unsigned char b, unsigned long port) | ||
205 | { | ||
206 | microdev_outb(b, port); | ||
207 | delay(); | ||
208 | } | ||
209 | |||
210 | void microdev_outw_p(unsigned short b, unsigned long port) | ||
211 | { | ||
212 | microdev_outw(b, port); | ||
213 | delay(); | ||
214 | } | ||
215 | |||
216 | void microdev_outl_p(unsigned int b, unsigned long port) | ||
217 | { | ||
218 | microdev_outl(b, port); | ||
219 | delay(); | ||
220 | } | ||
221 | |||
222 | void microdev_insb(unsigned long port, void *buffer, unsigned long count) | ||
223 | { | ||
224 | volatile unsigned char *port_addr; | ||
225 | unsigned char *buf = buffer; | ||
226 | |||
227 | port_addr = (volatile unsigned char *)PORT2ADDR(port); | ||
228 | |||
229 | while (count--) | ||
230 | *buf++ = *port_addr; | ||
231 | } | ||
232 | |||
233 | void microdev_insw(unsigned long port, void *buffer, unsigned long count) | ||
234 | { | ||
235 | volatile unsigned short *port_addr; | ||
236 | unsigned short *buf = buffer; | ||
237 | |||
238 | port_addr = (volatile unsigned short *)PORT2ADDR(port); | ||
239 | |||
240 | while (count--) | ||
241 | *buf++ = *port_addr; | ||
242 | } | ||
243 | |||
244 | void microdev_insl(unsigned long port, void *buffer, unsigned long count) | ||
245 | { | ||
246 | volatile unsigned long *port_addr; | ||
247 | unsigned int *buf = buffer; | ||
248 | |||
249 | port_addr = (volatile unsigned long *)PORT2ADDR(port); | ||
250 | |||
251 | while (count--) | ||
252 | *buf++ = *port_addr; | ||
253 | } | ||
254 | |||
255 | void microdev_outsb(unsigned long port, const void *buffer, unsigned long count) | ||
256 | { | ||
257 | volatile unsigned char *port_addr; | ||
258 | const unsigned char *buf = buffer; | ||
259 | |||
260 | port_addr = (volatile unsigned char *)PORT2ADDR(port); | ||
261 | |||
262 | while (count--) | ||
263 | *port_addr = *buf++; | ||
264 | } | ||
265 | |||
266 | void microdev_outsw(unsigned long port, const void *buffer, unsigned long count) | ||
267 | { | ||
268 | volatile unsigned short *port_addr; | ||
269 | const unsigned short *buf = buffer; | ||
270 | |||
271 | port_addr = (volatile unsigned short *)PORT2ADDR(port); | ||
272 | |||
273 | while (count--) | ||
274 | *port_addr = *buf++; | ||
275 | } | ||
276 | |||
277 | void microdev_outsl(unsigned long port, const void *buffer, unsigned long count) | ||
278 | { | ||
279 | volatile unsigned long *port_addr; | ||
280 | const unsigned int *buf = buffer; | ||
281 | |||
282 | port_addr = (volatile unsigned long *)PORT2ADDR(port); | ||
283 | |||
284 | while (count--) | ||
285 | *port_addr = *buf++; | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * map I/O ports to memory-mapped addresses | ||
290 | */ | ||
291 | unsigned long microdev_isa_port2addr(unsigned long offset) | ||
292 | { | ||
293 | unsigned long result; | ||
294 | |||
295 | if ((offset >= IO_LAN91C111_BASE) && | ||
296 | (offset < IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) { | ||
297 | /* | ||
298 | * SMSC LAN91C111 Ethernet chip | ||
299 | */ | ||
300 | result = IO_LAN91C111_PHYS + offset - IO_LAN91C111_BASE; | ||
301 | } else if ((offset >= IO_SUPERIO_BASE) && | ||
302 | (offset < IO_SUPERIO_BASE + IO_SUPERIO_EXTENT)) { | ||
303 | /* | ||
304 | * SMSC FDC37C93xAPM SuperIO chip | ||
305 | * | ||
306 | * Configuration Registers | ||
307 | */ | ||
308 | result = IO_SUPERIO_PHYS + (offset << 1); | ||
309 | #if 0 | ||
310 | } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG || | ||
311 | offset == KBD_STATUS_REG) { | ||
312 | /* | ||
313 | * SMSC FDC37C93xAPM SuperIO chip | ||
314 | * | ||
315 | * PS/2 Keyboard + Mouse (ports 0x60 and 0x64). | ||
316 | */ | ||
317 | result = IO_SUPERIO_PHYS + (offset << 1); | ||
318 | #endif | ||
319 | } else if (((offset >= IO_IDE1_BASE) && | ||
320 | (offset < IO_IDE1_BASE + IO_IDE_EXTENT)) || | ||
321 | (offset == IO_IDE1_MISC)) { | ||
322 | /* | ||
323 | * SMSC FDC37C93xAPM SuperIO chip | ||
324 | * | ||
325 | * IDE #1 | ||
326 | */ | ||
327 | result = IO_SUPERIO_PHYS + (offset << 1); | ||
328 | } else if (((offset >= IO_IDE2_BASE) && | ||
329 | (offset < IO_IDE2_BASE + IO_IDE_EXTENT)) || | ||
330 | (offset == IO_IDE2_MISC)) { | ||
331 | /* | ||
332 | * SMSC FDC37C93xAPM SuperIO chip | ||
333 | * | ||
334 | * IDE #2 | ||
335 | */ | ||
336 | result = IO_SUPERIO_PHYS + (offset << 1); | ||
337 | } else if ((offset >= IO_SERIAL1_BASE) && | ||
338 | (offset < IO_SERIAL1_BASE + IO_SERIAL_EXTENT)) { | ||
339 | /* | ||
340 | * SMSC FDC37C93xAPM SuperIO chip | ||
341 | * | ||
342 | * Serial #1 | ||
343 | */ | ||
344 | result = IO_SUPERIO_PHYS + (offset << 1); | ||
345 | } else if ((offset >= IO_SERIAL2_BASE) && | ||
346 | (offset < IO_SERIAL2_BASE + IO_SERIAL_EXTENT)) { | ||
347 | /* | ||
348 | * SMSC FDC37C93xAPM SuperIO chip | ||
349 | * | ||
350 | * Serial #2 | ||
351 | */ | ||
352 | result = IO_SUPERIO_PHYS + (offset << 1); | ||
353 | } else if ((offset >= IO_ISP1161_BASE) && | ||
354 | (offset < IO_ISP1161_BASE + IO_ISP1161_EXTENT)) { | ||
355 | /* | ||
356 | * Philips USB ISP1161x chip | ||
357 | */ | ||
358 | result = IO_ISP1161_PHYS + offset - IO_ISP1161_BASE; | ||
359 | } else { | ||
360 | /* | ||
361 | * safe default. | ||
362 | */ | ||
363 | printk("Warning: unexpected port in %s( offset = 0x%lx )\n", | ||
364 | __FUNCTION__, offset); | ||
365 | result = PVR; | ||
366 | } | ||
367 | |||
368 | return result; | ||
369 | } | ||
370 | |||
diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c new file mode 100644 index 000000000000..1298883eca4b --- /dev/null +++ b/arch/sh/boards/superh/microdev/irq.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/superh/microdev/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com) | ||
5 | * | ||
6 | * SuperH SH4-202 MicroDev board support. | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/irq.h> | ||
15 | |||
16 | #include <asm/system.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/mach/irq.h> | ||
19 | |||
20 | #define NUM_EXTERNAL_IRQS 16 /* IRL0 .. IRL15 */ | ||
21 | |||
22 | |||
23 | static const struct { | ||
24 | unsigned char fpgaIrq; | ||
25 | unsigned char mapped; | ||
26 | const char *name; | ||
27 | } fpgaIrqTable[NUM_EXTERNAL_IRQS] = { | ||
28 | { 0, 0, "unused" }, /* IRQ #0 IRL=15 0x200 */ | ||
29 | { MICRODEV_FPGA_IRQ_KEYBOARD, 1, "keyboard" }, /* IRQ #1 IRL=14 0x220 */ | ||
30 | { MICRODEV_FPGA_IRQ_SERIAL1, 1, "Serial #1"}, /* IRQ #2 IRL=13 0x240 */ | ||
31 | { MICRODEV_FPGA_IRQ_ETHERNET, 1, "Ethernet" }, /* IRQ #3 IRL=12 0x260 */ | ||
32 | { MICRODEV_FPGA_IRQ_SERIAL2, 0, "Serial #2"}, /* IRQ #4 IRL=11 0x280 */ | ||
33 | { 0, 0, "unused" }, /* IRQ #5 IRL=10 0x2a0 */ | ||
34 | { 0, 0, "unused" }, /* IRQ #6 IRL=9 0x2c0 */ | ||
35 | { MICRODEV_FPGA_IRQ_USB_HC, 1, "USB" }, /* IRQ #7 IRL=8 0x2e0 */ | ||
36 | { MICRODEV_IRQ_PCI_INTA, 1, "PCI INTA" }, /* IRQ #8 IRL=7 0x300 */ | ||
37 | { MICRODEV_IRQ_PCI_INTB, 1, "PCI INTB" }, /* IRQ #9 IRL=6 0x320 */ | ||
38 | { MICRODEV_IRQ_PCI_INTC, 1, "PCI INTC" }, /* IRQ #10 IRL=5 0x340 */ | ||
39 | { MICRODEV_IRQ_PCI_INTD, 1, "PCI INTD" }, /* IRQ #11 IRL=4 0x360 */ | ||
40 | { MICRODEV_FPGA_IRQ_MOUSE, 1, "mouse" }, /* IRQ #12 IRL=3 0x380 */ | ||
41 | { MICRODEV_FPGA_IRQ_IDE2, 1, "IDE #2" }, /* IRQ #13 IRL=2 0x3a0 */ | ||
42 | { MICRODEV_FPGA_IRQ_IDE1, 1, "IDE #1" }, /* IRQ #14 IRL=1 0x3c0 */ | ||
43 | { 0, 0, "unused" }, /* IRQ #15 IRL=0 0x3e0 */ | ||
44 | }; | ||
45 | |||
46 | #if (MICRODEV_LINUX_IRQ_KEYBOARD != 1) | ||
47 | # error Inconsistancy in defining the IRQ# for Keyboard! | ||
48 | #endif | ||
49 | |||
50 | #if (MICRODEV_LINUX_IRQ_ETHERNET != 3) | ||
51 | # error Inconsistancy in defining the IRQ# for Ethernet! | ||
52 | #endif | ||
53 | |||
54 | #if (MICRODEV_LINUX_IRQ_USB_HC != 7) | ||
55 | # error Inconsistancy in defining the IRQ# for USB! | ||
56 | #endif | ||
57 | |||
58 | #if (MICRODEV_LINUX_IRQ_MOUSE != 12) | ||
59 | # error Inconsistancy in defining the IRQ# for PS/2 Mouse! | ||
60 | #endif | ||
61 | |||
62 | #if (MICRODEV_LINUX_IRQ_IDE2 != 13) | ||
63 | # error Inconsistancy in defining the IRQ# for secondary IDE! | ||
64 | #endif | ||
65 | |||
66 | #if (MICRODEV_LINUX_IRQ_IDE1 != 14) | ||
67 | # error Inconsistancy in defining the IRQ# for primary IDE! | ||
68 | #endif | ||
69 | |||
70 | static void enable_microdev_irq(unsigned int irq); | ||
71 | static void disable_microdev_irq(unsigned int irq); | ||
72 | |||
73 | /* shutdown is same as "disable" */ | ||
74 | #define shutdown_microdev_irq disable_microdev_irq | ||
75 | |||
76 | static void mask_and_ack_microdev(unsigned int); | ||
77 | static void end_microdev_irq(unsigned int irq); | ||
78 | |||
79 | static unsigned int startup_microdev_irq(unsigned int irq) | ||
80 | { | ||
81 | enable_microdev_irq(irq); | ||
82 | return 0; /* never anything pending */ | ||
83 | } | ||
84 | |||
85 | static struct hw_interrupt_type microdev_irq_type = { | ||
86 | "MicroDev-IRQ", | ||
87 | startup_microdev_irq, | ||
88 | shutdown_microdev_irq, | ||
89 | enable_microdev_irq, | ||
90 | disable_microdev_irq, | ||
91 | mask_and_ack_microdev, | ||
92 | end_microdev_irq | ||
93 | }; | ||
94 | |||
95 | static void disable_microdev_irq(unsigned int irq) | ||
96 | { | ||
97 | unsigned int flags; | ||
98 | unsigned int fpgaIrq; | ||
99 | |||
100 | if (irq >= NUM_EXTERNAL_IRQS) return; | ||
101 | if (!fpgaIrqTable[irq].mapped) return; | ||
102 | |||
103 | fpgaIrq = fpgaIrqTable[irq].fpgaIrq; | ||
104 | |||
105 | /* disable interrupts */ | ||
106 | local_irq_save(flags); | ||
107 | |||
108 | /* disable interupts on the FPGA INTC register */ | ||
109 | ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG); | ||
110 | |||
111 | /* restore interrupts */ | ||
112 | local_irq_restore(flags); | ||
113 | } | ||
114 | |||
115 | static void enable_microdev_irq(unsigned int irq) | ||
116 | { | ||
117 | unsigned long priorityReg, priorities, pri; | ||
118 | unsigned int flags; | ||
119 | unsigned int fpgaIrq; | ||
120 | |||
121 | |||
122 | if (irq >= NUM_EXTERNAL_IRQS) return; | ||
123 | if (!fpgaIrqTable[irq].mapped) return; | ||
124 | |||
125 | pri = 15 - irq; | ||
126 | |||
127 | fpgaIrq = fpgaIrqTable[irq].fpgaIrq; | ||
128 | priorityReg = MICRODEV_FPGA_INTPRI_REG(fpgaIrq); | ||
129 | |||
130 | /* disable interrupts */ | ||
131 | local_irq_save(flags); | ||
132 | |||
133 | /* set priority for the interrupt */ | ||
134 | priorities = ctrl_inl(priorityReg); | ||
135 | priorities &= ~MICRODEV_FPGA_INTPRI_MASK(fpgaIrq); | ||
136 | priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri); | ||
137 | ctrl_outl(priorities, priorityReg); | ||
138 | |||
139 | /* enable interupts on the FPGA INTC register */ | ||
140 | ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG); | ||
141 | |||
142 | /* restore interrupts */ | ||
143 | local_irq_restore(flags); | ||
144 | } | ||
145 | |||
146 | /* This functions sets the desired irq handler to be a MicroDev type */ | ||
147 | static void __init make_microdev_irq(unsigned int irq) | ||
148 | { | ||
149 | disable_irq_nosync(irq); | ||
150 | irq_desc[irq].handler = µdev_irq_type; | ||
151 | disable_microdev_irq(irq); | ||
152 | } | ||
153 | |||
154 | static void mask_and_ack_microdev(unsigned int irq) | ||
155 | { | ||
156 | disable_microdev_irq(irq); | ||
157 | } | ||
158 | |||
159 | static void end_microdev_irq(unsigned int irq) | ||
160 | { | ||
161 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
162 | { | ||
163 | enable_microdev_irq(irq); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | extern void __init init_microdev_irq(void) | ||
168 | { | ||
169 | int i; | ||
170 | |||
171 | /* disable interupts on the FPGA INTC register */ | ||
172 | ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG); | ||
173 | |||
174 | for (i = 0; i < NUM_EXTERNAL_IRQS; i++) | ||
175 | { | ||
176 | make_microdev_irq(i); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | extern void microdev_print_fpga_intc_status(void) | ||
181 | { | ||
182 | volatile unsigned int * const intenb = (unsigned int*)MICRODEV_FPGA_INTENB_REG; | ||
183 | volatile unsigned int * const intdsb = (unsigned int*)MICRODEV_FPGA_INTDSB_REG; | ||
184 | volatile unsigned int * const intpria = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(0); | ||
185 | volatile unsigned int * const intprib = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(8); | ||
186 | volatile unsigned int * const intpric = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(16); | ||
187 | volatile unsigned int * const intprid = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(24); | ||
188 | volatile unsigned int * const intsrc = (unsigned int*)MICRODEV_FPGA_INTSRC_REG; | ||
189 | volatile unsigned int * const intreq = (unsigned int*)MICRODEV_FPGA_INTREQ_REG; | ||
190 | |||
191 | printk("-------------------------- microdev_print_fpga_intc_status() ------------------\n"); | ||
192 | printk("FPGA_INTENB = 0x%08x\n", *intenb); | ||
193 | printk("FPGA_INTDSB = 0x%08x\n", *intdsb); | ||
194 | printk("FPGA_INTSRC = 0x%08x\n", *intsrc); | ||
195 | printk("FPGA_INTREQ = 0x%08x\n", *intreq); | ||
196 | printk("FPGA_INTPRI[3..0] = %08x:%08x:%08x:%08x\n", *intprid, *intpric, *intprib, *intpria); | ||
197 | printk("-------------------------------------------------------------------------------\n"); | ||
198 | } | ||
199 | |||
200 | |||
diff --git a/arch/sh/boards/superh/microdev/led.c b/arch/sh/boards/superh/microdev/led.c new file mode 100644 index 000000000000..52a98e69d3f0 --- /dev/null +++ b/arch/sh/boards/superh/microdev/led.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/led_microdev.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com> | ||
5 | * Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com) | ||
6 | * | ||
7 | * May be copied or modified under the terms of the GNU General Public | ||
8 | * License. See linux/COPYING for more information. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/io.h> | ||
14 | |||
15 | #define LED_REGISTER 0xa6104d20 | ||
16 | |||
17 | static void mach_led_d9(int value) | ||
18 | { | ||
19 | unsigned long reg; | ||
20 | reg = ctrl_inl(LED_REGISTER); | ||
21 | reg &= ~1; | ||
22 | reg |= (value & 1); | ||
23 | ctrl_outl(reg, LED_REGISTER); | ||
24 | return; | ||
25 | } | ||
26 | |||
27 | static void mach_led_d10(int value) | ||
28 | { | ||
29 | unsigned long reg; | ||
30 | reg = ctrl_inl(LED_REGISTER); | ||
31 | reg &= ~2; | ||
32 | reg |= ((value & 1) << 1); | ||
33 | ctrl_outl(reg, LED_REGISTER); | ||
34 | return; | ||
35 | } | ||
36 | |||
37 | |||
38 | #ifdef CONFIG_HEARTBEAT | ||
39 | #include <linux/sched.h> | ||
40 | |||
41 | static unsigned char banner_table[] = { | ||
42 | 0x11, 0x01, 0x11, 0x01, 0x11, 0x03, | ||
43 | 0x11, 0x01, 0x11, 0x01, 0x13, 0x03, | ||
44 | 0x11, 0x01, 0x13, 0x01, 0x13, 0x01, 0x11, 0x03, | ||
45 | 0x11, 0x03, | ||
46 | 0x11, 0x01, 0x13, 0x01, 0x11, 0x03, | ||
47 | 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x07, | ||
48 | 0x13, 0x01, 0x13, 0x03, | ||
49 | 0x11, 0x01, 0x11, 0x03, | ||
50 | 0x13, 0x01, 0x11, 0x01, 0x13, 0x01, 0x11, 0x03, | ||
51 | 0x11, 0x01, 0x13, 0x01, 0x11, 0x03, | ||
52 | 0x13, 0x01, 0x13, 0x01, 0x13, 0x03, | ||
53 | 0x13, 0x01, 0x11, 0x01, 0x11, 0x03, | ||
54 | 0x11, 0x03, | ||
55 | 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x13, 0x07, | ||
56 | 0xff | ||
57 | }; | ||
58 | |||
59 | static void banner(void) | ||
60 | { | ||
61 | static int pos = 0; | ||
62 | static int count = 0; | ||
63 | |||
64 | if (count) { | ||
65 | count--; | ||
66 | } else { | ||
67 | int val = banner_table[pos]; | ||
68 | if (val == 0xff) { | ||
69 | pos = 0; | ||
70 | val = banner_table[pos]; | ||
71 | } | ||
72 | pos++; | ||
73 | mach_led_d10((val >> 4) & 1); | ||
74 | count = 10 * (val & 0xf); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* From heartbeat_harp in the stboards directory */ | ||
79 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
80 | void microdev_heartbeat(void) | ||
81 | { | ||
82 | static unsigned cnt = 0, period = 0, dist = 0; | ||
83 | |||
84 | if (cnt == 0 || cnt == dist) | ||
85 | mach_led_d9(1); | ||
86 | else if (cnt == 7 || cnt == dist+7) | ||
87 | mach_led_d9(0); | ||
88 | |||
89 | if (++cnt > period) { | ||
90 | cnt = 0; | ||
91 | /* The hyperbolic function below modifies the heartbeat period | ||
92 | * length in dependency of the current (5min) load. It goes | ||
93 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
94 | * f(inf)->30. */ | ||
95 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
96 | dist = period / 4; | ||
97 | } | ||
98 | |||
99 | banner(); | ||
100 | } | ||
101 | |||
102 | #endif | ||
diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c new file mode 100644 index 000000000000..c18919941ec0 --- /dev/null +++ b/arch/sh/boards/superh/microdev/setup.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/superh/microdev/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com) | ||
5 | * Copyright (C) 2003, 2004 SuperH, Inc. | ||
6 | * Copyright (C) 2004 Paul Mundt | ||
7 | * | ||
8 | * SuperH SH4-202 MicroDev board support. | ||
9 | * | ||
10 | * May be copied or modified under the terms of the GNU General Public | ||
11 | * License. See linux/COPYING for more information. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/mach/irq.h> | ||
20 | #include <asm/mach/io.h> | ||
21 | #include <asm/machvec.h> | ||
22 | #include <asm/machvec_init.h> | ||
23 | |||
24 | extern void microdev_heartbeat(void); | ||
25 | |||
26 | /* | ||
27 | * The Machine Vector | ||
28 | */ | ||
29 | |||
30 | struct sh_machine_vector mv_sh4202_microdev __initmv = { | ||
31 | .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */ | ||
32 | |||
33 | .mv_inb = microdev_inb, | ||
34 | .mv_inw = microdev_inw, | ||
35 | .mv_inl = microdev_inl, | ||
36 | .mv_outb = microdev_outb, | ||
37 | .mv_outw = microdev_outw, | ||
38 | .mv_outl = microdev_outl, | ||
39 | |||
40 | .mv_inb_p = microdev_inb_p, | ||
41 | .mv_inw_p = microdev_inw_p, | ||
42 | .mv_inl_p = microdev_inl_p, | ||
43 | .mv_outb_p = microdev_outb_p, | ||
44 | .mv_outw_p = microdev_outw_p, | ||
45 | .mv_outl_p = microdev_outl_p, | ||
46 | |||
47 | .mv_insb = microdev_insb, | ||
48 | .mv_insw = microdev_insw, | ||
49 | .mv_insl = microdev_insl, | ||
50 | .mv_outsb = microdev_outsb, | ||
51 | .mv_outsw = microdev_outsw, | ||
52 | .mv_outsl = microdev_outsl, | ||
53 | |||
54 | .mv_isa_port2addr = microdev_isa_port2addr, | ||
55 | |||
56 | .mv_init_irq = init_microdev_irq, | ||
57 | |||
58 | #ifdef CONFIG_HEARTBEAT | ||
59 | .mv_heartbeat = microdev_heartbeat, | ||
60 | #endif | ||
61 | }; | ||
62 | ALIAS_MV(sh4202_microdev) | ||
63 | |||
64 | /****************************************************************************/ | ||
65 | |||
66 | |||
67 | /* | ||
68 | * Setup for the SMSC FDC37C93xAPM | ||
69 | */ | ||
70 | #define SMSC_CONFIG_PORT_ADDR (0x3F0) | ||
71 | #define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR | ||
72 | #define SMSC_DATA_PORT_ADDR (SMSC_INDEX_PORT_ADDR + 1) | ||
73 | |||
74 | #define SMSC_ENTER_CONFIG_KEY 0x55 | ||
75 | #define SMSC_EXIT_CONFIG_KEY 0xaa | ||
76 | |||
77 | #define SMCS_LOGICAL_DEV_INDEX 0x07 /* Logical Device Number */ | ||
78 | #define SMSC_DEVICE_ID_INDEX 0x20 /* Device ID */ | ||
79 | #define SMSC_DEVICE_REV_INDEX 0x21 /* Device Revision */ | ||
80 | #define SMSC_ACTIVATE_INDEX 0x30 /* Activate */ | ||
81 | #define SMSC_PRIMARY_BASE_INDEX 0x60 /* Primary Base Address */ | ||
82 | #define SMSC_SECONDARY_BASE_INDEX 0x62 /* Secondary Base Address */ | ||
83 | #define SMSC_PRIMARY_INT_INDEX 0x70 /* Primary Interrupt Select */ | ||
84 | #define SMSC_SECONDARY_INT_INDEX 0x72 /* Secondary Interrupt Select */ | ||
85 | #define SMSC_HDCS0_INDEX 0xf0 /* HDCS0 Address Decoder */ | ||
86 | #define SMSC_HDCS1_INDEX 0xf1 /* HDCS1 Address Decoder */ | ||
87 | |||
88 | #define SMSC_IDE1_DEVICE 1 /* IDE #1 logical device */ | ||
89 | #define SMSC_IDE2_DEVICE 2 /* IDE #2 logical device */ | ||
90 | #define SMSC_PARALLEL_DEVICE 3 /* Parallel Port logical device */ | ||
91 | #define SMSC_SERIAL1_DEVICE 4 /* Serial #1 logical device */ | ||
92 | #define SMSC_SERIAL2_DEVICE 5 /* Serial #2 logical device */ | ||
93 | #define SMSC_KEYBOARD_DEVICE 7 /* Keyboard logical device */ | ||
94 | #define SMSC_CONFIG_REGISTERS 8 /* Configuration Registers (Aux I/O) */ | ||
95 | |||
96 | #define SMSC_READ_INDEXED(index) ({ \ | ||
97 | outb((index), SMSC_INDEX_PORT_ADDR); \ | ||
98 | inb(SMSC_DATA_PORT_ADDR); }) | ||
99 | #define SMSC_WRITE_INDEXED(val, index) ({ \ | ||
100 | outb((index), SMSC_INDEX_PORT_ADDR); \ | ||
101 | outb((val), SMSC_DATA_PORT_ADDR); }) | ||
102 | |||
103 | #define IDE1_PRIMARY_BASE 0x01f0 /* Task File Registe base for IDE #1 */ | ||
104 | #define IDE1_SECONDARY_BASE 0x03f6 /* Miscellaneous AT registers for IDE #1 */ | ||
105 | #define IDE2_PRIMARY_BASE 0x0170 /* Task File Registe base for IDE #2 */ | ||
106 | #define IDE2_SECONDARY_BASE 0x0376 /* Miscellaneous AT registers for IDE #2 */ | ||
107 | |||
108 | #define SERIAL1_PRIMARY_BASE 0x03f8 | ||
109 | #define SERIAL2_PRIMARY_BASE 0x02f8 | ||
110 | |||
111 | #define MSB(x) ( (x) >> 8 ) | ||
112 | #define LSB(x) ( (x) & 0xff ) | ||
113 | |||
114 | /* General-Purpose base address on CPU-board FPGA */ | ||
115 | #define MICRODEV_FPGA_GP_BASE 0xa6100000ul | ||
116 | |||
117 | /* assume a Keyboard Controller is present */ | ||
118 | int microdev_kbd_controller_present = 1; | ||
119 | |||
120 | const char *get_system_type(void) | ||
121 | { | ||
122 | return "SH4-202 MicroDev"; | ||
123 | } | ||
124 | |||
125 | static struct resource smc91x_resources[] = { | ||
126 | [0] = { | ||
127 | .start = 0x300, | ||
128 | .end = 0x300 + 0x0001000 - 1, | ||
129 | .flags = IORESOURCE_MEM, | ||
130 | }, | ||
131 | [1] = { | ||
132 | .start = MICRODEV_LINUX_IRQ_ETHERNET, | ||
133 | .end = MICRODEV_LINUX_IRQ_ETHERNET, | ||
134 | .flags = IORESOURCE_IRQ, | ||
135 | }, | ||
136 | }; | ||
137 | |||
138 | static struct platform_device smc91x_device = { | ||
139 | .name = "smc91x", | ||
140 | .id = -1, | ||
141 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
142 | .resource = smc91x_resources, | ||
143 | }; | ||
144 | |||
145 | static int __init smc91x_setup(void) | ||
146 | { | ||
147 | return platform_device_register(&smc91x_device); | ||
148 | } | ||
149 | |||
150 | __initcall(smc91x_setup); | ||
151 | |||
152 | /* | ||
153 | * Initialize the board | ||
154 | */ | ||
155 | void __init platform_setup(void) | ||
156 | { | ||
157 | int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul); | ||
158 | const int fpgaRevision = *fpgaRevisionRegister; | ||
159 | int * const CacheControlRegister = (int*)CCR; | ||
160 | |||
161 | printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n", | ||
162 | get_system_type(), fpgaRevision, *CacheControlRegister); | ||
163 | } | ||
164 | |||
165 | |||
166 | /****************************************************************************/ | ||
167 | |||
168 | |||
169 | /* | ||
170 | * Setup for the SMSC FDC37C93xAPM | ||
171 | */ | ||
172 | static int __init smsc_superio_setup(void) | ||
173 | { | ||
174 | |||
175 | unsigned char devid, devrev; | ||
176 | |||
177 | /* Initially the chip is in run state */ | ||
178 | /* Put it into configuration state */ | ||
179 | outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); | ||
180 | |||
181 | /* Read device ID info */ | ||
182 | devid = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX); | ||
183 | devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX); | ||
184 | if ( (devid==0x30) && (devrev==0x01) ) | ||
185 | { | ||
186 | printk("SMSC FDC37C93xAPM SuperIO device detected\n"); | ||
187 | } | ||
188 | else | ||
189 | { /* not the device identity we expected */ | ||
190 | printk("Not detected a SMSC FDC37C93xAPM SuperIO device (devid=0x%02x, rev=0x%02x)\n", | ||
191 | devid, devrev); | ||
192 | /* inform the keyboard driver that we have no keyboard controller */ | ||
193 | microdev_kbd_controller_present = 0; | ||
194 | /* little point in doing anything else in this functon */ | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* Select the keyboard device */ | ||
199 | SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX); | ||
200 | /* enable it */ | ||
201 | SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); | ||
202 | /* enable the interrupts */ | ||
203 | SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX); | ||
204 | SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX); | ||
205 | |||
206 | /* Select the Serial #1 device */ | ||
207 | SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX); | ||
208 | /* enable it */ | ||
209 | SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); | ||
210 | /* program with port addresses */ | ||
211 | SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); | ||
212 | SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); | ||
213 | SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX); | ||
214 | /* enable the interrupts */ | ||
215 | SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX); | ||
216 | |||
217 | /* Select the Serial #2 device */ | ||
218 | SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX); | ||
219 | /* enable it */ | ||
220 | SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); | ||
221 | /* program with port addresses */ | ||
222 | SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); | ||
223 | SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); | ||
224 | SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX); | ||
225 | /* enable the interrupts */ | ||
226 | SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX); | ||
227 | |||
228 | /* Select the IDE#1 device */ | ||
229 | SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX); | ||
230 | /* enable it */ | ||
231 | SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); | ||
232 | /* program with port addresses */ | ||
233 | SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); | ||
234 | SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); | ||
235 | SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0); | ||
236 | SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1); | ||
237 | SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX); | ||
238 | SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX); | ||
239 | /* select the interrupt */ | ||
240 | SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX); | ||
241 | |||
242 | /* Select the IDE#2 device */ | ||
243 | SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX); | ||
244 | /* enable it */ | ||
245 | SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); | ||
246 | /* program with port addresses */ | ||
247 | SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0); | ||
248 | SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1); | ||
249 | SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0); | ||
250 | SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1); | ||
251 | /* select the interrupt */ | ||
252 | SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX); | ||
253 | |||
254 | /* Select the configuration registers */ | ||
255 | SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX); | ||
256 | /* enable the appropriate GPIO pins for IDE functionality: | ||
257 | * bit[0] In/Out 1==input; 0==output | ||
258 | * bit[1] Polarity 1==invert; 0==no invert | ||
259 | * bit[2] Int Enb #1 1==Enable Combined IRQ #1; 0==disable | ||
260 | * bit[3:4] Function Select 00==original; 01==Alternate Function #1 | ||
261 | */ | ||
262 | SMSC_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */ | ||
263 | SMSC_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */ | ||
264 | SMSC_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */ | ||
265 | SMSC_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */ | ||
266 | SMSC_WRITE_INDEXED(0x08, 0xe8); /* GP20 = nIDE2_OE */ | ||
267 | |||
268 | /* Exit the configuraton state */ | ||
269 | outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | |||
275 | /* This is grotty, but, because kernel is always referenced on the link line | ||
276 | * before any devices, this is safe. | ||
277 | */ | ||
278 | __initcall(smsc_superio_setup); | ||
diff --git a/arch/sh/boards/unknown/Makefile b/arch/sh/boards/unknown/Makefile new file mode 100644 index 000000000000..cffc21031e71 --- /dev/null +++ b/arch/sh/boards/unknown/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for unknown SH boards | ||
3 | # | ||
4 | |||
5 | obj-y := mach.o io.o setup.o | ||
6 | |||
diff --git a/arch/sh/boards/unknown/io.c b/arch/sh/boards/unknown/io.c new file mode 100644 index 000000000000..8f3f17267bd9 --- /dev/null +++ b/arch/sh/boards/unknown/io.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/io_unknown.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * I/O routine for unknown hardware. | ||
10 | */ | ||
11 | |||
12 | static unsigned int unknown_handler(void) | ||
13 | { | ||
14 | return 0; | ||
15 | } | ||
16 | |||
17 | #define UNKNOWN_ALIAS(fn) \ | ||
18 | void unknown_##fn(void) __attribute__ ((alias ("unknown_handler"))); | ||
19 | |||
20 | UNKNOWN_ALIAS(inb) | ||
21 | UNKNOWN_ALIAS(inw) | ||
22 | UNKNOWN_ALIAS(inl) | ||
23 | UNKNOWN_ALIAS(outb) | ||
24 | UNKNOWN_ALIAS(outw) | ||
25 | UNKNOWN_ALIAS(outl) | ||
26 | UNKNOWN_ALIAS(inb_p) | ||
27 | UNKNOWN_ALIAS(inw_p) | ||
28 | UNKNOWN_ALIAS(inl_p) | ||
29 | UNKNOWN_ALIAS(outb_p) | ||
30 | UNKNOWN_ALIAS(outw_p) | ||
31 | UNKNOWN_ALIAS(outl_p) | ||
32 | UNKNOWN_ALIAS(insb) | ||
33 | UNKNOWN_ALIAS(insw) | ||
34 | UNKNOWN_ALIAS(insl) | ||
35 | UNKNOWN_ALIAS(outsb) | ||
36 | UNKNOWN_ALIAS(outsw) | ||
37 | UNKNOWN_ALIAS(outsl) | ||
38 | UNKNOWN_ALIAS(readb) | ||
39 | UNKNOWN_ALIAS(readw) | ||
40 | UNKNOWN_ALIAS(readl) | ||
41 | UNKNOWN_ALIAS(writeb) | ||
42 | UNKNOWN_ALIAS(writew) | ||
43 | UNKNOWN_ALIAS(writel) | ||
44 | UNKNOWN_ALIAS(isa_port2addr) | ||
45 | UNKNOWN_ALIAS(ioremap) | ||
46 | UNKNOWN_ALIAS(iounmap) | ||
diff --git a/arch/sh/boards/unknown/mach.c b/arch/sh/boards/unknown/mach.c new file mode 100644 index 000000000000..ad0bcc60a640 --- /dev/null +++ b/arch/sh/boards/unknown/mach.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/mach_unknown.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Machine specific code for an unknown machine (internal peripherials only) | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/machvec.h> | ||
16 | #include <asm/machvec_init.h> | ||
17 | |||
18 | #include <asm/io_unknown.h> | ||
19 | |||
20 | #include <asm/rtc.h> | ||
21 | /* | ||
22 | * The Machine Vector | ||
23 | */ | ||
24 | |||
25 | struct sh_machine_vector mv_unknown __initmv = { | ||
26 | #if defined(CONFIG_CPU_SH4) | ||
27 | .mv_nr_irqs = 48, | ||
28 | #elif defined(CONFIG_CPU_SUBTYPE_SH7708) | ||
29 | .mv_nr_irqs = 32, | ||
30 | #elif defined(CONFIG_CPU_SUBTYPE_SH7709) | ||
31 | .mv_nr_irqs = 61, | ||
32 | #endif | ||
33 | |||
34 | .mv_inb = unknown_inb, | ||
35 | .mv_inw = unknown_inw, | ||
36 | .mv_inl = unknown_inl, | ||
37 | .mv_outb = unknown_outb, | ||
38 | .mv_outw = unknown_outw, | ||
39 | .mv_outl = unknown_outl, | ||
40 | |||
41 | .mv_inb_p = unknown_inb_p, | ||
42 | .mv_inw_p = unknown_inw_p, | ||
43 | .mv_inl_p = unknown_inl_p, | ||
44 | .mv_outb_p = unknown_outb_p, | ||
45 | .mv_outw_p = unknown_outw_p, | ||
46 | .mv_outl_p = unknown_outl_p, | ||
47 | |||
48 | .mv_insb = unknown_insb, | ||
49 | .mv_insw = unknown_insw, | ||
50 | .mv_insl = unknown_insl, | ||
51 | .mv_outsb = unknown_outsb, | ||
52 | .mv_outsw = unknown_outsw, | ||
53 | .mv_outsl = unknown_outsl, | ||
54 | |||
55 | .mv_readb = unknown_readb, | ||
56 | .mv_readw = unknown_readw, | ||
57 | .mv_readl = unknown_readl, | ||
58 | .mv_writeb = unknown_writeb, | ||
59 | .mv_writew = unknown_writew, | ||
60 | .mv_writel = unknown_writel, | ||
61 | |||
62 | .mv_ioremap = unknown_ioremap, | ||
63 | .mv_iounmap = unknown_iounmap, | ||
64 | |||
65 | .mv_isa_port2addr = unknown_isa_port2addr, | ||
66 | }; | ||
67 | ALIAS_MV(unknown) | ||
diff --git a/arch/sh/boards/unknown/setup.c b/arch/sh/boards/unknown/setup.c new file mode 100644 index 000000000000..7d772a6f8865 --- /dev/null +++ b/arch/sh/boards/unknown/setup.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/boards/unknown/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Paul Mundt | ||
5 | * | ||
6 | * May be copied or modified under the terms of the GNU General Public | ||
7 | * License. See linux/COPYING for more information. | ||
8 | * | ||
9 | * Setup code for an unknown machine (internal peripherials only) | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | const char *get_system_type(void) | ||
16 | { | ||
17 | return "Unknown"; | ||
18 | } | ||
19 | |||
20 | void __init platform_setup(void) | ||
21 | { | ||
22 | } | ||
23 | |||