summaryrefslogtreecommitdiffstats
path: root/src/southbridge/intel/i82801ix/dmi_setup.c
blob: 663c6d363dc2ddd3a0353db6f112cbe2552218a1 (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
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2012 secunet Security Networks AG
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <device/pci_def.h>
#include <console/console.h>
#include <northbridge/intel/gm45/gm45.h>
#include "i82801ix.h"

/* VC1 Port Arbitration Table */
static const u8 vc1_pat[] = {
	0x0f, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x0f, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0xf0, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0xf0, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x0f, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x0f, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0xf0, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x0f,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0xf0, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
};
void i82801ix_dmi_setup(void)
{
	int i;
	u32 reg32;

	RCBA32(RCBA_V1CAP) = (RCBA32(RCBA_V1CAP) & ~(0x7f<<16)) | (0x12<<16);

	/* NB: other CIRs are handled in i82801ix_early_settings(). */
	RCBA32(RCBA_CIR1) = 0x00109000;
	RCBA16(RCBA_CIR3) = 0x060b;
	RCBA32(RCBA_CIR2) = 0x86000040;
	RCBA8(RCBA_BCR)   = 0x45;
	RCBA32(RCBA_CIR6) &= ~(1 << 7);


	/* VC1 setup for isochronous transfers: */

	/* Set VC1 virtual channel id to 1. */
	RCBA32(RCBA_V1CTL) = (RCBA32(RCBA_V1CTL) & ~(0x7 << 24)) | (0x1 << 24);
	/* Enable TC7 traffic on VC1. */
	RCBA32(RCBA_V1CTL) = (RCBA32(RCBA_V1CTL) & ~(0x7f << 1)) | (1 << 7);
	/* Disable TC7-TC1 traffic on VC0. */
	RCBA32(RCBA_V0CTL) &= ~(0x7f << 1);
	/* TC7-TC1 traffic on PCIe root ports will be disabled in pci driver. */

	/* Set table type to time-based WRR. */
	RCBA32(RCBA_V1CTL) = (RCBA32(RCBA_V1CTL) & ~(0x7 << 17)) | (0x4 << 17);
	/* Program port arbitration table. */
	for (i = 0; i < sizeof(vc1_pat); ++i)
		RCBA8(RCBA_PAT + i) = vc1_pat[i];
	/* Load port arbitration table. */
	RCBA32(RCBA_V1CTL) |= (1 << 16);

	/* Enable VC1. */
	RCBA32(RCBA_V1CTL) |= (1 << 31);


	/* Setup RCRB: */

	/* Set component id to 2 for southbridge, northbridge has id 1. */
	RCBA8(RCBA_ESD + 2) = 2;
	/* Set target port number and target component id of the northbridge. */
	RCBA8(RCBA_ULD + 3) = 1;
	RCBA8(RCBA_ULD + 2) = 1;
	/* Set target rcrb base address, i.e. DMIBAR. */
	RCBA32(RCBA_ULBA) = (uintptr_t)DEFAULT_DMIBAR;

	/* Enable ASPM. */
	if (LPC_IS_MOBILE(PCI_DEV(0, 0x1f, 0))) {
		reg32 = RCBA32(RCBA_DMC);
		/* Enable mobile specific power saving (set this first). */
		reg32 = (reg32 & ~(3 << 10)) | (1 << 10);
		RCBA32(RCBA_DMC) = reg32;
		/* Enable DMI power savings. */
		reg32 |= (1 << 19);
		RCBA32(RCBA_DMC) = reg32;
		/* Advertise L0s and L1. */
		RCBA32(RCBA_LCAP) |= (3 << 10);
		/* Enable L0s and L1. */
		RCBA32(RCBA_LCTL) |= (3 <<  0);
	} else {
		/* Enable DMI power savings. */
		RCBA32(RCBA_DMC) |= (1 << 19);
		/* Advertise L0s only. */
		RCBA32(RCBA_LCAP) = (RCBA32(RCBA_LCAP) & ~(3<<10)) | (1<<10);
		/* Enable L0s only. */
		RCBA32(RCBA_LCTL) = (RCBA32(RCBA_LCTL) & ~(3<< 0)) | (1<< 0);
	}
}

/* Should be called after VC1 has been enabled on both sides. */
void i82801ix_dmi_poll_vc1(void)
{
	int timeout;

	timeout = 0x7ffff;
	printk(BIOS_DEBUG, "ICH9 waits for VC1 negotiation... ");
	while ((RCBA32(RCBA_V1STS) & (1 << 1)) && --timeout) {}
	if (!timeout)
		printk(BIOS_DEBUG, "timeout!\n");
	else
		printk(BIOS_DEBUG, "done.\n");

	/* Check for x2 DMI link. */
	if (((RCBA16(RCBA_LSTS) >> 4) & 0x3f) == 2) {
		printk(BIOS_DEBUG, "x2 DMI link detected.\n");
		RCBA32(0x2024) = (RCBA32(0x2024) & ~(7 << 21)) | (3 << 21);
		RCBA16(0x20c4) |= (1 << 15);
		RCBA16(0x20e4) |= (1 << 15);
		/* TODO: Maybe we have to save and
		         restore these settings across S3. */
	}

	timeout = 0x7ffff;
	printk(BIOS_DEBUG, "ICH9 waits for port arbitration table update... ");
	while ((RCBA32(RCBA_V1STS) & (1 << 0)) && --timeout) {}
	if (!timeout)
		printk(BIOS_DEBUG, "timeout!\n");
	else
		printk(BIOS_DEBUG, "done.\n");
}