Repository: tiiuae/nuttx
Pull request #371: fpga: Add reset controller for FPGA peripherals
Author: login: pussuw
Labels: name: Size: M
name: Arch: risc-v
Created: 2025-03-17T14:09:00Z | Merged: 2025-03-31T08:41:51Z

Needs FPGA + bootloader update





Diff:
diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig
index 9075bd9c94002..55ba042815c02 100644
--- a/arch/risc-v/src/mpfs/Kconfig
+++ b/arch/risc-v/src/mpfs/Kconfig
@@ -961,6 +961,12 @@ config MPFS_MPUCFG
 	---help---
 		Enable driver to set MPUCFG entries.
 
+config MPFS_RCC
+	bool "Enable Reset and Clock Controller (RCC) driver"
+	default y
+	---help---
+		Enable driver for reset / clock controller.
+
 config MPFS_HAVE_CORERMII
 	bool "CoreRMII FPGA IP block configured"
 	default n
diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs
index b9636528ad688..0eab65e7a403d 100644
--- a/arch/risc-v/src/mpfs/Make.defs
+++ b/arch/risc-v/src/mpfs/Make.defs
@@ -133,3 +133,7 @@ endif
 ifeq ($(CONFIG_MPFS_CRYPTO),y)
 include mpfs/crypto.defs
 endif
+
+ifeq ($(CONFIG_MPFS_RCC),y)
+CHIP_CSRCS += mpfs_rcc.c
+endif
diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_fpga_sysreg.h b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_sysreg.h
new file mode 100644
index 0000000000000..c41f0e0225a2f
--- /dev/null
+++ b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_sysreg.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/hardware/mpfs_fpga_sysreg.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_SYSREG_H
+#define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_SYSREG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MPFS_FPGA_SYSREG_BASE 0x42000000
+
+/* 0x10 : 32 bit Reset 1 control registers ->
+ *         0x00 - I2C reset
+ *         0x04 - SPI reset
+ *         0x08 - UART reset
+ *         0x0C - PWM reset
+ *  0x20 : 32 bit Reset 2 control registers ->
+ *         0x00 - CAN reset
+ */
+
+#define MPFS_FPGA_SYSREG_I2C    (MPFS_FPGA_SYSREG_BASE + 0x10)
+#define MPFS_FPGA_SYSREG_SPI    (MPFS_FPGA_SYSREG_BASE + 0x14)
+#define MPFS_FPGA_SYSREG_UART   (MPFS_FPGA_SYSREG_BASE + 0x18)
+#define MPFS_FPGA_SYSREG_PWM    (MPFS_FPGA_SYSREG_BASE + 0x1C)
+#define MPFS_FPGA_SYSREG_CAN    (MPFS_FPGA_SYSREG_BASE + 0x20)
+
+/* Soft reset control register per instance. Applies to all peripherals. */
+
+#define MPFS_FPGA_SYSREG_SOFT_RESET_CR(x) (1 << (x))
+
+#endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_SYSREG_H */
diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_sysreg.h b/arch/risc-v/src/mpfs/hardware/mpfs_sysreg.h
index ed2ebb83702f7..ca769647bae03 100644
--- a/arch/risc-v/src/mpfs/hardware/mpfs_sysreg.h
+++ b/arch/risc-v/src/mpfs/hardware/mpfs_sysreg.h
@@ -137,6 +137,11 @@
 #define MPFS_SYSREG_SPARE_PERIM_RW_OFFSET              0x02DC /* Spare signal back to G5C */
 #define MPFS_SYSREG_SPARE_FIC_OFFSET                   0x02E0 /* Unused FIC resets */
 
