diff options
author | Rudolf Marek <r.marek@assembler.cz> | 2013-12-07 22:29:36 +0100 |
---|---|---|
committer | Alexandru Gagniuc <mr.nuke.me@gmail.com> | 2014-04-06 18:03:52 +0200 |
commit | 6181e3dcd7202b2460aad91237f314b8dacf686a (patch) | |
tree | 855b23c63c60f1b4f209abab7709b54a26688ab4 | |
parent | 4f5a5254c5ad0aa0227113c3fd31b12c0783c131 (diff) |
amd/agesa/hudson: Implement PNP resource setup in LPC bridge
The previous SBxxx generations were setting up LPC bridge based
on the PNP resources. Implement it also for AGESA Hudson.
The AGESA itself opens one big region DFLT_SIO_PME_BASE_ADDRESS
(512 bytes). Make the code smart enough to detect already used
region and if any resource fits into AGESA defined region, do nothing.
Change-Id: I718d034bc4c778697a7bd0506d4550c8f5a43159
Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
Reviewed-on: http://review.coreboot.org/4497
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
-rw-r--r-- | src/southbridge/amd/agesa/hudson/lpc.c | 174 |
1 files changed, 173 insertions, 1 deletions
diff --git a/src/southbridge/amd/agesa/hudson/lpc.c b/src/southbridge/amd/agesa/hudson/lpc.c index 3af3eb8ede..a0dc0727d9 100644 --- a/src/southbridge/amd/agesa/hudson/lpc.c +++ b/src/southbridge/amd/agesa/hudson/lpc.c @@ -129,8 +129,180 @@ static void hudson_lpc_set_resources(struct device *dev) */ static void hudson_lpc_enable_childrens_resources(device_t dev) { - printk(BIOS_DEBUG, "hudson_lpc_enable_childrens_resources\n"); + struct bus *link; + u32 reg, reg_x; + int var_num = 0; + u16 reg_var[3]; + u16 reg_size[1] = {512}; + u8 wiosize = pci_read_config8(dev, 0x74); + /* Be bit relaxed, tolerate that LPC region might be bigger than resource we try to fit, + * do it like this for all regions < 16 bytes. If there is a resource > 16 bytes + * it must be 512 bytes to be able to allocate the fresh LPC window. + * + * AGESA likes to enable already one LPC region in wide port base 0x64-0x65, + * using DFLT_SIO_PME_BASE_ADDRESS, 512 bytes size + * The code tries to check if resource can fit into this region + */ + + reg = pci_read_config32(dev, 0x44); + reg_x = pci_read_config32(dev, 0x48); + + /* check if ranges are free and not use them if entry is just already taken */ + if (reg_x & (1 << 2)) + var_num = 1; + /* just in case check if someone did not manually set other ranges too */ + if (reg_x & (1 << 24)) + var_num = 2; + + if (reg_x & (1 << 25)) + var_num = 3; + + /* check AGESA region size */ + if (wiosize & (1 << 0)) + reg_size[0] = 16; + + reg_var[2] = pci_read_config16(dev, 0x90); + reg_var[1] = pci_read_config16(dev, 0x66); + reg_var[0] = pci_read_config16(dev, 0x64); + + for (link = dev->link_list; link; link = link->next) { + device_t child; + for (child = link->children; child; + child = child->sibling) { + if (child->enabled + && (child->path.type == DEVICE_PATH_PNP)) { + struct resource *res; + for (res = child->resource_list; res; res = res->next) { + u32 base, end; /* don't need long long */ + u32 rsize, set = 0, set_x = 0; + if (!(res->flags & IORESOURCE_IO)) + continue; + base = res->base; + end = resource_end(res); + /* find a resource size */ + printk(BIOS_DEBUG, "hudson lpc decode:%s, base=0x%08x, end=0x%08x\n", + dev_path(child), base, end); + switch (base) { + case 0x60: /* KB */ + case 0x64: /* MS */ + set |= (1 << 29); + rsize = 1; + break; + case 0x3f8: /* COM1 */ + set |= (1 << 6); + rsize = 8; + break; + case 0x2f8: /* COM2 */ + set |= (1 << 7); + rsize = 8; + break; + case 0x378: /* Parallel 1 */ + set |= (1 << 0); + set |= (1 << 1); /* + 0x778 for ECP */ + rsize = 8; + break; + case 0x3f0: /* FD0 */ + set |= (1 << 26); + rsize = 8; + break; + case 0x220: /* 0x220 - 0x227 */ + set |= (1 << 8); + rsize = 8; + break; + case 0x228: /* 0x228 - 0x22f */ + set |= (1 << 9); + rsize = 8; + break; + case 0x238: /* 0x238 - 0x23f */ + set |= (1 << 10); + rsize = 8; + break; + case 0x300: /* 0x300 -0x301 */ + set |= (1 << 18); + rsize = 2; + break; + case 0x400: + set_x |= (1 << 16); + rsize = 0x40; + break; + case 0x480: + set_x |= (1 << 17); + rsize = 0x40; + case 0x500: + set_x |= (1 << 18); + rsize = 0x40; + break; + case 0x580: + set_x |= (1 << 19); + rsize = 0x40; + break; + case 0x4700: + set_x |= (1 << 22); + rsize = 0xc; + break; + case 0xfd60: + set_x |= (1 << 23); + rsize = 16; + break; + default: + rsize = 0; + /* try AGESA allocated region in region 0 */ + if ((var_num > 0) && ((base >=reg_var[0]) && + ((base + res->size) <= (reg_var[0] + reg_size[0])))) + rsize = reg_size[0]; + } + /* check if region found and matches the enable */ + if (res->size <= rsize) { + reg |= set; + reg_x |= set_x; + /* check if we can fit resource in variable range */ + } else if ((var_num < 3) && + ((res->size <= 16) || (res->size == 512))) { + /* use variable ranges if pre-defined do not match */ + switch (var_num) { + case 0: + reg_x |= (1 << 2); + if (res->size <= 16) { + wiosize |= (1 << 0); + } + break; + case 1: + reg_x |= (1 << 24); + if (res->size <= 16) + wiosize |= (1 << 2); + break; + case 2: + reg_x |= (1 << 25); + if (res->size <= 16) + wiosize |= (1 << 3); + break; + } + reg_var[var_num++] = + base & 0xffff; + } else { + printk(BIOS_ERR, "cannot fit LPC decode region:%s, base=0x%08x, end=0x%08x\n", + dev_path(child), base, end); + } + } + } + } + } + pci_write_config32(dev, 0x44, reg); + pci_write_config32(dev, 0x48, reg_x); + /* Set WideIO for as many IOs found (fall through is on purpose) */ + switch (var_num) { + case 3: + pci_write_config16(dev, 0x90, reg_var[2]); + /* fall through */ + case 2: + pci_write_config16(dev, 0x66, reg_var[1]); + /* fall through */ + case 1: + pci_write_config16(dev, 0x64, reg_var[0]); + break; + } + pci_write_config8(dev, 0x74, wiosize); } static void hudson_lpc_enable_resources(device_t dev) |