All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Subject: [PULL 30/39] tests/qtest: Test PWM fan RPM using MFT in PWM test
Date: Fri, 12 Mar 2021 13:51:31 +0000	[thread overview]
Message-ID: <20210312135140.1099-31-peter.maydell@linaro.org> (raw)
In-Reply-To: <20210312135140.1099-1-peter.maydell@linaro.org>

From: Hao Wu <wuhaotsh@google.com>

This patch adds testing of PWM fan RPMs in the existing npcm7xx pwm
test. It tests whether the MFT module can measure correct fan values
for a PWM fan in NPCM7XX boards.

Reviewed-by: Doug Evans <dje@google.com>
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Signed-off-by: Hao Wu <wuhaotsh@google.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20210311180855.149764-6-wuhaotsh@google.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 tests/qtest/npcm7xx_pwm-test.c | 205 ++++++++++++++++++++++++++++++++-
 1 file changed, 199 insertions(+), 6 deletions(-)

diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
index 3d82654b81a..72317f4c812 100644
--- a/tests/qtest/npcm7xx_pwm-test.c
+++ b/tests/qtest/npcm7xx_pwm-test.c
@@ -45,6 +45,7 @@
 #define PLL_FBDV(rv)    extract32((rv), 16, 12)
 #define PLL_OTDV1(rv)   extract32((rv), 8, 3)
 #define PLL_OTDV2(rv)   extract32((rv), 13, 3)
+#define APB4CKDIV(rv)   extract32((rv), 30, 2)
 #define APB3CKDIV(rv)   extract32((rv), 28, 2)
 #define CLK2CKDIV(rv)   extract32((rv), 0, 1)
 #define CLK4CKDIV(rv)   extract32((rv), 26, 2)
@@ -52,6 +53,49 @@
 
 #define MAX_DUTY        1000000
 
+/* MFT (PWM fan) related */
+#define MFT_BA(n)       (0xf0180000 + ((n) * 0x1000))
+#define MFT_IRQ(n)      (96 + (n))
+#define MFT_CNT1        0x00
+#define MFT_CRA         0x02
+#define MFT_CRB         0x04
+#define MFT_CNT2        0x06
+#define MFT_PRSC        0x08
+#define MFT_CKC         0x0a
+#define MFT_MCTRL       0x0c
+#define MFT_ICTRL       0x0e
+#define MFT_ICLR        0x10
+#define MFT_IEN         0x12
+#define MFT_CPA         0x14
+#define MFT_CPB         0x16
+#define MFT_CPCFG       0x18
+#define MFT_INASEL      0x1a
+#define MFT_INBSEL      0x1c
+
+#define MFT_MCTRL_ALL   0x64
+#define MFT_ICLR_ALL    0x3f
+#define MFT_IEN_ALL     0x3f
+#define MFT_CPCFG_EQ_MODE 0x44
+
+#define MFT_CKC_C2CSEL  BIT(3)
+#define MFT_CKC_C1CSEL  BIT(0)
+
+#define MFT_ICTRL_TFPND BIT(5)
+#define MFT_ICTRL_TEPND BIT(4)
+#define MFT_ICTRL_TDPND BIT(3)
+#define MFT_ICTRL_TCPND BIT(2)
+#define MFT_ICTRL_TBPND BIT(1)
+#define MFT_ICTRL_TAPND BIT(0)
+
+#define MFT_MAX_CNT     0xffff
+#define MFT_TIMEOUT     0x5000
+
+#define DEFAULT_RPM     19800
+#define DEFAULT_PRSC    255
+#define MFT_PULSE_PER_REVOLUTION 2
+
+#define MAX_ERROR       1
+
 typedef struct PWMModule {
     int irq;
     uint64_t base_addr;
@@ -210,19 +254,36 @@ static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
     return pwm_qom_get(qts, path, name);
 }
 
+static void mft_qom_set(QTestState *qts, int index, const char *name,
+                        uint32_t value)
+{
+    QDict *response;
+    char *path = g_strdup_printf("/machine/soc/mft[%d]", index);
+
+    g_test_message("Setting properties %s of mft[%d] with value %u",
+                   name, index, value);
+    response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
+            " 'arguments': { 'path': %s, "
+            " 'property': %s, 'value': %u}}",
+            path, name, value);
+    /* The qom set message returns successfully. */
+    g_assert_true(qdict_haskey(response, "return"));
+}
+
 static uint32_t get_pll(uint32_t con)
 {
     return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
             * PLL_OTDV2(con));
 }
 
