blob: 9c49d6c655ce6f4b6bb8939c89118b4d0a3ccc87 [file] [log] [blame]
Aaron Durbin1318e882016-07-12 23:39:51 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2016 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
Aaron Durbin81d1e092016-07-13 01:49:10 -050016#include <commonlib/helpers.h>
17#include <console/console.h>
Aaron Durbin1318e882016-07-12 23:39:51 -050018#include <stdint.h>
19#include <soc/iosf.h>
20#include <soc/itss.h>
21
22#define IOSF_ITSS_PORT_ID 0xd0
23#define ITSS_MAX_IRQ 119
24#define IPC0 0x3200
25#define IRQS_PER_IPC 32
Aaron Durbin81d1e092016-07-13 01:49:10 -050026#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1)/IRQS_PER_IPC)
Aaron Durbin1318e882016-07-12 23:39:51 -050027
28void itss_set_irq_polarity(int irq, int active_low)
29{
30 uint32_t mask;
31 uint32_t val;
32 uint16_t reg;
33 const uint16_t port = IOSF_ITSS_PORT_ID;
34
35 if (irq < 0 || irq > ITSS_MAX_IRQ)
36 return;
37
38 reg = IPC0 + sizeof(uint32_t) * (irq / IRQS_PER_IPC);
39 mask = 1 << (irq % IRQS_PER_IPC);
40
41 val = iosf_read(port, reg);
42 val &= ~mask;
43 /* Setting the bit makes the IRQ active low. */
44 val |= active_low ? mask : 0;
45 iosf_write(port, reg, val);
46}
Aaron Durbin81d1e092016-07-13 01:49:10 -050047
48static uint32_t irq_snapshot[NUM_IPC_REGS];
49
50void itss_snapshot_irq_polarities(int start, int end)
51{
52 int i;
53 int reg_start;
54 int reg_end;
55 const uint16_t port = IOSF_ITSS_PORT_ID;
56
57 if (start < 0 || start > ITSS_MAX_IRQ ||
58 end < 0 || end > ITSS_MAX_IRQ || end < start)
59 return;
60
61 reg_start = start / IRQS_PER_IPC;
62 reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
63
64 for (i = reg_start; i < reg_end; i++) {
65 uint16_t reg = IPC0 + sizeof(uint32_t) * i;
66 irq_snapshot[i] = iosf_read(port, reg);
67 }
68}
69
70static void show_irq_polarities(const char *msg)
71{
72 int i;
73 const uint16_t port = IOSF_ITSS_PORT_ID;
74
75 printk(BIOS_INFO, "ITSS IRQ Polarities %s:\n", msg);
76 for (i = 0; i < NUM_IPC_REGS; i++) {
77 uint16_t reg = IPC0 + sizeof(uint32_t) * i;
78 printk(BIOS_INFO, "IPC%d: 0x%08x\n", i, iosf_read(port, reg));
79 }
80}
81
82void itss_restore_irq_polarities(int start, int end)
83{
84 int i;
85 int reg_start;
86 int reg_end;
87 const uint16_t port = IOSF_ITSS_PORT_ID;
88
89 if (start < 0 || start > ITSS_MAX_IRQ ||
90 end < 0 || end > ITSS_MAX_IRQ || end < start)
91 return;
92
93 show_irq_polarities("Before");
94
95 reg_start = start / IRQS_PER_IPC;
96 reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
97
98 for (i = reg_start; i < reg_end; i++) {
99 uint32_t mask;
100 uint32_t val;
101 uint16_t reg;
102 int irq_start;
103 int irq_end;
104
105 irq_start = i * IRQS_PER_IPC;
106 irq_end = MIN(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ);
107
108 if (start > irq_end)
109 continue;
110 if (end < irq_start)
111 break;
112
113 /* Track bits within the bounds of of the register. */
114 irq_start = MAX(start, irq_start) % IRQS_PER_IPC;
115 irq_end = MIN(end, irq_end) % IRQS_PER_IPC;
116
117 /* Create bitmask of the inclusive range of start and end. */
118 mask = (((1U << irq_end) - 1) | (1U << irq_end));
119 mask &= ~((1U << irq_start) - 1);
120
121 reg = IPC0 + sizeof(uint32_t) * i;
122 val = iosf_read(port, reg);
123 val &= ~mask;
124 val |= mask & irq_snapshot[i];
125 iosf_write(port, reg, val);
126 }
127
128 show_irq_polarities("After");
129}