blob: 8d813b6f8dd8cdeda33913dd37849249613f374f [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>
17#include <console/console.h>
18#include <delay.h>
19#include <device/device.h>
20#include <device/resource.h>
21#include <device/pci.h>
22#include <stdint.h>
23#include <reg_script.h>
24
Duncan Lauriefd461e32013-11-08 23:00:24 -080025#if CONFIG_ARCH_X86
26#include <cpu/x86/msr.h>
27#endif
28
Werner Zeh9d021532016-02-19 10:02:49 +010029#define HAS_IOSF (IS_ENABLED(CONFIG_SOC_INTEL_BAYTRAIL) || \
30 IS_ENABLED(CONFIG_SOC_INTEL_FSP_BAYTRAIL))
31
32#if HAS_IOSF
Julius Werner18ea2d32014-10-07 16:42:17 -070033#include <soc/iosf.h> /* TODO: wrap in <soc/reg_script.h, remove #ifdef? */
Duncan Laurie72748002013-10-31 08:26:23 -070034#endif
35
36#define POLL_DELAY 100 /* 100us */
37#if defined(__PRE_RAM__)
38#define EMPTY_DEV 0
39#else
40#define EMPTY_DEV NULL
41#endif
42
Duncan Laurie72748002013-10-31 08:26:23 -070043static inline void reg_script_set_dev(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -080044 device_t dev)
Duncan Laurie72748002013-10-31 08:26:23 -070045{
46 ctx->dev = dev;
47 ctx->res = NULL;
48}
49
50static inline void reg_script_set_step(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -080051 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -070052{
53 ctx->step = step;
54}
55
56static inline const struct reg_script *
57reg_script_get_step(struct reg_script_context *ctx)
58{
59 return ctx->step;
60}
61
62static struct resource *reg_script_get_resource(struct reg_script_context *ctx)
63{
64#if defined(__PRE_RAM__)
65 return NULL;
66#else
67 struct resource *res;
68 const struct reg_script *step = reg_script_get_step(ctx);
69
70 res = ctx->res;
71
72 if (res != NULL && res->index == step->res_index)
73 return res;
74
75 res = find_resource(ctx->dev, step->res_index);
76 ctx->res = res;
77 return res;
78#endif
79}
80
81static uint32_t reg_script_read_pci(struct reg_script_context *ctx)
82{
83 const struct reg_script *step = reg_script_get_step(ctx);
84
85 switch (step->size) {
86 case REG_SCRIPT_SIZE_8:
87 return pci_read_config8(ctx->dev, step->reg);
88 case REG_SCRIPT_SIZE_16:
89 return pci_read_config16(ctx->dev, step->reg);
90 case REG_SCRIPT_SIZE_32:
91 return pci_read_config32(ctx->dev, step->reg);
92 }
93 return 0;
94}
95
96static void reg_script_write_pci(struct reg_script_context *ctx)
97{
98 const struct reg_script *step = reg_script_get_step(ctx);
99
100 switch (step->size) {
101 case REG_SCRIPT_SIZE_8:
102 pci_write_config8(ctx->dev, step->reg, step->value);
103 break;
104 case REG_SCRIPT_SIZE_16:
105 pci_write_config16(ctx->dev, step->reg, step->value);
106 break;
107 case REG_SCRIPT_SIZE_32:
108 pci_write_config32(ctx->dev, step->reg, step->value);
109 break;
110 }
111}
112
113static uint32_t reg_script_read_io(struct reg_script_context *ctx)
114{
115 const struct reg_script *step = reg_script_get_step(ctx);
116
117 switch (step->size) {
118 case REG_SCRIPT_SIZE_8:
119 return inb(step->reg);
120 case REG_SCRIPT_SIZE_16:
121 return inw(step->reg);
122 case REG_SCRIPT_SIZE_32:
123 return inl(step->reg);
124 }
125 return 0;
126}
127
128static void reg_script_write_io(struct reg_script_context *ctx)
129{
130 const struct reg_script *step = reg_script_get_step(ctx);
131
132 switch (step->size) {
133 case REG_SCRIPT_SIZE_8:
134 outb(step->value, step->reg);
135 break;
136 case REG_SCRIPT_SIZE_16:
137 outw(step->value, step->reg);
138 break;
139 case REG_SCRIPT_SIZE_32:
140 outl(step->value, step->reg);
141 break;
142 }
143}
144
145static uint32_t reg_script_read_mmio(struct reg_script_context *ctx)
146{
147 const struct reg_script *step = reg_script_get_step(ctx);
148
149 switch (step->size) {
150 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800151 return read8((u8 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700152 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800153 return read16((u16 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700154 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800155 return read32((u32 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700156 }
157 return 0;
158}
159
160static void reg_script_write_mmio(struct reg_script_context *ctx)
161{
162 const struct reg_script *step = reg_script_get_step(ctx);
163
164 switch (step->size) {
165 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800166 write8((u8 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700167 break;
168 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800169 write16((u16 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700170 break;
171 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800172 write32((u32 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700173 break;
174 }
175}
176
177static uint32_t reg_script_read_res(struct reg_script_context *ctx)
178{
179 struct resource *res;
180 uint32_t val = 0;
181 const struct reg_script *step = reg_script_get_step(ctx);
182
183 res = reg_script_get_resource(ctx);
184
185 if (res == NULL)
186 return val;
187
188 if (res->flags & IORESOURCE_IO) {
189 const struct reg_script io_step = {
190 .size = step->size,
191 .reg = res->base + step->reg,
192 };
193 reg_script_set_step(ctx, &io_step);
194 val = reg_script_read_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800195 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700196 const struct reg_script mmio_step = {
197 .size = step->size,
198 .reg = res->base + step->reg,
199 };
200 reg_script_set_step(ctx, &mmio_step);
201 val = reg_script_read_mmio(ctx);
202 }
203 reg_script_set_step(ctx, step);
204 return val;
205}
206
207static void reg_script_write_res(struct reg_script_context *ctx)
208{
209 struct resource *res;
210 const struct reg_script *step = reg_script_get_step(ctx);
211
212 res = reg_script_get_resource(ctx);
213
214 if (res == NULL)
215 return;
216
217 if (res->flags & IORESOURCE_IO) {
218 const struct reg_script io_step = {
219 .size = step->size,
220 .reg = res->base + step->reg,
221 .value = step->value,
222 };
223 reg_script_set_step(ctx, &io_step);
224 reg_script_write_io(ctx);
Lee Leahy342f8d62017-03-10 15:31:56 -0800225 } else if (res->flags & IORESOURCE_MEM) {
Duncan Laurie72748002013-10-31 08:26:23 -0700226 const struct reg_script mmio_step = {
227 .size = step->size,
228 .reg = res->base + step->reg,
229 .value = step->value,
230 };
231 reg_script_set_step(ctx, &mmio_step);
232 reg_script_write_mmio(ctx);
233 }
234 reg_script_set_step(ctx, step);
235}
236
Werner Zeh9d021532016-02-19 10:02:49 +0100237#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700238static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
239{
Duncan Laurie72748002013-10-31 08:26:23 -0700240 const struct reg_script *step = reg_script_get_step(ctx);
241
242 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800243 case IOSF_PORT_AUNIT:
244 return iosf_aunit_read(step->reg);
245 case IOSF_PORT_CPU_BUS:
246 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700247 case IOSF_PORT_BUNIT:
248 return iosf_bunit_read(step->reg);
249 case IOSF_PORT_DUNIT_CH0:
250 return iosf_dunit_ch0_read(step->reg);
251 case IOSF_PORT_PMC:
252 return iosf_punit_read(step->reg);
253 case IOSF_PORT_USBPHY:
254 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800255 case IOSF_PORT_SEC:
256 return iosf_sec_read(step->reg);
257 case IOSF_PORT_0x45:
258 return iosf_port45_read(step->reg);
259 case IOSF_PORT_0x46:
260 return iosf_port46_read(step->reg);
261 case IOSF_PORT_0x47:
262 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600263 case IOSF_PORT_SCORE:
264 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800265 case IOSF_PORT_0x55:
266 return iosf_port55_read(step->reg);
267 case IOSF_PORT_0x58:
268 return iosf_port58_read(step->reg);
269 case IOSF_PORT_0x59:
270 return iosf_port59_read(step->reg);
271 case IOSF_PORT_0x5a:
272 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700273 case IOSF_PORT_USHPHY:
274 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600275 case IOSF_PORT_SCC:
276 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600277 case IOSF_PORT_LPSS:
278 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800279 case IOSF_PORT_0xa2:
280 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600281 case IOSF_PORT_CCU:
282 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800283 case IOSF_PORT_SSUS:
284 return iosf_ssus_read(step->reg);
285 default:
286 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
287 step->id);
288 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700289 }
Duncan Laurie72748002013-10-31 08:26:23 -0700290 return 0;
291}
292
293static void reg_script_write_iosf(struct reg_script_context *ctx)
294{
Duncan Laurie72748002013-10-31 08:26:23 -0700295 const struct reg_script *step = reg_script_get_step(ctx);
296
297 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800298 case IOSF_PORT_AUNIT:
299 iosf_aunit_write(step->reg, step->value);
300 break;
301 case IOSF_PORT_CPU_BUS:
302 iosf_cpu_bus_write(step->reg, step->value);
303 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700304 case IOSF_PORT_BUNIT:
305 iosf_bunit_write(step->reg, step->value);
306 break;
307 case IOSF_PORT_DUNIT_CH0:
308 iosf_dunit_write(step->reg, step->value);
309 break;
310 case IOSF_PORT_PMC:
311 iosf_punit_write(step->reg, step->value);
312 break;
313 case IOSF_PORT_USBPHY:
314 iosf_usbphy_write(step->reg, step->value);
315 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800316 case IOSF_PORT_SEC:
317 iosf_sec_write(step->reg, step->value);
318 break;
319 case IOSF_PORT_0x45:
320 iosf_port45_write(step->reg, step->value);
321 break;
322 case IOSF_PORT_0x46:
323 iosf_port46_write(step->reg, step->value);
324 break;
325 case IOSF_PORT_0x47:
326 iosf_port47_write(step->reg, step->value);
327 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600328 case IOSF_PORT_SCORE:
329 iosf_score_write(step->reg, step->value);
330 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800331 case IOSF_PORT_0x55:
332 iosf_port55_write(step->reg, step->value);
333 break;
334 case IOSF_PORT_0x58:
335 iosf_port58_write(step->reg, step->value);
336 break;
337 case IOSF_PORT_0x59:
338 iosf_port59_write(step->reg, step->value);
339 break;
340 case IOSF_PORT_0x5a:
341 iosf_port5a_write(step->reg, step->value);
342 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700343 case IOSF_PORT_USHPHY:
344 iosf_ushphy_write(step->reg, step->value);
345 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600346 case IOSF_PORT_SCC:
347 iosf_scc_write(step->reg, step->value);
348 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600349 case IOSF_PORT_LPSS:
350 iosf_lpss_write(step->reg, step->value);
351 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800352 case IOSF_PORT_0xa2:
353 iosf_porta2_write(step->reg, step->value);
354 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600355 case IOSF_PORT_CCU:
356 iosf_ccu_write(step->reg, step->value);
357 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800358 case IOSF_PORT_SSUS:
359 iosf_ssus_write(step->reg, step->value);
360 break;
361 default:
362 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
363 step->id);
364 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700365 }
Duncan Laurie72748002013-10-31 08:26:23 -0700366}
Werner Zeh9d021532016-02-19 10:02:49 +0100367#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700368
Duncan Laurie72748002013-10-31 08:26:23 -0700369
Duncan Lauriefd461e32013-11-08 23:00:24 -0800370static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
371{
372#if CONFIG_ARCH_X86
373 const struct reg_script *step = reg_script_get_step(ctx);
374 msr_t msr = rdmsr(step->reg);
375 uint64_t value = msr.hi;
376 value = msr.hi;
377 value <<= 32;
378 value |= msr.lo;
379 return value;
380#endif
381}
382
383static void reg_script_write_msr(struct reg_script_context *ctx)
384{
385#if CONFIG_ARCH_X86
386 const struct reg_script *step = reg_script_get_step(ctx);
387 msr_t msr;
388 msr.hi = step->value >> 32;
389 msr.lo = step->value & 0xffffffff;
390 wrmsr(step->reg, msr);
391#endif
392}
393
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700394/* Locate the structure containing the platform specific bus access routines */
395static const struct reg_script_bus_entry
396 *find_bus(const struct reg_script *step)
397{
Lee Leahyefcee9f2016-04-29 17:26:36 -0700398 extern const struct reg_script_bus_entry *_rsbe_init_begin[];
399 extern const struct reg_script_bus_entry *_ersbe_init_begin[];
Lee Leahyb2d834a2017-03-08 16:52:22 -0800400 const struct reg_script_bus_entry * const *bus;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700401 size_t table_entries;
402 size_t i;
403
404 /* Locate the platform specific bus */
Lee Leahyefcee9f2016-04-29 17:26:36 -0700405 bus = _rsbe_init_begin;
406 table_entries = &_ersbe_init_begin[0] - &_rsbe_init_begin[0];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700407 for (i = 0; i < table_entries; i++) {
Lee Leahyefcee9f2016-04-29 17:26:36 -0700408 if (bus[i]->type == step->type)
409 return bus[i];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700410 }
411
412 /* Bus not found */
413 return NULL;
414}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700415
Lee Leahy564dc9c2016-04-29 15:07:19 -0700416static void reg_script_display(struct reg_script_context *ctx,
417 const struct reg_script *step, const char *arrow, uint64_t value)
418{
419 /* Display the register address and data */
420 if (ctx->display_prefix != NULL)
421 printk(BIOS_INFO, "%s: ", ctx->display_prefix);
422 if (ctx->display_features & REG_SCRIPT_DISPLAY_REGISTER)
423 printk(BIOS_INFO, "0x%08x %s ", step->reg, arrow);
424 if (ctx->display_features & REG_SCRIPT_DISPLAY_VALUE)
425 switch (step->size) {
426 case REG_SCRIPT_SIZE_8:
427 printk(BIOS_INFO, "0x%02x\n", (uint8_t)value);
428 break;
429 case REG_SCRIPT_SIZE_16:
430 printk(BIOS_INFO, "0x%04x\n", (int16_t)value);
431 break;
432 case REG_SCRIPT_SIZE_32:
433 printk(BIOS_INFO, "0x%08x\n", (uint32_t)value);
434 break;
435 default:
436 printk(BIOS_INFO, "0x%016llx\n", value);
437 break;
438 }
439}
440
Duncan Lauriefd461e32013-11-08 23:00:24 -0800441static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700442{
443 const struct reg_script *step = reg_script_get_step(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700444 uint64_t value = 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700445
446 switch (step->type) {
447 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700448 ctx->display_prefix = "PCI";
449 value = reg_script_read_pci(ctx);
450 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700451 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700452 ctx->display_prefix = "IO";
453 value = reg_script_read_io(ctx);
454 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700455 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700456 ctx->display_prefix = "MMIO";
457 value = reg_script_read_mmio(ctx);
458 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700459 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700460 ctx->display_prefix = "RES";
461 value = reg_script_read_res(ctx);
462 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800463 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700464 ctx->display_prefix = "MSR";
465 value = reg_script_read_msr(ctx);
466 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100467#if HAS_IOSF
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700468 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700469 ctx->display_prefix = "IOSF";
470 value = reg_script_read_iosf(ctx);
471 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100472#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700473 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700474 {
475 const struct reg_script_bus_entry *bus;
476
477 /* Read from the platform specific bus */
478 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800479 if (bus != NULL) {
Lee Leahy564dc9c2016-04-29 15:07:19 -0700480 value = bus->reg_script_read(ctx);
481 break;
Stefan Reinauerf7dd6d52016-05-04 17:52:56 -0700482 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700483 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700484 printk(BIOS_ERR,
485 "Unsupported read type (0x%x) for this device!\n",
486 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700487 return 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700488 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700489
490 /* Display the register address and data */
491 if (ctx->display_features)
492 reg_script_display(ctx, step, "-->", value);
493 return value;
Duncan Laurie72748002013-10-31 08:26:23 -0700494}
495
496static void reg_script_write(struct reg_script_context *ctx)
497{
498 const struct reg_script *step = reg_script_get_step(ctx);
499
500 switch (step->type) {
501 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700502 ctx->display_prefix = "PCI";
Duncan Laurie72748002013-10-31 08:26:23 -0700503 reg_script_write_pci(ctx);
504 break;
505 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700506 ctx->display_prefix = "IO";
Duncan Laurie72748002013-10-31 08:26:23 -0700507 reg_script_write_io(ctx);
508 break;
509 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700510 ctx->display_prefix = "MMIO";
Duncan Laurie72748002013-10-31 08:26:23 -0700511 reg_script_write_mmio(ctx);
512 break;
513 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700514 ctx->display_prefix = "RES";
Duncan Laurie72748002013-10-31 08:26:23 -0700515 reg_script_write_res(ctx);
516 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700517 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700518 ctx->display_prefix = "MSR";
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700519 reg_script_write_msr(ctx);
520 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100521#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700522 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700523 ctx->display_prefix = "IOSF";
Duncan Laurie72748002013-10-31 08:26:23 -0700524 reg_script_write_iosf(ctx);
525 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100526#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700527 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700528 {
529 const struct reg_script_bus_entry *bus;
530
531 /* Write to the platform specific bus */
532 bus = find_bus(step);
Lee Leahy36984d82017-03-10 17:56:44 -0800533 if (bus != NULL) {
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700534 bus->reg_script_write(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700535 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700536 }
537 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700538 printk(BIOS_ERR,
539 "Unsupported write type (0x%x) for this device!\n",
540 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700541 return;
Duncan Laurie72748002013-10-31 08:26:23 -0700542 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700543
544 /* Display the register address and data */
545 if (ctx->display_features)
546 reg_script_display(ctx, step, "<--", step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700547}
548
549static void reg_script_rmw(struct reg_script_context *ctx)
550{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800551 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700552 const struct reg_script *step = reg_script_get_step(ctx);
553 struct reg_script write_step = *step;
554
555 value = reg_script_read(ctx);
556 value &= step->mask;
557 value |= step->value;
558 write_step.value = value;
559 reg_script_set_step(ctx, &write_step);
560 reg_script_write(ctx);
561 reg_script_set_step(ctx, step);
562}
563
Lee Leahy6bcbe572016-04-23 07:58:27 -0700564static void reg_script_rxw(struct reg_script_context *ctx)
565{
566 uint64_t value;
567 const struct reg_script *step = reg_script_get_step(ctx);
568 struct reg_script write_step = *step;
569
570/*
571 * XOR logic table
572 * Input XOR Value
573 * 0 0 0
574 * 0 1 1
575 * 1 0 1
576 * 1 1 0
577 *
578 * Supported operations
579 *
580 * Input Mask Temp XOR Value Operation
581 * 0 0 0 0 0 Clear bit
582 * 1 0 0 0 0
583 * 0 0 0 1 1 Set bit
584 * 1 0 0 1 1
585 * 0 1 0 0 0 Preserve bit
586 * 1 1 1 0 1
587 * 0 1 0 1 1 Toggle bit
588 * 1 1 1 1 0
589 */
590 value = reg_script_read(ctx);
591 value &= step->mask;
592 value ^= step->value;
593 write_step.value = value;
594 reg_script_set_step(ctx, &write_step);
595 reg_script_write(ctx);
596 reg_script_set_step(ctx, step);
597}
598
Duncan Laurie72748002013-10-31 08:26:23 -0700599/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
600 * as recursive call with a new context that has the same dev and resource
601 * as the previous one. That will run to completion and then move on to the
602 * next step of the previous context. */
603static void reg_script_run_next(struct reg_script_context *ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800604 const struct reg_script *step);
Duncan Laurie72748002013-10-31 08:26:23 -0700605
Duncan Lauriefd461e32013-11-08 23:00:24 -0800606
607static void reg_script_run_step(struct reg_script_context *ctx,
608 const struct reg_script *step)
609{
610 uint64_t value = 0, try;
611
Lee Leahy564dc9c2016-04-29 15:07:19 -0700612 ctx->display_features = ctx->display_state;
613 ctx->display_prefix = NULL;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800614 switch (step->command) {
615 case REG_SCRIPT_COMMAND_READ:
616 (void)reg_script_read(ctx);
617 break;
618 case REG_SCRIPT_COMMAND_WRITE:
619 reg_script_write(ctx);
620 break;
621 case REG_SCRIPT_COMMAND_RMW:
622 reg_script_rmw(ctx);
623 break;
Lee Leahy6bcbe572016-04-23 07:58:27 -0700624 case REG_SCRIPT_COMMAND_RXW:
625 reg_script_rxw(ctx);
626 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800627 case REG_SCRIPT_COMMAND_POLL:
628 for (try = 0; try < step->timeout; try += POLL_DELAY) {
629 value = reg_script_read(ctx) & step->mask;
630 if (value == step->value)
631 break;
632 udelay(POLL_DELAY);
633 }
634 if (try >= step->timeout)
635 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
636 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
637 step->reg, (unsigned long)step->value,
638 (unsigned long)value);
639 break;
640 case REG_SCRIPT_COMMAND_SET_DEV:
641 reg_script_set_dev(ctx, step->dev);
642 break;
643 case REG_SCRIPT_COMMAND_NEXT:
644 reg_script_run_next(ctx, step->next);
645 break;
Lee Leahy564dc9c2016-04-29 15:07:19 -0700646 case REG_SCRIPT_COMMAND_DISPLAY:
647 ctx->display_state = step->value;
648 break;
649
Duncan Lauriefd461e32013-11-08 23:00:24 -0800650 default:
651 printk(BIOS_WARNING, "Invalid command: %08x\n",
652 step->command);
653 break;
654 }
655}
656
Duncan Laurie72748002013-10-31 08:26:23 -0700657static void reg_script_run_with_context(struct reg_script_context *ctx)
658{
Duncan Laurie72748002013-10-31 08:26:23 -0700659 while (1) {
660 const struct reg_script *step = reg_script_get_step(ctx);
661
662 if (step->command == REG_SCRIPT_COMMAND_END)
663 break;
664
Duncan Lauriefd461e32013-11-08 23:00:24 -0800665 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700666 reg_script_set_step(ctx, step + 1);
667 }
668}
669
670static void reg_script_run_next(struct reg_script_context *prev_ctx,
Lee Leahye20a3192017-03-09 16:21:34 -0800671 const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700672{
673 struct reg_script_context ctx;
674
675 /* Use prev context as a basis but start at a new step. */
676 ctx = *prev_ctx;
677 reg_script_set_step(&ctx, step);
678 reg_script_run_with_context(&ctx);
679}
680
Aaron Durbind86f0b72013-12-10 17:09:40 -0800681void reg_script_run_on_dev(device_t dev, const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700682{
683 struct reg_script_context ctx;
684
Lee Leahy564dc9c2016-04-29 15:07:19 -0700685 ctx.display_state = REG_SCRIPT_DISPLAY_NOTHING;
Aaron Durbind86f0b72013-12-10 17:09:40 -0800686 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700687 reg_script_set_step(&ctx, step);
688 reg_script_run_with_context(&ctx);
689}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800690
691void reg_script_run(const struct reg_script *step)
692{
693 reg_script_run_on_dev(EMPTY_DEV, step);
694}