basic modification from way back
[powerpc.git] / arch / powerpc / platforms / embedded6xx / kvme080.c
1 /*
2  * Board setup routines for KVME080.
3  *
4  * Copyright 2007 Sangmoon Kim <dogoil@etinsys.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
12 #include <linux/initrd.h>
13 #include <linux/delay.h>
14 #include <linux/ide.h>
15 #include <linux/root_dev.h>
16 #include <linux/bcd.h>
17 #include <linux/mc146818rtc.h>
18
19 #include <asm/time.h>
20 #include <asm/mpic.h>
21 #include <asm/mpc10x.h>
22 #include <asm/pci-bridge.h>
23
24 static int __init
25 kvme080_probe(void)
26 {
27         unsigned long root = of_get_flat_dt_root();
28
29         if (of_flat_dt_is_compatible(root, "kvme080"))
30                 return 1;
31         return 0;
32 }
33
34 static int __init
35 kvme080_setup_pci(struct device_node *dnp)
36 {
37         int len;
38         struct pci_controller *hose;
39         int *bus_range;
40
41         printk("Adding PCI host bridge %s\n", dnp->full_name);
42
43         bus_range = (int *) get_property(dnp, "bus-range", &len);
44         if (bus_range == NULL || len < 2 * sizeof(int))
45                 printk(KERN_WARNING "Can't get bus-range for %s, assume"
46                                 " bus 0\n", dnp->full_name);
47
48         hose = pcibios_alloc_controller();
49         if (hose == NULL) {
50                 printk("PCI Host bridge init failed\n");
51                 return -ENOMEM;
52         }
53         hose->arch_data = dnp;
54         hose->first_busno = bus_range ? bus_range[0] : 0;
55         hose->last_busno = bus_range ? bus_range[1] : 0xff;
56         hose->set_cfg_type = 1;
57         setup_indirect_pci(hose, 0xfcc00000, 0xfce00000);
58
59         printk(KERN_INFO "Found PCI host bridge %s", dnp->full_name);
60
61         /* Interpret the "ranges" property */
62         /* This also maps the I/O region and sets isa_io/mem_base */
63         pci_process_bridge_OF_ranges(hose, dnp, 1);
64         return 0;
65 }
66
67 static void __init
68 kvme080_setup_arch(void)
69 {
70         struct device_node *dnp;
71         const u32 *prop;
72         u64 size;
73         phys_addr_t paddr;
74
75 #ifdef CONFIG_BLK_DEV_INITRD
76         if (initrd_start)
77                 ROOT_DEV = Root_RAM0;
78         else
79 #endif
80 #ifdef  CONFIG_ROOT_NFS
81                 ROOT_DEV = Root_NFS;
82 #else
83                 ROOT_DEV = Root_HDA1;
84 #endif
85         for (dnp = NULL; (dnp=of_find_node_by_type(dnp,"pci")) != NULL;)
86                 kvme080_setup_pci(dnp);
87
88         printk(KERN_INFO "Etin Systems KVME080 Board\n");
89         printk(KERN_INFO "Port by Sangmoon Kim (dogoil@etinsys.com)\n");
90 }
91
92 static void __init
93 kvme080_init_IRQ(void)
94 {
95         struct mpic *mpic;
96         struct device_node *dnp;
97         const u32 *prop;
98         int size;
99         phys_addr_t paddr;
100
101         dnp = of_find_node_by_type(NULL, "open-pic");
102         if (dnp == NULL)
103                 return;
104
105         prop = of_get_address(dnp, 0, NULL, NULL);
106         paddr = (phys_addr_t)of_translate_address(dnp, prop);
107
108         mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 0, 0,
109                           "EPIC");
110         BUG_ON(mpic == NULL);
111
112         prop = (u32 *)get_property(dnp, "serial-mode", &size);
113         if (prop != NULL)
114                 mpic_set_serial_int(mpic, *(u32 *)prop);
115
116         /* PCI IRQs */
117         mpic_assign_isu(mpic, 0, paddr + 0x10200);
118
119         /* I2C */
120         mpic_assign_isu(mpic, 1, paddr + 0x11020);
121
122         /* ttyS0 */
123         mpic_assign_isu(mpic, 2, paddr + 0x11120);
124
125         /* ttyS1 */
126         mpic_assign_isu(mpic, 3, paddr + 0x11140);
127
128         mpic_init(mpic);
129 }
130
131 static void
132 kvme080_restart(char *cmd)
133 {
134         unsigned long srr;
135
136         local_irq_disable();
137         asm volatile(
138         " lis %0,0xfff0\n \
139           ori %0,%0,0x0100\n \
140           mtspr 26,%0\n \
141           sync\n \
142           lis %0,0x0000\n \
143           ori %0,%0,0x0000\n \
144           mtspr 27,%0\n \
145           sync\n \
146           rfi "
147           : "=r" (srr));
148 }
149
150 static void
151 kvme080_power_off(void)
152 {
153         local_irq_disable();
154         for(;;);        /* No way to shut power off with software */
155         /* NOTREACHED */
156 }
157
158 static void
159 kvme080_halt(void)
160 {
161         kvme080_power_off();
162         /* NOTREACHED */
163 }
164
165 extern spinlock_t rtc_lock;
166 static unsigned char *rtc_base = (unsigned char*)NULL;
167
168 static long __init
169 kvme080_time_init(void)
170 {
171         char val;
172         struct device_node *dnp;
173         const u32 *prop;
174         u64 size;
175         phys_addr_t paddr;
176
177         dnp = of_find_node_by_type(NULL, "rtc");
178         if (!dnp)
179                 return -1;
180
181         prop = of_get_address(dnp, 0, &size, NULL);
182         if (!prop)
183                 return -1;
184
185         paddr = (phys_addr_t)of_translate_address(dnp, prop);
186         if (paddr == (phys_addr_t)OF_BAD_ADDR)
187                 return -1;
188
189         rtc_base = (unsigned char *)ioremap(paddr, (ssize_t)size);
190
191         if(!rtc_base)
192                 return -1;
193
194         spin_lock(&rtc_lock);
195         val = readb(rtc_base);
196         if (val & 0xc0)
197                 writeb(val & 0x3f, rtc_base);
198         spin_unlock(&rtc_lock);
199
200         return 0;
201 }
202
203 static int
204 kvme080_set_rtc_time(struct rtc_time *tp)
205 {
206         if (!rtc_base)
207                 return -1;
208
209         spin_lock(&rtc_lock);
210
211         writeb(readb(rtc_base) | 0x80, rtc_base);
212
213         writeb(BIN2BCD(tp->tm_sec), rtc_base + 1);
214         writeb(BIN2BCD(tp->tm_min), rtc_base + 2);
215         writeb(BIN2BCD(tp->tm_hour), rtc_base + 3);
216         writeb(BIN2BCD(tp->tm_mday), rtc_base + 5);
217         writeb(BIN2BCD(tp->tm_mon), rtc_base + 6);
218         writeb(BIN2BCD(tp->tm_year % 100), rtc_base + 7);
219
220         writeb((readb(rtc_base) & 0x40) |
221                BIN2BCD((tp->tm_year < 100) ? 20 : 21), rtc_base);
222
223         spin_unlock(&rtc_lock);
224
225         return 0;
226 }
227
228 static void
229 kvme080_get_rtc_time(struct rtc_time *tp)
230 {
231         if (!rtc_base)
232                 return;
233
234         spin_lock(&rtc_lock);
235
236         writeb(readb(rtc_base) | 0x40, rtc_base);
237
238         tp->tm_sec = readb(rtc_base + 1) & 0x7f;
239         tp->tm_min = readb(rtc_base + 2) & 0x7f;
240         tp->tm_hour = readb(rtc_base + 3) & 0x3f;
241         tp->tm_mday = readb(rtc_base + 5) & 0x3f;
242         tp->tm_mon = readb(rtc_base + 6) & 0x1f;
243         tp->tm_year = readb(rtc_base + 7) & 0xff;
244
245         writeb(readb(rtc_base) & ~0x40, rtc_base);
246
247         tp->tm_sec = BCD2BIN(tp->tm_sec);
248         tp->tm_min = BCD2BIN(tp->tm_min);
249         tp->tm_hour = BCD2BIN(tp->tm_hour);
250         tp->tm_mday = BCD2BIN(tp->tm_mday);
251         tp->tm_mon = BCD2BIN(tp->tm_mon);
252         tp->tm_year = BCD2BIN(tp->tm_year);
253
254         if (tp->tm_year < 80)
255                 tp->tm_year += 100;
256
257         spin_unlock(&rtc_lock);
258 }
259
260 static unsigned char
261 kvme080_nvram_read_val(int addr)
262 {
263         if (!nvram_base)
264                 return 0;
265         return readb(nvram_base + addr);
266 }
267
268 static void
269 kvme080_nvram_write_val(int addr, unsigned char val)
270 {
271         if (!nvram_base)
272                 return;
273         writeb(val, nvram_base + addr);
274 }
275
276 static ssize_t
277 kvme080_nvram_size(void)
278 {
279         return nvram_size;
280 }
281
282 define_machine(kvme080) {
283         .name                   = "kvme080",
284         .probe                  = kvme080_probe,
285         .setup_arch             = kvme080_setup_arch,
286         .init_IRQ               = kvme080_init_IRQ,
287         .get_irq                = mpic_get_irq,
288         .restart                = kvme080_restart,
289         .power_off              = kvme080_power_off,
290         .halt                   = kvme080_halt,
291         .time_init              = kvme080_time_init,
292         .set_rtc_time           = kvme080_set_rtc_time,
293         .get_rtc_time           = kvme080_get_rtc_time,
294         .calibrate_decr         = generic_calibrate_decr,
295         .nvram_read_val         = kvme080_nvram_read_val,
296         .nvram_write_val        = kvme080_nvram_write_val,
297         .nvram_size             = kvme080_nvram_size,
298         .progress               = udbg_progress,
299 };