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
|
/* SPDX-License-Identifier: GPL-2.0-only */
#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");
}
|