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