All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arnaud Minier <arnaud.minier@telecom-paris.fr>
To: qemu-devel@nongnu.org
Cc: "Thomas Huth" <thuth@redhat.com>,
	"Arnaud Minier" <arnaud.minier@telecom-paris.fr>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Alistair Francis" <alistair@alistair23.me>,
	"Inès Varhol" <ines.varhol@telecom-paris.fr>,
	"Samuel Tardieu" <samuel.tardieu@telecom-paris.fr>,
	qemu-arm@nongnu.org, "Laurent Vivier" <lvivier@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>
Subject: [PATCH v6 6/8] hw/misc/stm32l4x5_rcc: Add write protections to CR register
Date: Sun,  3 Mar 2024 15:06:41 +0100	[thread overview]
Message-ID: <20240303140643.81957-7-arnaud.minier@telecom-paris.fr> (raw)
In-Reply-To: <20240303140643.81957-1-arnaud.minier@telecom-paris.fr>

Add write protections for the fields in the CR register.
PLL configuration write protections (among others) have not
been handled yet. This is planned in a future patch set.

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
---
 hw/misc/stm32l4x5_rcc.c | 164 ++++++++++++++++++++++++++++------------
 1 file changed, 114 insertions(+), 50 deletions(-)

diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c
index 503051e93d..4596ca2872 100644
--- a/hw/misc/stm32l4x5_rcc.c
+++ b/hw/misc/stm32l4x5_rcc.c
@@ -374,9 +374,47 @@ static void rcc_update_irq(Stm32l4x5RccState *s)
     }
 }
 
-static void rcc_update_cr_register(Stm32l4x5RccState *s)
+static void rcc_update_msi(Stm32l4x5RccState *s, uint32_t previous_value)
+{
+    uint32_t val;
+
+    static const uint32_t msirange[] = {
+        100000, 200000, 400000, 800000, 1000000, 2000000,
+        4000000, 8000000, 16000000, 24000000, 32000000, 48000000
+    };
+    /* MSIRANGE and MSIRGSEL */
+    val = extract32(s->cr, R_CR_MSIRGSEL_SHIFT, R_CR_MSIRGSEL_LENGTH);
+    if (val) {
+        /* MSIRGSEL is set, use the MSIRANGE field */
+        val = extract32(s->cr, R_CR_MSIRANGE_SHIFT, R_CR_MSIRANGE_LENGTH);
+    } else {
+        /* MSIRGSEL is not set, use the MSISRANGE field */
+        val = extract32(s->csr, R_CSR_MSISRANGE_SHIFT, R_CSR_MSISRANGE_LENGTH);
+    }
+
+    if (val < ARRAY_SIZE(msirange)) {
+        clock_update_hz(s->msi_rc, msirange[val]);
+    } else {
+        /*
+         * There is a hardware write protection if the value is out of bound.
+         * Restore the previous value.
+         */
+        s->cr = (s->cr & ~R_CSR_MSISRANGE_MASK) |
+                (previous_value & R_CSR_MSISRANGE_MASK);
+    }
+}
+
+/*
+ * TODO: Add write-protection for all registers:
+ * DONE: CR
+ */
+
+static void rcc_update_cr_register(Stm32l4x5RccState *s, uint32_t previous_value)
 {
     int val;
+    const RccClockMuxSource current_pll_src =
+        CLOCK_MUX_INIT_INFO[RCC_CLOCK_MUX_PLL_INPUT].src_mapping[
+            s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].src];
 
     /* PLLSAI2ON and update PLLSAI2RDY */
     val = FIELD_EX32(s->cr, CR, PLLSAI2ON);
@@ -396,77 +434,101 @@ static void rcc_update_cr_register(Stm32l4x5RccState *s)
         s->cifr |= R_CIFR_PLLSAI1RDYF_MASK;
     }
 
-    /* PLLON and update PLLRDY */
+    /*
+     * PLLON and update PLLRDY
+     * PLLON cannot be reset if the PLL clock is used as the system clock.
+     */
     val = FIELD_EX32(s->cr, CR, PLLON);
