xref: /openbmc/u-boot/arch/x86/cpu/ivybridge/bd82x6x.c (revision 0c41e59a37fbd5b10d4837ae30c288a084997465)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
24e7a6acaSSimon Glass /*
34e7a6acaSSimon Glass  * Copyright (C) 2014 Google, Inc
44e7a6acaSSimon Glass  */
54e7a6acaSSimon Glass #include <common.h>
6aad78d27SSimon Glass #include <dm.h>
74e7a6acaSSimon Glass #include <errno.h>
84e7a6acaSSimon Glass #include <fdtdec.h>
94e7a6acaSSimon Glass #include <malloc.h>
10f2b85ab5SSimon Glass #include <pch.h>
1125d5352cSSimon Glass #include <asm/cpu.h>
12bb096b9fSSimon Glass #include <asm/intel_regs.h>
13a5ea3a7dSSimon Glass #include <asm/io.h>
144e7a6acaSSimon Glass #include <asm/lapic.h>
158c30b571SSimon Glass #include <asm/lpc_common.h>
164e7a6acaSSimon Glass #include <asm/pci.h>
174e7a6acaSSimon Glass #include <asm/arch/model_206ax.h>
184e7a6acaSSimon Glass #include <asm/arch/pch.h>
194e7a6acaSSimon Glass #include <asm/arch/sandybridge.h>
204e7a6acaSSimon Glass 
2105af050eSSimon Glass DECLARE_GLOBAL_DATA_PTR;
2205af050eSSimon Glass 
23ec2af6f8SBin Meng #define GPIO_BASE		0x48
24f2b85ab5SSimon Glass #define BIOS_CTRL		0xdc
25f2b85ab5SSimon Glass 
26*67b0cda7SSimon Glass #define RCBA_AUDIO_CONFIG	0x2030
27*67b0cda7SSimon Glass #define RCBA_AUDIO_CONFIG_HDA	BIT(31)
28*67b0cda7SSimon Glass #define RCBA_AUDIO_CONFIG_MASK	0xfe
29*67b0cda7SSimon Glass 
3087077e97SBin Meng #ifndef CONFIG_HAVE_FSP
31a5ea3a7dSSimon Glass static int pch_revision_id = -1;
32a5ea3a7dSSimon Glass static int pch_type = -1;
33a5ea3a7dSSimon Glass 
34a5ea3a7dSSimon Glass /**
35a5ea3a7dSSimon Glass  * pch_silicon_revision() - Read silicon revision ID from the PCH
36a5ea3a7dSSimon Glass  *
37a5ea3a7dSSimon Glass  * @dev:	PCH device
38a5ea3a7dSSimon Glass  * @return silicon revision ID
39a5ea3a7dSSimon Glass  */
pch_silicon_revision(struct udevice * dev)40a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev)
41a5ea3a7dSSimon Glass {
42a5ea3a7dSSimon Glass 	u8 val;
43a5ea3a7dSSimon Glass 
44a5ea3a7dSSimon Glass 	if (pch_revision_id < 0) {
45a5ea3a7dSSimon Glass 		dm_pci_read_config8(dev, PCI_REVISION_ID, &val);
46a5ea3a7dSSimon Glass 		pch_revision_id = val;
47a5ea3a7dSSimon Glass 	}
48a5ea3a7dSSimon Glass 
49a5ea3a7dSSimon Glass 	return pch_revision_id;
50a5ea3a7dSSimon Glass }
51a5ea3a7dSSimon Glass 
pch_silicon_type(struct udevice * dev)52a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev)
53a5ea3a7dSSimon Glass {
54a5ea3a7dSSimon Glass 	u8 val;
55a5ea3a7dSSimon Glass 
56a5ea3a7dSSimon Glass 	if (pch_type < 0) {
57a5ea3a7dSSimon Glass 		dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val);
58a5ea3a7dSSimon Glass 		pch_type = val;
59a5ea3a7dSSimon Glass 	}
60a5ea3a7dSSimon Glass 
61a5ea3a7dSSimon Glass 	return pch_type;
62a5ea3a7dSSimon Glass }
63a5ea3a7dSSimon Glass 
64a5ea3a7dSSimon Glass /**
65a5ea3a7dSSimon Glass  * pch_silicon_supported() - Check if a certain revision is supported
66a5ea3a7dSSimon Glass  *
67a5ea3a7dSSimon Glass  * @dev:	PCH device
68a5ea3a7dSSimon Glass  * @type:	PCH type
69a5ea3a7dSSimon Glass  * @rev:	Minimum required resion
70a5ea3a7dSSimon Glass  * @return 0 if not supported, 1 if supported
71a5ea3a7dSSimon Glass  */
pch_silicon_supported(struct udevice * dev,int type,int rev)72a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev)
73a5ea3a7dSSimon Glass {
74a5ea3a7dSSimon Glass 	int cur_type = pch_silicon_type(dev);
75a5ea3a7dSSimon Glass 	int cur_rev = pch_silicon_revision(dev);
76a5ea3a7dSSimon Glass 
77a5ea3a7dSSimon Glass 	switch (type) {
78a5ea3a7dSSimon Glass 	case PCH_TYPE_CPT:
79a5ea3a7dSSimon Glass 		/* CougarPoint minimum revision */
80a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
81a5ea3a7dSSimon Glass 			return 1;
82a5ea3a7dSSimon Glass 		/* PantherPoint any revision */
83a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_PPT)
84a5ea3a7dSSimon Glass 			return 1;
85a5ea3a7dSSimon Glass 		break;
86a5ea3a7dSSimon Glass 
87a5ea3a7dSSimon Glass 	case PCH_TYPE_PPT:
88a5ea3a7dSSimon Glass 		/* PantherPoint minimum revision */
89a5ea3a7dSSimon Glass 		if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
90a5ea3a7dSSimon Glass 			return 1;
91a5ea3a7dSSimon Glass 		break;
92a5ea3a7dSSimon Glass 	}
93a5ea3a7dSSimon Glass 
94a5ea3a7dSSimon Glass 	return 0;
95a5ea3a7dSSimon Glass }
96a5ea3a7dSSimon Glass 
97a5ea3a7dSSimon Glass #define IOBP_RETRY 1000
iobp_poll(void)98a5ea3a7dSSimon Glass static inline int iobp_poll(void)
99a5ea3a7dSSimon Glass {
100a5ea3a7dSSimon Glass 	unsigned try = IOBP_RETRY;
101a5ea3a7dSSimon Glass 	u32 data;
102a5ea3a7dSSimon Glass 
103a5ea3a7dSSimon Glass 	while (try--) {
104a5ea3a7dSSimon Glass 		data = readl(RCB_REG(IOBPS));
105a5ea3a7dSSimon Glass 		if ((data & 1) == 0)
106a5ea3a7dSSimon Glass 			return 1;
107a5ea3a7dSSimon Glass 		udelay(10);
108a5ea3a7dSSimon Glass 	}
109a5ea3a7dSSimon Glass 
110a5ea3a7dSSimon Glass 	printf("IOBP timeout\n");
111a5ea3a7dSSimon Glass 	return 0;
112a5ea3a7dSSimon Glass }
113a5ea3a7dSSimon Glass 
pch_iobp_update(struct udevice * dev,u32 address,u32 andvalue,u32 orvalue)114a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue,
115a5ea3a7dSSimon Glass 		     u32 orvalue)
116a5ea3a7dSSimon Glass {
117a5ea3a7dSSimon Glass 	u32 data;
118a5ea3a7dSSimon Glass 
119a5ea3a7dSSimon Glass 	/* Set the address */
120a5ea3a7dSSimon Glass 	writel(address, RCB_REG(IOBPIRI));
121a5ea3a7dSSimon Glass 
122a5ea3a7dSSimon Glass 	/* READ OPCODE */
123a5ea3a7dSSimon Glass 	if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
124a5ea3a7dSSimon Glass 		writel(IOBPS_RW_BX, RCB_REG(IOBPS));
125a5ea3a7dSSimon Glass 	else
126a5ea3a7dSSimon Glass 		writel(IOBPS_READ_AX, RCB_REG(IOBPS));
127a5ea3a7dSSimon Glass 	if (!iobp_poll())
128a5ea3a7dSSimon Glass 		return;
129a5ea3a7dSSimon Glass 
130a5ea3a7dSSimon Glass 	/* Read IOBP data */
131a5ea3a7dSSimon Glass 	data = readl(RCB_REG(IOBPD));
132a5ea3a7dSSimon Glass 	if (!iobp_poll())
133a5ea3a7dSSimon Glass 		return;
134a5ea3a7dSSimon Glass 
135a5ea3a7dSSimon Glass 	/* Check for successful transaction */
136a5ea3a7dSSimon Glass 	if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) {
137a5ea3a7dSSimon Glass 		printf("IOBP read 0x%08x failed\n", address);
138a5ea3a7dSSimon Glass 		return;
139a5ea3a7dSSimon Glass 	}
140a5ea3a7dSSimon Glass 
141a5ea3a7dSSimon Glass 	/* Update the data */
142a5ea3a7dSSimon Glass 	data &= andvalue;
143a5ea3a7dSSimon Glass 	data |= orvalue;
144a5ea3a7dSSimon Glass 
145a5ea3a7dSSimon Glass 	/* WRITE OPCODE */
146a5ea3a7dSSimon Glass 	if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
147a5ea3a7dSSimon Glass 		writel(IOBPS_RW_BX, RCB_REG(IOBPS));
148a5ea3a7dSSimon Glass 	else
149a5ea3a7dSSimon Glass 		writel(IOBPS_WRITE_AX, RCB_REG(IOBPS));
150a5ea3a7dSSimon Glass 	if (!iobp_poll())
151a5ea3a7dSSimon Glass 		return;
152a5ea3a7dSSimon Glass 
153a5ea3a7dSSimon Glass 	/* Write IOBP data */
154a5ea3a7dSSimon Glass 	writel(data, RCB_REG(IOBPD));
155a5ea3a7dSSimon Glass 	if (!iobp_poll())
156a5ea3a7dSSimon Glass 		return;
157a5ea3a7dSSimon Glass }
158a5ea3a7dSSimon Glass 
bd82x6x_probe(struct udevice * dev)159aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev)
1604e7a6acaSSimon Glass {
1614acc83d4SSimon Glass 	if (!(gd->flags & GD_FLG_RELOC))
1624acc83d4SSimon Glass 		return 0;
1634acc83d4SSimon Glass 
16401a67908SSimon Glass 	/* Cause the SATA device to do its init */
165a219639dSSimon Glass 	uclass_first_device(UCLASS_AHCI, &dev);
16601a67908SSimon Glass 
1674e7a6acaSSimon Glass 	return 0;
1684e7a6acaSSimon Glass }
16987077e97SBin Meng #endif /* CONFIG_HAVE_FSP */
1704e7a6acaSSimon Glass 
bd82x6x_pch_get_spi_base(struct udevice * dev,ulong * sbasep)1713e389d8bSBin Meng static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep)
172f2b85ab5SSimon Glass {
173f2b85ab5SSimon Glass 	u32 rcba;
174f2b85ab5SSimon Glass 
175f2b85ab5SSimon Glass 	dm_pci_read_config32(dev, PCH_RCBA, &rcba);
176f2b85ab5SSimon Glass 	/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */
177f2b85ab5SSimon Glass 	rcba = rcba & 0xffffc000;
178f2b85ab5SSimon Glass 	*sbasep = rcba + 0x3800;
179f2b85ab5SSimon Glass 
180f2b85ab5SSimon Glass 	return 0;
181f2b85ab5SSimon Glass }
182f2b85ab5SSimon Glass 
bd82x6x_set_spi_protect(struct udevice * dev,bool protect)183f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
184f2b85ab5SSimon Glass {
1858c30b571SSimon Glass 	return lpc_set_spi_protect(dev, BIOS_CTRL, protect);
186f2b85ab5SSimon Glass }
187f2b85ab5SSimon Glass 
bd82x6x_get_gpio_base(struct udevice * dev,u32 * gbasep)188ec2af6f8SBin Meng static int bd82x6x_get_gpio_base(struct udevice *dev, u32 *gbasep)
189ec2af6f8SBin Meng {
190ec2af6f8SBin Meng 	u32 base;
191ec2af6f8SBin Meng 
192ec2af6f8SBin Meng 	/*
193ec2af6f8SBin Meng 	 * GPIO_BASE moved to its current offset with ICH6, but prior to
194ec2af6f8SBin Meng 	 * that it was unused (or undocumented). Check that it looks
195ec2af6f8SBin Meng 	 * okay: not all ones or zeros.
196ec2af6f8SBin Meng 	 *
197ec2af6f8SBin Meng 	 * Note we don't need check bit0 here, because the Tunnel Creek
198ec2af6f8SBin Meng 	 * GPIO base address register bit0 is reserved (read returns 0),
199ec2af6f8SBin Meng 	 * while on the Ivybridge the bit0 is used to indicate it is an
200ec2af6f8SBin Meng 	 * I/O space.
201ec2af6f8SBin Meng 	 */
202ec2af6f8SBin Meng 	dm_pci_read_config32(dev, GPIO_BASE, &base);
203ec2af6f8SBin Meng 	if (base == 0x00000000 || base == 0xffffffff) {
204ec2af6f8SBin Meng 		debug("%s: unexpected BASE value\n", __func__);
205ec2af6f8SBin Meng 		return -ENODEV;
206ec2af6f8SBin Meng 	}
207ec2af6f8SBin Meng 
208ec2af6f8SBin Meng 	/*
209ec2af6f8SBin Meng 	 * Okay, I guess we're looking at the right device. The actual
210ec2af6f8SBin Meng 	 * GPIO registers are in the PCI device's I/O space, starting
211ec2af6f8SBin Meng 	 * at the offset that we just read. Bit 0 indicates that it's
212ec2af6f8SBin Meng 	 * an I/O address, not a memory address, so mask that off.
213ec2af6f8SBin Meng 	 */
214ec2af6f8SBin Meng 	*gbasep = base & 1 ? base & ~3 : base & ~15;
215ec2af6f8SBin Meng 
216ec2af6f8SBin Meng 	return 0;
217ec2af6f8SBin Meng }
218ec2af6f8SBin Meng 
bd82x6x_ioctl(struct udevice * dev,enum pch_req_t req,void * data,int size)219*67b0cda7SSimon Glass static int bd82x6x_ioctl(struct udevice *dev, enum pch_req_t req, void *data,
220*67b0cda7SSimon Glass 			 int size)
221*67b0cda7SSimon Glass {
222*67b0cda7SSimon Glass 	u32 rcba, val;
223*67b0cda7SSimon Glass 
224*67b0cda7SSimon Glass 	switch (req) {
225*67b0cda7SSimon Glass 	case PCH_REQ_HDA_CONFIG:
226*67b0cda7SSimon Glass 		dm_pci_read_config32(dev, PCH_RCBA, &rcba);
227*67b0cda7SSimon Glass 		val = readl(rcba + RCBA_AUDIO_CONFIG);
228*67b0cda7SSimon Glass 		if (!(val & RCBA_AUDIO_CONFIG_HDA))
229*67b0cda7SSimon Glass 			return -ENOENT;
230*67b0cda7SSimon Glass 
231*67b0cda7SSimon Glass 		return val & RCBA_AUDIO_CONFIG_MASK;
232*67b0cda7SSimon Glass 	default:
233*67b0cda7SSimon Glass 		return -ENOSYS;
234*67b0cda7SSimon Glass 	}
235*67b0cda7SSimon Glass }
236*67b0cda7SSimon Glass 
237f2b85ab5SSimon Glass static const struct pch_ops bd82x6x_pch_ops = {
2383e389d8bSBin Meng 	.get_spi_base	= bd82x6x_pch_get_spi_base,
239f2b85ab5SSimon Glass 	.set_spi_protect = bd82x6x_set_spi_protect,
240ec2af6f8SBin Meng 	.get_gpio_base	= bd82x6x_get_gpio_base,
241*67b0cda7SSimon Glass 	.ioctl		= bd82x6x_ioctl,
242f2b85ab5SSimon Glass };
243f2b85ab5SSimon Glass 
244aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = {
245aad78d27SSimon Glass 	{ .compatible = "intel,bd82x6x" },
246aad78d27SSimon Glass 	{ }
247aad78d27SSimon Glass };
248aad78d27SSimon Glass 
249aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = {
250aad78d27SSimon Glass 	.name		= "bd82x6x",
251aad78d27SSimon Glass 	.id		= UCLASS_PCH,
252aad78d27SSimon Glass 	.of_match	= bd82x6x_ids,
25387077e97SBin Meng #ifndef CONFIG_HAVE_FSP
254aad78d27SSimon Glass 	.probe		= bd82x6x_probe,
25587077e97SBin Meng #endif
256f2b85ab5SSimon Glass 	.ops		= &bd82x6x_pch_ops,
257aad78d27SSimon Glass };
258