bcm64: get inbound and outbound pci window base address from device tree

On the pi400, the xhci reset firmware mailbox request
assumes that the pci windows match the ones specified
in the device tree. The inbound window (pcidmawin)
also varies now depending on the amount of memory
installed.

It is all pretty ridiculous, as the firmware could as
well just read the pci controllers hardware register
to determine the window configuration and the os could
keep a nice simple 1:1 mapping (with pci dma addresses
== physical addresses).
This commit is contained in:
cinap_lenrek 2021-02-06 13:47:45 +01:00
parent 0e381493bf
commit efcfdd23d7
4 changed files with 43 additions and 15 deletions

View file

@ -12,6 +12,7 @@ static char *confname[MAXCONF];
static char *confval[MAXCONF];
static int nconf;
static char maxmem[256];
static char pciwin[38], pcidmawin[38];
static int
findconf(char *k)
@ -89,23 +90,23 @@ beget4(uchar *p)
static void
devtreeprop(char *path, char *key, void *val, int len)
{
uvlong addr, size;
uchar *p = val;
char *s;
if((strcmp(path, "/memory") == 0 || strcmp(path, "/memory@0") == 0)
&& strcmp(key, "reg") == 0){
if(findconf("*maxmem") < 0 && len > 0 && (len % (3*4)) == 0){
uvlong top;
uchar *p = val;
char *s;
top = (uvlong)beget4(p)<<32 | beget4(p+4);
top += beget4(p+8);
s = seprint(maxmem, &maxmem[sizeof(maxmem)], "%#llux", top);
addr = (uvlong)beget4(p)<<32 | beget4(p+4);
addr += beget4(p+8);
s = seprint(maxmem, &maxmem[sizeof(maxmem)], "%#llux", addr);
p += 3*4;
len -= 3*4;
while(len > 0){
top = (uvlong)beget4(p)<<32 | beget4(p+4);
s = seprint(s, &maxmem[sizeof(maxmem)], " %#llux", top);
top += beget4(p+8);
s = seprint(s, &maxmem[sizeof(maxmem)], " %#llux", top);
addr = (uvlong)beget4(p)<<32 | beget4(p+4);
s = seprint(s, &maxmem[sizeof(maxmem)], " %#llux", addr);
addr += beget4(p+8);
s = seprint(s, &maxmem[sizeof(maxmem)], " %#llux", addr);
p += 3*4;
len -= 3*4;
}
@ -113,6 +114,22 @@ devtreeprop(char *path, char *key, void *val, int len)
}
return;
}
if(strncmp(path, "/scb/pcie@", 10) == 0 && len == (3*4 + 4*4)){
if((beget4(p) & 0x3000000) == 0x2000000){
size = (uvlong)beget4(p+5*4)<<32 | beget4(p+5*4+4);
if(strcmp(key, "ranges") == 0 && findconf("*pciwin") < 0){
addr = (uvlong)beget4(p+3*4)<<32 | beget4(p+4*4);
snprint(pciwin, sizeof(pciwin), "%#llux %#llux", addr, addr+size);
addconf("*pciwin", pciwin);
} else if(strcmp(key, "dma-ranges") == 0 && findconf("*pcidmawin") < 0){
addr = (uvlong)beget4(p+1*4)<<32 | beget4(p+2*4);
addr -= (uvlong)beget4(p+3*4)<<32 | beget4(p+4*4);
snprint(pcidmawin, sizeof(pcidmawin), "%#llux %#llux", addr, addr+size);
addconf("*pcidmawin", pcidmawin);
}
}
return;
}
if(strcmp(path, "/chosen") == 0 && strcmp(key, "bootargs") == 0){
if(len > BOOTARGSLEN)
len = BOOTARGSLEN;

View file

@ -249,7 +249,8 @@ struct Soc { /* SoC dependent configuration */
uintptr physio;
uintptr virtio;
uintptr armlocal;
uintptr pciwin;
uintptr pciwin; /* PCI outbound window CPU->PCI */
uintptr pcidmawin; /* PCI inbound window PCI->DRAM */
int oscfreq;
};
extern Soc soc;

View file

@ -6,5 +6,5 @@ enum {
IRQether = IRQgic + 29,
};
#define PCIWINDOW 0
#define PCIWINDOW soc.pcidmawin
#define PCIWADDR(va) (PADDR(va)+PCIWINDOW)

View file

@ -244,6 +244,16 @@ void
pcibcmlink(void)
{
int log2dmasize = 30; // 1GB
char *s;
if((s = getconf("*pciwin")) != nil){
print("*pciwin: %s\n", s);
soc.pciwin = (uintptr)strtoll(s, nil, 16);
}
if((s = getconf("*pcidmawin")) != nil){
print("*pcidmawin: %s\n", s);
soc.pcidmawin = (uintptr)strtoll(s, nil, 16);
}
regs[RGR1_SW_INIT_1] |= 3;
delay(200);
@ -266,8 +276,8 @@ pcibcmlink(void)
// SCB_ACCESS_EN, CFG_READ_UR_MODE, MAX_BURST_SIZE_128, SCB0SIZE
regs[MISC_MISC_CTRL] = 1<<12 | 1<<13 | 0<<20 | (log2dmasize-15)<<27;
regs[MISC_RC_BAR2_CONFIG_LO] = (log2dmasize-15);
regs[MISC_RC_BAR2_CONFIG_HI] = 0;
regs[MISC_RC_BAR2_CONFIG_LO] = ((u32int)soc.pcidmawin & ~0x1F) | (log2dmasize-15);
regs[MISC_RC_BAR2_CONFIG_HI] = soc.pcidmawin >> 32;
regs[MISC_RC_BAR1_CONFIG_LO] = 0;
regs[MISC_RC_BAR3_CONFIG_LO] = 0;