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