cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

npcm7xx_pwm-test.c (19500B)


      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 "libqos/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
    273static uint32_t get_pll(uint32_t con)
    274{
    275    return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
    276            * PLL_OTDV2(con));
    277}
    278
    279static uint64_t read_pclk(QTestState *qts, bool mft)
    280{
    281    uint64_t freq = REF_HZ;
    282    uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
    283    uint32_t pllcon;
    284    uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
    285    uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
    286    uint32_t apbdiv = mft ? APB4CKDIV(clkdiv2) : APB3CKDIV(clkdiv2);
    287
    288    switch (CPUCKSEL(clksel)) {
    289    case 0:
    290        pllcon = qtest_readl(qts, CLK_BA + PLLCON0);
    291        freq = get_pll(pllcon);
    292        break;
    293    case 1:
    294        pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
    295        freq = get_pll(pllcon);
    296        break;
    297    case 2:
    298        break;
    299    case 3:
    300        break;
    301    default:
    302        g_assert_not_reached();
    303    }
    304
    305    freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + apbdiv);
    306
    307    return freq;
    308}
    309
    310static uint32_t pwm_selector(uint32_t csr)
    311{
    312    switch (csr) {
    313    case 0:
    314        return 2;
    315    case 1:
    316        return 4;
    317    case 2:
    318        return 8;
    319    case 3:
    320        return 16;
    321    case 4:
    322        return 1;
    323    default:
    324        g_assert_not_reached();
    325    }
    326}
    327
    328static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
    329        uint32_t cnr)
    330{
    331    return read_pclk(qts, false) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
    332}
    333
    334static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
    335{
    336    uint32_t duty;
    337
    338    if (cnr == 0) {
    339        /* PWM is stopped. */
    340        duty = 0;
    341    } else if (cmr >= cnr) {
    342        duty = MAX_DUTY;
    343    } else {
    344        duty = (uint64_t)MAX_DUTY * (cmr + 1) / (cnr + 1);
    345    }
    346
    347    if (inverted) {
    348        duty = MAX_DUTY - duty;
    349    }
    350
    351    return duty;
    352}
    353
    354static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
    355{
    356    return qtest_readl(qts, td->module->base_addr + offset);
    357}
    358
    359static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
    360        uint32_t value)
    361{
    362    qtest_writel(qts, td->module->base_addr + offset, value);
    363}
    364
    365static uint8_t mft_readb(QTestState *qts, int index, unsigned offset)
    366{
    367    return qtest_readb(qts, MFT_BA(index) + offset);
    368}
    369
    370static uint16_t mft_readw(QTestState *qts, int index, unsigned offset)
    371{
    372    return qtest_readw(qts, MFT_BA(index) + offset);
    373}
    374
    375static void mft_writeb(QTestState *qts, int index, unsigned offset,
    376                        uint8_t value)
    377{
    378    qtest_writeb(qts, MFT_BA(index) + offset, value);
    379}
    380
    381static void mft_writew(QTestState *qts, int index, unsigned offset,
    382                        uint16_t value)
    383{
    384    return qtest_writew(qts, MFT_BA(index) + offset, value);
    385}
    386
    387static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
    388{
    389    return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
    390}
    391
    392static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
    393{
    394    pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
    395}
    396
    397static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
    398{
    399    return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
    400}
    401
    402static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
    403{
    404    pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
    405}
    406
    407static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
    408{
    409    return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
    410}
    411
    412static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
    413{
    414    pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
    415}
    416
    417static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
    418{
    419    return pwm_read(qts, td, td->pwm->cnr_offset);
    420}
    421
    422static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
    423{
    424    pwm_write(qts, td, td->pwm->cnr_offset, value);
    425}
    426
    427static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
    428{
    429    return pwm_read(qts, td, td->pwm->cmr_offset);
    430}
    431
    432static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
    433{
    434    pwm_write(qts, td, td->pwm->cmr_offset, value);
    435}
    436
    437static int mft_compute_index(const TestData *td)
    438{
    439    int index = pwm_module_index(td->module) * ARRAY_SIZE(pwm_list) +
    440                pwm_index(td->pwm);
    441
    442    g_assert_cmpint(index, <,
    443                    ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list));
    444
    445    return index;
    446}
    447
    448static void mft_reset_counters(QTestState *qts, int index)
    449{
    450    mft_writew(qts, index, MFT_CNT1, MFT_MAX_CNT);
    451    mft_writew(qts, index, MFT_CNT2, MFT_MAX_CNT);
    452    mft_writew(qts, index, MFT_CRA, MFT_MAX_CNT);
    453    mft_writew(qts, index, MFT_CRB, MFT_MAX_CNT);
    454    mft_writew(qts, index, MFT_CPA, MFT_MAX_CNT - MFT_TIMEOUT);
    455    mft_writew(qts, index, MFT_CPB, MFT_MAX_CNT - MFT_TIMEOUT);
    456}
    457
    458static void mft_init(QTestState *qts, const TestData *td)
    459{
    460    int index = mft_compute_index(td);
    461
    462    /* Enable everything */
    463    mft_writeb(qts, index, MFT_CKC, 0);
    464    mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
    465    mft_writeb(qts, index, MFT_MCTRL, MFT_MCTRL_ALL);
    466    mft_writeb(qts, index, MFT_IEN, MFT_IEN_ALL);
    467    mft_writeb(qts, index, MFT_INASEL, 0);
    468    mft_writeb(qts, index, MFT_INBSEL, 0);
    469
    470    /* Set cpcfg to use EQ mode, same as kernel driver */
    471    mft_writeb(qts, index, MFT_CPCFG, MFT_CPCFG_EQ_MODE);
    472
    473    /* Write default counters, timeout and prescaler */
    474    mft_reset_counters(qts, index);
    475    mft_writeb(qts, index, MFT_PRSC, DEFAULT_PRSC);
    476
    477    /* Write default max rpm via QMP */
    478    mft_qom_set(qts, index, "max_rpm[0]", DEFAULT_RPM);
    479    mft_qom_set(qts, index, "max_rpm[1]", DEFAULT_RPM);
    480}
    481
    482static int32_t mft_compute_cnt(uint32_t rpm, uint64_t clk)
    483{
    484    uint64_t cnt;
    485
    486    if (rpm == 0) {
    487        return -1;
    488    }
    489
    490    cnt = clk * 60 / ((DEFAULT_PRSC + 1) * rpm * MFT_PULSE_PER_REVOLUTION);
    491    if (cnt >= MFT_TIMEOUT) {
    492        return -1;
    493    }
    494    return MFT_MAX_CNT - cnt;
    495}
    496
    497static void mft_verify_rpm(QTestState *qts, const TestData *td, uint64_t duty)
    498{
    499    int index = mft_compute_index(td);
    500    uint16_t cnt, cr;
    501    uint32_t rpm = DEFAULT_RPM * duty / MAX_DUTY;
    502    uint64_t clk = read_pclk(qts, true);
    503    int32_t expected_cnt = mft_compute_cnt(rpm, clk);
    504
    505    qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
    506    g_test_message(
    507        "verifying rpm for mft[%d]: clk: %" PRIu64 ", duty: %" PRIu64 ", rpm: %u, cnt: %d",
    508        index, clk, duty, rpm, expected_cnt);
    509
    510    /* Verify rpm for fan A */
    511    /* Stop capture */
    512    mft_writeb(qts, index, MFT_CKC, 0);
    513    mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
    514    mft_reset_counters(qts, index);
    515    g_assert_cmphex(mft_readw(qts, index, MFT_CNT1), ==, MFT_MAX_CNT);
    516    g_assert_cmphex(mft_readw(qts, index, MFT_CRA), ==, MFT_MAX_CNT);
    517    g_assert_cmphex(mft_readw(qts, index, MFT_CPA), ==,
    518                    MFT_MAX_CNT - MFT_TIMEOUT);
    519    /* Start capture */
    520    mft_writeb(qts, index, MFT_CKC, MFT_CKC_C1CSEL);
    521    g_assert_true(qtest_get_irq(qts, MFT_IRQ(index)));
    522    if (expected_cnt == -1) {
    523        g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TEPND);
    524    } else {
    525        g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TAPND);
    526        cnt = mft_readw(qts, index, MFT_CNT1);
    527        /*
    528         * Due to error in clock measurement and rounding, we might have a small
    529         * error in measuring RPM.
    530         */
    531        g_assert_cmphex(cnt + MAX_ERROR, >=, expected_cnt);
    532        g_assert_cmphex(cnt, <=, expected_cnt + MAX_ERROR);
    533        cr = mft_readw(qts, index, MFT_CRA);
    534        g_assert_cmphex(cnt, ==, cr);
    535    }
    536
    537    /* Verify rpm for fan B */
    538
    539    qtest_irq_intercept_out(qts, "/machine/soc/a9mpcore/gic");
    540}
    541
    542/* Check pwm registers can be reset to default value */
    543static void test_init(gconstpointer test_data)
    544{
    545    const TestData *td = test_data;
    546    QTestState *qts = qtest_init("-machine npcm750-evb");
    547    int module = pwm_module_index(td->module);
    548    int pwm = pwm_index(td->pwm);
    549
    550    g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
    551    g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
    552
    553    qtest_quit(qts);
    554}
    555
    556/* One-shot mode should not change frequency and duty cycle. */
    557static void test_oneshot(gconstpointer test_data)
    558{
    559    const TestData *td = test_data;
    560    QTestState *qts = qtest_init("-machine npcm750-evb");
    561    int module = pwm_module_index(td->module);
    562    int pwm = pwm_index(td->pwm);
    563    uint32_t ppr, csr, pcr;
    564    int i, j;
    565
    566    pcr = CH_EN;
    567    for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
    568        ppr = ppr_list[i];
    569        pwm_write_ppr(qts, td, ppr);
    570
    571        for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
    572            csr = csr_list[j];
    573            pwm_write_csr(qts, td, csr);
    574            pwm_write_pcr(qts, td, pcr);
    575
    576            g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
    577            g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
    578            g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
    579            g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
    580            g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
    581        }
    582    }
    583
    584    qtest_quit(qts);
    585}
    586
    587/* In toggle mode, the PWM generates correct outputs. */
    588static void test_toggle(gconstpointer test_data)
    589{
    590    const TestData *td = test_data;
    591    QTestState *qts = qtest_init("-machine npcm750-evb");
    592    int module = pwm_module_index(td->module);
    593    int pwm = pwm_index(td->pwm);
    594    uint32_t ppr, csr, pcr, cnr, cmr;
    595    int i, j, k, l;
    596    uint64_t expected_freq, expected_duty;
    597
    598    mft_init(qts, td);
    599
    600    pcr = CH_EN | CH_MOD;
    601    for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
    602        ppr = ppr_list[i];
    603        pwm_write_ppr(qts, td, ppr);
    604
    605        for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
    606            csr = csr_list[j];
    607            pwm_write_csr(qts, td, csr);
    608
    609            for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
    610                cnr = cnr_list[k];
    611                pwm_write_cnr(qts, td, cnr);
    612
    613                for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
    614                    cmr = cmr_list[l];
    615                    pwm_write_cmr(qts, td, cmr);
    616                    expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
    617                    expected_duty = pwm_compute_duty(cnr, cmr, false);
    618
    619                    pwm_write_pcr(qts, td, pcr);
    620                    g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
    621                    g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
    622                    g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
    623                    g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
    624                    g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
    625                    g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
    626                            ==, expected_duty);
    627                    if (expected_duty != 0 && expected_duty != 100) {
    628                        /* Duty cycle with 0 or 100 doesn't need frequency. */
    629                        g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
    630                                ==, expected_freq);
    631                    }
    632
    633                    /* Test MFT's RPM is correct. */
    634                    mft_verify_rpm(qts, td, expected_duty);
    635
    636                    /* Test inverted mode */
    637                    expected_duty = pwm_compute_duty(cnr, cmr, true);
    638                    pwm_write_pcr(qts, td, pcr | CH_INV);
    639                    g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
    640                    g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
    641                            ==, expected_duty);
    642                    if (expected_duty != 0 && expected_duty != 100) {
    643                        /* Duty cycle with 0 or 100 doesn't need frequency. */
    644                        g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
    645                                ==, expected_freq);
    646                    }
    647
    648                }
    649            }
    650        }
    651    }
    652
    653    qtest_quit(qts);
    654}
    655
    656static void pwm_add_test(const char *name, const TestData* td,
    657        GTestDataFunc fn)
    658{
    659    g_autofree char *full_name = g_strdup_printf(
    660            "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
    661            pwm_index(td->pwm), name);
    662    qtest_add_data_func(full_name, td, fn);
    663}
    664#define add_test(name, td) pwm_add_test(#name, td, test_##name)
    665
    666int main(int argc, char **argv)
    667{
    668    TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
    669
    670    g_test_init(&argc, &argv, NULL);
    671
    672    for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
    673        for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
    674            TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
    675
    676            td->module = &pwm_module_list[i];
    677            td->pwm = &pwm_list[j];
    678
    679            add_test(init, td);
    680            add_test(oneshot, td);
    681            add_test(toggle, td);
    682        }
    683    }
    684
    685    return g_test_run();
    686}