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