summaryrefslogtreecommitdiff
path: root/src/northbridge/via/vx900/traf_ctrl.c
blob: 8f3f6023adde6c0afe01678619ce5b872a7e0a38 (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
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2012  Alexandru Gagniuc <mr.nuke.me@gmail.com>
 *
 * 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, either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.h>
#include <device/pci_ops.h>
#include <device/pci_ids.h>
#include <console/console.h>
#include <drivers/generic/ioapic/chip.h>

#include "vx900.h"
#include "chip.h"

/**
 * @file vx900/traf_ctrl.c
 *
 * STATUS:
 * The same issues with the IOAPIC pointe in lpc.c also apply here.
 *
 * We need to check if the current PCIE lane configuration mechanism is sane.
 */

/**
 * \brief VX900: Set up the north module IOAPIC (for PCIE and VGA)
 *
 * Enable the IOAPIC in the south module, and properly set it up.
 * \n
 * This is the hardware specific initialization for the IOAPIC, and complements
 * the setup done by the generic IOAPIC driver. In order for the IOAPIC to work
 * properly, it _must_ be declared in devicetree.cb .
 * \n
 * We are assuming this is called before the drivers/generic/ioapic code,
 * which should be the case if devicetree.cb is set up properly.
 */
static void vx900_north_ioapic_setup(struct device *dev)
{
	u8 base_val;
	struct device *ioapic;
	ioapic_config_t *config;
	/* Find the IOAPIC, and make sure it's set up correctly in devicetree.cb
	 * If it's not, then the generic ioapic driver will not set it up
	 * correctly, and the MP table will not be correctly generated */
	for (ioapic = dev->next; ioapic; ioapic = ioapic->next) {
		if (ioapic->path.type == DEVICE_PATH_IOAPIC)
			break;
	}
	/* You did put an IOAPIC in devicetree.cb, didn't you? */
	if (ioapic == 0) {
		/* We don't have enough info to set up the IOAPIC */
		printk(BIOS_ERR, "ERROR: North module IOAPIC not found. "
		       "Check your devicetree.cb\n");
		return;
	}
	/* Found our IOAPIC, and it should not carry ISA interrupts */
	config = (ioapic_config_t *) ioapic->chip_info;
	if (config->have_isa_interrupts) {
		/* Umh, is this the right IOAPIC ? */
		printk(BIOS_ERR, "ERROR: North module IOAPIC should not carry "
		       "ISA interrupts.\n" "Check your devicetree.cb\n");
		printk(BIOS_ERR, "Will not initialize this IOAPIC.\n");
		return;
	}
	/* The base address of this IOAPIC _must_
	 *     be between 0xfec00000 and 0xfecfff00
	 *     be 256-byte aligned
	 */
	if ((config->base < (void *)0xfec0000 || config->base > (void *)0xfecfff00)
	    || (((uintptr_t)config->base & 0xff) != 0)) {
		printk(BIOS_ERR, "ERROR: North module IOAPIC base should be "
		       "between 0xfec00000 and 0xfecfff00\n"
		       "and must be aligned to a 256-byte boundary, "
		       "but we found it at 0x%p\n", config->base);
		return;
	}

	printk(BIOS_DEBUG, "VX900 TRAF_CTR: Setting up the north module IOAPIC "
	       "at %p\n", config->base);

	/* First register of the IOAPIC base */
	base_val = (((uintptr_t)config->base) >> 8) & 0xff;
	pci_write_config8(dev, 0x41, base_val);
	/* Second register of the base.
	 * Bit[7] also enables the IOAPIC and bit[5] enables MSI cycles */
	base_val = (((uintptr_t)config->base) >> 16) & 0xf;
	pci_or_config8(dev, 0x40, base_val | (1 << 7) | (1 << 5));
}

/*
 * Configures the PCI-express ports
 *
 * FIXME: triple-quadruple-check this
 */
static void vx900_pex_link_setup(struct device *dev)
{
	u8 reg8;
	struct northbridge_via_vx900_config *nb = (void *)dev->chip_info;

	reg8 = pci_read_config8(dev, 0xb0);
	reg8 &= ~((1 << 7) | (1 << 3));

	if (nb->assign_pex_to_dp)
		reg8 |= (1 << 7);

	if (!nb->pcie_port1_2_lane_wide)
		reg8 |= (1 << 3);

	pci_write_config8(dev, 0xb0, reg8);
}

static void vx900_traf_ctr_init(struct device *dev)
{
	vx900_north_ioapic_setup(dev);
	vx900_pex_link_setup(dev);
}

static struct device_operations traf_ctrl_ops = {
	.read_resources = pci_dev_read_resources,
	.set_resources = pci_dev_set_resources,
	.enable_resources = pci_dev_enable_resources,
	.init = vx900_traf_ctr_init,
	/* Need this here, or the IOAPIC driver won't be called.
	 * FIXME: Technically not a LPC bus. */
	.scan_bus = scan_lpc_bus,
};

static const struct pci_driver traf_ctrl_driver __pci_driver = {
	.ops = &traf_ctrl_ops,
	.vendor = PCI_VENDOR_ID_VIA,
	.device = PCI_DEVICE_ID_VIA_VX900_TRAF,
};