dd65b508ca409974c4c41df0e186461580ddaef0
[coreboot.git] / src / southbridge / via / k8t890 / dram.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
5  * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me@gmail.com>
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 as published by
9  * the Free Software Foundation; version 2 of the License.
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 <device/device.h>
22 #include <device/pci.h>
23 #include <device/pci_ids.h>
24 #include <console/console.h>
25 #include <cpu/x86/msr.h>
26 #include <cpu/amd/mtrr.h>
27 #include <pc80/mc146818rtc.h>
28 #include <bitops.h>
29 #include "k8x8xx.h"
30
31 static void dram_enable(struct device *dev)
32 {
33         msr_t msr;
34         u16 reg;
35
36         /*
37          * Enable Lowest Interrupt arbitration for APIC, enable NB APIC
38          * decoding, MSI support, no SMRAM, compatible SMM.
39          */
40         pci_write_config8(dev, 0x86, 0x19);
41
42         /*
43          * We want to use the 0xC0000-0xEFFFF as RAM mark area as RW, even if
44          * memory is doing K8 the DMA from SB will fail if we have it wrong,
45          * AND even we have it here, we must later copy it to SB to make it work :/
46          */
47
48         /* For CC000-CFFFF, bits 7:6 (10 = REn, 01 = WEn) bits 1:0 for
49          * C0000-C3FFF etc.
50          */
51         pci_write_config8(dev, 0x80, 0xff);
52         /* For page D0000-DFFFF */
53         pci_write_config8(dev, 0x81, 0xff);
54         /* For page E0000-EFFFF */
55         pci_write_config8(dev, 0x82, 0xff);
56         pci_write_config8(dev, 0x83, 0x30);
57
58         msr = rdmsr(TOP_MEM);
59         reg = pci_read_config16(dev, 0x84);
60         reg &= 0xf;
61         pci_write_config16(dev, 0x84, (msr.lo >> 16) | reg);
62
63         reg = pci_read_config16(dev, 0x88);
64         reg &= 0xf800;
65
66         /* The Address Next to the Last Valid DRAM Address */
67         pci_write_config16(dev, 0x88, (msr.lo >> 24) | reg);
68         
69         print_debug(" VIA_X_3 device dump:\n");
70         dump_south(dev);
71
72 }
73
74 #if CONFIG_GFXUMA
75 extern uint64_t uma_memory_base, uma_memory_size;
76 #endif
77
78 static void dram_enable_k8m890(struct device *dev)
79 {
80 #if CONFIG_GFXUMA
81         msr_t msr;
82         int ret;
83         unsigned int fbbits;
84
85         /* use CMOS */
86         if (CONFIG_VIDEO_MB == -1) {
87                 ret = get_option(&fbbits, "videoram_size");
88                 if (ret) {
89                         printk(BIOS_WARNING, "Failed to get videoram size (error %d), using default.\n", ret);
90                         fbbits = 5;
91                 }
92
93                 if ((fbbits < 1) || (fbbits > 7)) {
94                         printk(BIOS_WARNING, "Invalid videoram size (%d), using default.\n",
95                                        4 << fbbits);
96                         fbbits = 5;
97         }
98                 uma_memory_size = 4 << (fbbits + 20);
99         } else {
100                 uma_memory_size = (CONFIG_VIDEO_MB << 20);
101         }
102
103         msr = rdmsr(TOP_MEM);
104         uma_memory_base = msr.lo - uma_memory_size;
105         printk(BIOS_INFO, "K8M890: UMA base is %llx size is %u (MB)\n", uma_memory_base,
106                                 (u32) (uma_memory_size / 1024 / 1024));
107         /* enable VGA, so the bridges gets VGA_EN and resources are set */
108         pci_write_config8(dev, 0xa1, 0x80);
109 #endif
110         dram_enable(dev);
111 }
112
113 int
114 k8m890_host_fb_size_get(void)
115 {
116         struct device *dev = dev_find_device(PCI_VENDOR_ID_VIA,
117                                              PCI_DEVICE_ID_VIA_K8M800_DRAM, 0);
118         if(!dev) dev = dev_find_device(PCI_VENDOR_ID_VIA,
119                                              PCI_DEVICE_ID_VIA_K8M890CE_3, 0);
120         unsigned char tmp;
121
122         tmp = pci_read_config8(dev, 0xA1);
123         tmp >>= 4;
124         if (tmp & 0x08)
125                 return 4 << (tmp & 7);
126         else
127                 return 0;
128 }
129
130 static void dram_init_fb(struct device *dev)
131 {
132 #if CONFIG_GFXUMA
133         /* Important bits:
134          * Enable the internal GFX bit 7 of reg 0xa1 plus in same reg:
135          * bits 6:4 X fbuffer size will be  2^(X+2) or 100 = 64MB, 101 = 128MB
136          * bits 3:0 BASE [31:28]
137          * reg 0xa0 bits 7:1 BASE [27:21] bit0 enable CPU access
138          */
139         unsigned int fbbits = 0;
140         u8 tmp;
141
142         fbbits = ((log2(uma_memory_size >> 20) - 2) << 4);
143         printk(BIOS_INFO, "K8M890: Using a %dMB framebuffer.\n", (unsigned int) (uma_memory_size >> 20));
144
145         /* Step 1: enable UMA but no FB */
146         pci_write_config8(dev, 0xa1, 0x80);
147
148         /* Step 2: enough is just the FB size, the CPU accessible address is not needed */
149         tmp = fbbits | 0x80;
150         pci_write_config8(dev, 0xa1, tmp);
151
152         /* TODO K8 needs some UMA fine tuning too maybe call some generic routine here? */
153 #endif
154 }
155
156 static const struct device_operations dram_ops_t = {
157         .read_resources         = pci_dev_read_resources,
158         .set_resources          = pci_dev_set_resources,
159         .enable_resources       = pci_dev_enable_resources,
160         .enable                 = dram_enable,
161         .ops_pci                = 0,
162 };
163
164 static const struct device_operations dram_ops_m = {
165         .read_resources         = pci_dev_read_resources,
166         .set_resources          = pci_dev_set_resources,
167         .enable_resources       = pci_dev_enable_resources,
168         .enable                 = dram_enable_k8m890,
169         .init                   = dram_init_fb,
170         .ops_pci                = 0,
171 };
172
173 static const struct pci_driver northbridge_driver_t800 __pci_driver = {
174         .ops    = &dram_ops_t,
175         .vendor = PCI_VENDOR_ID_VIA,
176         .device = PCI_DEVICE_ID_VIA_K8T800_DRAM,
177 };
178
179 static const struct pci_driver northbridge_driver_m800 __pci_driver = {
180         .ops    = &dram_ops_m,
181         .vendor = PCI_VENDOR_ID_VIA,
182         .device = PCI_DEVICE_ID_VIA_K8M800_DRAM,
183 };
184
185 static const struct pci_driver northbridge_driver_t890 __pci_driver = {
186         .ops    = &dram_ops_t,
187         .vendor = PCI_VENDOR_ID_VIA,
188         .device = PCI_DEVICE_ID_VIA_K8T890CE_3,
189 };
190
191 static const struct pci_driver northbridge_driver_t890cf __pci_driver = {
192         .ops    = &dram_ops_t,
193         .vendor = PCI_VENDOR_ID_VIA,
194         .device = PCI_DEVICE_ID_VIA_K8T890CF_3,
195 };
196
197 static const struct pci_driver northbridge_driver_m890 __pci_driver = {
198         .ops    = &dram_ops_m,
199         .vendor = PCI_VENDOR_ID_VIA,
200         .device = PCI_DEVICE_ID_VIA_K8M890CE_3,
201 };