xref: /netbsd-src/sys/arch/emips/stand/common/prom_iface.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* Copyright (c) 1999 The NetBSD Foundation, Inc.
2  * All rights reserved.
3  *
4  * Copyright (c) 2008 Microsoft.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *        This product includes software developed by the NetBSD
17  *        Foundation, Inc. and its contributors.
18  * 4. Neither the name of The NetBSD Foundation nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <lib/libsa/stand.h>
37 #include <lib/libsa/loadfile.h>
38 #include <lib/libkern/libkern.h>
39 
40 #include <sys/param.h>
41 #include <sys/exec.h>
42 #include <sys/exec_elf.h>
43 #include <sys/reboot.h>
44 
45 #include <machine/emipsreg.h>
46 
47 #include "common.h"
48 #include "bootinfo.h"
49 #include "start.h"
50 #include "prom_iface.h"
51 
52 #if _DEBUG
53 #define TRACE(x) printf x
54 #else
55 #define TRACE(x)
56 #endif
57 
58 void epmc_halt(void);
59 void save_locore(void);
60 void restore_locore(void);
61 
62 static void *nope(void) {return NULL;}
63 int getchar(void){return GetChar();}
64 
65 static void
66 real_halt(void *arg)
67 {
68     int howto = (int)arg;
69     u_int ps = GetPsr();
70 
71     /* Turn off interrupts and the TLB */
72 #define EMIPS_SR_RP  0x08000000  /* reduced power */
73 #define EMIPS_SR_TS  0x00200000  /* TLB shutdown  */
74 #define EMIPS_SR_RST 0x00000080  /* Soft-reset    */
75 #define EMIPS_SR_INT 0x0000ff00  /* Interrupt enable mask */
76 #define EMIPS_SR_IEc 0x00000001  /* Interrupt enable current */
77 
78     ps &= ~(EMIPS_SR_INT | EMIPS_SR_IEc);
79     ps |= EMIPS_SR_TS;
80     SetPsr(ps);
81 
82     /* Reset entry must be restored for reboot
83      */
84     restore_locore();
85 
86     /* Tell the power manager to halt? */
87     for (;howto & RB_HALT;) {
88         epmc_halt();
89 
90         /* We should not be here!! */
91         ps |= EMIPS_SR_RP | EMIPS_SR_INT; /* but not current */
92         SetPsr(ps);
93     }
94 
95     /* For a reboot, all we can really do is a reset actually */
96     for (;;) {
97         ps |= EMIPS_SR_RST;
98         SetPsr(ps);
99     }
100 }
101 
102 static void
103 halt(int *unused, int howto)
104 {
105     /* We must switch to a safe stack! TLB will go down
106      */
107     switch_stack_and_call((void *)howto,real_halt);
108     /* no return, stack lost */
109 }
110 
111 struct callback cb = {
112     nope,
113     nope,
114     nope,
115     nope,
116     nope,
117     nope,
118     nope,
119     nope,
120     nope,
121     getchar,
122     nope,
123     nope,
124     printf,
125     nope,
126     nope,
127     nope,
128     nope,
129     nope,
130     nope,
131     nope,
132     nope,
133     nope,
134     nope,
135     nope,
136     nope,
137     nope,
138     nope,
139     nope,
140     nope,
141     nope,
142     nope,
143     nope,
144     getsysid,
145     nope,
146     nope,
147     nope,
148     nope,
149     nope,
150     nope,
151     halt
152 };
153 
154 typedef char *string_t;
155 
156 void epmc_halt(void)
157 {
158     struct _Pmc *pm = (struct _Pmc *)0xfff00000;
159 
160     pm->SystemPowerDisable = PMCSC_CPU;
161 }
162 
163 
164 int init_usart(void)
165 {
166     struct _Usart *us = (struct _Usart *)0xfff90000;
167 
168     us->Baud = 0x29;
169     us->Control = (USC_RXEN|USC_TXEN|USC_BPC_8|USC_NONE|USC_1STOP|USC_CLKDIV_4);
170     return 1;
171 }
172 
173 /* Need to scan the PMT for all memory controllers
174  * Actually.. just enough to make the kernel fit but we dont know how big it is
175  */
176 
177 /* Common format for SRAM, DDRAM, and FLASH controllers.
178  * Use SRAM decl. and careful about DDRAM that is twice as big.
179  */
180 typedef struct _Sram *ram_controller_t;
181 # define                RAMBT_TAG   SRAMBT_TAG
182 # define                RAMBT_BASE  SRAMBT_BASE
183 # define                RAMST_SIZE  SRAMST_SIZE
184 
185 int init_memory(void)
186 {
187     struct _Pmt *Pmt;
188     ram_controller_t Ram, Ours, First;
189     uint32_t base, addr, moi = (uint32_t)(&init_memory) & 0x3ffff000;
190     size_t size;
191     uint16_t tag;
192     int nsr, ndr, nfl;
193 
194     /* Make three passes.
195      * First find which controller we are running under, cuz we cant touch it.
196      * Then remap every RAM segment around it.
197      * Then make sure FLASH segments do not overlap RAM.
198      */
199 
200     nsr = ndr = nfl = 0;
201     First = Ours = NULL;
202     base = ~0;
203     for (Pmt = ThePmt;;Pmt--) {
204         tag = Pmt->Tag;
205         //printf("PMT @%x tag=%x\n",Pmt,tag);
206         switch (tag) {
207         case PMTTAG_END_OF_TABLE:
208             goto DoneFirst;
209         case PMTTAG_SRAM:
210         case PMTTAG_DDRAM:
211         case PMTTAG_FLASH:
212             Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
213             /* Scan the whole segment */
214             for (;;) {
215                 //printf("RAM @%x tag=%x ctl=%x\n", Ram, Ram->BaseAddressAndTag,Ram->Control);
216                 if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
217                     break;
218                 addr = Ram->BaseAddressAndTag & RAMBT_BASE;
219                 if ((tag != PMTTAG_FLASH) && (addr < base)) {
220                     base = addr;
221                     First = Ram;
222                 }
223                 size = Ram->Control & RAMST_SIZE;
224                 if ((moi >= addr) && (moi < (addr + size))) {
225                     Ours = Ram;
226                 }
227                 /* Next one.. and count them */
228                 Ram++;
229                 switch (tag) {
230                 case PMTTAG_SRAM:
231                     nsr++;
232                     break;
233                 case PMTTAG_FLASH:
234                     nfl++;
235                     break;
236                 case PMTTAG_DDRAM:
237                     Ram++; /* yeach */
238                     ndr++;
239                     break;
240                 }
241             }
242             break;
243         default:
244             break;
245         }
246     }
247 
248     /* Make sure we know */
249  DoneFirst:
250     if ((First == NULL) || (Ours == NULL)) {
251         printf("Bad memory layout (%p, %p), wont work.\n", First, Ours);
252         return 0;
253     }
254 
255     /* Second pass now */
256     base += First->BaseAddressAndTag & RAMBT_BASE;
257     for (Pmt = ThePmt;;Pmt--) {
258         tag = Pmt->Tag;
259         //printf("PMT @%x tag=%x\n",Pmt,tag);
260         switch (tag) {
261         case PMTTAG_END_OF_TABLE:
262             goto DoneSecond;
263         case PMTTAG_SRAM:
264         case PMTTAG_DDRAM:
265         case PMTTAG_FLASH:
266             Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
267             /* Scan the whole segment */
268             for (;;) {
269                 //printf("RAM @%x tag=%x ctl=%x\n", Ram, Ram->BaseAddressAndTag,Ram->Control);
270                 if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
271                     break;
272                 /* Leave us alone */
273                 if (Ram == Ours)
274                     goto Next;
275                 /* Leave the first alone too */
276                 if (Ram == First)
277                     goto Next;
278                 /* We do FLASH next round */
279                 if (tag == PMTTAG_FLASH)
280                     goto Next;
281 
282                 addr = Ram->BaseAddressAndTag & RAMBT_BASE;
283                 size = Ram->Control & RAMST_SIZE;
284 
285                 /* Dont make it overlap with us */
286                 if ((moi >= base) && (moi < (base + size)))
287                     base += Ours->Control & RAMST_SIZE;
288 
289                 if (addr != base) {
290                     printf("remapping %x+%x to %x\n", addr, size, base);
291                     Ram->BaseAddressAndTag = base;
292                 }
293                 base += size;
294 
295             Next:
296                 Ram++;
297                 if (tag == PMTTAG_DDRAM) Ram++; /* yeach */
298             }
299             break;
300         default:
301             break;
302         }
303     }
304  DoneSecond:
305 
306     /* Third pass now: FLASH */
307     for (Pmt = ThePmt;;Pmt--) {
308         tag = Pmt->Tag;
309         //printf("PMT @%x tag=%x\n",Pmt,tag);
310         switch (tag) {
311         case PMTTAG_END_OF_TABLE:
312             goto DoneThird;
313         case PMTTAG_FLASH:
314             Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
315             /* Scan the whole segment */
316             for (;;Ram++) {
317                 //printf("RAM @%x tag=%x ctl=%x\n", Ram, Ram->BaseAddressAndTag,Ram->Control);
318                 if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
319                     break;
320                 /* Leave us alone */
321                 if (Ram == Ours)
322                     continue;
323 
324                 addr = Ram->BaseAddressAndTag & RAMBT_BASE;
325                 size = Ram->Control & RAMST_SIZE;
326 
327                 /* No need to move if it does not overlap RAM */
328                 if (addr >= base)
329                     continue;
330 
331                 /* Ahi */
332                 printf("remapping FLASH %x+%x to %x\n", addr, size, base);
333                 Ram->BaseAddressAndTag = base;
334                 base += size;
335             }
336             break;
337         default:
338             break;
339         }
340     }
341 DoneThird:
342     return (nfl<<16) | (nsr << 8) | (ndr << 0);
343 }
344 
345 u_int startjump[2];
346 u_int exceptioncode[(0x200-0x080)/4]; /* Change if ExceptionHandlerEnd changes */
347 
348 void save_locore(void)
349 {
350     memcpy(startjump,start,sizeof startjump);
351     memcpy(exceptioncode,ExceptionHandler,sizeof exceptioncode);
352 }
353 
354 void restore_locore(void)
355 {
356     memcpy(start,startjump,sizeof startjump);
357     memcpy(ExceptionHandler,exceptioncode,sizeof exceptioncode);
358     /* BUGBUG flush icache */
359 }
360 
361 void call_kernel(uint32_t addr, char *kname, char *kargs, u_int bim, char *bip)
362 {
363     int argc = 0;
364     string_t argv[3];
365     int code = PROM_MAGIC;
366     struct callback * cv = &cb;
367 
368     /* Safeguard ourselves */
369     save_locore();
370 
371     if (kargs == NULL) kargs = "";
372     argv[0] = kname;
373     argv[1] = kargs;
374     argv[2] = NULL;
375     argc = 2;
376 
377     TRACE(("Geronimo(%x,%s %s)!\n",addr,kname,kargs));
378     ((void(*)(int,char**,int,struct callback *,u_int,char*))addr)
379            (argc,argv,code,cv,bim,bip);
380 }
381 
382