qemu/tests/qtest/npcm7xx_gpio-test.c
<<
>>
Prefs
   1/*
   2 * QTest testcase for the Nuvoton NPCM7xx GPIO modules.
   3 *
   4 * Copyright 2020 Google LLC
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the
   8 * Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14 * for more details.
  15 */
  16
  17#include "qemu/osdep.h"
  18#include "libqtest-single.h"
  19
  20#define NR_GPIO_DEVICES (8)
  21#define GPIO(x)         (0xf0010000 + (x) * 0x1000)
  22#define GPIO_IRQ(x)     (116 + (x))
  23
  24/* GPIO registers */
  25#define GP_N_TLOCK1     0x00
  26#define GP_N_DIN        0x04 /* Data IN */
  27#define GP_N_POL        0x08 /* Polarity */
  28#define GP_N_DOUT       0x0c /* Data OUT */
  29#define GP_N_OE         0x10 /* Output Enable */
  30#define GP_N_OTYP       0x14
  31#define GP_N_MP         0x18
  32#define GP_N_PU         0x1c /* Pull-up */
  33#define GP_N_PD         0x20 /* Pull-down */
  34#define GP_N_DBNC       0x24 /* Debounce */
  35#define GP_N_EVTYP      0x28 /* Event Type */
  36#define GP_N_EVBE       0x2c /* Event Both Edge */
  37#define GP_N_OBL0       0x30
  38#define GP_N_OBL1       0x34
  39#define GP_N_OBL2       0x38
  40#define GP_N_OBL3       0x3c
  41#define GP_N_EVEN       0x40 /* Event Enable */
  42#define GP_N_EVENS      0x44 /* Event Set (enable) */
  43#define GP_N_EVENC      0x48 /* Event Clear (disable) */
  44#define GP_N_EVST       0x4c /* Event Status */
  45#define GP_N_SPLCK      0x50
  46#define GP_N_MPLCK      0x54
  47#define GP_N_IEM        0x58 /* Input Enable */
  48#define GP_N_OSRC       0x5c
  49#define GP_N_ODSC       0x60
  50#define GP_N_DOS        0x68 /* Data OUT Set */
  51#define GP_N_DOC        0x6c /* Data OUT Clear */
  52#define GP_N_OES        0x70 /* Output Enable Set */
  53#define GP_N_OEC        0x74 /* Output Enable Clear */
  54#define GP_N_TLOCK2     0x7c
  55
  56static void gpio_unlock(int n)
  57{
  58    if (readl(GPIO(n) + GP_N_TLOCK1) != 0) {
  59        writel(GPIO(n) + GP_N_TLOCK2, 0xc0de1248);
  60        writel(GPIO(n) + GP_N_TLOCK1, 0xc0defa73);
  61    }
  62}
  63
  64/* Restore the GPIO controller to a sensible default state. */
  65static void gpio_reset(int n)
  66{
  67    gpio_unlock(0);
  68
  69    writel(GPIO(n) + GP_N_EVEN, 0x00000000);
  70    writel(GPIO(n) + GP_N_EVST, 0xffffffff);
  71    writel(GPIO(n) + GP_N_POL, 0x00000000);
  72    writel(GPIO(n) + GP_N_DOUT, 0x00000000);
  73    writel(GPIO(n) + GP_N_OE, 0x00000000);
  74    writel(GPIO(n) + GP_N_OTYP, 0x00000000);
  75    writel(GPIO(n) + GP_N_PU, 0xffffffff);
  76    writel(GPIO(n) + GP_N_PD, 0x00000000);
  77    writel(GPIO(n) + GP_N_IEM, 0xffffffff);
  78}
  79
  80static void test_dout_to_din(void)
  81{
  82    gpio_reset(0);
  83
  84    /* When output is enabled, DOUT should be reflected on DIN. */
  85    writel(GPIO(0) + GP_N_OE, 0xffffffff);
  86    /* PU and PD shouldn't have any impact on DIN. */
  87    writel(GPIO(0) + GP_N_PU, 0xffff0000);
  88    writel(GPIO(0) + GP_N_PD, 0x0000ffff);
  89    writel(GPIO(0) + GP_N_DOUT, 0x12345678);
  90    g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x12345678);
  91    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x12345678);
  92}
  93
  94static void test_pullup_pulldown(void)
  95{
  96    gpio_reset(0);
  97
  98    /*
  99     * When output is disabled, and PD is the inverse of PU, PU should be
 100     * reflected on DIN. If PD is not the inverse of PU, the state of DIN is
 101     * undefined, so we don't test that.
 102     */
 103    writel(GPIO(0) + GP_N_OE, 0x00000000);
 104    /* DOUT shouldn't have any impact on DIN. */
 105    writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
 106    writel(GPIO(0) + GP_N_PU, 0x23456789);
 107    writel(GPIO(0) + GP_N_PD, ~0x23456789U);
 108    g_assert_cmphex(readl(GPIO(0) + GP_N_PU), ==, 0x23456789);
 109    g_assert_cmphex(readl(GPIO(0) + GP_N_PD), ==, ~0x23456789U);
 110    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x23456789);
 111}
 112
 113static void test_output_enable(void)
 114{
 115    gpio_reset(0);
 116
 117    /*
 118     * With all pins weakly pulled down, and DOUT all-ones, OE should be
 119     * reflected on DIN.
 120     */
 121    writel(GPIO(0) + GP_N_DOUT, 0xffffffff);
 122    writel(GPIO(0) + GP_N_PU, 0x00000000);
 123    writel(GPIO(0) + GP_N_PD, 0xffffffff);
 124    writel(GPIO(0) + GP_N_OE, 0x3456789a);
 125    g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3456789a);
 126    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3456789a);
 127
 128    writel(GPIO(0) + GP_N_OEC, 0x00030002);
 129    g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x34547898);
 130    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x34547898);
 131
 132    writel(GPIO(0) + GP_N_OES, 0x0000f001);
 133    g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3454f899);
 134    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3454f899);
 135}
 136
 137static void test_open_drain(void)
 138{
 139    gpio_reset(0);
 140
 141    /*
 142     * Upper half of DOUT drives a 1 only if the corresponding bit in OTYP is
 143     * not set. If OTYP is set, DIN is determined by PU/PD. Lower half of
 144     * DOUT always drives a 0 regardless of OTYP; PU/PD have no effect.  When
 145     * OE is 0, output is determined by PU/PD; OTYP has no effect.
 146     */
 147    writel(GPIO(0) + GP_N_OTYP, 0x456789ab);
 148    writel(GPIO(0) + GP_N_OE, 0xf0f0f0f0);
 149    writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
 150    writel(GPIO(0) + GP_N_PU, 0xff00ff00);
 151    writel(GPIO(0) + GP_N_PD, 0x00ff00ff);
 152    g_assert_cmphex(readl(GPIO(0) + GP_N_OTYP), ==, 0x456789ab);
 153    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff900f00);
 154}
 155
 156static void test_polarity(void)
 157{
 158    gpio_reset(0);
 159
 160    /*
 161     * In push-pull mode, DIN should reflect DOUT because the signal is
 162     * inverted in both directions.
 163     */
 164    writel(GPIO(0) + GP_N_OTYP, 0x00000000);
 165    writel(GPIO(0) + GP_N_OE, 0xffffffff);
 166    writel(GPIO(0) + GP_N_DOUT, 0x56789abc);
 167    writel(GPIO(0) + GP_N_POL, 0x6789abcd);
 168    g_assert_cmphex(readl(GPIO(0) + GP_N_POL), ==, 0x6789abcd);
 169    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x56789abc);
 170
 171    /*
 172     * When turning off the drivers, DIN should reflect the inverse of the
 173     * pulled-up lines.
 174     */
 175    writel(GPIO(0) + GP_N_OE, 0x00000000);
 176    writel(GPIO(0) + GP_N_POL, 0xffffffff);
 177    writel(GPIO(0) + GP_N_PU, 0x789abcde);
 178    writel(GPIO(0) + GP_N_PD, ~0x789abcdeU);
 179    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, ~0x789abcdeU);
 180
 181    /*
 182     * In open-drain mode, DOUT=1 will appear to drive the pin high (since DIN
 183     * is inverted), while DOUT=0 will leave the pin floating.
 184     */
 185    writel(GPIO(0) + GP_N_OTYP, 0xffffffff);
 186    writel(GPIO(0) + GP_N_OE, 0xffffffff);
 187    writel(GPIO(0) + GP_N_PU, 0xffff0000);
 188    writel(GPIO(0) + GP_N_PD, 0x0000ffff);
 189    writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
 190    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff00ffff);
 191}
 192
 193static void test_input_mask(void)
 194{
 195    gpio_reset(0);
 196
 197    /* IEM=0 forces the input to zero before polarity inversion. */
 198    writel(GPIO(0) + GP_N_OE, 0xffffffff);
 199    writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
 200    writel(GPIO(0) + GP_N_POL, 0xffff0000);
 201    writel(GPIO(0) + GP_N_IEM, 0x87654321);
 202    g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff9a4300);
 203}
 204
 205static void test_temp_lock(void)
 206{
 207    gpio_reset(0);
 208
 209    writel(GPIO(0) + GP_N_DOUT, 0x98765432);
 210
 211    /* Make sure we're unlocked initially. */
 212    g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
 213    /* Writing any value to TLOCK1 will lock. */
 214    writel(GPIO(0) + GP_N_TLOCK1, 0);
 215    g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
 216    writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
 217    g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
 218    /* Now, try to unlock. */
 219    gpio_unlock(0);
 220    g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
 221    writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
 222    g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
 223
 224    /* Try it again, but write TLOCK2 to lock. */
 225    writel(GPIO(0) + GP_N_TLOCK2, 0);
 226    g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
 227    writel(GPIO(0) + GP_N_DOUT, 0x98765432);
 228    g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
 229    /* Now, try to unlock. */
 230    gpio_unlock(0);
 231    g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
 232    writel(GPIO(0) + GP_N_DOUT, 0x98765432);
 233    g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
 234}
 235
 236static void test_events_level(void)
 237{
 238    gpio_reset(0);
 239
 240    writel(GPIO(0) + GP_N_EVTYP, 0x00000000);
 241    writel(GPIO(0) + GP_N_DOUT, 0xba987654);
 242    writel(GPIO(0) + GP_N_OE, 0xffffffff);
 243    writel(GPIO(0) + GP_N_EVST, 0xffffffff);
 244
 245    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
 246    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 247    writel(GPIO(0) + GP_N_DOUT, 0x00000000);
 248    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
 249    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 250    writel(GPIO(0) + GP_N_EVST, 0x00007654);
 251    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba980000);
 252    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 253    writel(GPIO(0) + GP_N_EVST, 0xba980000);
 254    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
 255    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 256}
 257
 258static void test_events_rising_edge(void)
 259{
 260    gpio_reset(0);
 261
 262    writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
 263    writel(GPIO(0) + GP_N_EVBE, 0x00000000);
 264    writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
 265    writel(GPIO(0) + GP_N_OE, 0xffffffff);
 266    writel(GPIO(0) + GP_N_EVST, 0xffffffff);
 267
 268    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
 269    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 270    writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
 271    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x0000ff00);
 272    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 273    writel(GPIO(0) + GP_N_DOUT, 0x00ff0000);
 274    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
 275    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 276    writel(GPIO(0) + GP_N_EVST, 0x0000f000);
 277    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ff0f00);
 278    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 279    writel(GPIO(0) + GP_N_EVST, 0x00ff0f00);
 280    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
 281    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 282}
 283
 284static void test_events_both_edges(void)
 285{
 286    gpio_reset(0);
 287
 288    writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
 289    writel(GPIO(0) + GP_N_EVBE, 0xffffffff);
 290    writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
 291    writel(GPIO(0) + GP_N_OE, 0xffffffff);
 292    writel(GPIO(0) + GP_N_EVST, 0xffffffff);
 293
 294    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
 295    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 296    writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
 297    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
 298    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 299    writel(GPIO(0) + GP_N_DOUT, 0xef00ff08);
 300    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ffff08);
 301    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 302    writel(GPIO(0) + GP_N_EVST, 0x0000f000);
 303    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ff0f08);
 304    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 305    writel(GPIO(0) + GP_N_EVST, 0x10ff0f08);
 306    g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
 307    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
 308}
 309
 310static void test_gpion_irq(gconstpointer test_data)
 311{
 312    intptr_t n = (intptr_t)test_data;
 313
 314    gpio_reset(n);
 315
 316    writel(GPIO(n) + GP_N_EVTYP, 0x00000000);
 317    writel(GPIO(n) + GP_N_DOUT, 0x00000000);
 318    writel(GPIO(n) + GP_N_OE, 0xffffffff);
 319    writel(GPIO(n) + GP_N_EVST, 0xffffffff);
 320    writel(GPIO(n) + GP_N_EVEN, 0x00000000);
 321
 322    /* Trigger an event; interrupts are masked. */
 323    g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00000000);
 324    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 325    writel(GPIO(n) + GP_N_DOS, 0x00008000);
 326    g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00008000);
 327    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 328
 329    /* Unmask all event interrupts; verify that the interrupt fired. */
 330    writel(GPIO(n) + GP_N_EVEN, 0xffffffff);
 331    g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 332
 333    /* Clear the current bit, set a new bit, irq stays asserted. */
 334    writel(GPIO(n) + GP_N_DOC, 0x00008000);
 335    g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 336    writel(GPIO(n) + GP_N_DOS, 0x00000200);
 337    g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 338    writel(GPIO(n) + GP_N_EVST, 0x00008000);
 339    g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 340
 341    /* Mask/unmask the event that's currently active. */
 342    writel(GPIO(n) + GP_N_EVENC, 0x00000200);
 343    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 344    writel(GPIO(n) + GP_N_EVENS, 0x00000200);
 345    g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 346
 347    /* Clear the input and the status bit, irq is deasserted. */
 348    writel(GPIO(n) + GP_N_DOC, 0x00000200);
 349    g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 350    writel(GPIO(n) + GP_N_EVST, 0x00000200);
 351    g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
 352}
 353
 354int main(int argc, char **argv)
 355{
 356    int ret;
 357    int i;
 358
 359    g_test_init(&argc, &argv, NULL);
 360    g_test_set_nonfatal_assertions();
 361
 362    qtest_add_func("/npcm7xx_gpio/dout_to_din", test_dout_to_din);
 363    qtest_add_func("/npcm7xx_gpio/pullup_pulldown", test_pullup_pulldown);
 364    qtest_add_func("/npcm7xx_gpio/output_enable", test_output_enable);
 365    qtest_add_func("/npcm7xx_gpio/open_drain", test_open_drain);
 366    qtest_add_func("/npcm7xx_gpio/polarity", test_polarity);
 367    qtest_add_func("/npcm7xx_gpio/input_mask", test_input_mask);
 368    qtest_add_func("/npcm7xx_gpio/temp_lock", test_temp_lock);
 369    qtest_add_func("/npcm7xx_gpio/events/level", test_events_level);
 370    qtest_add_func("/npcm7xx_gpio/events/rising_edge", test_events_rising_edge);
 371    qtest_add_func("/npcm7xx_gpio/events/both_edges", test_events_both_edges);
 372
 373    for (i = 0; i < NR_GPIO_DEVICES; i++) {
 374        g_autofree char *test_name =
 375            g_strdup_printf("/npcm7xx_gpio/gpio[%d]/irq", i);
 376        qtest_add_data_func(test_name, (void *)(intptr_t)i, test_gpion_irq);
 377    }
 378
 379    qtest_start("-machine npcm750-evb");
 380    qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
 381    ret = g_test_run();
 382    qtest_end();
 383
 384    return ret;
 385}
 386