blob: 3e6cb29383a6d0fcc1ae218b234224304739765e [file] [log] [blame]
Nils Jacobsd0ac7892011-12-30 23:00:11 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
5 * Copyright (C) 2010 Nils Jacobs
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Paul Menzela8ae1c62013-02-20 13:21:20 +010013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Nils Jacobsd0ac7892011-12-30 23:00:11 +010014 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000021#include <console/console.h>
22#include <arch/io.h>
23#include <stdint.h>
24#include <device/device.h>
25#include <device/pci.h>
26#include <device/pci_ids.h>
27#include <stdlib.h>
28#include <string.h>
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000029#include "northbridge.h"
30#include <cpu/amd/gx2def.h>
31#include <cpu/x86/msr.h>
32#include <cpu/x86/cache.h>
33
Nils Jacobs1c6d4e62010-12-26 05:12:49 +000034struct gliutable
35{
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000036 unsigned long desc_name;
37 unsigned short desc_type;
38 unsigned long hi, lo;
39};
40
41struct gliutable gliu0table[] = {
Nils Jacobsa4f06f12011-12-30 22:30:27 +010042 {.desc_name=GLIU0_P2D_BM_0, .desc_type= BM,.hi= MSR_MC + 0x0,.lo= 0x0FFF80}, /* 0-7FFFF to MC */
43 {.desc_name=GLIU0_P2D_BM_1, .desc_type= BM,.hi= MSR_MC + 0x0,.lo=(0x80 << 20) + 0x0FFFE0}, /* 80000-9ffff to Mc */
44 {.desc_name=GLIU0_P2D_SC_0, .desc_type= SC_SHADOW,.hi= MSR_MC + 0x0,.lo= 0x03}, /* C0000-Fffff split to MC and PCI (sub decode) A0000-Bffff handled by SoftVideo */
45 {.desc_name=GLIU0_P2D_R_0, .desc_type= R_SYSMEM,.hi= MSR_MC,.lo= 0x0}, /* Catch and fix dynamicly. */
46 {.desc_name=GLIU0_P2D_BMO_0, .desc_type= BMO_SMM,.hi= MSR_MC,.lo= 0x0}, /* Catch and fix dynamicly. */
47 {.desc_name=GLIU0_GLD_MSR_COH, .desc_type= OTHER,.hi= 0x0,.lo= GL0_CPU},
48 {.desc_name=GL_END, .desc_type= GL_END,.hi= 0x0,.lo= 0x0},
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000049};
50
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000051struct gliutable gliu1table[] = {
Nils Jacobsa4f06f12011-12-30 22:30:27 +010052 {.desc_name=GLIU1_P2D_BM_0, .desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= 0x0FFF80}, /* 0-7FFFF to MC */
53 {.desc_name=GLIU1_P2D_BM_1, .desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= (0x80 << 20) + 0x0FFFE0},/* 80000-9ffff to Mc */
54 {.desc_name=GLIU1_P2D_SC_0, .desc_type= SC_SHADOW,.hi= MSR_GL0 + 0x0,.lo= 0x03}, /* C0000-Fffff split to MC and PCI (sub decode) */
55 {.desc_name=GLIU1_P2D_R_0, .desc_type= R_SYSMEM,.hi= MSR_GL0,.lo= 0x0}, /* Catch and fix dynamicly. */
56 {.desc_name=GLIU1_P2D_BM_3, .desc_type= BM_SMM,.hi= MSR_GL0,.lo= 0x0}, /* Catch and fix dynamicly. */
57 {.desc_name=GLIU1_GLD_MSR_COH, .desc_type= OTHER,.hi= 0x0,.lo= GL1_GLIU0},
58 {.desc_name=GLIU1_IOD_SC_0, .desc_type= SCIO,.hi= (GL1_GLCP << 29) + 0x0,.lo= 0x033000F0}, /* FooGlue FPU 0xF0 */
59 {.desc_name=GL_END, .desc_type= GL_END,.hi= 0x0,.lo= 0x0},
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000060};
61
Nils Jacobsa4f06f12011-12-30 22:30:27 +010062struct gliutable *gliutables[] = { gliu0table, gliu1table, 0 };
Ronald G. Minnich42231882006-04-07 16:55:20 +000063
Nils Jacobs1c6d4e62010-12-26 05:12:49 +000064struct msrinit
65{
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000066 unsigned long msrnum;
Li-Ta Lod8d8fff2006-04-13 17:00:38 +000067 msr_t msr;
68};
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000069
Nils Jacobsa4f06f12011-12-30 22:30:27 +010070struct msrinit ClockGatingDefault[] = {
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000071 {GLIU0_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}},
Nils Jacobs5beac7f2010-11-03 13:19:50 +000072 /* MC must stay off in SDR mode. It is turned on in CPUBug??? lotus #77.142 */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000073 {MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}},
74 {GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}},
Nils Jacobs1c6d4e62010-12-26 05:12:49 +000075 {VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* lotus #77.163 */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000076 {GP_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}},
77 {DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0155}},
78 {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}},
79 {GLPCI_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}},
Nils Jacobs1c6d4e62010-12-26 05:12:49 +000080 {FG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* Always on */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000081 {0xffffffff, {0xffffffff, 0xffffffff}},
82};
Nils Jacobs1c6d4e62010-12-26 05:12:49 +000083
84/* All On */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000085struct msrinit ClockGatingAllOn[] = {
86 {GLIU0_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
87 {MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
88 {GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
89 {VG_GLD_MSR_PM, {.hi=0x00, .lo=0x00}},
90 {GP_GLD_MSR_PM, {.hi=0x00,.lo=0x000000001}},
91 {DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
92 {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
93 {GLPCI_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
94 {FG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}},
95 {0xffffffff, {0xffffffff, 0xffffffff}},
96};
97
Nils Jacobs1c6d4e62010-12-26 05:12:49 +000098/* Performance */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +000099struct msrinit ClockGatingPerformance[] = {
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000100 {VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* lotus #77.163 */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000101 {GP_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}},
102 {DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0155}},
103 {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}},
104 {0xffffffff, {0xffffffff, 0xffffffff}},
105};
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000106
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000107/* SET GeodeLink PRIORITY */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100108struct msrinit GeodeLinkPriorityTable[] = {
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000109 {CPU_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0220}}, /* CPU Priority. */
110 {DF_GLD_MSR_MASTER_CONF, {.hi=0x00,.lo=0x0000}}, /* DF Priority. */
111 {VG_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0720}}, /* VG Primary and Secondary Priority. */
112 {GP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0010}}, /* Graphics Priority. */
113 {GLPCI_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0027}}, /* GLPCI Priority + PID */
114 {GLCP_GLD_MSR_CONF, {.hi=0x00,.lo=0x0001}}, /* GLCP Priority + PID */
Nils Jacobs84be0f52010-12-29 21:12:10 +0000115 {FG_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0622}}, /* FG PID */
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000116 {0x0FFFFFFFF, {0x0FFFFFFFF, 0x0FFFFFFFF}}, /* END */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000117};
118
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000119static void writeglmsr(struct gliutable *gl)
120{
Ronald G. Minnich42231882006-04-07 16:55:20 +0000121 msr_t msr;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000122
Ronald G. Minnich42231882006-04-07 16:55:20 +0000123 msr.lo = gl->lo;
124 msr.hi = gl->hi;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000125 wrmsr(gl->desc_name, msr); /* MSR - see table above */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100126 printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__, gl->desc_name, msr.hi, msr.lo);
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000127}
128
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000129static void ShadowInit(struct gliutable *gl)
Li-Ta Lod8d8fff2006-04-13 17:00:38 +0000130{
Ronald G. Minnich42231882006-04-07 16:55:20 +0000131 msr_t msr;
132
133 msr = rdmsr(gl->desc_name);
134
135 if (msr.lo == 0) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000136 writeglmsr(gl);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000137 }
138}
139
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000140static void SysmemInit(struct gliutable *gl)
Li-Ta Lod8d8fff2006-04-13 17:00:38 +0000141{
Ronald G. Minnich42231882006-04-07 16:55:20 +0000142 msr_t msr;
143 int sizembytes, sizebytes;
144
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000145 /* Figure out how much RAM is in the machine and alocate all to the
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100146 * system. We will adjust for SMM now and Frame Buffer later.
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000147 */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000148 sizembytes = sizeram();
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100149 printk(BIOS_DEBUG, "%s: enable for %dMBytes\n", __func__, sizembytes);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000150 sizebytes = sizembytes << 20;
151
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100152 sizebytes -= ((SMM_SIZE * 1024) + 1);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000153
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100154 /* 20 bit address The bottom 12 bits go into bits 20-31 in msr.lo
155 The top 8 bits go into 0-7 of msr.hi. */
156 sizebytes --;
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000157 msr.hi = (gl->hi & 0xFFFFFF00) | (sizebytes >> 24);
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100158 sizebytes <<= 8; /* move bits 23:12 in bits 31:20. */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000159 sizebytes &= 0xfff00000;
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100160 sizebytes |= 0x100; /* start at 1MB */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000161 msr.lo = sizebytes;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000162 wrmsr(gl->desc_name, msr); /* MSR - see table above */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100163 printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__,
Ronald G. Minnich42231882006-04-07 16:55:20 +0000164 gl->desc_name, msr.hi, msr.lo);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000165}
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000166
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000167static void SMMGL0Init(struct gliutable *gl)
168{
Ronald G. Minnich42231882006-04-07 16:55:20 +0000169 msr_t msr;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100170 int sizebytes = sizeram() << 20;
Ronald G. Minnich42231882006-04-07 16:55:20 +0000171 long offset;
172
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100173 sizebytes -= (SMM_SIZE * 1024);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000174
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000175 printk(BIOS_DEBUG, "%s: %d bytes\n", __func__, sizebytes);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000176
177 offset = sizebytes - SMM_OFFSET;
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100178 offset = (offset >> 12) & 0x000fffff;
179 printk(BIOS_DEBUG, "%s: offset is 0x%08x\n", __func__, SMM_OFFSET);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000180
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100181 msr.hi = offset << 8 | gl->hi;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100182 msr.hi |= SMM_OFFSET >> 24;
Ronald G. Minnich42231882006-04-07 16:55:20 +0000183
184 msr.lo = SMM_OFFSET << 8;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100185 msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000186
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000187 wrmsr(gl->desc_name, msr); /* MSR - See table above */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100188 printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__, gl->desc_name, msr.hi, msr.lo);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000189}
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000190
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000191static void SMMGL1Init(struct gliutable *gl)
192{
Ronald G. Minnich42231882006-04-07 16:55:20 +0000193 msr_t msr;
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100194 printk(BIOS_DEBUG, "%s:\n", __func__);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000195
196 msr.hi = gl->hi;
197 /* I don't think this is needed */
198 msr.hi &= 0xffffff00;
199 msr.hi |= (SMM_OFFSET >> 24);
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100200 msr.lo = (SMM_OFFSET << 8) & 0xfff00000;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100201 msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000202
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000203 wrmsr(gl->desc_name, msr); /* MSR - See table above */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100204 printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__, gl->desc_name, msr.hi, msr.lo);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000205}
206
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000207static void GLIUInit(struct gliutable *gl)
208{
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100209 while (gl->desc_type != GL_END) {
210 switch (gl->desc_type) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000211 default:
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000212 writeglmsr(gl);
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000213 case SC_SHADOW: /* Check for a Shadow entry */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000214 ShadowInit(gl);
215 break;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000216
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000217 case R_SYSMEM: /* check for a SYSMEM entry */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000218 SysmemInit(gl);
219 break;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000220
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100221 case BMO_SMM: /* check for a SMM entry */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000222 SMMGL0Init(gl);
223 break;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000224
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100225 case BM_SMM: /* check for a SMM entry */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000226 SMMGL1Init(gl);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000227 break;
228 }
229 gl++;
230 }
Ronald G. Minnich42231882006-04-07 16:55:20 +0000231}
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000232
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000233/* Set up GLPCI settings for reads/write into memory.
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000234 *
235 * R0: 0-640KB,
236 * R1: 1MB - Top of System Memory
237 * R2: SMM Memory
238 * R3: Framebuffer? - not set up yet
239 * R4: ??
240 */
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000241static void GLPCIInit(void)
242{
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000243 struct gliutable *gl = 0;
244 int i;
245 msr_t msr;
246 int msrnum;
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000247
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000248 /* R0 - GLPCI settings for Conventional Memory space. */
249 msr.hi = (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; /* 640 */
250 msr.lo = 0; /* 0 */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100251 msr.lo |= GLPCI_RC_LOWER_EN_SET + GLPCI_RC_LOWER_PF_SET + GLPCI_RC_LOWER_WC_SET;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000252 msrnum = GLPCI_RC0;
253 wrmsr(msrnum, msr);
254
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000255 /* R1 - GLPCI settings for SysMem space. */
256 /* Get systop from GLIU0 SYSTOP Descriptor */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100257 for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000258 if (gliu0table[i].desc_type == R_SYSMEM) {
259 gl = &gliu0table[i];
260 break;
261 }
262 }
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000263 if (gl) {
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000264 unsigned long pah, pal;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000265 msrnum = gl->desc_name;
266 msr = rdmsr(msrnum);
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000267 /* example R_SYSMEM value: 20:00:00:0f:fb:f0:01:00
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100268 * translates to a base of 0x00100000 and top of 0xffbf0000
269 * base of 1M and top of around 256M
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000270 */
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000271 /* we have to create a page-aligned (4KB page) address for base and top
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000272 * so we need a high page aligned addresss (pah) and low page aligned address (pal)
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000273 * pah is from msr.hi << 12 | msr.low >> 20. pal is msr.lo << 12
274 */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100275 pah = ((msr.hi & 0xff) << 12) | ((msr.lo >> 20) & 0xfff);
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000276 /* we have the page address. Now make it a page-aligned address */
277 pah <<= 12;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000278
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000279 pal = msr.lo << 12;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100280 msr.hi = pah;
281 msr.lo = pal;
Ronald G. Minnichc01fe5d2006-05-03 03:30:23 +0000282 msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET | GLPCI_RC_LOWER_WC_SET;
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100283 printk(BIOS_DEBUG, "GLPCI R1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi);
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000284 msrnum = GLPCI_RC1;
285 wrmsr(msrnum, msr);
286 }
287
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000288 /* R2 - GLPCI settings for SMM space. */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100289 msr.hi = ((SMM_OFFSET + (SMM_SIZE * 1024 - 1)) >> 12) << GLPCI_RC_UPPER_TOP_SHIFT;
290 msr.lo = (SMM_OFFSET >> 12) << GLPCI_RC_LOWER_BASE_SHIFT;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000291 msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET;
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100292 printk(BIOS_DEBUG, "GLPCI R2: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi);
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000293 msrnum = GLPCI_RC2;
294 wrmsr(msrnum, msr);
295
296 /* this is done elsewhere already, but it does no harm to do it more than once */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100297 /* write serialize memory hole to PCI. Need to unWS when something is shadowed regardless of cachablility. */
298 msr.lo = 0x021212121; /* cache disabled and write serialized */
299 msr.hi = 0x021212121; /* cache disabled and write serialized */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000300
301 msrnum = CPU_RCONF_A0_BF;
302 wrmsr(msrnum, msr);
303
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000304 msrnum = CPU_RCONF_C0_DF;
305 wrmsr(msrnum, msr);
306
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000307 msrnum = CPU_RCONF_E0_FF;
308 wrmsr(msrnum, msr);
309
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000310 /* Set Non-Cacheable Read Only for NorthBound Transactions to Memory. The Enable bit is handled in the Shadow setup. */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000311 msrnum = GLPCI_A0_BF;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100312 msr.hi = 0x35353535;
313 msr.lo = 0x35353535;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000314 wrmsr(msrnum, msr);
315
316 msrnum = GLPCI_C0_DF;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100317 msr.hi = 0x35353535;
318 msr.lo = 0x35353535;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000319 wrmsr(msrnum, msr);
320
321 msrnum = GLPCI_E0_FF;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100322 msr.hi = 0x35353535;
323 msr.lo = 0x35353535;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000324 wrmsr(msrnum, msr);
325
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000326 /* Set WSREQ */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000327 msrnum = CPU_DM_CONFIG0;
328 msr = rdmsr(msrnum);
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100329 msr.hi &= ~(7 << DM_CONFIG0_UPPER_WSREQ_SHIFT);
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000330 msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT ; /* reduce to 1 for safe mode. */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000331 wrmsr(msrnum, msr);
332
333 /* we are ignoring the 5530 case for now, and perhaps forever. */
334
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100335 /* 553X NB Init */
Patrick Georgi472efa62012-02-16 20:44:20 +0100336
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100337 /* Arbiter setup */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000338 msrnum = GLPCI_ARB;
339 msr = rdmsr(msrnum);
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100340 msr.hi |= GLPCI_ARB_UPPER_PRE0_SET | GLPCI_ARB_UPPER_PRE1_SET;
341 msr.lo |= GLPCI_ARB_LOWER_IIE_SET;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000342 wrmsr(msrnum, msr);
343
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000344 msrnum = GLPCI_CTRL;
345 msr = rdmsr(msrnum);
346
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100347 msr.lo |= GLPCI_CTRL_LOWER_ME_SET | GLPCI_CTRL_LOWER_OWC_SET | GLPCI_CTRL_LOWER_PCD_SET; /* (Out will be disabled in CPUBUG649 for < 2.0 parts .) */
348 msr.lo |= GLPCI_CTRL_LOWER_LDE_SET;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000349
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100350 msr.lo &= ~(0x03 << GLPCI_CTRL_LOWER_IRFC_SHIFT);
351 msr.lo |= 0x02 << GLPCI_CTRL_LOWER_IRFC_SHIFT;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000352
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100353 msr.lo &= ~(0x07 << GLPCI_CTRL_LOWER_IRFT_SHIFT);
354 msr.lo |= 0x06 << GLPCI_CTRL_LOWER_IRFT_SHIFT;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000355
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100356 msr.hi &= ~(0x0f << GLPCI_CTRL_UPPER_FTH_SHIFT);
357 msr.hi |= 0x0F << GLPCI_CTRL_UPPER_FTH_SHIFT;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000358
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100359 msr.hi &= ~(0x0f << GLPCI_CTRL_UPPER_RTH_SHIFT);
360 msr.hi |= 0x0F << GLPCI_CTRL_UPPER_RTH_SHIFT;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000361
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100362 msr.hi &= ~(0x0f << GLPCI_CTRL_UPPER_SBRTH_SHIFT);
363 msr.hi |= 0x0F << GLPCI_CTRL_UPPER_SBRTH_SHIFT;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000364
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100365 msr.hi &= ~(0x03 << GLPCI_CTRL_UPPER_WTO_SHIFT);
366 msr.hi |= 0x06 << GLPCI_CTRL_UPPER_WTO_SHIFT;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000367
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100368 msr.hi &= ~(0x03 << GLPCI_CTRL_UPPER_ILTO_SHIFT);
369 msr.hi |= 0x00 << GLPCI_CTRL_UPPER_ILTO_SHIFT;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000370 wrmsr(msrnum, msr);
371
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000372 /* Set GLPCI Latency Timer. */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000373 msrnum = GLPCI_CTRL;
374 msr = rdmsr(msrnum);
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100375 msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT; /* Change once 1.x is gone. */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000376 wrmsr(msrnum, msr);
377
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000378 /* GLPCI_SPARE */
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000379 msrnum = GLPCI_SPARE;
380 msr = rdmsr(msrnum);
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100381 msr.lo &= ~0x7;
382 msr.lo |= GLPCI_SPARE_LOWER_AILTO_SET | GLPCI_SPARE_LOWER_PPD_SET | GLPCI_SPARE_LOWER_PPC_SET | GLPCI_SPARE_LOWER_MPC_SET | GLPCI_SPARE_LOWER_NSE_SET | GLPCI_SPARE_LOWER_SUPO_SET;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000383 wrmsr(msrnum, msr);
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000384}
385
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000386/* Enable Clock Gating. */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100387static void ClockGatingInit(void)
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000388{
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000389 msr_t msr;
390 struct msrinit *gating = ClockGatingDefault;
391 int i;
392
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100393 for (i = 0; gating->msrnum != 0xffffffff; i++) {
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000394 msr = rdmsr(gating->msrnum);
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000395 msr.hi |= gating->msr.hi;
396 msr.lo |= gating->msr.lo;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000397 wrmsr(gating->msrnum, msr); /* MSR - See the table above */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100398 gating += 1;
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000399 }
Ronald G. Minnich40fedaf2006-04-06 23:35:52 +0000400}
Ronald G. Minnich42231882006-04-07 16:55:20 +0000401
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000402static void GeodeLinkPriority(void)
403{
Stefan Reinauer86fc9842011-10-13 17:26:10 -0700404 msr_t msr = { 0, 0 };
Patrick Georgi472efa62012-02-16 20:44:20 +0100405
Ronald G. Minnich42231882006-04-07 16:55:20 +0000406 struct msrinit *prio = GeodeLinkPriorityTable;
407 int i;
408
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100409 for (i = 0; prio->msrnum != 0xffffffff; i++) {
Ronald G. Minnich42231882006-04-07 16:55:20 +0000410 msr = rdmsr(prio->msrnum);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000411 msr.hi |= prio->msr.hi;
412 msr.lo &= ~0xfff;
413 msr.lo |= prio->msr.lo;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000414 wrmsr(prio->msrnum, msr); /* MSR - See the table above */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100415 prio += 1;
Ronald G. Minnich42231882006-04-07 16:55:20 +0000416 }
417}
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000418
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000419/* Get the GLIU0 shadow register settings.
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000420 *
421 * If the setShadow function is used then all shadow descriptors
422 * will stay sync'ed.
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000423 */
424static uint64_t getShadow(void)
425{
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100426 msr_t msr = { 0, 0 };
Patrick Georgi472efa62012-02-16 20:44:20 +0100427
Nils Jacobs84be0f52010-12-29 21:12:10 +0000428 msr = rdmsr(GLIU0_P2D_SC_0);
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000429 return ( ( (uint64_t) msr.hi ) << 32 ) | msr.lo;
430}
431
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000432/* Set the cache RConf registers for the memory hole.
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000433 *
434 * Keeps all cache shadow descriptors sync'ed.
435 * This is part of the PCI lockup solution.
436 *
437 * Entry: EDX:EAX is the shadow settings.
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000438 */
439static void setShadowRCONF(uint32_t shadowHi, uint32_t shadowLo)
440{
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000441 /* ok this is whacky bit translation time. */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000442 int bit;
443 uint8_t shadowByte;
Stefan Reinauer86fc9842011-10-13 17:26:10 -0700444 msr_t msr = { 0, 0 };
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000445 shadowByte = (uint8_t) (shadowLo >> 16);
446
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000447 /* load up D000 settings in edx. */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000448 for (bit = 8; (bit > 4); bit--) {
449 msr.hi <<= 8;
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000450 msr.hi |= 1; /* cache disable PCI/Shadow memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000451 if (shadowByte && (1 << bit))
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000452 msr.hi |= 0x20; /* write serialize PCI memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000453 }
454
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000455 /* load up C000 settings in eax. */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100456 for (; bit; bit--) {
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000457 msr.lo <<= 8;
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000458 msr.lo |= 1; /* cache disable PCI/Shadow memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000459 if (shadowByte && (1 << bit))
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000460 msr.lo |= 0x20; /* write serialize PCI memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000461 }
462
463 wrmsr(CPU_RCONF_C0_DF, msr);
464
465 shadowByte = (uint8_t) (shadowLo >> 24);
466
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000467 /* load up F000 settings in edx. */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000468 for (bit = 8; (bit > 4); bit--) {
469 msr.hi <<= 8;
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000470 msr.hi |= 1; /* cache disable PCI/Shadow memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000471 if (shadowByte && (1 << bit))
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000472 msr.hi |= 0x20; /* write serialize PCI memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000473 }
474
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000475 /* load up E000 settings in eax. */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100476 for (; bit; bit--) {
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000477 msr.lo <<= 8;
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000478 msr.lo |= 1; /* cache disable PCI/Shadow memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000479 if (shadowByte && (1 << bit))
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000480 msr.lo |= 0x20; /* write serialize PCI memory */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000481 }
482
483 wrmsr(CPU_RCONF_E0_FF, msr);
484}
485
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000486/* Set the GLPCI registers for the memory hole.
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000487 * Keeps all cache shadow descriptors sync'ed.
488 * Entry: EDX:EAX is the shadow settings
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000489 */
490static void setShadowGLPCI(uint32_t shadowHi, uint32_t shadowLo)
491{
492 msr_t msr;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000493
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000494 /* Set the Enable Register. */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000495 msr = rdmsr(GLPCI_REN);
496 msr.lo &= 0xFFFF00FF;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100497 msr.lo |= ((shadowLo & 0xFFFF0000) >> 8);
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000498 wrmsr(GLPCI_REN, msr);
499}
500
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000501/* Set the GLIU SC register settings. Scans descriptor tables for SC_SHADOW.
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000502 * Keeps all shadow descriptors sync'ed.
503 * Entry: EDX:EAX is the shadow settings
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000504 */
505static void setShadow(uint64_t shadowSettings)
506{
507 int i;
508 msr_t msr;
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100509 struct gliutable *pTable;
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000510 uint32_t shadowLo, shadowHi;
511
512 shadowLo = (uint32_t) shadowSettings;
513 shadowHi = (uint32_t) (shadowSettings >> 32);
514
515 setShadowRCONF(shadowHi, shadowLo);
516 setShadowGLPCI(shadowHi, shadowLo);
517
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100518 for (i = 0; gliutables[i]; i++) {
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000519 for (pTable = gliutables[i]; pTable->desc_type != GL_END; pTable++) {
520 if (pTable->desc_type == SC_SHADOW) {
521
522 msr = rdmsr(pTable->desc_name);
523 msr.lo = (uint32_t) shadowSettings;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000524 msr.hi &= 0xFFFF0000; /* maintain PDID in upper EDX */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000525 msr.hi |= ((uint32_t) (shadowSettings >> 32)) & 0x0000FFFF;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000526 wrmsr(pTable->desc_name, msr); /* MSR - See the table above */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000527
528 }
529 }
530 }
531}
532
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100533static void rom_shadow_settings(void)
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000534{
535 uint64_t shadowSettings = getShadow();
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000536 shadowSettings &= (uint64_t) 0xFFFF00000000FFFFULL; /* Disable read & writes */
537 shadowSettings |= (uint64_t) 0x0000FFFFFFFF0000ULL; /* Enable reads for C0000-FFFFF */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000538 setShadow(shadowSettings);
539}
540
Nils Jacobs1c6d4e62010-12-26 05:12:49 +0000541/* Set up RCONF_DEFAULT and any other RCONF registers needed.
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000542 *
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000543 * DEVRC_RCONF_DEFAULT:
544 * ROMRC(63:56) = 04h ; write protect ROMBASE
545 * ROMBASE(36:55) = 0FFFC0h ; Top of PCI/bottom of rom chipselect area
546 * DEVRC(35:28) = 39h ; cache disabled in PCI memory + WS bit on + Write Combine + write burst.
547 * SYSTOP(27:8) = top of system memory
548 * SYSRC(7:0) = 00h ; writeback, can set to 08h to make writethrough
549 */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000550#define SYSMEM_RCONF_WRITETHROUGH 8
551#define DEVRC_RCONF_DEFAULT 0x21
552#define ROMBASE_RCONF_DEFAULT 0xFFFC0000
553#define ROMRC_RCONF_DEFAULT 0x25
554
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100555static void enable_L_cache(void)
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000556{
557 struct gliutable *gl = 0;
558 int i;
559 msr_t msr;
560 uint8_t SysMemCacheProp;
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000561
562 /* Locate SYSMEM entry in GLIU0table */
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100563 for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000564 if (gliu0table[i].desc_type == R_SYSMEM) {
565 gl = &gliu0table[i];
566 break;
567 }
568 }
569 if (gl == 0) {
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000570 post_code(0xCE); /* POST_RCONFInitError */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000571 while (1);
572 }
573
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000574/* sysdescfound: */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000575 msr = rdmsr(gl->desc_name);
576
Stefan Reinauer14e22772010-04-27 06:56:47 +0000577 /* 20 bit address - The bottom 12 bits go into bits 20-31 in eax, the
578 * top 8 bits go into 0-7 of edx.
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000579 */
580 msr.lo = (msr.lo & 0xFFFFFF00) | (msr.hi & 0xFF);
581 msr.lo = ((msr.lo << 12) | (msr.lo >> 20)) & 0x000FFFFF;
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000582 msr.lo <<= RCONF_DEFAULT_LOWER_SYSTOP_SHIFT; /* 8 */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000583
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000584 /* Set Default SYSMEM region properties */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100585 msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH; /* NOT writethrough == writeback 8 (or ~8) */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000586
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000587 /* Set PCI space cache properties */
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100588 msr.hi = (DEVRC_RCONF_DEFAULT >> 4); /* setting is split betwwen hi and lo... */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000589 msr.lo |= (DEVRC_RCONF_DEFAULT << 28);
590
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000591 /* Set the ROMBASE. This is usually FFFC0000h */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000592 msr.hi |= (ROMBASE_RCONF_DEFAULT >> 12) << RCONF_DEFAULT_UPPER_ROMBASE_SHIFT;
593
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000594 /* Set ROMBASE cache properties. */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000595 msr.hi |= ((ROMRC_RCONF_DEFAULT >> 8) | (ROMRC_RCONF_DEFAULT << 24));
Stefan Reinauer14e22772010-04-27 06:56:47 +0000596
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000597 /* now program RCONF_DEFAULT */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000598 wrmsr(CPU_RCONF_DEFAULT, msr);
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100599 printk(BIOS_DEBUG, "CPU_RCONF_DEFAULT (1808): 0x%08X:0x%08X\n", msr.hi, msr.lo);
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000600
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100601 /* RCONF_BYPASS: Cache tablewalk properties and SMM header access properties. */
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000602 /* Set to match system memory cache properties. */
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000603 msr = rdmsr(CPU_RCONF_DEFAULT);
604 SysMemCacheProp = (uint8_t) (msr.lo & 0xFF);
605 msr = rdmsr(CPU_RCONF_BYPASS);
606 msr.lo = (msr.lo & 0xFFFF0000) | (SysMemCacheProp << 8) | SysMemCacheProp;
607 wrmsr(CPU_RCONF_BYPASS, msr);
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100608 printk(BIOS_DEBUG, "CPU_RCONF_BYPASS (180A): 0x%08x : 0x%08x\n", msr.hi, msr.lo);
609}
610
611static void setup_gx2_cache(void)
612{
613 msr_t msr;
614
615 enable_L_cache();
616
617 /* Make sure all INVD instructions are treated as WBINVD. We do this
618 * because we've found some programs which require this behavior.
619 */
620 msr = rdmsr(CPU_DM_CONFIG0);
621 msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET;
622 wrmsr(CPU_DM_CONFIG0, msr);
623
624 x86_enable_cache();
625 wbinvd();
Ronald G. Minnichfb937492006-06-10 22:57:15 +0000626}
627
Nils Jacobs84be0f52010-12-29 21:12:10 +0000628uint32_t get_systop(void)
629{
630 struct gliutable *gl = 0;
631 uint32_t systop;
632 msr_t msr;
633 int i;
634
635 for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
636 if (gliu0table[i].desc_type == R_SYSMEM) {
637 gl = &gliu0table[i];
638 break;
639 }
640 }
641 if (gl) {
642 msr = rdmsr(gl->desc_name);
643 systop = ((msr.hi & 0xFF) << 24) | ((msr.lo & 0xFFF00000) >> 8);
644 systop += 0x1000; /* 4K */
645 } else {
646 systop =
647 ((sizeram() - CONFIG_VIDEO_MB) * 1024) - SMM_SIZE - 1024;
648 }
649 return systop;
650}
651
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000652/* Core Logic initialization: Host bridge. */
Nils Jacobs84be0f52010-12-29 21:12:10 +0000653void northbridge_init_early(void)
Li-Ta Lod8d8fff2006-04-13 17:00:38 +0000654{
Ronald G. Minnich42231882006-04-07 16:55:20 +0000655 int i;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000656 printk(BIOS_DEBUG, "Enter %s\n", __func__);
Li-Ta Lod8d8fff2006-04-13 17:00:38 +0000657
Nils Jacobsa4f06f12011-12-30 22:30:27 +0100658 for (i = 0; gliutables[i]; i++)
Ronald G. Minnich42231882006-04-07 16:55:20 +0000659 GLIUInit(gliutables[i]);
660
Nils Jacobs5beac7f2010-11-03 13:19:50 +0000661 /* Now that the descriptor to memory is set up. */
662 /* The memory controller needs one read to synch its lines before it can be used. */
Ronald G. Minnich42231882006-04-07 16:55:20 +0000663 i = *(int *) 0;
664
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100665 GeodeLinkPriority();
666
667 setup_gx2_cache();
668
669 rom_shadow_settings();
670
Ronald G. Minnich42231882006-04-07 16:55:20 +0000671 GLPCIInit();
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100672
Ronald G. Minnich42231882006-04-07 16:55:20 +0000673 ClockGatingInit();
Nils Jacobsd0ac7892011-12-30 23:00:11 +0100674
675 __asm__ __volatile__("FINIT\n");
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000676 printk(BIOS_DEBUG, "Exit %s\n", __func__);
Ronald G. Minnich42231882006-04-07 16:55:20 +0000677}
678