xref: /openbmc/u-boot/arch/x86/cpu/ivybridge/bd82x6x.c (revision a5ea3a7d4a29f4251c032385f89ef7776f081be8)
14e7a6acaSSimon Glass /*
24e7a6acaSSimon Glass  * Copyright (C) 2014 Google, Inc
34e7a6acaSSimon Glass  *
44e7a6acaSSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
54e7a6acaSSimon Glass  */
64e7a6acaSSimon Glass #include <common.h>
7aad78d27SSimon Glass #include <dm.h>
84e7a6acaSSimon Glass #include <errno.h>
94e7a6acaSSimon Glass #include <fdtdec.h>
104e7a6acaSSimon Glass #include <malloc.h>
11f2b85ab5SSimon Glass #include <pch.h>
12*a5ea3a7dSSimon Glass #include <asm/io.h>
134e7a6acaSSimon Glass #include <asm/lapic.h>
144e7a6acaSSimon Glass #include <asm/pci.h>
154e7a6acaSSimon Glass #include <asm/arch/bd82x6x.h>
164e7a6acaSSimon Glass #include <asm/arch/model_206ax.h>
174e7a6acaSSimon Glass #include <asm/arch/pch.h>
184e7a6acaSSimon Glass #include <asm/arch/sandybridge.h>
194e7a6acaSSimon Glass 
20f2b85ab5SSimon Glass #define BIOS_CTRL	0xdc
21f2b85ab5SSimon Glass 
22*a5ea3a7dSSimon Glass static int pch_revision_id = -1;
23*a5ea3a7dSSimon Glass static int pch_type = -1;
24*a5ea3a7dSSimon Glass 
25*a5ea3a7dSSimon Glass /**
26*a5ea3a7dSSimon Glass  * pch_silicon_revision() - Read silicon revision ID from the PCH
27*a5ea3a7dSSimon Glass  *
28*a5ea3a7dSSimon Glass  * @dev:	PCH device
29*a5ea3a7dSSimon Glass  * @return silicon revision ID
30*a5ea3a7dSSimon Glass  */
31*a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev)
32*a5ea3a7dSSimon Glass {
33*a5ea3a7dSSimon Glass 	u8 val;
34*a5ea3a7dSSimon Glass 
35*a5ea3a7dSSimon Glass 	if (pch_revision_id < 0) {
36*a5ea3a7dSSimon Glass 		dm_pci_read_config8(dev, PCI_REVISION_ID, &val);
37*a5ea3a7dSSimon Glass 		pch_revision_id = val;
38*a5ea3a7dSSimon Glass 	}
39*a5ea3a7dSSimon Glass 
40*a5ea3a7dSSimon Glass 	return pch_revision_id;
41*a5ea3a7dSSimon Glass }
42*a5ea3a7dSSimon Glass 
43*a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev)
44*a5ea3a7dSSimon Glass {
45*a5ea3a7dSSimon Glass 	u8 val;
46*a5ea3a7dSSimon Glass 
47*a5ea3a7dSSimon Glass 	if (pch_type < 0) {
48*a5ea3a7dSSimon Glass 		dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val);
49*a5ea3a7dSSimon Glass 		pch_type = val;
50*a5ea3a7dSSimon Glass 	}
51*a5ea3a7dSSimon Glass 
52*a5ea3a7dSSimon Glass 	return pch_type;
53*a5ea3a7dSSimon Glass }
54*a5ea3a7dSSimon Glass 
55*a5ea3a7dSSimon Glass /**
56*a5ea3a7dSSimon Glass  * pch_silicon_supported() - Check if a certain revision is supported
57*a5ea3a7dSSimon Glass  *
58*a5ea3a7dSSimon Glass  * @dev:	PCH device
59*a5ea3a7dSSimon Glass  * @type:	PCH type
60*a5ea3a7dSSimon Glass  * @rev:	Minimum required resion
61*a5ea3a7dSSimon Glass  * @return 0 if not supported, 1 if supported
62*a5ea3a7dSSimon Glass  */
63*a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev)
64*a5ea3a7dSSimon Glass {
65*a5ea3a7dSSimon Glass 	int cur_type = pch_silicon_type(dev);
66*a5ea3a7dSSimon Glass 	int cur_rev = pch_silicon_revision(dev);
67*a5ea3a7dSSimon Glass 
68*a5ea3a7dSSimon Glass 	switch (type) {
69*a5ea3a7dSSimon Glass 	case PCH_TYPE_CPT:
70*a5ea3a7dSSimon Glass 		/* CougarPoint minimum revision */
71*a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
72*a5ea3a7dSSimon Glass 			return 1;
73*a5ea3a7dSSimon Glass 		/* PantherPoint any revision */
74*a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_PPT)
75*a5ea3a7dSSimon Glass 			return 1;
76*a5ea3a7dSSimon Glass 		break;
77*a5ea3a7dSSimon Glass 
78*a5ea3a7dSSimon Glass 	case PCH_TYPE_PPT:
79*a5ea3a7dSSimon Glass 		/* PantherPoint minimum revision */
80*a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
81*a5ea3a7dSSimon Glass 			return 1;
82*a5ea3a7dSSimon Glass 		break;
83*a5ea3a7dSSimon Glass 	}
84*a5ea3a7dSSimon Glass 
85*a5ea3a7dSSimon Glass 	return 0;
86*a5ea3a7dSSimon Glass }
87*a5ea3a7dSSimon Glass 
88*a5ea3a7dSSimon Glass #define IOBP_RETRY 1000
89*a5ea3a7dSSimon Glass static inline int iobp_poll(void)
90*a5ea3a7dSSimon Glass {
91*a5ea3a7dSSimon Glass 	unsigned try = IOBP_RETRY;
92*a5ea3a7dSSimon Glass 	u32 data;
93*a5ea3a7dSSimon Glass 
94*a5ea3a7dSSimon Glass 	while (try--) {
95*a5ea3a7dSSimon Glass 		data = readl(RCB_REG(IOBPS));
96*a5ea3a7dSSimon Glass 		if ((data & 1) == 0)
97*a5ea3a7dSSimon Glass 			return 1;
98*a5ea3a7dSSimon Glass 		udelay(10);
99*a5ea3a7dSSimon Glass 	}
100*a5ea3a7dSSimon Glass 
101*a5ea3a7dSSimon Glass 	printf("IOBP timeout\n");
102*a5ea3a7dSSimon Glass 	return 0;
103*a5ea3a7dSSimon Glass }
104*a5ea3a7dSSimon Glass 
105*a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue,
106*a5ea3a7dSSimon Glass 		     u32 orvalue)
107*a5ea3a7dSSimon Glass {
108*a5ea3a7dSSimon Glass 	u32 data;
109*a5ea3a7dSSimon Glass 
110*a5ea3a7dSSimon Glass 	/* Set the address */
111*a5ea3a7dSSimon Glass 	writel(address, RCB_REG(IOBPIRI));
112*a5ea3a7dSSimon Glass 
113*a5ea3a7dSSimon Glass 	/* READ OPCODE */
114*a5ea3a7dSSimon Glass 	if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
115*a5ea3a7dSSimon Glass 		writel(IOBPS_RW_BX, RCB_REG(IOBPS));
116*a5ea3a7dSSimon Glass 	else
117*a5ea3a7dSSimon Glass 		writel(IOBPS_READ_AX, RCB_REG(IOBPS));
118*a5ea3a7dSSimon Glass 	if (!iobp_poll())
119*a5ea3a7dSSimon Glass 		return;
120*a5ea3a7dSSimon Glass 
121*a5ea3a7dSSimon Glass 	/* Read IOBP data */
122*a5ea3a7dSSimon Glass 	data = readl(RCB_REG(IOBPD));
123*a5ea3a7dSSimon Glass 	if (!iobp_poll())
124*a5ea3a7dSSimon Glass 		return;
125*a5ea3a7dSSimon Glass 
126*a5ea3a7dSSimon Glass 	/* Check for successful transaction */
127*a5ea3a7dSSimon Glass 	if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) {
128*a5ea3a7dSSimon Glass 		printf("IOBP read 0x%08x failed\n", address);
129*a5ea3a7dSSimon Glass 		return;
130*a5ea3a7dSSimon Glass 	}
131*a5ea3a7dSSimon Glass 
132*a5ea3a7dSSimon Glass 	/* Update the data */
133*a5ea3a7dSSimon Glass 	data &= andvalue;
134*a5ea3a7dSSimon Glass 	data |= orvalue;
135*a5ea3a7dSSimon Glass 
136*a5ea3a7dSSimon Glass 	/* WRITE OPCODE */
137*a5ea3a7dSSimon Glass 	if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
138*a5ea3a7dSSimon Glass 		writel(IOBPS_RW_BX, RCB_REG(IOBPS));
139*a5ea3a7dSSimon Glass 	else
140*a5ea3a7dSSimon Glass 		writel(IOBPS_WRITE_AX, RCB_REG(IOBPS));
141*a5ea3a7dSSimon Glass 	if (!iobp_poll())
142*a5ea3a7dSSimon Glass 		return;
143*a5ea3a7dSSimon Glass 
144*a5ea3a7dSSimon Glass 	/* Write IOBP data */
145*a5ea3a7dSSimon Glass 	writel(data, RCB_REG(IOBPD));
146*a5ea3a7dSSimon Glass 	if (!iobp_poll())
147*a5ea3a7dSSimon Glass 		return;
148*a5ea3a7dSSimon Glass }
149*a5ea3a7dSSimon Glass 
150aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev)
1514e7a6acaSSimon Glass {
1523ac83935SSimon Glass 	const void *blob = gd->fdt_blob;
15301a67908SSimon Glass 	int gma_node;
154effcf067SSimon Glass 	int ret;
15572cd085aSSimon Glass 
1564acc83d4SSimon Glass 	if (!(gd->flags & GD_FLG_RELOC))
1574acc83d4SSimon Glass 		return 0;
1584acc83d4SSimon Glass 
15901a67908SSimon Glass 	/* Cause the SATA device to do its init */
16001a67908SSimon Glass 	uclass_first_device(UCLASS_DISK, &dev);
16101a67908SSimon Glass 
1629baeca4bSSimon Glass 	bd82x6x_usb_ehci_init(PCH_EHCI1_DEV);
1639baeca4bSSimon Glass 	bd82x6x_usb_ehci_init(PCH_EHCI2_DEV);
16472cd085aSSimon Glass 
165effcf067SSimon Glass 	gma_node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_GMA);
166effcf067SSimon Glass 	if (gma_node < 0) {
167effcf067SSimon Glass 		debug("%s: Cannot find GMA node\n", __func__);
168effcf067SSimon Glass 		return -EINVAL;
169effcf067SSimon Glass 	}
1709bf727fcSSimon Glass 	ret = dm_pci_bus_find_bdf(PCH_VIDEO_DEV, &dev);
1719bf727fcSSimon Glass 	if (ret)
1729bf727fcSSimon Glass 		return ret;
1739bf727fcSSimon Glass 	ret = gma_func0_init(dev, blob, gma_node);
174effcf067SSimon Glass 	if (ret)
175effcf067SSimon Glass 		return ret;
176effcf067SSimon Glass 
1774e7a6acaSSimon Glass 	return 0;
1784e7a6acaSSimon Glass }
1794e7a6acaSSimon Glass 
180f2b85ab5SSimon Glass static int bd82x6x_pch_get_sbase(struct udevice *dev, ulong *sbasep)
181f2b85ab5SSimon Glass {
182f2b85ab5SSimon Glass 	u32 rcba;
183f2b85ab5SSimon Glass 
184f2b85ab5SSimon Glass 	dm_pci_read_config32(dev, PCH_RCBA, &rcba);
185f2b85ab5SSimon Glass 	/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */
186f2b85ab5SSimon Glass 	rcba = rcba & 0xffffc000;
187f2b85ab5SSimon Glass 	*sbasep = rcba + 0x3800;
188f2b85ab5SSimon Glass 
189f2b85ab5SSimon Glass 	return 0;
190f2b85ab5SSimon Glass }
191f2b85ab5SSimon Glass 
192f2b85ab5SSimon Glass static enum pch_version bd82x6x_pch_get_version(struct udevice *dev)
193f2b85ab5SSimon Glass {
194f2b85ab5SSimon Glass 	return PCHV_9;
195f2b85ab5SSimon Glass }
196f2b85ab5SSimon Glass 
197f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
198f2b85ab5SSimon Glass {
199f2b85ab5SSimon Glass 	uint8_t bios_cntl;
200f2b85ab5SSimon Glass 
201f2b85ab5SSimon Glass 	/* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
202f2b85ab5SSimon Glass 	dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl);
203f2b85ab5SSimon Glass 	if (protect) {
204f2b85ab5SSimon Glass 		bios_cntl &= ~BIOS_CTRL_BIOSWE;
205f2b85ab5SSimon Glass 		bios_cntl |= BIT(5);
206f2b85ab5SSimon Glass 	} else {
207f2b85ab5SSimon Glass 		bios_cntl |= BIOS_CTRL_BIOSWE;
208f2b85ab5SSimon Glass 		bios_cntl &= ~BIT(5);
209f2b85ab5SSimon Glass 	}
210f2b85ab5SSimon Glass 	dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl);
211f2b85ab5SSimon Glass 
212f2b85ab5SSimon Glass 	return 0;
213f2b85ab5SSimon Glass }
214f2b85ab5SSimon Glass 
215f2b85ab5SSimon Glass static const struct pch_ops bd82x6x_pch_ops = {
216f2b85ab5SSimon Glass 	.get_sbase	= bd82x6x_pch_get_sbase,
217f2b85ab5SSimon Glass 	.get_version	= bd82x6x_pch_get_version,
218f2b85ab5SSimon Glass 	.set_spi_protect = bd82x6x_set_spi_protect,
219f2b85ab5SSimon Glass };
220f2b85ab5SSimon Glass 
221aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = {
222aad78d27SSimon Glass 	{ .compatible = "intel,bd82x6x" },
223aad78d27SSimon Glass 	{ }
224aad78d27SSimon Glass };
225aad78d27SSimon Glass 
226aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = {
227aad78d27SSimon Glass 	.name		= "bd82x6x",
228aad78d27SSimon Glass 	.id		= UCLASS_PCH,
229aad78d27SSimon Glass 	.of_match	= bd82x6x_ids,
230aad78d27SSimon Glass 	.probe		= bd82x6x_probe,
231f2b85ab5SSimon Glass 	.ops		= &bd82x6x_pch_ops,
232aad78d27SSimon Glass };
233