Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:49

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsMicroblaze
0007  *
0008  * @brief MicroBlaze AXI GPIO implementation
0009  */
0010 
0011 /*
0012  * Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <assert.h>
0037 
0038 #include <bsp/fatal.h>
0039 #include <bsp/fdt.h>
0040 #include <bsp/microblaze-gpio.h>
0041 
0042 #include <libfdt.h>
0043 
0044 #ifdef __cplusplus
0045 extern "C" {
0046 #endif /* __cplusplus */
0047 
0048 #ifdef BSP_MICROBLAZE_FPGA_USE_FDT
0049 rtems_status_code microblaze_gpio_init_context_from_fdt(
0050   Microblaze_GPIO_context *context,
0051   int index
0052 )
0053 {
0054   if ( context == NULL ) {
0055     return RTEMS_INVALID_ADDRESS;
0056   }
0057 
0058   const char* compatible = "xlnx,xps-gpio-1.00.a";
0059   const void *fdt = bsp_fdt_get();
0060   int node = fdt_node_offset_by_compatible( fdt, -1, compatible );
0061   if ( node < 0 ) {
0062     return RTEMS_INVALID_NUMBER;
0063   }
0064 
0065   /* Get the desired GPIO node if index is greater than zero. */
0066   for(int i = 0; i < index; i++) {
0067     node = fdt_node_offset_by_compatible( fdt, node, compatible );
0068     if ( node < 0 ) {
0069       return RTEMS_INVALID_NUMBER;
0070     }
0071   }
0072 
0073   const uint32_t *prop;
0074   prop = fdt_getprop( fdt, node, "reg", NULL );
0075   if ( prop != NULL ) {
0076     context->regs = (Microblaze_GPIO_registers *) fdt32_to_cpu( prop[0] );
0077   } else {
0078     return RTEMS_INVALID_NUMBER;
0079   }
0080 
0081   prop = fdt_getprop( fdt, node, "xlnx,is-dual", NULL );
0082   if ( prop != NULL ) {
0083     context->is_dual = fdt32_to_cpu( prop[0] ) != 0 ? true : false;
0084   } else {
0085     return RTEMS_INVALID_NUMBER;
0086   }
0087 
0088   prop = fdt_getprop( fdt, node, "xlnx,interrupt-present", NULL );
0089   if ( prop != NULL ) {
0090     context->has_interrupts = fdt32_to_cpu( prop[0] ) != 0 ? true : false;
0091   } else {
0092     return RTEMS_INVALID_NUMBER;
0093   }
0094 
0095   if ( context->has_interrupts ) {
0096     prop = fdt_getprop( fdt, node, "interrupts", NULL );
0097     if ( prop != NULL ) {
0098       context->irq = fdt32_to_cpu( prop[0] );
0099     } else {
0100       return RTEMS_INVALID_NUMBER;
0101     }
0102   }
0103 
0104   return RTEMS_SUCCESSFUL;
0105 }
0106 #endif /* BSP_MICROBLAZE_FPGA_USE_FDT */
0107 
0108 void microblaze_gpio_set_data_direction(
0109   Microblaze_GPIO_context *ctx,
0110   uint32_t                 channel,
0111   uint32_t                 mask
0112 )
0113 {
0114   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0115 
0116   if ( channel == 1 ) {
0117     ctx->regs->gpio_tri = mask;
0118   } else if ( ctx->is_dual && channel == 2 ) {
0119     ctx->regs->gpio2_tri = mask;
0120   }
0121 }
0122 
0123 uint32_t microblaze_gpio_get_data_direction(
0124   Microblaze_GPIO_context *ctx,
0125   uint32_t                 channel
0126 )
0127 {
0128   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0129 
0130   if ( channel == 1 ) {
0131     return ctx->regs->gpio_tri;
0132   } else if ( ctx->is_dual && channel == 2 ) {
0133     return ctx->regs->gpio2_tri;
0134   }
0135 
0136   return 0;
0137 }
0138 
0139 uint32_t microblaze_gpio_discrete_read(
0140   Microblaze_GPIO_context *ctx,
0141   uint32_t                 channel
0142 )
0143 {
0144   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0145 
0146   if ( channel == 1 ) {
0147     return ctx->regs->gpio_data;
0148   } else if ( ctx->is_dual && channel == 2 ) {
0149     return ctx->regs->gpio2_tri;
0150   }
0151 
0152   return 0;
0153 }
0154 
0155 void microblaze_gpio_discrete_write(
0156   Microblaze_GPIO_context *ctx,
0157   uint32_t                 channel,
0158   uint32_t                 mask
0159 )
0160 {
0161   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0162 
0163   if ( channel == 1 ) {
0164     ctx->regs->gpio_data = mask;
0165   } else if ( ctx->is_dual && channel == 2 ) {
0166     ctx->regs->gpio2_tri = mask;
0167   }
0168 }
0169 
0170 void microblaze_gpio_discrete_set(
0171   Microblaze_GPIO_context *ctx,
0172   uint32_t                 channel,
0173   uint32_t                 mask
0174 )
0175 {
0176   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0177 
0178   if ( channel == 1 ) {
0179     ctx->regs->gpio_data |= mask;
0180   } else if ( ctx->is_dual && channel == 2 ) {
0181     ctx->regs->gpio2_tri |= mask;
0182   }
0183 }
0184 
0185 void microblaze_gpio_discrete_clear(
0186   Microblaze_GPIO_context *ctx,
0187   uint32_t                 channel,
0188   uint32_t                 mask
0189 )
0190 {
0191   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0192 
0193   if ( channel == 1 ) {
0194     ctx->regs->gpio_data &= ~mask;
0195   } else if ( ctx->is_dual && channel == 2 ) {
0196     ctx->regs->gpio2_tri &= ~mask;
0197   }
0198 }
0199 
0200 rtems_vector_number microblaze_gpio_get_irq( Microblaze_GPIO_context *ctx )
0201 {
0202   return ctx->irq;
0203 }
0204 
0205 void microblaze_gpio_interrupt_global_enable( Microblaze_GPIO_context *ctx )
0206 {
0207   assert( ctx->has_interrupts );
0208 
0209   if ( ctx->has_interrupts ) {
0210     ctx->regs->gier = GLOBAL_INTERRUPT_REGISTER_ENABLE;
0211   }
0212 }
0213 
0214 void microblaze_gpio_interrupt_global_disable( Microblaze_GPIO_context *ctx )
0215 {
0216   assert( ctx->has_interrupts );
0217 
0218   if ( ctx->has_interrupts ) {
0219     ctx->regs->gier = 0x0;
0220   }
0221 }
0222 
0223 void microblaze_gpio_interrupt_enable(
0224   Microblaze_GPIO_context *ctx,
0225   uint32_t                 channel
0226 )
0227 {
0228   assert( ctx->has_interrupts );
0229   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0230 
0231   if ( ctx->has_interrupts ) {
0232     if ( channel == 1 ) {
0233       ctx->regs->ip_ier |= CHANNEL_1_INTERRUPT_REGISTER;
0234     } else if ( ctx->is_dual && channel == 2 ) {
0235       ctx->regs->ip_ier |= CHANNEL_2_INTERRUPT_REGISTER;
0236     }
0237   }
0238 }
0239 
0240 void microblaze_gpio_interrupt_disable(
0241   Microblaze_GPIO_context *ctx,
0242   uint32_t                 channel
0243 )
0244 {
0245   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0246 
0247   if ( channel == 1 ) {
0248     ctx->regs->ip_ier &= ~CHANNEL_1_INTERRUPT_REGISTER;
0249   } else if ( ctx->is_dual && channel == 2 ) {
0250     ctx->regs->ip_ier &= ~CHANNEL_2_INTERRUPT_REGISTER;
0251   }
0252 }
0253 
0254 void microblaze_gpio_interrupt_clear(
0255   Microblaze_GPIO_context *ctx,
0256   uint32_t                 channel
0257 )
0258 {
0259   assert( channel == 1 || (ctx->is_dual && channel == 2) );
0260 
0261   if ( channel == 1 ) {
0262     ctx->regs->ip_isr &= CHANNEL_1_INTERRUPT_REGISTER;
0263   } else if ( ctx->is_dual && channel == 2 ) {
0264     ctx->regs->ip_isr &= CHANNEL_2_INTERRUPT_REGISTER;
0265   }
0266 }
0267 
0268 uint32_t microblaze_gpio_interrupt_get_enabled( Microblaze_GPIO_context *ctx )
0269 {
0270   assert( ctx->has_interrupts );
0271 
0272   if ( ctx->has_interrupts ) {
0273     return ctx->regs->ip_ier;
0274   }
0275 
0276   return 0;
0277 }
0278 
0279 uint32_t microblaze_gpio_interrupt_get_status( Microblaze_GPIO_context *ctx )
0280 {
0281   assert( ctx->has_interrupts );
0282 
0283   if ( ctx->has_interrupts ) {
0284     return ctx->regs->ip_isr;
0285   }
0286 
0287   return 0;
0288 }
0289 
0290 #ifdef __cplusplus
0291 }
0292 #endif /* __cplusplus */