+#define MPFS_SYSREG_SOFT_RESET_CR     (MPFS_SYSREG_BASE + \
+                                       MPFS_SYSREG_SOFT_RESET_CR_OFFSET)
+#define MPFS_SYSREG_SUBBLK_CLOCK_CR   (MPFS_SYSREG_BASE + \
+                                       MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET)
+
 /* Register bit field definitions *******************************************/
 
 /* CLOCK_CONFIG_CR:
diff --git a/arch/risc-v/src/mpfs/mpfs_corepwm.c b/arch/risc-v/src/mpfs/mpfs_corepwm.c
index dcdc4bbc733c4..31bc7039d6afc 100644
--- a/arch/risc-v/src/mpfs/mpfs_corepwm.c
+++ b/arch/risc-v/src/mpfs/mpfs_corepwm.c
@@ -44,7 +44,11 @@
 
 #include <arch/board/board.h>
 
+#include "mpfs_rcc.h"
+
+#include "hardware/mpfs_memorymap.h"
 #include "hardware/mpfs_corepwm.h"
+#include "hardware/mpfs_sysreg.h"
 #include "riscv_internal.h"
 
 /****************************************************************************
@@ -752,6 +756,25 @@ static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
   return -ENOTTY;
 }
 
+static int pwm_init(struct mpfs_pwmtimer_s *priv)
+{
+  /* Toggle peripheral reset */
+
+  mpfs_set_reset(MPFS_RCC_I2C, priv->pwmid, 1);
+  mpfs_set_reset(MPFS_RCC_I2C, priv->pwmid, 0);
+
+  /* Release FIC reset and enable clocks */
+
+  modifyreg32(MPFS_SYSREG_SOFT_RESET_CR,
+              SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA,
+              0);
+
+  modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0,
+              SYSREG_SUBBLK_CLOCK_CR_FIC3);
+
+  return OK;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -795,6 +818,7 @@ struct pwm_lowerhalf_s *mpfs_corepwm_init(int pwmid)
       return NULL;
   }
 
+  pwm_init(lower);
+
   return (struct pwm_lowerhalf_s *)lower;
 }
-
diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c
index 21ee3b42e8a8e..e08ab1dc5fdef 100644
--- a/arch/risc-v/src/mpfs/mpfs_corespi.c
+++ b/arch/risc-v/src/mpfs/mpfs_corespi.c
@@ -44,6 +44,7 @@
 
 #include "mpfs_gpio.h"
 #include "mpfs_corespi.h"
+#include "mpfs_rcc.h"
 #include "hardware/mpfs_corespi.h"
 #include "hardware/mpfs_sysreg.h"
 #include "riscv_internal.h"
@@ -1708,6 +1709,11 @@ static void mpfs_spi_init(struct spi_dev_s *dev)
       putreg32(MPFS_DMA_TX_IRQ, MPFS_DMA_IRQ_MSK);
     }
 
+  /* Toggle peripheral reset */
+
+  mpfs_set_reset(MPFS_RCC_SPI, priv->id, 1);
+  mpfs_set_reset(MPFS_RCC_SPI, priv->id, 0);
+
   /* Release FIC reset and enable clocks */
 
   modifyreg32(MPFS_SYSREG_SOFT_RESET_CR,
diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c
index df3249c561743..1d5646e9ad61d 100644
--- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c
+++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c
@@ -47,11 +47,13 @@
 
 #include <arch/board/board.h>
 
+#include "mpfs_rcc.h"
 #include "mpfs_fpga_canfd.h"
 #include "riscv_internal.h"
 #include "mpfs_memorymap.h"
 
 #include "hardware/mpfs_fpga_canfd.h"
+#include "hardware/mpfs_sysreg.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -2471,6 +2473,17 @@ static int mpfs_reset(struct mpfs_driver_s *priv)
               0);
   modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, SYSREG_SUBBLK_CLOCK_CR_FIC3);
 
+  /* Release reset for CAN IP */
+
+  if (priv->base == CONFIG_MPFS_CANFD_BASE0)
+    {
+      mpfs_set_reset(MPFS_RCC_CAN, 0, 0);
+    }
+  else
+    {
+      mpfs_set_reset(MPFS_RCC_CAN, 1, 0);
+    }
+
   /* Reset CAN controller */
 
   putreg32(MPFS_CANFD_MODE_RST, priv->base + MPFS_CANFD_MODE_OFFSET);
diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c
index 8201bcd4f17a6..f51e16c0a07c7 100644
--- a/arch/risc-v/src/mpfs/mpfs_i2c.c
+++ b/arch/risc-v/src/mpfs/mpfs_i2c.c
@@ -48,6 +48,7 @@
 
 #include "mpfs_gpio.h"
 #include "mpfs_i2c.h"
+#include "mpfs_rcc.h"
 #include "riscv_internal.h"
 #include "hardware/mpfs_i2c.h"
 
@@ -369,6 +370,11 @@ static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv)
 
       if (priv->fpga)
         {
+          /* Toggle peripheral reset */
+
+          mpfs_set_reset(MPFS_RCC_I2C, priv->id, 1);
+          mpfs_set_reset(MPFS_RCC_I2C, priv->id, 0);
+
           /* FIC3 is used by many, don't reset it here, or many
            * FPGA based modules will stop working right here. Just
            * bring out of reset instead.
diff --git a/arch/risc-v/src/mpfs/mpfs_lowputc.c b/arch/risc-v/src/mpfs/mpfs_lowputc.c
index c73a8ca22d58d..4818ecdbd7295 100644
--- a/arch/risc-v/src/mpfs/mpfs_lowputc.c
+++ b/arch/risc-v/src/mpfs/mpfs_lowputc.c
@@ -34,6 +34,7 @@
 #include "hardware/mpfs_memorymap.h"
 #include "hardware/mpfs_uart.h"
 #include "mpfs.h"
+#include "mpfs_rcc.h"
 #include "mpfs_clockconfig.h"
 #include "mpfs_config.h"
 
@@ -307,6 +308,36 @@ void mpfs_lowsetup(void)
   modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
               0, MPFS_CONSOLE_CLOCKBIT);
 
+#ifdef CONFIG_MPFS_FPGA_UART
+  switch (MPFS_CONSOLE_BASE)
+    {
+    case MPFS_FPGA_UART0_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 0, 0);
+      break;
+    case MPFS_FPGA_UART1_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 1, 0);
+      break;
+    case MPFS_FPGA_UART2_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 2, 0);
+      break;
+    case MPFS_FPGA_UART3_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 3, 0);
+      break;
+    case MPFS_FPGA_UART4_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 4, 0);
+      break;
+    case MPFS_FPGA_UART5_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 5, 0);
+      break;
+    case MPFS_FPGA_UART6_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 6, 0);
+      break;
+    case MPFS_FPGA_UART7_BASE:
+      mpfs_set_reset(MPFS_RCC_UART, 7, 0);
+      break;
+    }
+#endif
+
   switch (MPFS_CONSOLE_BITS)
     {
     case 5:
diff --git a/arch/risc-v/src/mpfs/mpfs_rcc.c b/arch/risc-v/src/mpfs/mpfs_rcc.c
new file mode 100644
index 0000000000000..c675c069efdf1
--- /dev/null
+++ b/arch/risc-v/src/mpfs/mpfs_rcc.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/mpfs_rcc.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/spinlock.h>
+
+#include <errno.h>
+#include <sys/types.h>
+
+#include "mpfs_rcc.h"
+#include "mpfs_memorymap.h"
+
+#include "hardware/mpfs_fpga_sysreg.h"
+
+#include "riscv_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static uintptr_t g_reset_reg[] =
+{
+  [MPFS_RCC_CAN]  = MPFS_FPGA_SYSREG_CAN,
+  [MPFS_RCC_I2C]  = MPFS_FPGA_SYSREG_I2C,
+  [MPFS_RCC_SPI]  = MPFS_FPGA_SYSREG_SPI,
+  [MPFS_RCC_PWM]  = MPFS_FPGA_SYSREG_PWM,
+  [MPFS_RCC_UART] = MPFS_FPGA_SYSREG_UART,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mpfs_set_reset
+ *
+ * Description:
+ *   Enable / disable peripheral reset.
+ *
+ * Input Parameters:
+ *   rcc_id   - Device id.
+ *   instance - Optional instance number for device.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+int mpfs_set_reset(int rcc_id, int instance, bool state)
+{
+  uintptr_t reg;
+  UNUSED(instance); /* Unused, for now */
+
+  if (rcc_id >= MPFS_RCC_LAST)
+    {
+      return -ENODEV;
+    }
+
+  reg = g_reset_reg[rcc_id];
+  if (reg == 0)
+    {
+      return -ENODEV;
+    }
+
+  if (state)
+    {
+      modifyreg32(reg, 0, MPFS_FPGA_SYSREG_SOFT_RESET_CR(instance));
+    }
+  else
+    {
+      modifyreg32(reg, MPFS_FPGA_SYSREG_SOFT_RESET_CR(instance), 0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: mpfs_set_clock
+ *
+ * Description:
+ *   Enable / disable peripheral clock.
+ *
+ * Input Parameters:
+ *   rcc_id   - Device id.
+ *   instance - Optional instance number for device.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+int mpfs_set_clock(int rcc_id, int instance, bool state)
+{
+  return -ENODEV;
+}
diff --git a/arch/risc-v/src/mpfs/mpfs_rcc.h b/arch/risc-v/src/mpfs/mpfs_rcc.h
new file mode 100644
index 0000000000000..6437de22c8e8b
--- /dev/null
+++ b/arch/risc-v/src/mpfs/mpfs_rcc.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * arch/risc-v/src/mpfs/mpfs_rcc.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef ARCH_RISC_V_SRC_MPFS_MPFS_RCC_H
+#define ARCH_RISC_V_SRC_MPFS_MPFS_RCC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+enum mpfs_rcc_id_e
+{
+  MPFS_RCC_CAN,
+  MPFS_RCC_I2C,
+  MPFS_RCC_PWM,
+  MPFS_RCC_SPI,
+  MPFS_RCC_UART,
+  MPFS_RCC_LAST,
+};
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mpfs_set_reset
+ *
+ * Description:
+ *   Enable / disable peripheral reset.
+ *
+ * Input Parameters:
+ *   rcc_id   - Device id.
+ *   instance - Optional instance number for device.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MPFS_RCC
+int mpfs_set_reset(int rcc_id, int instance, bool state);
+#else
+#  define mpfs_set_reset(rcc_id, instance, state) (0)
+#endif
+
+/****************************************************************************
+ * Name: mpfs_set_clock
+ *
+ * Description:
+ *   Enable / disable peripheral clock.
+ *
+ * Input Parameters:
+ *   rcc_id   - Device id.
+ *   instance - Optional instance number for device.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MPFS_RCC
+int mpfs_set_clock(int rcc_id, int instance, bool state);
+#else
+#  define mpfs_set_clock(rcc_id, instance, state) (0)
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* ARCH_RISC_V_SRC_MPFS_MPFS_RCC_H */
diff --git a/arch/risc-v/src/mpfs/mpfs_serial.c b/arch/risc-v/src/mpfs/mpfs_serial.c
index 41e4437dffe84..9127f1673c255 100644
--- a/arch/risc-v/src/mpfs/mpfs_serial.c
+++ b/arch/risc-v/src/mpfs/mpfs_serial.c
@@ -50,8 +50,12 @@
 #include "mpfs.h"
 #include "mpfs_config.h"
 #include "mpfs_clockconfig.h"
+#include "mpfs_rcc.h"
 #include "riscv_internal.h"
 
+#include "hardware/mpfs_sysreg.h"
+#include "hardware/mpfs_fpga_sysreg.h"
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -754,53 +758,69 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable)
       reset_bit = SYSREG_SOFT_RESET_CR_MMUART4;
       break;
     case MPFS_FPGA_UART0_BASE:
+      reset_bit = 0;
+      break;
     case MPFS_FPGA_UART1_BASE:
+      reset_bit = 1;
+      break;
     case MPFS_FPGA_UART2_BASE:
+      reset_bit = 2;
+      break;
     case MPFS_FPGA_UART3_BASE:
+      reset_bit = 3;
+      break;
     case MPFS_FPGA_UART4_BASE:
+      reset_bit = 4;
+      break;
     case MPFS_FPGA_UART5_BASE:
+      reset_bit = 5;
+      break;
     case MPFS_FPGA_UART6_BASE:
+      reset_bit = 6;
+      break;
     case MPFS_FPGA_UART7_BASE:
-      clock_bit = SYSREG_SUBBLK_CLOCK_CR_FIC3;
-      reset_bit = SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA;
+      reset_bit = 7;
       break;
 
     default:
       return;
     }
 
-  /* reset on for non-fpga */
-
-  if (!priv->fpga)
-    {
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  0, reset_bit);
-    }
-
-  if (enable)
+  if (priv->fpga)
     {
-      /* reset off */
+      /* Release FPGA, FIC3 from reset and enable clock */
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  reset_bit, 0);
+      modifyreg32(MPFS_SYSREG_SOFT_RESET_CR,
+                  SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3,
+                  0);
 
