blob: bcfb6c5fbe25babb24dbc6c9ce9d2df11f0726dc [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
Duncan Laurie72748002013-10-31 08:26:23 -070029#if CONFIG_SOC_INTEL_BAYTRAIL
Julius Werner18ea2d32014-10-07 16:42:17 -070030#include <soc/iosf.h> /* TODO: wrap in <soc/reg_script.h, remove #ifdef? */
Duncan Laurie72748002013-10-31 08:26:23 -070031#endif
32
33#define POLL_DELAY 100 /* 100us */
34#if defined(__PRE_RAM__)
35#define EMPTY_DEV 0
36#else
37#define EMPTY_DEV NULL
38#endif
39
Duncan Laurie72748002013-10-31 08:26:23 -070040static inline void reg_script_set_dev(struct reg_script_context *ctx,
41 device_t dev)
42{
43 ctx->dev = dev;
44 ctx->res = NULL;
45}
46
47static inline void reg_script_set_step(struct reg_script_context *ctx,
48 const struct reg_script *step)
49{
50 ctx->step = step;
51}
52
53static inline const struct reg_script *
54reg_script_get_step(struct reg_script_context *ctx)
55{
56 return ctx->step;
57}
58
59static struct resource *reg_script_get_resource(struct reg_script_context *ctx)
60{
61#if defined(__PRE_RAM__)
62 return NULL;
63#else
64 struct resource *res;
65 const struct reg_script *step = reg_script_get_step(ctx);
66
67 res = ctx->res;
68
69 if (res != NULL && res->index == step->res_index)
70 return res;
71
72 res = find_resource(ctx->dev, step->res_index);
73 ctx->res = res;
74 return res;
75#endif
76}
77
78static uint32_t reg_script_read_pci(struct reg_script_context *ctx)
79{
80 const struct reg_script *step = reg_script_get_step(ctx);
81
82 switch (step->size) {
83 case REG_SCRIPT_SIZE_8:
84 return pci_read_config8(ctx->dev, step->reg);
85 case REG_SCRIPT_SIZE_16:
86 return pci_read_config16(ctx->dev, step->reg);
87 case REG_SCRIPT_SIZE_32:
88 return pci_read_config32(ctx->dev, step->reg);
89 }
90 return 0;
91}
92
93static void reg_script_write_pci(struct reg_script_context *ctx)
94{
95 const struct reg_script *step = reg_script_get_step(ctx);
96
97 switch (step->size) {
98 case REG_SCRIPT_SIZE_8:
99 pci_write_config8(ctx->dev, step->reg, step->value);
100 break;
101 case REG_SCRIPT_SIZE_16:
102 pci_write_config16(ctx->dev, step->reg, step->value);
103 break;
104 case REG_SCRIPT_SIZE_32:
105 pci_write_config32(ctx->dev, step->reg, step->value);
106 break;
107 }
108}
109
110static uint32_t reg_script_read_io(struct reg_script_context *ctx)
111{
112 const struct reg_script *step = reg_script_get_step(ctx);
113
114 switch (step->size) {
115 case REG_SCRIPT_SIZE_8:
116 return inb(step->reg);
117 case REG_SCRIPT_SIZE_16:
118 return inw(step->reg);
119 case REG_SCRIPT_SIZE_32:
120 return inl(step->reg);
121 }
122 return 0;
123}
124
125static void reg_script_write_io(struct reg_script_context *ctx)
126{
127 const struct reg_script *step = reg_script_get_step(ctx);
128
129 switch (step->size) {
130 case REG_SCRIPT_SIZE_8:
131 outb(step->value, step->reg);
132 break;
133 case REG_SCRIPT_SIZE_16:
134 outw(step->value, step->reg);
135 break;
136 case REG_SCRIPT_SIZE_32:
137 outl(step->value, step->reg);
138 break;
139 }
140}
141
142static uint32_t reg_script_read_mmio(struct reg_script_context *ctx)
143{
144 const struct reg_script *step = reg_script_get_step(ctx);
145
146 switch (step->size) {
147 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800148 return read8((u8 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700149 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800150 return read16((u16 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700151 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800152 return read32((u32 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700153 }
154 return 0;
155}
156
157static void reg_script_write_mmio(struct reg_script_context *ctx)
158{
159 const struct reg_script *step = reg_script_get_step(ctx);
160
161 switch (step->size) {
162 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800163 write8((u8 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700164 break;
165 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800166 write16((u16 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700167 break;
168 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800169 write32((u32 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700170 break;
171 }
172}
173
174static uint32_t reg_script_read_res(struct reg_script_context *ctx)
175{
176 struct resource *res;
177 uint32_t val = 0;
178 const struct reg_script *step = reg_script_get_step(ctx);
179
180 res = reg_script_get_resource(ctx);
181
182 if (res == NULL)
183 return val;
184
185 if (res->flags & IORESOURCE_IO) {
186 const struct reg_script io_step = {
187 .size = step->size,
188 .reg = res->base + step->reg,
189 };
190 reg_script_set_step(ctx, &io_step);
191 val = reg_script_read_io(ctx);
192 }
193 else if (res->flags & IORESOURCE_MEM) {
194 const struct reg_script mmio_step = {
195 .size = step->size,
196 .reg = res->base + step->reg,
197 };
198 reg_script_set_step(ctx, &mmio_step);
199 val = reg_script_read_mmio(ctx);
200 }
201 reg_script_set_step(ctx, step);
202 return val;
203}
204
205static void reg_script_write_res(struct reg_script_context *ctx)
206{
207 struct resource *res;
208 const struct reg_script *step = reg_script_get_step(ctx);
209
210 res = reg_script_get_resource(ctx);
211
212 if (res == NULL)
213 return;
214
215 if (res->flags & IORESOURCE_IO) {
216 const struct reg_script io_step = {
217 .size = step->size,
218 .reg = res->base + step->reg,
219 .value = step->value,
220 };
221 reg_script_set_step(ctx, &io_step);
222 reg_script_write_io(ctx);
223 }
224 else if (res->flags & IORESOURCE_MEM) {
225 const struct reg_script mmio_step = {
226 .size = step->size,
227 .reg = res->base + step->reg,
228 .value = step->value,
229 };
230 reg_script_set_step(ctx, &mmio_step);
231 reg_script_write_mmio(ctx);
232 }
233 reg_script_set_step(ctx, step);
234}
235
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700236#if CONFIG_SOC_INTEL_BAYTRAIL
Duncan Laurie72748002013-10-31 08:26:23 -0700237static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
238{
Duncan Laurie72748002013-10-31 08:26:23 -0700239 const struct reg_script *step = reg_script_get_step(ctx);
240
241 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800242 case IOSF_PORT_AUNIT:
243 return iosf_aunit_read(step->reg);
244 case IOSF_PORT_CPU_BUS:
245 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700246 case IOSF_PORT_BUNIT:
247 return iosf_bunit_read(step->reg);
248 case IOSF_PORT_DUNIT_CH0:
249 return iosf_dunit_ch0_read(step->reg);
250 case IOSF_PORT_PMC:
251 return iosf_punit_read(step->reg);
252 case IOSF_PORT_USBPHY:
253 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800254 case IOSF_PORT_SEC:
255 return iosf_sec_read(step->reg);
256 case IOSF_PORT_0x45:
257 return iosf_port45_read(step->reg);
258 case IOSF_PORT_0x46:
259 return iosf_port46_read(step->reg);
260 case IOSF_PORT_0x47:
261 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600262 case IOSF_PORT_SCORE:
263 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800264 case IOSF_PORT_0x55:
265 return iosf_port55_read(step->reg);
266 case IOSF_PORT_0x58:
267 return iosf_port58_read(step->reg);
268 case IOSF_PORT_0x59:
269 return iosf_port59_read(step->reg);
270 case IOSF_PORT_0x5a:
271 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700272 case IOSF_PORT_USHPHY:
273 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600274 case IOSF_PORT_SCC:
275 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600276 case IOSF_PORT_LPSS:
277 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800278 case IOSF_PORT_0xa2:
279 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600280 case IOSF_PORT_CCU:
281 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800282 case IOSF_PORT_SSUS:
283 return iosf_ssus_read(step->reg);
284 default:
285 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
286 step->id);
287 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700288 }
Duncan Laurie72748002013-10-31 08:26:23 -0700289 return 0;
290}
291
292static void reg_script_write_iosf(struct reg_script_context *ctx)
293{
Duncan Laurie72748002013-10-31 08:26:23 -0700294 const struct reg_script *step = reg_script_get_step(ctx);
295
296 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800297 case IOSF_PORT_AUNIT:
298 iosf_aunit_write(step->reg, step->value);
299 break;
300 case IOSF_PORT_CPU_BUS:
301 iosf_cpu_bus_write(step->reg, step->value);
302 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700303 case IOSF_PORT_BUNIT:
304 iosf_bunit_write(step->reg, step->value);
305 break;
306 case IOSF_PORT_DUNIT_CH0:
307 iosf_dunit_write(step->reg, step->value);
308 break;
309 case IOSF_PORT_PMC:
310 iosf_punit_write(step->reg, step->value);
311 break;
312 case IOSF_PORT_USBPHY:
313 iosf_usbphy_write(step->reg, step->value);
314 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800315 case IOSF_PORT_SEC:
316 iosf_sec_write(step->reg, step->value);
317 break;
318 case IOSF_PORT_0x45:
319 iosf_port45_write(step->reg, step->value);
320 break;
321 case IOSF_PORT_0x46:
322 iosf_port46_write(step->reg, step->value);
323 break;
324 case IOSF_PORT_0x47:
325 iosf_port47_write(step->reg, step->value);
326 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600327 case IOSF_PORT_SCORE:
328 iosf_score_write(step->reg, step->value);
329 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800330 case IOSF_PORT_0x55:
331 iosf_port55_write(step->reg, step->value);
332 break;
333 case IOSF_PORT_0x58:
334 iosf_port58_write(step->reg, step->value);
335 break;
336 case IOSF_PORT_0x59:
337 iosf_port59_write(step->reg, step->value);
338 break;
339 case IOSF_PORT_0x5a:
340 iosf_port5a_write(step->reg, step->value);
341 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700342 case IOSF_PORT_USHPHY:
343 iosf_ushphy_write(step->reg, step->value);
344 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600345 case IOSF_PORT_SCC:
346 iosf_scc_write(step->reg, step->value);
347 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600348 case IOSF_PORT_LPSS:
349 iosf_lpss_write(step->reg, step->value);
350 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800351 case IOSF_PORT_0xa2:
352 iosf_porta2_write(step->reg, step->value);
353 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600354 case IOSF_PORT_CCU:
355 iosf_ccu_write(step->reg, step->value);
356 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800357 case IOSF_PORT_SSUS:
358 iosf_ssus_write(step->reg, step->value);
359 break;
360 default:
361 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
362 step->id);
363 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700364 }
Duncan Laurie72748002013-10-31 08:26:23 -0700365}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700366#endif
367
Duncan Laurie72748002013-10-31 08:26:23 -0700368
Duncan Lauriefd461e32013-11-08 23:00:24 -0800369static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
370{
371#if CONFIG_ARCH_X86
372 const struct reg_script *step = reg_script_get_step(ctx);
373 msr_t msr = rdmsr(step->reg);
374 uint64_t value = msr.hi;
375 value = msr.hi;
376 value <<= 32;
377 value |= msr.lo;
378 return value;
379#endif
380}
381
382static void reg_script_write_msr(struct reg_script_context *ctx)
383{
384#if CONFIG_ARCH_X86
385 const struct reg_script *step = reg_script_get_step(ctx);
386 msr_t msr;
387 msr.hi = step->value >> 32;
388 msr.lo = step->value & 0xffffffff;
389 wrmsr(step->reg, msr);
390#endif
391}
392
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700393#ifndef __PRE_RAM__
394/* Default routine provided for systems without platform specific busses */
395const struct reg_script_bus_entry *__attribute__((weak))
396 platform_bus_table(size_t *table_entries)
397{
398 /* No platform bus type table supplied */
399 *table_entries = 0;
400 return NULL;
401}
402
403/* Locate the structure containing the platform specific bus access routines */
404static const struct reg_script_bus_entry
405 *find_bus(const struct reg_script *step)
406{
407 const struct reg_script_bus_entry *bus;
408 size_t table_entries;
409 size_t i;
410
411 /* Locate the platform specific bus */
412 bus = platform_bus_table(&table_entries);
413 for (i = 0; i < table_entries; i++) {
414 if (bus[i].type == step->type)
415 return &bus[i];
416 }
417
418 /* Bus not found */
419 return NULL;
420}
421#endif
422
Duncan Lauriefd461e32013-11-08 23:00:24 -0800423static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700424{
425 const struct reg_script *step = reg_script_get_step(ctx);
426
427 switch (step->type) {
428 case REG_SCRIPT_TYPE_PCI:
429 return reg_script_read_pci(ctx);
430 case REG_SCRIPT_TYPE_IO:
431 return reg_script_read_io(ctx);
432 case REG_SCRIPT_TYPE_MMIO:
433 return reg_script_read_mmio(ctx);
434 case REG_SCRIPT_TYPE_RES:
435 return reg_script_read_res(ctx);
Duncan Lauriefd461e32013-11-08 23:00:24 -0800436 case REG_SCRIPT_TYPE_MSR:
437 return reg_script_read_msr(ctx);
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700438#if CONFIG_SOC_INTEL_BAYTRAIL
439 case REG_SCRIPT_TYPE_IOSF:
440 return reg_script_read_iosf(ctx);
441#endif
442 default:
443#ifndef __PRE_RAM__
444 {
445 const struct reg_script_bus_entry *bus;
446
447 /* Read from the platform specific bus */
448 bus = find_bus(step);
449 if (NULL != bus)
450 return bus->reg_script_read(ctx);
451 }
452#endif
453 printk(BIOS_ERR,
454 "Unsupported read type (0x%x) for this device!\n",
455 step->type);
456 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700457 }
458 return 0;
459}
460
461static void reg_script_write(struct reg_script_context *ctx)
462{
463 const struct reg_script *step = reg_script_get_step(ctx);
464
465 switch (step->type) {
466 case REG_SCRIPT_TYPE_PCI:
467 reg_script_write_pci(ctx);
468 break;
469 case REG_SCRIPT_TYPE_IO:
470 reg_script_write_io(ctx);
471 break;
472 case REG_SCRIPT_TYPE_MMIO:
473 reg_script_write_mmio(ctx);
474 break;
475 case REG_SCRIPT_TYPE_RES:
476 reg_script_write_res(ctx);
477 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700478 case REG_SCRIPT_TYPE_MSR:
479 reg_script_write_msr(ctx);
480 break;
481#if CONFIG_SOC_INTEL_BAYTRAIL
Duncan Laurie72748002013-10-31 08:26:23 -0700482 case REG_SCRIPT_TYPE_IOSF:
483 reg_script_write_iosf(ctx);
484 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700485#endif
486 default:
487#ifndef __PRE_RAM__
488 {
489 const struct reg_script_bus_entry *bus;
490
491 /* Write to the platform specific bus */
492 bus = find_bus(step);
493 if (NULL != bus) {
494 bus->reg_script_write(ctx);
495 return;
496 }
497 }
498#endif
499 printk(BIOS_ERR,
500 "Unsupported write type (0x%x) for this device!\n",
501 step->type);
Duncan Lauriefd461e32013-11-08 23:00:24 -0800502 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700503 }
504}
505
506static void reg_script_rmw(struct reg_script_context *ctx)
507{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800508 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700509 const struct reg_script *step = reg_script_get_step(ctx);
510 struct reg_script write_step = *step;
511
512 value = reg_script_read(ctx);
513 value &= step->mask;
514 value |= step->value;
515 write_step.value = value;
516 reg_script_set_step(ctx, &write_step);
517 reg_script_write(ctx);
518 reg_script_set_step(ctx, step);
519}
520
521/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
522 * as recursive call with a new context that has the same dev and resource
523 * as the previous one. That will run to completion and then move on to the
524 * next step of the previous context. */
525static void reg_script_run_next(struct reg_script_context *ctx,
526 const struct reg_script *step);
527
Duncan Lauriefd461e32013-11-08 23:00:24 -0800528
529static void reg_script_run_step(struct reg_script_context *ctx,
530 const struct reg_script *step)
531{
532 uint64_t value = 0, try;
533
534 switch (step->command) {
535 case REG_SCRIPT_COMMAND_READ:
536 (void)reg_script_read(ctx);
537 break;
538 case REG_SCRIPT_COMMAND_WRITE:
539 reg_script_write(ctx);
540 break;
541 case REG_SCRIPT_COMMAND_RMW:
542 reg_script_rmw(ctx);
543 break;
544 case REG_SCRIPT_COMMAND_POLL:
545 for (try = 0; try < step->timeout; try += POLL_DELAY) {
546 value = reg_script_read(ctx) & step->mask;
547 if (value == step->value)
548 break;
549 udelay(POLL_DELAY);
550 }
551 if (try >= step->timeout)
552 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
553 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
554 step->reg, (unsigned long)step->value,
555 (unsigned long)value);
556 break;
557 case REG_SCRIPT_COMMAND_SET_DEV:
558 reg_script_set_dev(ctx, step->dev);
559 break;
560 case REG_SCRIPT_COMMAND_NEXT:
561 reg_script_run_next(ctx, step->next);
562 break;
563 default:
564 printk(BIOS_WARNING, "Invalid command: %08x\n",
565 step->command);
566 break;
567 }
568}
569
Duncan Laurie72748002013-10-31 08:26:23 -0700570static void reg_script_run_with_context(struct reg_script_context *ctx)
571{
Duncan Laurie72748002013-10-31 08:26:23 -0700572 while (1) {
573 const struct reg_script *step = reg_script_get_step(ctx);
574
575 if (step->command == REG_SCRIPT_COMMAND_END)
576 break;
577
Duncan Lauriefd461e32013-11-08 23:00:24 -0800578 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700579 reg_script_set_step(ctx, step + 1);
580 }
581}
582
583static void reg_script_run_next(struct reg_script_context *prev_ctx,
584 const struct reg_script *step)
585{
586 struct reg_script_context ctx;
587
588 /* Use prev context as a basis but start at a new step. */
589 ctx = *prev_ctx;
590 reg_script_set_step(&ctx, step);
591 reg_script_run_with_context(&ctx);
592}
593
Aaron Durbind86f0b72013-12-10 17:09:40 -0800594void reg_script_run_on_dev(device_t dev, const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700595{
596 struct reg_script_context ctx;
597
Aaron Durbind86f0b72013-12-10 17:09:40 -0800598 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700599 reg_script_set_step(&ctx, step);
600 reg_script_run_with_context(&ctx);
601}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800602
603void reg_script_run(const struct reg_script *step)
604{
605 reg_script_run_on_dev(EMPTY_DEV, step);
606}