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"
19 #include "libqos/libqtest.h"
20 #include "qapi/qmp/qdict.h"
21 #include "qapi/qmp/qnum.h"
23 #define REF_HZ 25000000
25 /* Register field definitions. */
30 /* Registers shared between all PWMs in a module */
37 /* CLK module related */
38 #define CLK_BA 0xf0801000
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 APB3CKDIV(rv) extract32((rv), 28, 2)
49 #define CLK2CKDIV(rv) extract32((rv), 0, 1)
50 #define CLK4CKDIV(rv) extract32((rv), 26, 2)
51 #define CPUCKSEL(rv) extract32((rv), 0, 2)
53 #define MAX_DUTY 1000000
55 typedef struct PWMModule
{
67 typedef struct TestData
{
68 const PWMModule
*module
;
72 static const PWMModule pwm_module_list
[] = {
75 .base_addr
= 0xf0103000
79 .base_addr
= 0xf0104000
83 static const PWM pwm_list
[] = {
110 static const int ppr_base
[] = { 0, 0, 8, 8 };
111 static const int csr_base
[] = { 0, 4, 8, 12 };
112 static const int pcr_base
[] = { 0, 8, 12, 16 };
114 static const uint32_t ppr_list
[] = {
119 255, /* Max possible value. */
122 static const uint32_t csr_list
[] = {
127 4, /* Max possible value. */
130 static const uint32_t cnr_list
[] = {
139 65535, /* Max possible value. */
142 static const uint32_t cmr_list
[] = {
152 65535, /* Max possible value. */
155 /* Returns the index of the PWM module. */
156 static int pwm_module_index(const PWMModule
*module
)
158 ptrdiff_t diff
= module
- pwm_module_list
;
160 g_assert_true(diff
>= 0 && diff
< ARRAY_SIZE(pwm_module_list
));
165 /* Returns the index of the PWM entry. */
166 static int pwm_index(const PWM
*pwm
)
168 ptrdiff_t diff
= pwm
- pwm_list
;
170 g_assert_true(diff
>= 0 && diff
< ARRAY_SIZE(pwm_list
));
175 static uint64_t pwm_qom_get(QTestState
*qts
, const char *path
, const char *name
)
180 g_test_message("Getting properties %s from %s", name
, path
);
181 response
= qtest_qmp(qts
, "{ 'execute': 'qom-get',"
182 " 'arguments': { 'path': %s, 'property': %s}}",
184 /* The qom set message returns successfully. */
185 g_assert_true(qdict_haskey(response
, "return"));
186 val
= qnum_get_uint(qobject_to(QNum
, qdict_get(response
, "return")));
187 qobject_unref(response
);
191 static uint64_t pwm_get_freq(QTestState
*qts
, int module_index
, int pwm_index
)
196 sprintf(path
, "/machine/soc/pwm[%d]", module_index
);
197 sprintf(name
, "freq[%d]", pwm_index
);
199 return pwm_qom_get(qts
, path
, name
);
202 static uint64_t pwm_get_duty(QTestState
*qts
, int module_index
, int pwm_index
)
207 sprintf(path
, "/machine/soc/pwm[%d]", module_index
);
208 sprintf(name
, "duty[%d]", pwm_index
);
210 return pwm_qom_get(qts
, path
, name
);
213 static uint32_t get_pll(uint32_t con
)
215 return REF_HZ
* PLL_FBDV(con
) / (PLL_INDV(con
) * PLL_OTDV1(con
)
219 static uint64_t read_pclk(QTestState
*qts
)
221 uint64_t freq
= REF_HZ
;
222 uint32_t clksel
= qtest_readl(qts
, CLK_BA
+ CLKSEL
);
224 uint32_t clkdiv1
= qtest_readl(qts
, CLK_BA
+ CLKDIV1
);
225 uint32_t clkdiv2
= qtest_readl(qts
, CLK_BA
+ CLKDIV2
);
227 switch (CPUCKSEL(clksel
)) {
229 pllcon
= qtest_readl(qts
, CLK_BA
+ PLLCON0
);
230 freq
= get_pll(pllcon
);
233 pllcon
= qtest_readl(qts
, CLK_BA
+ PLLCON1
);
234 freq
= get_pll(pllcon
);
241 g_assert_not_reached();
244 freq
>>= (CLK2CKDIV(clkdiv1
) + CLK4CKDIV(clkdiv1
) + APB3CKDIV(clkdiv2
));
249 static uint32_t pwm_selector(uint32_t csr
)
263 g_assert_not_reached();
267 static uint64_t pwm_compute_freq(QTestState
*qts
, uint32_t ppr
, uint32_t csr
,
270 return read_pclk(qts
) / ((ppr
+ 1) * pwm_selector(csr
) * (cnr
+ 1));
273 static uint64_t pwm_compute_duty(uint32_t cnr
, uint32_t cmr
, bool inverted
)
278 /* PWM is stopped. */
280 } else if (cmr
>= cnr
) {
283 duty
= (uint64_t)MAX_DUTY
* (cmr
+ 1) / (cnr
+ 1);
287 duty
= MAX_DUTY
- duty
;
293 static uint32_t pwm_read(QTestState
*qts
, const TestData
*td
, unsigned offset
)
295 return qtest_readl(qts
, td
->module
->base_addr
+ offset
);
298 static void pwm_write(QTestState
*qts
, const TestData
*td
, unsigned offset
,
301 qtest_writel(qts
, td
->module
->base_addr
+ offset
, value
);
304 static uint32_t pwm_read_ppr(QTestState
*qts
, const TestData
*td
)
306 return extract32(pwm_read(qts
, td
, PPR
), ppr_base
[pwm_index(td
->pwm
)], 8);
309 static void pwm_write_ppr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
311 pwm_write(qts
, td
, PPR
, value
<< ppr_base
[pwm_index(td
->pwm
)]);
314 static uint32_t pwm_read_csr(QTestState
*qts
, const TestData
*td
)
316 return extract32(pwm_read(qts
, td
, CSR
), csr_base
[pwm_index(td
->pwm
)], 3);
319 static void pwm_write_csr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
321 pwm_write(qts
, td
, CSR
, value
<< csr_base
[pwm_index(td
->pwm
)]);
324 static uint32_t pwm_read_pcr(QTestState
*qts
, const TestData
*td
)
326 return extract32(pwm_read(qts
, td
, PCR
), pcr_base
[pwm_index(td
->pwm
)], 4);
329 static void pwm_write_pcr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
331 pwm_write(qts
, td
, PCR
, value
<< pcr_base
[pwm_index(td
->pwm
)]);
334 static uint32_t pwm_read_cnr(QTestState
*qts
, const TestData
*td
)
336 return pwm_read(qts
, td
, td
->pwm
->cnr_offset
);
339 static void pwm_write_cnr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
341 pwm_write(qts
, td
, td
->pwm
->cnr_offset
, value
);
344 static uint32_t pwm_read_cmr(QTestState
*qts
, const TestData
*td
)
346 return pwm_read(qts
, td
, td
->pwm
->cmr_offset
);
349 static void pwm_write_cmr(QTestState
*qts
, const TestData
*td
, uint32_t value
)
351 pwm_write(qts
, td
, td
->pwm
->cmr_offset
, value
);
354 /* Check pwm registers can be reset to default value */
355 static void test_init(gconstpointer test_data
)
357 const TestData
*td
= test_data
;
358 QTestState
*qts
= qtest_init("-machine quanta-gsj");
359 int module
= pwm_module_index(td
->module
);
360 int pwm
= pwm_index(td
->pwm
);
362 g_assert_cmpuint(pwm_get_freq(qts
, module
, pwm
), ==, 0);
363 g_assert_cmpuint(pwm_get_duty(qts
, module
, pwm
), ==, 0);
368 /* One-shot mode should not change frequency and duty cycle. */
369 static void test_oneshot(gconstpointer test_data
)
371 const TestData
*td
= test_data
;
372 QTestState
*qts
= qtest_init("-machine quanta-gsj");
373 int module
= pwm_module_index(td
->module
);
374 int pwm
= pwm_index(td
->pwm
);
375 uint32_t ppr
, csr
, pcr
;
379 for (i
= 0; i
< ARRAY_SIZE(ppr_list
); ++i
) {
381 pwm_write_ppr(qts
, td
, ppr
);
383 for (j
= 0; j
< ARRAY_SIZE(csr_list
); ++j
) {
385 pwm_write_csr(qts
, td
, csr
);
386 pwm_write_pcr(qts
, td
, pcr
);
388 g_assert_cmpuint(pwm_read_ppr(qts
, td
), ==, ppr
);
389 g_assert_cmpuint(pwm_read_csr(qts
, td
), ==, csr
);
390 g_assert_cmpuint(pwm_read_pcr(qts
, td
), ==, pcr
);
391 g_assert_cmpuint(pwm_get_freq(qts
, module
, pwm
), ==, 0);
392 g_assert_cmpuint(pwm_get_duty(qts
, module
, pwm
), ==, 0);
399 /* In toggle mode, the PWM generates correct outputs. */
400 static void test_toggle(gconstpointer test_data
)
402 const TestData
*td
= test_data
;
403 QTestState
*qts
= qtest_init("-machine quanta-gsj");
404 int module
= pwm_module_index(td
->module
);
405 int pwm
= pwm_index(td
->pwm
);
406 uint32_t ppr
, csr
, pcr
, cnr
, cmr
;
408 uint64_t expected_freq
, expected_duty
;
410 pcr
= CH_EN
| CH_MOD
;
411 for (i
= 0; i
< ARRAY_SIZE(ppr_list
); ++i
) {
413 pwm_write_ppr(qts
, td
, ppr
);
415 for (j
= 0; j
< ARRAY_SIZE(csr_list
); ++j
) {
417 pwm_write_csr(qts
, td
, csr
);
419 for (k
= 0; k
< ARRAY_SIZE(cnr_list
); ++k
) {
421 pwm_write_cnr(qts
, td
, cnr
);
423 for (l
= 0; l
< ARRAY_SIZE(cmr_list
); ++l
) {
425 pwm_write_cmr(qts
, td
, cmr
);
426 expected_freq
= pwm_compute_freq(qts
, ppr
, csr
, cnr
);
427 expected_duty
= pwm_compute_duty(cnr
, cmr
, false);
429 pwm_write_pcr(qts
, td
, pcr
);
430 g_assert_cmpuint(pwm_read_ppr(qts
, td
), ==, ppr
);
431 g_assert_cmpuint(pwm_read_csr(qts
, td
), ==, csr
);
432 g_assert_cmpuint(pwm_read_pcr(qts
, td
), ==, pcr
);
433 g_assert_cmpuint(pwm_read_cnr(qts
, td
), ==, cnr
);
434 g_assert_cmpuint(pwm_read_cmr(qts
, td
), ==, cmr
);
435 g_assert_cmpuint(pwm_get_duty(qts
, module
, pwm
),
437 if (expected_duty
!= 0 && expected_duty
!= 100) {
438 /* Duty cycle with 0 or 100 doesn't need frequency. */
439 g_assert_cmpuint(pwm_get_freq(qts
, module
, pwm
),
443 /* Test inverted mode */
444 expected_duty
= pwm_compute_duty(cnr
, cmr
, true);
445 pwm_write_pcr(qts
, td
, pcr
| CH_INV
);
446 g_assert_cmpuint(pwm_read_pcr(qts
, td
), ==, pcr
| CH_INV
);
447 g_assert_cmpuint(pwm_get_duty(qts
, module
, pwm
),
449 if (expected_duty
!= 0 && expected_duty
!= 100) {
450 /* Duty cycle with 0 or 100 doesn't need frequency. */
451 g_assert_cmpuint(pwm_get_freq(qts
, module
, pwm
),
463 static void pwm_add_test(const char *name
, const TestData
* td
,
466 g_autofree
char *full_name
= g_strdup_printf(
467 "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td
->module
),
468 pwm_index(td
->pwm
), name
);
469 qtest_add_data_func(full_name
, td
, fn
);
471 #define add_test(name, td) pwm_add_test(#name, td, test_##name)
473 int main(int argc
, char **argv
)
475 TestData test_data_list
[ARRAY_SIZE(pwm_module_list
) * ARRAY_SIZE(pwm_list
)];
477 g_test_init(&argc
, &argv
, NULL
);
479 for (int i
= 0; i
< ARRAY_SIZE(pwm_module_list
); ++i
) {
480 for (int j
= 0; j
< ARRAY_SIZE(pwm_list
); ++j
) {
481 TestData
*td
= &test_data_list
[i
* ARRAY_SIZE(pwm_list
) + j
];
483 td
->module
= &pwm_module_list
[i
];
484 td
->pwm
= &pwm_list
[j
];
487 add_test(oneshot
, td
);
488 add_test(toggle
, td
);