qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

npcm7xx_pwm-test.c (19541B)


      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 
     99 typedef struct PWMModule {
    100     int irq;
    101     uint64_t base_addr;
    102 } PWMModule;
    103 
    104 typedef 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 
    111 typedef struct TestData {
    112     const PWMModule *module;
    113     const PWM *pwm;
    114 } TestData;
    115 
    116 static 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 
    127 static 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 
    154 static const int ppr_base[] = { 0, 0, 8, 8 };
    155 static const int csr_base[] = { 0, 4, 8, 12 };
    156 static const int pcr_base[] = { 0, 8, 12, 16 };
    157 
    158 static const uint32_t ppr_list[] = {
    159     0,
    160     1,
    161     10,
    162     100,
    163     255, /* Max possible value. */
    164 };
    165 
    166 static const uint32_t csr_list[] = {
    167     0,
    168     1,
    169     2,
    170     3,
    171     4, /* Max possible value. */
    172 };
    173 
    174 static 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 
    186 static 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. */
    200 static 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. */
    210 static 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 
    219 static 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 
    235 static 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 
    246 static 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 
    257 static 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 
    276 static 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 
    282 static 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 
    313 static 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 
    331 static 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 
    337 static 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 
    357 static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
    358 {
    359     return qtest_readl(qts, td->module->base_addr + offset);
    360 }
    361 
    362 static 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 
    368 static uint8_t mft_readb(QTestState *qts, int index, unsigned offset)
    369 {
    370     return qtest_readb(qts, MFT_BA(index) + offset);
    371 }
    372 
    373 static uint16_t mft_readw(QTestState *qts, int index, unsigned offset)
    374 {
    375     return qtest_readw(qts, MFT_BA(index) + offset);
    376 }
    377 
    378 static 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 
    384 static 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 
    390 static 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 
    395 static 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 
    400 static 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 
    405 static 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 
    410 static 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 
    415 static 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 
    420 static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
    421 {
    422     return pwm_read(qts, td, td->pwm->cnr_offset);
    423 }
    424 
    425 static 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 
    430 static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
    431 {
    432     return pwm_read(qts, td, td->pwm->cmr_offset);
    433 }
    434 
    435 static 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 
    440 static 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 
    451 static 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 
    461 static 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 
    485 static 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 
    500 static 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 */
    546 static 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. */
    560 static 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. */
    591 static 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 
    659 static 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 
    669 int 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 }