Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / arch / mips / pmcs-msp71xx / msp_prom.c
1 /*
2  * BRIEF MODULE DESCRIPTION
3  *    PROM library initialisation code, assuming a version of
4  *    pmon is the boot code.
5  *
6  * Copyright 2000,2001 MontaVista Software Inc.
7  * Author: MontaVista Software, Inc.
8  *              ppopov@mvista.com or source@mvista.com
9  *
10  * This file was derived from Carsten Langgaard's
11  * arch/mips/mips-boards/xx files.
12  *
13  * Carsten Langgaard, carstenl@mips.com
14  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
15  *
16  *  This program is free software; you can redistribute  it and/or modify it
17  *  under  the terms of  the GNU General  Public License as published by the
18  *  Free Software Foundation;  either version 2 of the  License, or (at your
19  *  option) any later version.
20  *
21  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
22  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
23  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
24  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
25  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
27  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
29  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  *  You should have received a copy of the  GNU General Public License along
33  *  with this program; if not, write  to the Free Software Foundation, Inc.,
34  *  675 Mass Ave, Cambridge, MA 02139, USA.
35  */
36
37 #include <linux/export.h>
38 #include <linux/kernel.h>
39 #include <linux/init.h>
40 #include <linux/string.h>
41 #include <linux/interrupt.h>
42 #include <linux/mm.h>
43 #include <linux/slab.h>
44
45 #include <asm/addrspace.h>
46 #include <asm/bootinfo.h>
47 #include <asm-generic/sections.h>
48 #include <asm/page.h>
49
50 #include <msp_prom.h>
51 #include <msp_regs.h>
52
53 /* global PROM environment variables and pointers */
54 int prom_argc;
55 char **prom_argv, **prom_envp;
56 int *prom_vec;
57
58 /* debug flag */
59 int init_debug = 1;
60
61 /* memory blocks */
62 struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
63
64 #define MAX_PROM_MEM 5
65 static phys_addr_t prom_mem_base[MAX_PROM_MEM] __initdata;
66 static phys_addr_t prom_mem_size[MAX_PROM_MEM] __initdata;
67 static unsigned int nr_prom_mem __initdata;
68
69 /* default feature sets */
70 static char msp_default_features[] =
71 #if defined(CONFIG_PMC_MSP4200_EVAL) \
72  || defined(CONFIG_PMC_MSP4200_GW)
73         "ERER";
74 #elif defined(CONFIG_PMC_MSP7120_EVAL) \
75  || defined(CONFIG_PMC_MSP7120_GW)
76         "EMEMSP";
77 #elif defined(CONFIG_PMC_MSP7120_FPGA)
78         "EMEM";
79 #endif
80
81 /* conversion functions */
82 static inline unsigned char str2hexnum(unsigned char c)
83 {
84         if (c >= '0' && c <= '9')
85                 return c - '0';
86         if (c >= 'a' && c <= 'f')
87                 return c - 'a' + 10;
88         return 0; /* foo */
89 }
90
91 int str2eaddr(unsigned char *ea, unsigned char *str)
92 {
93         int index = 0;
94         unsigned char num = 0;
95
96         while (*str != '\0') {
97                 if ((*str == '.') || (*str == ':')) {
98                         ea[index++] = num;
99                         num = 0;
100                         str++;
101                 } else {
102                         num = num << 4;
103                         num |= str2hexnum(*str++);
104                 }
105         }
106
107         if (index == 5) {
108                 ea[index++] = num;
109                 return 0;
110         } else
111                 return -1;
112 }
113 EXPORT_SYMBOL(str2eaddr);
114
115 static inline unsigned long str2hex(unsigned char *str)
116 {
117         int value = 0;
118
119         while (*str) {
120                 value = value << 4;
121                 value |= str2hexnum(*str++);
122         }
123
124         return value;
125 }
126
127 /* function to query the system information */
128 const char *get_system_type(void)
129 {
130 #if defined(CONFIG_PMC_MSP4200_EVAL)
131         return "PMC-Sierra MSP4200 Eval Board";
132 #elif defined(CONFIG_PMC_MSP4200_GW)
133         return "PMC-Sierra MSP4200 VoIP Gateway";
134 #elif defined(CONFIG_PMC_MSP7120_EVAL)
135         return "PMC-Sierra MSP7120 Eval Board";
136 #elif defined(CONFIG_PMC_MSP7120_GW)
137         return "PMC-Sierra MSP7120 Residential Gateway";
138 #elif defined(CONFIG_PMC_MSP7120_FPGA)
139         return "PMC-Sierra MSP7120 FPGA";
140 #else
141         #error "What is the type of *your* MSP?"
142 #endif
143 }
144
145 int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr)
146 {
147         char *ethaddr_str;
148
149         ethaddr_str = prom_getenv(ethaddr_name);
150         if (!ethaddr_str) {
151                 printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name);
152                 return -1;
153         }
154
155         if (str2eaddr(ethernet_addr, ethaddr_str) == -1) {
156                 printk(KERN_WARNING "%s badly formatted-<%s>\n",
157                         ethaddr_name, ethaddr_str);
158                 return -1;
159         }
160
161         if (init_debug > 1) {
162                 int i;
163                 printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name);
164                 for (i = 0; i < 5; i++)
165                         printk(KERN_DEBUG "%02x:",
166                                 (unsigned char)*(ethernet_addr+i));
167                 printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i));
168         }
169
170         return 0;
171 }
172 EXPORT_SYMBOL(get_ethernet_addr);
173
174 static char *get_features(void)
175 {
176         char *feature = prom_getenv(FEATURES);
177
178         if (feature == NULL) {
179                 /* default features based on MACHINE_TYPE */
180                 feature = msp_default_features;
181         }
182
183         return feature;
184 }
185
186 static char test_feature(char c)
187 {
188         char *feature = get_features();
189
190         while (*feature) {
191                 if (*feature++ == c)
192                         return *feature;
193                 feature++;
194         }
195
196         return FEATURE_NOEXIST;
197 }
198
199 unsigned long get_deviceid(void)
200 {
201         char *deviceid = prom_getenv(DEVICEID);
202
203         if (deviceid == NULL)
204                 return *DEV_ID_REG;
205         else
206                 return str2hex(deviceid);
207 }
208
209 char identify_pci(void)
210 {
211         return test_feature(PCI_KEY);
212 }
213 EXPORT_SYMBOL(identify_pci);
214
215 char identify_pcimux(void)
216 {
217         return test_feature(PCIMUX_KEY);
218 }
219
220 char identify_sec(void)
221 {
222         return test_feature(SEC_KEY);
223 }
224 EXPORT_SYMBOL(identify_sec);
225
226 char identify_spad(void)
227 {
228         return test_feature(SPAD_KEY);
229 }
230 EXPORT_SYMBOL(identify_spad);
231
232 char identify_tdm(void)
233 {
234         return test_feature(TDM_KEY);
235 }
236 EXPORT_SYMBOL(identify_tdm);
237
238 char identify_zsp(void)
239 {
240         return test_feature(ZSP_KEY);
241 }
242 EXPORT_SYMBOL(identify_zsp);
243
244 static char identify_enetfeature(char key, unsigned long interface_num)
245 {
246         char *feature = get_features();
247
248         while (*feature) {
249                 if (*feature++ == key && interface_num-- == 0)
250                         return *feature;
251                 feature++;
252         }
253
254         return FEATURE_NOEXIST;
255 }
256
257 char identify_enet(unsigned long interface_num)
258 {
259         return identify_enetfeature(ENET_KEY, interface_num);
260 }
261 EXPORT_SYMBOL(identify_enet);
262
263 char identify_enetTxD(unsigned long interface_num)
264 {
265         return identify_enetfeature(ENETTXD_KEY, interface_num);
266 }
267 EXPORT_SYMBOL(identify_enetTxD);
268
269 unsigned long identify_family(void)
270 {
271         unsigned long deviceid;
272
273         deviceid = get_deviceid();
274
275         return deviceid & CPU_DEVID_FAMILY;
276 }
277 EXPORT_SYMBOL(identify_family);
278
279 unsigned long identify_revision(void)
280 {
281         unsigned long deviceid;
282
283         deviceid = get_deviceid();
284
285         return deviceid & CPU_DEVID_REVISION;
286 }
287 EXPORT_SYMBOL(identify_revision);
288
289 /* PROM environment functions */
290 char *prom_getenv(char *env_name)
291 {
292         /*
293          * Return a pointer to the given environment variable.  prom_envp
294          * points to a null terminated array of pointers to variables.
295          * Environment variables are stored in the form of "memsize=64"
296          */
297
298         char **var = prom_envp;
299         int i = strlen(env_name);
300
301         while (*var) {
302                 if (strncmp(env_name, *var, i) == 0) {
303                         return *var + strlen(env_name) + 1;
304                 }
305                 var++;
306         }
307
308         return NULL;
309 }
310
311 /* PROM commandline functions */
312 void  __init prom_init_cmdline(void)
313 {
314         char *cp;
315         int actr;
316
317         actr = 1; /* Always ignore argv[0] */
318
319         cp = &(arcs_cmdline[0]);
320         while (actr < prom_argc) {
321                 strcpy(cp, prom_argv[actr]);
322                 cp += strlen(prom_argv[actr]);
323                 *cp++ = ' ';
324                 actr++;
325         }
326         if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
327                 --cp;
328         *cp = '\0';
329 }
330
331 /* memory allocation functions */
332 static int __init prom_memtype_classify(unsigned int type)
333 {
334         switch (type) {
335         case yamon_free:
336                 return BOOT_MEM_RAM;
337         case yamon_prom:
338                 return BOOT_MEM_ROM_DATA;
339         default:
340                 return BOOT_MEM_RESERVED;
341         }
342 }
343
344 void __init prom_meminit(void)
345 {
346         struct prom_pmemblock *p;
347
348         p = prom_getmdesc();
349
350         while (p->size) {
351                 long type;
352                 unsigned long base, size;
353
354                 type = prom_memtype_classify(p->type);
355                 base = p->base;
356                 size = p->size;
357
358                 add_memory_region(base, size, type);
359                 p++;
360
361                 if (type == BOOT_MEM_ROM_DATA) {
362                         if (nr_prom_mem >= MAX_PROM_MEM) {
363                                 pr_err("Too many ROM DATA regions");
364                                 continue;
365                         }
366                         prom_mem_base[nr_prom_mem] = base;
367                         prom_mem_size[nr_prom_mem] = size;
368                         nr_prom_mem++;
369                 }
370         }
371 }
372
373 void __init prom_free_prom_memory(void)
374 {
375         int     argc;
376         char    **argv;
377         char    **envp;
378         char    *ptr;
379         int     len = 0;
380         int     i;
381
382         /*
383          * preserve environment variables and command line from pmon/bbload
384          * first preserve the command line
385          */
386         for (argc = 0; argc < prom_argc; argc++) {
387                 len += sizeof(char *);                  /* length of pointer */
388                 len += strlen(prom_argv[argc]) + 1;     /* length of string */
389         }
390         len += sizeof(char *);          /* plus length of null pointer */
391
392         argv = kmalloc(len, GFP_KERNEL);
393         ptr = (char *) &argv[prom_argc + 1];    /* strings follow array */
394
395         for (argc = 0; argc < prom_argc; argc++) {
396                 argv[argc] = ptr;
397                 strcpy(ptr, prom_argv[argc]);
398                 ptr += strlen(prom_argv[argc]) + 1;
399         }
400         argv[prom_argc] = NULL;         /* end array with null pointer */
401         prom_argv = argv;
402
403         /* next preserve the environment variables */
404         len = 0;
405         i = 0;
406         for (envp = prom_envp; *envp != NULL; envp++) {
407                 i++;            /* count number of environment variables */
408                 len += sizeof(char *);          /* length of pointer */
409                 len += strlen(*envp) + 1;       /* length of string */
410         }
411         len += sizeof(char *);          /* plus length of null pointer */
412
413         envp = kmalloc(len, GFP_KERNEL);
414         ptr = (char *) &envp[i+1];
415
416         for (argc = 0; argc < i; argc++) {
417                 envp[argc] = ptr;
418                 strcpy(ptr, prom_envp[argc]);
419                 ptr += strlen(prom_envp[argc]) + 1;
420         }
421         envp[i] = NULL;                 /* end array with null pointer */
422         prom_envp = envp;
423
424         for (i = 0; i < nr_prom_mem; i++) {
425                 free_init_pages("prom memory",
426                         prom_mem_base[i], prom_mem_base[i] + prom_mem_size[i]);
427         }
428 }
429
430 struct prom_pmemblock *__init prom_getmdesc(void)
431 {
432         static char     memsz_env[] __initdata = "memsize";
433         static char     heaptop_env[] __initdata = "heaptop";
434         char            *str;
435         unsigned int    memsize;
436         unsigned int    heaptop;
437         int i;
438
439         str = prom_getenv(memsz_env);
440         if (!str) {
441                 ppfinit("memsize not set in boot prom, "
442                         "set to default (32Mb)\n");
443                 memsize = 0x02000000;
444         } else {
445                 memsize = simple_strtol(str, NULL, 0);
446
447                 if (memsize == 0) {
448                         /* if memsize is a bad size, use reasonable default */
449                         memsize = 0x02000000;
450                 }
451
452                 /* convert to physical address (removing caching bits, etc) */
453                 memsize = CPHYSADDR(memsize);
454         }
455
456         str = prom_getenv(heaptop_env);
457         if (!str) {
458                 heaptop = CPHYSADDR((u32)&_text);
459                 ppfinit("heaptop not set in boot prom, "
460                         "set to default 0x%08x\n", heaptop);
461         } else {
462                 heaptop = simple_strtol(str, NULL, 16);
463                 if (heaptop == 0) {
464                         /* heaptop conversion bad, might have 0xValue */
465                         heaptop = simple_strtol(str, NULL, 0);
466
467                         if (heaptop == 0) {
468                                 /* heaptop still bad, use reasonable default */
469                                 heaptop = CPHYSADDR((u32)&_text);
470                         }
471                 }
472
473                 /* convert to physical address (removing caching bits, etc) */
474                 heaptop = CPHYSADDR((u32)heaptop);
475         }
476
477         /* the base region */
478         i = 0;
479         mdesc[i].type = BOOT_MEM_RESERVED;
480         mdesc[i].base = 0x00000000;
481         mdesc[i].size = PAGE_ALIGN(0x300 + 0x80);
482                 /* jtag interrupt vector + sizeof vector */
483
484         /* PMON data */
485         if (heaptop > mdesc[i].base + mdesc[i].size) {
486                 i++;                    /* 1 */
487                 mdesc[i].type = BOOT_MEM_ROM_DATA;
488                 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
489                 mdesc[i].size = heaptop - mdesc[i].base;
490         }
491
492         /* end of PMON data to start of kernel -- probably zero .. */
493         if (heaptop != CPHYSADDR((u32)_text)) {
494                 i++;    /* 2 */
495                 mdesc[i].type = BOOT_MEM_RAM;
496                 mdesc[i].base = heaptop;
497                 mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base;
498         }
499
500         /*  kernel proper */
501         i++;                    /* 3 */
502         mdesc[i].type = BOOT_MEM_RESERVED;
503         mdesc[i].base = CPHYSADDR((u32)_text);
504         mdesc[i].size = CPHYSADDR(PAGE_ALIGN((u32)_end)) - mdesc[i].base;
505
506         /* Remainder of RAM -- under memsize */
507         i++;                    /* 5 */
508         mdesc[i].type = yamon_free;
509         mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
510         mdesc[i].size = memsize - mdesc[i].base;
511
512         return &mdesc[0];
513 }