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