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 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 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 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 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 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 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 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 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 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