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