e55efcb667e2ccded9f172adad752fe015aa403e
[coreboot.git] / src / northbridge / amd / gx2 / northbridgeinit.c
1 /*
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
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * 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
21 #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>
29 #include <bitops.h>
30 #include "chip.h"
31 #include "northbridge.h"
32 #include <cpu/amd/gx2def.h>
33 #include <cpu/x86/msr.h>
34 #include <cpu/x86/cache.h>
35
36 struct gliutable
37 {
38         unsigned long desc_name;
39         unsigned short desc_type;
40         unsigned long hi, lo;
41 };
42
43 struct gliutable gliu0table[] = {
44         {.desc_name=GLIU0_P2D_BM_0,     .desc_type= BM,.hi= MSR_MC + 0x0,.lo= 0x0FFF80},                /* 0-7FFFF to MC */
45         {.desc_name=GLIU0_P2D_BM_1,     .desc_type= BM,.hi= MSR_MC + 0x0,.lo=(0x80 << 20) + 0x0FFFE0},  /* 80000-9ffff to Mc */
46         {.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 */
47         {.desc_name=GLIU0_P2D_R_0,      .desc_type= R_SYSMEM,.hi= MSR_MC,.lo= 0x0},                     /* Catch and fix dynamicly. */
48         {.desc_name=GLIU0_P2D_BMO_0,    .desc_type= BMO_SMM,.hi= MSR_MC,.lo= 0x0},                      /* Catch and fix dynamicly. */
49         {.desc_name=GLIU0_GLD_MSR_COH,  .desc_type= OTHER,.hi= 0x0,.lo= GL0_CPU},
50         {.desc_name=GL_END,             .desc_type= GL_END,.hi= 0x0,.lo= 0x0},
51 };
52
53 struct gliutable gliu1table[] = {
54         {.desc_name=GLIU1_P2D_BM_0,     .desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= 0x0FFF80},               /* 0-7FFFF to MC */
55         {.desc_name=GLIU1_P2D_BM_1,     .desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= (0x80 << 20) + 0x0FFFE0},/* 80000-9ffff to Mc */
56         {.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) */
57         {.desc_name=GLIU1_P2D_R_0,      .desc_type= R_SYSMEM,.hi= MSR_GL0,.lo= 0x0},                    /* Catch and fix dynamicly. */
58         {.desc_name=GLIU1_P2D_BM_3,     .desc_type= BM_SMM,.hi= MSR_GL0,.lo= 0x0},                      /* Catch and fix dynamicly. */
59         {.desc_name=GLIU1_GLD_MSR_COH,  .desc_type= OTHER,.hi= 0x0,.lo= GL1_GLIU0},
60         {.desc_name=GLIU1_IOD_SC_0,     .desc_type= SCIO,.hi= (GL1_GLCP << 29) + 0x0,.lo= 0x033000F0},  /* FooGlue FPU 0xF0 */
61         {.desc_name=GL_END,             .desc_type= GL_END,.hi= 0x0,.lo= 0x0},
62 };
63
64 struct gliutable *gliutables[] = { gliu0table, gliu1table, 0 };
65
66 struct msrinit
67 {
68         unsigned long msrnum;
69         msr_t msr;
70 };
71
72 struct msrinit ClockGatingDefault[] = {
73         {GLIU0_GLD_MSR_PM,      {.hi=0x00,.lo=0x0005}},
74         /* MC must stay off in SDR mode. It is turned on in CPUBug??? lotus #77.142 */
75         {MC_GLD_MSR_PM,         {.hi=0x00,.lo=0x0000}},
76         {GLIU1_GLD_MSR_PM,      {.hi=0x00,.lo=0x0005}},
77         {VG_GLD_MSR_PM,         {.hi=0x00,.lo=0x0000}}, /* lotus #77.163 */
78         {GP_GLD_MSR_PM,         {.hi=0x00,.lo=0x0001}},
79         {DF_GLD_MSR_PM,         {.hi=0x00,.lo=0x0155}},
80         {GLCP_GLD_MSR_PM,       {.hi=0x00,.lo=0x0015}},
81         {GLPCI_GLD_MSR_PM,      {.hi=0x00,.lo=0x0015}},
82         {FG_GLD_MSR_PM,         {.hi=0x00,.lo=0x0000}}, /* Always on */
83         {0xffffffff,                            {0xffffffff, 0xffffffff}},
84 };
85
86 /* All On */
87 struct msrinit ClockGatingAllOn[] = {
88         {GLIU0_GLD_MSR_PM,      {.hi=0x00,.lo=0x0FFFFFFFF}},
89         {MC_GLD_MSR_PM,         {.hi=0x00,.lo=0x0FFFFFFFF}},
90         {GLIU1_GLD_MSR_PM,      {.hi=0x00,.lo=0x0FFFFFFFF}},
91         {VG_GLD_MSR_PM,         {.hi=0x00, .lo=0x00}},
92         {GP_GLD_MSR_PM,         {.hi=0x00,.lo=0x000000001}},
93         {DF_GLD_MSR_PM,         {.hi=0x00,.lo=0x0FFFFFFFF}},
94         {GLCP_GLD_MSR_PM,       {.hi=0x00,.lo=0x0FFFFFFFF}},
95         {GLPCI_GLD_MSR_PM,      {.hi=0x00,.lo=0x0FFFFFFFF}},
96         {FG_GLD_MSR_PM,         {.hi=0x00,.lo=0x0000}},
97         {0xffffffff,                            {0xffffffff, 0xffffffff}},
98 };
99
100 /* Performance */
101 struct msrinit ClockGatingPerformance[] = {
102         {VG_GLD_MSR_PM,         {.hi=0x00,.lo=0x0000}}, /* lotus #77.163 */
103         {GP_GLD_MSR_PM,         {.hi=0x00,.lo=0x0001}},
104         {DF_GLD_MSR_PM,         {.hi=0x00,.lo=0x0155}},
105         {GLCP_GLD_MSR_PM,       {.hi=0x00,.lo=0x0015}},
106         {0xffffffff,                            {0xffffffff, 0xffffffff}},
107 };
108
109 /* SET GeodeLink PRIORITY */
110 struct msrinit GeodeLinkPriorityTable[] = {
111         {CPU_GLD_MSR_CONFIG,            {.hi=0x00,.lo=0x0220}},         /* CPU Priority. */
112         {DF_GLD_MSR_MASTER_CONF,        {.hi=0x00,.lo=0x0000}},         /* DF Priority. */
113         {VG_GLD_MSR_CONFIG,             {.hi=0x00,.lo=0x0720}},         /* VG Primary and Secondary Priority. */
114         {GP_GLD_MSR_CONFIG,             {.hi=0x00,.lo=0x0010}},         /* Graphics Priority. */
115         {GLPCI_GLD_MSR_CONFIG,          {.hi=0x00,.lo=0x0027}},         /* GLPCI Priority + PID */
116         {GLCP_GLD_MSR_CONF,             {.hi=0x00,.lo=0x0001}},         /* GLCP Priority + PID */
117         {FG_GLD_MSR_CONFIG,             {.hi=0x00,.lo=0x0622}},         /* FG PID */
118         {0x0FFFFFFFF,                   {0x0FFFFFFFF, 0x0FFFFFFFF}},    /* END */
119 };
120
121 static void writeglmsr(struct gliutable *gl)
122 {
123         msr_t msr;
124
125         msr.lo = gl->lo;
126         msr.hi = gl->hi;
127         wrmsr(gl->desc_name, msr);      /* MSR - see table above */
128         printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__, gl->desc_name, msr.hi, msr.lo);
129 }
130
131 static void ShadowInit(struct gliutable *gl)
132 {
133         msr_t msr;
134
135         msr = rdmsr(gl->desc_name);
136
137         if (msr.lo == 0) {
138                 writeglmsr(gl);
139         }
140 }
141
142 static void SysmemInit(struct gliutable *gl)
143 {
144         msr_t msr;
145         int sizembytes, sizebytes;
146
147         /* Figure out how much RAM is in the machine and alocate all to the
148          * system. We will adjust for SMM now and Frame Buffer later.
149          */
150         sizembytes = sizeram();
151         printk(BIOS_DEBUG, "%s: enable for %dMBytes\n", __func__, sizembytes);
152         sizebytes = sizembytes << 20;
153
154         sizebytes -= ((SMM_SIZE * 1024) + 1);
155
156         /* 20 bit address The bottom 12 bits go into bits 20-31 in msr.lo
157            The top 8 bits go into 0-7 of msr.hi. */
158         sizebytes --;
159         msr.hi = (gl->hi & 0xFFFFFF00) | (sizebytes >> 24);
160         sizebytes <<= 8;        /* move bits 23:12 in bits 31:20. */
161         sizebytes &= 0xfff00000;
162         sizebytes |= 0x100;     /* start at 1MB */
163         msr.lo = sizebytes;
164         wrmsr(gl->desc_name, msr);      /* MSR - see table above */
165         printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__,
166                                 gl->desc_name, msr.hi, msr.lo);
167 }
168
169 static void SMMGL0Init(struct gliutable *gl)
170 {
171         msr_t msr;
172         int sizebytes = sizeram() << 20;
173         long offset;
174
175         sizebytes -= (SMM_SIZE * 1024);
176
177         printk(BIOS_DEBUG, "%s: %d bytes\n", __func__, sizebytes);
178
179         offset = sizebytes - SMM_OFFSET;
180         offset = (offset >> 12) & 0x000fffff;
181         printk(BIOS_DEBUG, "%s: offset is 0x%08x\n", __func__, SMM_OFFSET);
182
183         msr.hi = offset << 8 | gl->hi;
184         msr.hi |= SMM_OFFSET >> 24;
185
186         msr.lo = SMM_OFFSET << 8;
187         msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff;
188
189         wrmsr(gl->desc_name, msr);      /* MSR - See table above */
190         printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__, gl->desc_name, msr.hi, msr.lo);
191 }
192
193 static void SMMGL1Init(struct gliutable *gl)
194 {
195         msr_t msr;
196         printk(BIOS_DEBUG, "%s:\n", __func__);
197
198         msr.hi = gl->hi;
199         /* I don't think this is needed */
200         msr.hi &= 0xffffff00;
201         msr.hi |= (SMM_OFFSET >> 24);
202         msr.lo = (SMM_OFFSET << 8) & 0xfff00000;
203         msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff;
204
205         wrmsr(gl->desc_name, msr);      /* MSR - See table above */
206         printk(BIOS_DEBUG, "%s: MSR 0x%08lx, val 0x%08x:0x%08x\n", __func__, gl->desc_name, msr.hi, msr.lo);
207 }
208
209 static void GLIUInit(struct gliutable *gl)
210 {
211         while (gl->desc_type != GL_END) {
212                 switch (gl->desc_type) {
213                 default:
214                         writeglmsr(gl);
215                 case SC_SHADOW: /* Check for a Shadow entry */
216                         ShadowInit(gl);
217                         break;
218
219                 case R_SYSMEM: /* check for a SYSMEM entry */
220                         SysmemInit(gl);
221                         break;
222
223                 case BMO_SMM: /* check for a SMM entry */
224                         SMMGL0Init(gl);
225                         break;
226
227                 case BM_SMM: /* check for a SMM entry */
228                         SMMGL1Init(gl);
229                         break;
230                 }
231                 gl++;
232         }
233 }
234
235 /* Set up GLPCI settings for reads/write into memory.
236  *
237  * R0:  0-640KB,
238  * R1:  1MB - Top of System Memory
239  * R2: SMM Memory
240  * R3: Framebuffer? - not set up yet
241  * R4: ??
242  */
243 static void GLPCIInit(void)
244 {
245         struct gliutable *gl = 0;
246         int i;
247         msr_t msr;
248         int msrnum;
249
250         /* R0 - GLPCI settings for Conventional Memory space. */
251         msr.hi =  (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; /* 640 */
252         msr.lo =  0;                                            /* 0 */
253         msr.lo |= GLPCI_RC_LOWER_EN_SET + GLPCI_RC_LOWER_PF_SET + GLPCI_RC_LOWER_WC_SET;
254         msrnum = GLPCI_RC0;
255         wrmsr(msrnum, msr);
256
257         /* R1 - GLPCI settings for SysMem space. */
258         /* Get systop from GLIU0 SYSTOP Descriptor */
259         for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
260                 if (gliu0table[i].desc_type == R_SYSMEM) {
261                         gl = &gliu0table[i];
262                         break;
263                 }
264         }
265         if (gl) {
266                 unsigned long pah, pal;
267                 msrnum = gl->desc_name;
268                 msr = rdmsr(msrnum);
269                 /* example R_SYSMEM value: 20:00:00:0f:fb:f0:01:00
270                  * translates to a base of 0x00100000 and top of 0xffbf0000
271                  * base of 1M and top of around 256M
272                  */
273                 /* we have to create a page-aligned (4KB page) address for base and top
274                  * so we need a high page aligned addresss (pah) and low page aligned address (pal)
275                  * pah is from msr.hi << 12 | msr.low >> 20. pal is msr.lo << 12
276                  */
277                 pah = ((msr.hi & 0xff) << 12) | ((msr.lo >> 20) & 0xfff);
278                 /* we have the page address. Now make it a page-aligned address */
279                 pah <<= 12;
280
281                 pal = msr.lo << 12;
282                 msr.hi = pah;
283                 msr.lo = pal;
284                 msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET | GLPCI_RC_LOWER_WC_SET;
285                 printk(BIOS_DEBUG, "GLPCI R1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi);
286                 msrnum = GLPCI_RC1;
287                 wrmsr(msrnum, msr);
288         }
289
290         /* R2 - GLPCI settings for SMM space. */
291         msr.hi = ((SMM_OFFSET + (SMM_SIZE * 1024 - 1)) >> 12) << GLPCI_RC_UPPER_TOP_SHIFT;
292         msr.lo = (SMM_OFFSET >> 12) << GLPCI_RC_LOWER_BASE_SHIFT;
293         msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET;
294         printk(BIOS_DEBUG, "GLPCI R2: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi);
295         msrnum = GLPCI_RC2;
296         wrmsr(msrnum, msr);
297
298         /* this is done elsewhere already, but it does no harm to do it more than once */
299         /* write serialize memory hole to PCI. Need to unWS when something is shadowed regardless of cachablility. */
300         msr.lo = 0x021212121;   /* cache disabled and write serialized */
301         msr.hi = 0x021212121;   /* cache disabled and write serialized */
302
303         msrnum = CPU_RCONF_A0_BF;
304         wrmsr(msrnum, msr);
305
306         msrnum = CPU_RCONF_C0_DF;
307         wrmsr(msrnum, msr);
308
309         msrnum = CPU_RCONF_E0_FF;
310         wrmsr(msrnum, msr);
311
312         /* Set Non-Cacheable Read Only for NorthBound Transactions to Memory. The Enable bit is handled in the Shadow setup. */
313         msrnum = GLPCI_A0_BF;
314         msr.hi = 0x35353535;
315         msr.lo = 0x35353535;
316         wrmsr(msrnum, msr);
317
318         msrnum = GLPCI_C0_DF;
319         msr.hi = 0x35353535;
320         msr.lo = 0x35353535;
321         wrmsr(msrnum, msr);
322
323         msrnum = GLPCI_E0_FF;
324         msr.hi = 0x35353535;
325         msr.lo = 0x35353535;
326         wrmsr(msrnum, msr);
327
328         /* Set WSREQ */
329         msrnum = CPU_DM_CONFIG0;
330         msr = rdmsr(msrnum);
331         msr.hi &= ~(7 << DM_CONFIG0_UPPER_WSREQ_SHIFT);
332         msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT     ;       /* reduce to 1 for safe mode. */
333         wrmsr(msrnum, msr);
334
335         /* we are ignoring the 5530 case for now, and perhaps forever. */
336
337         /* 553X NB Init */
338         
339         /* Arbiter setup */
340         msrnum = GLPCI_ARB;
341         msr = rdmsr(msrnum);
342         msr.hi |= GLPCI_ARB_UPPER_PRE0_SET | GLPCI_ARB_UPPER_PRE1_SET;
343         msr.lo |= GLPCI_ARB_LOWER_IIE_SET;
344         wrmsr(msrnum, msr);
345
346         msrnum = GLPCI_CTRL;
347         msr = rdmsr(msrnum);
348
349         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 .) */
350         msr.lo |= GLPCI_CTRL_LOWER_LDE_SET;
351
352         msr.lo &= ~(0x03 << GLPCI_CTRL_LOWER_IRFC_SHIFT);
353         msr.lo |= 0x02 << GLPCI_CTRL_LOWER_IRFC_SHIFT;
354
355         msr.lo &= ~(0x07 << GLPCI_CTRL_LOWER_IRFT_SHIFT);
356         msr.lo |= 0x06 << GLPCI_CTRL_LOWER_IRFT_SHIFT;
357
358         msr.hi &= ~(0x0f << GLPCI_CTRL_UPPER_FTH_SHIFT);
359         msr.hi |= 0x0F << GLPCI_CTRL_UPPER_FTH_SHIFT;
360
361         msr.hi &= ~(0x0f << GLPCI_CTRL_UPPER_RTH_SHIFT);
362         msr.hi |= 0x0F << GLPCI_CTRL_UPPER_RTH_SHIFT;
363
364         msr.hi &= ~(0x0f << GLPCI_CTRL_UPPER_SBRTH_SHIFT);
365         msr.hi |= 0x0F << GLPCI_CTRL_UPPER_SBRTH_SHIFT;
366
367         msr.hi &= ~(0x03 << GLPCI_CTRL_UPPER_WTO_SHIFT);
368         msr.hi |= 0x06 << GLPCI_CTRL_UPPER_WTO_SHIFT;
369
370         msr.hi &= ~(0x03 << GLPCI_CTRL_UPPER_ILTO_SHIFT);
371         msr.hi |= 0x00 << GLPCI_CTRL_UPPER_ILTO_SHIFT;
372         wrmsr(msrnum, msr);
373
374         /* Set GLPCI Latency Timer. */
375         msrnum = GLPCI_CTRL;
376         msr = rdmsr(msrnum);
377         msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT;   /* Change once 1.x is gone. */
378         wrmsr(msrnum, msr);
379
380         /* GLPCI_SPARE */
381         msrnum = GLPCI_SPARE;
382         msr = rdmsr(msrnum);
383         msr.lo &= ~0x7;
384         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;
385         wrmsr(msrnum, msr);
386 }
387
388 /* Enable Clock Gating. */
389 static void ClockGatingInit(void)
390 {
391         msr_t msr;
392         struct msrinit *gating = ClockGatingDefault;
393         int i;
394
395         for (i = 0; gating->msrnum != 0xffffffff; i++) {
396                 msr = rdmsr(gating->msrnum);
397                 msr.hi |= gating->msr.hi;
398                 msr.lo |= gating->msr.lo;
399                 wrmsr(gating->msrnum, msr);     /* MSR - See the table above */
400                 gating += 1;
401         }
402 }
403
404 static void GeodeLinkPriority(void)
405 {
406         msr_t msr = { 0, 0 };
407         
408         struct msrinit *prio = GeodeLinkPriorityTable;
409         int i;
410
411         for (i = 0; prio->msrnum != 0xffffffff; i++) {
412                 msr = rdmsr(prio->msrnum);
413                 msr.hi |= prio->msr.hi;
414                 msr.lo &= ~0xfff;
415                 msr.lo |= prio->msr.lo;
416                 wrmsr(prio->msrnum, msr);       /* MSR - See the table above */
417                 prio += 1;
418         }
419 }
420
421 /* Get the GLIU0 shadow register settings.
422  *
423  * If the setShadow function is used then all shadow descriptors
424  * will stay sync'ed.
425  */
426 static uint64_t getShadow(void)
427 {
428         msr_t msr = { 0, 0 };
429         
430         msr = rdmsr(GLIU0_P2D_SC_0);
431         return ( ( (uint64_t) msr.hi ) << 32 ) | msr.lo;
432 }
433
434 /* Set the cache RConf registers for the memory hole.
435  *
436  * Keeps all cache shadow descriptors sync'ed.
437  * This is part of the PCI lockup solution.
438  *
439  * Entry: EDX:EAX is the shadow settings.
440  */
441 static void setShadowRCONF(uint32_t shadowHi, uint32_t shadowLo)
442 {
443         /* ok this is whacky bit translation time. */
444         int bit;
445         uint8_t shadowByte;
446         msr_t msr = { 0, 0 };
447         shadowByte = (uint8_t) (shadowLo >> 16);
448
449         /* load up D000 settings in edx. */
450         for (bit = 8; (bit > 4); bit--) {
451                 msr.hi <<= 8;
452                 msr.hi |= 1;                    /* cache disable PCI/Shadow memory */
453                 if (shadowByte && (1 << bit))
454                         msr.hi |= 0x20;         /* write serialize PCI memory */
455         }
456
457         /* load up C000 settings in eax. */
458         for (; bit; bit--) {
459                 msr.lo <<= 8;
460                 msr.lo |= 1;                    /* cache disable PCI/Shadow memory */
461                 if (shadowByte && (1 << bit))
462                         msr.lo |= 0x20;         /* write serialize PCI memory */
463         }
464
465         wrmsr(CPU_RCONF_C0_DF, msr);
466
467         shadowByte = (uint8_t) (shadowLo >> 24);
468
469         /* load up F000 settings in edx. */
470         for (bit = 8; (bit > 4); bit--) {
471                 msr.hi <<= 8;
472                 msr.hi |= 1;                    /* cache disable PCI/Shadow memory */
473                 if (shadowByte && (1 << bit))
474                         msr.hi |= 0x20;         /* write serialize PCI memory */
475         }
476
477         /* load up E000 settings in eax. */
478         for (; bit; bit--) {
479                 msr.lo <<= 8;
480                 msr.lo |= 1;                    /* cache disable PCI/Shadow memory */
481                 if (shadowByte && (1 << bit))
482                         msr.lo |= 0x20;         /* write serialize PCI memory */
483         }
484
485         wrmsr(CPU_RCONF_E0_FF, msr);
486 }
487
488 /* Set the GLPCI registers for the memory hole.
489  * Keeps all cache shadow descriptors sync'ed.
490  * Entry: EDX:EAX is the shadow settings
491  */
492 static void setShadowGLPCI(uint32_t shadowHi, uint32_t shadowLo)
493 {
494         msr_t msr;
495
496         /* Set the Enable Register. */
497         msr = rdmsr(GLPCI_REN);
498         msr.lo &= 0xFFFF00FF;
499         msr.lo |= ((shadowLo & 0xFFFF0000) >> 8);
500         wrmsr(GLPCI_REN, msr);
501 }
502
503 /* Set the GLIU SC register settings. Scans descriptor tables for SC_SHADOW.
504  * Keeps all shadow descriptors sync'ed.
505  * Entry: EDX:EAX is the shadow settings
506  */
507 static void setShadow(uint64_t shadowSettings)
508 {
509         int i;
510         msr_t msr;
511         struct gliutable *pTable;
512         uint32_t shadowLo, shadowHi;
513
514         shadowLo = (uint32_t) shadowSettings;
515         shadowHi = (uint32_t) (shadowSettings >> 32);
516
517         setShadowRCONF(shadowHi, shadowLo);
518         setShadowGLPCI(shadowHi, shadowLo);
519
520         for (i = 0; gliutables[i]; i++) {
521                 for (pTable = gliutables[i]; pTable->desc_type != GL_END; pTable++) {
522                         if (pTable->desc_type == SC_SHADOW) {
523
524                                 msr = rdmsr(pTable->desc_name);
525                                 msr.lo = (uint32_t) shadowSettings;
526                                 msr.hi &= 0xFFFF0000;           /* maintain PDID in upper EDX */
527                                 msr.hi |= ((uint32_t) (shadowSettings >> 32)) & 0x0000FFFF;
528                                 wrmsr(pTable->desc_name, msr);  /* MSR - See the table above */
529
530                         }
531                 }
532         }
533 }
534
535 static void rom_shadow_settings(void)
536 {
537         uint64_t shadowSettings = getShadow();
538         shadowSettings &= (uint64_t) 0xFFFF00000000FFFFULL;     /* Disable read & writes */
539         shadowSettings |= (uint64_t) 0x0000FFFFFFFF0000ULL;     /* Enable reads for C0000-FFFFF */
540         setShadow(shadowSettings);
541 }
542
543 /* Set up RCONF_DEFAULT and any other RCONF registers needed.
544  *
545  * DEVRC_RCONF_DEFAULT:
546  * ROMRC(63:56) = 04h    ; write protect ROMBASE
547  * ROMBASE(36:55) = 0FFFC0h ; Top of PCI/bottom of rom chipselect area
548  * DEVRC(35:28) =  39h   ; cache disabled in PCI memory + WS bit on + Write Combine + write burst.
549  * SYSTOP(27:8) = top of system memory
550  * SYSRC(7:0) = 00h              ; writeback, can set to 08h to make writethrough
551  */
552 #define SYSMEM_RCONF_WRITETHROUGH 8
553 #define DEVRC_RCONF_DEFAULT 0x21
554 #define ROMBASE_RCONF_DEFAULT 0xFFFC0000
555 #define ROMRC_RCONF_DEFAULT 0x25
556
557 static void enable_L_cache(void)
558 {
559         struct gliutable *gl = 0;
560         int i;
561         msr_t msr;
562         uint8_t SysMemCacheProp;
563
564         /* Locate SYSMEM entry in GLIU0table */
565         for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
566                 if (gliu0table[i].desc_type == R_SYSMEM) {
567                         gl = &gliu0table[i];
568                         break;
569                 }
570         }
571         if (gl == 0) {
572                 post_code(0xCE);        /* POST_RCONFInitError */
573                 while (1);
574         }
575
576 /* sysdescfound: */
577         msr = rdmsr(gl->desc_name);
578
579         /* 20 bit address -  The bottom 12 bits go into bits 20-31 in eax, the
580          * top 8 bits go into 0-7 of edx.
581          */
582         msr.lo = (msr.lo & 0xFFFFFF00) | (msr.hi & 0xFF);
583         msr.lo = ((msr.lo << 12) | (msr.lo >> 20)) & 0x000FFFFF;
584         msr.lo <<= RCONF_DEFAULT_LOWER_SYSTOP_SHIFT;    /* 8 */
585
586         /* Set Default SYSMEM region properties */
587         msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH;   /* NOT writethrough == writeback 8 (or ~8) */
588
589         /* Set PCI space cache properties */
590         msr.hi = (DEVRC_RCONF_DEFAULT >> 4);    /* setting is split betwwen hi and lo... */
591         msr.lo |= (DEVRC_RCONF_DEFAULT << 28);
592
593         /* Set the ROMBASE. This is usually FFFC0000h */
594         msr.hi |= (ROMBASE_RCONF_DEFAULT >> 12) << RCONF_DEFAULT_UPPER_ROMBASE_SHIFT;
595
596         /* Set ROMBASE cache properties. */
597         msr.hi |= ((ROMRC_RCONF_DEFAULT >> 8) | (ROMRC_RCONF_DEFAULT << 24));
598
599         /* now program RCONF_DEFAULT */
600         wrmsr(CPU_RCONF_DEFAULT, msr);
601         printk(BIOS_DEBUG, "CPU_RCONF_DEFAULT (1808): 0x%08X:0x%08X\n", msr.hi, msr.lo);
602
603         /* RCONF_BYPASS: Cache tablewalk properties and SMM header access properties. */
604         /* Set to match system memory cache properties. */
605         msr = rdmsr(CPU_RCONF_DEFAULT);
606         SysMemCacheProp = (uint8_t) (msr.lo & 0xFF);
607         msr = rdmsr(CPU_RCONF_BYPASS);
608         msr.lo = (msr.lo & 0xFFFF0000) | (SysMemCacheProp << 8) | SysMemCacheProp;
609         wrmsr(CPU_RCONF_BYPASS, msr);
610         printk(BIOS_DEBUG, "CPU_RCONF_BYPASS (180A): 0x%08x : 0x%08x\n", msr.hi, msr.lo);
611 }
612
613 static void setup_gx2_cache(void)
614 {
615         msr_t msr;
616
617         enable_L_cache();
618
619         /* Make sure all INVD instructions are treated as WBINVD.  We do this
620          * because we've found some programs which require this behavior.
621          */
622         msr = rdmsr(CPU_DM_CONFIG0);
623         msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET;
624         wrmsr(CPU_DM_CONFIG0, msr);
625
626         x86_enable_cache();
627         wbinvd();
628 }
629
630 uint32_t get_systop(void)
631 {
632         struct gliutable *gl = 0;
633         uint32_t systop;
634         msr_t msr;
635         int i;
636
637         for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
638                 if (gliu0table[i].desc_type == R_SYSMEM) {
639                         gl = &gliu0table[i];
640                         break;
641                 }
642         }
643         if (gl) {
644                 msr = rdmsr(gl->desc_name);
645                 systop = ((msr.hi & 0xFF) << 24) | ((msr.lo & 0xFFF00000) >> 8);
646                 systop += 0x1000;       /* 4K */
647         } else {
648                 systop =
649                     ((sizeram() - CONFIG_VIDEO_MB) * 1024) - SMM_SIZE - 1024;
650         }
651         return systop;
652 }
653
654 /* Core Logic initialization: Host bridge. */
655 void northbridge_init_early(void)
656 {
657         int i;
658         printk(BIOS_DEBUG, "Enter %s\n", __func__);
659
660         for (i = 0; gliutables[i]; i++)
661                 GLIUInit(gliutables[i]);
662
663         /* Now that the descriptor to memory is set up. */
664         /* The memory controller needs one read to synch its lines before it can be used. */
665         i = *(int *) 0;
666
667         GeodeLinkPriority();
668
669         setup_gx2_cache();
670
671         rom_shadow_settings();
672
673         GLPCIInit();
674
675         ClockGatingInit();
676
677         __asm__ __volatile__("FINIT\n");
678         printk(BIOS_DEBUG, "Exit %s\n", __func__);
679 }
680