-      /* clock on */
+      modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0,
+                  SYSREG_SUBBLK_CLOCK_CR_FIC3);
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                  0, clock_bit);
+      mpfs_set_reset(MPFS_RCC_UART, reset_bit, 1);
+      mpfs_set_reset(MPFS_RCC_UART, reset_bit, 0);
     }
   else
     {
-      /* clock off for non-fpga */
+      /* reset on */
+
+      modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, 0, reset_bit);
 
-      if (!priv->fpga)
+      if (enable)
+        {
+          /* reset off */
+
+          modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, reset_bit, 0);
+
+          /* clock on */
+
+          modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, clock_bit);
+        }
+      else
         {
-          /* Turning off FPGA clk would disable it for all other FPGA
-           * peripherals as well. Don't touch it without refcnt mechanism.
-           */
+          /* clock off */
 
-          modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                      clock_bit, 0);
+          modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, clock_bit, 0);
         }
     }
 }


Reviews:
user: login: jlaitine
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-18T06:15:22Z
user: login: pussuw
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-18T06:59:37Z
user: login: jlaitine
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-18T10:02:21Z
user: login: jlaitine
body: LGTM!
state: APPROVED
author_association: NONE
submitted_at: 2025-03-19T13:13:38Z
user: login: jpaali
body: Looks good
state: APPROVED
author_association: NONE
submitted_at: 2025-03-21T10:13:58Z

