Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-3.10.git] / arch / mips / alchemy / devboards / platform.c
1 /*
2  * devoard misc stuff.
3  */
4
5 #include <linux/init.h>
6 #include <linux/mtd/mtd.h>
7 #include <linux/mtd/map.h>
8 #include <linux/mtd/physmap.h>
9 #include <linux/slab.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm.h>
12
13 #include <asm/bootinfo.h>
14 #include <asm/reboot.h>
15 #include <asm/mach-au1x00/au1000.h>
16 #include <asm/mach-db1x00/bcsr.h>
17
18 #include <prom.h>
19
20 void __init prom_init(void)
21 {
22         unsigned char *memsize_str;
23         unsigned long memsize;
24
25         prom_argc = (int)fw_arg0;
26         prom_argv = (char **)fw_arg1;
27         prom_envp = (char **)fw_arg2;
28
29         prom_init_cmdline();
30         memsize_str = prom_getenv("memsize");
31         if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
32                 memsize = 64 << 20; /* all devboards have at least 64MB RAM */
33
34         add_memory_region(0, memsize, BOOT_MEM_RAM);
35 }
36
37 void prom_putchar(unsigned char c)
38 {
39 #ifdef CONFIG_MIPS_DB1300
40         alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
41 #else
42         alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
43 #endif
44 }
45
46
47 static struct platform_device db1x00_rtc_dev = {
48         .name   = "rtc-au1xxx",
49         .id     = -1,
50 };
51
52
53 static void db1x_power_off(void)
54 {
55         bcsr_write(BCSR_RESETS, 0);
56         bcsr_write(BCSR_SYSTEM, BCSR_SYSTEM_PWROFF | BCSR_SYSTEM_RESET);
57 }
58
59 static void db1x_reset(char *c)
60 {
61         bcsr_write(BCSR_RESETS, 0);
62         bcsr_write(BCSR_SYSTEM, 0);
63 }
64
65 static int __init db1x_late_setup(void)
66 {
67         if (!pm_power_off)
68                 pm_power_off = db1x_power_off;
69         if (!_machine_halt)
70                 _machine_halt = db1x_power_off;
71         if (!_machine_restart)
72                 _machine_restart = db1x_reset;
73
74         platform_device_register(&db1x00_rtc_dev);
75
76         return 0;
77 }
78 device_initcall(db1x_late_setup);
79
80 /* register a pcmcia socket */
81 int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start,
82                                        phys_addr_t pcmcia_attr_end,
83                                        phys_addr_t pcmcia_mem_start,
84                                        phys_addr_t pcmcia_mem_end,
85                                        phys_addr_t pcmcia_io_start,
86                                        phys_addr_t pcmcia_io_end,
87                                        int card_irq,
88                                        int cd_irq,
89                                        int stschg_irq,
90                                        int eject_irq,
91                                        int id)
92 {
93         int cnt, i, ret;
94         struct resource *sr;
95         struct platform_device *pd;
96
97         cnt = 5;
98         if (eject_irq)
99                 cnt++;
100         if (stschg_irq)
101                 cnt++;
102
103         sr = kzalloc(sizeof(struct resource) * cnt, GFP_KERNEL);
104         if (!sr)
105                 return -ENOMEM;
106
107         pd = platform_device_alloc("db1xxx_pcmcia", id);
108         if (!pd) {
109                 ret = -ENOMEM;
110                 goto out;
111         }
112
113         sr[0].name      = "pcmcia-attr";
114         sr[0].flags     = IORESOURCE_MEM;
115         sr[0].start     = pcmcia_attr_start;
116         sr[0].end       = pcmcia_attr_end;
117
118         sr[1].name      = "pcmcia-mem";
119         sr[1].flags     = IORESOURCE_MEM;
120         sr[1].start     = pcmcia_mem_start;
121         sr[1].end       = pcmcia_mem_end;
122
123         sr[2].name      = "pcmcia-io";
124         sr[2].flags     = IORESOURCE_MEM;
125         sr[2].start     = pcmcia_io_start;
126         sr[2].end       = pcmcia_io_end;
127
128         sr[3].name      = "insert";
129         sr[3].flags     = IORESOURCE_IRQ;
130         sr[3].start = sr[3].end = cd_irq;
131
132         sr[4].name      = "card";
133         sr[4].flags     = IORESOURCE_IRQ;
134         sr[4].start = sr[4].end = card_irq;
135
136         i = 5;
137         if (stschg_irq) {
138                 sr[i].name      = "stschg";
139                 sr[i].flags     = IORESOURCE_IRQ;
140                 sr[i].start = sr[i].end = stschg_irq;
141                 i++;
142         }
143         if (eject_irq) {
144                 sr[i].name      = "eject";
145                 sr[i].flags     = IORESOURCE_IRQ;
146                 sr[i].start = sr[i].end = eject_irq;
147         }
148
149         pd->resource = sr;
150         pd->num_resources = cnt;
151
152         ret = platform_device_add(pd);
153         if (!ret)
154                 return 0;
155
156         platform_device_put(pd);
157 out:
158         kfree(sr);
159         return ret;
160 }
161
162 #define YAMON_SIZE      0x00100000
163 #define YAMON_ENV_SIZE  0x00040000
164
165 int __init db1x_register_norflash(unsigned long size, int width,
166                                   int swapped)
167 {
168         struct physmap_flash_data *pfd;
169         struct platform_device *pd;
170         struct mtd_partition *parts;
171         struct resource *res;
172         int ret, i;
173
174         if (size < (8 * 1024 * 1024))
175                 return -EINVAL;
176
177         ret = -ENOMEM;
178         parts = kzalloc(sizeof(struct mtd_partition) * 5, GFP_KERNEL);
179         if (!parts)
180                 goto out;
181
182         res = kzalloc(sizeof(struct resource), GFP_KERNEL);
183         if (!res)
184                 goto out1;
185
186         pfd = kzalloc(sizeof(struct physmap_flash_data), GFP_KERNEL);
187         if (!pfd)
188                 goto out2;
189
190         pd = platform_device_alloc("physmap-flash", 0);
191         if (!pd)
192                 goto out3;
193
194         /* NOR flash ends at 0x20000000, regardless of size */
195         res->start = 0x20000000 - size;
196         res->end = 0x20000000 - 1;
197         res->flags = IORESOURCE_MEM;
198
199         /* partition setup.  Most Develboards have a switch which allows
200          * to swap the physical locations of the 2 NOR flash banks.
201          */
202         i = 0;
203         if (!swapped) {
204                 /* first NOR chip */
205                 parts[i].offset = 0;
206                 parts[i].name = "User FS";
207                 parts[i].size = size / 2;
208                 i++;
209         }
210
211         parts[i].offset = MTDPART_OFS_APPEND;
212         parts[i].name = "User FS 2";
213         parts[i].size = (size / 2) - (0x20000000 - 0x1fc00000);
214         i++;
215
216         parts[i].offset = MTDPART_OFS_APPEND;
217         parts[i].name = "YAMON";
218         parts[i].size = YAMON_SIZE;
219         parts[i].mask_flags = MTD_WRITEABLE;
220         i++;
221
222         parts[i].offset = MTDPART_OFS_APPEND;
223         parts[i].name = "raw kernel";
224         parts[i].size = 0x00400000 - YAMON_SIZE - YAMON_ENV_SIZE;
225         i++;
226
227         parts[i].offset = MTDPART_OFS_APPEND;
228         parts[i].name = "YAMON Env";
229         parts[i].size = YAMON_ENV_SIZE;
230         parts[i].mask_flags = MTD_WRITEABLE;
231         i++;
232
233         if (swapped) {
234                 parts[i].offset = MTDPART_OFS_APPEND;
235                 parts[i].name = "User FS";
236                 parts[i].size = size / 2;
237                 i++;
238         }
239
240         pfd->width = width;
241         pfd->parts = parts;
242         pfd->nr_parts = 5;
243
244         pd->dev.platform_data = pfd;
245         pd->resource = res;
246         pd->num_resources = 1;
247
248         ret = platform_device_add(pd);
249         if (!ret)
250                 return ret;
251
252         platform_device_put(pd);
253 out3:
254         kfree(pfd);
255 out2:
256         kfree(res);
257 out1:
258         kfree(parts);
259 out:
260         return ret;
261 }