diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2010-08-05 08:25:56 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-08-05 08:25:56 -0400 |
commit | 79d7cd31f9a3d3e75ae67f742aa5eb199cfa71cf (patch) | |
tree | cce7cbd31518851116a0f2a01f9fc3d1dfa1419e /arch/mips/pnx8550 | |
parent | 86c6d4d0acc64543a485c11e197d0bd2c5ae0bb2 (diff) |
MIPS: PNX8550: Move code one directory level up.
It was sharing the nxp directory but no code with pnx833x and will fit
better into the new platform makefile scheme, if moved. Also after the
pnx833x code has been moved up, the pnx8550 Code was the last users of
the nxp dir.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pnx8550')
-rw-r--r-- | arch/mips/pnx8550/common/Makefile | 28 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/int.c | 236 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/pci.c | 134 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/platform.c | 133 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/proc.c | 110 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/prom.c | 128 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/reset.c | 50 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/setup.c | 145 | ||||
-rw-r--r-- | arch/mips/pnx8550/common/time.c | 151 | ||||
-rw-r--r-- | arch/mips/pnx8550/jbs/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/pnx8550/jbs/board_setup.c | 56 | ||||
-rw-r--r-- | arch/mips/pnx8550/jbs/init.c | 53 | ||||
-rw-r--r-- | arch/mips/pnx8550/jbs/irqmap.c | 35 | ||||
-rw-r--r-- | arch/mips/pnx8550/stb810/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/pnx8550/stb810/board_setup.c | 41 | ||||
-rw-r--r-- | arch/mips/pnx8550/stb810/irqmap.c | 22 | ||||
-rw-r--r-- | arch/mips/pnx8550/stb810/prom_init.c | 46 |
17 files changed, 1376 insertions, 0 deletions
diff --git a/arch/mips/pnx8550/common/Makefile b/arch/mips/pnx8550/common/Makefile new file mode 100644 index 000000000000..dd9e7b1f7fd3 --- /dev/null +++ b/arch/mips/pnx8550/common/Makefile | |||
@@ -0,0 +1,28 @@ | |||
1 | # | ||
2 | # Per Hallsmark, per.hallsmark@mvista.com | ||
3 | # | ||
4 | # ######################################################################## | ||
5 | # | ||
6 | # This program is free software; you can distribute it and/or modify it | ||
7 | # under the terms of the GNU General Public License (Version 2) as | ||
8 | # published by the Free Software Foundation. | ||
9 | # | ||
10 | # This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
13 | # for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License along | ||
16 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
18 | # | ||
19 | # ####################################################################### | ||
20 | # | ||
21 | # Makefile for the PNX8550 specific kernel interface routines | ||
22 | # under Linux. | ||
23 | # | ||
24 | |||
25 | obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o | ||
26 | obj-$(CONFIG_PCI) += pci.o | ||
27 | |||
28 | EXTRA_CFLAGS += -Werror | ||
diff --git a/arch/mips/pnx8550/common/int.c b/arch/mips/pnx8550/common/int.c new file mode 100644 index 000000000000..cfed5051dc6d --- /dev/null +++ b/arch/mips/pnx8550/common/int.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2005 Embedded Alley Solutions, Inc | ||
4 | * Ported to 2.6. | ||
5 | * | ||
6 | * Per Hallsmark, per.hallsmark@mvista.com | ||
7 | * Copyright (C) 2000, 2001 MIPS Technologies, Inc. | ||
8 | * Copyright (C) 2001 Ralf Baechle | ||
9 | * | ||
10 | * Cleaned up and bug fixing: Pete Popov, ppopov@embeddedalley.com | ||
11 | * | ||
12 | * This program is free software; you can distribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License (Version 2) as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
19 | * for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License along | ||
22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
23 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
24 | * | ||
25 | */ | ||
26 | #include <linux/compiler.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/random.h> | ||
33 | #include <linux/module.h> | ||
34 | |||
35 | #include <asm/io.h> | ||
36 | #include <int.h> | ||
37 | #include <uart.h> | ||
38 | |||
39 | /* default prio for interrupts */ | ||
40 | /* first one is a no-no so therefore always prio 0 (disabled) */ | ||
41 | static char gic_prio[PNX8550_INT_GIC_TOTINT] = { | ||
42 | 0, 1, 1, 1, 1, 15, 1, 1, 1, 1, // 0 - 9 | ||
43 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 - 19 | ||
44 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20 - 29 | ||
45 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30 - 39 | ||
46 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 - 49 | ||
47 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 50 - 59 | ||
48 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 - 69 | ||
49 | 1 // 70 | ||
50 | }; | ||
51 | |||
52 | static void hw0_irqdispatch(int irq) | ||
53 | { | ||
54 | /* find out which interrupt */ | ||
55 | irq = PNX8550_GIC_VECTOR_0 >> 3; | ||
56 | |||
57 | if (irq == 0) { | ||
58 | printk("hw0_irqdispatch: irq 0, spurious interrupt?\n"); | ||
59 | return; | ||
60 | } | ||
61 | do_IRQ(PNX8550_INT_GIC_MIN + irq); | ||
62 | } | ||
63 | |||
64 | |||
65 | static void timer_irqdispatch(int irq) | ||
66 | { | ||
67 | irq = (0x01c0 & read_c0_config7()) >> 6; | ||
68 | |||
69 | if (unlikely(irq == 0)) { | ||
70 | printk("timer_irqdispatch: irq 0, spurious interrupt?\n"); | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | if (irq & 0x1) | ||
75 | do_IRQ(PNX8550_INT_TIMER1); | ||
76 | if (irq & 0x2) | ||
77 | do_IRQ(PNX8550_INT_TIMER2); | ||
78 | if (irq & 0x4) | ||
79 | do_IRQ(PNX8550_INT_TIMER3); | ||
80 | } | ||
81 | |||
82 | asmlinkage void plat_irq_dispatch(void) | ||
83 | { | ||
84 | unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; | ||
85 | |||
86 | if (pending & STATUSF_IP2) | ||
87 | hw0_irqdispatch(2); | ||
88 | else if (pending & STATUSF_IP7) { | ||
89 | if (read_c0_config7() & 0x01c0) | ||
90 | timer_irqdispatch(7); | ||
91 | } else | ||
92 | spurious_interrupt(); | ||
93 | } | ||
94 | |||
95 | static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) | ||
96 | { | ||
97 | unsigned long status = read_c0_status(); | ||
98 | |||
99 | status &= ~((clr_mask & 0xFF) << 8); | ||
100 | status |= (set_mask & 0xFF) << 8; | ||
101 | |||
102 | write_c0_status(status); | ||
103 | } | ||
104 | |||
105 | static inline void mask_gic_int(unsigned int irq_nr) | ||
106 | { | ||
107 | /* interrupt disabled, bit 26(WE_ENABLE)=1 and bit 16(enable)=0 */ | ||
108 | PNX8550_GIC_REQ(irq_nr) = 1<<28; /* set priority to 0 */ | ||
109 | } | ||
110 | |||
111 | static inline void unmask_gic_int(unsigned int irq_nr) | ||
112 | { | ||
113 | /* set prio mask to lower four bits and enable interrupt */ | ||
114 | PNX8550_GIC_REQ(irq_nr) = (1<<26 | 1<<16) | (1<<28) | gic_prio[irq_nr]; | ||
115 | } | ||
116 | |||
117 | static inline void mask_irq(unsigned int irq_nr) | ||
118 | { | ||
119 | if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) { | ||
120 | modify_cp0_intmask(1 << irq_nr, 0); | ||
121 | } else if ((PNX8550_INT_GIC_MIN <= irq_nr) && | ||
122 | (irq_nr <= PNX8550_INT_GIC_MAX)) { | ||
123 | mask_gic_int(irq_nr - PNX8550_INT_GIC_MIN); | ||
124 | } else if ((PNX8550_INT_TIMER_MIN <= irq_nr) && | ||
125 | (irq_nr <= PNX8550_INT_TIMER_MAX)) { | ||
126 | modify_cp0_intmask(1 << 7, 0); | ||
127 | } else { | ||
128 | printk("mask_irq: irq %d doesn't exist!\n", irq_nr); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | static inline void unmask_irq(unsigned int irq_nr) | ||
133 | { | ||
134 | if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) { | ||
135 | modify_cp0_intmask(0, 1 << irq_nr); | ||
136 | } else if ((PNX8550_INT_GIC_MIN <= irq_nr) && | ||
137 | (irq_nr <= PNX8550_INT_GIC_MAX)) { | ||
138 | unmask_gic_int(irq_nr - PNX8550_INT_GIC_MIN); | ||
139 | } else if ((PNX8550_INT_TIMER_MIN <= irq_nr) && | ||
140 | (irq_nr <= PNX8550_INT_TIMER_MAX)) { | ||
141 | modify_cp0_intmask(0, 1 << 7); | ||
142 | } else { | ||
143 | printk("mask_irq: irq %d doesn't exist!\n", irq_nr); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | int pnx8550_set_gic_priority(int irq, int priority) | ||
148 | { | ||
149 | int gic_irq = irq-PNX8550_INT_GIC_MIN; | ||
150 | int prev_priority = PNX8550_GIC_REQ(gic_irq) & 0xf; | ||
151 | |||
152 | gic_prio[gic_irq] = priority; | ||
153 | PNX8550_GIC_REQ(gic_irq) |= (0x10000000 | gic_prio[gic_irq]); | ||
154 | |||
155 | return prev_priority; | ||
156 | } | ||
157 | |||
158 | static struct irq_chip level_irq_type = { | ||
159 | .name = "PNX Level IRQ", | ||
160 | .ack = mask_irq, | ||
161 | .mask = mask_irq, | ||
162 | .mask_ack = mask_irq, | ||
163 | .unmask = unmask_irq, | ||
164 | }; | ||
165 | |||
166 | static struct irqaction gic_action = { | ||
167 | .handler = no_action, | ||
168 | .flags = IRQF_DISABLED, | ||
169 | .name = "GIC", | ||
170 | }; | ||
171 | |||
172 | static struct irqaction timer_action = { | ||
173 | .handler = no_action, | ||
174 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
175 | .name = "Timer", | ||
176 | }; | ||
177 | |||
178 | void __init arch_init_irq(void) | ||
179 | { | ||
180 | int i; | ||
181 | int configPR; | ||
182 | |||
183 | for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) { | ||
184 | set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq); | ||
185 | mask_irq(i); /* mask the irq just in case */ | ||
186 | } | ||
187 | |||
188 | /* init of GIC/IPC interrupts */ | ||
189 | /* should be done before cp0 since cp0 init enables the GIC int */ | ||
190 | for (i = PNX8550_INT_GIC_MIN; i <= PNX8550_INT_GIC_MAX; i++) { | ||
191 | int gic_int_line = i - PNX8550_INT_GIC_MIN; | ||
192 | if (gic_int_line == 0 ) | ||
193 | continue; // don't fiddle with int 0 | ||
194 | /* | ||
195 | * enable change of TARGET, ENABLE and ACTIVE_LOW bits | ||
196 | * set TARGET 0 to route through hw0 interrupt | ||
197 | * set ACTIVE_LOW 0 active high (correct?) | ||
198 | * | ||
199 | * We really should setup an interrupt description table | ||
200 | * to do this nicely. | ||
201 | * Note, PCI INTA is active low on the bus, but inverted | ||
202 | * in the GIC, so to us it's active high. | ||
203 | */ | ||
204 | PNX8550_GIC_REQ(i - PNX8550_INT_GIC_MIN) = 0x1E000000; | ||
205 | |||
206 | /* mask/priority is still 0 so we will not get any | ||
207 | * interrupts until it is unmasked */ | ||
208 | |||
209 | set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq); | ||
210 | } | ||
211 | |||
212 | /* Priority level 0 */ | ||
213 | PNX8550_GIC_PRIMASK_0 = PNX8550_GIC_PRIMASK_1 = 0; | ||
214 | |||
215 | /* Set int vector table address */ | ||
216 | PNX8550_GIC_VECTOR_0 = PNX8550_GIC_VECTOR_1 = 0; | ||
217 | |||
218 | set_irq_chip_and_handler(MIPS_CPU_GIC_IRQ, &level_irq_type, | ||
219 | handle_level_irq); | ||
220 | setup_irq(MIPS_CPU_GIC_IRQ, &gic_action); | ||
221 | |||
222 | /* init of Timer interrupts */ | ||
223 | for (i = PNX8550_INT_TIMER_MIN; i <= PNX8550_INT_TIMER_MAX; i++) | ||
224 | set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq); | ||
225 | |||
226 | /* Stop Timer 1-3 */ | ||
227 | configPR = read_c0_config7(); | ||
228 | configPR |= 0x00000038; | ||
229 | write_c0_config7(configPR); | ||
230 | |||
231 | set_irq_chip_and_handler(MIPS_CPU_TIMER_IRQ, &level_irq_type, | ||
232 | handle_level_irq); | ||
233 | setup_irq(MIPS_CPU_TIMER_IRQ, &timer_action); | ||
234 | } | ||
235 | |||
236 | EXPORT_SYMBOL(pnx8550_set_gic_priority); | ||
diff --git a/arch/mips/pnx8550/common/pci.c b/arch/mips/pnx8550/common/pci.c new file mode 100644 index 000000000000..98e86ddb86cc --- /dev/null +++ b/arch/mips/pnx8550/common/pci.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * | ||
5 | * Author: source@mvista.com | ||
6 | * | ||
7 | * This program is free software; you can distribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License (Version 2) as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
14 | * for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
19 | */ | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | |||
25 | #include <pci.h> | ||
26 | #include <glb.h> | ||
27 | #include <nand.h> | ||
28 | |||
29 | static struct resource pci_io_resource = { | ||
30 | .start = PNX8550_PCIIO + 0x1000, /* reserve regacy I/O space */ | ||
31 | .end = PNX8550_PCIIO + PNX8550_PCIIO_SIZE, | ||
32 | .name = "pci IO space", | ||
33 | .flags = IORESOURCE_IO | ||
34 | }; | ||
35 | |||
36 | static struct resource pci_mem_resource = { | ||
37 | .start = PNX8550_PCIMEM, | ||
38 | .end = PNX8550_PCIMEM + PNX8550_PCIMEM_SIZE - 1, | ||
39 | .name = "pci memory space", | ||
40 | .flags = IORESOURCE_MEM | ||
41 | }; | ||
42 | |||
43 | extern struct pci_ops pnx8550_pci_ops; | ||
44 | |||
45 | static struct pci_controller pnx8550_controller = { | ||
46 | .pci_ops = &pnx8550_pci_ops, | ||
47 | .io_map_base = PNX8550_PORT_BASE, | ||
48 | .io_resource = &pci_io_resource, | ||
49 | .mem_resource = &pci_mem_resource, | ||
50 | }; | ||
51 | |||
52 | /* Return the total size of DRAM-memory, (RANK0 + RANK1) */ | ||
53 | static inline unsigned long get_system_mem_size(void) | ||
54 | { | ||
55 | /* Read IP2031_RANK0_ADDR_LO */ | ||
56 | unsigned long dram_r0_lo = inl(PCI_BASE | 0x65010); | ||
57 | /* Read IP2031_RANK1_ADDR_HI */ | ||
58 | unsigned long dram_r1_hi = inl(PCI_BASE | 0x65018); | ||
59 | |||
60 | return dram_r1_hi - dram_r0_lo + 1; | ||
61 | } | ||
62 | |||
63 | static int __init pnx8550_pci_setup(void) | ||
64 | { | ||
65 | int pci_mem_code; | ||
66 | int mem_size = get_system_mem_size() >> 20; | ||
67 | |||
68 | /* Clear the Global 2 Register, PCI Inta Output Enable Registers | ||
69 | Bit 1:Enable DAC Powerdown | ||
70 | -> 0:DACs are enabled and are working normally | ||
71 | 1:DACs are powerdown | ||
72 | Bit 0:Enable of PCI inta output | ||
73 | -> 0 = Disable PCI inta output | ||
74 | 1 = Enable PCI inta output | ||
75 | */ | ||
76 | PNX8550_GLB2_ENAB_INTA_O = 0; | ||
77 | |||
78 | /* Calc the PCI mem size code */ | ||
79 | if (mem_size >= 128) | ||
80 | pci_mem_code = SIZE_128M; | ||
81 | else if (mem_size >= 64) | ||
82 | pci_mem_code = SIZE_64M; | ||
83 | else if (mem_size >= 32) | ||
84 | pci_mem_code = SIZE_32M; | ||
85 | else | ||
86 | pci_mem_code = SIZE_16M; | ||
87 | |||
88 | /* Set PCI_XIO registers */ | ||
89 | outl(pci_mem_resource.start, PCI_BASE | PCI_BASE1_LO); | ||
90 | outl(pci_mem_resource.end + 1, PCI_BASE | PCI_BASE1_HI); | ||
91 | outl(pci_io_resource.start, PCI_BASE | PCI_BASE2_LO); | ||
92 | outl(pci_io_resource.end, PCI_BASE | PCI_BASE2_HI); | ||
93 | |||
94 | /* Send memory transaction via PCI_BASE2 */ | ||
95 | outl(0x00000001, PCI_BASE | PCI_IO); | ||
96 | |||
97 | /* Unlock the setup register */ | ||
98 | outl(0xca, PCI_BASE | PCI_UNLOCKREG); | ||
99 | |||
100 | /* | ||
101 | * BAR0 of PNX8550 (pci base 10) must be zero in order for ide | ||
102 | * to work, and in order for bus_to_baddr to work without any | ||
103 | * hacks. | ||
104 | */ | ||
105 | outl(0x00000000, PCI_BASE | PCI_BASE10); | ||
106 | |||
107 | /* | ||
108 | *These two bars are set by default or the boot code. | ||
109 | * However, it's safer to set them here so we're not boot | ||
110 | * code dependent. | ||
111 | */ | ||
112 | outl(0x1be00000, PCI_BASE | PCI_BASE14); /* PNX MMIO */ | ||
113 | outl(PNX8550_NAND_BASE_ADDR, PCI_BASE | PCI_BASE18); /* XIO */ | ||
114 | |||
115 | outl(PCI_EN_TA | | ||
116 | PCI_EN_PCI2MMI | | ||
117 | PCI_EN_XIO | | ||
118 | PCI_SETUP_BASE18_SIZE(SIZE_32M) | | ||
119 | PCI_SETUP_BASE18_EN | | ||
120 | PCI_SETUP_BASE14_EN | | ||
121 | PCI_SETUP_BASE10_PREF | | ||
122 | PCI_SETUP_BASE10_SIZE(pci_mem_code) | | ||
123 | PCI_SETUP_CFGMANAGE_EN | | ||
124 | PCI_SETUP_PCIARB_EN, | ||
125 | PCI_BASE | | ||
126 | PCI_SETUP); /* PCI_SETUP */ | ||
127 | outl(0x00000000, PCI_BASE | PCI_CTRL); /* PCI_CONTROL */ | ||
128 | |||
129 | register_pci_controller(&pnx8550_controller); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | arch_initcall(pnx8550_pci_setup); | ||
diff --git a/arch/mips/pnx8550/common/platform.c b/arch/mips/pnx8550/common/platform.c new file mode 100644 index 000000000000..5264cc09a27b --- /dev/null +++ b/arch/mips/pnx8550/common/platform.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * Platform device support for NXP PNX8550 SoCs | ||
3 | * | ||
4 | * Copyright 2005, Embedded Alley Solutions, Inc | ||
5 | * | ||
6 | * Based on arch/mips/au1000/common/platform.c | ||
7 | * Platform device support for Au1x00 SoCs. | ||
8 | * | ||
9 | * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public | ||
12 | * License version 2. This program is licensed "as is" without any | ||
13 | * warranty of any kind, whether express or implied. | ||
14 | */ | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/resource.h> | ||
20 | #include <linux/serial.h> | ||
21 | #include <linux/serial_pnx8xxx.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | |||
24 | #include <int.h> | ||
25 | #include <usb.h> | ||
26 | #include <uart.h> | ||
27 | |||
28 | static struct resource pnx8550_usb_ohci_resources[] = { | ||
29 | [0] = { | ||
30 | .start = PNX8550_USB_OHCI_OP_BASE, | ||
31 | .end = PNX8550_USB_OHCI_OP_BASE + | ||
32 | PNX8550_USB_OHCI_OP_LEN, | ||
33 | .flags = IORESOURCE_MEM, | ||
34 | }, | ||
35 | [1] = { | ||
36 | .start = PNX8550_INT_USB, | ||
37 | .end = PNX8550_INT_USB, | ||
38 | .flags = IORESOURCE_IRQ, | ||
39 | }, | ||
40 | }; | ||
41 | |||
42 | static struct resource pnx8550_uart_resources[] = { | ||
43 | [0] = { | ||
44 | .start = PNX8550_UART_PORT0, | ||
45 | .end = PNX8550_UART_PORT0 + 0xfff, | ||
46 | .flags = IORESOURCE_MEM, | ||
47 | }, | ||
48 | [1] = { | ||
49 | .start = PNX8550_UART_INT(0), | ||
50 | .end = PNX8550_UART_INT(0), | ||
51 | .flags = IORESOURCE_IRQ, | ||
52 | }, | ||
53 | [2] = { | ||
54 | .start = PNX8550_UART_PORT1, | ||
55 | .end = PNX8550_UART_PORT1 + 0xfff, | ||
56 | .flags = IORESOURCE_MEM, | ||
57 | }, | ||
58 | [3] = { | ||
59 | .start = PNX8550_UART_INT(1), | ||
60 | .end = PNX8550_UART_INT(1), | ||
61 | .flags = IORESOURCE_IRQ, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | struct pnx8xxx_port pnx8xxx_ports[] = { | ||
66 | [0] = { | ||
67 | .port = { | ||
68 | .type = PORT_PNX8XXX, | ||
69 | .iotype = UPIO_MEM, | ||
70 | .membase = (void __iomem *)PNX8550_UART_PORT0, | ||
71 | .mapbase = PNX8550_UART_PORT0, | ||
72 | .irq = PNX8550_UART_INT(0), | ||
73 | .uartclk = 3692300, | ||
74 | .fifosize = 16, | ||
75 | .flags = UPF_BOOT_AUTOCONF, | ||
76 | .line = 0, | ||
77 | }, | ||
78 | }, | ||
79 | [1] = { | ||
80 | .port = { | ||
81 | .type = PORT_PNX8XXX, | ||
82 | .iotype = UPIO_MEM, | ||
83 | .membase = (void __iomem *)PNX8550_UART_PORT1, | ||
84 | .mapbase = PNX8550_UART_PORT1, | ||
85 | .irq = PNX8550_UART_INT(1), | ||
86 | .uartclk = 3692300, | ||
87 | .fifosize = 16, | ||
88 | .flags = UPF_BOOT_AUTOCONF, | ||
89 | .line = 1, | ||
90 | }, | ||
91 | }, | ||
92 | }; | ||
93 | |||
94 | /* The dmamask must be set for OHCI to work */ | ||
95 | static u64 ohci_dmamask = DMA_BIT_MASK(32); | ||
96 | |||
97 | static u64 uart_dmamask = DMA_BIT_MASK(32); | ||
98 | |||
99 | static struct platform_device pnx8550_usb_ohci_device = { | ||
100 | .name = "pnx8550-ohci", | ||
101 | .id = -1, | ||
102 | .dev = { | ||
103 | .dma_mask = &ohci_dmamask, | ||
104 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
105 | }, | ||
106 | .num_resources = ARRAY_SIZE(pnx8550_usb_ohci_resources), | ||
107 | .resource = pnx8550_usb_ohci_resources, | ||
108 | }; | ||
109 | |||
110 | static struct platform_device pnx8550_uart_device = { | ||
111 | .name = "pnx8xxx-uart", | ||
112 | .id = -1, | ||
113 | .dev = { | ||
114 | .dma_mask = &uart_dmamask, | ||
115 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
116 | .platform_data = pnx8xxx_ports, | ||
117 | }, | ||
118 | .num_resources = ARRAY_SIZE(pnx8550_uart_resources), | ||
119 | .resource = pnx8550_uart_resources, | ||
120 | }; | ||
121 | |||
122 | static struct platform_device *pnx8550_platform_devices[] __initdata = { | ||
123 | &pnx8550_usb_ohci_device, | ||
124 | &pnx8550_uart_device, | ||
125 | }; | ||
126 | |||
127 | static int __init pnx8550_platform_init(void) | ||
128 | { | ||
129 | return platform_add_devices(pnx8550_platform_devices, | ||
130 | ARRAY_SIZE(pnx8550_platform_devices)); | ||
131 | } | ||
132 | |||
133 | arch_initcall(pnx8550_platform_init); | ||
diff --git a/arch/mips/pnx8550/common/proc.c b/arch/mips/pnx8550/common/proc.c new file mode 100644 index 000000000000..3bba5ec828e8 --- /dev/null +++ b/arch/mips/pnx8550/common/proc.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * This program is free software; you can distribute it and/or modify it | ||
3 | * under the terms of the GNU General Public License (Version 2) as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
7 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
8 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
9 | * for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License along | ||
12 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
13 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel_stat.h> | ||
21 | #include <linux/random.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <int.h> | ||
25 | #include <uart.h> | ||
26 | |||
27 | |||
28 | static int pnx8550_timers_read(char* page, char** start, off_t offset, int count, int* eof, void* data) | ||
29 | { | ||
30 | int len = 0; | ||
31 | int configPR = read_c0_config7(); | ||
32 | |||
33 | if (offset==0) { | ||
34 | len += sprintf(&page[len], "Timer: count, compare, tc, status\n"); | ||
35 | len += sprintf(&page[len], " 1: %11i, %8i, %1i, %s\n", | ||
36 | read_c0_count(), read_c0_compare(), | ||
37 | (configPR>>6)&0x1, ((configPR>>3)&0x1)? "off":"on"); | ||
38 | len += sprintf(&page[len], " 2: %11i, %8i, %1i, %s\n", | ||
39 | read_c0_count2(), read_c0_compare2(), | ||
40 | (configPR>>7)&0x1, ((configPR>>4)&0x1)? "off":"on"); | ||
41 | len += sprintf(&page[len], " 3: %11i, %8i, %1i, %s\n", | ||
42 | read_c0_count3(), read_c0_compare3(), | ||
43 | (configPR>>8)&0x1, ((configPR>>5)&0x1)? "off":"on"); | ||
44 | } | ||
45 | |||
46 | return len; | ||
47 | } | ||
48 | |||
49 | static int pnx8550_registers_read(char* page, char** start, off_t offset, int count, int* eof, void* data) | ||
50 | { | ||
51 | int len = 0; | ||
52 | |||
53 | if (offset==0) { | ||
54 | len += sprintf(&page[len], "config1: %#10.8x\n", read_c0_config1()); | ||
55 | len += sprintf(&page[len], "config2: %#10.8x\n", read_c0_config2()); | ||
56 | len += sprintf(&page[len], "config3: %#10.8x\n", read_c0_config3()); | ||
57 | len += sprintf(&page[len], "configPR: %#10.8x\n", read_c0_config7()); | ||
58 | len += sprintf(&page[len], "status: %#10.8x\n", read_c0_status()); | ||
59 | len += sprintf(&page[len], "cause: %#10.8x\n", read_c0_cause()); | ||
60 | len += sprintf(&page[len], "count: %#10.8x\n", read_c0_count()); | ||
61 | len += sprintf(&page[len], "count_2: %#10.8x\n", read_c0_count2()); | ||
62 | len += sprintf(&page[len], "count_3: %#10.8x\n", read_c0_count3()); | ||
63 | len += sprintf(&page[len], "compare: %#10.8x\n", read_c0_compare()); | ||
64 | len += sprintf(&page[len], "compare_2: %#10.8x\n", read_c0_compare2()); | ||
65 | len += sprintf(&page[len], "compare_3: %#10.8x\n", read_c0_compare3()); | ||
66 | } | ||
67 | |||
68 | return len; | ||
69 | } | ||
70 | |||
71 | static struct proc_dir_entry* pnx8550_dir; | ||
72 | static struct proc_dir_entry* pnx8550_timers; | ||
73 | static struct proc_dir_entry* pnx8550_registers; | ||
74 | |||
75 | static int pnx8550_proc_init( void ) | ||
76 | { | ||
77 | |||
78 | // Create /proc/pnx8550 | ||
79 | pnx8550_dir = proc_mkdir("pnx8550", NULL); | ||
80 | if (!pnx8550_dir) { | ||
81 | printk(KERN_ERR "Can't create pnx8550 proc dir\n"); | ||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | // Create /proc/pnx8550/timers | ||
86 | pnx8550_timers = create_proc_read_entry( | ||
87 | "timers", | ||
88 | 0, | ||
89 | pnx8550_dir, | ||
90 | pnx8550_timers_read, | ||
91 | NULL); | ||
92 | |||
93 | if (!pnx8550_timers) | ||
94 | printk(KERN_ERR "Can't create pnx8550 timers proc file\n"); | ||
95 | |||
96 | // Create /proc/pnx8550/registers | ||
97 | pnx8550_registers = create_proc_read_entry( | ||
98 | "registers", | ||
99 | 0, | ||
100 | pnx8550_dir, | ||
101 | pnx8550_registers_read, | ||
102 | NULL); | ||
103 | |||
104 | if (!pnx8550_registers) | ||
105 | printk(KERN_ERR "Can't create pnx8550 registers proc file\n"); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | __initcall(pnx8550_proc_init); | ||
diff --git a/arch/mips/pnx8550/common/prom.c b/arch/mips/pnx8550/common/prom.c new file mode 100644 index 000000000000..32f70097c3c7 --- /dev/null +++ b/arch/mips/pnx8550/common/prom.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Per Hallsmark, per.hallsmark@mvista.com | ||
4 | * | ||
5 | * Based on jmr3927/common/prom.c | ||
6 | * | ||
7 | * 2004 (c) MontaVista Software, Inc. This file is licensed under the | ||
8 | * terms of the GNU General Public License version 2. This program is | ||
9 | * licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/serial_pnx8xxx.h> | ||
17 | |||
18 | #include <asm/bootinfo.h> | ||
19 | #include <uart.h> | ||
20 | |||
21 | /* #define DEBUG_CMDLINE */ | ||
22 | |||
23 | extern int prom_argc; | ||
24 | extern char **prom_argv, **prom_envp; | ||
25 | |||
26 | typedef struct | ||
27 | { | ||
28 | char *name; | ||
29 | /* char *val; */ | ||
30 | }t_env_var; | ||
31 | |||
32 | |||
33 | char * prom_getcmdline(void) | ||
34 | { | ||
35 | return &(arcs_cmdline[0]); | ||
36 | } | ||
37 | |||
38 | void __init prom_init_cmdline(void) | ||
39 | { | ||
40 | int i; | ||
41 | |||
42 | arcs_cmdline[0] = '\0'; | ||
43 | for (i = 0; i < prom_argc; i++) { | ||
44 | strcat(arcs_cmdline, prom_argv[i]); | ||
45 | strcat(arcs_cmdline, " "); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | char *prom_getenv(char *envname) | ||
50 | { | ||
51 | /* | ||
52 | * Return a pointer to the given environment variable. | ||
53 | * Environment variables are stored in the form of "memsize=64". | ||
54 | */ | ||
55 | |||
56 | t_env_var *env = (t_env_var *)prom_envp; | ||
57 | int i; | ||
58 | |||
59 | i = strlen(envname); | ||
60 | |||
61 | while(env->name) { | ||
62 | if(strncmp(envname, env->name, i) == 0) { | ||
63 | return(env->name + strlen(envname) + 1); | ||
64 | } | ||
65 | env++; | ||
66 | } | ||
67 | return(NULL); | ||
68 | } | ||
69 | |||
70 | inline unsigned char str2hexnum(unsigned char c) | ||
71 | { | ||
72 | if(c >= '0' && c <= '9') | ||
73 | return c - '0'; | ||
74 | if(c >= 'a' && c <= 'f') | ||
75 | return c - 'a' + 10; | ||
76 | if(c >= 'A' && c <= 'F') | ||
77 | return c - 'A' + 10; | ||
78 | return 0; /* foo */ | ||
79 | } | ||
80 | |||
81 | inline void str2eaddr(unsigned char *ea, unsigned char *str) | ||
82 | { | ||
83 | int i; | ||
84 | |||
85 | for(i = 0; i < 6; i++) { | ||
86 | unsigned char num; | ||
87 | |||
88 | if((*str == '.') || (*str == ':')) | ||
89 | str++; | ||
90 | num = str2hexnum(*str++) << 4; | ||
91 | num |= (str2hexnum(*str++)); | ||
92 | ea[i] = num; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | int get_ethernet_addr(char *ethernet_addr) | ||
97 | { | ||
98 | char *ethaddr_str; | ||
99 | |||
100 | ethaddr_str = prom_getenv("ethaddr"); | ||
101 | if (!ethaddr_str) { | ||
102 | printk("ethaddr not set in boot prom\n"); | ||
103 | return -1; | ||
104 | } | ||
105 | str2eaddr(ethernet_addr, ethaddr_str); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | void __init prom_free_prom_memory(void) | ||
110 | { | ||
111 | } | ||
112 | |||
113 | extern int pnx8550_console_port; | ||
114 | |||
115 | /* used by early printk */ | ||
116 | void prom_putchar(char c) | ||
117 | { | ||
118 | if (pnx8550_console_port != -1) { | ||
119 | /* Wait until FIFO not full */ | ||
120 | while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & PNX8XXX_UART_FIFO_TXFIFO) >> 16) >= 16) | ||
121 | ; | ||
122 | /* Send one char */ | ||
123 | ip3106_fifo(UART_BASE, pnx8550_console_port) = c; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | EXPORT_SYMBOL(get_ethernet_addr); | ||
128 | EXPORT_SYMBOL(str2eaddr); | ||
diff --git a/arch/mips/pnx8550/common/reset.c b/arch/mips/pnx8550/common/reset.c new file mode 100644 index 000000000000..fadd8744a6bc --- /dev/null +++ b/arch/mips/pnx8550/common/reset.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /*. | ||
2 | * | ||
3 | * ######################################################################## | ||
4 | * | ||
5 | * This program is free software; you can distribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License (Version 2) as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
12 | * for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
17 | * | ||
18 | * ######################################################################## | ||
19 | * | ||
20 | * Reset the PNX8550 board. | ||
21 | * | ||
22 | */ | ||
23 | #include <linux/kernel.h> | ||
24 | |||
25 | #include <asm/reboot.h> | ||
26 | #include <glb.h> | ||
27 | |||
28 | void pnx8550_machine_restart(char *command) | ||
29 | { | ||
30 | char head[] = "************* Machine restart *************"; | ||
31 | char foot[] = "*******************************************"; | ||
32 | |||
33 | printk("\n\n"); | ||
34 | printk("%s\n", head); | ||
35 | if (command != NULL) | ||
36 | printk("* %s\n", command); | ||
37 | printk("%s\n", foot); | ||
38 | |||
39 | PNX8550_RST_CTL = PNX8550_RST_DO_SW_RST; | ||
40 | } | ||
41 | |||
42 | void pnx8550_machine_halt(void) | ||
43 | { | ||
44 | printk("*** Machine halt. (Not implemented) ***\n"); | ||
45 | } | ||
46 | |||
47 | void pnx8550_machine_power_off(void) | ||
48 | { | ||
49 | printk("*** Machine power off. (Not implemented) ***\n"); | ||
50 | } | ||
diff --git a/arch/mips/pnx8550/common/setup.c b/arch/mips/pnx8550/common/setup.c new file mode 100644 index 000000000000..64246c9c875c --- /dev/null +++ b/arch/mips/pnx8550/common/setup.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * | ||
3 | * 2.6 port, Embedded Alley Solutions, Inc | ||
4 | * | ||
5 | * Based on Per Hallsmark, per.hallsmark@mvista.com | ||
6 | * | ||
7 | * This program is free software; you can distribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License (Version 2) as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
14 | * for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/serial_pnx8xxx.h> | ||
28 | #include <linux/pm.h> | ||
29 | |||
30 | #include <asm/cpu.h> | ||
31 | #include <asm/bootinfo.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/mipsregs.h> | ||
34 | #include <asm/reboot.h> | ||
35 | #include <asm/pgtable.h> | ||
36 | #include <asm/time.h> | ||
37 | |||
38 | #include <glb.h> | ||
39 | #include <int.h> | ||
40 | #include <pci.h> | ||
41 | #include <uart.h> | ||
42 | #include <nand.h> | ||
43 | |||
44 | extern void __init board_setup(void); | ||
45 | extern void pnx8550_machine_restart(char *); | ||
46 | extern void pnx8550_machine_halt(void); | ||
47 | extern void pnx8550_machine_power_off(void); | ||
48 | extern struct resource ioport_resource; | ||
49 | extern struct resource iomem_resource; | ||
50 | extern char *prom_getcmdline(void); | ||
51 | |||
52 | struct resource standard_io_resources[] = { | ||
53 | { | ||
54 | .start = 0x00, | ||
55 | .end = 0x1f, | ||
56 | .name = "dma1", | ||
57 | .flags = IORESOURCE_BUSY | ||
58 | }, { | ||
59 | .start = 0x40, | ||
60 | .end = 0x5f, | ||
61 | .name = "timer", | ||
62 | .flags = IORESOURCE_BUSY | ||
63 | }, { | ||
64 | .start = 0x80, | ||
65 | .end = 0x8f, | ||
66 | .name = "dma page reg", | ||
67 | .flags = IORESOURCE_BUSY | ||
68 | }, { | ||
69 | .start = 0xc0, | ||
70 | .end = 0xdf, | ||
71 | .name = "dma2", | ||
72 | .flags = IORESOURCE_BUSY | ||
73 | }, | ||
74 | }; | ||
75 | |||
76 | #define STANDARD_IO_RESOURCES ARRAY_SIZE(standard_io_resources) | ||
77 | |||
78 | extern struct resource pci_io_resource; | ||
79 | extern struct resource pci_mem_resource; | ||
80 | |||
81 | /* Return the total size of DRAM-memory, (RANK0 + RANK1) */ | ||
82 | unsigned long get_system_mem_size(void) | ||
83 | { | ||
84 | /* Read IP2031_RANK0_ADDR_LO */ | ||
85 | unsigned long dram_r0_lo = inl(PCI_BASE | 0x65010); | ||
86 | /* Read IP2031_RANK1_ADDR_HI */ | ||
87 | unsigned long dram_r1_hi = inl(PCI_BASE | 0x65018); | ||
88 | |||
89 | return dram_r1_hi - dram_r0_lo + 1; | ||
90 | } | ||
91 | |||
92 | int pnx8550_console_port = -1; | ||
93 | |||
94 | void __init plat_mem_setup(void) | ||
95 | { | ||
96 | int i; | ||
97 | char* argptr; | ||
98 | |||
99 | board_setup(); /* board specific setup */ | ||
100 | |||
101 | _machine_restart = pnx8550_machine_restart; | ||
102 | _machine_halt = pnx8550_machine_halt; | ||
103 | pm_power_off = pnx8550_machine_power_off; | ||
104 | |||
105 | /* Clear the Global 2 Register, PCI Inta Output Enable Registers | ||
106 | Bit 1:Enable DAC Powerdown | ||
107 | -> 0:DACs are enabled and are working normally | ||
108 | 1:DACs are powerdown | ||
109 | Bit 0:Enable of PCI inta output | ||
110 | -> 0 = Disable PCI inta output | ||
111 | 1 = Enable PCI inta output | ||
112 | */ | ||
113 | PNX8550_GLB2_ENAB_INTA_O = 0; | ||
114 | |||
115 | /* IO/MEM resources. */ | ||
116 | set_io_port_base(PNX8550_PORT_BASE); | ||
117 | ioport_resource.start = 0; | ||
118 | ioport_resource.end = ~0; | ||
119 | iomem_resource.start = 0; | ||
120 | iomem_resource.end = ~0; | ||
121 | |||
122 | /* Request I/O space for devices on this board */ | ||
123 | for (i = 0; i < STANDARD_IO_RESOURCES; i++) | ||
124 | request_resource(&ioport_resource, standard_io_resources + i); | ||
125 | |||
126 | /* Place the Mode Control bit for GPIO pin 16 in primary function */ | ||
127 | /* Pin 16 is used by UART1, UA1_TX */ | ||
128 | outl((PNX8550_GPIO_MODE_PRIMOP << PNX8550_GPIO_MC_16_BIT) | | ||
129 | (PNX8550_GPIO_MODE_PRIMOP << PNX8550_GPIO_MC_17_BIT), | ||
130 | PNX8550_GPIO_MC1); | ||
131 | |||
132 | argptr = prom_getcmdline(); | ||
133 | if ((argptr = strstr(argptr, "console=ttyS")) != NULL) { | ||
134 | argptr += strlen("console=ttyS"); | ||
135 | pnx8550_console_port = *argptr == '0' ? 0 : 1; | ||
136 | |||
137 | /* We must initialize the UART (console) before early printk */ | ||
138 | /* Set LCR to 8-bit and BAUD to 38400 (no 5) */ | ||
139 | ip3106_lcr(UART_BASE, pnx8550_console_port) = | ||
140 | PNX8XXX_UART_LCR_8BIT; | ||
141 | ip3106_baud(UART_BASE, pnx8550_console_port) = 5; | ||
142 | } | ||
143 | |||
144 | return; | ||
145 | } | ||
diff --git a/arch/mips/pnx8550/common/time.c b/arch/mips/pnx8550/common/time.c new file mode 100644 index 000000000000..8836c6203df0 --- /dev/null +++ b/arch/mips/pnx8550/common/time.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Copyright 2001, 2002, 2003 MontaVista Software Inc. | ||
3 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
4 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) | ||
5 | * | ||
6 | * Common time service routines for MIPS machines. See | ||
7 | * Documents/MIPS/README.txt. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/param.h> | ||
19 | #include <linux/time.h> | ||
20 | #include <linux/timer.h> | ||
21 | #include <linux/smp.h> | ||
22 | #include <linux/kernel_stat.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | |||
26 | #include <asm/bootinfo.h> | ||
27 | #include <asm/cpu.h> | ||
28 | #include <asm/time.h> | ||
29 | #include <asm/hardirq.h> | ||
30 | #include <asm/div64.h> | ||
31 | #include <asm/debug.h> | ||
32 | |||
33 | #include <int.h> | ||
34 | #include <cm.h> | ||
35 | |||
36 | static unsigned long cpj; | ||
37 | |||
38 | static cycle_t hpt_read(struct clocksource *cs) | ||
39 | { | ||
40 | return read_c0_count2(); | ||
41 | } | ||
42 | |||
43 | static struct clocksource pnx_clocksource = { | ||
44 | .name = "pnx8xxx", | ||
45 | .rating = 200, | ||
46 | .read = hpt_read, | ||
47 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
48 | }; | ||
49 | |||
50 | static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id) | ||
51 | { | ||
52 | struct clock_event_device *c = dev_id; | ||
53 | |||
54 | /* clear MATCH, signal the event */ | ||
55 | c->event_handler(c); | ||
56 | |||
57 | return IRQ_HANDLED; | ||
58 | } | ||
59 | |||
60 | static struct irqaction pnx8xxx_timer_irq = { | ||
61 | .handler = pnx8xxx_timer_interrupt, | ||
62 | .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, | ||
63 | .name = "pnx8xxx_timer", | ||
64 | }; | ||
65 | |||
66 | static irqreturn_t monotonic_interrupt(int irq, void *dev_id) | ||
67 | { | ||
68 | /* Timer 2 clear interrupt */ | ||
69 | write_c0_compare2(-1); | ||
70 | return IRQ_HANDLED; | ||
71 | } | ||
72 | |||
73 | static struct irqaction monotonic_irqaction = { | ||
74 | .handler = monotonic_interrupt, | ||
75 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
76 | .name = "Monotonic timer", | ||
77 | }; | ||
78 | |||
79 | static int pnx8xxx_set_next_event(unsigned long delta, | ||
80 | struct clock_event_device *evt) | ||
81 | { | ||
82 | write_c0_compare(delta); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static struct clock_event_device pnx8xxx_clockevent = { | ||
87 | .name = "pnx8xxx_clockevent", | ||
88 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
89 | .set_next_event = pnx8xxx_set_next_event, | ||
90 | }; | ||
91 | |||
92 | static inline void timer_ack(void) | ||
93 | { | ||
94 | write_c0_compare(cpj); | ||
95 | } | ||
96 | |||
97 | __init void plat_time_init(void) | ||
98 | { | ||
99 | unsigned int configPR; | ||
100 | unsigned int n; | ||
101 | unsigned int m; | ||
102 | unsigned int p; | ||
103 | unsigned int pow2p; | ||
104 | |||
105 | pnx8xxx_clockevent.cpumask = cpu_none_mask; | ||
106 | clockevents_register_device(&pnx8xxx_clockevent); | ||
107 | clocksource_register(&pnx_clocksource); | ||
108 | |||
109 | /* Timer 1 start */ | ||
110 | configPR = read_c0_config7(); | ||
111 | configPR &= ~0x00000008; | ||
112 | write_c0_config7(configPR); | ||
113 | |||
114 | /* Timer 2 start */ | ||
115 | configPR = read_c0_config7(); | ||
116 | configPR &= ~0x00000010; | ||
117 | write_c0_config7(configPR); | ||
118 | |||
119 | /* Timer 3 stop */ | ||
120 | configPR = read_c0_config7(); | ||
121 | configPR |= 0x00000020; | ||
122 | write_c0_config7(configPR); | ||
123 | |||
124 | |||
125 | /* PLL0 sets MIPS clock (PLL1 <=> TM1, PLL6 <=> TM2, PLL5 <=> mem) */ | ||
126 | /* (but only if CLK_MIPS_CTL select value [bits 3:1] is 1: FIXME) */ | ||
127 | |||
128 | n = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_N_MASK) >> 16; | ||
129 | m = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_M_MASK) >> 8; | ||
130 | p = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_P_MASK) >> 2; | ||
131 | pow2p = (1 << p); | ||
132 | |||
133 | db_assert(m != 0 && pow2p != 0); | ||
134 | |||
135 | /* | ||
136 | * Compute the frequency as in the PNX8550 User Manual 1.0, p.186 | ||
137 | * (a.k.a. 8-10). Divide by HZ for a timer offset that results in | ||
138 | * HZ timer interrupts per second. | ||
139 | */ | ||
140 | mips_hpt_frequency = 27UL * ((1000000UL * n)/(m * pow2p)); | ||
141 | cpj = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); | ||
142 | write_c0_count(0); | ||
143 | timer_ack(); | ||
144 | |||
145 | /* Setup Timer 2 */ | ||
146 | write_c0_count2(0); | ||
147 | write_c0_compare2(0xffffffff); | ||
148 | |||
149 | setup_irq(PNX8550_INT_TIMER1, &pnx8xxx_timer_irq); | ||
150 | setup_irq(PNX8550_INT_TIMER2, &monotonic_irqaction); | ||
151 | } | ||
diff --git a/arch/mips/pnx8550/jbs/Makefile b/arch/mips/pnx8550/jbs/Makefile new file mode 100644 index 000000000000..ad6a8ca7d8ce --- /dev/null +++ b/arch/mips/pnx8550/jbs/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | |||
2 | # Makefile for the NXP JBS Board. | ||
3 | |||
4 | lib-y := init.o board_setup.o irqmap.o | ||
diff --git a/arch/mips/pnx8550/jbs/board_setup.c b/arch/mips/pnx8550/jbs/board_setup.c new file mode 100644 index 000000000000..57dd903ca408 --- /dev/null +++ b/arch/mips/pnx8550/jbs/board_setup.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * JBS Specific board startup routines. | ||
3 | * | ||
4 | * Copyright 2005, Embedded Alley Solutions, Inc | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
12 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
14 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
15 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
16 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
17 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
18 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
19 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
20 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License along | ||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/mc146818rtc.h> | ||
32 | #include <linux/delay.h> | ||
33 | |||
34 | #include <asm/cpu.h> | ||
35 | #include <asm/bootinfo.h> | ||
36 | #include <asm/irq.h> | ||
37 | #include <asm/mipsregs.h> | ||
38 | #include <asm/reboot.h> | ||
39 | #include <asm/pgtable.h> | ||
40 | |||
41 | #include <glb.h> | ||
42 | |||
43 | /* CP0 hazard avoidance. */ | ||
44 | #define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ | ||
45 | "nop; nop; nop; nop; nop; nop;\n\t" \ | ||
46 | ".set reorder\n\t") | ||
47 | |||
48 | void __init board_setup(void) | ||
49 | { | ||
50 | unsigned long configpr; | ||
51 | |||
52 | configpr = read_c0_config7(); | ||
53 | configpr |= (1<<19); /* enable tlb */ | ||
54 | write_c0_config7(configpr); | ||
55 | BARRIER; | ||
56 | } | ||
diff --git a/arch/mips/pnx8550/jbs/init.c b/arch/mips/pnx8550/jbs/init.c new file mode 100644 index 000000000000..d59b4a4e5e8b --- /dev/null +++ b/arch/mips/pnx8550/jbs/init.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2005 Embedded Alley Solutions, Inc | ||
4 | * source@embeddedalley.com | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
12 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
14 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
15 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
16 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
17 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
18 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
19 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
20 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License along | ||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/bootmem.h> | ||
31 | #include <asm/addrspace.h> | ||
32 | #include <asm/bootinfo.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/kernel.h> | ||
35 | |||
36 | int prom_argc; | ||
37 | char **prom_argv, **prom_envp; | ||
38 | extern void __init prom_init_cmdline(void); | ||
39 | extern char *prom_getenv(char *envname); | ||
40 | |||
41 | const char *get_system_type(void) | ||
42 | { | ||
43 | return "NXP PNX8550/JBS"; | ||
44 | } | ||
45 | |||
46 | void __init prom_init(void) | ||
47 | { | ||
48 | unsigned long memsize; | ||
49 | |||
50 | //memsize = 0x02800000; /* Trimedia uses memory above */ | ||
51 | memsize = 0x08000000; /* Trimedia uses memory above */ | ||
52 | add_memory_region(0, memsize, BOOT_MEM_RAM); | ||
53 | } | ||
diff --git a/arch/mips/pnx8550/jbs/irqmap.c b/arch/mips/pnx8550/jbs/irqmap.c new file mode 100644 index 000000000000..7fc89842002c --- /dev/null +++ b/arch/mips/pnx8550/jbs/irqmap.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * NXP JBS board irqmap. | ||
3 | * | ||
4 | * Copyright 2005 Embedded Alley Solutions, Inc | ||
5 | * source@embeddealley.com | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
13 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
14 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
15 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
17 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
18 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
21 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/init.h> | ||
29 | #include <int.h> | ||
30 | |||
31 | char pnx8550_irq_tab[][5] __initdata = { | ||
32 | [8] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | ||
33 | [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | ||
34 | [17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | ||
35 | }; | ||
diff --git a/arch/mips/pnx8550/stb810/Makefile b/arch/mips/pnx8550/stb810/Makefile new file mode 100644 index 000000000000..ab91d72c5664 --- /dev/null +++ b/arch/mips/pnx8550/stb810/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | |||
2 | # Makefile for the NXP STB810 Board. | ||
3 | |||
4 | lib-y := prom_init.o board_setup.o irqmap.o | ||
diff --git a/arch/mips/pnx8550/stb810/board_setup.c b/arch/mips/pnx8550/stb810/board_setup.c new file mode 100644 index 000000000000..af2a55e0b4e9 --- /dev/null +++ b/arch/mips/pnx8550/stb810/board_setup.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * STB810 specific board startup routines. | ||
3 | * | ||
4 | * Based on the arch/mips/nxp/pnx8550/jbs/board_setup.c | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * source@mvista.com | ||
8 | * | ||
9 | * Copyright 2005 MontaVista Software Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/console.h> | ||
22 | #include <linux/mc146818rtc.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <asm/cpu.h> | ||
26 | #include <asm/bootinfo.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/mipsregs.h> | ||
29 | #include <asm/reboot.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | |||
32 | #include <glb.h> | ||
33 | |||
34 | void __init board_setup(void) | ||
35 | { | ||
36 | unsigned long configpr; | ||
37 | |||
38 | configpr = read_c0_config7(); | ||
39 | configpr |= (1<<19); /* enable tlb */ | ||
40 | write_c0_config7(configpr); | ||
41 | } | ||
diff --git a/arch/mips/pnx8550/stb810/irqmap.c b/arch/mips/pnx8550/stb810/irqmap.c new file mode 100644 index 000000000000..8c034963ddcd --- /dev/null +++ b/arch/mips/pnx8550/stb810/irqmap.c | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * NXP STB810 board irqmap. | ||
3 | * | ||
4 | * Author: MontaVista Software, Inc. | ||
5 | * source@mvista.com | ||
6 | * | ||
7 | * Copyright 2005 MontaVista Software Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <int.h> | ||
17 | |||
18 | char pnx8550_irq_tab[][5] __initdata = { | ||
19 | [8] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | ||
20 | [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | ||
21 | [10] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | ||
22 | }; | ||
diff --git a/arch/mips/pnx8550/stb810/prom_init.c b/arch/mips/pnx8550/stb810/prom_init.c new file mode 100644 index 000000000000..ca7f4ada0640 --- /dev/null +++ b/arch/mips/pnx8550/stb810/prom_init.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * STB810 specific prom routines | ||
3 | * | ||
4 | * Author: MontaVista Software, Inc. | ||
5 | * source@mvista.com | ||
6 | * | ||
7 | * Copyright 2005 MontaVista Software Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/bootmem.h> | ||
19 | #include <asm/addrspace.h> | ||
20 | #include <asm/bootinfo.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/kernel.h> | ||
23 | |||
24 | int prom_argc; | ||
25 | char **prom_argv, **prom_envp; | ||
26 | extern void __init prom_init_cmdline(void); | ||
27 | extern char *prom_getenv(char *envname); | ||
28 | |||
29 | const char *get_system_type(void) | ||
30 | { | ||
31 | return "NXP PNX8950/STB810"; | ||
32 | } | ||
33 | |||
34 | void __init prom_init(void) | ||
35 | { | ||
36 | unsigned long memsize; | ||
37 | |||
38 | prom_argc = (int) fw_arg0; | ||
39 | prom_argv = (char **) fw_arg1; | ||
40 | prom_envp = (char **) fw_arg2; | ||
41 | |||
42 | prom_init_cmdline(); | ||
43 | |||
44 | memsize = 0x08000000; /* Trimedia uses memory above */ | ||
45 | add_memory_region(0, memsize, BOOT_MEM_RAM); | ||
46 | } | ||