-    pll_set_enable(&s->plls[RCC_PLL_PLL], val);
-    s->cr = (s->cr & ~R_CR_PLLRDY_MASK) |
-            (val << R_CR_PLLRDY_SHIFT);
-    if (s->cier & R_CIER_PLLRDYIE_MASK) {
-        s->cifr |= R_CIFR_PLLRDYF_MASK;
+    if (FIELD_EX32(s->cfgr, CFGR, SWS) != 0b11) {
+        pll_set_enable(&s->plls[RCC_PLL_PLL], val);
+        s->cr = (s->cr & ~R_CR_PLLRDY_MASK) |
+                (val << R_CR_PLLRDY_SHIFT);
+        if (s->cier & R_CIER_PLLRDYIE_MASK) {
+            s->cifr |= R_CIFR_PLLRDYF_MASK;
+        }
+    } else {
+        s->cr |= R_CR_PLLON_MASK;
     }
 
     /* CSSON: TODO */
     /* HSEBYP: TODO */
 
-    /* HSEON and update HSERDY */
+    /*
+     * HSEON and update HSERDY.
+     * HSEON cannot be reset if the HSE oscillator is used directly or
+     * indirectly as the system clock.
+     */
     val = FIELD_EX32(s->cr, CR, HSEON);
-    s->cr = (s->cr & ~R_CR_HSERDY_MASK) |
-            (val << R_CR_HSERDY_SHIFT);
-    if (val) {
-        clock_update_hz(s->hse, s->hse_frequency);
-        if (s->cier & R_CIER_HSERDYIE_MASK) {
-            s->cifr |= R_CIFR_HSERDYF_MASK;
+    if (FIELD_EX32(s->cfgr, CFGR, SWS) != 0b10 &&
+        current_pll_src != RCC_CLOCK_MUX_SRC_HSE) {
+        s->cr = (s->cr & ~R_CR_HSERDY_MASK) |
+                (val << R_CR_HSERDY_SHIFT);
+        if (val) {
+            clock_update_hz(s->hse, s->hse_frequency);
+            if (s->cier & R_CIER_HSERDYIE_MASK) {
+                s->cifr |= R_CIFR_HSERDYF_MASK;
+            }
+        } else {
+            clock_update(s->hse, 0);
         }
     } else {
-        clock_update(s->hse, 0);
+        s->cr |= R_CR_HSEON_MASK;
     }
 
     /* HSIAFS: TODO*/
     /* HSIKERON: TODO*/
 
-    /* HSION and update HSIRDY*/
-    val = FIELD_EX32(s->cr, CR, HSION);
-    s->cr = (s->cr & ~R_CR_HSIRDY_MASK) |
-            (val << R_CR_HSIRDY_SHIFT);
-    if (val) {
+    /*
+     * HSION and update HSIRDY
+     * HSION is set by hardware if the HSI16 is used directly
+     * or indirectly as system clock.
+     */
+    if (FIELD_EX32(s->cfgr, CFGR, SWS) == 0b01 ||
+        current_pll_src == RCC_CLOCK_MUX_SRC_HSI) {
+        s->cr |= (R_CR_HSION_MASK | R_CR_HSIRDY_MASK);
         clock_update_hz(s->hsi16_rc, HSI_FRQ);
         if (s->cier & R_CIER_HSIRDYIE_MASK) {
             s->cifr |= R_CIFR_HSIRDYF_MASK;
         }
     } else {
-        clock_update(s->hsi16_rc, 0);
+        val = FIELD_EX32(s->cr, CR, HSION);
+        if (val) {
+            clock_update_hz(s->hsi16_rc, HSI_FRQ);
+            s->cr |= R_CR_HSIRDY_MASK;
+            if (s->cier & R_CIER_HSIRDYIE_MASK) {
+                s->cifr |= R_CIFR_HSIRDYF_MASK;
+            }
+        } else {
+            clock_update(s->hsi16_rc, 0);
+            s->cr &= ~R_CR_HSIRDY_MASK;
+        }
     }
 
-    static const uint32_t msirange[] = {
-        100000, 200000, 400000, 800000, 1000000, 2000000,
-        4000000, 8000000, 16000000, 24000000, 32000000, 48000000
-    };
-    /* MSIRANGE and MSIRGSEL */
-    val = FIELD_EX32(s->cr, CR, MSIRGSEL);
-    if (val) {
-        /* MSIRGSEL is set, use the MSIRANGE field */
-        val = FIELD_EX32(s->cr, CR, MSIRANGE);
-    } else {
-        /* MSIRGSEL is not set, use the MSISRANGE field */
-        val = FIELD_EX32(s->csr, CSR, MSISRANGE);
-    }
+    /* MSIPLLEN: TODO */
 
-    if (val < ARRAY_SIZE(msirange)) {
-        clock_update_hz(s->msi_rc, msirange[val]);
+    /*
+     * MSION and update MSIRDY
+     * Set by hardware when used directly or indirectly as system clock.
+     */
+    if (FIELD_EX32(s->cfgr, CFGR, SWS) == 0b00 ||
+        current_pll_src == RCC_CLOCK_MUX_SRC_MSI) {
+            s->cr |= (R_CR_MSION_MASK | R_CR_MSIRDY_MASK);
+            if (!(previous_value & R_CR_MSION_MASK) && (s->cier & R_CIER_MSIRDYIE_MASK)) {
+                s->cifr |= R_CIFR_MSIRDYF_MASK;
+            }
+            rcc_update_msi(s, previous_value);
     } else {
-        clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ);
-        /* TODO: there is a write protection if the value is out of bound,
-           implement that instead of setting the default */
-    }
-
-    /* MSIPLLEN */
-
-    /* MSION and update MSIRDY */
-    val = FIELD_EX32(s->cr, CR, MSION);
-    s->cr = (s->cr & ~R_CR_MSIRDY_MASK) |
-            (val << R_CR_MSIRDY_SHIFT);
-    if (s->cier & R_CIER_MSIRDYIE_MASK) {
-        s->cifr |= R_CIFR_MSIRDYF_MASK;
+        val = FIELD_EX32(s->cr, CR, MSION);
+        if (val) {
+            s->cr |= R_CR_MSIRDY_MASK;
+            rcc_update_msi(s, previous_value);
+            if (s->cier & R_CIER_MSIRDYIE_MASK) {
+                s->cifr |= R_CIFR_MSIRDYF_MASK;
+            }
+        } else {
+            s->cr &= ~R_CR_MSIRDY_MASK;
+            clock_update(s->msi_rc, 0);
+        }
     }
     rcc_update_irq(s);
 }
@@ -991,15 +1053,17 @@ static void stm32l4x5_rcc_write(void *opaque, hwaddr addr,
                                   uint64_t val64, unsigned int size)
 {
     Stm32l4x5RccState *s = opaque;
+    uint32_t previous_value = 0;
     const uint32_t value = val64;
 
     trace_stm32l4x5_rcc_write(addr, value);
 
     switch (addr) {
     case A_CR:
+        previous_value = s->cr;
         s->cr = (s->cr & CR_READ_SET_MASK) |
                 (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK));
-        rcc_update_cr_register(s);
+        rcc_update_cr_register(s, previous_value);
         break;
     case A_ICSCR:
         s->icscr = value & ~ICSCR_READ_ONLY_MASK;
-- 
2.34.1



  parent reply	other threads:[~2024-03-03 14:11 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-03 14:06 [PATCH v6 0/8] Add device STM32L4x5 RCC Arnaud Minier
2024-03-03 14:06 ` [PATCH v6 1/8] hw/misc/stm32l4x5_rcc: Implement STM32L4x5_RCC skeleton Arnaud Minier
2024-03-03 14:06 ` [PATCH v6 2/8] hw/misc/stm32l4x5_rcc: Add an internal clock multiplexer object Arnaud Minier
2024-03-03 14:06 ` [PATCH v6 3/8] hw/misc/stm32l4x5_rcc: Add an internal PLL Clock object Arnaud Minier
2024-03-03 14:06 ` [PATCH v6 4/8] hw/misc/stm32l4x5_rcc: Initialize PLLs and clock multiplexers Arnaud Minier
2024-03-03 14:06 ` [PATCH v6 5/8] hw/misc/stm32l4x5_rcc: Handle Register Updates Arnaud Minier
2024-03-03 14:06 ` Arnaud Minier [this message]
2024-03-03 14:06 ` [PATCH v6 7/8] hw/arm/stm32l4x5_soc.c: Use the RCC Sysclk Arnaud Minier
2024-03-03 14:06 ` [PATCH v6 8/8] tests/qtest/stm32l4x5_rcc-test.c: Add tests for the STM32L4x5_RCC Arnaud Minier
2024-03-04 16:44 ` [PATCH v6 0/8] Add device STM32L4x5 RCC 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=20240303140643.81957-7-arnaud.minier@telecom-paris.fr \
    --to=arnaud.minier@telecom-paris.fr \
    --cc=alistair@alistair23.me \
    --cc=ines.varhol@telecom-paris.fr \
    --cc=lvivier@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=samuel.tardieu@telecom-paris.fr \
    --cc=thuth@redhat.com \
    /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.