f48f1a324a
the change to support no-execute bits broke the original raspberry pi1, as it uses backwards compatible page table format. to use the XN bit, subpage AP bits have to be disabled using the XP bit in CP15 Control Register c1 Bit 23.
244 lines
3.7 KiB
C
244 lines
3.7 KiB
C
/*
|
|
* bcm2836 (e.g.raspberry pi 2) architecture-specific stuff
|
|
*/
|
|
|
|
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "../port/error.h"
|
|
#include "io.h"
|
|
#include "arm.h"
|
|
|
|
#include "../port/netif.h"
|
|
|
|
typedef struct Mbox Mbox;
|
|
typedef struct Mboxes Mboxes;
|
|
|
|
#define POWERREGS (VIRTIO+0x100000)
|
|
|
|
Soc soc = {
|
|
.dramsize = 0x3F000000, /* was 1024*MiB, but overlaps with physio */
|
|
.busdram = 0xC0000000,
|
|
.iosize = 16*MiB,
|
|
.virtio = VIRTIO,
|
|
.physio = 0x3F000000,
|
|
.busio = 0x7E000000,
|
|
.armlocal = 0x40000000,
|
|
.l1ptedramattrs = Cached | Buffered | L1wralloc | L1sharable,
|
|
.l2ptedramattrs = Cached | Buffered | L2wralloc | L2sharable,
|
|
};
|
|
|
|
enum {
|
|
Wdogfreq = 65536,
|
|
Wdogtime = 10, /* seconds, ≤ 15 */
|
|
};
|
|
|
|
/*
|
|
* Power management / watchdog registers
|
|
*/
|
|
enum {
|
|
Rstc = 0x1c>>2,
|
|
Password = 0x5A<<24,
|
|
CfgMask = 0x03<<4,
|
|
CfgReset = 0x02<<4,
|
|
Rsts = 0x20>>2,
|
|
Wdog = 0x24>>2,
|
|
};
|
|
|
|
/*
|
|
* Arm local regs for smp
|
|
*/
|
|
struct Mbox {
|
|
u32int doorbell;
|
|
u32int mbox1;
|
|
u32int mbox2;
|
|
u32int startcpu;
|
|
};
|
|
struct Mboxes {
|
|
Mbox set[4];
|
|
Mbox clr[4];
|
|
};
|
|
|
|
enum {
|
|
Mboxregs = 0x80
|
|
};
|
|
|
|
static Lock startlock[MAXMACH + 1];
|
|
|
|
void
|
|
archreset(void)
|
|
{
|
|
fpon();
|
|
}
|
|
|
|
void
|
|
archreboot(void)
|
|
{
|
|
u32int *r;
|
|
|
|
r = (u32int*)POWERREGS;
|
|
r[Wdog] = Password | 1;
|
|
r[Rstc] = Password | (r[Rstc] & ~CfgMask) | CfgReset;
|
|
coherence();
|
|
for(;;)
|
|
;
|
|
}
|
|
|
|
void
|
|
wdogfeed(void)
|
|
{
|
|
u32int *r;
|
|
|
|
r = (u32int*)POWERREGS;
|
|
r[Wdog] = Password | (Wdogtime * Wdogfreq);
|
|
r[Rstc] = Password | (r[Rstc] & ~CfgMask) | CfgReset;
|
|
}
|
|
|
|
void
|
|
wdogoff(void)
|
|
{
|
|
u32int *r;
|
|
|
|
r = (u32int*)POWERREGS;
|
|
r[Rstc] = Password | (r[Rstc] & ~CfgMask);
|
|
}
|
|
|
|
|
|
char *
|
|
cputype2name(char *buf, int size)
|
|
{
|
|
u32int r;
|
|
uint part;
|
|
char *p;
|
|
|
|
r = cpidget(); /* main id register */
|
|
assert((r >> 24) == 'A');
|
|
part = (r >> 4) & MASK(12);
|
|
switch(part){
|
|
case 0xc07:
|
|
p = seprint(buf, buf + size, "Cortex-A7");
|
|
break;
|
|
case 0xd03:
|
|
p = seprint(buf, buf + size, "Cortex-A53");
|
|
break;
|
|
default:
|
|
p = seprint(buf, buf + size, "Unknown-%#x", part);
|
|
break;
|
|
}
|
|
seprint(p, buf + size, " r%ldp%ld",
|
|
(r >> 20) & MASK(4), r & MASK(4));
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
cpuidprint(void)
|
|
{
|
|
char name[64];
|
|
|
|
cputype2name(name, sizeof name);
|
|
delay(50); /* let uart catch up */
|
|
print("cpu%d: %dMHz ARM %s\n", m->machno, m->cpumhz, name);
|
|
}
|
|
|
|
int
|
|
getncpus(void)
|
|
{
|
|
int n, max;
|
|
char *p;
|
|
n = 4;
|
|
if(n > MAXMACH)
|
|
n = MAXMACH;
|
|
p = getconf("*ncpu");
|
|
if(p && (max = atoi(p)) > 0 && n > max)
|
|
n = max;
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
startcpu(uint cpu)
|
|
{
|
|
Mboxes *mb;
|
|
int i;
|
|
void cpureset();
|
|
|
|
mb = (Mboxes*)(ARMLOCAL + Mboxregs);
|
|
if(mb->clr[cpu].startcpu)
|
|
return -1;
|
|
mb->set[cpu].startcpu = PADDR(cpureset);
|
|
coherence();
|
|
sev();
|
|
for(i = 0; i < 1000; i++)
|
|
if(mb->clr[cpu].startcpu == 0)
|
|
return 0;
|
|
mb->clr[cpu].startcpu = PADDR(cpureset);
|
|
mb->set[cpu].doorbell = 1;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
mboxclear(uint cpu)
|
|
{
|
|
Mboxes *mb;
|
|
|
|
mb = (Mboxes*)(ARMLOCAL + Mboxregs);
|
|
mb->clr[cpu].mbox1 = 1;
|
|
}
|
|
|
|
void
|
|
wakecpu(uint cpu)
|
|
{
|
|
Mboxes *mb;
|
|
|
|
mb = (Mboxes*)(ARMLOCAL + Mboxregs);
|
|
mb->set[cpu].mbox1 = 1;
|
|
}
|
|
|
|
int
|
|
startcpus(uint ncpu)
|
|
{
|
|
int i, timeout;
|
|
|
|
for(i = 0; i < ncpu; i++)
|
|
lock(&startlock[i]);
|
|
cachedwbse(startlock, sizeof startlock);
|
|
for(i = 1; i < ncpu; i++){
|
|
if(startcpu(i) < 0)
|
|
return i;
|
|
timeout = 10000000;
|
|
while(!canlock(&startlock[i]))
|
|
if(--timeout == 0)
|
|
return i;
|
|
unlock(&startlock[i]);
|
|
}
|
|
return ncpu;
|
|
}
|
|
|
|
void
|
|
archbcm2link(void)
|
|
{
|
|
addclock0link(wdogfeed, HZ);
|
|
}
|
|
|
|
void
|
|
cpustart(int cpu)
|
|
{
|
|
Mboxes *mb;
|
|
|
|
up = nil;
|
|
machinit();
|
|
mb = (Mboxes*)(ARMLOCAL + Mboxregs);
|
|
mb->clr[cpu].doorbell = 1;
|
|
trapinit();
|
|
clockinit();
|
|
mmuinit1(0);
|
|
timersinit();
|
|
cpuidprint();
|
|
archreset();
|
|
active.machs[m->machno] = 1;
|
|
unlock(&startlock[cpu]);
|
|
schedinit();
|
|
panic("schedinit returned");
|
|
}
|