blob: 6234af67d5e8ab7c343dadfb092863d16cdfafda [file] [log] [blame]
Duncan Laurie72748002013-10-31 08:26:23 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2013 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Duncan Laurie72748002013-10-31 08:26:23 -070014 */
15
16#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020017#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020018#include <device/pci_ops.h>
Duncan Laurie72748002013-10-31 08:26:23 -070019#include <console/console.h>
20#include <delay.h>
21#include <device/device.h>
22#include <device/resource.h>
23#include <device/pci.h>
24#include <stdint.h>
25#include <reg_script.h>
26
Martin Roth1bf55b42017-06-24 14:16:38 -060027#if IS_ENABLED(CONFIG_ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -080028#include <cpu/x86/msr.h>
29#endif
30
Werner Zeh9d021532016-02-19 10:02:49 +010031#define HAS_IOSF (IS_ENABLED(CONFIG_SOC_INTEL_BAYTRAIL) || \
32 IS_ENABLED(CONFIG_SOC_INTEL_FSP_BAYTRAIL))
33
34#if HAS_IOSF
Julius Werner18ea2d32014-10-07 16:42:17 -070035#include <soc/iosf.h> /* TODO: wrap in <soc/reg_script.h, remove #ifdef? */
Duncan Laurie72748002013-10-31 08:26:23 -070036#endif
37
38#define POLL_DELAY 100 /* 100us */
39#if defined(__PRE_RAM__)
40#define EMPTY_DEV 0
41#else
42#define EMPTY_DEV NULL
43#endif
44
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +010045#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070046static inline void reg_script_set_dev(struct reg_script_context *ctx,
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +010047 pci_devfn_t dev)
48#else
49static inline void reg_script_set_dev(struct reg_script_context *ctx,
50 struct device *dev)
51#endif
Duncan Laurie72748002013-10-31 08:26:23 -070052{
53 ctx->dev = dev;
54 ctx->res = NULL;
55}
56
57static inline void reg_script_set_step(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -080058 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -070059{
60 ctx->step = step;
61}
62
63static inline const struct reg_script *
64reg_script_get_step(struct reg_script_context *ctx)
65{
66 return ctx->step;
67}
68
69static struct resource *reg_script_get_resource(struct reg_script_context *ctx)
70{
71#if defined(__PRE_RAM__)
72 return NULL;
73#else
74 struct resource *res;
75 const struct reg_script *step = reg_script_get_step(ctx);
76
77 res = ctx->res;
78
79 if (res != NULL && res->index == step->res_index)
80 return res;
81
82 res = find_resource(ctx->dev, step->res_index);
83 ctx->res = res;
84 return res;
85#endif
86}
87
88static uint32_t reg_script_read_pci(struct reg_script_context *ctx)
89{
90 const struct reg_script *step = reg_script_get_step(ctx);
91
92 switch (step->size) {
93 case REG_SCRIPT_SIZE_8:
94 return pci_read_config8(ctx->dev, step->reg);
95 case REG_SCRIPT_SIZE_16:
96 return pci_read_config16(ctx->dev, step->reg);
97 case REG_SCRIPT_SIZE_32:
98 return pci_read_config32(ctx->dev, step->reg);
99 }
100 return 0;
101}
102
103static void reg_script_write_pci(struct reg_script_context *ctx)
104{
105 const struct reg_script *step = reg_script_get_step(ctx);
106
107 switch (step->size) {
108 case REG_SCRIPT_SIZE_8:
109 pci_write_config8(ctx->dev, step->reg, step->value);
110 break;
111 case REG_SCRIPT_SIZE_16:
112 pci_write_config16(ctx->dev, step->reg, step->value);
113 break;
114 case REG_SCRIPT_SIZE_32:
115 pci_write_config32(ctx->dev, step->reg, step->value);
116 break;
117 }
118}
119
120static uint32_t reg_script_read_io(struct reg_script_context *ctx)
121{
122 const struct reg_script *step = reg_script_get_step(ctx);
123
124 switch (step->size) {
125 case REG_SCRIPT_SIZE_8:
126 return inb(step->reg);
127 case REG_SCRIPT_SIZE_16:
128 return inw(step->reg);
129 case REG_SCRIPT_SIZE_32:
130 return inl(step->reg);
131 }
132 return 0;
133}
134
135static void reg_script_write_io(struct reg_script_context *ctx)
136{
137 const struct reg_script *step = reg_script_get_step(ctx);
138
139 switch (step->size) {
140 case REG_SCRIPT_SIZE_8:
141 outb(step->value, step->reg);
142 break;
143 case REG_SCRIPT_SIZE_16:
144 outw(step->value, step->reg);
145 break;
146 case REG_SCRIPT_SIZE_32:
147 outl(step->value, step->reg);
148 break;
149 }
150}
151
152static uint32_t reg_script_read_mmio(struct reg_script_context *ctx)
153{
154 const struct reg_script *step = reg_script_get_step(ctx);
155
156 switch (step->size) {
157 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800158 return read8((u8 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700159 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800160 return read16((u16 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700161 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800162 return read32((u32 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700163 }
164 return 0;
165}
166
167static void reg_script_write_mmio(struct reg_script_context *ctx)
168{
169 const struct reg_script *step = reg_script_get_step(ctx);
170
171 switch (step->size) {
172 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800173 write8((u8 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700174 break;
175 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800176 write16((u16 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700177 break;
178 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800179 write32((u32 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700180 break;
181 }
182}
183
184static uint32_t reg_script_read_res(struct reg_script_context *ctx)
185{
186 struct resource *res;
187 uint32_t val = 0;
188 const struct reg_script *step = reg_script_get_step(ctx);
189
190 res = reg_script_get_resource(ctx);
191
192 if (res == NULL)
193 return val;
194
195 if (res->flags & IORESOURCE_IO) {
196 const struct reg_script io_step = {
197 .size = step->size,
198 .reg = res->base + step->reg,
199 };
200 reg_script_set_step(ctx, &io_step);
201 val = reg_script_read_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800202 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700203 const struct reg_script mmio_step = {
204 .size = step->size,
205 .reg = res->base + step->reg,
206 };
207 reg_script_set_step(ctx, &mmio_step);
208 val = reg_script_read_mmio(ctx);
209 }
210 reg_script_set_step(ctx, step);
211 return val;
212}
213
214static void reg_script_write_res(struct reg_script_context *ctx)
215{
216 struct resource *res;
217 const struct reg_script *step = reg_script_get_step(ctx);
218
219 res = reg_script_get_resource(ctx);
220
221 if (res == NULL)
222 return;
223
224 if (res->flags & IORESOURCE_IO) {
225 const struct reg_script io_step = {
226 .size = step->size,
227 .reg = res->base + step->reg,
228 .value = step->value,
229 };
230 reg_script_set_step(ctx, &io_step);
231 reg_script_write_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800232 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700233 const struct reg_script mmio_step = {
234 .size = step->size,
235 .reg = res->base + step->reg,
236 .value = step->value,
237 };
238 reg_script_set_step(ctx, &mmio_step);
239 reg_script_write_mmio(ctx);
240 }
241 reg_script_set_step(ctx, step);
242}
243
Werner Zeh9d021532016-02-19 10:02:49 +0100244#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700245static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
246{
Duncan Laurie72748002013-10-31 08:26:23 -0700247 const struct reg_script *step = reg_script_get_step(ctx);
248
249 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800250 case IOSF_PORT_AUNIT:
251 return iosf_aunit_read(step->reg);
252 case IOSF_PORT_CPU_BUS:
253 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700254 case IOSF_PORT_BUNIT:
255 return iosf_bunit_read(step->reg);
256 case IOSF_PORT_DUNIT_CH0:
257 return iosf_dunit_ch0_read(step->reg);
258 case IOSF_PORT_PMC:
259 return iosf_punit_read(step->reg);
260 case IOSF_PORT_USBPHY:
261 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800262 case IOSF_PORT_SEC:
263 return iosf_sec_read(step->reg);
264 case IOSF_PORT_0x45:
265 return iosf_port45_read(step->reg);
266 case IOSF_PORT_0x46:
267 return iosf_port46_read(step->reg);
268 case IOSF_PORT_0x47:
269 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600270 case IOSF_PORT_SCORE:
271 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800272 case IOSF_PORT_0x55:
273 return iosf_port55_read(step->reg);
274 case IOSF_PORT_0x58:
275 return iosf_port58_read(step->reg);
276 case IOSF_PORT_0x59:
277 return iosf_port59_read(step->reg);
278 case IOSF_PORT_0x5a:
279 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700280 case IOSF_PORT_USHPHY:
281 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600282 case IOSF_PORT_SCC:
283 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600284 case IOSF_PORT_LPSS:
285 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800286 case IOSF_PORT_0xa2:
287 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600288 case IOSF_PORT_CCU:
289 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800290 case IOSF_PORT_SSUS:
291 return iosf_ssus_read(step->reg);
292 default:
293 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
294 step->id);
295 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700296 }
Duncan Laurie72748002013-10-31 08:26:23 -0700297 return 0;
298}
299
300static void reg_script_write_iosf(struct reg_script_context *ctx)
301{
Duncan Laurie72748002013-10-31 08:26:23 -0700302 const struct reg_script *step = reg_script_get_step(ctx);
303
304 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800305 case IOSF_PORT_AUNIT:
306 iosf_aunit_write(step->reg, step->value);
307 break;
308 case IOSF_PORT_CPU_BUS:
309 iosf_cpu_bus_write(step->reg, step->value);
310 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700311 case IOSF_PORT_BUNIT:
312 iosf_bunit_write(step->reg, step->value);
313 break;
314 case IOSF_PORT_DUNIT_CH0:
315 iosf_dunit_write(step->reg, step->value);
316 break;
317 case IOSF_PORT_PMC:
318 iosf_punit_write(step->reg, step->value);
319 break;
320 case IOSF_PORT_USBPHY:
321 iosf_usbphy_write(step->reg, step->value);
322 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800323 case IOSF_PORT_SEC:
324 iosf_sec_write(step->reg, step->value);
325 break;
326 case IOSF_PORT_0x45:
327 iosf_port45_write(step->reg, step->value);
328 break;
329 case IOSF_PORT_0x46:
330 iosf_port46_write(step->reg, step->value);
331 break;
332 case IOSF_PORT_0x47:
333 iosf_port47_write(step->reg, step->value);
334 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600335 case IOSF_PORT_SCORE:
336 iosf_score_write(step->reg, step->value);
337 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800338 case IOSF_PORT_0x55:
339 iosf_port55_write(step->reg, step->value);
340 break;
341 case IOSF_PORT_0x58:
342 iosf_port58_write(step->reg, step->value);
343 break;
344 case IOSF_PORT_0x59:
345 iosf_port59_write(step->reg, step->value);
346 break;
347 case IOSF_PORT_0x5a:
348 iosf_port5a_write(step->reg, step->value);
349 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700350 case IOSF_PORT_USHPHY:
351 iosf_ushphy_write(step->reg, step->value);
352 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600353 case IOSF_PORT_SCC:
354 iosf_scc_write(step->reg, step->value);
355 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600356 case IOSF_PORT_LPSS:
357 iosf_lpss_write(step->reg, step->value);
358 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800359 case IOSF_PORT_0xa2:
360 iosf_porta2_write(step->reg, step->value);
361 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600362 case IOSF_PORT_CCU:
363 iosf_ccu_write(step->reg, step->value);
364 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800365 case IOSF_PORT_SSUS:
366 iosf_ssus_write(step->reg, step->value);
367 break;
368 default:
369 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
370 step->id);
371 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700372 }
Duncan Laurie72748002013-10-31 08:26:23 -0700373}
Werner Zeh9d021532016-02-19 10:02:49 +0100374#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700375
Duncan Laurie72748002013-10-31 08:26:23 -0700376
Duncan Lauriefd461e32013-11-08 23:00:24 -0800377static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
378{
Martin Roth1bf55b42017-06-24 14:16:38 -0600379#if IS_ENABLED(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 = rdmsr(step->reg);
382 uint64_t value = msr.hi;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800383 value <<= 32;
384 value |= msr.lo;
385 return value;
386#endif
387}
388
389static void reg_script_write_msr(struct reg_script_context *ctx)
390{
Martin Roth1bf55b42017-06-24 14:16:38 -0600391#if IS_ENABLED(CONFIG_ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -0800392 const struct reg_script *step = reg_script_get_step(ctx);
393 msr_t msr;
394 msr.hi = step->value >> 32;
395 msr.lo = step->value & 0xffffffff;
396 wrmsr(step->reg, msr);
397#endif
398}
399
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700400/* Locate the structure containing the platform specific bus access routines */
401static const struct reg_script_bus_entry
402 *find_bus(const struct reg_script *step)
403{
Lee Leahyefcee9f2016-04-29 17:26:36 -0700404 extern const struct reg_script_bus_entry *_rsbe_init_begin[];
405 extern const struct reg_script_bus_entry *_ersbe_init_begin[];
Lee Leahyb2d834a2017-03-08 16:52:22 -0800406 const struct reg_script_bus_entry * const *bus;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700407 size_t table_entries;
408 size_t i;
409
410 /* Locate the platform specific bus */
Lee Leahyefcee9f2016-04-29 17:26:36 -0700411 bus = _rsbe_init_begin;
412 table_entries = &_ersbe_init_begin[0] - &_rsbe_init_begin[0];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700413 for (i = 0; i < table_entries; i++) {
Lee Leahyefcee9f2016-04-29 17:26:36 -0700414 if (bus[i]->type == step->type)
415 return bus[i];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700416 }
417
418 /* Bus not found */
419 return NULL;
420}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700421
Lee Leahy564dc9c2016-04-29 15:07:19 -0700422static void reg_script_display(struct reg_script_context *ctx,
423 const struct reg_script *step, const char *arrow, uint64_t value)
424{
425 /* Display the register address and data */
426 if (ctx->display_prefix != NULL)
427 printk(BIOS_INFO, "%s: ", ctx->display_prefix);
428 if (ctx->display_features & REG_SCRIPT_DISPLAY_REGISTER)
429 printk(BIOS_INFO, "0x%08x %s ", step->reg, arrow);
430 if (ctx->display_features & REG_SCRIPT_DISPLAY_VALUE)
431 switch (step->size) {
432 case REG_SCRIPT_SIZE_8:
433 printk(BIOS_INFO, "0x%02x\n", (uint8_t)value);
434 break;
435 case REG_SCRIPT_SIZE_16:
436 printk(BIOS_INFO, "0x%04x\n", (int16_t)value);
437 break;
438 case REG_SCRIPT_SIZE_32:
439 printk(BIOS_INFO, "0x%08x\n", (uint32_t)value);
440 break;
441 default:
442 printk(BIOS_INFO, "0x%016llx\n", value);
443 break;
444 }
445}
446
Duncan Lauriefd461e32013-11-08 23:00:24 -0800447static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700448{
449 const struct reg_script *step = reg_script_get_step(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700450 uint64_t value = 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700451
452 switch (step->type) {
453 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700454 ctx->display_prefix = "PCI";
455 value = reg_script_read_pci(ctx);
456 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700457 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700458 ctx->display_prefix = "IO";
459 value = reg_script_read_io(ctx);
460 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700461 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700462 ctx->display_prefix = "MMIO";
463 value = reg_script_read_mmio(ctx);
464 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700465 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700466 ctx->display_prefix = "RES";
467 value = reg_script_read_res(ctx);
468 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800469 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700470 ctx->display_prefix = "MSR";
471 value = reg_script_read_msr(ctx);
472 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100473#if HAS_IOSF
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700474 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700475 ctx->display_prefix = "IOSF";
476 value = reg_script_read_iosf(ctx);
477 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100478#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700479 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700480 {
481 const struct reg_script_bus_entry *bus;
482
483 /* Read from the platform specific bus */
484 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800485 if (bus != NULL) {
Lee Leahy564dc9c2016-04-29 15:07:19 -0700486 value = bus->reg_script_read(ctx);
487 break;
Stefan Reinauerf7dd6d52016-05-04 17:52:56 -0700488 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700489 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700490 printk(BIOS_ERR,
491 "Unsupported read type (0x%x) for this device!\n",
492 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700493 return 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700494 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700495
496 /* Display the register address and data */
497 if (ctx->display_features)
498 reg_script_display(ctx, step, "-->", value);
499 return value;
Duncan Laurie72748002013-10-31 08:26:23 -0700500}
501
502static void reg_script_write(struct reg_script_context *ctx)
503{
504 const struct reg_script *step = reg_script_get_step(ctx);
505
506 switch (step->type) {
507 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700508 ctx->display_prefix = "PCI";
Duncan Laurie72748002013-10-31 08:26:23 -0700509 reg_script_write_pci(ctx);
510 break;
511 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700512 ctx->display_prefix = "IO";
Duncan Laurie72748002013-10-31 08:26:23 -0700513 reg_script_write_io(ctx);
514 break;
515 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700516 ctx->display_prefix = "MMIO";
Duncan Laurie72748002013-10-31 08:26:23 -0700517 reg_script_write_mmio(ctx);
518 break;
519 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700520 ctx->display_prefix = "RES";
Duncan Laurie72748002013-10-31 08:26:23 -0700521 reg_script_write_res(ctx);
522 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700523 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700524 ctx->display_prefix = "MSR";
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700525 reg_script_write_msr(ctx);
526 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100527#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700528 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700529 ctx->display_prefix = "IOSF";
Duncan Laurie72748002013-10-31 08:26:23 -0700530 reg_script_write_iosf(ctx);
531 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100532#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700533 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700534 {
535 const struct reg_script_bus_entry *bus;
536
537 /* Write to the platform specific bus */
538 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800539 if (bus != NULL) {
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700540 bus->reg_script_write(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700541 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700542 }
543 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700544 printk(BIOS_ERR,
545 "Unsupported write type (0x%x) for this device!\n",
546 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700547 return;
Duncan Laurie72748002013-10-31 08:26:23 -0700548 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700549
550 /* Display the register address and data */
551 if (ctx->display_features)
552 reg_script_display(ctx, step, "<--", step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700553}
554
555static void reg_script_rmw(struct reg_script_context *ctx)
556{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800557 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700558 const struct reg_script *step = reg_script_get_step(ctx);
559 struct reg_script write_step = *step;
560
561 value = reg_script_read(ctx);
562 value &= step->mask;
563 value |= step->value;
564 write_step.value = value;
565 reg_script_set_step(ctx, &write_step);
566 reg_script_write(ctx);
567 reg_script_set_step(ctx, step);
568}
569
Lee Leahy6bcbe572016-04-23 07:58:27 -0700570static void reg_script_rxw(struct reg_script_context *ctx)
571{
572 uint64_t value;
573 const struct reg_script *step = reg_script_get_step(ctx);
574 struct reg_script write_step = *step;
575
576/*
577 * XOR logic table
578 * Input XOR Value
579 * 0 0 0
580 * 0 1 1
581 * 1 0 1
582 * 1 1 0
583 *
584 * Supported operations
585 *
586 * Input Mask Temp XOR Value Operation
587 * 0 0 0 0 0 Clear bit
588 * 1 0 0 0 0
589 * 0 0 0 1 1 Set bit
590 * 1 0 0 1 1
591 * 0 1 0 0 0 Preserve bit
592 * 1 1 1 0 1
593 * 0 1 0 1 1 Toggle bit
594 * 1 1 1 1 0
595 */
596 value = reg_script_read(ctx);
597 value &= step->mask;
598 value ^= step->value;
599 write_step.value = value;
600 reg_script_set_step(ctx, &write_step);
601 reg_script_write(ctx);
602 reg_script_set_step(ctx, step);
603}
604
Duncan Laurie72748002013-10-31 08:26:23 -0700605/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
606 * as recursive call with a new context that has the same dev and resource
607 * as the previous one. That will run to completion and then move on to the
608 * next step of the previous context. */
609static void reg_script_run_next(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800610 const struct reg_script *step);
Duncan Laurie72748002013-10-31 08:26:23 -0700611
Duncan Lauriefd461e32013-11-08 23:00:24 -0800612
613static void reg_script_run_step(struct reg_script_context *ctx,
614 const struct reg_script *step)
615{
616 uint64_t value = 0, try;
617
Lee Leahy564dc9c2016-04-29 15:07:19 -0700618 ctx->display_features = ctx->display_state;
619 ctx->display_prefix = NULL;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800620 switch (step->command) {
621 case REG_SCRIPT_COMMAND_READ:
622 (void)reg_script_read(ctx);
623 break;
624 case REG_SCRIPT_COMMAND_WRITE:
625 reg_script_write(ctx);
626 break;
627 case REG_SCRIPT_COMMAND_RMW:
628 reg_script_rmw(ctx);
629 break;
Lee Leahy6bcbe572016-04-23 07:58:27 -0700630 case REG_SCRIPT_COMMAND_RXW:
631 reg_script_rxw(ctx);
632 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800633 case REG_SCRIPT_COMMAND_POLL:
634 for (try = 0; try < step->timeout; try += POLL_DELAY) {
635 value = reg_script_read(ctx) & step->mask;
636 if (value == step->value)
637 break;
638 udelay(POLL_DELAY);
639 }
640 if (try >= step->timeout)
641 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
642 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
643 step->reg, (unsigned long)step->value,
644 (unsigned long)value);
645 break;
646 case REG_SCRIPT_COMMAND_SET_DEV:
647 reg_script_set_dev(ctx, step->dev);
648 break;
649 case REG_SCRIPT_COMMAND_NEXT:
650 reg_script_run_next(ctx, step->next);
651 break;
Lee Leahy564dc9c2016-04-29 15:07:19 -0700652 case REG_SCRIPT_COMMAND_DISPLAY:
653 ctx->display_state = step->value;
654 break;
655
Duncan Lauriefd461e32013-11-08 23:00:24 -0800656 default:
657 printk(BIOS_WARNING, "Invalid command: %08x\n",
658 step->command);
659 break;
660 }
661}
662
Duncan Laurie72748002013-10-31 08:26:23 -0700663static void reg_script_run_with_context(struct reg_script_context *ctx)
664{
Duncan Laurie72748002013-10-31 08:26:23 -0700665 while (1) {
666 const struct reg_script *step = reg_script_get_step(ctx);
667
668 if (step->command == REG_SCRIPT_COMMAND_END)
669 break;
670
Duncan Lauriefd461e32013-11-08 23:00:24 -0800671 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700672 reg_script_set_step(ctx, step + 1);
673 }
674}
675
676static void reg_script_run_next(struct reg_script_context *prev_ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800677 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700678{
679 struct reg_script_context ctx;
680
681 /* Use prev context as a basis but start at a new step. */
682 ctx = *prev_ctx;
683 reg_script_set_step(&ctx, step);
684 reg_script_run_with_context(&ctx);
685}
686
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +0100687#ifdef __SIMPLE_DEVICE__
688void reg_script_run_on_dev(pci_devfn_t dev, const struct reg_script *step)
689#else
690void reg_script_run_on_dev(struct device *dev, const struct reg_script *step)
691#endif
Duncan Laurie72748002013-10-31 08:26:23 -0700692{
693 struct reg_script_context ctx;
694
Lee Leahy564dc9c2016-04-29 15:07:19 -0700695 ctx.display_state = REG_SCRIPT_DISPLAY_NOTHING;
Aaron Durbind86f0b72013-12-10 17:09:40 -0800696 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700697 reg_script_set_step(&ctx, step);
698 reg_script_run_with_context(&ctx);
699}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800700
701void reg_script_run(const struct reg_script *step)
702{
703 reg_script_run_on_dev(EMPTY_DEV, step);
704}