summaryrefslogtreecommitdiffstats
path: root/src/southbridge/intel/bd82x6x/common.c
blob: 7163d3edc7bdf300cf671fa045df28c4ca0a63a5 (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
/* SPDX-License-Identifier: GPL-2.0-only */

#define __SIMPLE_DEVICE__

#include <console/console.h>
#include <delay.h>
#include <device/pci.h>
#include <device/pci_def.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#include <stdint.h>

#include "pch.h"

int pch_silicon_revision(void)
{
	static int pch_revision_id = -1;

	if (pch_revision_id < 0)
		pch_revision_id = pci_read_config8(PCH_LPC_DEV, PCI_REVISION_ID);

	return pch_revision_id;
}

int pch_silicon_type(void)
{
	static int pch_type = -1;

	if (pch_type < 0)
		pch_type = pci_read_config8(PCH_LPC_DEV, PCI_DEVICE_ID + 1);

	return pch_type;
}

bool pch_is_mobile(void)
{
	const u16 devids[] = {
		PCI_DID_INTEL_6_SERIES_MOBILE_SFF, PCI_DID_INTEL_6_SERIES_MOBILE,
		PCI_DID_INTEL_6_SERIES_UM67, PCI_DID_INTEL_6_SERIES_HM65,
		PCI_DID_INTEL_6_SERIES_HM67, PCI_DID_INTEL_6_SERIES_QS67,
		PCI_DID_INTEL_6_SERIES_QM67,
		PCI_DID_INTEL_7_SERIES_MOBILE, PCI_DID_INTEL_7_SERIES_MOBILE_SFF,
		PCI_DID_INTEL_7_SERIES_QM77, PCI_DID_INTEL_7_SERIES_QS77,
		PCI_DID_INTEL_7_SERIES_HM77, PCI_DID_INTEL_7_SERIES_UM77,
		PCI_DID_INTEL_7_SERIES_HM76, PCI_DID_INTEL_7_SERIES_HM75,
		PCI_DID_INTEL_7_SERIES_HM70, PCI_DID_INTEL_7_SERIES_NM70
	};
	u16 devid = pci_s_read_config16(PCH_LPC_DEV, PCI_DEVICE_ID);

	for (size_t i = 0; i < ARRAY_SIZE(devids); i++)
		if (devid == devids[i])
			return true;
	return false;
}

int pch_silicon_supported(int type, int rev)
{
	int cur_type = pch_silicon_type();
	int cur_rev = pch_silicon_revision();

	switch (type) {
	case PCH_TYPE_CPT:
		/* CougarPoint minimum revision */
		if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
			return 1;
		/* PantherPoint any revision */
		if (cur_type == PCH_TYPE_PPT)
			return 1;
		break;

	case PCH_TYPE_PPT:
		/* PantherPoint minimum revision */
		if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
			return 1;
		break;
	}

	return 0;
}

#define IOBP_RETRY 1000
static inline int iobp_poll(void)
{
	unsigned int try = IOBP_RETRY;
	u32 data;

	while (try--) {
		data = RCBA32(IOBPS);
		if ((data & 1) == 0)
			return 1;
		udelay(10);
	}

	printk(BIOS_ERR, "IOBP timeout\n");
	return 0;
}

void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
{
	u32 data;

	/* Set the address */
	RCBA32(IOBPIRI) = address;

	/* READ OPCODE */
	if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0))
		RCBA32(IOBPS) = IOBPS_RW_BX;
	else
		RCBA32(IOBPS) = IOBPS_READ_AX;
	if (!iobp_poll())
		return;

	/* Read IOBP data */
	data = RCBA32(IOBPD);
	if (!iobp_poll())
		return;

	/* Check for successful transaction */
	if ((RCBA32(IOBPS) & 0x6) != 0) {
		printk(BIOS_ERR, "IOBP read 0x%08x failed\n", address);
		return;
	}

	/* Update the data */
	data &= andvalue;
	data |= orvalue;

	/* WRITE OPCODE */
	if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0))
		RCBA32(IOBPS) = IOBPS_RW_BX;
	else
		RCBA32(IOBPS) = IOBPS_WRITE_AX;
	if (!iobp_poll())
		return;

	/* Write IOBP data */
	RCBA32(IOBPD) = data;
	if (!iobp_poll())
		return;
}