Review comments:
diff_hunk: @@ -754,55 +764,84 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable)
       reset_bit = SYSREG_SOFT_RESET_CR_MMUART4;
       break;
     case MPFS_FPGA_UART0_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(0);
+      break;
     case MPFS_FPGA_UART1_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(1);
+      break;
     case MPFS_FPGA_UART2_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(2);
+      break;
     case MPFS_FPGA_UART3_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(3);
+      break;
     case MPFS_FPGA_UART4_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(4);
+      break;
     case MPFS_FPGA_UART5_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(5);
+      break;
     case MPFS_FPGA_UART6_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(6);
+      break;
     case MPFS_FPGA_UART7_BASE:
-      clock_bit = SYSREG_SUBBLK_CLOCK_CR_FIC3;
-      reset_bit = SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA;
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(7);
       break;
 
     default:
       return;
     }
 
-  /* reset on for non-fpga */
+  /* SYSREG for MSS or FPGA. Notice that we don't touch the fabric clock
+   * or reset here (for FPGA devices). That is handled at a higher level.
+   */
 
   if (!priv->fpga)
     {
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  0, reset_bit);
+      reset_reg = MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET;
+      clock_reg = MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET;
     }
-
-  if (enable)
+  else
     {
-      /* reset off */
+      reset_reg = MPFS_FPGA_SYSREG_UART;
+      clock_reg = 0; /* No register to control clocks, for now */
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  reset_bit, 0);
+      /* Release FPGA, FIC3 from reset and enable clock */
 
-      /* clock on */
+      modifyreg32(MPFS_SYSREG_SOFT_RESET_CR,
+                  SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3,
+                  0);
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                  0, clock_bit);
+      modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0,
+                  SYSREG_SUBBLK_CLOCK_CR_FIC3);
     }
