aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge/amd/rs780/rs780_gfx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge/amd/rs780/rs780_gfx.c')
-rw-r--r--src/southbridge/amd/rs780/rs780_gfx.c260
1 files changed, 168 insertions, 92 deletions
diff --git a/src/southbridge/amd/rs780/rs780_gfx.c b/src/southbridge/amd/rs780/rs780_gfx.c
index a9801a17cd..c2a220cf19 100644
--- a/src/southbridge/amd/rs780/rs780_gfx.c
+++ b/src/southbridge/amd/rs780/rs780_gfx.c
@@ -39,6 +39,8 @@ extern int is_dev3_present(void);
void set_pcie_reset(void);
void set_pcie_dereset(void);
+extern uint64_t uma_memory_base, uma_memory_size;
+
/* Trust the original resource allocation. Don't do it again. */
#undef DONT_TRUST_RESOURCE_ALLOCATION
//#define DONT_TRUST_RESOURCE_ALLOCATION
@@ -304,11 +306,15 @@ static void internal_gfx_pci_dev_init(struct device *dev)
volatile u32 * pointer;
int i;
u16 command;
- u32 value, sblk;
+ u32 value;
u16 deviceid, vendorid;
device_t nb_dev = dev_find_slot(0, 0);
device_t k8_f2 = dev_find_slot(0, PCI_DEVFN(0x18, 2));
device_t k8_f0 = dev_find_slot(0, PCI_DEVFN(0x18, 0));
+ static const u8 ht_freq_lookup [] = {2, 0, 4, 0, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 0, 0, 28, 30, 32};
+ static const u8 ht_width_lookup [] = {8, 16, 0, 0, 2, 4, 0, 0};
+ static const u16 memclk_lookup_fam0F [] = {100, 0, 133, 0, 0, 166, 0, 200};
+ static const u16 memclk_lookup_fam10 [] = {200, 266, 333, 400, 533, 667, 800, 800};
/* We definetely will use this in future. Just leave it here. */
/*struct southbridge_amd_rs780_config *cfg =
@@ -339,6 +345,8 @@ static void internal_gfx_pci_dev_init(struct device *dev)
*(GpuF0MMReg + 0x2180/4) = ((value&0xff00)>>8)|((value&0xff000000)>>8);
*(GpuF0MMReg + 0x2c04/4) = ((value&0xff00)<<8);
*(GpuF0MMReg + 0x5428/4) = ((value&0xffff0000)+0x10000)-((value&0xffff)<<16);
+ *(GpuF0MMReg + 0xF774/4) = 0xffffffff;
+ *(GpuF0MMReg + 0xF770/4) = 0x00000001;
*(GpuF0MMReg + 0x2000/4) = 0x00000011;
*(GpuF0MMReg + 0x200c/4) = 0x00000020;
*(GpuF0MMReg + 0x2010/4) = 0x10204810;
@@ -352,21 +360,28 @@ static void internal_gfx_pci_dev_init(struct device *dev)
*(GpuF0MMReg + 0x7de4/4) |= (1<<3) | (1<<4);
/* Force allow LDT_STOP Cool'n'Quiet workaround. */
*(GpuF0MMReg + 0x655c/4) |= 1<<4;
+
+ // disable write combining, needed for stability
+ // reference bios does this only for RS780 rev A11
+ // need to figure out why we need it for all revs
+ *(GpuF0MMReg + 0x2000/4) = 0x00000010;
+ *(GpuF0MMReg + 0x2408/4) = 1 << 9;
+ *(GpuF0MMReg + 0x2000/4) = 0x00000011;
+
/* GFX_InitFBAccess finished. */
- /* GFX_StartMC. */
#if (CONFIG_GFXUMA == 1) /* for UMA mode. */
- /* MC_INIT_COMPLETE. */
- set_nbmc_enable_bits(nb_dev, 0x2, 0, 1<<31);
- /* MC_STARTUP, MC_POWERED_UP and MC_VMODE.*/
- set_nbmc_enable_bits(nb_dev, 0x1, 1<<18, 1|1<<2);
-
- set_nbmc_enable_bits(nb_dev, 0xb1, 0, 1<<6);
- set_nbmc_enable_bits(nb_dev, 0xc3, 0, 1);
- nbmc_write_index(nb_dev, 0x07, 0x18);
- nbmc_write_index(nb_dev, 0x06, 0x00000102);
- nbmc_write_index(nb_dev, 0x09, 0x40000008);
- set_nbmc_enable_bits(nb_dev, 0x6, 0, 1<<31);
+ /* GFX_StartMC. */
+ set_nbmc_enable_bits(nb_dev, 0x02, 0x00000000, 0x80000000);
+ set_nbmc_enable_bits(nb_dev, 0x01, 0x00000000, 0x00000001);
+ set_nbmc_enable_bits(nb_dev, 0x01, 0x00000000, 0x00000004);
+ set_nbmc_enable_bits(nb_dev, 0x01, 0x00040000, 0x00000000);
+ set_nbmc_enable_bits(nb_dev, 0xB1, 0xFFFF0000, 0x00000040);
+ set_nbmc_enable_bits(nb_dev, 0xC3, 0x00000000, 0x00000001);
+ set_nbmc_enable_bits(nb_dev, 0x07, 0xFFFFFFFF, 0x00000018);
+ set_nbmc_enable_bits(nb_dev, 0x06, 0xFFFFFFFF, 0x00000102);
+ set_nbmc_enable_bits(nb_dev, 0x09, 0xFFFFFFFF, 0x40000008);
+ set_nbmc_enable_bits(nb_dev, 0x06, 0x00000000, 0x80000000);
/* GFX_StartMC finished. */
#else
/* for SP mode. */
@@ -418,77 +433,110 @@ static void internal_gfx_pci_dev_init(struct device *dev)
vgainfo.sHeader.ucTableContentRevision = 2;
#if (CONFIG_GFXUMA == 0) /* SP mode. */
+ // Side port support is incomplete, do not use it
+ // These parameters must match the motherboard
vgainfo.ulBootUpSidePortClock = 667*100;
- vgainfo.ucMemoryType = 3;
+ vgainfo.ucMemoryType = 3; // 3=ddr3 sp mem, 2=ddr2 sp mem
vgainfo.ulMinSidePortClock = 333*100;
#endif
- vgainfo.ulBootUpEngineClock = 500 * 100; /* set boot up GFX engine clock. */
- vgainfo.ulReserved1[0] = 0; vgainfo.ulReserved1[1] = 0;
- value = pci_read_config32(k8_f2, 0x94);
- printk(BIOS_DEBUG, "MEMCLK = %x\n", value&0x7);
- vgainfo.ulBootUpUMAClock = 333 * 100; /* set boot up UMA memory clock. */
- vgainfo.ulBootUpSidePortClock = 0; /* disable SP. */
- vgainfo.ulMinSidePortClock = 0; /* disable SP. */
- for(i=0; i<6; i++)
- vgainfo.ulReserved2[i] = 0;
- vgainfo.ulSystemConfig = 0;
- //vgainfo.ulSystemConfig |= 1<<1 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7 | 1;
- vgainfo.ulBootUpReqDisplayVector = 0; //?
- vgainfo.ulOtherDisplayMisc = 0; //?
- vgainfo.ulDDISlot1Config = 0x000c0011; //0; //VGA
- //vgainfo.ulDDISlot1Config = 0x000c00FF; //0; //HDMI
- vgainfo.ulDDISlot2Config = 0x00130022; //0; //?
- vgainfo.ucMemoryType = 2;
+ vgainfo.ulBootUpEngineClock = 500 * 100; // setup option on reference BIOS, 500 is default
+
+ // find the DDR memory frequency
+ if (is_family10h()) {
+ value = pci_read_config32(k8_f2, 0x94); // read channel 0 DRAM Configuration High Register
+ if (extractbit(value, 14)) // if channel 0 disabled, channel 1 must have memory
+ value = pci_read_config32(k8_f2, 0x194);// read channel 1 DRAM Configuration High Register
+ vgainfo.ulBootUpUMAClock = memclk_lookup_fam10 [extractbits (value, 0, 2)] * 100;
+ }
+ if (is_family0Fh()) {
+ value = pci_read_config32(k8_f2, 0x94);
+ vgainfo.ulBootUpUMAClock = memclk_lookup_fam0F [extractbits (value, 20, 22)] * 100;
+ }
+
/* UMA Channel Number: 1 or 2. */
- vgainfo.ucUMAChannelNumber = 2;
- vgainfo.ucDockingPinBit = 0; //?
- vgainfo.ucDockingPinPolarity = 0; //?
- vgainfo.ulDockingPinCFGInfo = 0; //?
- vgainfo.ulCPUCapInfo = 3; /* K8. */
-
- /* page 5-19 on BDG. */
- vgainfo.usNumberOfCyclesInPeriod = 0x8019;
- vgainfo.usMaxNBVoltage = 0x1a;
- vgainfo.usMinNBVoltage = 0;
- vgainfo.usBootUpNBVoltage = 0x1a;
-
- /* Get SBLink value (HyperTransport I/O Hub Link ID). */
- value = pci_read_config32(k8_f0, 0x64);
- sblk = (value >> 8) & 0x3;
- printk(BIOS_DEBUG, "SBLINK = %d.\n", sblk);
+ vgainfo.ucUMAChannelNumber = 1;
+ if (is_family0Fh()) {
+ value = pci_read_config32(k8_f2, 0x90);
+ if (extractbit(value, 11)) // 128-bit mode
+ vgainfo.ucUMAChannelNumber = 2;
+ }
+ if (is_family10h()) {
+ u32 dch0 = pci_read_config32(k8_f2, 0x94);
+ u32 dch1 = pci_read_config32(k8_f2, 0x194);
+ if (extractbit(dch0, 14) == 0 && extractbit(dch1, 14) == 0) { // both channels enabled
+ value = pci_read_config32(k8_f2, 0x110);
+ if (extractbit(value, 4)) // ganged mode
+ vgainfo.ucUMAChannelNumber = 2;
+ }
+ }
+
+ // processor type
+ if (is_family0Fh())
+ vgainfo.ulCPUCapInfo = 3;
+ if (is_family10h())
+ vgainfo.ulCPUCapInfo = 2;
/* HT speed */
- value = pci_read_config32(nb_dev, 0xd0);
- printk(BIOS_DEBUG, "NB HT speed = %x.\n", value);
- value = pci_read_config32(k8_f0, 0x88 + (sblk * 0x20));
- printk(BIOS_DEBUG, "CPU HT speed = %x.\n", value);
- vgainfo.ulHTLinkFreq = 100 * 100; /* set HT speed. */
+ value = pci_read_config8(nb_dev, 0xd1);
+ value = ht_freq_lookup [value] * 100; // HT link frequency in MHz
+ vgainfo.ulHTLinkFreq = value * 100; // HT frequency in units of 100 MHz
+ vgainfo.ulHighVoltageHTLinkFreq = vgainfo.ulHTLinkFreq;
+ vgainfo.ulLowVoltageHTLinkFreq = vgainfo.ulHTLinkFreq;
+
+ if (value <= 1800)
+ vgainfo.ulLowVoltageHTLinkFreq = vgainfo.ulHTLinkFreq;
+ else {
+ int sblink, cpuLnkFreqCap, nbLnkFreqCap;
+ value = pci_read_config32(k8_f0, 0x64);
+ sblink = extractbits(value, 8, 10);
+ cpuLnkFreqCap = pci_read_config16(k8_f0, 0x8a + sblink * 0x20);
+ nbLnkFreqCap = pci_read_config16(nb_dev, 0xd2);
+ if (cpuLnkFreqCap & nbLnkFreqCap & (1 << 10)) // if both 1800 MHz capable
+ vgainfo.ulLowVoltageHTLinkFreq = 1800*100;
+ }
/* HT width. */
- value = pci_read_config32(nb_dev, 0xc8);
- printk(BIOS_DEBUG, "HT width = %x.\n", value);
- vgainfo.usMinHTLinkWidth = 16;
- vgainfo.usMaxHTLinkWidth = 16;
- vgainfo.usUMASyncStartDelay = 322;
- vgainfo.usUMADataReturnTime = 86;
- vgainfo.usLinkStatusZeroTime = 0x00c8; //0; //?
- vgainfo.usReserved = 0;
- vgainfo.ulHighVoltageHTLinkFreq = 100 * 100;
- vgainfo.ulLowVoltageHTLinkFreq = 100 * 100;
- vgainfo.usMaxUpStreamHTLinkWidth = 16;
- vgainfo.usMaxDownStreamHTLinkWidth = 16;
- vgainfo.usMinUpStreamHTLinkWidth = 16;
- vgainfo.usMinDownStreamHTLinkWidth = 16;
- for(i=0; i<97; i++)
- vgainfo.ulReserved3[i] = 0;
+ value = pci_read_config8(nb_dev, 0xcb);
+ vgainfo.usMinDownStreamHTLinkWidth =
+ vgainfo.usMaxDownStreamHTLinkWidth =
+ vgainfo.usMinUpStreamHTLinkWidth =
+ vgainfo.usMaxUpStreamHTLinkWidth =
+ vgainfo.usMinHTLinkWidth =
+ vgainfo.usMaxHTLinkWidth = ht_width_lookup [extractbits(value, 0, 2)];
+
+ if (is_family0Fh()) {
+ vgainfo.usUMASyncStartDelay = 322;
+ vgainfo.usUMADataReturnTime = 286;
+ }
+
+ if (is_family10h()) {
+ static u16 t0mult_lookup [] = {10, 50, 200, 2000};
+ int t0time, t0scale;
+ value = pci_read_config32(k8_f0, 0x16c);
+ t0time = extractbits(value, 0, 3);
+ t0scale = extractbits(value, 4, 5);
+ vgainfo.usLinkStatusZeroTime = t0mult_lookup [t0scale] * t0time;
+ vgainfo.usUMASyncStartDelay = 100;
+ if (vgainfo.ulHTLinkFreq < 1000 * 100) { // less than 1000 MHz
+ vgainfo.usUMADataReturnTime = 300;
+ vgainfo.usLinkStatusZeroTime = 6 * 100; // 6us for GH in HT1 mode
+ }
+ else {
+ int lssel;
+ value = pci_read_config32(nb_dev, 0xac);
+ lssel = extractbits (value, 7, 8);
+ vgainfo.usUMADataReturnTime = 1300;
+ if (lssel == 0) vgainfo.usUMADataReturnTime = 150;
+ }
+ }
/* Transfer the Table to VBIOS. */
pointer = (u32 *)&vgainfo;
for(i=0; i<sizeof(ATOM_INTEGRATED_SYSTEM_INFO_V2); i+=4)
{
#if (CONFIG_GFXUMA == 1)
- *GpuF0MMReg = 0x80000000 + 0x10000000 - 512 + i;
+ *GpuF0MMReg = 0x80000000 + uma_memory_size - 512 + i;
#else
*GpuF0MMReg = 0x80000000 + 0x8000000 - 512 + i;
#endif
@@ -497,11 +545,22 @@ static void internal_gfx_pci_dev_init(struct device *dev)
/* GFX_InitLate. */
{
- u8 temp8;
- temp8 = pci_read_config8(dev, 0x4);
- //temp8 &= ~1; /* CIM clears this bit. Strangely, I can'd. */
- temp8 |= 1<<1|1<<2;
- pci_write_config8(dev, 0x4, temp8);
+ u32 temp;
+ temp = pci_read_config8(dev, 0x4);
+ //temp &= ~1; /* CIM clears this bit. Strangely, I can'd. */
+ temp |= 1<<1|1<<2;
+ pci_write_config8(dev, 0x4, temp);
+
+ // if the GFX debug bar is writable, then it has
+ // been programmed and can be safely enabled now
+ temp = pci_read_config32(nb_dev, 0x8c);
+
+ // if bits 1 (intgfx_enable) and 9 (gfx_debug_bar_enable)
+ // then enable gfx debug bar (set gxf_debug_decode_enable)
+ if (temp & 0x202)
+ temp |= (1 << 10);
+ pci_write_config32(nb_dev, 0x8c, temp);
+
}
#ifdef DONT_TRUST_RESOURCE_ALLOCATION
@@ -584,7 +643,6 @@ static void internal_gfx_pci_dev_init(struct device *dev)
* Set registers in RS780 and CPU to enable the internal GFX.
* Please refer to CIM source code and BKDG.
*/
-extern uint64_t uma_memory_base, uma_memory_size;
static void rs780_internal_gfx_enable(device_t dev)
{
@@ -637,7 +695,9 @@ static void rs780_internal_gfx_enable(device_t dev)
#if (CONFIG_GFXUMA == 1)
/* GFX_InitUMA. */
/* Copy CPU DDR Controller to NB MC. */
+ device_t k8_f1 = dev_find_slot(0, PCI_DEVFN(0x18, 1));
device_t k8_f2 = dev_find_slot(0, PCI_DEVFN(0x18, 2));
+ device_t k8_f4 = dev_find_slot(0, PCI_DEVFN(0x18, 4));
for (i = 0; i < 12; i++)
{
l_dword = pci_read_config32(k8_f2, 0x40 + i * 4);
@@ -646,23 +706,39 @@ static void rs780_internal_gfx_enable(device_t dev)
l_dword = pci_read_config32(k8_f2, 0x80);
nbmc_write_index(nb_dev, 0x3c, l_dword);
-
l_dword = pci_read_config32(k8_f2, 0x94);
- if(l_dword & (1<<22))
- set_nbmc_enable_bits(nb_dev, 0x3c, 0, 1<<16);
- else
- set_nbmc_enable_bits(nb_dev, 0x3c, 1<<16, 0);
-
- if(l_dword & (1<<8))
- set_nbmc_enable_bits(nb_dev, 0x3c, 0, 1<<17);
- else
- set_nbmc_enable_bits(nb_dev, 0x3c, 1<<17, 0);
-
+ set_nbmc_enable_bits(nb_dev, 0x3c, 0, !!(l_dword & (1<<22))<<16);
+ set_nbmc_enable_bits(nb_dev, 0x3c, 0, !!(l_dword & (1<< 8))<<17);
l_dword = pci_read_config32(k8_f2, 0x90);
- if(l_dword & (1<<10))
- set_nbmc_enable_bits(nb_dev, 0x3c, 0, 1<<18);
- else
- set_nbmc_enable_bits(nb_dev, 0x3c, 1<<18, 0);
+ set_nbmc_enable_bits(nb_dev, 0x3c, 0, !!(l_dword & (1<<10))<<18);
+ if (is_family10h())
+ {
+ for (i = 0; i < 12; i++)
+ {
+ l_dword = pci_read_config32(k8_f2, 0x140 + i * 4);
+ nbmc_write_index(nb_dev, 0x3d + i, l_dword);
+ }
+
+ l_dword = pci_read_config32(k8_f2, 0x180);
+ nbmc_write_index(nb_dev, 0x49, l_dword);
+ l_dword = pci_read_config32(k8_f2, 0x194);
+ set_nbmc_enable_bits(nb_dev, 0x49, 0, !!(l_dword & (1<<22))<<16);
+ set_nbmc_enable_bits(nb_dev, 0x49, 0, !!(l_dword & (1<< 8))<<17);
+ l_dword = pci_read_config32(k8_f2, 0x190);
+ set_nbmc_enable_bits(nb_dev, 0x49, 0, !!(l_dword & (1<<10))<<18);
+
+ l_dword = pci_read_config32(k8_f2, 0x110);
+ nbmc_write_index(nb_dev, 0x4a, l_dword);
+ l_dword = pci_read_config32(k8_f2, 0x114);
+ nbmc_write_index(nb_dev, 0x4b, l_dword);
+ l_dword = pci_read_config32(k8_f4, 0x44);
+ set_nbmc_enable_bits(nb_dev, 0x4a, 0, !!(l_dword & (1<<22))<<24);
+ l_dword = pci_read_config32(k8_f1, 0x40);
+ nbmc_write_index(nb_dev, 0x4c, l_dword);
+ l_dword = pci_read_config32(k8_f1, 0xf0);
+ nbmc_write_index(nb_dev, 0x4d, l_dword);
+ }
+
/* Set UMA in the 780 side. */
/* UMA start address, size. */
@@ -672,7 +748,7 @@ static void rs780_internal_gfx_enable(device_t dev)
nbmc_write_index(nb_dev, 0x10, ((uma_memory_size - 1 + 0xC0000000) & (~0xffff)) | 0xc000);
nbmc_write_index(nb_dev, 0x11, uma_memory_base);
nbmc_write_index(nb_dev, 0x12, 0);
- nbmc_write_index(nb_dev, 0xf0, 256);
+ nbmc_write_index(nb_dev, 0xf0, uma_memory_size >> 20);
/* GFX_InitUMA finished. */
#else
/* GFX_InitSP. */
@@ -1016,7 +1092,7 @@ void rs780_gfx_init(device_t nb_dev, device_t dev, u32 port)
/* 5.9.1.1. Disables the GFX REFCLK transmitter so that the GFX
* REFCLK PAD can be driven by an external source. */
/* 5.9.1.2. Enables GFX REFCLK receiver to receive the REFCLK from an external source. */
- set_nbmisc_enable_bits(nb_dev, 0x38, 1 << 29 | 1 << 28, 0 << 29 | 1 << 28);
+ set_nbmisc_enable_bits(nb_dev, 0x38, 1 << 29 | 1 << 28 | 1 << 26, 1 << 28);
/* 5.9.1.3 Selects the GFX REFCLK to be the source for PLL A. */
/* 5.9.1.4 Selects the GFX REFCLK to be the source for PLL B. */