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 }
262