[PATCH] microblaze: Add AXI GPIO driver

Alex White alex.white at oarcorp.com
Tue Mar 15 20:27:35 UTC 2022


---
 bsps/include/dev/gpio/xilinx-axi-gpio.h       | 311 ++++++++++++++++++
 bsps/shared/dev/gpio/xilinx-axi-gpio.c        | 221 +++++++++++++
 .../bsps/microblaze/microblaze_fpga/obj.yml   |   2 +
 3 files changed, 534 insertions(+)
 create mode 100644 bsps/include/dev/gpio/xilinx-axi-gpio.h
 create mode 100644 bsps/shared/dev/gpio/xilinx-axi-gpio.c

diff --git a/bsps/include/dev/gpio/xilinx-axi-gpio.h b/bsps/include/dev/gpio/xilinx-axi-gpio.h
new file mode 100644
index 0000000000..dbd8748f34
--- /dev/null
+++ b/bsps/include/dev/gpio/xilinx-axi-gpio.h
@@ -0,0 +1,311 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSBSPsShared
+ *
+ * @brief Xilinx AXI GPIO definitions
+ */
+
+/*
+ * Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XILINX_AXI_GPIO_H
+#define XILINX_AXI_GPIO_H
+
+#include <bspopts.h>
+#include <bsp/utility.h>
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct {
+  /* Channel 1 data values */
+
+  /*
+   * Used to read general purpose input ports and write to general purpose
+   * output ports from channel 1.
+   */
+  uint32_t gpio_data;
+
+  /*
+   * The 3-state control register for channel 1 is used for the dynamic
+   * configuration of ports as input or output. When a bit is set to 1, the
+   * corresponding I/O port is an input port. When a bit is set to 0, it is an
+   * output port.
+   */
+  uint32_t gpio_tri;
+
+  /* Channel 2 data values */
+
+  /*
+   * Used to read general purpose input ports and write to general purpose
+   * output ports from channel 2.
+   */
+  uint32_t gpio2_data;
+
+  /*
+   * The 3-state control register for channel 2 is used for the dynamic
+   * configuration of ports as input or output. When a bit is set to 1, the
+   * corresponding I/O port is an input port. When a bit is set to 0, it is an
+   * output port.
+   */
+  uint32_t gpio2_tri;
+
+  char _unused[272];
+
+  /* Only the 31st bit is used to enable interrupts globally */
+  #define GLOBAL_INTERRUPT_REGISTER_ENABLE BSP_BIT32(31)
+
+  /*
+   * Global Interrupt Enable Register
+   *
+   * Determines whether interrupts are enabled or disabled.
+   *
+   * 0 - Disabled
+   * 1 - Enabled
+   */
+  uint32_t gier;
+
+  char _unused2[12];
+
+  /* Used with ip_isr and ip_ier member variables */
+  #define CHANNEL_1_INTERRUPT_REGISTER BSP_BIT32(0)
+  #define CHANNEL_2_INTERRUPT_REGISTER BSP_BIT32(1)
+
+  /*
+   * IP Status Registers
+   *
+   * Contains the status bit for each channel.
+   *
+   * 0 - Disabled
+   * 1 - Enabled
+   */
+  uint32_t ip_isr;
+
+  char _unused3[4];
+
+  /*
+   * IP Interrupt Enable Register
+   *
+   * Provides the ability to independtly control whether interrupts for each
+   * channel are enabled or disabled.
+   *
+   * 0 - No Channel input interrupt
+   * 1 - Channel input interrupt
+   */
+  uint32_t ip_ier;
+} xilinx_axi_gpio;
+
+typedef struct {
+  volatile xilinx_axi_gpio *regs;
+  bool                      is_dual;
+  uint32_t                  irq;
+  bool                      has_interrupts;
+} xilinx_axi_gpio_context;
+
+/**
+ * @brief Set pin configuration for the specified GPIO channel.
+ *
+ * Changes the pin configuration for a channel. Bits set to 0 are output, and
+ * bits set to 1 are input.
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the GPIO channel
+ * @param[in] mask the mask to be applied to @ channel
+ *
+ * @retval None
+ */
+void axi_gpio_set_data_direction(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+);
+
+/**
+ * @brief Get pin configuration for specified GPIO channel.
+ *
+ * Gets the current pin configuration for a specified GPIO channel. Bits set to
+ * 0 are output, and bits set to 1 are input.
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the GPIO channel
+ *
+ * @retval bitmask specifiying which pins on a channel are input or output
+ */
+uint32_t axi_gpio_get_data_direction(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+);
+
+/**
+ * @brief Reads data for specified GPIO channel.
+ *
+ * @param[in] channel the GPIO channel
+ *
+ * @retval Current values in discretes register.
+ */
+uint32_t axi_gpio_discrete_read(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+);
+
+/**
+ * @brief Writes to data register for specified GPIO channel.
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the GPIO channel
+ * @param[in] mask the mask to be applied to @ channel
+ *
+ * @retval None
+ */
+void axi_gpio_discrete_write(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+);
+
+/**
+ * @brief Set bits to 1 on specified GPIO channel.
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the GPIO channel
+ * @param[in] mask the mask to be applied to @ channel
+ *
+ * @retval None
+ */
+void axi_gpio_discrete_set(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+);
+
+/**
+ * @brief Set bits to 0 on specified GPIO channel.
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the GPIO channel
+ * @param[in] mask the mask to be applied to @ channel
+ *
+ * @retval None
+ */
+void axi_gpio_discrete_clear(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+);
+
+/**
+ * @brief Returns the vector number of the interrupt handler.
+ *
+ * @param[in] ctx the GPIO context
+ *
+ * @retval the vector number
+ */
+rtems_vector_number axi_gpio_get_irq( xilinx_axi_gpio_context *ctx );
+
+/**
+ * @brief Turns on interrupts globally.
+ *
+ * @param[in] ctx the GPIO context
+ *
+ * @retval None
+ */
+void axi_gpio_interrupt_global_enable( xilinx_axi_gpio_context *ctx );
+
+/**
+ * @brief Turns off interrupts globally.
+ *
+ * @param[in] ctx the GPIO context
+ *
+ * @retval None
+ */
+void axi_gpio_interrupt_global_disable( xilinx_axi_gpio_context *ctx );
+
+/**
+ * @brief Enables interrupts on specified channel
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the channel to enable interrupts on
+ *
+ * @retval None
+ */
+void axi_gpio_interrupt_enable(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+);
+
+/**
+ * @brief Disables interrupts on specified channel
+ *
+ * @param[in] ctx the GPIO context
+ * @param[in] channel the channel to turn interrupts on for
+ *
+ * @retval None
+ */
+void axi_gpio_interrupt_disable(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+);
+
+/**
+ * @brief Clear status of interrupt signals on a specific channel
+ *
+ * @param[in] ctx     the GPIO context
+ * @param[in] channel the channel to clear the interrupt pending status from
+ *
+ * @retval None
+ */
+void axi_gpio_interrupt_clear(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+);
+
+/**
+ * @brief Return a bitmask of the interrupts that are enabled
+ *
+ * @param[in] ctx the GPIO context
+ *
+ * @retval the bitmask of enabled interrupts
+ */
+uint32_t axi_gpio_interrupt_get_enabled( xilinx_axi_gpio_context *ctx );
+
+/**
+ * @brief Return a bitmask of the status of the interrupt signals
+ *
+ * @param[in] ctx the GPIO context
+ *
+ * @retval bitmask containing statuses of interrupt signals
+ */
+uint32_t axi_gpio_interrupt_get_status( xilinx_axi_gpio_context *ctx );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XILINX_AXI_GPIO_H */
diff --git a/bsps/shared/dev/gpio/xilinx-axi-gpio.c b/bsps/shared/dev/gpio/xilinx-axi-gpio.c
new file mode 100644
index 0000000000..53146a7bf0
--- /dev/null
+++ b/bsps/shared/dev/gpio/xilinx-axi-gpio.c
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSBSPsShared
+ *
+ * @brief Xilinx AXI GPIO implementation
+ */
+
+/*
+ * Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#include <bsp/fatal.h>
+#include <dev/gpio/xilinx-axi-gpio.h>
+
+void axi_gpio_set_data_direction(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    ctx->regs->gpio_tri = mask;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    ctx->regs->gpio2_tri = mask;
+  }
+}
+
+uint32_t axi_gpio_get_data_direction(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    return ctx->regs->gpio_tri;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    return ctx->regs->gpio2_tri;
+  }
+
+  return 0;
+}
+
+uint32_t axi_gpio_discrete_read(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    return ctx->regs->gpio_data;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    return ctx->regs->gpio2_tri;
+  }
+
+  return 0;
+}
+
+void axi_gpio_discrete_write(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    ctx->regs->gpio_data = mask;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    ctx->regs->gpio2_tri = mask;
+  }
+}
+
+void axi_gpio_discrete_set(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    ctx->regs->gpio_data |= mask;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    ctx->regs->gpio2_tri |= mask;
+  }
+}
+
+void axi_gpio_discrete_clear(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel,
+  uint32_t                 mask
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    ctx->regs->gpio_data &= ~mask;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    ctx->regs->gpio2_tri &= ~mask;
+  }
+}
+
+rtems_vector_number axi_gpio_get_irq( xilinx_axi_gpio_context *ctx )
+{
+  return ctx->irq;
+}
+
+void axi_gpio_interrupt_global_enable( xilinx_axi_gpio_context *ctx )
+{
+  assert( ctx->has_interrupts );
+
+  if ( ctx->has_interrupts ) {
+    ctx->regs->gier = GLOBAL_INTERRUPT_REGISTER_ENABLE;
+  }
+}
+
+void axi_gpio_interrupt_global_disable( xilinx_axi_gpio_context *ctx )
+{
+  assert( ctx->has_interrupts );
+
+  if ( ctx->has_interrupts ) {
+    ctx->regs->gier = 0x0;
+  }
+}
+
+void axi_gpio_interrupt_enable(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+)
+{
+  assert( ctx->has_interrupts );
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( ctx->has_interrupts ) {
+    if ( channel == 1 ) {
+      ctx->regs->ip_ier |= CHANNEL_1_INTERRUPT_REGISTER;
+    } else if ( ctx->is_dual && channel == 2 ) {
+      ctx->regs->ip_ier |= CHANNEL_2_INTERRUPT_REGISTER;
+    }
+  }
+}
+
+void axi_gpio_interrupt_disable(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    ctx->regs->ip_ier &= ~CHANNEL_1_INTERRUPT_REGISTER;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    ctx->regs->ip_ier &= ~CHANNEL_2_INTERRUPT_REGISTER;
+  }
+}
+
+void axi_gpio_interrupt_clear(
+  xilinx_axi_gpio_context *ctx,
+  uint32_t                 channel
+)
+{
+  assert( channel == 1 || (ctx->is_dual && channel == 2) );
+
+  if ( channel == 1 ) {
+    ctx->regs->ip_isr &= CHANNEL_1_INTERRUPT_REGISTER;
+  } else if ( ctx->is_dual && channel == 2 ) {
+    ctx->regs->ip_isr &= CHANNEL_2_INTERRUPT_REGISTER;
+  }
+}
+
+uint32_t axi_gpio_interrupt_get_enabled( xilinx_axi_gpio_context *ctx )
+{
+  assert( ctx->has_interrupts );
+
+  if ( ctx->has_interrupts ) {
+    return ctx->regs->ip_ier;
+  }
+
+  return 0;
+}
+
+uint32_t axi_gpio_interrupt_get_status( xilinx_axi_gpio_context *ctx )
+{
+  assert( ctx->has_interrupts );
+
+  if ( ctx->has_interrupts ) {
+    return ctx->regs->ip_isr;
+  }
+
+  return 0;
+}
diff --git a/spec/build/bsps/microblaze/microblaze_fpga/obj.yml b/spec/build/bsps/microblaze/microblaze_fpga/obj.yml
index 993ba04004..3d151db193 100644
--- a/spec/build/bsps/microblaze/microblaze_fpga/obj.yml
+++ b/spec/build/bsps/microblaze/microblaze_fpga/obj.yml
@@ -14,6 +14,7 @@ install:
   - bsps/microblaze/microblaze_fpga/include/tm27.h
 - destination: ${BSP_INCLUDEDIR}/bsp
   source:
+  - bsps/include/dev/gpio/xilinx-axi-gpio.h
   - bsps/microblaze/microblaze_fpga/include/bsp/irq.h
   - bsps/microblaze/microblaze_fpga/include/bsp/jffs2_qspi.h
   - bsps/microblaze/include/common/xil_types.h
@@ -44,6 +45,7 @@ source:
 - bsps/shared/dev/cpucounter/cpucounterfrequency.c
 - bsps/shared/dev/cpucounter/cpucounterread.c
 - bsps/shared/dev/getentropy/getentropy-cpucounter.c
+- bsps/shared/dev/gpio/xilinx-axi-gpio.c
 - bsps/shared/dev/serial/console-termios-init.c
 - bsps/shared/dev/serial/console-termios.c
 - bsps/shared/irq/irq-default-handler.c
-- 
2.32.0



More information about the devel mailing list