blob: 73b781a43bae22cf8b67b639181c553744ffc3c1 [file] [log] [blame]
Angel Pons118a9c72020-04-02 23:48:34 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Duncan Laurie72748002013-10-31 08:26:23 -07002
3#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02004#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02005#include <device/pci_ops.h>
Duncan Laurie72748002013-10-31 08:26:23 -07006#include <console/console.h>
7#include <delay.h>
8#include <device/device.h>
9#include <device/resource.h>
10#include <device/pci.h>
11#include <stdint.h>
12#include <reg_script.h>
13
Julius Wernercd49cce2019-03-05 16:53:33 -080014#if CONFIG(ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -080015#include <cpu/x86/msr.h>
16#endif
17
Arthur Heymansd9802112019-11-19 18:46:44 +010018#define HAS_IOSF (CONFIG(SOC_INTEL_BAYTRAIL))
Werner Zeh9d021532016-02-19 10:02:49 +010019
20#if HAS_IOSF
Julius Werner18ea2d32014-10-07 16:42:17 -070021#include <soc/iosf.h> /* TODO: wrap in <soc/reg_script.h, remove #ifdef? */
Duncan Laurie72748002013-10-31 08:26:23 -070022#endif
23
24#define POLL_DELAY 100 /* 100us */
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030025
26#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070027#define EMPTY_DEV 0
28#else
29#define EMPTY_DEV NULL
30#endif
31
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +010032#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070033static inline void reg_script_set_dev(struct reg_script_context *ctx,
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +010034 pci_devfn_t dev)
35#else
36static inline void reg_script_set_dev(struct reg_script_context *ctx,
37 struct device *dev)
38#endif
Duncan Laurie72748002013-10-31 08:26:23 -070039{
40 ctx->dev = dev;
41 ctx->res = NULL;
42}
43
44static inline void reg_script_set_step(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -080045 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -070046{
47 ctx->step = step;
48}
49
50static inline const struct reg_script *
51reg_script_get_step(struct reg_script_context *ctx)
52{
53 return ctx->step;
54}
55
56static struct resource *reg_script_get_resource(struct reg_script_context *ctx)
57{
Kyösti Mälkkie3acc8f2019-09-13 10:49:20 +030058#ifdef __SIMPLE_DEVICE__
Duncan Laurie72748002013-10-31 08:26:23 -070059 return NULL;
60#else
61 struct resource *res;
62 const struct reg_script *step = reg_script_get_step(ctx);
63
64 res = ctx->res;
65
66 if (res != NULL && res->index == step->res_index)
67 return res;
68
69 res = find_resource(ctx->dev, step->res_index);
70 ctx->res = res;
71 return res;
72#endif
73}
74
75static uint32_t reg_script_read_pci(struct reg_script_context *ctx)
76{
77 const struct reg_script *step = reg_script_get_step(ctx);
78
79 switch (step->size) {
80 case REG_SCRIPT_SIZE_8:
81 return pci_read_config8(ctx->dev, step->reg);
82 case REG_SCRIPT_SIZE_16:
83 return pci_read_config16(ctx->dev, step->reg);
84 case REG_SCRIPT_SIZE_32:
85 return pci_read_config32(ctx->dev, step->reg);
86 }
87 return 0;
88}
89
90static void reg_script_write_pci(struct reg_script_context *ctx)
91{
92 const struct reg_script *step = reg_script_get_step(ctx);
93
94 switch (step->size) {
95 case REG_SCRIPT_SIZE_8:
96 pci_write_config8(ctx->dev, step->reg, step->value);
97 break;
98 case REG_SCRIPT_SIZE_16:
99 pci_write_config16(ctx->dev, step->reg, step->value);
100 break;
101 case REG_SCRIPT_SIZE_32:
102 pci_write_config32(ctx->dev, step->reg, step->value);
103 break;
104 }
105}
106
107static uint32_t reg_script_read_io(struct reg_script_context *ctx)
108{
109 const struct reg_script *step = reg_script_get_step(ctx);
110
111 switch (step->size) {
112 case REG_SCRIPT_SIZE_8:
113 return inb(step->reg);
114 case REG_SCRIPT_SIZE_16:
115 return inw(step->reg);
116 case REG_SCRIPT_SIZE_32:
117 return inl(step->reg);
118 }
119 return 0;
120}
121
122static void reg_script_write_io(struct reg_script_context *ctx)
123{
124 const struct reg_script *step = reg_script_get_step(ctx);
125
126 switch (step->size) {
127 case REG_SCRIPT_SIZE_8:
128 outb(step->value, step->reg);
129 break;
130 case REG_SCRIPT_SIZE_16:
131 outw(step->value, step->reg);
132 break;
133 case REG_SCRIPT_SIZE_32:
134 outl(step->value, step->reg);
135 break;
136 }
137}
138
139static uint32_t reg_script_read_mmio(struct reg_script_context *ctx)
140{
141 const struct reg_script *step = reg_script_get_step(ctx);
142
143 switch (step->size) {
144 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800145 return read8((u8 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700146 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800147 return read16((u16 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700148 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800149 return read32((u32 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700150 }
151 return 0;
152}
153
154static void reg_script_write_mmio(struct reg_script_context *ctx)
155{
156 const struct reg_script *step = reg_script_get_step(ctx);
157
158 switch (step->size) {
159 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800160 write8((u8 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700161 break;
162 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800163 write16((u16 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700164 break;
165 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800166 write32((u32 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700167 break;
168 }
169}
170
171static uint32_t reg_script_read_res(struct reg_script_context *ctx)
172{
173 struct resource *res;
174 uint32_t val = 0;
175 const struct reg_script *step = reg_script_get_step(ctx);
176
177 res = reg_script_get_resource(ctx);
178
179 if (res == NULL)
180 return val;
181
182 if (res->flags & IORESOURCE_IO) {
183 const struct reg_script io_step = {
184 .size = step->size,
185 .reg = res->base + step->reg,
186 };
187 reg_script_set_step(ctx, &io_step);
188 val = reg_script_read_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800189 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700190 const struct reg_script mmio_step = {
191 .size = step->size,
192 .reg = res->base + step->reg,
193 };
194 reg_script_set_step(ctx, &mmio_step);
195 val = reg_script_read_mmio(ctx);
196 }
197 reg_script_set_step(ctx, step);
198 return val;
199}
200
201static void reg_script_write_res(struct reg_script_context *ctx)
202{
203 struct resource *res;
204 const struct reg_script *step = reg_script_get_step(ctx);
205
206 res = reg_script_get_resource(ctx);
207
208 if (res == NULL)
209 return;
210
211 if (res->flags & IORESOURCE_IO) {
212 const struct reg_script io_step = {
213 .size = step->size,
214 .reg = res->base + step->reg,
215 .value = step->value,
216 };
217 reg_script_set_step(ctx, &io_step);
218 reg_script_write_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800219 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700220 const struct reg_script mmio_step = {
221 .size = step->size,
222 .reg = res->base + step->reg,
223 .value = step->value,
224 };
225 reg_script_set_step(ctx, &mmio_step);
226 reg_script_write_mmio(ctx);
227 }
228 reg_script_set_step(ctx, step);
229}
230
Werner Zeh9d021532016-02-19 10:02:49 +0100231#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700232static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
233{
Duncan Laurie72748002013-10-31 08:26:23 -0700234 const struct reg_script *step = reg_script_get_step(ctx);
235
236 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800237 case IOSF_PORT_AUNIT:
238 return iosf_aunit_read(step->reg);
239 case IOSF_PORT_CPU_BUS:
240 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700241 case IOSF_PORT_BUNIT:
242 return iosf_bunit_read(step->reg);
243 case IOSF_PORT_DUNIT_CH0:
244 return iosf_dunit_ch0_read(step->reg);
245 case IOSF_PORT_PMC:
246 return iosf_punit_read(step->reg);
247 case IOSF_PORT_USBPHY:
248 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800249 case IOSF_PORT_SEC:
250 return iosf_sec_read(step->reg);
251 case IOSF_PORT_0x45:
252 return iosf_port45_read(step->reg);
253 case IOSF_PORT_0x46:
254 return iosf_port46_read(step->reg);
255 case IOSF_PORT_0x47:
256 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600257 case IOSF_PORT_SCORE:
258 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800259 case IOSF_PORT_0x55:
260 return iosf_port55_read(step->reg);
261 case IOSF_PORT_0x58:
262 return iosf_port58_read(step->reg);
263 case IOSF_PORT_0x59:
264 return iosf_port59_read(step->reg);
265 case IOSF_PORT_0x5a:
266 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700267 case IOSF_PORT_USHPHY:
268 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600269 case IOSF_PORT_SCC:
270 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600271 case IOSF_PORT_LPSS:
272 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800273 case IOSF_PORT_0xa2:
274 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600275 case IOSF_PORT_CCU:
276 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800277 case IOSF_PORT_SSUS:
278 return iosf_ssus_read(step->reg);
279 default:
280 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
281 step->id);
282 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700283 }
Duncan Laurie72748002013-10-31 08:26:23 -0700284 return 0;
285}
286
287static void reg_script_write_iosf(struct reg_script_context *ctx)
288{
Duncan Laurie72748002013-10-31 08:26:23 -0700289 const struct reg_script *step = reg_script_get_step(ctx);
290
291 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800292 case IOSF_PORT_AUNIT:
293 iosf_aunit_write(step->reg, step->value);
294 break;
295 case IOSF_PORT_CPU_BUS:
296 iosf_cpu_bus_write(step->reg, step->value);
297 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700298 case IOSF_PORT_BUNIT:
299 iosf_bunit_write(step->reg, step->value);
300 break;
301 case IOSF_PORT_DUNIT_CH0:
302 iosf_dunit_write(step->reg, step->value);
303 break;
304 case IOSF_PORT_PMC:
305 iosf_punit_write(step->reg, step->value);
306 break;
307 case IOSF_PORT_USBPHY:
308 iosf_usbphy_write(step->reg, step->value);
309 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800310 case IOSF_PORT_SEC:
311 iosf_sec_write(step->reg, step->value);
312 break;
313 case IOSF_PORT_0x45:
314 iosf_port45_write(step->reg, step->value);
315 break;
316 case IOSF_PORT_0x46:
317 iosf_port46_write(step->reg, step->value);
318 break;
319 case IOSF_PORT_0x47:
320 iosf_port47_write(step->reg, step->value);
321 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600322 case IOSF_PORT_SCORE:
323 iosf_score_write(step->reg, step->value);
324 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800325 case IOSF_PORT_0x55:
326 iosf_port55_write(step->reg, step->value);
327 break;
328 case IOSF_PORT_0x58:
329 iosf_port58_write(step->reg, step->value);
330 break;
331 case IOSF_PORT_0x59:
332 iosf_port59_write(step->reg, step->value);
333 break;
334 case IOSF_PORT_0x5a:
335 iosf_port5a_write(step->reg, step->value);
336 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700337 case IOSF_PORT_USHPHY:
338 iosf_ushphy_write(step->reg, step->value);
339 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600340 case IOSF_PORT_SCC:
341 iosf_scc_write(step->reg, step->value);
342 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600343 case IOSF_PORT_LPSS:
344 iosf_lpss_write(step->reg, step->value);
345 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800346 case IOSF_PORT_0xa2:
347 iosf_porta2_write(step->reg, step->value);
348 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600349 case IOSF_PORT_CCU:
350 iosf_ccu_write(step->reg, step->value);
351 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800352 case IOSF_PORT_SSUS:
353 iosf_ssus_write(step->reg, step->value);
354 break;
355 default:
356 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
357 step->id);
358 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700359 }
Duncan Laurie72748002013-10-31 08:26:23 -0700360}
Werner Zeh9d021532016-02-19 10:02:49 +0100361#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700362
Duncan Laurie72748002013-10-31 08:26:23 -0700363
Duncan Lauriefd461e32013-11-08 23:00:24 -0800364static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
365{
Julius Wernercd49cce2019-03-05 16:53:33 -0800366#if CONFIG(ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -0800367 const struct reg_script *step = reg_script_get_step(ctx);
368 msr_t msr = rdmsr(step->reg);
369 uint64_t value = msr.hi;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800370 value <<= 32;
371 value |= msr.lo;
372 return value;
373#endif
374}
375
376static void reg_script_write_msr(struct reg_script_context *ctx)
377{
Julius Wernercd49cce2019-03-05 16:53:33 -0800378#if CONFIG(ARCH_X86)
Duncan Lauriefd461e32013-11-08 23:00:24 -0800379 const struct reg_script *step = reg_script_get_step(ctx);
380 msr_t msr;
381 msr.hi = step->value >> 32;
382 msr.lo = step->value & 0xffffffff;
383 wrmsr(step->reg, msr);
384#endif
385}
386
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700387/* Locate the structure containing the platform specific bus access routines */
388static const struct reg_script_bus_entry
389 *find_bus(const struct reg_script *step)
390{
Lee Leahyefcee9f2016-04-29 17:26:36 -0700391 extern const struct reg_script_bus_entry *_rsbe_init_begin[];
392 extern const struct reg_script_bus_entry *_ersbe_init_begin[];
Lee Leahyb2d834a2017-03-08 16:52:22 -0800393 const struct reg_script_bus_entry * const *bus;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700394 size_t table_entries;
395 size_t i;
396
397 /* Locate the platform specific bus */
Lee Leahyefcee9f2016-04-29 17:26:36 -0700398 bus = _rsbe_init_begin;
399 table_entries = &_ersbe_init_begin[0] - &_rsbe_init_begin[0];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700400 for (i = 0; i < table_entries; i++) {
Lee Leahyefcee9f2016-04-29 17:26:36 -0700401 if (bus[i]->type == step->type)
402 return bus[i];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700403 }
404
405 /* Bus not found */
406 return NULL;
407}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700408
Lee Leahy564dc9c2016-04-29 15:07:19 -0700409static void reg_script_display(struct reg_script_context *ctx,
410 const struct reg_script *step, const char *arrow, uint64_t value)
411{
412 /* Display the register address and data */
413 if (ctx->display_prefix != NULL)
414 printk(BIOS_INFO, "%s: ", ctx->display_prefix);
415 if (ctx->display_features & REG_SCRIPT_DISPLAY_REGISTER)
416 printk(BIOS_INFO, "0x%08x %s ", step->reg, arrow);
417 if (ctx->display_features & REG_SCRIPT_DISPLAY_VALUE)
418 switch (step->size) {
419 case REG_SCRIPT_SIZE_8:
420 printk(BIOS_INFO, "0x%02x\n", (uint8_t)value);
421 break;
422 case REG_SCRIPT_SIZE_16:
423 printk(BIOS_INFO, "0x%04x\n", (int16_t)value);
424 break;
425 case REG_SCRIPT_SIZE_32:
426 printk(BIOS_INFO, "0x%08x\n", (uint32_t)value);
427 break;
428 default:
429 printk(BIOS_INFO, "0x%016llx\n", value);
430 break;
431 }
432}
433
Duncan Lauriefd461e32013-11-08 23:00:24 -0800434static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700435{
436 const struct reg_script *step = reg_script_get_step(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700437 uint64_t value = 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700438
439 switch (step->type) {
440 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700441 ctx->display_prefix = "PCI";
442 value = reg_script_read_pci(ctx);
443 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700444 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700445 ctx->display_prefix = "IO";
446 value = reg_script_read_io(ctx);
447 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700448 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700449 ctx->display_prefix = "MMIO";
450 value = reg_script_read_mmio(ctx);
451 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700452 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700453 ctx->display_prefix = "RES";
454 value = reg_script_read_res(ctx);
455 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800456 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700457 ctx->display_prefix = "MSR";
458 value = reg_script_read_msr(ctx);
459 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100460#if HAS_IOSF
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700461 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700462 ctx->display_prefix = "IOSF";
463 value = reg_script_read_iosf(ctx);
464 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100465#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700466 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700467 {
468 const struct reg_script_bus_entry *bus;
469
470 /* Read from the platform specific bus */
471 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800472 if (bus != NULL) {
Lee Leahy564dc9c2016-04-29 15:07:19 -0700473 value = bus->reg_script_read(ctx);
474 break;
Stefan Reinauerf7dd6d52016-05-04 17:52:56 -0700475 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700476 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700477 printk(BIOS_ERR,
478 "Unsupported read type (0x%x) for this device!\n",
479 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700480 return 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700481 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700482
483 /* Display the register address and data */
484 if (ctx->display_features)
485 reg_script_display(ctx, step, "-->", value);
486 return value;
Duncan Laurie72748002013-10-31 08:26:23 -0700487}
488
489static void reg_script_write(struct reg_script_context *ctx)
490{
491 const struct reg_script *step = reg_script_get_step(ctx);
492
493 switch (step->type) {
494 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700495 ctx->display_prefix = "PCI";
Duncan Laurie72748002013-10-31 08:26:23 -0700496 reg_script_write_pci(ctx);
497 break;
498 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700499 ctx->display_prefix = "IO";
Duncan Laurie72748002013-10-31 08:26:23 -0700500 reg_script_write_io(ctx);
501 break;
502 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700503 ctx->display_prefix = "MMIO";
Duncan Laurie72748002013-10-31 08:26:23 -0700504 reg_script_write_mmio(ctx);
505 break;
506 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700507 ctx->display_prefix = "RES";
Duncan Laurie72748002013-10-31 08:26:23 -0700508 reg_script_write_res(ctx);
509 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700510 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700511 ctx->display_prefix = "MSR";
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700512 reg_script_write_msr(ctx);
513 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100514#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700515 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700516 ctx->display_prefix = "IOSF";
Duncan Laurie72748002013-10-31 08:26:23 -0700517 reg_script_write_iosf(ctx);
518 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100519#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700520 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700521 {
522 const struct reg_script_bus_entry *bus;
523
524 /* Write to the platform specific bus */
525 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800526 if (bus != NULL) {
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700527 bus->reg_script_write(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700528 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700529 }
530 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700531 printk(BIOS_ERR,
532 "Unsupported write type (0x%x) for this device!\n",
533 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700534 return;
Duncan Laurie72748002013-10-31 08:26:23 -0700535 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700536
537 /* Display the register address and data */
538 if (ctx->display_features)
539 reg_script_display(ctx, step, "<--", step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700540}
541
542static void reg_script_rmw(struct reg_script_context *ctx)
543{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800544 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700545 const struct reg_script *step = reg_script_get_step(ctx);
546 struct reg_script write_step = *step;
547
548 value = reg_script_read(ctx);
549 value &= step->mask;
550 value |= step->value;
551 write_step.value = value;
552 reg_script_set_step(ctx, &write_step);
553 reg_script_write(ctx);
554 reg_script_set_step(ctx, step);
555}
556
Lee Leahy6bcbe572016-04-23 07:58:27 -0700557static void reg_script_rxw(struct reg_script_context *ctx)
558{
559 uint64_t value;
560 const struct reg_script *step = reg_script_get_step(ctx);
561 struct reg_script write_step = *step;
562
563/*
564 * XOR logic table
565 * Input XOR Value
566 * 0 0 0
567 * 0 1 1
568 * 1 0 1
569 * 1 1 0
570 *
571 * Supported operations
572 *
573 * Input Mask Temp XOR Value Operation
574 * 0 0 0 0 0 Clear bit
575 * 1 0 0 0 0
576 * 0 0 0 1 1 Set bit
577 * 1 0 0 1 1
578 * 0 1 0 0 0 Preserve bit
579 * 1 1 1 0 1
580 * 0 1 0 1 1 Toggle bit
581 * 1 1 1 1 0
582 */
583 value = reg_script_read(ctx);
584 value &= step->mask;
585 value ^= step->value;
586 write_step.value = value;
587 reg_script_set_step(ctx, &write_step);
588 reg_script_write(ctx);
589 reg_script_set_step(ctx, step);
590}
591
Duncan Laurie72748002013-10-31 08:26:23 -0700592/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
593 * as recursive call with a new context that has the same dev and resource
594 * as the previous one. That will run to completion and then move on to the
595 * next step of the previous context. */
596static void reg_script_run_next(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800597 const struct reg_script *step);
Duncan Laurie72748002013-10-31 08:26:23 -0700598
Duncan Lauriefd461e32013-11-08 23:00:24 -0800599
600static void reg_script_run_step(struct reg_script_context *ctx,
601 const struct reg_script *step)
602{
603 uint64_t value = 0, try;
604
Lee Leahy564dc9c2016-04-29 15:07:19 -0700605 ctx->display_features = ctx->display_state;
606 ctx->display_prefix = NULL;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800607 switch (step->command) {
608 case REG_SCRIPT_COMMAND_READ:
609 (void)reg_script_read(ctx);
610 break;
611 case REG_SCRIPT_COMMAND_WRITE:
612 reg_script_write(ctx);
613 break;
614 case REG_SCRIPT_COMMAND_RMW:
615 reg_script_rmw(ctx);
616 break;
Lee Leahy6bcbe572016-04-23 07:58:27 -0700617 case REG_SCRIPT_COMMAND_RXW:
618 reg_script_rxw(ctx);
619 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800620 case REG_SCRIPT_COMMAND_POLL:
621 for (try = 0; try < step->timeout; try += POLL_DELAY) {
622 value = reg_script_read(ctx) & step->mask;
623 if (value == step->value)
624 break;
625 udelay(POLL_DELAY);
626 }
627 if (try >= step->timeout)
628 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
629 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
630 step->reg, (unsigned long)step->value,
631 (unsigned long)value);
632 break;
633 case REG_SCRIPT_COMMAND_SET_DEV:
634 reg_script_set_dev(ctx, step->dev);
635 break;
636 case REG_SCRIPT_COMMAND_NEXT:
637 reg_script_run_next(ctx, step->next);
638 break;
Lee Leahy564dc9c2016-04-29 15:07:19 -0700639 case REG_SCRIPT_COMMAND_DISPLAY:
640 ctx->display_state = step->value;
641 break;
642
Duncan Lauriefd461e32013-11-08 23:00:24 -0800643 default:
644 printk(BIOS_WARNING, "Invalid command: %08x\n",
645 step->command);
646 break;
647 }
648}
649
Duncan Laurie72748002013-10-31 08:26:23 -0700650static void reg_script_run_with_context(struct reg_script_context *ctx)
651{
Duncan Laurie72748002013-10-31 08:26:23 -0700652 while (1) {
653 const struct reg_script *step = reg_script_get_step(ctx);
654
655 if (step->command == REG_SCRIPT_COMMAND_END)
656 break;
657
Duncan Lauriefd461e32013-11-08 23:00:24 -0800658 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700659 reg_script_set_step(ctx, step + 1);
660 }
661}
662
663static void reg_script_run_next(struct reg_script_context *prev_ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800664 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700665{
666 struct reg_script_context ctx;
667
668 /* Use prev context as a basis but start at a new step. */
669 ctx = *prev_ctx;
670 reg_script_set_step(&ctx, step);
671 reg_script_run_with_context(&ctx);
672}
673
Elyes HAOUASf9e47cc2018-12-05 11:03:36 +0100674#ifdef __SIMPLE_DEVICE__
675void reg_script_run_on_dev(pci_devfn_t dev, const struct reg_script *step)
676#else
677void reg_script_run_on_dev(struct device *dev, const struct reg_script *step)
678#endif
Duncan Laurie72748002013-10-31 08:26:23 -0700679{
680 struct reg_script_context ctx;
681
Lee Leahy564dc9c2016-04-29 15:07:19 -0700682 ctx.display_state = REG_SCRIPT_DISPLAY_NOTHING;
Aaron Durbind86f0b72013-12-10 17:09:40 -0800683 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700684 reg_script_set_step(&ctx, step);
685 reg_script_run_with_context(&ctx);
686}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800687
688void reg_script_run(const struct reg_script *step)
689{
690 reg_script_run_on_dev(EMPTY_DEV, step);
691}