1
0
Files
2022-09-29 17:59:04 +03:00

1391 lines
33 KiB
C

/**************************************************************************
* *
* Copyright (C) 1996, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#if defined(IP32SIM)
#define Sim 1
#else
#undef Sim
#endif
#include <arcs/hinv.h>
#include <sys/cpu.h>
#include <sys/sbd.h>
#include <sys/crime.h>
#include <sys/sema.h>
#include <sys/gfx.h>
#include <sys/mace.h>
#include <sys/IP32flash.h>
#include <sys/ds17287.h>
#include <sys/param.h>
#include <arcs/folder.h>
#include <arcs/cfgtree.h>
#include <fault.h>
#include <assert.h>
#include <libsc.h>
#include <trace.h>
#include <flash.h>
#include <sys/types.h>
#include <sys/debug.h>
#if 0
#include <sys/systm.h> /* for us_delay() */
#include <sys/param.h> /* for DELAY() */
#endif
#include <sys/crime.h> /* from irix/kern, for CRM_BASEADDR */
#include <sys/crimedef.h>
#include <sys/crimereg.h>
#include <sys/crime_gfx.h>
#include <sys/crime_gbe.h>
#include <sys/mips_addrspace.h> /* for PHYS_TO_K1 */
#include <hw_copy.h>
#include <crm_stand.h>
#if !defined(__inttypes_INCLUDED)
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
typedef unsigned long long int uintmax_t;
typedef unsigned long int uintptr_t;
typedef signed long long int int64_t;
#endif
extern unsigned _dcache_size;
extern unsigned _icache_size;
extern unsigned _sidcache_size;
extern unsigned _dcache_linesize;
extern unsigned _icache_linesize;
extern unsigned _scache_linesize;
extern unsigned _r4600sc_sidcache_size;
extern __dcache_inval(void*,int);
extern void ds2502_get_eaddr(char*) ;
extern void DPRINTF (char *, ...) ;
extern void usecwait(int);
extern void us_delay(int);
extern void flushbus(void);
extern int ticksper1024inst(void);
extern int cpuclkper100ticks(unsigned int*);
unsigned int cpu_get_memsize(void);
void cpu_mem_init (void);
extern uint32_t r4k_getticker(void);
#if 0
#define C0_IMP_R10000 0x9
#endif
extern struct gbechip *crm_GBE_Base;
extern int i2cfp_PanelOff(struct gbechip *);
extern int usingFlatPanel;
/*****************************************************************************
* Misc. IP32 routines *
*****************************************************************************/
#if 0
int cachewrback = 1; /* Mark cache as writeback */
#endif
/*****************************************************************************
* Misc. IP32 cpu_xxx routines *
*****************************************************************************/
/*************
* cpu_errputc
*------------
* Call appropriate errputc.
*/
void
cpu_errputc(char c)
{
extern void mace_errputc(char);
mace_errputc(c);
}
/*************
* cpu_acpanic
*------------
*/
void
cpu_acpanic(char * str)
{
printf("Cannot malloc %s component of config tree.\n",str);
printf("Incomplete config tree -- cannot continue.\n");
}
/******************
* cpu_get_disp_str
*-----------------
* Return display path
*/
char*
cpu_get_disp_str(void)
{
return "video()";
}
/****************
* cpu_get_serial
*---------------
* Return serial path
*/
char*
cpu_get_serial(void)
{
return "serial(0)";
}
/*****************
* cpu_get_kbd_str
*----------------
* Return keyboard path
*/
char*
cpu_get_kbd_str(void)
{
return "keyboard()";
}
/***************
* cpu_get_mouse
*--------------
*/
char*
cpu_get_mouse(void)
{
return "pointer()";
}
/***************
* cpu_get_eaddr
*--------------
* Return sether address in the form of
* 0800aabbccdd (08:00:aa:bb:cc:dd)
*/
void
cpu_get_eaddr(char* eaddr)
{
ds2502_get_eaddr(eaddr) ;
return ;
}
/******
* htoa
*-----
* convert 4 digit hex numbet to ascii
*/
char
htoa(short digit)
{
char num ;
if (digit > 9)
num = (digit - 10) + 0x61 ;
else
num = digit + 0x30 ;
return num ;
}
/*******************
* cpu_get_eaddr_str
*------------------
* Return sether address in the form of
* 0800aabbccdd (08:00:aa:bb:cc:dd)
*/
void
cpu_get_eaddr_str(char* eaddr)
{
unsigned char addr [6], tmp ;
int idx1, idx2 ;
ds2502_get_eaddr(addr) ;
for (idx1=0,idx2=0; idx2<6; idx1+=3,idx2+=1) {
eaddr[idx1] = htoa((addr[idx2] & 0xf0)>> 4) ;
eaddr[idx1+1] = htoa(addr[idx2] & 0x0f) ;
if (idx1 < 15) eaddr[idx1+2] = ':' ;
}
return ;
}
extern void crm_hardreset(void);
extern void crm_softreset(void);
/***************
* cpu_hardreset
* -------------
* Write to crime control register hardreset bit
* to cause system wide hardreset.
*/
void
cpu_hardreset(void)
{
crm_hardreset() ;
panic ("cpu_harreset: Can not reset the system\n");
}
/***************
* cpu_softreset
* -------------
* Write to crime control register softreset bit
* to cause system wide softreset.
*/
void
cpu_softreset(void)
{
crm_softreset();
panic ("cpu_softreset: Can not reset the system\n");
}
/***********
* cpu_reset
* ---------
* This function was called by _init_saio to initialize
* MP spinlock subsystem, we'll have to figure this out for
* MP MOOSEHEAD system. For now simply return is sufficient.
*/
void
cpu_reset(void)
{
return;
}
/**********
* rtc_init
* --------
* make sure the clock is in the right mode:
* Kickstart and wakeup flags cleared
* Kickstart interrupt enabled
* Wakeup interrupt disabled
*/
extern int _rtcinitted ;
void
cpu_rtcinit(void)
{
volatile register ds17287_clk_t *clock = RTDS_CLOCK_ADDR;
int rega;
rega = clock->registera & ~DS_REGA_DV2; /* clear rega dv2 */
rega |= DS_REGA_DV1; /* set rega dv1 */
clock->registera = rega | DS_REGA_DV0; /* select bank1 */
flushbus();
clock->ram[DS_BANK1_XCTRLB] &= ~DS_XCTRLB_WIE;
clock->ram[DS_BANK1_XCTRLB] |= (DS_XCTRLB_KSE|DS_XCTRLB_ABE);
clock->ram[DS_BANK1_XCTRLA] &= ~(DS_XCTRLA_KF|DS_XCTRLA_WF);
clock->registera &= ~DS_REGA_DV0;
flushbus();
_rtcinitted = 1;
return ;
}
/***************
* cpu_powerdown
* -------------
* shut down the power supply. Dallas docs indicate that the following
* conditions must hold for kickstart to work:
*
* dv 2/1/0 in register a must have a value of 01xb
* ((kf & kse) != 1) && ((wf & wie) != 1)
* kse == 1 to enable powerup via the power switch
*
* I make sure that these conditions hold here and then set pab to 1
* which should shutdown the power supply.
*/
extern int _rtcinitted ;
void
cpu_powerdown(int setwie)
{
volatile register ds17287_clk_t *clock = RTDS_CLOCK_ADDR;
int rega;
rega = clock->registera & ~DS_REGA_DV2; /* clear rega dv2 */
rega |= DS_REGA_DV1; /* set dv1, and set DV0 to select bank1 */
while (1) {
clock->registera = rega | DS_REGA_DV0;
flushbus();
if (setwie != 0x0)
clock->ram[DS_BANK1_XCTRLB] |= DS_XCTRLB_WIE|DS_XCTRLB_ABE|DS_XCTRLB_KSE;
else {
clock->ram[DS_BANK1_XCTRLB] &= ~DS_XCTRLB_WIE;
clock->ram[DS_BANK1_XCTRLB] |= DS_XCTRLB_ABE|DS_XCTRLB_KSE;
}
do {
#if defined(DEBUG)
_rtcinitted = 0; /* turned off the scandev checking. */
printf (" *** Clearing the KF and WF flags ***\n");
#endif
clock->ram[DS_BANK1_XCTRLA] &= ~(DS_XCTRLA_KF|DS_XCTRLA_WF);
flushbus();
DELAY(1000000);
} while((clock->ram[DS_BANK1_XCTRLA] & (DS_XCTRLA_KF|DS_XCTRLA_WF))!=0) ;
if (usingFlatPanel)
{
i2cfp_PanelOff( crm_GBE_Base );
}
clock->ram[DS_BANK1_XCTRLA] |= DS_XCTRLA_PAB; /* shut down power */
clock->registera = rega;
flushbus();
DELAY(1000000);
printf(" *** Power supply did not shut down ***\n");
DELAY(1000000);
}
}
/**************
* cpu_scandevs
* ------------
* Check the power switch once a while and turn the power off
* if power switch interrupt was detected.
*/
void
cpu_scandevs(void)
{
volatile register ds17287_clk_t *clock = RTDS_CLOCK_ADDR;
int xctrla;
/*
* Check the power switch.
*/
if (_rtcinitted) {
if ((clock->registerc & DS_REGC_IRQF) != 0x0) {
/* clear interrupt condition */
clock->registera |= DS_REGA_DV0;
flushbus();
xctrla = clock->ram[DS_BANK1_XCTRLA];
clock->ram[DS_BANK1_XCTRLA] &= ~(DS_XCTRLA_KF|DS_XCTRLA_WF);
clock->registera &= ~DS_REGA_DV0;
flushbus();
if ((xctrla & DS_XCTRLA_KF) != 0x0) {
#if defined(DEBUG)
printf ("System power off interrupt detected\n");
#endif
cpu_powerdown (0);
}
#if defined(DEBUG)
else {
/* Ignore all rest of interrupt conditions. !? */
printf ("RTC irq received w/o kickstart condition.\n");
printf ("Clock interrupt status %x\n", xctrla);
}
#endif
}
}
return ;
}
/*****************************************************************************
* IP32 CPU frequency related stuff. *
*****************************************************************************/
/*
* this is the table of known cpu freq that we support
* table is in the order of increasing freq.
* (Found in the kern tree).
*/
static int freq[] = {
1000000,
2000000,
4000000,
8000000,
12000000,
16000000,
20000000,
25000000,
30000000,
33000000,
36000000,
40000000,
50000000,
66666000, /* round to 1000 so we get integer divide */
75000000,
87370000,
90000000,
97500000,
100000000,
120000000
} ;
/*
* following routines are in IP32kasm.s
*/
#ifdef MASTER_FREQ
#undef MASTER_FREQ
#endif
#define MASTER_FREQ 66000000 /* Crime upcounter frequency */
/********************
* cpu_get_freq(void)
*-------------------
* find the frequency of the running CPU
* was findcpufreq_raw() in kern tree.
*-------------------
* NOTE:::
* This routine works if we are running in cached
* mode, so please check config register before jump
* on conclusion that this routine does not work.
*/
int
cpu_get_freq(void)
{
int ticks;
int i, closest,tmp,clock, freq_ret;
int fcount= 0;
int freqtbl_siz = sizeof(freq) / sizeof(int);
unsigned int cpu_count, tick_count;
cpu_count = cpuclkper100ticks(&tick_count);
/* do division first to avoid overflow */
ticks = cpu_count * (MASTER_FREQ / tick_count); /* to HZ */
closest = -1;
for (i=0; i<(sizeof(freq)/sizeof(int)); i++) {
if ( ticks > freq[i] )
tmp = ticks - freq[i];
else
tmp = freq[i] - ticks;
if ( closest == -1 ) {
clock = i;
closest = tmp;
continue;
}
if ( tmp < closest ) {
closest = tmp;
clock = i;
}
}
freq_ret = freq[clock];
/*
* if the calculated freq is greater than the max that we know about
* and if the margin is more than 4Mhz then lets use the calculated
* freq instead of rounding it down to what's in the table
*/
if (ticks > freq[freqtbl_siz-1] &&
(ticks - freq[freqtbl_siz-1]) > 4000000)
freq_ret = ticks;
return(freq_ret);
}
/************************
* cpu_get_freq_str(void)
*-----------------------
* return cpu freq in ascii string format
*-------------------
*/
char *
cpu_get_freq_str(void)
{
static char cpu_freq_str[4]; /* Seems big enough for now! */
int freq = ((cpu_get_freq()*2)/1000000);
sprintf(&cpu_freq_str[0],"%d", freq);
return &cpu_freq_str[0];
}
/********************
* GetRelativeTime(void)
*-------------------
* The IP32 version use T5/R5K internal free runnung counter. If
* the time between calls is longer than a single overflow of the
* counter, then this won't be accurate. If you want to time
* something that takes a real long time, then make sure this
* gets called periodically, or use the GetTime() function.
*-------------------
*/
uint32_t
GetRelativeTime(void)
{
static int lasttime; /* last returned value */
static unsigned cummdelta; /* cummulative fraction of a sec. */
static unsigned lasttick; /* last value of count register */
static int tickhz; /* ticker speed in Hz */
unsigned thistick; /* current value of count register */
if ( ! lasttick ) {
tickhz = cpu_get_freq() ;
lasttick = r4k_getticker();
return 0;
}
thistick = r4k_getticker();
if ( thistick < lasttick )
cummdelta += (0xffffffff - lasttick) + thistick;
else
cummdelta += thistick - lasttick;
lasttick = thistick;
while ( cummdelta > tickhz ) {
cummdelta -= tickhz;
lasttime += 1;
}
return lasttime;
}
#if 0
int
findcpufreq(void)
{
return(findcpufreq_raw()/1000000);
}
#endif
/*****************************************************************************
* IP32 FLASH routines *
*****************************************************************************/
/*
* these defines ought to be in a header file, well, later ...
*/
#if !defined(Sim)
#define FWriteWait 2048
#else
#define FWriteWait 4
#endif
#define FSecSize 256
/************
* flashWrite
* ----------
* Write a long to FLASH
* Note:::
* we assume that the caller know what he is doing,
* the flash can only be update in a sector base, and the
* the write have to be sequentally done for all 256 bytes -
* the whole sector.
* ----------
*/
static void
flashWrite(long* ptr, long data, long* bytecount)
{
register int byteidx ;
register long bytewritten = *bytecount ;
register unsigned char currChar ;
volatile unsigned char *dst = (unsigned char*)ptr ;
for (byteidx = 24 ; byteidx >= 0 ; byteidx -= 8, dst++) {
*dst = currChar = (unsigned char) ((data >> byteidx) & 0xff) ;
bytewritten += 1 ;
while (bytewritten == FSecSize) {
/* have to loop here until flash is happy */
for (bytewritten = FWriteWait; bytewritten > 0; bytewritten -= 1) ;
if (*dst != currChar)
bytewritten = FSecSize ;
else {
bytewritten = 0 ;
break ;
}
}
}
/* Update the bytecount and return. */
*bytecount = bytewritten ;
return ;
}
/************
* flashFlush
* ----------
* Flush write to flash
* ----------
*/
static void
flashFlush(void)
{}
/*************
* flashEnable
* -----------
* Enable writes to the flash
* -----------
*/
static void
flashEnable(int e)
{
long long *fe = (long long*)PHYS_TO_K1(ISA_FLASH_NIC_REG);
if (e)
*fe |= ISA_FLASH_WE;
else
*fe &= ~ISA_FLASH_WE;
}
/*
* Environment variable FLASH object (the only one we have for IP32).
*/
FlashROM envFlash = {
(FlashSegment*)PHYS_TO_K1(FLASH_PHYS_BASE),
(FlashSegment*)PHYS_TO_K1(FLASH_PHYS_BASE+FLASH_SIZE),
FLASH_PAGE_SIZE,
FLASH_SIZE,
flashWrite,
flashFlush,
flashEnable,
};
/*****************************************************************************
* IP32 specific configuration data *
*****************************************************************************/
#define SYSBOARDID "SGI-IP32"
#define SYSBOARDIDLEN 9
static COMPONENT IP32tmpl = {
SystemClass, /* Class */
ARC, /* Type */
0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0, /* Affinity */
0, /* ConfigurationDataSize */
SYSBOARDIDLEN, /* IdentifierLength */
SYSBOARDID /* Identifier */
};
static COMPONENT cputmpl = {
ProcessorClass, /* Class */
CPU, /* Type */
0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
11, /* IdentifierLength */
"MIPS-R4000" /* Identifier */
};
static COMPONENT fputmpl = {
ProcessorClass, /* Class */
FPU, /* Type */
0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
14, /* IdentifierLength */
"MIPS-R4000FPC" /* Identifier */
};
static COMPONENT cachetmpl = {
CacheClass, /* Class */
PrimaryICache, /* Type */
0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
0, /* IdentifierLength */
NULL /* Identifier */
};
static COMPONENT memtmpl = {
MemoryClass, /* Class */
Memory, /* Type */
0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
0, /* Identifier Length */
NULL /* Identifier */
};
/******
* log2
* ----
* Some funny little routine.
*/
static int
log2(int x){
int n,v;
for(n=0,v=1;v<x;v<<=1,n++) ;
return(n);
}
/******
* crc
* ----
* Some funny crc generator for ds2502
*/
void
CRCengine(uint8_t inbit, uint8_t *CRCptr)
{
register uint8_t CRC, bit08, bit34, bit45 ;
/*
* Generate bit 0/8
*/
CRC = *CRCptr ;
bit08 = (inbit & 0x1) ^ (CRC & 0x1) ;
/*
* Generate bit 3/4
*/
bit34 = ((CRC >> 3) & 0x1) ^ bit08 ;
/*
* Generate bit 4/5
*/
bit45 = ((CRC >> 4) & 0x1) ^ bit08 ;
/*
* Shift all bits into their corresponding position.
*/
bit08 = bit08 << 7 ;
bit34 = bit34 << 2 ;
bit45 = bit45 << 3 ;
CRC = (CRC >> 1) & 0x73 ;
CRC = CRC | bit08 | bit34 | bit45 ;
/*
* Update global CRC
*/
*CRCptr = CRC & 0xff ;
return ;
}
/*****************
* setCPUSpecifics
* ---------------
* CPU specific data structures.
*/
extern uint32_t Read_C0_PRId (void) ;
static void
setCPUSpecifics(COMPONENT* cpu)
{
uint32_t PRId ;
PRId = Read_C0_PRId () ;
/*
* Check the processor implementation #
*/
switch (PRId >>C0_IMPSHIFT) {
case C0_IMP_TRITON:
cpu->Identifier = "MIPS-R5000" ;
break ;
case C0_IMP_R10000:
cpu->Identifier = "MIPS-R10000" ;
break ;
case C0_IMP_R4700:
cpu->Identifier = "MIPS-R4700" ;
break ;
case C0_IMP_R4600:
cpu->Identifier = "MIPS-R4600" ;
break ;
case C0_IMP_R4400:
cpu->Identifier = "MIPS-R4400" ;
break ;
default:
cpu->Identifier = "MIPS-?????" ;
}
/*
* set the CPU freguence, make sure the cpu->Key == 0,
* so that the cpufreq will return a correct value to hinv_cmd.c
* FIXED THE cpu_get_freq in fw/stubs.c,
* it always return 50 MHz - 50000000.
*/
cpu->Key = 0 ;
return ;
}
/*****************
* setFPUSpecifics
*----------------
* maybe we need to do something here, but I really
* don't know much about it.
*/
static void
setFPUSpecifics(COMPONENT* fpu)
{
switch (Read_C0_PRId() >>C0_IMPSHIFT) {
case C0_IMP_TRITON:
fpu->Identifier = "MIPS-R5000FPC" ;
break ;
case C0_IMP_R10000:
fpu->Identifier = "MIPS-R10000FPC" ;
break ;
case C0_IMP_R4700:
fpu->Identifier = "MIPS-R4700FPC" ;
break ;
case C0_IMP_R4600:
fpu->Identifier = "MIPS-R4600FPC" ;
break ;
case C0_IMP_R4400:
fpu->Identifier = "MIPS-R4400FPC" ;
break ;
default:
fpu->Identifier = "MIPS-?????FPC" ;
}
return ;
}
/********************
* setMemorySpecifics
*-------------------
* Determind the size of memory here, check the
* data structure to figure out what the hack is
* this.
*/
static void
setMemorySpecifics(COMPONENT* mem) {
#if defined(May28NinetySix)
/* We should not call cpu_mem_init here, _saio_init already did
it, the result is losting yet another 4M of address space */
cpu_mem_init () ;
#endif
mem->Key = (ULONG) (cpu_get_memsize() / _PAGESZ) ;
}
/*******************
* setCacheSpecifics
*------------------
* Seup primary, secondary cache size, block size
* and line size, and ..., etc.
*/
static void
setCacheSpecifics(COMPONENT* cache)
{
union key_u k;
/* NOTE: Setting the cache specifics is processor dependent */
switch(cache->Type){
case PrimaryICache:
k.cache.c_bsize = 1;
k.cache.c_lsize = log2(_icache_linesize);
k.cache.c_size = log2(_icache_size>>12);
break;
case PrimaryDCache:
k.cache.c_bsize = 1;
k.cache.c_lsize = log2(_dcache_linesize);
k.cache.c_size = log2(_dcache_size>>12);
break;
case SecondaryCache:
k.cache.c_bsize = 1;
k.cache.c_lsize = log2(_scache_linesize);
k.cache.c_size = log2(_sidcache_size>>12);
break;
default:
assert(0);
}
cache->Key = k.FullKey;
return ;
}
/*****************
* cpu_makecfgroot
*----------------
* Its a little different from the one I have seen in
* arcs/lib/libsk/lib
*/
cfgnode_t*
cpu_makecfgroot(void)
{
COMPONENT* root;
root = AddChild(0,&IP32tmpl,0);
assert(root);
return (cfgnode_t*)root;
}
/******************
* IP32_cpu_install
*-----------------
* Add CPU, FPU, cache, and memory to configuration
* Each has a generic template which we add first. We then call setXSpecifics
* to add platform specific data.
*/
void
IP32_cpu_install(COMPONENT* root)
{
COMPONENT* cpu;
COMPONENT* fpu;
COMPONENT* cache;
COMPONENT* mem;
COMPONENT* pci;
/* Add CPU to the configuration */
cpu = AddChild(root,&cputmpl,0);
assert(cpu);
setCPUSpecifics(cpu);
/* Add FPU to the configuration */
fpu = AddChild(cpu,&fputmpl,0);
assert(fpu);
setFPUSpecifics(fpu);
/* Add PI and PD CACHE to the configuration */
cache = AddChild(cpu,&cachetmpl,0);
assert(cache);
setCacheSpecifics(cache);
cache = AddChild(cpu,&cachetmpl,0);
assert(cache);
cache->Type = PrimaryDCache;
setCacheSpecifics(cache);
/* Optionally add secondary cache */
/*
* NOTE: The 4600sc is a class of PC CPU's with a SC grafted
* on after the fact. A more generic configuration rule would be nice.
*/
if (_sidcache_size!=0 || _r4600sc_sidcache_size!=0){
cache = AddChild(cpu,&cachetmpl,0);
assert(cache);
cache->Type = SecondaryCache;
setCacheSpecifics(cache);
}
/* Add Memory to the configuration */
mem = AddChild(cpu,&memtmpl,0);
assert(mem);
setMemorySpecifics(mem);
}
/*****************************************************************************
* IP32 memory configuration related functions. *
*****************************************************************************/
/*****************
* cpu_get_membase
* ---------------
* Return base address of memory.
*/
static unsigned int
cpu_get_membase(void)
{
return (unsigned int)PHYS_RAMBASE;
}
/*****************
* cpu_get_memsize
* ---------------
* Dynamically figure out the memory size, post1
* should have the Bank Control register setup
* correctly.
*/
#define M32 32*1024*1024
#define M128 128*1024*1024
uint32_t
cpu_get_memsize (void)
{
register int i ;
register uint64_t BankCNTL, tmp ;
register uint32_t CRIMEreg, size ;
CRIMEreg = (uint32_t) (CRM_MEM_BANK_CTRL(0)|K1BASE) ;
size = M32 ; /* Default to 32M */
tmp = * (uint64_t *) CRIMEreg ; /* remember bank 0 */
if ((tmp & CRM_MEM_BANK_CTRL_SDRAM_SIZE) != 0x0) size = M128 ;
for (i = 1, CRIMEreg += 8 ; i < 8 ; i++) {
BankCNTL = * (uint64_t *) CRIMEreg ;
if (BankCNTL != tmp) { /* There is SIMM in this bank. */
if ((BankCNTL & CRM_MEM_BANK_CTRL_SDRAM_SIZE) != 0x0)
size += M128 ;
else
size += M32 ;
}
CRIMEreg += 8 ;
}
return size ;
}
/**************
* cpu_mem_init
* ------------
* Initialize the arcs memory data structure ????
*/
#define NPHYS0_PAGES 2
void
cpu_mem_init(void) {
md_add(cpu_get_membase()+ptob(NPHYS0_PAGES),
btop(_min(cpu_get_memsize(),0x10000000)) - NPHYS0_PAGES,
FreeMemory);
md_add(0,NPHYS0_PAGES,FreeMemory);
}
/***************
* alloc_memdesc
* -------------
* Add what we know to be the prom's stack and bss.
* Text and data are safe in prom in I/O space.
*/
/* #define DEBUG 1 */
void
alloc_memdesc(void)
{
#if defined(DEBUG)
MEMORYDESCRIPTOR *m, *mem_getblock(void);
#endif
/*
* allocate the stack and bss addresses so we don't end up giving it
* away.
*/
md_alloc(KDM_TO_PHYS(PROM_RAMBASE),
arcs_btop(KDM_TO_PHYS(PROM_TILE_BASE)-KDM_TO_PHYS(PROM_RAMBASE)),
FirmwarePermanent);
/* This also include the free tiles pool */
md_alloc(KDM_TO_PHYS(PROM_TILE_BASE),
arcs_btop(KDM_TO_PHYS(PROM_STACK)-KDM_TO_PHYS(PROM_TILE_BASE)),
FirmwareTemporary);
/* This is for PROM frame buffer */
md_alloc(KDM_TO_PHYS(PROM_FB_TILE_START),
arcs_btop(KDM_TO_PHYS(PROM_FB_TILE_LIMIT) -
KDM_TO_PHYS(PROM_FB_TILE_START)),
FirmwareTemporary);
#if defined(DEBUG)
m = mem_getblock();
printf ("Base Page addr = 0x%08lx, pages = %04ld, TopAddr = 0x%08x\n",
arcs_ptob(m->BasePage), m->PageCount,
arcs_ptob(m->BasePage + m->PageCount));
mem_list();
#endif
/* #undef DEBUG */
}
#if 0 /* all mte functions are now in lib/libsk/ml */
/*****************************************************************************
* IP32 mte clean functions *
*****************************************************************************/
/* These stubs imply that if there is no gfx.a, CRIME is idle except
* for calls from ml/MOOSEHEAD/mte_copy.c -wsm12/18/95.
*/
int crmSavePP () { return 0; }
void crimeRestore() { }
int crimeLockOut() { return 0; }
/* Useful Macros
typedef unsigned long int uintptr_t;
*/
#define CRM_SRCBUF_LINEAR_A (4<<5)
#define CRM_SRCBUF_LINEAR_B (5<<5)
#define CRM_DSTBUF_LINEAR_A (4<<2)
#define CRM_DSTBUF_LINEAR_B (5<<2)
#define MTE_SRCECC (1 << 1)
#define MTE_DSTECC (1)
#define CRMSTAT_MTE_FLUSHED (1 << 25)
/* Make these real once the hardware comes back */
#define MTE_COST_PER_REGWRITE 0x100 /* XXX */
#define MTE_COST_PER_PRIMITIVE (MTE_COST_PER_REGWRITE * 3) /* XXX */
/* Assumes CRM_PAGE_SIZE == 0x1000 */
#define CRM_PAGE_SHIFT 12
#if USE_64BIT_C
# define WRITE_REG64(reg, value) *(volatile _crmreg_t *)(reg) = (value);
#else
/* from IP32asm.s */
#if defined(WRITE_REG64)
#undef WRITE_REG64
# define WRITE_REG64(reg, value) write_reg64((value), (reg))
#endif
#endif
#define CRM_REG(reg) ((uintptr_t)crime+(reg))
#define CRIME_SET32(reg, value) (*(volatile __uint32_t *)CRM_REG(reg) = (value))
#define CRIME_SET32_AND_GO(reg, value) CRIME_SET32((reg)|CRM_START_OFFSET, (value))
#define CRIME_SET64(reg, value) WRITE_REG64(CRM_REG(reg), (value))
#define MTE_REG(reg) ((reg)|CRM_MTE_BASE)
#define MTE_SET32(reg, value) CRIME_SET32(MTE_REG(reg), (value))
#define MTE_SET32_AND_GO(reg, value) CRIME_SET32_AND_GO(MTE_REG(reg), (value))
#define countof(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
/* LOCAL declarations */
static void *crime = (void *) PHYS_TO_K1(CRM_BASEADDR + 0x1000000);
static int mte_set_tlb(paddr_t addr, int bcount, uint_t tlb, int *nbytes);
static void mte_fifo_wait(int nentries);
static void mte_spin(void);
extern int get_crm_rev(void);
/*
* EXPORTS
*/
void
mte_zero(paddr_t addr, size_t bcount)
{
const __uint32_t ZERO_OP = ( MTE_CLEAR | CRM_DSTBUF_LINEAR_A
| MTE_DSTECC);
int tlba;
if (get_crm_rev() < 1)
return;
/*
* MTE can only handle 128K max at one time. Break
* the request up into chunks which are no larger than
* 128K
*/
while (bcount) {
int count;
int nbytes;
count = (bcount > 0x20000) ? 0x20000 : bcount;
tlba |= mte_set_tlb(addr, count, CRM_TLB_LINEAR_A_OFFSET, &nbytes);
count = MIN(count, nbytes);
/* Now do the zero */
mte_fifo_wait(5);
/*
* we use addr + count - 1 because MTE copies and zero
* operations are inclusive. We actually want to clea
* count bytes starting at addr.
*/
MTE_SET32(CRM_MTE_DST0_REG, (uintptr_t)addr);
MTE_SET32(CRM_MTE_DST1_REG, (uintptr_t)((addr+count) - 1));
MTE_SET32(CRM_MTE_FGVALUE_REG, 0x0);
MTE_SET32(CRM_MTE_BYTEMASK_REG, 0xffffffff);
MTE_SET32_AND_GO(CRM_MTE_MODE_REG, ZERO_OP);
bcount -= count;
addr += count;
/* wait for the xfer to finish */
mte_spin();
}
}
/* Estimated number of usecs before an MTE operation will be acted on.
*
* The returned value may have an arbitrary amount of error. (I.e., we
* are free to sacrifice accuracy for ease of computation.)
*/
static int
mte_delay()
{
uint_t status;
if (crimeLockOut(crime))
return(HW_COPY_NOT_AVAILABLE);
status = *(volatile uint_t *)CRM_REG(CRM_STATUS_BASE|CRM_STATUS_REG);
return(status & CRMSTAT_MTE_FLUSHED ? 0 :
(MTE_COST_PER_PRIMITIVE +
CRMSTAT_IB_LEVEL(status) * MTE_COST_PER_REGWRITE));
}
/* Spin until MTE is idle */
static void
mte_spin()
{
while (!*(volatile uint_t *)
CRM_REG(CRM_STATUS_BASE|CRM_STATUS_REG) & CRMSTAT_MTE_FLUSHED)
DELAY(1);
}
/*
* LOCAL definitions
*/
#define MAX_SPAN (0x20000 - 1)
static int
mte_set_tlb(paddr_t addr, int bcount, uint_t tlb_offset, int *nbytes)
{
u_long page;
u_long page_last;
paddr_t addr_end = ((u_long) addr + bcount - 1);
int indices = 0;
int index;
page = (u_long)addr >> CRM_PAGE_SHIFT;
page_last = (u_long)addr_end >> CRM_PAGE_SHIFT;
*nbytes = 0;
/*
* check to see if we start on an odd page.
* Since TLB entries are paired, the first page
* mapped must be an even page.
*/
if (page & 0x1) {
--page;
addr = (page << CRM_PAGE_SHIFT);
*nbytes -= CRM_PAGE_SIZE;
}
/*
* now that we have the starting page calculated, check for
* overflow. Adjust ending page if we would overflow the
* the mte page table.
*/
if ((addr_end - (page << CRM_PAGE_SHIFT)) > MAX_SPAN) {
page_last = ((page<<CRM_PAGE_SHIFT) + MAX_SPAN) >> CRM_PAGE_SHIFT;
}
/* Make sure there's enough room in the command fifo for our writes */
mte_fifo_wait((page_last - page)/2);
for (; page <= page_last; page += 2) {
/* just map vaddr to paddr */
index = (page & 0x1f) >> 1;
CRIME_SET64(CRM_TLB_BASE+tlb_offset+(index*sizeof(_crmreg_t)),
((_crmreg_t)(1<<31 | page) << 32) |
(_crmreg_t)(1<<31 | page+1));
indices |= 1<<index;
*nbytes += (CRM_PAGE_SIZE * 2);
}
return(indices);
}
/* We don't want to take a Crime-FIFO-hiwater-mark interrupt
* for a variety of reasons (it happens before the fifo actually fills;
* it's expensive; and we may have the interrupt masked, anyway, etc.)
* so we just make sure there's enough room in the fifo before we write
* something. Poll, waiting for it to drain, if there isn't.
*
* This assumes that no one can come in at interrupt and write it the fifo,
* which is true because hw_copy.c only lets one caller in here at a time.
*/
static void
mte_fifo_wait(int nentries)
{
while (CRIME_FIFO_DEPTH -
CRMSTAT_IB_LEVEL(*(volatile uint_t *)
CRM_REG(CRM_STATUS_BASE|CRM_STATUS_REG)) <
nentries)
DELAY(1);
}
#endif /* mte functions */
/*****************************************************************************
* IP32 miscellaneous *
*****************************************************************************/
/**************
* jumper_off()
*-------------
*/
int
jumper_off(void) {
uint64_t Jumper_value = *(uint64_t*)(PHYS_TO_K1(ISA_FLASH_NIC_REG))
& ISA_PWD_CLEAR;
return (Jumper_value == 0) ? 1 : 0;
}
/***************
* showException
*--------------
* NOTE: Temporary
*/
void
showException(ulong sr, ulong cause, ulong badvaddr, ulong epc){
char buf[80];
sprintf(buf,"%08x %08x %08x %08x\n", sr, cause, badvaddr, epc);
_errputs(buf);
}
/**********
* __assert
*---------
* NOTE: Probably shouldn't be here.
*/
void
__assert(const char* ex, const char* file, int line){
char buf[128];
sprintf(buf,
"assertion failure (%s) in file %s at line %d\n",
ex, file, line);
panic(buf);
}
/*****************************************************************************
* Find and get the version on flash *
*****************************************************************************/
/* Flash ROM definition */
#define IMPOSSIBLE 0
char*
getversion(void)
{
FlashSegment* Seg = (FlashSegment*)0;
char *Ptr;
int i;
while (Seg = nextSegment(&envFlash,Seg)) {
#if 0
printf ("Current segment = %s\n", Seg->name);
#endif
if(strcmp(Seg->name, "version") == 0x0) {
#if 0
printf ("the version segment address = 0x%0x\n", Seg);
printf ("the version body address = 0x%0x\n", body(Seg));
#endif
for (Ptr=(char*)body(Seg),i=0;i < 1024;i++,Ptr+=1)
if (strcmp(Ptr,"VSEGOK") == 0x0) {
#if 0
printf ("Found VSEGOK at location 0x%0x\n", Ptr+8);
#endif
return Ptr+8;
}
/* We have an version segment but we can not find the first
non blank string */
assert(IMPOSSIBLE);
}
}
assert(IMPOSSIBLE);
}