1 /*
2 * Verify PL031 functionality
3 *
4 * This test verifies whether the emulated PL031 behaves correctly.
5 *
6 * Copyright 2019 Amazon.com, Inc. or its affiliates.
7 * Author: Alexander Graf <graf@amazon.com>
8 *
9 * This work is licensed under the terms of the GNU LGPL, version 2.
10 */
11 #include <libcflat.h>
12 #include <devicetree.h>
13 #include <asm/processor.h>
14 #include <asm/io.h>
15 #include <asm/gic.h>
16
17 struct pl031_regs {
18 uint32_t dr; /* Data Register */
19 uint32_t mr; /* Match Register */
20 uint32_t lr; /* Load Register */
21 union {
22 uint8_t cr; /* Control Register */
23 uint32_t cr32;
24 };
25 union {
26 uint8_t imsc; /* Interrupt Mask Set or Clear register */
27 uint32_t imsc32;
28 };
29 union {
30 uint8_t ris; /* Raw Interrupt Status */
31 uint32_t ris32;
32 };
33 union {
34 uint8_t mis; /* Masked Interrupt Status */
35 uint32_t mis32;
36 };
37 union {
38 uint8_t icr; /* Interrupt Clear Register */
39 uint32_t icr32;
40 };
41 uint32_t reserved[1008];
42 uint32_t periph_id[4];
43 uint32_t pcell_id[4];
44 };
45
46 static u32 cntfrq;
47 static struct pl031_regs *pl031;
48 static int pl031_irq;
49 static void *gic_ispendr;
50 static volatile bool irq_triggered;
51
check_id(void)52 static int check_id(void)
53 {
54 uint32_t id[] = { 0x31, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
55 int i;
56
57 for (i = 0; i < ARRAY_SIZE(id); i++)
58 if (id[i] != readl(&pl031->periph_id[i]))
59 return 1;
60
61 return 0;
62 }
63
check_ro(void)64 static int check_ro(void)
65 {
66 uint32_t offs[] = { offsetof(struct pl031_regs, ris),
67 offsetof(struct pl031_regs, mis),
68 offsetof(struct pl031_regs, periph_id[0]),
69 offsetof(struct pl031_regs, periph_id[1]),
70 offsetof(struct pl031_regs, periph_id[2]),
71 offsetof(struct pl031_regs, periph_id[3]),
72 offsetof(struct pl031_regs, pcell_id[0]),
73 offsetof(struct pl031_regs, pcell_id[1]),
74 offsetof(struct pl031_regs, pcell_id[2]),
75 offsetof(struct pl031_regs, pcell_id[3]) };
76 int i;
77
78 for (i = 0; i < ARRAY_SIZE(offs); i++) {
79 uint32_t before32;
80 uint16_t before16;
81 uint8_t before8;
82 void *addr = (void*)pl031 + offs[i];
83 uint32_t poison = 0xdeadbeefULL;
84
85 before8 = readb(addr);
86 before16 = readw(addr);
87 before32 = readl(addr);
88
89 writeb(poison, addr);
90 writew(poison, addr);
91 writel(poison, addr);
92
93 if (before8 != readb(addr))
94 return 1;
95 if (before16 != readw(addr))
96 return 1;
97 if (before32 != readl(addr))
98 return 1;
99 }
100
101 return 0;
102 }
103
check_rtc_freq(void)104 static int check_rtc_freq(void)
105 {
106 uint32_t seconds_to_wait = 2;
107 uint32_t before = readl(&pl031->dr);
108 uint64_t before_tick = get_cntvct();
109 uint64_t target_tick = before_tick + (cntfrq * seconds_to_wait);
110
111 /* Wait for 2 seconds */
112 while (get_cntvct() < target_tick) ;
113
114 if (readl(&pl031->dr) != before + seconds_to_wait)
115 return 1;
116
117 return 0;
118 }
119
gic_irq_pending(void)120 static bool gic_irq_pending(void)
121 {
122 uint32_t offset = (pl031_irq / 32) * 4;
123
124 return readl(gic_ispendr + offset) & (1 << (pl031_irq & 31));
125 }
126
irq_handler(struct pt_regs * regs)127 static void irq_handler(struct pt_regs *regs)
128 {
129 u32 irqstat = gic_read_iar();
130 u32 irqnr = gic_iar_irqnr(irqstat);
131
132 gic_write_eoir(irqstat);
133
134 if (irqnr == pl031_irq) {
135 report(readl(&pl031->ris) == 1, " RTC RIS == 1");
136 report(readl(&pl031->mis) == 1, " RTC MIS == 1");
137
138 /* Writing one to bit zero should clear IRQ status */
139 writel(1, &pl031->icr);
140
141 report(readl(&pl031->ris) == 0, " RTC RIS == 0");
142 report(readl(&pl031->mis) == 0, " RTC MIS == 0");
143 irq_triggered = true;
144 } else {
145 report_info("Unexpected interrupt: %"PRIu32"\n", irqnr);
146 return;
147 }
148 }
149
check_rtc_irq(void)150 static int check_rtc_irq(void)
151 {
152 uint32_t seconds_to_wait = 1;
153 uint32_t before = readl(&pl031->dr);
154 uint64_t before_tick = get_cntvct();
155 uint64_t target_tick = before_tick + (cntfrq * (seconds_to_wait + 1));
156
157 report_info("Checking IRQ trigger (MR)");
158
159 irq_triggered = false;
160
161 /* Fire IRQ in 1 second */
162 writel(before + seconds_to_wait, &pl031->mr);
163
164 #ifdef __aarch64__
165 install_irq_handler(EL1H_IRQ, irq_handler);
166 #else
167 install_exception_handler(EXCPTN_IRQ, irq_handler);
168 #endif
169
170 /* Wait until 2 seconds are over */
171 while (get_cntvct() < target_tick) ;
172
173 report(!gic_irq_pending(), " RTC IRQ not delivered without mask");
174
175 /* Mask the IRQ so that it gets delivered */
176 writel(1, &pl031->imsc);
177 report(gic_irq_pending(), " RTC IRQ pending now");
178
179 /* Enable retrieval of IRQ */
180 gic_enable_irq(pl031_irq);
181 local_irq_enable();
182
183 report(irq_triggered, " IRQ triggered");
184 report(!gic_irq_pending(), " RTC IRQ not pending anymore");
185 if (!irq_triggered) {
186 report_info(" RTC RIS: %"PRIx32, readl(&pl031->ris));
187 report_info(" RTC MIS: %"PRIx32, readl(&pl031->mis));
188 report_info(" RTC IMSC: %"PRIx32, readl(&pl031->imsc));
189 report_info(" GIC IRQs pending: %08"PRIx32" %08"PRIx32, readl(gic_ispendr), readl(gic_ispendr + 4));
190 }
191
192 local_irq_disable();
193 return 0;
194 }
195
rtc_irq_init(void)196 static void rtc_irq_init(void)
197 {
198 gic_enable_defaults();
199
200 switch (gic_version()) {
201 case 2:
202 gic_ispendr = gicv2_dist_base() + GICD_ISPENDR;
203 break;
204 case 3:
205 gic_ispendr = gicv3_dist_base() + GICD_ISPENDR;
206 break;
207 }
208 }
209
rtc_fdt_init(void)210 static int rtc_fdt_init(void)
211 {
212 const struct fdt_property *prop;
213 const void *fdt = dt_fdt();
214 struct dt_pbus_reg base;
215 int node, len;
216 u32 *data;
217 int ret;
218
219 node = fdt_node_offset_by_compatible(fdt, -1, "arm,pl031");
220 if (node < 0)
221 return -1;
222
223 prop = fdt_get_property(fdt, node, "interrupts", &len);
224 assert(prop && len == (3 * sizeof(u32)));
225 data = (u32 *)prop->data;
226 assert(data[0] == 0); /* SPI */
227 pl031_irq = SPI(fdt32_to_cpu(data[1]));
228
229 ret = dt_pbus_translate_node(node, 0, &base);
230 assert(!ret);
231 pl031 = ioremap(base.addr, base.size);
232
233 return 0;
234 }
235
main(int argc,char ** argv)236 int main(int argc, char **argv)
237 {
238 cntfrq = get_cntfrq();
239 rtc_irq_init();
240 if (rtc_fdt_init()) {
241 report_skip("Skipping PL031 tests. No device present.");
242 return 0;
243 }
244
245 report_prefix_push("pl031");
246 report(!check_id(), "Periph/PCell IDs match");
247 report(!check_ro(), "R/O fields are R/O");
248 report(!check_rtc_freq(), "RTC ticks at 1HZ");
249 report(!gic_irq_pending(), "RTC IRQ not pending yet");
250 check_rtc_irq();
251
252 return report_summary();
253 }
254