-  else
-    {
-      /* clock off for non-fpga */
 
-      if (!priv->fpga)
-        {
-          /* Turning off FPGA clk would disable it for all other FPGA
-           * peripherals as well. Don't touch it without refcnt mechanism.
-           */
+   /* reset on */
 
-          modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                      clock_bit, 0);
-        }
-    }
+   modifyreg32(reset_reg, 0, reset_bit);
+
+   if (enable)
+     {
+       /* reset off */
+
+       modifyreg32(reset_reg, reset_bit, 0);
+
+       /* clock on */
+
+       if (clock_reg != 0)
path: arch/risc-v/src/mpfs/mpfs_serial.c
user: login: jlaitine
body: Isn't this commentary dead code kind of useless? Just comment would be sufficient, I don't believe that there will be a register for controlling clocks, at least in the near future...
created_at: 2025-03-18T06:15:22Z
author_association: NONE
diff_hunk: @@ -754,55 +764,84 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable)
       reset_bit = SYSREG_SOFT_RESET_CR_MMUART4;
       break;
     case MPFS_FPGA_UART0_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(0);
+      break;
     case MPFS_FPGA_UART1_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(1);
+      break;
     case MPFS_FPGA_UART2_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(2);
+      break;
     case MPFS_FPGA_UART3_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(3);
+      break;
     case MPFS_FPGA_UART4_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(4);
+      break;
     case MPFS_FPGA_UART5_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(5);
+      break;
     case MPFS_FPGA_UART6_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(6);
+      break;
     case MPFS_FPGA_UART7_BASE:
-      clock_bit = SYSREG_SUBBLK_CLOCK_CR_FIC3;
-      reset_bit = SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA;
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(7);
       break;
 
     default:
       return;
     }
 
-  /* reset on for non-fpga */
+  /* SYSREG for MSS or FPGA. Notice that we don't touch the fabric clock
+   * or reset here (for FPGA devices). That is handled at a higher level.
+   */
 
   if (!priv->fpga)
     {
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  0, reset_bit);
+      reset_reg = MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET;
+      clock_reg = MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET;
     }
-
-  if (enable)
+  else
     {
-      /* reset off */
+      reset_reg = MPFS_FPGA_SYSREG_UART;
+      clock_reg = 0; /* No register to control clocks, for now */
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  reset_bit, 0);
+      /* Release FPGA, FIC3 from reset and enable clock */
 
-      /* clock on */
+      modifyreg32(MPFS_SYSREG_SOFT_RESET_CR,
+                  SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3,
+                  0);
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                  0, clock_bit);
+      modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0,
+                  SYSREG_SUBBLK_CLOCK_CR_FIC3);
     }
-  else
-    {
-      /* clock off for non-fpga */
 
-      if (!priv->fpga)
-        {
-          /* Turning off FPGA clk would disable it for all other FPGA
-           * peripherals as well. Don't touch it without refcnt mechanism.
-           */
+   /* reset on */
 
-          modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                      clock_bit, 0);
-        }
-    }
+   modifyreg32(reset_reg, 0, reset_bit);
+
+   if (enable)
+     {
+       /* reset off */
+
+       modifyreg32(reset_reg, reset_bit, 0);
+
+       /* clock on */
+
+       if (clock_reg != 0)
path: arch/risc-v/src/mpfs/mpfs_serial.c
user: login: pussuw
body: There is no commented out code / dead code here.
created_at: 2025-03-18T06:59:28Z
author_association: NONE
diff_hunk: @@ -754,55 +764,84 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable)
       reset_bit = SYSREG_SOFT_RESET_CR_MMUART4;
       break;
     case MPFS_FPGA_UART0_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(0);
+      break;
     case MPFS_FPGA_UART1_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(1);
+      break;
     case MPFS_FPGA_UART2_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(2);
+      break;
     case MPFS_FPGA_UART3_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(3);
+      break;
     case MPFS_FPGA_UART4_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(4);
+      break;
     case MPFS_FPGA_UART5_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(5);
+      break;
     case MPFS_FPGA_UART6_BASE:
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(6);
+      break;
     case MPFS_FPGA_UART7_BASE:
-      clock_bit = SYSREG_SUBBLK_CLOCK_CR_FIC3;
-      reset_bit = SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA;
+      reset_bit = MPFS_FPGA_SYSREG_SOFT_RESET_CR(7);
       break;
 
     default:
       return;
     }
 
