blob: 70a0aea3e0244ebe42b7c45ee703a190ccb0d940 [file] [log] [blame]
Simon Glass17f1c402014-11-14 18:18:32 -07001/*
2 * Copyright (C) 2014 Google, Inc
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
Simon Glass17f1c402014-11-14 18:18:32 -07006#include <common.h>
Simon Glasse0e7b362015-03-05 12:25:33 -07007#include <dm.h>
Simon Glass17f1c402014-11-14 18:18:32 -07008#include <errno.h>
9#include <fdtdec.h>
10#include <malloc.h>
Simon Glass32761632016-01-18 20:19:21 -070011#include <pch.h>
Simon Glass6c9e1d82016-01-17 16:11:53 -070012#include <asm/io.h>
Simon Glass17f1c402014-11-14 18:18:32 -070013#include <asm/lapic.h>
14#include <asm/pci.h>
15#include <asm/arch/bd82x6x.h>
16#include <asm/arch/model_206ax.h>
17#include <asm/arch/pch.h>
18#include <asm/arch/sandybridge.h>
19
Simon Glass32761632016-01-18 20:19:21 -070020#define BIOS_CTRL 0xdc
21
Simon Glass6c9e1d82016-01-17 16:11:53 -070022static int pch_revision_id = -1;
23static int pch_type = -1;
24
25/**
26 * pch_silicon_revision() - Read silicon revision ID from the PCH
27 *
28 * @dev: PCH device
29 * @return silicon revision ID
30 */
31static int pch_silicon_revision(struct udevice *dev)
32{
33 u8 val;
34
35 if (pch_revision_id < 0) {
36 dm_pci_read_config8(dev, PCI_REVISION_ID, &val);
37 pch_revision_id = val;
38 }
39
40 return pch_revision_id;
41}
42
43int pch_silicon_type(struct udevice *dev)
44{
45 u8 val;
46
47 if (pch_type < 0) {
48 dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val);
49 pch_type = val;
50 }
51
52 return pch_type;
53}
54
55/**
56 * pch_silicon_supported() - Check if a certain revision is supported
57 *
58 * @dev: PCH device
59 * @type: PCH type
60 * @rev: Minimum required resion
61 * @return 0 if not supported, 1 if supported
62 */
63static int pch_silicon_supported(struct udevice *dev, int type, int rev)
64{
65 int cur_type = pch_silicon_type(dev);
66 int cur_rev = pch_silicon_revision(dev);
67
68 switch (type) {
69 case PCH_TYPE_CPT:
70 /* CougarPoint minimum revision */
71 if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
72 return 1;
73 /* PantherPoint any revision */
74 if (cur_type == PCH_TYPE_PPT)
75 return 1;
76 break;
77
78 case PCH_TYPE_PPT:
79 /* PantherPoint minimum revision */
80 if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
81 return 1;
82 break;
83 }
84
85 return 0;
86}
87
88#define IOBP_RETRY 1000
89static inline int iobp_poll(void)
90{
91 unsigned try = IOBP_RETRY;
92 u32 data;
93
94 while (try--) {
95 data = readl(RCB_REG(IOBPS));
96 if ((data & 1) == 0)
97 return 1;
98 udelay(10);
99 }
100
101 printf("IOBP timeout\n");
102 return 0;
103}
104
105void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue,
106 u32 orvalue)
107{
108 u32 data;
109
110 /* Set the address */
111 writel(address, RCB_REG(IOBPIRI));
112
113 /* READ OPCODE */
114 if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
115 writel(IOBPS_RW_BX, RCB_REG(IOBPS));
116 else
117 writel(IOBPS_READ_AX, RCB_REG(IOBPS));
118 if (!iobp_poll())
119 return;
120
121 /* Read IOBP data */
122 data = readl(RCB_REG(IOBPD));
123 if (!iobp_poll())
124 return;
125
126 /* Check for successful transaction */
127 if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) {
128 printf("IOBP read 0x%08x failed\n", address);
129 return;
130 }
131
132 /* Update the data */
133 data &= andvalue;
134 data |= orvalue;
135
136 /* WRITE OPCODE */
137 if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0))
138 writel(IOBPS_RW_BX, RCB_REG(IOBPS));
139 else
140 writel(IOBPS_WRITE_AX, RCB_REG(IOBPS));
141 if (!iobp_poll())
142 return;
143
144 /* Write IOBP data */
145 writel(data, RCB_REG(IOBPD));
146 if (!iobp_poll())
147 return;
148}
149
Simon Glasse0e7b362015-03-05 12:25:33 -0700150static int bd82x6x_probe(struct udevice *dev)
Simon Glass17f1c402014-11-14 18:18:32 -0700151{
Simon Glasscd0adb32014-11-14 18:18:38 -0700152 const void *blob = gd->fdt_blob;
Simon Glass39f3f8c2016-01-17 16:11:37 -0700153 int gma_node;
Simon Glassd90f8e12014-11-14 20:56:36 -0700154 int ret;
Simon Glass06409c92014-11-14 18:18:35 -0700155
Simon Glass044f1a02016-01-17 16:11:10 -0700156 if (!(gd->flags & GD_FLG_RELOC))
157 return 0;
158
Simon Glass39f3f8c2016-01-17 16:11:37 -0700159 /* Cause the SATA device to do its init */
160 uclass_first_device(UCLASS_DISK, &dev);
161
Simon Glass194d7572014-11-14 18:18:40 -0700162 bd82x6x_usb_ehci_init(PCH_EHCI1_DEV);
163 bd82x6x_usb_ehci_init(PCH_EHCI2_DEV);
Simon Glass06409c92014-11-14 18:18:35 -0700164
Simon Glassd90f8e12014-11-14 20:56:36 -0700165 gma_node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_GMA);
166 if (gma_node < 0) {
167 debug("%s: Cannot find GMA node\n", __func__);
168 return -EINVAL;
169 }
Simon Glass35230352015-11-29 13:17:55 -0700170 ret = dm_pci_bus_find_bdf(PCH_VIDEO_DEV, &dev);
171 if (ret)
172 return ret;
173 ret = gma_func0_init(dev, blob, gma_node);
Simon Glassd90f8e12014-11-14 20:56:36 -0700174 if (ret)
175 return ret;
176
Simon Glass17f1c402014-11-14 18:18:32 -0700177 return 0;
178}
179
Simon Glass32761632016-01-18 20:19:21 -0700180static int bd82x6x_pch_get_sbase(struct udevice *dev, ulong *sbasep)
181{
182 u32 rcba;
183
184 dm_pci_read_config32(dev, PCH_RCBA, &rcba);
185 /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */
186 rcba = rcba & 0xffffc000;
187 *sbasep = rcba + 0x3800;
188
189 return 0;
190}
191
192static enum pch_version bd82x6x_pch_get_version(struct udevice *dev)
193{
194 return PCHV_9;
195}
196
197static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
198{
199 uint8_t bios_cntl;
200
201 /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
202 dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl);
203 if (protect) {
204 bios_cntl &= ~BIOS_CTRL_BIOSWE;
205 bios_cntl |= BIT(5);
206 } else {
207 bios_cntl |= BIOS_CTRL_BIOSWE;
208 bios_cntl &= ~BIT(5);
209 }
210 dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl);
211
212 return 0;
213}
214
215static const struct pch_ops bd82x6x_pch_ops = {
216 .get_sbase = bd82x6x_pch_get_sbase,
217 .get_version = bd82x6x_pch_get_version,
218 .set_spi_protect = bd82x6x_set_spi_protect,
219};
220
Simon Glasse0e7b362015-03-05 12:25:33 -0700221static const struct udevice_id bd82x6x_ids[] = {
222 { .compatible = "intel,bd82x6x" },
223 { }
224};
225
226U_BOOT_DRIVER(bd82x6x_drv) = {
227 .name = "bd82x6x",
228 .id = UCLASS_PCH,
229 .of_match = bd82x6x_ids,
230 .probe = bd82x6x_probe,
Simon Glass32761632016-01-18 20:19:21 -0700231 .ops = &bd82x6x_pch_ops,
Simon Glasse0e7b362015-03-05 12:25:33 -0700232};