/* * 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" #include "etherif.h" typedef struct Mbox Mbox; typedef struct Mboxes Mboxes; #define POWERREGS (VIRTIO+0x100000) Soc soc = { .dramsize = 0x3F000000, /* was 1024*MiB, but overlaps with physio */ .physio = 0x3F000000, .busdram = 0xC0000000, .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); 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; 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; lock(&startlock[i]); unlock(&startlock[i]); } return ncpu; } void archbcm2link(void) { addclock0link(wdogfeed, HZ); } int archether(unsigned ctlrno, Ether *ether) { switch(ctlrno){ case 0: ether->type = "usb"; break; case 1: ether->type = "4330"; break; default: return 0; } ether->ctlrno = ctlrno; ether->irq = -1; ether->nopt = 0; return 1; } int l2ap(int ap) { return (AP(0, (ap))); } int cmpswap(long *addr, long old, long new) { return cas((ulong*)addr, old, new); } void cpustart(int cpu) { Mboxes *mb; void machon(int); up = nil; machinit(); mb = (Mboxes*)(ARMLOCAL + Mboxregs); mb->clr[cpu].doorbell = 1; trapinit(); clockinit(); mmuinit1(); timersinit(); cpuidprint(); archreset(); machon(m->machno); unlock(&startlock[cpu]); schedinit(); panic("schedinit returned"); }