-  /* reset on for non-fpga */
+  /* SYSREG for MSS or FPGA. Notice that we don't touch the fabric clock
+   * or reset here (for FPGA devices). That is handled at a higher level.
+   */
 
   if (!priv->fpga)
     {
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  0, reset_bit);
+      reset_reg = MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET;
+      clock_reg = MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET;
     }
-
-  if (enable)
+  else
     {
-      /* reset off */
+      reset_reg = MPFS_FPGA_SYSREG_UART;
+      clock_reg = 0; /* No register to control clocks, for now */
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
-                  reset_bit, 0);
+      /* Release FPGA, FIC3 from reset and enable clock */
 
-      /* clock on */
+      modifyreg32(MPFS_SYSREG_SOFT_RESET_CR,
+                  SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3,
+                  0);
 
-      modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                  0, clock_bit);
+      modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0,
+                  SYSREG_SUBBLK_CLOCK_CR_FIC3);
     }
-  else
-    {
-      /* clock off for non-fpga */
 
-      if (!priv->fpga)
-        {
-          /* Turning off FPGA clk would disable it for all other FPGA
-           * peripherals as well. Don't touch it without refcnt mechanism.
-           */
+   /* reset on */
 
-          modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
-                      clock_bit, 0);
-        }
-    }
+   modifyreg32(reset_reg, 0, reset_bit);
+
+   if (enable)
+     {
+       /* reset off */
+
+       modifyreg32(reset_reg, reset_bit, 0);
+
+       /* clock on */
+
+       if (clock_reg != 0)
path: arch/risc-v/src/mpfs/mpfs_serial.c
user: login: jlaitine
body: Ops, my bad. Didn't read it properly, sorry.
created_at: 2025-03-18T10:02:21Z
author_association: NONE

PR comments:
user: login: jlaitine
created_at: 2025-03-18T06:24:02Z
body: Code looks good in general, I just started wondering about one thing

- We'd most likely like to up-stream the driver parts, since at least corespi, corei2c and corepwm are publicly available Microchip IPs, and the existing code supports them
- But the new sysreg / reset register IP is our own, so not relevant for upstreaming
-> this hard-wires together drivers for publicly available IP blocks and our custom reset logic.

So, IMHO the drivers require to use some generic api & stubs to issue block reset, which can be implemented by whomever designs the FPGA, if reset functionality is required... Or have some CONFIG flag that can be used to leave out the reset functionality.

In other words, as the state of this PR is now, it is not possible to instantiate only publicly available IP blocks on FPGA and take the corresponding CoreXXX drivers into use with those, since the reset interfaces wouldn't work.


author_association: NONE
user: login: pussuw
created_at: 2025-03-18T06:56:08Z
body: > Code looks good in general, I just started wondering about one thing
> 
> * We'd most likely like to up-stream the driver parts, since at least corespi, corei2c and corepwm are publicly available Microchip IPs, and the existing code supports them
> * But the new sysreg / reset register IP is our own, so not relevant for upstreaming
>   -> this hard-wires together drivers for publicly available IP blocks and our custom reset logic.
> 
> So, IMHO the drivers require to use some generic api & stubs to issue block reset, which can be implemented by whomever designs the FPGA, if reset functionality is required... Or have some CONFIG flag that can be used to leave out the reset functionality.
> 
> In other words, as the state of this PR is now, it is not possible to instantiate only publicly available IP blocks on FPGA and take the corresponding CoreXXX drivers into use with those, since the reset interfaces wouldn't work.

Yes this code is not upstreamable. It is very specifically stated here as well. If you want a, generic reset and clock control driver is of course an option. That driver should precede this content.
author_association: NONE
user: login: pussuw
created_at: 2025-03-19T09:52:54Z
body: The stub driver is the first patch, that is going to upstream. The rest will stay with us.
author_association: NONE
user: login: pussuw
created_at: 2025-03-19T13:18:16Z
body: I'll do the upstream part first.
author_association: NONE