[PATCH] microblaze: Add AXI GPIO driver

Gedare Bloom gedare at rtems.org
Wed Mar 16 15:27:30 UTC 2022


On Tue, Mar 15, 2022 at 2:28 PM Alex White <alex.white at oarcorp.com> wrote:
>
> ---
>  bsps/include/dev/gpio/xilinx-axi-gpio.h       | 311 ++++++++++++++++++
>  bsps/shared/dev/gpio/xilinx-axi-gpio.c        | 221 +++++++++++++

Is this AXI GPIO interface consistent across Xilinx IP?

>  .../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
typo: independently

> +   * channel are enabled or disabled.
> +   *
> +   * 0 - No Channel input interrupt
> +   * 1 - Channel input interrupt
> +   */
> +  uint32_t ip_ier;
> +} xilinx_axi_gpio;

This `xilinx_` is not a proper namespace for RTEMS. it doesn't
correspond with any existing components and so it requires some
discussion and approval to introduce it.

> +
> +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(

neither is this `axi_`

> +  xilinx_axi_gpio_context *ctx,

Mixing the newly proposed namespaces is also confusing.

> +  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
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list