blob: b63a05b24859e714cae14f7b1856343969d4041b [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,
44 device_t dev)
45{
46 ctx->dev = dev;
47 ctx->res = NULL;
48}
49
50static inline void reg_script_set_step(struct reg_script_context *ctx,
51 const struct reg_script *step)
52{
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);
195 }
196 else if (res->flags & IORESOURCE_MEM) {
197 const struct reg_script mmio_step = {
198 .size = step->size,
199 .reg = res->base + step->reg,
200 };
201 reg_script_set_step(ctx, &mmio_step);
202 val = reg_script_read_mmio(ctx);
203 }
204 reg_script_set_step(ctx, step);
205 return val;
206}
207
208static void reg_script_write_res(struct reg_script_context *ctx)
209{
210 struct resource *res;
211 const struct reg_script *step = reg_script_get_step(ctx);
212
213 res = reg_script_get_resource(ctx);
214
215 if (res == NULL)
216 return;
217
218 if (res->flags & IORESOURCE_IO) {
219 const struct reg_script io_step = {
220 .size = step->size,
221 .reg = res->base + step->reg,
222 .value = step->value,
223 };
224 reg_script_set_step(ctx, &io_step);
225 reg_script_write_io(ctx);
226 }
227 else if (res->flags & IORESOURCE_MEM) {
228 const struct reg_script mmio_step = {
229 .size = step->size,
230 .reg = res->base + step->reg,
231 .value = step->value,
232 };
233 reg_script_set_step(ctx, &mmio_step);
234 reg_script_write_mmio(ctx);
235 }
236 reg_script_set_step(ctx, step);
237}
238
Werner Zeh9d021532016-02-19 10:02:49 +0100239#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700240static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
241{
Duncan Laurie72748002013-10-31 08:26:23 -0700242 const struct reg_script *step = reg_script_get_step(ctx);
243
244 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800245 case IOSF_PORT_AUNIT:
246 return iosf_aunit_read(step->reg);
247 case IOSF_PORT_CPU_BUS:
248 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700249 case IOSF_PORT_BUNIT:
250 return iosf_bunit_read(step->reg);
251 case IOSF_PORT_DUNIT_CH0:
252 return iosf_dunit_ch0_read(step->reg);
253 case IOSF_PORT_PMC:
254 return iosf_punit_read(step->reg);
255 case IOSF_PORT_USBPHY:
256 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800257 case IOSF_PORT_SEC:
258 return iosf_sec_read(step->reg);
259 case IOSF_PORT_0x45:
260 return iosf_port45_read(step->reg);
261 case IOSF_PORT_0x46:
262 return iosf_port46_read(step->reg);
263 case IOSF_PORT_0x47:
264 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600265 case IOSF_PORT_SCORE:
266 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800267 case IOSF_PORT_0x55:
268 return iosf_port55_read(step->reg);
269 case IOSF_PORT_0x58:
270 return iosf_port58_read(step->reg);
271 case IOSF_PORT_0x59:
272 return iosf_port59_read(step->reg);
273 case IOSF_PORT_0x5a:
274 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700275 case IOSF_PORT_USHPHY:
276 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600277 case IOSF_PORT_SCC:
278 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600279 case IOSF_PORT_LPSS:
280 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800281 case IOSF_PORT_0xa2:
282 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600283 case IOSF_PORT_CCU:
284 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800285 case IOSF_PORT_SSUS:
286 return iosf_ssus_read(step->reg);
287 default:
288 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
289 step->id);
290 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700291 }
Duncan Laurie72748002013-10-31 08:26:23 -0700292 return 0;
293}
294
295static void reg_script_write_iosf(struct reg_script_context *ctx)
296{
Duncan Laurie72748002013-10-31 08:26:23 -0700297 const struct reg_script *step = reg_script_get_step(ctx);
298
299 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800300 case IOSF_PORT_AUNIT:
301 iosf_aunit_write(step->reg, step->value);
302 break;
303 case IOSF_PORT_CPU_BUS:
304 iosf_cpu_bus_write(step->reg, step->value);
305 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700306 case IOSF_PORT_BUNIT:
307 iosf_bunit_write(step->reg, step->value);
308 break;
309 case IOSF_PORT_DUNIT_CH0:
310 iosf_dunit_write(step->reg, step->value);
311 break;
312 case IOSF_PORT_PMC:
313 iosf_punit_write(step->reg, step->value);
314 break;
315 case IOSF_PORT_USBPHY:
316 iosf_usbphy_write(step->reg, step->value);
317 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800318 case IOSF_PORT_SEC:
319 iosf_sec_write(step->reg, step->value);
320 break;
321 case IOSF_PORT_0x45:
322 iosf_port45_write(step->reg, step->value);
323 break;
324 case IOSF_PORT_0x46:
325 iosf_port46_write(step->reg, step->value);
326 break;
327 case IOSF_PORT_0x47:
328 iosf_port47_write(step->reg, step->value);
329 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600330 case IOSF_PORT_SCORE:
331 iosf_score_write(step->reg, step->value);
332 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800333 case IOSF_PORT_0x55:
334 iosf_port55_write(step->reg, step->value);
335 break;
336 case IOSF_PORT_0x58:
337 iosf_port58_write(step->reg, step->value);
338 break;
339 case IOSF_PORT_0x59:
340 iosf_port59_write(step->reg, step->value);
341 break;
342 case IOSF_PORT_0x5a:
343 iosf_port5a_write(step->reg, step->value);
344 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700345 case IOSF_PORT_USHPHY:
346 iosf_ushphy_write(step->reg, step->value);
347 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600348 case IOSF_PORT_SCC:
349 iosf_scc_write(step->reg, step->value);
350 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600351 case IOSF_PORT_LPSS:
352 iosf_lpss_write(step->reg, step->value);
353 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800354 case IOSF_PORT_0xa2:
355 iosf_porta2_write(step->reg, step->value);
356 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600357 case IOSF_PORT_CCU:
358 iosf_ccu_write(step->reg, step->value);
359 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800360 case IOSF_PORT_SSUS:
361 iosf_ssus_write(step->reg, step->value);
362 break;
363 default:
364 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
365 step->id);
366 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700367 }
Duncan Laurie72748002013-10-31 08:26:23 -0700368}
Werner Zeh9d021532016-02-19 10:02:49 +0100369#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700370
Duncan Laurie72748002013-10-31 08:26:23 -0700371
Duncan Lauriefd461e32013-11-08 23:00:24 -0800372static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
373{
374#if CONFIG_ARCH_X86
375 const struct reg_script *step = reg_script_get_step(ctx);
376 msr_t msr = rdmsr(step->reg);
377 uint64_t value = msr.hi;
378 value = msr.hi;
379 value <<= 32;
380 value |= msr.lo;
381 return value;
382#endif
383}
384
385static void reg_script_write_msr(struct reg_script_context *ctx)
386{
387#if CONFIG_ARCH_X86
388 const struct reg_script *step = reg_script_get_step(ctx);
389 msr_t msr;
390 msr.hi = step->value >> 32;
391 msr.lo = step->value & 0xffffffff;
392 wrmsr(step->reg, msr);
393#endif
394}
395
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700396/* Locate the structure containing the platform specific bus access routines */
397static const struct reg_script_bus_entry
398 *find_bus(const struct reg_script *step)
399{
Lee Leahyefcee9f2016-04-29 17:26:36 -0700400 extern const struct reg_script_bus_entry *_rsbe_init_begin[];
401 extern const struct reg_script_bus_entry *_ersbe_init_begin[];
Lee Leahyb2d834a2017-03-08 16:52:22 -0800402 const struct reg_script_bus_entry * const *bus;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700403 size_t table_entries;
404 size_t i;
405
406 /* Locate the platform specific bus */
Lee Leahyefcee9f2016-04-29 17:26:36 -0700407 bus = _rsbe_init_begin;
408 table_entries = &_ersbe_init_begin[0] - &_rsbe_init_begin[0];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700409 for (i = 0; i < table_entries; i++) {
Lee Leahyefcee9f2016-04-29 17:26:36 -0700410 if (bus[i]->type == step->type)
411 return bus[i];
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700412 }
413
414 /* Bus not found */
415 return NULL;
416}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700417
Lee Leahy564dc9c2016-04-29 15:07:19 -0700418static void reg_script_display(struct reg_script_context *ctx,
419 const struct reg_script *step, const char *arrow, uint64_t value)
420{
421 /* Display the register address and data */
422 if (ctx->display_prefix != NULL)
423 printk(BIOS_INFO, "%s: ", ctx->display_prefix);
424 if (ctx->display_features & REG_SCRIPT_DISPLAY_REGISTER)
425 printk(BIOS_INFO, "0x%08x %s ", step->reg, arrow);
426 if (ctx->display_features & REG_SCRIPT_DISPLAY_VALUE)
427 switch (step->size) {
428 case REG_SCRIPT_SIZE_8:
429 printk(BIOS_INFO, "0x%02x\n", (uint8_t)value);
430 break;
431 case REG_SCRIPT_SIZE_16:
432 printk(BIOS_INFO, "0x%04x\n", (int16_t)value);
433 break;
434 case REG_SCRIPT_SIZE_32:
435 printk(BIOS_INFO, "0x%08x\n", (uint32_t)value);
436 break;
437 default:
438 printk(BIOS_INFO, "0x%016llx\n", value);
439 break;
440 }
441}
442
Duncan Lauriefd461e32013-11-08 23:00:24 -0800443static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700444{
445 const struct reg_script *step = reg_script_get_step(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700446 uint64_t value = 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700447
448 switch (step->type) {
449 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700450 ctx->display_prefix = "PCI";
451 value = reg_script_read_pci(ctx);
452 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700453 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700454 ctx->display_prefix = "IO";
455 value = reg_script_read_io(ctx);
456 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700457 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700458 ctx->display_prefix = "MMIO";
459 value = reg_script_read_mmio(ctx);
460 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700461 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700462 ctx->display_prefix = "RES";
463 value = reg_script_read_res(ctx);
464 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800465 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700466 ctx->display_prefix = "MSR";
467 value = reg_script_read_msr(ctx);
468 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100469#if HAS_IOSF
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700470 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700471 ctx->display_prefix = "IOSF";
472 value = reg_script_read_iosf(ctx);
473 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100474#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700475 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700476 {
477 const struct reg_script_bus_entry *bus;
478
479 /* Read from the platform specific bus */
480 bus = find_bus(step);
Stefan Reinauerf7dd6d52016-05-04 17:52:56 -0700481 if (NULL != bus) {
Lee Leahy564dc9c2016-04-29 15:07:19 -0700482 value = bus->reg_script_read(ctx);
483 break;
Stefan Reinauerf7dd6d52016-05-04 17:52:56 -0700484 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700485 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700486 printk(BIOS_ERR,
487 "Unsupported read type (0x%x) for this device!\n",
488 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700489 return 0;
Duncan Laurie72748002013-10-31 08:26:23 -0700490 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700491
492 /* Display the register address and data */
493 if (ctx->display_features)
494 reg_script_display(ctx, step, "-->", value);
495 return value;
Duncan Laurie72748002013-10-31 08:26:23 -0700496}
497
498static void reg_script_write(struct reg_script_context *ctx)
499{
500 const struct reg_script *step = reg_script_get_step(ctx);
501
502 switch (step->type) {
503 case REG_SCRIPT_TYPE_PCI:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700504 ctx->display_prefix = "PCI";
Duncan Laurie72748002013-10-31 08:26:23 -0700505 reg_script_write_pci(ctx);
506 break;
507 case REG_SCRIPT_TYPE_IO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700508 ctx->display_prefix = "IO";
Duncan Laurie72748002013-10-31 08:26:23 -0700509 reg_script_write_io(ctx);
510 break;
511 case REG_SCRIPT_TYPE_MMIO:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700512 ctx->display_prefix = "MMIO";
Duncan Laurie72748002013-10-31 08:26:23 -0700513 reg_script_write_mmio(ctx);
514 break;
515 case REG_SCRIPT_TYPE_RES:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700516 ctx->display_prefix = "RES";
Duncan Laurie72748002013-10-31 08:26:23 -0700517 reg_script_write_res(ctx);
518 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700519 case REG_SCRIPT_TYPE_MSR:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700520 ctx->display_prefix = "MSR";
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700521 reg_script_write_msr(ctx);
522 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100523#if HAS_IOSF
Duncan Laurie72748002013-10-31 08:26:23 -0700524 case REG_SCRIPT_TYPE_IOSF:
Lee Leahy564dc9c2016-04-29 15:07:19 -0700525 ctx->display_prefix = "IOSF";
Duncan Laurie72748002013-10-31 08:26:23 -0700526 reg_script_write_iosf(ctx);
527 break;
Werner Zeh9d021532016-02-19 10:02:49 +0100528#endif /* HAS_IOSF */
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700529 default:
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700530 {
531 const struct reg_script_bus_entry *bus;
532
533 /* Write to the platform specific bus */
534 bus = find_bus(step);
535 if (NULL != bus) {
536 bus->reg_script_write(ctx);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700537 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700538 }
539 }
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700540 printk(BIOS_ERR,
541 "Unsupported write type (0x%x) for this device!\n",
542 step->type);
Lee Leahy564dc9c2016-04-29 15:07:19 -0700543 return;
Duncan Laurie72748002013-10-31 08:26:23 -0700544 }
Lee Leahy564dc9c2016-04-29 15:07:19 -0700545
546 /* Display the register address and data */
547 if (ctx->display_features)
548 reg_script_display(ctx, step, "<--", step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700549}
550
551static void reg_script_rmw(struct reg_script_context *ctx)
552{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800553 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700554 const struct reg_script *step = reg_script_get_step(ctx);
555 struct reg_script write_step = *step;
556
557 value = reg_script_read(ctx);
558 value &= step->mask;
559 value |= step->value;
560 write_step.value = value;
561 reg_script_set_step(ctx, &write_step);
562 reg_script_write(ctx);
563 reg_script_set_step(ctx, step);
564}
565
Lee Leahy6bcbe572016-04-23 07:58:27 -0700566static void reg_script_rxw(struct reg_script_context *ctx)
567{
568 uint64_t value;
569 const struct reg_script *step = reg_script_get_step(ctx);
570 struct reg_script write_step = *step;
571
572/*
573 * XOR logic table
574 * Input XOR Value
575 * 0 0 0
576 * 0 1 1
577 * 1 0 1
578 * 1 1 0
579 *
580 * Supported operations
581 *
582 * Input Mask Temp XOR Value Operation
583 * 0 0 0 0 0 Clear bit
584 * 1 0 0 0 0
585 * 0 0 0 1 1 Set bit
586 * 1 0 0 1 1
587 * 0 1 0 0 0 Preserve bit
588 * 1 1 1 0 1
589 * 0 1 0 1 1 Toggle bit
590 * 1 1 1 1 0
591 */
592 value = reg_script_read(ctx);
593 value &= step->mask;
594 value ^= step->value;
595 write_step.value = value;
596 reg_script_set_step(ctx, &write_step);
597 reg_script_write(ctx);
598 reg_script_set_step(ctx, step);
599}
600
Duncan Laurie72748002013-10-31 08:26:23 -0700601/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
602 * as recursive call with a new context that has the same dev and resource
603 * as the previous one. That will run to completion and then move on to the
604 * next step of the previous context. */
605static void reg_script_run_next(struct reg_script_context *ctx,
606 const struct reg_script *step);
607
Duncan Lauriefd461e32013-11-08 23:00:24 -0800608
609static void reg_script_run_step(struct reg_script_context *ctx,
610 const struct reg_script *step)
611{
612 uint64_t value = 0, try;
613
Lee Leahy564dc9c2016-04-29 15:07:19 -0700614 ctx->display_features = ctx->display_state;
615 ctx->display_prefix = NULL;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800616 switch (step->command) {
617 case REG_SCRIPT_COMMAND_READ:
618 (void)reg_script_read(ctx);
619 break;
620 case REG_SCRIPT_COMMAND_WRITE:
621 reg_script_write(ctx);
622 break;
623 case REG_SCRIPT_COMMAND_RMW:
624 reg_script_rmw(ctx);
625 break;
Lee Leahy6bcbe572016-04-23 07:58:27 -0700626 case REG_SCRIPT_COMMAND_RXW:
627 reg_script_rxw(ctx);
628 break;
Duncan Lauriefd461e32013-11-08 23:00:24 -0800629 case REG_SCRIPT_COMMAND_POLL:
630 for (try = 0; try < step->timeout; try += POLL_DELAY) {
631 value = reg_script_read(ctx) & step->mask;
632 if (value == step->value)
633 break;
634 udelay(POLL_DELAY);
635 }
636 if (try >= step->timeout)
637 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
638 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
639 step->reg, (unsigned long)step->value,
640 (unsigned long)value);
641 break;
642 case REG_SCRIPT_COMMAND_SET_DEV:
643 reg_script_set_dev(ctx, step->dev);
644 break;
645 case REG_SCRIPT_COMMAND_NEXT:
646 reg_script_run_next(ctx, step->next);
647 break;
Lee Leahy564dc9c2016-04-29 15:07:19 -0700648 case REG_SCRIPT_COMMAND_DISPLAY:
649 ctx->display_state = step->value;
650 break;
651
Duncan Lauriefd461e32013-11-08 23:00:24 -0800652 default:
653 printk(BIOS_WARNING, "Invalid command: %08x\n",
654 step->command);
655 break;
656 }
657}
658
Duncan Laurie72748002013-10-31 08:26:23 -0700659static void reg_script_run_with_context(struct reg_script_context *ctx)
660{
Duncan Laurie72748002013-10-31 08:26:23 -0700661 while (1) {
662 const struct reg_script *step = reg_script_get_step(ctx);
663
664 if (step->command == REG_SCRIPT_COMMAND_END)
665 break;
666
Duncan Lauriefd461e32013-11-08 23:00:24 -0800667 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700668 reg_script_set_step(ctx, step + 1);
669 }
670}
671
672static void reg_script_run_next(struct reg_script_context *prev_ctx,
673 const struct reg_script *step)
674{
675 struct reg_script_context ctx;
676
677 /* Use prev context as a basis but start at a new step. */
678 ctx = *prev_ctx;
679 reg_script_set_step(&ctx, step);
680 reg_script_run_with_context(&ctx);
681}
682
Aaron Durbind86f0b72013-12-10 17:09:40 -0800683void reg_script_run_on_dev(device_t dev, const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700684{
685 struct reg_script_context ctx;
686
Lee Leahy564dc9c2016-04-29 15:07:19 -0700687 ctx.display_state = REG_SCRIPT_DISPLAY_NOTHING;
Aaron Durbind86f0b72013-12-10 17:09:40 -0800688 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700689 reg_script_set_step(&ctx, step);
690 reg_script_run_with_context(&ctx);
691}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800692
693void reg_script_run(const struct reg_script *step)
694{
695 reg_script_run_on_dev(EMPTY_DEV, step);
696}