-static uint64_t read_pclk(QTestState *qts)
+static uint64_t read_pclk(QTestState *qts, bool mft)
 {
     uint64_t freq = REF_HZ;
     uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
     uint32_t pllcon;
     uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
     uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
+    uint32_t apbdiv = mft ? APB4CKDIV(clkdiv2) : APB3CKDIV(clkdiv2);
 
     switch (CPUCKSEL(clksel)) {
     case 0:
@@ -241,7 +302,7 @@ static uint64_t read_pclk(QTestState *qts)
         g_assert_not_reached();
     }
 
-    freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
+    freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + apbdiv);
 
     return freq;
 }
@@ -267,7 +328,7 @@ static uint32_t pwm_selector(uint32_t csr)
 static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
         uint32_t cnr)
 {
-    return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
+    return read_pclk(qts, false) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
 }
 
 static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
@@ -301,6 +362,28 @@ static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
     qtest_writel(qts, td->module->base_addr + offset, value);
 }
 
+static uint8_t mft_readb(QTestState *qts, int index, unsigned offset)
+{
+    return qtest_readb(qts, MFT_BA(index) + offset);
+}
+
+static uint16_t mft_readw(QTestState *qts, int index, unsigned offset)
+{
+    return qtest_readw(qts, MFT_BA(index) + offset);
+}
+
+static void mft_writeb(QTestState *qts, int index, unsigned offset,
+                        uint8_t value)
+{
+    qtest_writeb(qts, MFT_BA(index) + offset, value);
+}
+
+static void mft_writew(QTestState *qts, int index, unsigned offset,
+                        uint16_t value)
+{
+    return qtest_writew(qts, MFT_BA(index) + offset, value);
+}
+
 static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
 {
     return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
@@ -351,11 +434,116 @@ static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
     pwm_write(qts, td, td->pwm->cmr_offset, value);
 }
 
