blob: bd9cdddf1a2c7ec81b2a5dab303b8c69ee8fd9bd [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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <arch/io.h>
21#include <console/console.h>
22#include <delay.h>
23#include <device/device.h>
24#include <device/resource.h>
25#include <device/pci.h>
26#include <stdint.h>
27#include <reg_script.h>
28
Duncan Lauriefd461e32013-11-08 23:00:24 -080029#if CONFIG_ARCH_X86
30#include <cpu/x86/msr.h>
31#endif
32
Duncan Laurie72748002013-10-31 08:26:23 -070033#if CONFIG_SOC_INTEL_BAYTRAIL
Julius Werner18ea2d32014-10-07 16:42:17 -070034#include <soc/iosf.h> /* TODO: wrap in <soc/reg_script.h, remove #ifdef? */
Duncan Laurie72748002013-10-31 08:26:23 -070035#endif
36
37#define POLL_DELAY 100 /* 100us */
38#if defined(__PRE_RAM__)
39#define EMPTY_DEV 0
40#else
41#define EMPTY_DEV NULL
42#endif
43
Duncan Laurie72748002013-10-31 08:26:23 -070044static inline void reg_script_set_dev(struct reg_script_context *ctx,
45 device_t dev)
46{
47 ctx->dev = dev;
48 ctx->res = NULL;
49}
50
51static inline void reg_script_set_step(struct reg_script_context *ctx,
52 const struct reg_script *step)
53{
54 ctx->step = step;
55}
56
57static inline const struct reg_script *
58reg_script_get_step(struct reg_script_context *ctx)
59{
60 return ctx->step;
61}
62
63static struct resource *reg_script_get_resource(struct reg_script_context *ctx)
64{
65#if defined(__PRE_RAM__)
66 return NULL;
67#else
68 struct resource *res;
69 const struct reg_script *step = reg_script_get_step(ctx);
70
71 res = ctx->res;
72
73 if (res != NULL && res->index == step->res_index)
74 return res;
75
76 res = find_resource(ctx->dev, step->res_index);
77 ctx->res = res;
78 return res;
79#endif
80}
81
82static uint32_t reg_script_read_pci(struct reg_script_context *ctx)
83{
84 const struct reg_script *step = reg_script_get_step(ctx);
85
86 switch (step->size) {
87 case REG_SCRIPT_SIZE_8:
88 return pci_read_config8(ctx->dev, step->reg);
89 case REG_SCRIPT_SIZE_16:
90 return pci_read_config16(ctx->dev, step->reg);
91 case REG_SCRIPT_SIZE_32:
92 return pci_read_config32(ctx->dev, step->reg);
93 }
94 return 0;
95}
96
97static void reg_script_write_pci(struct reg_script_context *ctx)
98{
99 const struct reg_script *step = reg_script_get_step(ctx);
100
101 switch (step->size) {
102 case REG_SCRIPT_SIZE_8:
103 pci_write_config8(ctx->dev, step->reg, step->value);
104 break;
105 case REG_SCRIPT_SIZE_16:
106 pci_write_config16(ctx->dev, step->reg, step->value);
107 break;
108 case REG_SCRIPT_SIZE_32:
109 pci_write_config32(ctx->dev, step->reg, step->value);
110 break;
111 }
112}
113
114static uint32_t reg_script_read_io(struct reg_script_context *ctx)
115{
116 const struct reg_script *step = reg_script_get_step(ctx);
117
118 switch (step->size) {
119 case REG_SCRIPT_SIZE_8:
120 return inb(step->reg);
121 case REG_SCRIPT_SIZE_16:
122 return inw(step->reg);
123 case REG_SCRIPT_SIZE_32:
124 return inl(step->reg);
125 }
126 return 0;
127}
128
129static void reg_script_write_io(struct reg_script_context *ctx)
130{
131 const struct reg_script *step = reg_script_get_step(ctx);
132
133 switch (step->size) {
134 case REG_SCRIPT_SIZE_8:
135 outb(step->value, step->reg);
136 break;
137 case REG_SCRIPT_SIZE_16:
138 outw(step->value, step->reg);
139 break;
140 case REG_SCRIPT_SIZE_32:
141 outl(step->value, step->reg);
142 break;
143 }
144}
145
146static uint32_t reg_script_read_mmio(struct reg_script_context *ctx)
147{
148 const struct reg_script *step = reg_script_get_step(ctx);
149
150 switch (step->size) {
151 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800152 return read8((u8 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700153 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800154 return read16((u16 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700155 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800156 return read32((u32 *)step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700157 }
158 return 0;
159}
160
161static void reg_script_write_mmio(struct reg_script_context *ctx)
162{
163 const struct reg_script *step = reg_script_get_step(ctx);
164
165 switch (step->size) {
166 case REG_SCRIPT_SIZE_8:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800167 write8((u8 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700168 break;
169 case REG_SCRIPT_SIZE_16:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800170 write16((u16 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700171 break;
172 case REG_SCRIPT_SIZE_32:
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800173 write32((u32 *)step->reg, step->value);
Duncan Laurie72748002013-10-31 08:26:23 -0700174 break;
175 }
176}
177
178static uint32_t reg_script_read_res(struct reg_script_context *ctx)
179{
180 struct resource *res;
181 uint32_t val = 0;
182 const struct reg_script *step = reg_script_get_step(ctx);
183
184 res = reg_script_get_resource(ctx);
185
186 if (res == NULL)
187 return val;
188
189 if (res->flags & IORESOURCE_IO) {
190 const struct reg_script io_step = {
191 .size = step->size,
192 .reg = res->base + step->reg,
193 };
194 reg_script_set_step(ctx, &io_step);
195 val = reg_script_read_io(ctx);
196 }
197 else if (res->flags & IORESOURCE_MEM) {
198 const struct reg_script mmio_step = {
199 .size = step->size,
200 .reg = res->base + step->reg,
201 };
202 reg_script_set_step(ctx, &mmio_step);
203 val = reg_script_read_mmio(ctx);
204 }
205 reg_script_set_step(ctx, step);
206 return val;
207}
208
209static void reg_script_write_res(struct reg_script_context *ctx)
210{
211 struct resource *res;
212 const struct reg_script *step = reg_script_get_step(ctx);
213
214 res = reg_script_get_resource(ctx);
215
216 if (res == NULL)
217 return;
218
219 if (res->flags & IORESOURCE_IO) {
220 const struct reg_script io_step = {
221 .size = step->size,
222 .reg = res->base + step->reg,
223 .value = step->value,
224 };
225 reg_script_set_step(ctx, &io_step);
226 reg_script_write_io(ctx);
227 }
228 else if (res->flags & IORESOURCE_MEM) {
229 const struct reg_script mmio_step = {
230 .size = step->size,
231 .reg = res->base + step->reg,
232 .value = step->value,
233 };
234 reg_script_set_step(ctx, &mmio_step);
235 reg_script_write_mmio(ctx);
236 }
237 reg_script_set_step(ctx, step);
238}
239
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700240#if CONFIG_SOC_INTEL_BAYTRAIL
Duncan Laurie72748002013-10-31 08:26:23 -0700241static uint32_t reg_script_read_iosf(struct reg_script_context *ctx)
242{
Duncan Laurie72748002013-10-31 08:26:23 -0700243 const struct reg_script *step = reg_script_get_step(ctx);
244
245 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800246 case IOSF_PORT_AUNIT:
247 return iosf_aunit_read(step->reg);
248 case IOSF_PORT_CPU_BUS:
249 return iosf_cpu_bus_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700250 case IOSF_PORT_BUNIT:
251 return iosf_bunit_read(step->reg);
252 case IOSF_PORT_DUNIT_CH0:
253 return iosf_dunit_ch0_read(step->reg);
254 case IOSF_PORT_PMC:
255 return iosf_punit_read(step->reg);
256 case IOSF_PORT_USBPHY:
257 return iosf_usbphy_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800258 case IOSF_PORT_SEC:
259 return iosf_sec_read(step->reg);
260 case IOSF_PORT_0x45:
261 return iosf_port45_read(step->reg);
262 case IOSF_PORT_0x46:
263 return iosf_port46_read(step->reg);
264 case IOSF_PORT_0x47:
265 return iosf_port47_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600266 case IOSF_PORT_SCORE:
267 return iosf_score_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800268 case IOSF_PORT_0x55:
269 return iosf_port55_read(step->reg);
270 case IOSF_PORT_0x58:
271 return iosf_port58_read(step->reg);
272 case IOSF_PORT_0x59:
273 return iosf_port59_read(step->reg);
274 case IOSF_PORT_0x5a:
275 return iosf_port5a_read(step->reg);
Duncan Laurie72748002013-10-31 08:26:23 -0700276 case IOSF_PORT_USHPHY:
277 return iosf_ushphy_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600278 case IOSF_PORT_SCC:
279 return iosf_scc_read(step->reg);
Aaron Durbin64b902b2013-11-12 20:20:10 -0600280 case IOSF_PORT_LPSS:
281 return iosf_lpss_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800282 case IOSF_PORT_0xa2:
283 return iosf_porta2_read(step->reg);
Aaron Durbine8f97d42013-11-12 16:38:54 -0600284 case IOSF_PORT_CCU:
285 return iosf_ccu_read(step->reg);
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800286 case IOSF_PORT_SSUS:
287 return iosf_ssus_read(step->reg);
288 default:
289 printk(BIOS_DEBUG, "No read support for IOSF port 0x%x.\n",
290 step->id);
291 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700292 }
Duncan Laurie72748002013-10-31 08:26:23 -0700293 return 0;
294}
295
296static void reg_script_write_iosf(struct reg_script_context *ctx)
297{
Duncan Laurie72748002013-10-31 08:26:23 -0700298 const struct reg_script *step = reg_script_get_step(ctx);
299
300 switch (step->id) {
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800301 case IOSF_PORT_AUNIT:
302 iosf_aunit_write(step->reg, step->value);
303 break;
304 case IOSF_PORT_CPU_BUS:
305 iosf_cpu_bus_write(step->reg, step->value);
306 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700307 case IOSF_PORT_BUNIT:
308 iosf_bunit_write(step->reg, step->value);
309 break;
310 case IOSF_PORT_DUNIT_CH0:
311 iosf_dunit_write(step->reg, step->value);
312 break;
313 case IOSF_PORT_PMC:
314 iosf_punit_write(step->reg, step->value);
315 break;
316 case IOSF_PORT_USBPHY:
317 iosf_usbphy_write(step->reg, step->value);
318 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800319 case IOSF_PORT_SEC:
320 iosf_sec_write(step->reg, step->value);
321 break;
322 case IOSF_PORT_0x45:
323 iosf_port45_write(step->reg, step->value);
324 break;
325 case IOSF_PORT_0x46:
326 iosf_port46_write(step->reg, step->value);
327 break;
328 case IOSF_PORT_0x47:
329 iosf_port47_write(step->reg, step->value);
330 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600331 case IOSF_PORT_SCORE:
332 iosf_score_write(step->reg, step->value);
333 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800334 case IOSF_PORT_0x55:
335 iosf_port55_write(step->reg, step->value);
336 break;
337 case IOSF_PORT_0x58:
338 iosf_port58_write(step->reg, step->value);
339 break;
340 case IOSF_PORT_0x59:
341 iosf_port59_write(step->reg, step->value);
342 break;
343 case IOSF_PORT_0x5a:
344 iosf_port5a_write(step->reg, step->value);
345 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700346 case IOSF_PORT_USHPHY:
347 iosf_ushphy_write(step->reg, step->value);
348 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600349 case IOSF_PORT_SCC:
350 iosf_scc_write(step->reg, step->value);
351 break;
Aaron Durbin64b902b2013-11-12 20:20:10 -0600352 case IOSF_PORT_LPSS:
353 iosf_lpss_write(step->reg, step->value);
354 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800355 case IOSF_PORT_0xa2:
356 iosf_porta2_write(step->reg, step->value);
357 break;
Aaron Durbine8f97d42013-11-12 16:38:54 -0600358 case IOSF_PORT_CCU:
359 iosf_ccu_write(step->reg, step->value);
360 break;
Aaron Durbinbc5b5572013-12-11 17:13:10 -0800361 case IOSF_PORT_SSUS:
362 iosf_ssus_write(step->reg, step->value);
363 break;
364 default:
365 printk(BIOS_DEBUG, "No write support for IOSF port 0x%x.\n",
366 step->id);
367 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700368 }
Duncan Laurie72748002013-10-31 08:26:23 -0700369}
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700370#endif
371
Duncan Laurie72748002013-10-31 08:26:23 -0700372
Duncan Lauriefd461e32013-11-08 23:00:24 -0800373static uint64_t reg_script_read_msr(struct reg_script_context *ctx)
374{
375#if CONFIG_ARCH_X86
376 const struct reg_script *step = reg_script_get_step(ctx);
377 msr_t msr = rdmsr(step->reg);
378 uint64_t value = msr.hi;
379 value = msr.hi;
380 value <<= 32;
381 value |= msr.lo;
382 return value;
383#endif
384}
385
386static void reg_script_write_msr(struct reg_script_context *ctx)
387{
388#if CONFIG_ARCH_X86
389 const struct reg_script *step = reg_script_get_step(ctx);
390 msr_t msr;
391 msr.hi = step->value >> 32;
392 msr.lo = step->value & 0xffffffff;
393 wrmsr(step->reg, msr);
394#endif
395}
396
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700397#ifndef __PRE_RAM__
398/* Default routine provided for systems without platform specific busses */
399const struct reg_script_bus_entry *__attribute__((weak))
400 platform_bus_table(size_t *table_entries)
401{
402 /* No platform bus type table supplied */
403 *table_entries = 0;
404 return NULL;
405}
406
407/* Locate the structure containing the platform specific bus access routines */
408static const struct reg_script_bus_entry
409 *find_bus(const struct reg_script *step)
410{
411 const struct reg_script_bus_entry *bus;
412 size_t table_entries;
413 size_t i;
414
415 /* Locate the platform specific bus */
416 bus = platform_bus_table(&table_entries);
417 for (i = 0; i < table_entries; i++) {
418 if (bus[i].type == step->type)
419 return &bus[i];
420 }
421
422 /* Bus not found */
423 return NULL;
424}
425#endif
426
Duncan Lauriefd461e32013-11-08 23:00:24 -0800427static uint64_t reg_script_read(struct reg_script_context *ctx)
Duncan Laurie72748002013-10-31 08:26:23 -0700428{
429 const struct reg_script *step = reg_script_get_step(ctx);
430
431 switch (step->type) {
432 case REG_SCRIPT_TYPE_PCI:
433 return reg_script_read_pci(ctx);
434 case REG_SCRIPT_TYPE_IO:
435 return reg_script_read_io(ctx);
436 case REG_SCRIPT_TYPE_MMIO:
437 return reg_script_read_mmio(ctx);
438 case REG_SCRIPT_TYPE_RES:
439 return reg_script_read_res(ctx);
Duncan Lauriefd461e32013-11-08 23:00:24 -0800440 case REG_SCRIPT_TYPE_MSR:
441 return reg_script_read_msr(ctx);
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700442#if CONFIG_SOC_INTEL_BAYTRAIL
443 case REG_SCRIPT_TYPE_IOSF:
444 return reg_script_read_iosf(ctx);
445#endif
446 default:
447#ifndef __PRE_RAM__
448 {
449 const struct reg_script_bus_entry *bus;
450
451 /* Read from the platform specific bus */
452 bus = find_bus(step);
453 if (NULL != bus)
454 return bus->reg_script_read(ctx);
455 }
456#endif
457 printk(BIOS_ERR,
458 "Unsupported read type (0x%x) for this device!\n",
459 step->type);
460 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700461 }
462 return 0;
463}
464
465static void reg_script_write(struct reg_script_context *ctx)
466{
467 const struct reg_script *step = reg_script_get_step(ctx);
468
469 switch (step->type) {
470 case REG_SCRIPT_TYPE_PCI:
471 reg_script_write_pci(ctx);
472 break;
473 case REG_SCRIPT_TYPE_IO:
474 reg_script_write_io(ctx);
475 break;
476 case REG_SCRIPT_TYPE_MMIO:
477 reg_script_write_mmio(ctx);
478 break;
479 case REG_SCRIPT_TYPE_RES:
480 reg_script_write_res(ctx);
481 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700482 case REG_SCRIPT_TYPE_MSR:
483 reg_script_write_msr(ctx);
484 break;
485#if CONFIG_SOC_INTEL_BAYTRAIL
Duncan Laurie72748002013-10-31 08:26:23 -0700486 case REG_SCRIPT_TYPE_IOSF:
487 reg_script_write_iosf(ctx);
488 break;
Lee Leahy9f5a5c52014-08-29 13:38:59 -0700489#endif
490 default:
491#ifndef __PRE_RAM__
492 {
493 const struct reg_script_bus_entry *bus;
494
495 /* Write to the platform specific bus */
496 bus = find_bus(step);
497 if (NULL != bus) {
498 bus->reg_script_write(ctx);
499 return;
500 }
501 }
502#endif
503 printk(BIOS_ERR,
504 "Unsupported write type (0x%x) for this device!\n",
505 step->type);
Duncan Lauriefd461e32013-11-08 23:00:24 -0800506 break;
Duncan Laurie72748002013-10-31 08:26:23 -0700507 }
508}
509
510static void reg_script_rmw(struct reg_script_context *ctx)
511{
Duncan Lauriefd461e32013-11-08 23:00:24 -0800512 uint64_t value;
Duncan Laurie72748002013-10-31 08:26:23 -0700513 const struct reg_script *step = reg_script_get_step(ctx);
514 struct reg_script write_step = *step;
515
516 value = reg_script_read(ctx);
517 value &= step->mask;
518 value |= step->value;
519 write_step.value = value;
520 reg_script_set_step(ctx, &write_step);
521 reg_script_write(ctx);
522 reg_script_set_step(ctx, step);
523}
524
525/* In order to easily chain scripts together handle the REG_SCRIPT_COMMAND_NEXT
526 * as recursive call with a new context that has the same dev and resource
527 * as the previous one. That will run to completion and then move on to the
528 * next step of the previous context. */
529static void reg_script_run_next(struct reg_script_context *ctx,
530 const struct reg_script *step);
531
Duncan Lauriefd461e32013-11-08 23:00:24 -0800532
533static void reg_script_run_step(struct reg_script_context *ctx,
534 const struct reg_script *step)
535{
536 uint64_t value = 0, try;
537
538 switch (step->command) {
539 case REG_SCRIPT_COMMAND_READ:
540 (void)reg_script_read(ctx);
541 break;
542 case REG_SCRIPT_COMMAND_WRITE:
543 reg_script_write(ctx);
544 break;
545 case REG_SCRIPT_COMMAND_RMW:
546 reg_script_rmw(ctx);
547 break;
548 case REG_SCRIPT_COMMAND_POLL:
549 for (try = 0; try < step->timeout; try += POLL_DELAY) {
550 value = reg_script_read(ctx) & step->mask;
551 if (value == step->value)
552 break;
553 udelay(POLL_DELAY);
554 }
555 if (try >= step->timeout)
556 printk(BIOS_WARNING, "%s: POLL timeout waiting for "
557 "0x%x to be 0x%lx, got 0x%lx\n", __func__,
558 step->reg, (unsigned long)step->value,
559 (unsigned long)value);
560 break;
561 case REG_SCRIPT_COMMAND_SET_DEV:
562 reg_script_set_dev(ctx, step->dev);
563 break;
564 case REG_SCRIPT_COMMAND_NEXT:
565 reg_script_run_next(ctx, step->next);
566 break;
567 default:
568 printk(BIOS_WARNING, "Invalid command: %08x\n",
569 step->command);
570 break;
571 }
572}
573
Duncan Laurie72748002013-10-31 08:26:23 -0700574static void reg_script_run_with_context(struct reg_script_context *ctx)
575{
Duncan Laurie72748002013-10-31 08:26:23 -0700576 while (1) {
577 const struct reg_script *step = reg_script_get_step(ctx);
578
579 if (step->command == REG_SCRIPT_COMMAND_END)
580 break;
581
Duncan Lauriefd461e32013-11-08 23:00:24 -0800582 reg_script_run_step(ctx, step);
Duncan Laurie72748002013-10-31 08:26:23 -0700583 reg_script_set_step(ctx, step + 1);
584 }
585}
586
587static void reg_script_run_next(struct reg_script_context *prev_ctx,
588 const struct reg_script *step)
589{
590 struct reg_script_context ctx;
591
592 /* Use prev context as a basis but start at a new step. */
593 ctx = *prev_ctx;
594 reg_script_set_step(&ctx, step);
595 reg_script_run_with_context(&ctx);
596}
597
Aaron Durbind86f0b72013-12-10 17:09:40 -0800598void reg_script_run_on_dev(device_t dev, const struct reg_script *step)
Duncan Laurie72748002013-10-31 08:26:23 -0700599{
600 struct reg_script_context ctx;
601
Aaron Durbind86f0b72013-12-10 17:09:40 -0800602 reg_script_set_dev(&ctx, dev);
Duncan Laurie72748002013-10-31 08:26:23 -0700603 reg_script_set_step(&ctx, step);
604 reg_script_run_with_context(&ctx);
605}
Aaron Durbind86f0b72013-12-10 17:09:40 -0800606
607void reg_script_run(const struct reg_script *step)
608{
609 reg_script_run_on_dev(EMPTY_DEV, step);
610}