blob: 2549f2b8fc2eb8431a2820e093780984662287b0 [file] [log] [blame]
Angel Pons118a9c72020-04-02 23:48:34 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Duncan Laurie72748002013-10-31 08:26:23 -07003
4#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02005#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02006#include <device/pci_ops.h>
Duncan Laurie72748002013-10-31 08:26:23 -07007#include <console/console.h>
8#include <delay.h>
9#include <device/device.h>
10#include <device/resource.h>
11#include <device/pci.h>
12#include <stdint.h>
13#include <reg_script.h>
14
Julius Wernercd49cce2019-03-05 16:53:33 -080015#if CONFIG(ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -080016#include <cpu/x86/msr.h>
17#endif
18
Arthur Heymansd9802112019-11-19 18:46:44 +010019#define HAS_IOSF (CONFIG(SOC_INTEL_BAYTRAIL))
Werner Zeh9d021532016-02-19 10:02:49 +010020
21#if HAS_IOSF
Julius Werner18ea2d32014-10-07 16:42:17 -070022#include <soc/iosf.h> /* TODO: wrap in <soc/reg_script.h, remove #ifdef? */
Duncan Laurie72748002013-10-31 08:26:23 -070023#endif
24
25#define POLL_DELAY 100 /* 100us */
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030026
27#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070028#define EMPTY_DEV 0
29#else
30#define EMPTY_DEV NULL
31#endif
32
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +010033#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070034static inline void reg_script_set_dev(struct reg_script_context *ctx,
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +010035 pci_devfn_t dev)
36#else
37static inline void reg_script_set_dev(struct reg_script_context *ctx,
38 struct device *dev)
39#endif
Duncan Laurie72748002013-10-31 08:26:23 -070040{
41 ctx->dev = dev;
42 ctx->res = NULL;
43}
44
45static inline void reg_script_set_step(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -080046 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -070047{
48 ctx->step = step;
49}
50
51static inline const struct reg_script *
52reg_script_get_step(struct reg_script_context *ctx)
53{
54 return ctx->step;
55}
56
57static struct resource *reg_script_get_resource(struct reg_script_context *ctx)
58{
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030059#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070060 return NULL;
61#else
62 struct resource *res;
63 const struct reg_script *step = reg_script_get_step(ctx);
64
65 res = ctx->res;
66
67 if (res != NULL && res->index == step->res_index)
68 return res;
69
70 res = find_resource(ctx->dev, step->res_index);
71 ctx->res = res;
72 return res;
73#endif
74}
75
76static uint32_t reg_script_read_pci(struct reg_script_context *ctx)
77{
78 const struct reg_script *step = reg_script_get_step(ctx);
79
80 switch (step->size) {
81 case REG_SCRIPT_SIZE_8:
82 return pci_read_config8(ctx->dev, step->reg);
83 case REG_SCRIPT_SIZE_16:
84 return pci_read_config16(ctx->dev, step->reg);
85 case REG_SCRIPT_SIZE_32:
86 return pci_read_config32(ctx->dev, step->reg);
87 }
88 return 0;
89}
90
91static void reg_script_write_pci(struct reg_script_context *ctx)
92{
93 const struct reg_script *step = reg_script_get_step(ctx);
94
95 switch (step->size) {
96 case REG_SCRIPT_SIZE_8:
97 pci_write_config8(ctx->dev, step->reg, step->value);
98 break;
99 case REG_SCRIPT_SIZE_16:
100 pci_write_config16(ctx->dev, step->reg, step->value);
101 break;
102 case REG_SCRIPT_SIZE_32:
103 pci_write_config32(ctx->dev, step->reg, step->value);
104 break;
105 }
106}
107
108static uint32_t reg_script_read_io(struct reg_script_context *ctx)
109{
110 const struct reg_script *step = reg_script_get_step(ctx);
111
112 switch (step->size) {
113 case REG_SCRIPT_SIZE_8:
114 return inb(step->reg);
115 case REG_SCRIPT_SIZE_16:
116 return inw(step->reg);
117 case REG_SCRIPT_SIZE_32:
118 return inl(step->reg);
119 }
120 return 0;
121}
122
123static void reg_script_write_io(struct reg_script_context *ctx)
124{
125 const struct reg_script *step = reg_script_get_step(ctx);
126
127 switch (step->size) {
128 case REG_SCRIPT_SIZE_8:
129 outb(step->value, step->reg);
130 break;
131 case REG_SCRIPT_SIZE_16:
132 outw(step->value, step->reg);
133 break;
134 case REG_SCRIPT_SIZE_32:
135 outl(step->value, step->reg);
136 break;
137 }
138}
139
140static uint32_t reg_script_read_mmio(struct reg_script_context *ctx)
141{
142 const struct reg_script *step = reg_script_get_step(ctx);
143
144 switch (step->size) {
145 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800146 return read8((u8 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700147 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800148 return read16((u16 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700149 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800150 return read32((u32 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700151 }
152 return 0;
153}
154
155static void reg_script_write_mmio(struct reg_script_context *ctx)
156{
157 const struct reg_script *step = reg_script_get_step(ctx);
158
159 switch (step->size) {
160 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800161 write8((u8 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700162 break;
163 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800164 write16((u16 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700165 break;
166 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800167 write32((u32 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700168 break;
169 }
170}
171
172static uint32_t reg_script_read_res(struct reg_script_context *ctx)
173{
174 struct resource *res;
175 uint32_t val = 0;
176 const struct reg_script *step = reg_script_get_step(ctx);
177
178 res = reg_script_get_resource(ctx);
179
180 if (res == NULL)
181 return val;
182
183 if (res->flags & IORESOURCE_IO) {
184 const struct reg_script io_step = {
185 .size = step->size,
186 .reg = res->base + step->reg,
187 };
188 reg_script_set_step(ctx, &io_step);
189 val = reg_script_read_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800190 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700191 const struct reg_script mmio_step = {
192 .size = step->size,
193 .reg = res->base + step->reg,
194 };
195 reg_script_set_step(ctx, &mmio_step);
196 val = reg_script_read_mmio(ctx);
197 }
198 reg_script_set_step(ctx, step);
199 return val;
200}
201
202static void reg_script_write_res(struct reg_script_context *ctx)
203{
204 struct resource *res;
205 const struct reg_script *step = reg_script_get_step(ctx);
206
207 res = reg_script_get_resource(ctx);
208
209 if (res == NULL)
210 return;
211
212 if (res->flags & IORESOURCE_IO) {
213 const struct reg_script io_step = {
214 .size = step->size,
215 .reg = res->base + step->reg,
216 .value = step->value,
217 };
218 reg_script_set_step(ctx, &io_step);
219 reg_script_write_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800220 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700221 const struct reg_script mmio_step = {
222 .size = step->size,
223 .reg = res->base + step->reg,
224 .value = step->value,
225 };
226 reg_script_set_step(ctx, &mmio_step);
227 reg_script_write_mmio(ctx);
228 }
229 reg_script_set_step(ctx, step);
230}
231
Werner Zeh9d021532016-02-19 10:02:49 +0100232#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700233static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
234{
Duncan Laurie72748002013-10-31 08:26:23 -0700235 const struct reg_script *step = reg_script_get_step(ctx);
236
237 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800238 case IOSF_PORT_AUNIT:
239 return iosf_aunit_read(step->reg);
240 case IOSF_PORT_CPU_BUS:
241 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700242 case IOSF_PORT_BUNIT:
243 return iosf_bunit_read(step->reg);
244 case IOSF_PORT_DUNIT_CH0:
245 return iosf_dunit_ch0_read(step->reg);
246 case IOSF_PORT_PMC:
247 return iosf_punit_read(step->reg);
248 case IOSF_PORT_USBPHY:
249 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800250 case IOSF_PORT_SEC:
251 return iosf_sec_read(step->reg);
252 case IOSF_PORT_0x45:
253 return iosf_port45_read(step->reg);
254 case IOSF_PORT_0x46:
255 return iosf_port46_read(step->reg);
256 case IOSF_PORT_0x47:
257 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600258 case IOSF_PORT_SCORE:
259 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800260 case IOSF_PORT_0x55:
261 return iosf_port55_read(step->reg);
262 case IOSF_PORT_0x58:
263 return iosf_port58_read(step->reg);
264 case IOSF_PORT_0x59:
265 return iosf_port59_read(step->reg);
266 case IOSF_PORT_0x5a:
267 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700268 case IOSF_PORT_USHPHY:
269 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600270 case IOSF_PORT_SCC:
271 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600272 case IOSF_PORT_LPSS:
273 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800274 case IOSF_PORT_0xa2:
275 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600276 case IOSF_PORT_CCU:
277 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800278 case IOSF_PORT_SSUS:
279 return iosf_ssus_read(step->reg);
280 default:
281 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
282 step->id);
283 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700284 }
Duncan Laurie72748002013-10-31 08:26:23 -0700285 return 0;
286}
287
288static void reg_script_write_iosf(struct reg_script_context *ctx)
289{
Duncan Laurie72748002013-10-31 08:26:23 -0700290 const struct reg_script *step = reg_script_get_step(ctx);
291
292 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800293 case IOSF_PORT_AUNIT:
294 iosf_aunit_write(step->reg, step->value);
295 break;
296 case IOSF_PORT_CPU_BUS:
297 iosf_cpu_bus_write(step->reg, step->value);
298 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700299 case IOSF_PORT_BUNIT:
300 iosf_bunit_write(step->reg, step->value);
301 break;
302 case IOSF_PORT_DUNIT_CH0:
303 iosf_dunit_write(step->reg, step->value);
304 break;
305 case IOSF_PORT_PMC:
306 iosf_punit_write(step->reg, step->value);
307 break;
308 case IOSF_PORT_USBPHY:
309 iosf_usbphy_write(step->reg, step->value);
310 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800311 case IOSF_PORT_SEC:
312 iosf_sec_write(step->reg, step->value);
313 break;
314 case IOSF_PORT_0x45:
315 iosf_port45_write(step->reg, step->value);
316 break;
317 case IOSF_PORT_0x46:
318 iosf_port46_write(step->reg, step->value);
319 break;
320 case IOSF_PORT_0x47:
321 iosf_port47_write(step->reg, step->value);
322 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600323 case IOSF_PORT_SCORE:
324 iosf_score_write(step->reg, step->value);
325 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800326 case IOSF_PORT_0x55:
327 iosf_port55_write(step->reg, step->value);
328 break;
329 case IOSF_PORT_0x58:
330 iosf_port58_write(step->reg, step->value);
331 break;
332 case IOSF_PORT_0x59:
333 iosf_port59_write(step->reg, step->value);
334 break;
335 case IOSF_PORT_0x5a:
336 iosf_port5a_write(step->reg, step->value);
337 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700338 case IOSF_PORT_USHPHY:
339 iosf_ushphy_write(step->reg, step->value);
340 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600341 case IOSF_PORT_SCC:
342 iosf_scc_write(step->reg, step->value);
343 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600344 case IOSF_PORT_LPSS:
345 iosf_lpss_write(step->reg, step->value);
346 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800347 case IOSF_PORT_0xa2:
348 iosf_porta2_write(step->reg, step->value);
349 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600350 case IOSF_PORT_CCU:
351 iosf_ccu_write(step->reg, step->value);
352 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800353 case IOSF_PORT_SSUS:
354 iosf_ssus_write(step->reg, step->value);
355 break;
356 default:
357 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
358 step->id);
359 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700360 }
Duncan Laurie72748002013-10-31 08:26:23 -0700361}
Werner Zeh9d021532016-02-19 10:02:49 +0100362#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700363
Duncan Laurie72748002013-10-31 08:26:23 -0700364
Duncan Lauriefd461e32013-11-08 23:00:24 -0800365static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
366{
Julius Wernercd49cce2019-03-05 16:53:33 -0800367#if CONFIG(ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -0800368 const struct reg_script *step = reg_script_get_step(ctx);
369 msr_t msr = rdmsr(step->reg);
370 uint64_t value = msr.hi;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800371 value <<= 32;
372 value |= msr.lo;
373 return value;
374#endif
375}
376
377static void reg_script_write_msr(struct reg_script_context *ctx)
378{
Julius Wernercd49cce2019-03-05 16:53:33 -0800379#if CONFIG(ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -0800380 const struct reg_script *step = reg_script_get_step(ctx);
381 msr_t msr;
382 msr.hi = step->value >> 32;
383 msr.lo = step->value & 0xffffffff;
384 wrmsr(step->reg, msr);
385#endif
386}
387
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700388/* Locate the structure containing the platform specific bus access routines */
389static const struct reg_script_bus_entry
390 *find_bus(const struct reg_script *step)
391{
Lee Leahyefcee9f2016-04-29 17:26:36 -0700392 extern const struct reg_script_bus_entry *_rsbe_init_begin[];
393 extern const struct reg_script_bus_entry *_ersbe_init_begin[];
Lee Leahyb2d834a2017-03-08 16:52:22 -0800394 const struct reg_script_bus_entry * const *bus;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700395 size_t table_entries;
396 size_t i;
397
398 /* Locate the platform specific bus */
Lee Leahyefcee9f2016-04-29 17:26:36 -0700399 bus = _rsbe_init_begin;
400 table_entries = &_ersbe_init_begin[0] - &_rsbe_init_begin[0];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700401 for (i = 0; i < table_entries; i++) {
Lee Leahyefcee9f2016-04-29 17:26:36 -0700402 if (bus[i]->type == step->type)
403 return bus[i];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700404 }
405
406 /* Bus not found */
407 return NULL;
408}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700409
Lee Leahy564dc9c2016-04-29 15:07:19 -0700410static void reg_script_display(struct reg_script_context *ctx,
411 const struct reg_script *step, const char *arrow, uint64_t value)
412{
413 /* Display the register address and data */
414 if (ctx->display_prefix != NULL)
415 printk(BIOS_INFO, "%s: ", ctx->display_prefix);
416 if (ctx->display_features & REG_SCRIPT_DISPLAY_REGISTER)
417 printk(BIOS_INFO, "0x%08x %s ", step->reg, arrow);
418 if (ctx->display_features & REG_SCRIPT_DISPLAY_VALUE)
419 switch (step->size) {
420 case REG_SCRIPT_SIZE_8:
421 printk(BIOS_INFO, "0x%02x\n", (uint8_t)value);
422 break;
423 case REG_SCRIPT_SIZE_16:
424 printk(BIOS_INFO, "0x%04x\n", (int16_t)value);
425 break;
426 case REG_SCRIPT_SIZE_32:
427 printk(BIOS_INFO, "0x%08x\n", (uint32_t)value);
428 break;
429 default:
430 printk(BIOS_INFO, "0x%016llx\n", value);
431 break;
432 }
433}
434
Duncan Lauriefd461e32013-11-08 23:00:24 -0800435static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700436{
437 const struct reg_script *step = reg_script_get_step(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700438 uint64_t value = 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700439
440 switch (step->type) {
441 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700442 ctx->display_prefix = "PCI";
443 value = reg_script_read_pci(ctx);
444 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700445 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700446 ctx->display_prefix = "IO";
447 value = reg_script_read_io(ctx);
448 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700449 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700450 ctx->display_prefix = "MMIO";
451 value = reg_script_read_mmio(ctx);
452 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700453 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700454 ctx->display_prefix = "RES";
455 value = reg_script_read_res(ctx);
456 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800457 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700458 ctx->display_prefix = "MSR";
459 value = reg_script_read_msr(ctx);
460 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100461#if HAS_IOSF
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700462 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700463 ctx->display_prefix = "IOSF";
464 value = reg_script_read_iosf(ctx);
465 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100466#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700467 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700468 {
469 const struct reg_script_bus_entry *bus;
470
471 /* Read from the platform specific bus */
472 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800473 if (bus != NULL) {
Lee Leahy564dc9c2016-04-29 15:07:19 -0700474 value = bus->reg_script_read(ctx);
475 break;
Stefan Reinauerf7dd6d52016-05-04 17:52:56 -0700476 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700477 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700478 printk(BIOS_ERR,
479 "Unsupported read type (0x%x) for this device!\n",
480 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700481 return 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700482 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700483
484 /* Display the register address and data */
485 if (ctx->display_features)
486 reg_script_display(ctx, step, "-->", value);
487 return value;
Duncan Laurie72748002013-10-31 08:26:23 -0700488}
489
490static void reg_script_write(struct reg_script_context *ctx)
491{
492 const struct reg_script *step = reg_script_get_step(ctx);
493
494 switch (step->type) {
495 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700496 ctx->display_prefix = "PCI";
Duncan Laurie72748002013-10-31 08:26:23 -0700497 reg_script_write_pci(ctx);
498 break;
499 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700500 ctx->display_prefix = "IO";
Duncan Laurie72748002013-10-31 08:26:23 -0700501 reg_script_write_io(ctx);
502 break;
503 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700504 ctx->display_prefix = "MMIO";
Duncan Laurie72748002013-10-31 08:26:23 -0700505 reg_script_write_mmio(ctx);
506 break;
507 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700508 ctx->display_prefix = "RES";
Duncan Laurie72748002013-10-31 08:26:23 -0700509 reg_script_write_res(ctx);
510 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700511 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700512 ctx->display_prefix = "MSR";
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700513 reg_script_write_msr(ctx);
514 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100515#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700516 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700517 ctx->display_prefix = "IOSF";
Duncan Laurie72748002013-10-31 08:26:23 -0700518 reg_script_write_iosf(ctx);
519 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100520#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700521 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700522 {
523 const struct reg_script_bus_entry *bus;
524
525 /* Write to the platform specific bus */
526 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800527 if (bus != NULL) {
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700528 bus->reg_script_write(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700529 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700530 }
531 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700532 printk(BIOS_ERR,
533 "Unsupported write type (0x%x) for this device!\n",
534 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700535 return;
Duncan Laurie72748002013-10-31 08:26:23 -0700536 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700537
538 /* Display the register address and data */
539 if (ctx->display_features)
540 reg_script_display(ctx, step, "<--", step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700541}
542
543static void reg_script_rmw(struct reg_script_context *ctx)
544{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800545 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700546 const struct reg_script *step = reg_script_get_step(ctx);
547 struct reg_script write_step = *step;
548
549 value = reg_script_read(ctx);
550 value &= step->mask;
551 value |= step->value;
552 write_step.value = value;
553 reg_script_set_step(ctx, &write_step);
554 reg_script_write(ctx);
555 reg_script_set_step(ctx, step);
556}
557
Lee Leahy6bcbe572016-04-23 07:58:27 -0700558static void reg_script_rxw(struct reg_script_context *ctx)
559{
560 uint64_t value;
561 const struct reg_script *step = reg_script_get_step(ctx);
562 struct reg_script write_step = *step;
563
564/*
565 * XOR logic table
566 * Input XOR Value
567 * 0 0 0
568 * 0 1 1
569 * 1 0 1
570 * 1 1 0
571 *
572 * Supported operations
573 *
574 * Input Mask Temp XOR Value Operation
575 * 0 0 0 0 0 Clear bit
576 * 1 0 0 0 0
577 * 0 0 0 1 1 Set bit
578 * 1 0 0 1 1
579 * 0 1 0 0 0 Preserve bit
580 * 1 1 1 0 1
581 * 0 1 0 1 1 Toggle bit
582 * 1 1 1 1 0
583 */
584 value = reg_script_read(ctx);
585 value &= step->mask;
586 value ^= step->value;
587 write_step.value = value;
588 reg_script_set_step(ctx, &write_step);
589 reg_script_write(ctx);
590 reg_script_set_step(ctx, step);
591}
592
Duncan Laurie72748002013-10-31 08:26:23 -0700593/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
594 * as recursive call with a new context that has the same dev and resource
595 * as the previous one. That will run to completion and then move on to the
596 * next step of the previous context. */
597static void reg_script_run_next(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800598 const struct reg_script *step);
Duncan Laurie72748002013-10-31 08:26:23 -0700599
Duncan Lauriefd461e32013-11-08 23:00:24 -0800600
601static void reg_script_run_step(struct reg_script_context *ctx,
602 const struct reg_script *step)
603{
604 uint64_t value = 0, try;
605
Lee Leahy564dc9c2016-04-29 15:07:19 -0700606 ctx->display_features = ctx->display_state;
607 ctx->display_prefix = NULL;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800608 switch (step->command) {
609 case REG_SCRIPT_COMMAND_READ:
610 (void)reg_script_read(ctx);
611 break;
612 case REG_SCRIPT_COMMAND_WRITE:
613 reg_script_write(ctx);
614 break;
615 case REG_SCRIPT_COMMAND_RMW:
616 reg_script_rmw(ctx);
617 break;
Lee Leahy6bcbe572016-04-23 07:58:27 -0700618 case REG_SCRIPT_COMMAND_RXW:
619 reg_script_rxw(ctx);
620 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800621 case REG_SCRIPT_COMMAND_POLL:
622 for (try = 0; try < step->timeout; try += POLL_DELAY) {
623 value = reg_script_read(ctx) & step->mask;
624 if (value == step->value)
625 break;
626 udelay(POLL_DELAY);
627 }
628 if (try >= step->timeout)
629 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
630 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
631 step->reg, (unsigned long)step->value,
632 (unsigned long)value);
633 break;
634 case REG_SCRIPT_COMMAND_SET_DEV:
635 reg_script_set_dev(ctx, step->dev);
636 break;
637 case REG_SCRIPT_COMMAND_NEXT:
638 reg_script_run_next(ctx, step->next);
639 break;
Lee Leahy564dc9c2016-04-29 15:07:19 -0700640 case REG_SCRIPT_COMMAND_DISPLAY:
641 ctx->display_state = step->value;
642 break;
643
Duncan Lauriefd461e32013-11-08 23:00:24 -0800644 default:
645 printk(BIOS_WARNING, "Invalid command: %08x\n",
646 step->command);
647 break;
648 }
649}
650
Duncan Laurie72748002013-10-31 08:26:23 -0700651static void reg_script_run_with_context(struct reg_script_context *ctx)
652{
Duncan Laurie72748002013-10-31 08:26:23 -0700653 while (1) {
654 const struct reg_script *step = reg_script_get_step(ctx);
655
656 if (step->command == REG_SCRIPT_COMMAND_END)
657 break;
658
Duncan Lauriefd461e32013-11-08 23:00:24 -0800659 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700660 reg_script_set_step(ctx, step + 1);
661 }
662}
663
664static void reg_script_run_next(struct reg_script_context *prev_ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800665 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700666{
667 struct reg_script_context ctx;
668
669 /* Use prev context as a basis but start at a new step. */
670 ctx = *prev_ctx;
671 reg_script_set_step(&ctx, step);
672 reg_script_run_with_context(&ctx);
673}
674
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +0100675#ifdef __SIMPLE_DEVICE__
676void reg_script_run_on_dev(pci_devfn_t dev, const struct reg_script *step)
677#else
678void reg_script_run_on_dev(struct device *dev, const struct reg_script *step)
679#endif
Duncan Laurie72748002013-10-31 08:26:23 -0700680{
681 struct reg_script_context ctx;
682
Lee Leahy564dc9c2016-04-29 15:07:19 -0700683 ctx.display_state = REG_SCRIPT_DISPLAY_NOTHING;
Aaron Durbind86f0b72013-12-10 17:09:40 -0800684 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700685 reg_script_set_step(&ctx, step);
686 reg_script_run_with_context(&ctx);
687}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800688
689void reg_script_run(const struct reg_script *step)
690{
691 reg_script_run_on_dev(EMPTY_DEV, step);
692}