+static int mft_compute_index(const TestData *td)
+{
+    int index = pwm_module_index(td->module) * ARRAY_SIZE(pwm_list) +
+                pwm_index(td->pwm);
+
+    g_assert_cmpint(index, <,
+                    ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list));
+
+    return index;
+}
+
+static void mft_reset_counters(QTestState *qts, int index)
+{
+    mft_writew(qts, index, MFT_CNT1, MFT_MAX_CNT);
+    mft_writew(qts, index, MFT_CNT2, MFT_MAX_CNT);
+    mft_writew(qts, index, MFT_CRA, MFT_MAX_CNT);
+    mft_writew(qts, index, MFT_CRB, MFT_MAX_CNT);
+    mft_writew(qts, index, MFT_CPA, MFT_MAX_CNT - MFT_TIMEOUT);
+    mft_writew(qts, index, MFT_CPB, MFT_MAX_CNT - MFT_TIMEOUT);
+}
+
+static void mft_init(QTestState *qts, const TestData *td)
+{
+    int index = mft_compute_index(td);
+
+    /* Enable everything */
+    mft_writeb(qts, index, MFT_CKC, 0);
+    mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
+    mft_writeb(qts, index, MFT_MCTRL, MFT_MCTRL_ALL);
+    mft_writeb(qts, index, MFT_IEN, MFT_IEN_ALL);
+    mft_writeb(qts, index, MFT_INASEL, 0);
+    mft_writeb(qts, index, MFT_INBSEL, 0);
+
+    /* Set cpcfg to use EQ mode, same as kernel driver */
+    mft_writeb(qts, index, MFT_CPCFG, MFT_CPCFG_EQ_MODE);
+
+    /* Write default counters, timeout and prescaler */
+    mft_reset_counters(qts, index);
+    mft_writeb(qts, index, MFT_PRSC, DEFAULT_PRSC);
+
+    /* Write default max rpm via QMP */
+    mft_qom_set(qts, index, "max_rpm[0]", DEFAULT_RPM);
+    mft_qom_set(qts, index, "max_rpm[1]", DEFAULT_RPM);
+}
+
+static int32_t mft_compute_cnt(uint32_t rpm, uint64_t clk)
+{
+    uint64_t cnt;
+
+    if (rpm == 0) {
+        return -1;
+    }
+
+    cnt = clk * 60 / ((DEFAULT_PRSC + 1) * rpm * MFT_PULSE_PER_REVOLUTION);
+    if (cnt >= MFT_TIMEOUT) {
+        return -1;
+    }
+    return MFT_MAX_CNT - cnt;
+}
+
+static void mft_verify_rpm(QTestState *qts, const TestData *td, uint64_t duty)
+{
+    int index = mft_compute_index(td);
+    uint16_t cnt, cr;
+    uint32_t rpm = DEFAULT_RPM * duty / MAX_DUTY;
+    uint64_t clk = read_pclk(qts, true);
+    int32_t expected_cnt = mft_compute_cnt(rpm, clk);
+
+    qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
+    g_test_message(
+        "verifying rpm for mft[%d]: clk: %lu, duty: %lu, rpm: %u, cnt: %d",
+        index, clk, duty, rpm, expected_cnt);
+
+    /* Verify rpm for fan A */
+    /* Stop capture */
+    mft_writeb(qts, index, MFT_CKC, 0);
+    mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
+    mft_reset_counters(qts, index);
+    g_assert_cmphex(mft_readw(qts, index, MFT_CNT1), ==, MFT_MAX_CNT);
+    g_assert_cmphex(mft_readw(qts, index, MFT_CRA), ==, MFT_MAX_CNT);
+    g_assert_cmphex(mft_readw(qts, index, MFT_CPA), ==,
+                    MFT_MAX_CNT - MFT_TIMEOUT);
+    /* Start capture */
+    mft_writeb(qts, index, MFT_CKC, MFT_CKC_C1CSEL);
+    g_assert_true(qtest_get_irq(qts, MFT_IRQ(index)));
+    if (expected_cnt == -1) {
+        g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TEPND);
+    } else {
+        g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TAPND);
+        cnt = mft_readw(qts, index, MFT_CNT1);
+        /*
+         * Due to error in clock measurement and rounding, we might have a small
+         * error in measuring RPM.
+         */
+        g_assert_cmphex(cnt + MAX_ERROR, >=, expected_cnt);
+        g_assert_cmphex(cnt, <=, expected_cnt + MAX_ERROR);
+        cr = mft_readw(qts, index, MFT_CRA);
+        g_assert_cmphex(cnt, ==, cr);
+    }
+
+    /* Verify rpm for fan B */
+
+    qtest_irq_intercept_out(qts, "/machine/soc/a9mpcore/gic");
+}
+
 /* Check pwm registers can be reset to default value */
 static void test_init(gconstpointer test_data)
 {
     const TestData *td = test_data;
-    QTestState *qts = qtest_init("-machine quanta-gsj");
+    QTestState *qts = qtest_init("-machine npcm750-evb");
     int module = pwm_module_index(td->module);
     int pwm = pwm_index(td->pwm);
 
@@ -369,7 +557,7 @@ static void test_init(gconstpointer test_data)
 static void test_oneshot(gconstpointer test_data)
 {
     const TestData *td = test_data;
-    QTestState *qts = qtest_init("-machine quanta-gsj");
+    QTestState *qts = qtest_init("-machine npcm750-evb");
     int module = pwm_module_index(td->module);
     int pwm = pwm_index(td->pwm);
     uint32_t ppr, csr, pcr;
@@ -400,13 +588,15 @@ static void test_oneshot(gconstpointer test_data)
 static void test_toggle(gconstpointer test_data)
 {
     const TestData *td = test_data;
-    QTestState *qts = qtest_init("-machine quanta-gsj");
+    QTestState *qts = qtest_init("-machine npcm750-evb");
     int module = pwm_module_index(td->module);
     int pwm = pwm_index(td->pwm);
     uint32_t ppr, csr, pcr, cnr, cmr;
     int i, j, k, l;
     uint64_t expected_freq, expected_duty;
 
+    mft_init(qts, td);
+
     pcr = CH_EN | CH_MOD;
     for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
         ppr = ppr_list[i];
@@ -440,6 +630,9 @@ static void test_toggle(gconstpointer test_data)
                                 ==, expected_freq);
                     }
 
+                    /* Test MFT's RPM is correct. */
+                    mft_verify_rpm(qts, td, expected_duty);
+
                     /* Test inverted mode */
                     expected_duty = pwm_compute_duty(cnr, cmr, true);
                     pwm_write_pcr(qts, td, pcr | CH_INV);
-- 
2.20.1



  parent reply	other threads:[~2021-03-12 14:17 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-12 13:51 [PULL 00/39] target-arm queue Peter Maydell
2021-03-12 13:51 ` [PULL 01/39] hw/misc: versal: Add a model of the XRAM controller Peter Maydell
2021-03-12 13:51 ` [PULL 02/39] hw/arm: versal: Add support for the XRAMs Peter Maydell
2021-03-12 13:51 ` [PULL 03/39] intel_iommu: Fix mask may be uninitialized in vtd_context_device_invalidate Peter Maydell
2021-03-12 13:51 ` [PULL 04/39] dma: Introduce dma_aligned_pow2_mask() Peter Maydell
2021-03-12 13:51 ` [PULL 05/39] virtio-iommu: Handle non power of 2 range invalidations Peter Maydell
2021-03-12 13:51 ` [PULL 06/39] hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set Peter Maydell
2021-03-12 13:51 ` [PULL 07/39] hw/arm/smmuv3: Enforce invalidation on a power of two range Peter Maydell
2021-03-12 13:51 ` [PULL 08/39] hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling Peter Maydell
2021-03-12 13:51 ` [PULL 09/39] hw/arm/smmuv3: Uniformize sid traces Peter Maydell
2021-03-12 13:51 ` [PULL 10/39] target/arm: Fix sve_uzp_p vs odd vector lengths Peter Maydell
2021-03-12 13:51 ` [PULL 11/39] target/arm: Fix sve_zip_p " Peter Maydell
2021-03-12 13:51 ` [PULL 12/39] target/arm: Fix sve_punpk_p " Peter Maydell
2021-03-12 13:51 ` [PULL 13/39] target/arm: Update find_last_active for PREDDESC Peter Maydell
2021-03-12 13:51 ` [PULL 14/39] target/arm: Update BRKA, BRKB, BRKN " Peter Maydell
2021-03-12 13:51 ` [PULL 15/39] target/arm: Update CNTP " Peter Maydell
2021-03-12 13:51 ` [PULL 16/39] target/arm: Update WHILE " Peter Maydell
2021-03-12 13:51 ` [PULL 17/39] target/arm: Update sve reduction vs simd_desc Peter Maydell
2021-03-12 13:51 ` [PULL 18/39] hw/net/allwinner-sun8i-emac: traverse transmit queue using TX_CUR_DESC register value Peter Maydell
2021-03-12 13:51 ` [PULL 19/39] tests/acceptance/boot_linux_console: remove Armbian 19.11.3 bionic test for orangepi-pc machine Peter Maydell
2021-03-12 13:51 ` [PULL 20/39] tests/acceptance/boot_linux_console: change URL for test_arm_orangepi_bionic_20_08 Peter Maydell
2021-03-12 13:51 ` [PULL 21/39] tests/acceptance: update sunxi kernel from armbian to 5.10.16 Peter Maydell
2021-03-12 13:51 ` [PULL 22/39] tests/acceptance: drop ARMBIAN_ARTIFACTS_CACHED condition for orangepi-pc, cubieboard tests Peter Maydell
2021-03-12 13:51 ` [PULL 23/39] hw/timer/sse-timer: Propagate eventual error in sse_timer_realize() Peter Maydell
2021-03-12 13:51 ` [PULL 24/39] accel: kvm: Fix kvm_type invocation Peter Maydell
2021-03-12 13:51 ` [PULL 25/39] hw/arm/virt: KVM: The IPA lower bound is 32 Peter Maydell
2021-03-12 13:51 ` [PULL 26/39] hw/misc: Add GPIOs for duty in NPCM7xx PWM Peter Maydell
2021-03-12 13:51 ` [PULL 27/39] hw/misc: Add NPCM7XX MFT Module Peter Maydell
2021-03-12 13:51 ` [PULL 28/39] hw/arm: Add MFT device to NPCM7xx Soc Peter Maydell
2021-03-12 13:51 ` [PULL 29/39] hw/arm: Connect PWM fans in NPCM7XX boards Peter Maydell
2021-03-12 13:51 ` Peter Maydell [this message]
2021-03-12 13:51 ` [PULL 31/39] hw/display/pl110: Remove dead code for non-32-bpp surfaces Peter Maydell
2021-03-12 13:51 ` [PULL 32/39] hw/display/pl110: Pull included-once parts of template header into pl110.c Peter Maydell
2021-03-12 13:51 ` [PULL 33/39] hw/display/pl110: Remove use of BITS from pl110_template.h Peter Maydell
2021-03-12 13:51 ` [PULL 34/39] hw/display/pxa2xx_lcd: Remove dead code for non-32-bpp surfaces Peter Maydell
2021-03-12 13:51 ` [PULL 35/39] hw/display/pxa2xx_lcd: Remove dest_width state field Peter Maydell
2021-03-12 13:51 ` [PULL 36/39] hw/display/pxa2xx: Remove use of BITS in pxa2xx_template.h Peter Maydell
2021-03-12 13:51 ` [PULL 37/39] hw/display/pxa2xx: Apply brace-related coding style fixes to template header Peter Maydell
2021-03-12 13:51 ` [PULL 38/39] hw/display/pxa2xx: Apply whitespace-only " Peter Maydell
2021-03-12 13:51 ` [PULL 39/39] hw/display/pxa2xx: Inline " Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210312135140.1099-31-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.