summaryrefslogtreecommitdiffstats
path: root/src/northbridge/via/vt8623/northbridge.c
blob: 2d53f2335376991c757ca527f48e8e8b0aa98a02 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <mem.h>
#include <part/sizeram.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/hypertransport.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include <cpu/p6/mtrr.h>
#include "chip.h"
#include "northbridge.h"

static const uint8_t ramregs[] = {0x5a, 0x5b, 0x5c, 0x5d };

struct mem_range *sizeram(void)
{
	unsigned long mmio_basek;
	static struct mem_range mem[10];
	device_t dev;
	int i, idx;
	unsigned char rambits;

	dev = dev_find_slot(0, 0);
	if (!dev) {
		printk_err("Cannot find PCI: 0:0\n");
		return 0;
	}
	mem[0].basek = 0;
	mem[0].sizek = 0xa0000 >>10; // first 640k
	mem[1].basek = 0xc0000 >>10; // leave a hole for vga
	idx = 2;
	while(idx < sizeof(mem)/sizeof(mem[0])) {
		mem[idx].basek = 0;
		mem[idx].sizek = 0;
		idx++;
	}
	for(rambits = 0, i = 0; i < sizeof(ramregs)/sizeof(ramregs[0]); i++) {
		unsigned char reg;
		reg = pci_read_config8(dev, ramregs[i]);
		/* these are ENDING addresses, not sizes. 
		 * if there is memory in this slot, then reg will be > rambits.
		 * So we just take the max, that gives us total. 
		 * We take the highest one to cover for once and future linuxbios
		 * bugs. We warn about bugs.
		 */
		if (reg > rambits)
			rambits = reg;
		if (reg < rambits)
			printk_err("ERROR! register 0x%x is not set!\n", 
				ramregs[i]);
	}
	
	printk_debug("I would set ram size to 0x%x Kbytes\n", (rambits)*16*1024);
	mem[1].sizek = rambits*16*1024 - 32768 - (0xc0000 >> 10);
#if 1
	for(i = 0; i < idx; i++) {
		printk_debug("mem[%d].basek = %08x mem[%d].sizek = %08x\n",
			i, mem[i].basek, i, mem[i].sizek);
	}
#endif

	return mem;
}

/*
 * This fixup is based on capturing values from an Award bios.  Without
 * this fixup the DMA write performance is awful (i.e. hdparm -t /dev/hda is 20x
 * slower than normal, ethernet drops packets).
 * Apparently these registers govern some sort of bus master behavior.
 */
static void random_fixup() {
	device_t pcidev0 = dev_find_slot(0, 0);
	device_t pcidev1,pcidev2;
	unsigned long fb;
	unsigned char c;

	printk_debug("VT8623 random fixup ...\n");
	if (pcidev0) {
		pci_write_config8(pcidev0, 0x0d, 0x08);
		pci_write_config8(pcidev0, 0x70, 0x82);
		pci_write_config8(pcidev0, 0x71, 0xc8);
		pci_write_config8(pcidev0, 0x72, 0x0);
		pci_write_config8(pcidev0, 0x73, 0x01);
		pci_write_config8(pcidev0, 0x74, 0x01);
		pci_write_config8(pcidev0, 0x75, 0x08);
		pci_write_config8(pcidev0, 0x76, 0x52);
		pci_write_config8(pcidev0, 0x13, 0xd0);
		pci_write_config8(pcidev0, 0x84, 0x80);
		pci_write_config16(pcidev0,0x80, 0x610f);
		pci_write_config32(pcidev0,0x88, 0x02);
	}
	printk_debug("VT8623 AGP random fixup ...\n");
	pcidev1 = dev_find_device(PCI_VENDOR_ID_VIA,0xb091,0);
	if( pcidev1) {
		pci_write_config8(pcidev1,0x3e,0x0c);
		pci_write_config8(pcidev1,0x40,0x83);
		pci_write_config8(pcidev1,0x41,0xc5);
		pci_write_config8(pcidev1,0x43,0x44);
		pci_write_config8(pcidev1,0x44,0x34);
		pci_write_config8(pcidev1,0x83,0x02);
	}
	printk_debug("VGA random fixup ...\n");
	pcidev2 = dev_find_device(PCI_VENDOR_ID_VIA,0x3122,0);
	if( pcidev2 ){
		pci_write_config8(pcidev2,0x04,0x07);
		pci_write_config8(pcidev2,0x0d,0x20);
	}
	// fixup GART and framebuffer addresses properly
	// first set up frame buffer properly
	fb = pci_read_config32(pcidev2,0x10);  // base address of framebuffer
	printk_debug("Frame buffer at %8x\n",fb);
	c = pci_read_config8(pcidev0,0xe1) & 0xf0;    // size of vga
	c |= fb>>28;  // upper nibble of frame buffer address
	pci_write_config8(pcidev0,0xe1,c);
	c = (fb>>20) | 1; // enable framebuffer
	pci_write_config8(pcidev0,0xe0,c);
	pci_write_config8(pcidev0,0xe2,0x42); // 'cos award does

	
}
static void set_vga_mtrrs(void)
{
	device_t pcidev = dev_find_device(PCI_VENDOR_ID_VIA,0x3122,0);
	unsigned long fb;

	add_var_mtrr( 0xd0000000 >> 10, 0x08000000>>10, MTRR_TYPE_WRCOMB);
	fb = pci_read_config32(pcidev,0x10); // get the fb address
	add_var_mtrr( fb>>10, 8192, MTRR_TYPE_WRCOMB);
	

}

static void northbridge_init(struct chip *chip, enum chip_pass pass)
{

	struct northbridge_via_vt8623_config *conf = 
		(struct northbridge_via_vt8623_config *)chip->chip_info;

	switch (pass) {
	case CONF_PASS_PRE_PCI:
		break;
		
	case CONF_PASS_POST_PCI:
		random_fixup();
		break;
		
	case CONF_PASS_PRE_BOOT:
		set_vga_mtrrs();
		break;
		
	default:
		/* nothing yet */
		break;
	}
}

struct chip_operations northbridge_via_vt8623_control = {
	.enable    = northbridge_init,
	.name      = "VIA vt8623 Northbridge",
};
OpenPOWER on IntegriCloud