xref: /netbsd-src/sys/arch/emips/stand/common/prom_iface.c (revision fad88a189bc738ae57de078fa5bb457df7ffa219)
15f7e80a8Spooka /* Copyright (c) 1999 The NetBSD Foundation, Inc.
25f7e80a8Spooka  * All rights reserved.
35f7e80a8Spooka  *
45f7e80a8Spooka  * Copyright (c) 2008 Microsoft.  All rights reserved.
55f7e80a8Spooka  *
65f7e80a8Spooka  * Redistribution and use in source and binary forms, with or without
75f7e80a8Spooka  * modification, are permitted provided that the following conditions
85f7e80a8Spooka  * are met:
95f7e80a8Spooka  * 1. Redistributions of source code must retain the above copyright
105f7e80a8Spooka  *    notice, this list of conditions and the following disclaimer.
115f7e80a8Spooka  * 2. Redistributions in binary form must reproduce the above copyright
125f7e80a8Spooka  *    notice, this list of conditions and the following disclaimer in the
135f7e80a8Spooka  *    documentation and/or other materials provided with the distribution.
145f7e80a8Spooka  *
155f7e80a8Spooka  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
165f7e80a8Spooka  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
175f7e80a8Spooka  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
185f7e80a8Spooka  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
195f7e80a8Spooka  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
205f7e80a8Spooka  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
215f7e80a8Spooka  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
225f7e80a8Spooka  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
235f7e80a8Spooka  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
245f7e80a8Spooka  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
255f7e80a8Spooka  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
265f7e80a8Spooka  * POSSIBILITY OF SUCH DAMAGE.
275f7e80a8Spooka  */
285f7e80a8Spooka 
295f7e80a8Spooka #include <lib/libsa/stand.h>
305f7e80a8Spooka #include <lib/libsa/loadfile.h>
315f7e80a8Spooka #include <lib/libkern/libkern.h>
325f7e80a8Spooka 
335f7e80a8Spooka #include <sys/param.h>
345f7e80a8Spooka #include <sys/exec.h>
355f7e80a8Spooka #include <sys/exec_elf.h>
365f7e80a8Spooka #include <sys/reboot.h>
375f7e80a8Spooka 
385f7e80a8Spooka #include <machine/emipsreg.h>
395f7e80a8Spooka 
405f7e80a8Spooka #include "common.h"
415f7e80a8Spooka #include "bootinfo.h"
425f7e80a8Spooka #include "start.h"
435f7e80a8Spooka #include "prom_iface.h"
445f7e80a8Spooka 
455f7e80a8Spooka #if _DEBUG
465f7e80a8Spooka #define TRACE(x) printf x
475f7e80a8Spooka #else
485f7e80a8Spooka #define TRACE(x)
495f7e80a8Spooka #endif
505f7e80a8Spooka 
515f7e80a8Spooka void epmc_halt(void);
525f7e80a8Spooka void save_locore(void);
535f7e80a8Spooka void restore_locore(void);
545f7e80a8Spooka 
nope(void)5560d0010eSchristos static void *nope(void) {return NULL;}
getchar(void)565f7e80a8Spooka int getchar(void){return GetChar();}
575f7e80a8Spooka 
5860d0010eSchristos static void
real_halt(void * arg)5960d0010eSchristos real_halt(void *arg)
605f7e80a8Spooka {
615f7e80a8Spooka     int howto = (int)arg;
625f7e80a8Spooka     u_int ps = GetPsr();
635f7e80a8Spooka 
645f7e80a8Spooka     /* Turn off interrupts and the TLB */
655f7e80a8Spooka #define EMIPS_SR_RP  0x08000000  /* reduced power */
665f7e80a8Spooka #define EMIPS_SR_TS  0x00200000  /* TLB shutdown  */
675f7e80a8Spooka #define EMIPS_SR_RST 0x00000080  /* Soft-reset    */
685f7e80a8Spooka #define EMIPS_SR_INT 0x0000ff00  /* Interrupt enable mask */
695f7e80a8Spooka #define EMIPS_SR_IEc 0x00000001  /* Interrupt enable current */
705f7e80a8Spooka 
715f7e80a8Spooka     ps &= ~(EMIPS_SR_INT | EMIPS_SR_IEc);
725f7e80a8Spooka     ps |= EMIPS_SR_TS;
735f7e80a8Spooka     SetPsr(ps);
745f7e80a8Spooka 
755f7e80a8Spooka     /* Reset entry must be restored for reboot
765f7e80a8Spooka      */
775f7e80a8Spooka     restore_locore();
785f7e80a8Spooka 
795f7e80a8Spooka     /* Tell the power manager to halt? */
805f7e80a8Spooka     for (;howto & RB_HALT;) {
815f7e80a8Spooka         epmc_halt();
825f7e80a8Spooka 
835f7e80a8Spooka         /* We should not be here!! */
845f7e80a8Spooka         ps |= EMIPS_SR_RP | EMIPS_SR_INT; /* but not current */
855f7e80a8Spooka         SetPsr(ps);
865f7e80a8Spooka     }
875f7e80a8Spooka 
885f7e80a8Spooka     /* For a reboot, all we can really do is a reset actually */
895f7e80a8Spooka     for (;;) {
905f7e80a8Spooka         ps |= EMIPS_SR_RST;
915f7e80a8Spooka         SetPsr(ps);
925f7e80a8Spooka     }
935f7e80a8Spooka }
945f7e80a8Spooka 
9560d0010eSchristos static void
halt(int * unused,int howto)9660d0010eSchristos halt(int *unused, int howto)
975f7e80a8Spooka {
985f7e80a8Spooka     /* We must switch to a safe stack! TLB will go down
995f7e80a8Spooka      */
1005f7e80a8Spooka     switch_stack_and_call((void *)howto,real_halt);
1015f7e80a8Spooka     /* no return, stack lost */
1025f7e80a8Spooka }
1035f7e80a8Spooka 
1045f7e80a8Spooka struct callback cb = {
1055f7e80a8Spooka     nope,
1065f7e80a8Spooka     nope,
1075f7e80a8Spooka     nope,
1085f7e80a8Spooka     nope,
1095f7e80a8Spooka     nope,
1105f7e80a8Spooka     nope,
1115f7e80a8Spooka     nope,
1125f7e80a8Spooka     nope,
1135f7e80a8Spooka     nope,
1145f7e80a8Spooka     getchar,
1155f7e80a8Spooka     nope,
1165f7e80a8Spooka     nope,
1175f7e80a8Spooka     printf,
1185f7e80a8Spooka     nope,
1195f7e80a8Spooka     nope,
1205f7e80a8Spooka     nope,
1215f7e80a8Spooka     nope,
1225f7e80a8Spooka     nope,
1235f7e80a8Spooka     nope,
1245f7e80a8Spooka     nope,
1255f7e80a8Spooka     nope,
1265f7e80a8Spooka     nope,
1275f7e80a8Spooka     nope,
1285f7e80a8Spooka     nope,
1295f7e80a8Spooka     nope,
1305f7e80a8Spooka     nope,
1315f7e80a8Spooka     nope,
1325f7e80a8Spooka     nope,
1335f7e80a8Spooka     nope,
1345f7e80a8Spooka     nope,
1355f7e80a8Spooka     nope,
1365f7e80a8Spooka     nope,
1375f7e80a8Spooka     getsysid,
1385f7e80a8Spooka     nope,
1395f7e80a8Spooka     nope,
1405f7e80a8Spooka     nope,
1415f7e80a8Spooka     nope,
1425f7e80a8Spooka     nope,
1435f7e80a8Spooka     nope,
1445f7e80a8Spooka     halt
1455f7e80a8Spooka };
1465f7e80a8Spooka 
1475f7e80a8Spooka typedef char *string_t;
1485f7e80a8Spooka 
epmc_halt(void)1495f7e80a8Spooka void epmc_halt(void)
1505f7e80a8Spooka {
1515f7e80a8Spooka     struct _Pmc *pm = (struct _Pmc *)0xfff00000;
1525f7e80a8Spooka 
1535f7e80a8Spooka     pm->SystemPowerDisable = PMCSC_CPU;
1545f7e80a8Spooka }
1555f7e80a8Spooka 
1565f7e80a8Spooka 
init_usart(void)1575f7e80a8Spooka int init_usart(void)
1585f7e80a8Spooka {
1595f7e80a8Spooka     struct _Usart *us = (struct _Usart *)0xfff90000;
1605f7e80a8Spooka 
1615f7e80a8Spooka     us->Baud = 0x29;
1625f7e80a8Spooka     us->Control = (USC_RXEN|USC_TXEN|USC_BPC_8|USC_NONE|USC_1STOP|USC_CLKDIV_4);
1635f7e80a8Spooka     return 1;
1645f7e80a8Spooka }
1655f7e80a8Spooka 
1665f7e80a8Spooka /* Need to scan the PMT for all memory controllers
1675f7e80a8Spooka  * Actually.. just enough to make the kernel fit but we dont know how big it is
1685f7e80a8Spooka  */
1695f7e80a8Spooka 
1705f7e80a8Spooka /* Common format for SRAM, DDRAM, and FLASH controllers.
1715f7e80a8Spooka  * Use SRAM decl. and careful about DDRAM that is twice as big.
1725f7e80a8Spooka  */
1735f7e80a8Spooka typedef struct _Sram *ram_controller_t;
1745f7e80a8Spooka # define                RAMBT_TAG   SRAMBT_TAG
1755f7e80a8Spooka # define                RAMBT_BASE  SRAMBT_BASE
1765f7e80a8Spooka # define                RAMST_SIZE  SRAMST_SIZE
1775f7e80a8Spooka 
init_memory(void)1785f7e80a8Spooka int init_memory(void)
1795f7e80a8Spooka {
1805f7e80a8Spooka     struct _Pmt *Pmt;
1815f7e80a8Spooka     ram_controller_t Ram, Ours, First;
1825f7e80a8Spooka     uint32_t base, addr, moi = (uint32_t)(&init_memory) & 0x3ffff000;
1835f7e80a8Spooka     size_t size;
1845f7e80a8Spooka     uint16_t tag;
1855f7e80a8Spooka     int nsr, ndr, nfl;
1865f7e80a8Spooka 
1875f7e80a8Spooka     /* Make three passes.
1885f7e80a8Spooka      * First find which controller we are running under, cuz we cant touch it.
1895f7e80a8Spooka      * Then remap every RAM segment around it.
1905f7e80a8Spooka      * Then make sure FLASH segments do not overlap RAM.
1915f7e80a8Spooka      */
1925f7e80a8Spooka 
1935f7e80a8Spooka     nsr = ndr = nfl = 0;
1945f7e80a8Spooka     First = Ours = NULL;
1955f7e80a8Spooka     base = ~0;
1965f7e80a8Spooka     for (Pmt = ThePmt;;Pmt--) {
1975f7e80a8Spooka         tag = Pmt->Tag;
1985f7e80a8Spooka         //printf("PMT @%x tag=%x\n",Pmt,tag);
1995f7e80a8Spooka         switch (tag) {
2005f7e80a8Spooka         case PMTTAG_END_OF_TABLE:
2015f7e80a8Spooka             goto DoneFirst;
2025f7e80a8Spooka         case PMTTAG_SRAM:
2035f7e80a8Spooka         case PMTTAG_DDRAM:
2045f7e80a8Spooka         case PMTTAG_FLASH:
2055f7e80a8Spooka             Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
2065f7e80a8Spooka             /* Scan the whole segment */
2075f7e80a8Spooka             for (;;) {
2085f7e80a8Spooka                 //printf("RAM @%x tag=%x ctl=%x\n", Ram, Ram->BaseAddressAndTag,Ram->Control);
2095f7e80a8Spooka                 if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
2105f7e80a8Spooka                     break;
2115f7e80a8Spooka                 addr = Ram->BaseAddressAndTag & RAMBT_BASE;
2125f7e80a8Spooka                 if ((tag != PMTTAG_FLASH) && (addr < base)) {
2135f7e80a8Spooka                     base = addr;
2145f7e80a8Spooka                     First = Ram;
2155f7e80a8Spooka                 }
2165f7e80a8Spooka                 size = Ram->Control & RAMST_SIZE;
2175f7e80a8Spooka                 if ((moi >= addr) && (moi < (addr + size))) {
2185f7e80a8Spooka                     Ours = Ram;
2195f7e80a8Spooka                 }
2205f7e80a8Spooka                 /* Next one.. and count them */
2215f7e80a8Spooka                 Ram++;
2225f7e80a8Spooka                 switch (tag) {
2235f7e80a8Spooka                 case PMTTAG_SRAM:
2245f7e80a8Spooka                     nsr++;
2255f7e80a8Spooka                     break;
2265f7e80a8Spooka                 case PMTTAG_FLASH:
2275f7e80a8Spooka                     nfl++;
2285f7e80a8Spooka                     break;
2295f7e80a8Spooka                 case PMTTAG_DDRAM:
2305f7e80a8Spooka                     Ram++; /* yeach */
2315f7e80a8Spooka                     ndr++;
2325f7e80a8Spooka                     break;
2335f7e80a8Spooka                 }
2345f7e80a8Spooka             }
2355f7e80a8Spooka             break;
2365f7e80a8Spooka         default:
2375f7e80a8Spooka             break;
2385f7e80a8Spooka         }
2395f7e80a8Spooka     }
2405f7e80a8Spooka 
2415f7e80a8Spooka     /* Make sure we know */
2425f7e80a8Spooka  DoneFirst:
2435f7e80a8Spooka     if ((First == NULL) || (Ours == NULL)) {
244d1e515adSmartin         printf("Bad memory layout (%p, %p), wont work.\n", First, Ours);
2455f7e80a8Spooka         return 0;
2465f7e80a8Spooka     }
2475f7e80a8Spooka 
2485f7e80a8Spooka     /* Second pass now */
2495f7e80a8Spooka     base += First->BaseAddressAndTag & RAMBT_BASE;
2505f7e80a8Spooka     for (Pmt = ThePmt;;Pmt--) {
2515f7e80a8Spooka         tag = Pmt->Tag;
2525f7e80a8Spooka         //printf("PMT @%x tag=%x\n",Pmt,tag);
2535f7e80a8Spooka         switch (tag) {
2545f7e80a8Spooka         case PMTTAG_END_OF_TABLE:
2555f7e80a8Spooka             goto DoneSecond;
2565f7e80a8Spooka         case PMTTAG_SRAM:
2575f7e80a8Spooka         case PMTTAG_DDRAM:
2585f7e80a8Spooka         case PMTTAG_FLASH:
2595f7e80a8Spooka             Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
2605f7e80a8Spooka             /* Scan the whole segment */
2615f7e80a8Spooka             for (;;) {
2625f7e80a8Spooka                 //printf("RAM @%x tag=%x ctl=%x\n", Ram, Ram->BaseAddressAndTag,Ram->Control);
2635f7e80a8Spooka                 if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
2645f7e80a8Spooka                     break;
2655f7e80a8Spooka                 /* Leave us alone */
2665f7e80a8Spooka                 if (Ram == Ours)
2675f7e80a8Spooka                     goto Next;
2685f7e80a8Spooka                 /* Leave the first alone too */
2695f7e80a8Spooka                 if (Ram == First)
2705f7e80a8Spooka                     goto Next;
2715f7e80a8Spooka                 /* We do FLASH next round */
2725f7e80a8Spooka                 if (tag == PMTTAG_FLASH)
2735f7e80a8Spooka                     goto Next;
2745f7e80a8Spooka 
2755f7e80a8Spooka                 addr = Ram->BaseAddressAndTag & RAMBT_BASE;
2765f7e80a8Spooka                 size = Ram->Control & RAMST_SIZE;
2775f7e80a8Spooka 
2785f7e80a8Spooka                 /* Dont make it overlap with us */
2795f7e80a8Spooka                 if ((moi >= base) && (moi < (base + size)))
2805f7e80a8Spooka                     base += Ours->Control & RAMST_SIZE;
2815f7e80a8Spooka 
2825f7e80a8Spooka                 if (addr != base) {
283*88c859a1Sdholland                     printf("remapping %x+%zx to %x\n", addr, size, base);
2845f7e80a8Spooka                     Ram->BaseAddressAndTag = base;
2855f7e80a8Spooka                 }
2865f7e80a8Spooka                 base += size;
2875f7e80a8Spooka 
2885f7e80a8Spooka             Next:
2895f7e80a8Spooka                 Ram++;
2905f7e80a8Spooka                 if (tag == PMTTAG_DDRAM) Ram++; /* yeach */
2915f7e80a8Spooka             }
2925f7e80a8Spooka             break;
2935f7e80a8Spooka         default:
2945f7e80a8Spooka             break;
2955f7e80a8Spooka         }
2965f7e80a8Spooka     }
2975f7e80a8Spooka  DoneSecond:
2985f7e80a8Spooka 
2995f7e80a8Spooka     /* Third pass now: FLASH */
3005f7e80a8Spooka     for (Pmt = ThePmt;;Pmt--) {
3015f7e80a8Spooka         tag = Pmt->Tag;
3025f7e80a8Spooka         //printf("PMT @%x tag=%x\n",Pmt,tag);
3035f7e80a8Spooka         switch (tag) {
3045f7e80a8Spooka         case PMTTAG_END_OF_TABLE:
3055f7e80a8Spooka             goto DoneThird;
3065f7e80a8Spooka         case PMTTAG_FLASH:
3075f7e80a8Spooka             Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
3085f7e80a8Spooka             /* Scan the whole segment */
3095f7e80a8Spooka             for (;;Ram++) {
3105f7e80a8Spooka                 //printf("RAM @%x tag=%x ctl=%x\n", Ram, Ram->BaseAddressAndTag,Ram->Control);
3115f7e80a8Spooka                 if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
3125f7e80a8Spooka                     break;
3135f7e80a8Spooka                 /* Leave us alone */
3145f7e80a8Spooka                 if (Ram == Ours)
3155f7e80a8Spooka                     continue;
3165f7e80a8Spooka 
3175f7e80a8Spooka                 addr = Ram->BaseAddressAndTag & RAMBT_BASE;
3185f7e80a8Spooka                 size = Ram->Control & RAMST_SIZE;
3195f7e80a8Spooka 
3205f7e80a8Spooka                 /* No need to move if it does not overlap RAM */
3215f7e80a8Spooka                 if (addr >= base)
3225f7e80a8Spooka                     continue;
3235f7e80a8Spooka 
3245f7e80a8Spooka                 /* Ahi */
3255f7e80a8Spooka                 printf("remapping FLASH %x+%x to %x\n", addr, size, base);
3265f7e80a8Spooka                 Ram->BaseAddressAndTag = base;
3275f7e80a8Spooka                 base += size;
3285f7e80a8Spooka             }
3295f7e80a8Spooka             break;
3305f7e80a8Spooka         default:
3315f7e80a8Spooka             break;
3325f7e80a8Spooka         }
3335f7e80a8Spooka     }
3345f7e80a8Spooka DoneThird:
3355f7e80a8Spooka     return (nfl<<16) | (nsr << 8) | (ndr << 0);
3365f7e80a8Spooka }
3375f7e80a8Spooka 
3385f7e80a8Spooka u_int startjump[2];
3395f7e80a8Spooka u_int exceptioncode[(0x200-0x080)/4]; /* Change if ExceptionHandlerEnd changes */
3405f7e80a8Spooka 
save_locore(void)3415f7e80a8Spooka void save_locore(void)
3425f7e80a8Spooka {
3435f7e80a8Spooka     memcpy(startjump,start,sizeof startjump);
3445f7e80a8Spooka     memcpy(exceptioncode,ExceptionHandler,sizeof exceptioncode);
3455f7e80a8Spooka }
3465f7e80a8Spooka 
restore_locore(void)3475f7e80a8Spooka void restore_locore(void)
3485f7e80a8Spooka {
3495f7e80a8Spooka     memcpy(start,startjump,sizeof startjump);
3505f7e80a8Spooka     memcpy(ExceptionHandler,exceptioncode,sizeof exceptioncode);
3515f7e80a8Spooka     /* BUGBUG flush icache */
3525f7e80a8Spooka }
3535f7e80a8Spooka 
call_kernel(uint32_t addr,char * kname,char * kargs,u_int bim,char * bip)3545f7e80a8Spooka void call_kernel(uint32_t addr, char *kname, char *kargs, u_int bim, char *bip)
3555f7e80a8Spooka {
3565f7e80a8Spooka     int argc = 0;
3575f7e80a8Spooka     string_t argv[3];
3585f7e80a8Spooka     int code = PROM_MAGIC;
3595f7e80a8Spooka     struct callback * cv = &cb;
3605f7e80a8Spooka 
3615f7e80a8Spooka     /* Safeguard ourselves */
3625f7e80a8Spooka     save_locore();
3635f7e80a8Spooka 
3645f7e80a8Spooka     if (kargs == NULL) kargs = "";
3655f7e80a8Spooka     argv[0] = kname;
3665f7e80a8Spooka     argv[1] = kargs;
3675f7e80a8Spooka     argv[2] = NULL;
3685f7e80a8Spooka     argc = 2;
3695f7e80a8Spooka 
3705f7e80a8Spooka     TRACE(("Geronimo(%x,%s %s)!\n",addr,kname,kargs));
3715f7e80a8Spooka     ((void(*)(int,char**,int,struct callback *,u_int,char*))addr)
3725f7e80a8Spooka            (argc,argv,code,cv,bim,bip);
3735f7e80a8Spooka }
3745f7e80a8Spooka 
375