2 * QTests for Nuvoton NPCM7xx PWM Modules.
4 * Copyright 2020 Google LLC
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.
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
17 #include "qemu/osdep.h"
18 #include "qemu/bitops.h"
20 #include "qapi/qmp/qdict.h"
21 #include "qapi/qmp/qnum.h"
23 static int verbosity_level
;
25 #define REF_HZ 25000000
27 /* Register field definitions. */
32 /* Registers shared between all PWMs in a module */
39 /* CLK module related */
40 #define CLK_BA 0xf0801000
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)
56 #define MAX_DUTY 1000000
58 /* MFT (PWM fan) related */
59 #define MFT_BA(n) (0xf0180000 + ((n) * 0x1000))
60 #define MFT_IRQ(n) (96 + (n))
67 #define MFT_MCTRL 0x0c
68 #define MFT_ICTRL 0x0e
73 #define MFT_CPCFG 0x18
74 #define MFT_INASEL 0x1a
75 #define MFT_INBSEL 0x1c
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
82 #define MFT_CKC_C2CSEL BIT(3)
83 #define MFT_CKC_C1CSEL BIT(0)
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)
92 #define MFT_MAX_CNT 0xffff
93 #define MFT_TIMEOUT 0x5000
95 #define DEFAULT_RPM 19800
96 #define DEFAULT_PRSC 255
97 #define MFT_PULSE_PER_REVOLUTION 2
101 typedef struct PWMModule
{
110 uint32_t pwdr_offset
;
113 typedef struct TestData
{
114 const PWMModule
*module
;
118 static const PWMModule pwm_module_list
[] = {
121 .base_addr
= 0xf0103000
125 .base_addr
= 0xf0104000
129 static const PWM pwm_list
[] = {
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 };
160 static const uint32_t ppr_list
[] = {
165 255, /* Max possible value. */
168 static const uint32_t csr_list
[] = {
173 4, /* Max possible value. */
176 static const uint32_t cnr_list
[] = {
185 65535, /* Max possible value. */
188 static const uint32_t cmr_list
[] = {
198 65535, /* Max possible value. */
201 /* Returns the index of the PWM module. */
202 static int pwm_module_index(const PWMModule
*module
)
204 ptrdiff_t diff
= module
- pwm_module_list
;
206 g_assert(diff
>= 0 && diff
< ARRAY_SIZE(pwm_module_list
));
211 /* Returns the index of the PWM entry. */
212 static int pwm_index(const PWM
*pwm
)
214 ptrdiff_t diff
= pwm
- pwm_list
;
216 g_assert(diff
>= 0 && diff
< ARRAY_SIZE(pwm_list
));
221 static uint64_t pwm_qom_get(QTestState
*qts
, const char *path
, const char *name
)
226 if (verbosity_level
>= 2) {
227 g_test_message("Getting properties %s from %s", name
, path
);
229 response
= qtest_qmp(qts
, "{ 'execute': 'qom-get',"
230 " 'arguments': { 'path': %s, 'property': %s}}",
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
);
239 static uint64_t pwm_get_freq(QTestState
*qts
, int module_index
, int pwm_index
)
244 sprintf(path
, "/machine/soc/pwm[%d]", module_index
);
245 sprintf(name
, "freq[%d]", pwm_index
);
247 return pwm_qom_get(qts
, path
, name
);
250 static uint64_t pwm_get_duty(QTestState
*qts
, int module_index
, int pwm_index
)
255 sprintf(path
, "/machine/soc/pwm[%d]", module_index
);
256 sprintf(name
, "duty[%d]", pwm_index
);
258 return pwm_qom_get(qts
, path
, name
);
261 static void mft_qom_set(QTestState
*qts
, int index
, const char *name
,
265 char *path
= g_strdup_printf("/machine/soc/mft[%d]", index
);
267 if (verbosity_level
>= 2) {
268 g_test_message("Setting properties %s of mft[%d] with value %u",
271 response
= qtest_qmp(qts
, "{ 'execute': 'qom-set',"
272 " 'arguments': { 'path': %s, "
273 " 'property': %s, 'value': %u}}",
275 /* The qom set message returns successfully. */
276 g_assert_true(qdict_haskey(response
, "return"));
278 qobject_unref(response
);
282 static uint32_t get_pll(uint32_t con
)
284 return REF_HZ
* PLL_FBDV(con
) / (PLL_INDV(con
) * PLL_OTDV1(con
)
288 static uint64_t read_pclk(QTestState
*qts
, bool mft
)
290 uint64_t freq
= REF_HZ
;
291 uint32_t clksel
= qtest_readl(qts
, CLK_BA
+ CLKSEL
);
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
);
297 switch (CPUCKSEL(clksel
)) {
299 pllcon
= qtest_readl(qts
, CLK_BA
+ PLLCON0
);
300 freq
= get_pll(pllcon
);
303 pllcon
= qtest_readl(qts
, CLK_BA
+ PLLCON1
);
304 freq
= get_pll(pllcon
);
311 g_assert_not_reached();
314 freq
>>= (CLK2CKDIV(clkdiv1
) + CLK4CKDIV(clkdiv1
) + apbdiv
);
319 static uint32_t pwm_selector(uint32_t csr
)
333 g_assert_not_reached();
337 static uint64_t pwm_compute_freq(QTestState
*qts
, uint32_t ppr
, uint32_t csr
,
340 return read_pclk(qts
, false) / ((ppr
+ 1) * pwm_selector(csr
) * (cnr
+ 1));
343 static uint64_t pwm_compute_duty(uint32_t cnr
, uint32_t cmr
, bool inverted
)
348 /* PWM is stopped. */
350 } else if (cmr
>= cnr
) {
353 duty
= (uint64_t)MAX_DUTY
* (cmr
+ 1) / (cnr
+ 1);
357 duty
= MAX_DUTY
- duty
;
363 static uint32_t pwm_read(QTestState
*qts
, const TestData
*td
, unsigned offset
)
365 return qtest_readl(qts
, td
->module
->base_addr
+ offset
);
368 static void pwm_write(QTestState
*qts
, const TestData
*td
, unsigned offset
,
371 qtest_writel(qts
, td
->module
->base_addr
+ offset
, value
);
374 static uint8_t mft_readb(QTestState
*qts
, int index
, unsigned offset
)
376 return qtest_readb(qts
, MFT_BA(index
) + offset
);
379 static uint16_t mft_readw(QTestState
*qts
, int index
, unsigned offset
)
381 return qtest_readw(qts
, MFT_BA(index
) + offset
);
384 static void mft_writeb(QTestState
*qts
, int index
, unsigned offset
,
387 qtest_writeb(qts
, MFT_BA(index
) + offset
, value
);
390 static void mft_writew(QTestState
*qts
, int index
, unsigned offset
,
393 return qtest_writew(qts
, MFT_BA(index
) + offset
, value
);
396 static uint32_t pwm_read_ppr(QTestState
*qts
, const TestData
*td
)
398 return extract32(pwm_read(qts
, td
, PPR
), ppr_base
[pwm_index(td
->pwm
)], 8);
401 static void pwm_write_ppr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
403 pwm_write(qts
, td
, PPR
, value
<< ppr_base
[pwm_index(td
->pwm
)]);
406 static uint32_t pwm_read_csr(QTestState
*qts
, const TestData
*td
)
408 return extract32(pwm_read(qts
, td
, CSR
), csr_base
[pwm_index(td
->pwm
)], 3);
411 static void pwm_write_csr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
413 pwm_write(qts
, td
, CSR
, value
<< csr_base
[pwm_index(td
->pwm
)]);
416 static uint32_t pwm_read_pcr(QTestState
*qts
, const TestData
*td
)
418 return extract32(pwm_read(qts
, td
, PCR
), pcr_base
[pwm_index(td
->pwm
)], 4);
421 static void pwm_write_pcr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
423 pwm_write(qts
, td
, PCR
, value
<< pcr_base
[pwm_index(td
->pwm
)]);
426 static uint32_t pwm_read_cnr(QTestState
*qts
, const TestData
*td
)
428 return pwm_read(qts
, td
, td
->pwm
->cnr_offset
);
431 static void pwm_write_cnr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
433 pwm_write(qts
, td
, td
->pwm
->cnr_offset
, value
);
436 static uint32_t pwm_read_cmr(QTestState
*qts
, const TestData
*td
)
438 return pwm_read(qts
, td
, td
->pwm
->cmr_offset
);
441 static void pwm_write_cmr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
443 pwm_write(qts
, td
, td
->pwm
->cmr_offset
, value
);
446 static int mft_compute_index(const TestData
*td
)
448 int index
= pwm_module_index(td
->module
) * ARRAY_SIZE(pwm_list
) +
451 g_assert_cmpint(index
, <,
452 ARRAY_SIZE(pwm_module_list
) * ARRAY_SIZE(pwm_list
));
457 static void mft_reset_counters(QTestState
*qts
, int index
)
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
);
467 static void mft_init(QTestState
*qts
, const TestData
*td
)
469 int index
= mft_compute_index(td
);
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);
479 /* Set cpcfg to use EQ mode, same as kernel driver */
480 mft_writeb(qts
, index
, MFT_CPCFG
, MFT_CPCFG_EQ_MODE
);
482 /* Write default counters, timeout and prescaler */
483 mft_reset_counters(qts
, index
);
484 mft_writeb(qts
, index
, MFT_PRSC
, DEFAULT_PRSC
);
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
);
491 static int32_t mft_compute_cnt(uint32_t rpm
, uint64_t clk
)
499 cnt
= clk
* 60 / ((DEFAULT_PRSC
+ 1) * rpm
* MFT_PULSE_PER_REVOLUTION
);
500 if (cnt
>= MFT_TIMEOUT
) {
503 return MFT_MAX_CNT
- cnt
;
506 static void mft_verify_rpm(QTestState
*qts
, const TestData
*td
, uint64_t duty
)
508 int index
= mft_compute_index(td
);
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
);
514 qtest_irq_intercept_in(qts
, "/machine/soc/a9mpcore/gic");
515 if (verbosity_level
>= 2) {
517 "verifying rpm for mft[%d]: clk: %" PRIu64
", duty: %" PRIu64
518 ", rpm: %u, cnt: %d",
519 index
, clk
, duty
, rpm
, expected_cnt
);
522 /* Verify rpm for fan A */
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
);
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
);
537 g_assert_cmphex(mft_readb(qts
, index
, MFT_ICTRL
), ==, MFT_ICTRL_TAPND
);
538 cnt
= mft_readw(qts
, index
, MFT_CNT1
);
540 * Due to error in clock measurement and rounding, we might have a small
541 * error in measuring RPM.
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
);
549 /* Verify rpm for fan B */
551 qtest_irq_intercept_out(qts
, "/machine/soc/a9mpcore/gic");
554 /* Check pwm registers can be reset to default value */
555 static void test_init(gconstpointer test_data
)
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
);
562 g_assert_cmpuint(pwm_get_freq(qts
, module
, pwm
), ==, 0);
563 g_assert_cmpuint(pwm_get_duty(qts
, module
, pwm
), ==, 0);
568 /* One-shot mode should not change frequency and duty cycle. */
569 static void test_oneshot(gconstpointer test_data
)
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
;
579 for (i
= 0; i
< ARRAY_SIZE(ppr_list
); ++i
) {
581 pwm_write_ppr(qts
, td
, ppr
);
583 for (j
= 0; j
< ARRAY_SIZE(csr_list
); ++j
) {
585 pwm_write_csr(qts
, td
, csr
);
586 pwm_write_pcr(qts
, td
, pcr
);
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);
599 /* In toggle mode, the PWM generates correct outputs. */
600 static void test_toggle(gconstpointer test_data
)
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
;
608 uint64_t expected_freq
, expected_duty
;
609 int cnr_step
= g_test_quick() ? 2 : 1;
613 pcr
= CH_EN
| CH_MOD
;
614 for (i
= 0; i
< ARRAY_SIZE(ppr_list
); ++i
) {
616 pwm_write_ppr(qts
, td
, ppr
);
618 for (j
= 0; j
< ARRAY_SIZE(csr_list
); ++j
) {
620 pwm_write_csr(qts
, td
, csr
);
622 for (k
= 0; k
< ARRAY_SIZE(cnr_list
); k
+= cnr_step
) {
624 pwm_write_cnr(qts
, td
, cnr
);
626 for (l
= 0; l
< ARRAY_SIZE(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);
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
),
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
),
646 /* Test MFT's RPM is correct. */
647 mft_verify_rpm(qts
, td
, expected_duty
);
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
),
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
),
669 static void pwm_add_test(const char *name
, const TestData
* td
,
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
);
677 #define add_test(name, td) pwm_add_test(#name, td, test_##name)
679 int main(int argc
, char **argv
)
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;
684 char *v_env
= getenv("V");
687 verbosity_level
= atoi(v_env
);
690 g_test_init(&argc
, &argv
, NULL
);
692 if (!g_test_quick()) {
693 pwm_module_list_cnt
= ARRAY_SIZE(pwm_module_list
);
694 pwm_list_cnt
= ARRAY_SIZE(pwm_list
);
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
];
701 td
->module
= &pwm_module_list
[i
];
702 td
->pwm
= &pwm_list
[j
];
705 add_test(oneshot
, td
);
706 add_test(toggle
, td
);