qemu/tests/qtest/npcm7xx_pwm-test.c
<<
>>
Prefs
   1/*
   2 * QTests for Nuvoton NPCM7xx PWM 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 "qemu/bitops.h"
  19#include "libqtest.h"
  20#include "qapi/qmp/qdict.h"
  21#include "qapi/qmp/qnum.h"
  22
  23#define REF_HZ          25000000
  24
  25/* Register field definitions. */
  26#define CH_EN           BIT(0)
  27#define CH_INV          BIT(2)
  28#define CH_MOD          BIT(3)
  29
  30/* Registers shared between all PWMs in a module */
  31#define PPR             0x00
  32#define CSR             0x04
  33#define PCR             0x08
  34#define PIER            0x3c
  35#define PIIR            0x40
  36
  37/* CLK module related */
  38#define CLK_BA          0xf0801000
  39#define CLKSEL          0x04
  40#define CLKDIV1         0x08
  41#define CLKDIV2         0x2c
  42#define PLLCON0         0x0c
  43#define PLLCON1         0x10
  44#define PLL_INDV(rv)    extract32((rv), 0, 6)
  45#define PLL_FBDV(rv)    extract32((rv), 16, 12)
  46#define PLL_OTDV1(rv)   extract32((rv), 8, 3)
  47#define PLL_OTDV2(rv)   extract32((rv), 13, 3)
  48#define APB4CKDIV(rv)   extract32((rv), 30, 2)
  49#define APB3CKDIV(rv)   extract32((rv), 28, 2)
  50#define CLK2CKDIV(rv)   extract32((rv), 0, 1)
  51#define CLK4CKDIV(rv)   extract32((rv), 26, 2)
  52#define CPUCKSEL(rv)    extract32((rv), 0, 2)
  53
  54#define MAX_DUTY        1000000
  55
  56/* MFT (PWM fan) related */
  57#define MFT_BA(n)       (0xf0180000 + ((n) * 0x1000))
  58#define MFT_IRQ(n)      (96 + (n))
  59#define MFT_CNT1        0x00
  60#define MFT_CRA         0x02
  61#define MFT_CRB         0x04
  62#define MFT_CNT2        0x06
  63#define MFT_PRSC        0x08
  64#define MFT_CKC         0x0a
  65#define MFT_MCTRL       0x0c
  66#define MFT_ICTRL       0x0e
  67#define MFT_ICLR        0x10
  68#define MFT_IEN         0x12
  69#define MFT_CPA         0x14
  70#define MFT_CPB         0x16
  71#define MFT_CPCFG       0x18
  72#define MFT_INASEL      0x1a
  73#define MFT_INBSEL      0x1c
  74
  75#define MFT_MCTRL_ALL   0x64
  76#define MFT_ICLR_ALL    0x3f
  77#define MFT_IEN_ALL     0x3f
  78#define MFT_CPCFG_EQ_MODE 0x44
  79
  80#define MFT_CKC_C2CSEL  BIT(3)
  81#define MFT_CKC_C1CSEL  BIT(0)
  82
  83#define MFT_ICTRL_TFPND BIT(5)
  84#define MFT_ICTRL_TEPND BIT(4)
  85#define MFT_ICTRL_TDPND BIT(3)
  86#define MFT_ICTRL_TCPND BIT(2)
  87#define MFT_ICTRL_TBPND BIT(1)
  88#define MFT_ICTRL_TAPND BIT(0)
  89
  90#define MFT_MAX_CNT     0xffff
  91#define MFT_TIMEOUT     0x5000
  92
  93#define DEFAULT_RPM     19800
  94#define DEFAULT_PRSC    255
  95#define MFT_PULSE_PER_REVOLUTION 2
  96
  97#define MAX_ERROR       1
  98
  99typedef struct PWMModule {
 100    int irq;
 101    uint64_t base_addr;
 102} PWMModule;
 103
 104typedef struct PWM {
 105    uint32_t cnr_offset;
 106    uint32_t cmr_offset;
 107    uint32_t pdr_offset;
 108    uint32_t pwdr_offset;
 109} PWM;
 110
 111typedef struct TestData {
 112    const PWMModule *module;
 113    const PWM *pwm;
 114} TestData;
 115
 116static const PWMModule pwm_module_list[] = {
 117    {
 118        .irq        = 93,
 119        .base_addr  = 0xf0103000
 120    },
 121    {
 122        .irq        = 94,
 123        .base_addr  = 0xf0104000
 124    }
 125};
 126
 127static const PWM pwm_list[] = {
 128    {
 129        .cnr_offset     = 0x0c,
 130        .cmr_offset     = 0x10,
 131        .pdr_offset     = 0x14,
 132        .pwdr_offset    = 0x44,
 133    },
 134    {
 135        .cnr_offset     = 0x18,
 136        .cmr_offset     = 0x1c,
 137        .pdr_offset     = 0x20,
 138        .pwdr_offset    = 0x48,
 139    },
 140    {
 141        .cnr_offset     = 0x24,
 142        .cmr_offset     = 0x28,
 143        .pdr_offset     = 0x2c,
 144        .pwdr_offset    = 0x4c,
 145    },
 146    {
 147        .cnr_offset     = 0x30,
 148        .cmr_offset     = 0x34,
 149        .pdr_offset     = 0x38,
 150        .pwdr_offset    = 0x50,
 151    },
 152};
 153
 154static const int ppr_base[] = { 0, 0, 8, 8 };
 155static const int csr_base[] = { 0, 4, 8, 12 };
 156static const int pcr_base[] = { 0, 8, 12, 16 };
 157
 158static const uint32_t ppr_list[] = {
 159    0,
 160    1,
 161    10,
 162    100,
 163    255, /* Max possible value. */
 164};
 165
 166static const uint32_t csr_list[] = {
 167    0,
 168    1,
 169    2,
 170    3,
 171    4, /* Max possible value. */
 172};
 173
 174static const uint32_t cnr_list[] = {
 175    0,
 176    1,
 177    50,
 178    100,
 179    150,
 180    200,
 181    1000,
 182    10000,
 183    65535, /* Max possible value. */
 184};
 185
 186static const uint32_t cmr_list[] = {
 187    0,
 188    1,
 189    10,
 190    50,
 191    100,
 192    150,
 193    200,
 194    1000,
 195    10000,
 196    65535, /* Max possible value. */
 197};
 198
 199/* Returns the index of the PWM module. */
 200static int pwm_module_index(const PWMModule *module)
 201{
 202    ptrdiff_t diff = module - pwm_module_list;
 203
 204    g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
 205
 206    return diff;
 207}
 208
 209/* Returns the index of the PWM entry. */
 210static int pwm_index(const PWM *pwm)
 211{
 212    ptrdiff_t diff = pwm - pwm_list;
 213
 214    g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
 215
 216    return diff;
 217}
 218
 219static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name)
 220{
 221    QDict *response;
 222    uint64_t val;
 223
 224    g_test_message("Getting properties %s from %s", name, path);
 225    response = qtest_qmp(qts, "{ 'execute': 'qom-get',"
 226            " 'arguments': { 'path': %s, 'property': %s}}",
 227            path, name);
 228    /* The qom set message returns successfully. */
 229    g_assert_true(qdict_haskey(response, "return"));
 230    val = qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
 231    qobject_unref(response);
 232    return val;
 233}
 234
 235static uint64_t pwm_get_freq(QTestState *qts, int module_index, int pwm_index)
 236{
 237    char path[100];
 238    char name[100];
 239
 240    sprintf(path, "/machine/soc/pwm[%d]", module_index);
 241    sprintf(name, "freq[%d]", pwm_index);
 242
 243    return pwm_qom_get(qts, path, name);
 244}
 245
 246static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
 247{
 248    char path[100];
 249    char name[100];
 250
 251    sprintf(path, "/machine/soc/pwm[%d]", module_index);
 252    sprintf(name, "duty[%d]", pwm_index);
 253
 254    return pwm_qom_get(qts, path, name);
 255}
 256
 257static void mft_qom_set(QTestState *qts, int index, const char *name,
 258                        uint32_t value)
 259{
 260    QDict *response;
 261    char *path = g_strdup_printf("/machine/soc/mft[%d]", index);
 262
 263    g_test_message("Setting properties %s of mft[%d] with value %u",
 264                   name, index, value);
 265    response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
 266            " 'arguments': { 'path': %s, "
 267            " 'property': %s, 'value': %u}}",
 268            path, name, value);
 269    /* The qom set message returns successfully. */
 270    g_assert_true(qdict_haskey(response, "return"));
 271
 272    qobject_unref(response);
 273    g_free(path);
 274}
 275
 276static uint32_t get_pll(uint32_t con)
 277{
 278    return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
 279            * PLL_OTDV2(con));
 280}
 281
 282static uint64_t read_pclk(QTestState *qts, bool mft)
 283{
 284    uint64_t freq = REF_HZ;
 285    uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
 286    uint32_t pllcon;
 287    uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
 288    uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
 289    uint32_t apbdiv = mft ? APB4CKDIV(clkdiv2) : APB3CKDIV(clkdiv2);
 290
 291    switch (CPUCKSEL(clksel)) {
 292    case 0:
 293        pllcon = qtest_readl(qts, CLK_BA + PLLCON0);
 294        freq = get_pll(pllcon);
 295        break;
 296    case 1:
 297        pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
 298        freq = get_pll(pllcon);
 299        break;
 300    case 2:
 301        break;
 302    case 3:
 303        break;
 304    default:
 305        g_assert_not_reached();
 306    }
 307
 308    freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + apbdiv);
 309
 310    return freq;
 311}
 312
 313static uint32_t pwm_selector(uint32_t csr)
 314{
 315    switch (csr) {
 316    case 0:
 317        return 2;
 318    case 1:
 319        return 4;
 320    case 2:
 321        return 8;
 322    case 3:
 323        return 16;
 324    case 4:
 325        return 1;
 326    default:
 327        g_assert_not_reached();
 328    }
 329}
 330
 331static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
 332        uint32_t cnr)
 333{
 334    return read_pclk(qts, false) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
 335}
 336
 337static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
 338{
 339    uint32_t duty;
 340
 341    if (cnr == 0) {
 342        /* PWM is stopped. */
 343        duty = 0;
 344    } else if (cmr >= cnr) {
 345        duty = MAX_DUTY;
 346    } else {
 347        duty = (uint64_t)MAX_DUTY * (cmr + 1) / (cnr + 1);
 348    }
 349
 350    if (inverted) {
 351        duty = MAX_DUTY - duty;
 352    }
 353
 354    return duty;
 355}
 356
 357static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
 358{
 359    return qtest_readl(qts, td->module->base_addr + offset);
 360}
 361
 362static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
 363        uint32_t value)
 364{
 365    qtest_writel(qts, td->module->base_addr + offset, value);
 366}
 367
 368static uint8_t mft_readb(QTestState *qts, int index, unsigned offset)
 369{
 370    return qtest_readb(qts, MFT_BA(index) + offset);
 371}
 372
 373static uint16_t mft_readw(QTestState *qts, int index, unsigned offset)
 374{
 375    return qtest_readw(qts, MFT_BA(index) + offset);
 376}
 377
 378static void mft_writeb(QTestState *qts, int index, unsigned offset,
 379                        uint8_t value)
 380{
 381    qtest_writeb(qts, MFT_BA(index) + offset, value);
 382}
 383
 384static void mft_writew(QTestState *qts, int index, unsigned offset,
 385                        uint16_t value)
 386{
 387    return qtest_writew(qts, MFT_BA(index) + offset, value);
 388}
 389
 390static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
 391{
 392    return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
 393}
 394
 395static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
 396{
 397    pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
 398}
 399
 400static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
 401{
 402    return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
 403}
 404
 405static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
 406{
 407    pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
 408}
 409
 410static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
 411{
 412    return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
 413}
 414
 415static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
 416{
 417    pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
 418}
 419
 420static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
 421{
 422    return pwm_read(qts, td, td->pwm->cnr_offset);
 423}
 424
 425static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
 426{
 427    pwm_write(qts, td, td->pwm->cnr_offset, value);
 428}
 429
 430static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
 431{
 432    return pwm_read(qts, td, td->pwm->cmr_offset);
 433}
 434
 435static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
 436{
 437    pwm_write(qts, td, td->pwm->cmr_offset, value);
 438}
 439
 440static int mft_compute_index(const TestData *td)
 441{
 442    int index = pwm_module_index(td->module) * ARRAY_SIZE(pwm_list) +
 443                pwm_index(td->pwm);
 444
 445    g_assert_cmpint(index, <,
 446                    ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list));
 447
 448    return index;
 449}
 450
 451static void mft_reset_counters(QTestState *qts, int index)
 452{
 453    mft_writew(qts, index, MFT_CNT1, MFT_MAX_CNT);
 454    mft_writew(qts, index, MFT_CNT2, MFT_MAX_CNT);
 455    mft_writew(qts, index, MFT_CRA, MFT_MAX_CNT);
 456    mft_writew(qts, index, MFT_CRB, MFT_MAX_CNT);
 457    mft_writew(qts, index, MFT_CPA, MFT_MAX_CNT - MFT_TIMEOUT);
 458    mft_writew(qts, index, MFT_CPB, MFT_MAX_CNT - MFT_TIMEOUT);
 459}
 460
 461static void mft_init(QTestState *qts, const TestData *td)
 462{
 463    int index = mft_compute_index(td);
 464
 465    /* Enable everything */
 466    mft_writeb(qts, index, MFT_CKC, 0);
 467    mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
 468    mft_writeb(qts, index, MFT_MCTRL, MFT_MCTRL_ALL);
 469    mft_writeb(qts, index, MFT_IEN, MFT_IEN_ALL);
 470    mft_writeb(qts, index, MFT_INASEL, 0);
 471    mft_writeb(qts, index, MFT_INBSEL, 0);
 472
 473    /* Set cpcfg to use EQ mode, same as kernel driver */
 474    mft_writeb(qts, index, MFT_CPCFG, MFT_CPCFG_EQ_MODE);
 475
 476    /* Write default counters, timeout and prescaler */
 477    mft_reset_counters(qts, index);
 478    mft_writeb(qts, index, MFT_PRSC, DEFAULT_PRSC);
 479
 480    /* Write default max rpm via QMP */
 481    mft_qom_set(qts, index, "max_rpm[0]", DEFAULT_RPM);
 482    mft_qom_set(qts, index, "max_rpm[1]", DEFAULT_RPM);
 483}
 484
 485static int32_t mft_compute_cnt(uint32_t rpm, uint64_t clk)
 486{
 487    uint64_t cnt;
 488
 489    if (rpm == 0) {
 490        return -1;
 491    }
 492
 493    cnt = clk * 60 / ((DEFAULT_PRSC + 1) * rpm * MFT_PULSE_PER_REVOLUTION);
 494    if (cnt >= MFT_TIMEOUT) {
 495        return -1;
 496    }
 497    return MFT_MAX_CNT - cnt;
 498}
 499
 500static void mft_verify_rpm(QTestState *qts, const TestData *td, uint64_t duty)
 501{
 502    int index = mft_compute_index(td);
 503    uint16_t cnt, cr;
 504    uint32_t rpm = DEFAULT_RPM * duty / MAX_DUTY;
 505    uint64_t clk = read_pclk(qts, true);
 506    int32_t expected_cnt = mft_compute_cnt(rpm, clk);
 507
 508    qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
 509    g_test_message(
 510        "verifying rpm for mft[%d]: clk: %" PRIu64 ", duty: %" PRIu64 ", rpm: %u, cnt: %d",
 511        index, clk, duty, rpm, expected_cnt);
 512
 513    /* Verify rpm for fan A */
 514    /* Stop capture */
 515    mft_writeb(qts, index, MFT_CKC, 0);
 516    mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
 517    mft_reset_counters(qts, index);
 518    g_assert_cmphex(mft_readw(qts, index, MFT_CNT1), ==, MFT_MAX_CNT);
 519    g_assert_cmphex(mft_readw(qts, index, MFT_CRA), ==, MFT_MAX_CNT);
 520    g_assert_cmphex(mft_readw(qts, index, MFT_CPA), ==,
 521                    MFT_MAX_CNT - MFT_TIMEOUT);
 522    /* Start capture */
 523    mft_writeb(qts, index, MFT_CKC, MFT_CKC_C1CSEL);
 524    g_assert_true(qtest_get_irq(qts, MFT_IRQ(index)));
 525    if (expected_cnt == -1) {
 526        g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TEPND);
 527    } else {
 528        g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TAPND);
 529        cnt = mft_readw(qts, index, MFT_CNT1);
 530        /*
 531         * Due to error in clock measurement and rounding, we might have a small
 532         * error in measuring RPM.
 533         */
 534        g_assert_cmphex(cnt + MAX_ERROR, >=, expected_cnt);
 535        g_assert_cmphex(cnt, <=, expected_cnt + MAX_ERROR);
 536        cr = mft_readw(qts, index, MFT_CRA);
 537        g_assert_cmphex(cnt, ==, cr);
 538    }
 539
 540    /* Verify rpm for fan B */
 541
 542    qtest_irq_intercept_out(qts, "/machine/soc/a9mpcore/gic");
 543}
 544
 545/* Check pwm registers can be reset to default value */
 546static void test_init(gconstpointer test_data)
 547{
 548    const TestData *td = test_data;
 549    QTestState *qts = qtest_init("-machine npcm750-evb");
 550    int module = pwm_module_index(td->module);
 551    int pwm = pwm_index(td->pwm);
 552
 553    g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
 554    g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
 555
 556    qtest_quit(qts);
 557}
 558
 559/* One-shot mode should not change frequency and duty cycle. */
 560static void test_oneshot(gconstpointer test_data)
 561{
 562    const TestData *td = test_data;
 563    QTestState *qts = qtest_init("-machine npcm750-evb");
 564    int module = pwm_module_index(td->module);
 565    int pwm = pwm_index(td->pwm);
 566    uint32_t ppr, csr, pcr;
 567    int i, j;
 568
 569    pcr = CH_EN;
 570    for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
 571        ppr = ppr_list[i];
 572        pwm_write_ppr(qts, td, ppr);
 573
 574        for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
 575            csr = csr_list[j];
 576            pwm_write_csr(qts, td, csr);
 577            pwm_write_pcr(qts, td, pcr);
 578
 579            g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
 580            g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
 581            g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
 582            g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
 583            g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
 584        }
 585    }
 586
 587    qtest_quit(qts);
 588}
 589
 590/* In toggle mode, the PWM generates correct outputs. */
 591static void test_toggle(gconstpointer test_data)
 592{
 593    const TestData *td = test_data;
 594    QTestState *qts = qtest_init("-machine npcm750-evb");
 595    int module = pwm_module_index(td->module);
 596    int pwm = pwm_index(td->pwm);
 597    uint32_t ppr, csr, pcr, cnr, cmr;
 598    int i, j, k, l;
 599    uint64_t expected_freq, expected_duty;
 600
 601    mft_init(qts, td);
 602
 603    pcr = CH_EN | CH_MOD;
 604    for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
 605        ppr = ppr_list[i];
 606        pwm_write_ppr(qts, td, ppr);
 607
 608        for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
 609            csr = csr_list[j];
 610            pwm_write_csr(qts, td, csr);
 611
 612            for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
 613                cnr = cnr_list[k];
 614                pwm_write_cnr(qts, td, cnr);
 615
 616                for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
 617                    cmr = cmr_list[l];
 618                    pwm_write_cmr(qts, td, cmr);
 619                    expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
 620                    expected_duty = pwm_compute_duty(cnr, cmr, false);
 621
 622                    pwm_write_pcr(qts, td, pcr);
 623                    g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
 624                    g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
 625                    g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
 626                    g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
 627                    g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
 628                    g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
 629                            ==, expected_duty);
 630                    if (expected_duty != 0 && expected_duty != 100) {
 631                        /* Duty cycle with 0 or 100 doesn't need frequency. */
 632                        g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
 633                                ==, expected_freq);
 634                    }
 635
 636                    /* Test MFT's RPM is correct. */
 637                    mft_verify_rpm(qts, td, expected_duty);
 638
 639                    /* Test inverted mode */
 640                    expected_duty = pwm_compute_duty(cnr, cmr, true);
 641                    pwm_write_pcr(qts, td, pcr | CH_INV);
 642                    g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
 643                    g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
 644                            ==, expected_duty);
 645                    if (expected_duty != 0 && expected_duty != 100) {
 646                        /* Duty cycle with 0 or 100 doesn't need frequency. */
 647                        g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
 648                                ==, expected_freq);
 649                    }
 650
 651                }
 652            }
 653        }
 654    }
 655
 656    qtest_quit(qts);
 657}
 658
 659static void pwm_add_test(const char *name, const TestData* td,
 660        GTestDataFunc fn)
 661{
 662    g_autofree char *full_name = g_strdup_printf(
 663            "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
 664            pwm_index(td->pwm), name);
 665    qtest_add_data_func(full_name, td, fn);
 666}
 667#define add_test(name, td) pwm_add_test(#name, td, test_##name)
 668
 669int main(int argc, char **argv)
 670{
 671    TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
 672
 673    g_test_init(&argc, &argv, NULL);
 674
 675    for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
 676        for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
 677            TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
 678
 679            td->module = &pwm_module_list[i];
 680            td->pwm = &pwm_list[j];
 681
 682            add_test(init, td);
 683            add_test(oneshot, td);
 684            add_test(toggle, td);
 685        }
 686    }
 687
 688    return g_test_run();
 689}
 690