xref: /openbmc/u-boot/arch/x86/cpu/ivybridge/bd82x6x.c (revision 3e389d8ba666c5c2ad42021c2087630c1e412954)
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>
1225d5352cSSimon Glass #include <syscon.h>
1325d5352cSSimon Glass #include <asm/cpu.h>
14a5ea3a7dSSimon Glass #include <asm/io.h>
154e7a6acaSSimon Glass #include <asm/lapic.h>
164e7a6acaSSimon Glass #include <asm/pci.h>
174e7a6acaSSimon Glass #include <asm/arch/bd82x6x.h>
184e7a6acaSSimon Glass #include <asm/arch/model_206ax.h>
194e7a6acaSSimon Glass #include <asm/arch/pch.h>
204e7a6acaSSimon Glass #include <asm/arch/sandybridge.h>
214e7a6acaSSimon Glass 
22f2b85ab5SSimon Glass #define BIOS_CTRL	0xdc
23f2b85ab5SSimon Glass 
24a5ea3a7dSSimon Glass static int pch_revision_id = -1;
25a5ea3a7dSSimon Glass static int pch_type = -1;
26a5ea3a7dSSimon Glass 
27a5ea3a7dSSimon Glass /**
28a5ea3a7dSSimon Glass  * pch_silicon_revision() - Read silicon revision ID from the PCH
29a5ea3a7dSSimon Glass  *
30a5ea3a7dSSimon Glass  * @dev:	PCH device
31a5ea3a7dSSimon Glass  * @return silicon revision ID
32a5ea3a7dSSimon Glass  */
33a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev)
34a5ea3a7dSSimon Glass {
35a5ea3a7dSSimon Glass 	u8 val;
36a5ea3a7dSSimon Glass 
37a5ea3a7dSSimon Glass 	if (pch_revision_id < 0) {
38a5ea3a7dSSimon Glass 		dm_pci_read_config8(dev, PCI_REVISION_ID, &val);
39a5ea3a7dSSimon Glass 		pch_revision_id = val;
40a5ea3a7dSSimon Glass 	}
41a5ea3a7dSSimon Glass 
42a5ea3a7dSSimon Glass 	return pch_revision_id;
43a5ea3a7dSSimon Glass }
44a5ea3a7dSSimon Glass 
45a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev)
46a5ea3a7dSSimon Glass {
47a5ea3a7dSSimon Glass 	u8 val;
48a5ea3a7dSSimon Glass 
49a5ea3a7dSSimon Glass 	if (pch_type < 0) {
50a5ea3a7dSSimon Glass 		dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val);
51a5ea3a7dSSimon Glass 		pch_type = val;
52a5ea3a7dSSimon Glass 	}
53a5ea3a7dSSimon Glass 
54a5ea3a7dSSimon Glass 	return pch_type;
55a5ea3a7dSSimon Glass }
56a5ea3a7dSSimon Glass 
57a5ea3a7dSSimon Glass /**
58a5ea3a7dSSimon Glass  * pch_silicon_supported() - Check if a certain revision is supported
59a5ea3a7dSSimon Glass  *
60a5ea3a7dSSimon Glass  * @dev:	PCH device
61a5ea3a7dSSimon Glass  * @type:	PCH type
62a5ea3a7dSSimon Glass  * @rev:	Minimum required resion
63a5ea3a7dSSimon Glass  * @return 0 if not supported, 1 if supported
64a5ea3a7dSSimon Glass  */
65a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev)
66a5ea3a7dSSimon Glass {
67a5ea3a7dSSimon Glass 	int cur_type = pch_silicon_type(dev);
68a5ea3a7dSSimon Glass 	int cur_rev = pch_silicon_revision(dev);
69a5ea3a7dSSimon Glass 
70a5ea3a7dSSimon Glass 	switch (type) {
71a5ea3a7dSSimon Glass 	case PCH_TYPE_CPT:
72a5ea3a7dSSimon Glass 		/* CougarPoint minimum revision */
73a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
74a5ea3a7dSSimon Glass 			return 1;
75a5ea3a7dSSimon Glass 		/* PantherPoint any revision */
76a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_PPT)
77a5ea3a7dSSimon Glass 			return 1;
78a5ea3a7dSSimon Glass 		break;
79a5ea3a7dSSimon Glass 
80a5ea3a7dSSimon Glass 	case PCH_TYPE_PPT:
81a5ea3a7dSSimon Glass 		/* PantherPoint minimum revision */
82a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
83a5ea3a7dSSimon Glass 			return 1;
84a5ea3a7dSSimon Glass 		break;
85a5ea3a7dSSimon Glass 	}
86a5ea3a7dSSimon Glass 
87a5ea3a7dSSimon Glass 	return 0;
88a5ea3a7dSSimon Glass }
89a5ea3a7dSSimon Glass 
90a5ea3a7dSSimon Glass #define IOBP_RETRY 1000
91a5ea3a7dSSimon Glass static inline int iobp_poll(void)
92a5ea3a7dSSimon Glass {
93a5ea3a7dSSimon Glass 	unsigned try = IOBP_RETRY;
94a5ea3a7dSSimon Glass 	u32 data;
95a5ea3a7dSSimon Glass 
96a5ea3a7dSSimon Glass 	while (try--) {
97a5ea3a7dSSimon Glass 		data = readl(RCB_REG(IOBPS));
98a5ea3a7dSSimon Glass 		if ((data & 1) == 0)
99a5ea3a7dSSimon Glass 			return 1;
100a5ea3a7dSSimon Glass 		udelay(10);
101a5ea3a7dSSimon Glass 	}
102a5ea3a7dSSimon Glass 
103a5ea3a7dSSimon Glass 	printf("IOBP timeout\n");
104a5ea3a7dSSimon Glass 	return 0;
105a5ea3a7dSSimon Glass }
106a5ea3a7dSSimon Glass 
107a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue,
108a5ea3a7dSSimon Glass 		     u32 orvalue)
109a5ea3a7dSSimon Glass {
110a5ea3a7dSSimon Glass 	u32 data;
111a5ea3a7dSSimon Glass 
112a5ea3a7dSSimon Glass 	/* Set the address */
113a5ea3a7dSSimon Glass 	writel(address, RCB_REG(IOBPIRI));
114a5ea3a7dSSimon Glass 
115a5ea3a7dSSimon Glass 	/* READ OPCODE */
116a5ea3a7dSSimon Glass 	if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
117a5ea3a7dSSimon Glass 		writel(IOBPS_RW_BX, RCB_REG(IOBPS));
118a5ea3a7dSSimon Glass 	else
119a5ea3a7dSSimon Glass 		writel(IOBPS_READ_AX, RCB_REG(IOBPS));
120a5ea3a7dSSimon Glass 	if (!iobp_poll())
121a5ea3a7dSSimon Glass 		return;
122a5ea3a7dSSimon Glass 
123a5ea3a7dSSimon Glass 	/* Read IOBP data */
124a5ea3a7dSSimon Glass 	data = readl(RCB_REG(IOBPD));
125a5ea3a7dSSimon Glass 	if (!iobp_poll())
126a5ea3a7dSSimon Glass 		return;
127a5ea3a7dSSimon Glass 
128a5ea3a7dSSimon Glass 	/* Check for successful transaction */
129a5ea3a7dSSimon Glass 	if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) {
130a5ea3a7dSSimon Glass 		printf("IOBP read 0x%08x failed\n", address);
131a5ea3a7dSSimon Glass 		return;
132a5ea3a7dSSimon Glass 	}
133a5ea3a7dSSimon Glass 
134a5ea3a7dSSimon Glass 	/* Update the data */
135a5ea3a7dSSimon Glass 	data &= andvalue;
136a5ea3a7dSSimon Glass 	data |= orvalue;
137a5ea3a7dSSimon Glass 
138a5ea3a7dSSimon Glass 	/* WRITE OPCODE */
139a5ea3a7dSSimon Glass 	if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
140a5ea3a7dSSimon Glass 		writel(IOBPS_RW_BX, RCB_REG(IOBPS));
141a5ea3a7dSSimon Glass 	else
142a5ea3a7dSSimon Glass 		writel(IOBPS_WRITE_AX, RCB_REG(IOBPS));
143a5ea3a7dSSimon Glass 	if (!iobp_poll())
144a5ea3a7dSSimon Glass 		return;
145a5ea3a7dSSimon Glass 
146a5ea3a7dSSimon Glass 	/* Write IOBP data */
147a5ea3a7dSSimon Glass 	writel(data, RCB_REG(IOBPD));
148a5ea3a7dSSimon Glass 	if (!iobp_poll())
149a5ea3a7dSSimon Glass 		return;
150a5ea3a7dSSimon Glass }
151a5ea3a7dSSimon Glass 
152aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev)
1534e7a6acaSSimon Glass {
15425d5352cSSimon Glass 	struct udevice *gma_dev;
155effcf067SSimon Glass 	int ret;
15672cd085aSSimon Glass 
1574acc83d4SSimon Glass 	if (!(gd->flags & GD_FLG_RELOC))
1584acc83d4SSimon Glass 		return 0;
1594acc83d4SSimon Glass 
16001a67908SSimon Glass 	/* Cause the SATA device to do its init */
16101a67908SSimon Glass 	uclass_first_device(UCLASS_DISK, &dev);
16201a67908SSimon Glass 
16325d5352cSSimon Glass 	ret = syscon_get_by_driver_data(X86_SYSCON_GMA, &gma_dev);
1649bf727fcSSimon Glass 	if (ret)
1659bf727fcSSimon Glass 		return ret;
16625d5352cSSimon Glass 	ret = gma_func0_init(gma_dev);
167effcf067SSimon Glass 	if (ret)
168effcf067SSimon Glass 		return ret;
169effcf067SSimon Glass 
1704e7a6acaSSimon Glass 	return 0;
1714e7a6acaSSimon Glass }
1724e7a6acaSSimon Glass 
173*3e389d8bSBin Meng static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep)
174f2b85ab5SSimon Glass {
175f2b85ab5SSimon Glass 	u32 rcba;
176f2b85ab5SSimon Glass 
177f2b85ab5SSimon Glass 	dm_pci_read_config32(dev, PCH_RCBA, &rcba);
178f2b85ab5SSimon Glass 	/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */
179f2b85ab5SSimon Glass 	rcba = rcba & 0xffffc000;
180f2b85ab5SSimon Glass 	*sbasep = rcba + 0x3800;
181f2b85ab5SSimon Glass 
182f2b85ab5SSimon Glass 	return 0;
183f2b85ab5SSimon Glass }
184f2b85ab5SSimon Glass 
185f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
186f2b85ab5SSimon Glass {
187f2b85ab5SSimon Glass 	uint8_t bios_cntl;
188f2b85ab5SSimon Glass 
189f2b85ab5SSimon Glass 	/* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
190f2b85ab5SSimon Glass 	dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl);
191f2b85ab5SSimon Glass 	if (protect) {
192f2b85ab5SSimon Glass 		bios_cntl &= ~BIOS_CTRL_BIOSWE;
193f2b85ab5SSimon Glass 		bios_cntl |= BIT(5);
194f2b85ab5SSimon Glass 	} else {
195f2b85ab5SSimon Glass 		bios_cntl |= BIOS_CTRL_BIOSWE;
196f2b85ab5SSimon Glass 		bios_cntl &= ~BIT(5);
197f2b85ab5SSimon Glass 	}
198f2b85ab5SSimon Glass 	dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl);
199f2b85ab5SSimon Glass 
200f2b85ab5SSimon Glass 	return 0;
201f2b85ab5SSimon Glass }
202f2b85ab5SSimon Glass 
203f2b85ab5SSimon Glass static const struct pch_ops bd82x6x_pch_ops = {
204*3e389d8bSBin Meng 	.get_spi_base	= bd82x6x_pch_get_spi_base,
205f2b85ab5SSimon Glass 	.set_spi_protect = bd82x6x_set_spi_protect,
206f2b85ab5SSimon Glass };
207f2b85ab5SSimon Glass 
208aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = {
209aad78d27SSimon Glass 	{ .compatible = "intel,bd82x6x" },
210aad78d27SSimon Glass 	{ }
211aad78d27SSimon Glass };
212aad78d27SSimon Glass 
213aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = {
214aad78d27SSimon Glass 	.name		= "bd82x6x",
215aad78d27SSimon Glass 	.id		= UCLASS_PCH,
216aad78d27SSimon Glass 	.of_match	= bd82x6x_ids,
217aad78d27SSimon Glass 	.probe		= bd82x6x_probe,
218f2b85ab5SSimon Glass 	.ops		= &bd82x6x_pch_ops,
219aad78d27SSimon Glass };
220