diff options
Diffstat (limited to 'bsps/shared/dev')
71 files changed, 11251 insertions, 739 deletions
diff --git a/bsps/shared/dev/btimer/btimer-cpucounter.c b/bsps/shared/dev/btimer/btimer-cpucounter.c index ade1c02cd1..8757cb844b 100644 --- a/bsps/shared/dev/btimer/btimer-cpucounter.c +++ b/bsps/shared/dev/btimer/btimer-cpucounter.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2017 embedded brains GmbH. All rights reserved. + * Copyright (c) 2017 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems/btimer.h> diff --git a/bsps/shared/dev/btimer/btimer-stub.c b/bsps/shared/dev/btimer/btimer-stub.c deleted file mode 100644 index d1e3313115..0000000000 --- a/bsps/shared/dev/btimer/btimer-stub.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file implements a stub benchmark timer that is sufficient to - * satisfy linking the RTEMS Benchmarks. - * - * COPYRIGHT (c) 1989-2001. - * On-Line Applications Research Corporation (OAR). - */ - -#include <bsp.h> -#include <rtems/btimer.h> - -bool benchmark_timer_find_average_overhead; - -void benchmark_timer_initialize(void) -{ -} - -benchmark_timer_t benchmark_timer_read(void) -{ - if (benchmark_timer_find_average_overhead) - return 1; - return 0; -} - -void benchmark_timer_disable_subtracting_average_overhead( - bool find_flag -) -{ - benchmark_timer_find_average_overhead = find_flag; -} diff --git a/bsps/shared/dev/clock/arm-generic-timer.c b/bsps/shared/dev/clock/arm-generic-timer.c index 3046c53a46..ba159f6833 100644 --- a/bsps/shared/dev/clock/arm-generic-timer.c +++ b/bsps/shared/dev/clock/arm-generic-timer.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2017 embedded brains GmbH. All rights reserved. + * Copyright (c) 2017 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <bsp.h> @@ -41,15 +54,12 @@ typedef struct { static arm_gt_clock_context arm_gt_clock_instance; -/* This is defined in dev/clock/clockimpl.h */ -void Clock_isr(rtems_irq_hdl_param arg); - -static void arm_gt_clock_at_tick(void) +static void arm_gt_clock_at_tick(arm_gt_clock_context *ctx) { uint64_t cval; uint32_t interval; - interval = arm_gt_clock_instance.interval; + interval = ctx->interval; cval = arm_gt_clock_get_compare_value(); cval += interval; arm_gt_clock_set_compare_value(cval); @@ -58,7 +68,7 @@ static void arm_gt_clock_at_tick(void) #endif /* ARM_GENERIC_TIMER_UNMASK_AT_TICK */ } -static void arm_gt_clock_handler_install(void) +static void arm_gt_clock_handler_install(rtems_interrupt_handler handler) { rtems_status_code sc; @@ -66,8 +76,8 @@ static void arm_gt_clock_handler_install(void) arm_gt_clock_instance.irq, "Clock", RTEMS_INTERRUPT_UNIQUE, - (rtems_interrupt_handler) Clock_isr, - NULL + handler, + &arm_gt_clock_instance ); if (sc != RTEMS_SUCCESSFUL) { bsp_fatal(BSP_ARM_FATAL_GENERIC_TIMER_CLOCK_IRQ_INSTALL); @@ -172,14 +182,14 @@ RTEMS_SYSINIT_ITEM( RTEMS_SYSINIT_ORDER_FIRST ); -#define Clock_driver_support_at_tick() \ - arm_gt_clock_at_tick() +#define Clock_driver_support_at_tick(arg) \ + arm_gt_clock_at_tick(arg) #define Clock_driver_support_initialize_hardware() \ arm_gt_clock_initialize() #define Clock_driver_support_install_isr(isr) \ - arm_gt_clock_handler_install() + arm_gt_clock_handler_install(isr) /* Include shared source clock driver code */ #include "../../shared/dev/clock/clockimpl.h" diff --git a/bsps/shared/dev/clock/bcm2835-system-timer.c b/bsps/shared/dev/clock/bcm2835-system-timer.c new file mode 100644 index 0000000000..bb8490d03a --- /dev/null +++ b/bsps/shared/dev/clock/bcm2835-system-timer.c @@ -0,0 +1,94 @@ +/** + * @file + * + * @ingroup RTEMSDriverClockImpl + * + * @brief This source file contains the implementation of the BCM2835 Clock + * Driver. + */ + +/* + * Copyright (c) 2013 Alan Cudmore + * Copyright (c) 2016 Pavel Pisa + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.rtems.org/license/LICENSE + * +*/ + +#include <rtems.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/raspberrypi.h> +#include <rtems/timecounter.h> + +static struct timecounter raspberrypi_tc; + +static uint32_t raspberrypi_clock_get_timecount(struct timecounter *tc) +{ + return BCM2835_REG(BCM2835_GPU_TIMER_CLO); +} + +static void raspberrypi_clock_at_tick(void) +{ + uint32_t act_val; + uint32_t next_cmp = BCM2835_REG(BCM2835_GPU_TIMER_C3); + next_cmp += rtems_configuration_get_microseconds_per_tick(); + BCM2835_REG(BCM2835_GPU_TIMER_C3) = next_cmp; + act_val = BCM2835_REG(BCM2835_GPU_TIMER_CLO); + + /* + * Clear interrupt only if there is time left to the next tick. + * If time of the next tick has already passed then interrupt + * request stays active and fires immediately after current tick + * processing is finished. + */ + if ((int32_t)(next_cmp - act_val) > 0) + BCM2835_REG(BCM2835_GPU_TIMER_CS) = BCM2835_GPU_TIMER_CS_M3; +} + +static void raspberrypi_clock_handler_install_isr( + rtems_interrupt_handler clock_isr +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = rtems_interrupt_handler_install( + BCM2835_IRQ_ID_GPU_TIMER_M3, + "Clock", + RTEMS_INTERRUPT_UNIQUE, + clock_isr, + NULL + ); + if ( sc != RTEMS_SUCCESSFUL ) { + rtems_fatal_error_occurred(0xdeadbeef); + } +} + +static void raspberrypi_clock_initialize_hardware(void) +{ + uint32_t next_cmp = BCM2835_REG(BCM2835_GPU_TIMER_CLO); + next_cmp += rtems_configuration_get_microseconds_per_tick(); + BCM2835_REG(BCM2835_GPU_TIMER_C3) = next_cmp; + BCM2835_REG(BCM2835_GPU_TIMER_CS) = BCM2835_GPU_TIMER_CS_M3; + + raspberrypi_tc.tc_get_timecount = raspberrypi_clock_get_timecount; + raspberrypi_tc.tc_counter_mask = 0xffffffff; + raspberrypi_tc.tc_frequency = 1000000; /* 1 MHz */ + raspberrypi_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&raspberrypi_tc); +} + +#define Clock_driver_support_at_tick(arg) raspberrypi_clock_at_tick() + +#define Clock_driver_support_initialize_hardware() raspberrypi_clock_initialize_hardware() + +#define Clock_driver_support_install_isr(clock_isr) \ + raspberrypi_clock_handler_install_isr(clock_isr) + +#define CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR 1 + +#include "../../../shared/dev/clock/clockimpl.h" diff --git a/bsps/shared/dev/clock/clockimpl.h b/bsps/shared/dev/clock/clockimpl.h index dad71307f4..b27f7c15bc 100644 --- a/bsps/shared/dev/clock/clockimpl.h +++ b/bsps/shared/dev/clock/clockimpl.h @@ -1,18 +1,40 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * - * @ingroup bsp_clock + * @ingroup RTEMSDriverClockImpl + * + * @brief This header file contains the shared Clock Driver implementation. * - * @brief Clock Tick Device Driver Shell + * This header file shall only be included by a particular Clock Driver + * implementation source file. */ /* * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <stdlib.h> @@ -20,27 +42,35 @@ #include <bsp.h> #include <rtems/clockdrv.h> #include <rtems/score/percpu.h> +#include <rtems/score/processormaskimpl.h> #include <rtems/score/smpimpl.h> #include <rtems/score/timecounter.h> #include <rtems/score/thread.h> #include <rtems/score/watchdogimpl.h> -#ifdef Clock_driver_nanoseconds_since_last_tick -#error "Update driver to use the timecounter instead of nanoseconds extension" -#endif - /** - * @defgroup bsp_clock Clock Support - * - * @ingroup RTEMSBSPsShared + * @defgroup RTEMSDriverClockImpl Clock Driver Implementation * - * @brief Clock support + * @ingroup RTEMSDriverClock * + * @brief This group contains the Clock Driver implementation. */ + +#ifdef Clock_driver_nanoseconds_since_last_tick +#error "Update driver to use the timecounter instead of nanoseconds extension" +#endif + #if CLOCK_DRIVER_USE_FAST_IDLE && CLOCK_DRIVER_ISRS_PER_TICK #error "Fast Idle PLUS n ISRs per tick is not supported" #endif +#if defined(BSP_FEATURE_IRQ_EXTENSION) || \ + (CPU_SIMPLE_VECTORED_INTERRUPTS != TRUE) +typedef void * Clock_isr_argument; +#else +typedef rtems_vector_number Clock_isr_argument; +#endif + /** * @brief Do nothing by default. */ @@ -59,7 +89,7 @@ * @brief Do nothing by default. */ #ifndef Clock_driver_support_at_tick - #define Clock_driver_support_at_tick() + #define Clock_driver_support_at_tick( arg ) do { (void) arg; } while (0) #endif /** @@ -74,8 +104,9 @@ * instead of the default. */ #ifndef Clock_driver_timecounter_tick -static void Clock_driver_timecounter_tick( void ) +static void Clock_driver_timecounter_tick( Clock_isr_argument arg ) { + (void) arg; #if defined(CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER) rtems_clock_tick(); #elif defined(RTEMS_SMP) && defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR) @@ -117,25 +148,31 @@ volatile uint32_t Clock_driver_ticks; #error "Clock_driver_support_shutdown_hardware() is no longer supported" #endif +#if CLOCK_DRIVER_USE_FAST_IDLE +static bool _Clock_Has_watchdogs(const Per_CPU_Control *cpu) +{ + size_t i; + + for (i = 0; i < RTEMS_ARRAY_SIZE(cpu->Watchdog.Header); ++i) { + if (_Watchdog_Header_first(&cpu->Watchdog.Header[i]) != NULL) { + return true; + } + } + + return false; +} +#endif + /** * @brief Clock_isr * * This is the clock tick interrupt handler. * - * @param vector Vector number. + * @param arg is the clock interrupt handler argument. */ -#if defined(BSP_FEATURE_IRQ_EXTENSION) || \ - (CPU_SIMPLE_VECTORED_INTERRUPTS != TRUE) -void Clock_isr(void *arg); -void Clock_isr(void *arg) +void Clock_isr( Clock_isr_argument arg ); +void Clock_isr( Clock_isr_argument arg ) { -#else -rtems_isr Clock_isr(rtems_vector_number vector); -rtems_isr Clock_isr( - rtems_vector_number vector -) -{ -#endif /* * Accurate count of ISRs */ @@ -143,7 +180,7 @@ rtems_isr Clock_isr( #if CLOCK_DRIVER_USE_FAST_IDLE { - Clock_driver_timecounter_tick(); + Clock_driver_timecounter_tick( arg ); if (_SMP_Get_processor_maximum() == 1) { struct timecounter *tc; @@ -160,6 +197,7 @@ rtems_isr Clock_isr( cpu_self->thread_dispatch_disable_level == cpu_self->isr_nest_level && cpu_self->heir == cpu_self->executing && cpu_self->executing->is_idle + && _Clock_Has_watchdogs(cpu_self) ) { ISR_lock_Context lock_context; @@ -172,7 +210,7 @@ rtems_isr Clock_isr( } } - Clock_driver_support_at_tick(); + Clock_driver_support_at_tick( arg ); } #else /* @@ -180,14 +218,14 @@ rtems_isr Clock_isr( * * The counter/timer may or may not be set to automatically reload. */ - Clock_driver_support_at_tick(); + Clock_driver_support_at_tick( arg ); #if CLOCK_DRIVER_ISRS_PER_TICK /* * The driver is multiple ISRs per clock tick. */ if ( !Clock_driver_isrs ) { - Clock_driver_timecounter_tick(); + Clock_driver_timecounter_tick( arg ); Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK_VALUE; } @@ -196,7 +234,7 @@ rtems_isr Clock_isr( /* * The driver is one ISR per clock tick. */ - Clock_driver_timecounter_tick(); + Clock_driver_timecounter_tick( arg ); #endif #endif } diff --git a/bsps/shared/dev/clock/xil-ttc.c b/bsps/shared/dev/clock/xil-ttc.c new file mode 100644 index 0000000000..624845d71c --- /dev/null +++ b/bsps/shared/dev/clock/xil-ttc.c @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSDriverClockXilTTC + * + * @brief This source file contains a Clock Driver implementation using the + * Xilinx Triple Timer Counter (TTC). + */ + +/* + * Copyright (C) 2024 embedded brains GmbH & Co. KG + * Copyright (C) 2023 Reflex Aerospace GmbH + * + * Written by Philip Kirkpatrick <p.kirkpatrick@reflexaerospace.com> + * + * 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 <bsp.h> +#include <bsp/irq.h> +#include <bsp/fatal.h> +#include <dev/clock/xttcps_hw.h> +#include <rtems/sysinit.h> +#include <rtems/timecounter.h> + +#if XTTCPS_COUNT_VALUE_MASK != UINT32_MAX +#error "unexpected XTTCPS_COUNT_VALUE_MASK value" +#endif + +/** + * @defgroup RTEMSDriverClockXilTTC \ + * Xilinx Triple Timer Counter (TTC) Clock Driver + * + * @ingroup RTEMSDriverClockImpl + * + * @brief This group contains the Xilinx Triple Timer Counter (TTC) Clock + * Driver implementation. + * + * @{ + */ + +uint32_t _CPU_Counter_frequency( void ) +{ + return XIL_CLOCK_TTC_REFERENCE_CLOCK; +} + +CPU_Counter_ticks _CPU_Counter_read(void) +{ + return XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); +} + +static void xil_ttc_initialize(void) +{ + /* Do not use a prescaler to get a high resolution time source */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_CLK_CNTRL_OFFSET, 0); + + /* Disable interupts */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_IER_OFFSET, 0); + + /* + * Enable the timer, do not enable waveform output, increment up, use + * overflow mode, enable match mode. + */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_CNT_CNTRL_OFFSET, + XTTCPS_CNT_CNTRL_EN_WAVE_MASK | XTTCPS_CNT_CNTRL_MATCH_MASK); +} + +RTEMS_SYSINIT_ITEM( + xil_ttc_initialize, + RTEMS_SYSINIT_CPU_COUNTER, + RTEMS_SYSINIT_ORDER_MIDDLE +); + +typedef struct { + struct timecounter base; + uint32_t irq_match_interval; +} xil_ttc_timecounter; + +static xil_ttc_timecounter xil_ttc_clock_instance; + +static uint32_t xil_ttc_get_timecount(struct timecounter *tc) +{ + (void) tc; + return XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); +} + +static void xil_ttc_clock_driver_support_initialize_hardware(void) +{ + xil_ttc_timecounter *tc; + uint64_t frequency; + uint32_t irq_match_interval; + uint32_t count; + + tc = &xil_ttc_clock_instance; + frequency = XIL_CLOCK_TTC_REFERENCE_CLOCK; + irq_match_interval = (uint32_t) + ((frequency * rtems_configuration_get_microseconds_per_tick()) / 1000000); + + /* Setup match register to generate clock interrupts */ + count = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET, + count + irq_match_interval); + + /* Clear interupts (clear on read) */ + (void) XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_ISR_OFFSET); + + /* Enable interupt for match register */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_IER_OFFSET, + XTTCPS_IXR_MATCH_0_MASK); + + /* Install timecounter */ + tc->irq_match_interval = irq_match_interval; + tc->base.tc_counter_mask = UINT32_MAX; + tc->base.tc_frequency = XIL_CLOCK_TTC_REFERENCE_CLOCK; + tc->base.tc_get_timecount = xil_ttc_get_timecount; + tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&tc->base); +} + +static void xil_ttc_clock_driver_support_at_tick(xil_ttc_timecounter *tc) +{ + uint32_t irq_match_interval; + uint32_t count; + uint32_t match; + + irq_match_interval = tc->irq_match_interval; + + /* Update match register */ + match = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET); + match += irq_match_interval; + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET, match); + + /* Clear interupts (clear on read) */ + (void) XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_ISR_OFFSET); + + /* Check that the new match value is in the future */ + count = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); + + while (RTEMS_PREDICT_FALSE(match - count > irq_match_interval)) { + /* + * Tick misses may happen if interrupts are disabled for an extremly long + * period or while debugging. + */ + rtems_timecounter_tick(); + + /* Update match register */ + match += irq_match_interval; + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET, match); + + /* Clear interupts (clear on read) */ + (void) XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_ISR_OFFSET); + + /* Maybe the new match value is now in the future */ + count = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); + } +} + +static rtems_interrupt_entry xil_ttc_interrupt_entry; + +static void xil_ttc_clock_driver_support_install_isr( + rtems_interrupt_handler handler +) +{ + rtems_status_code sc; + + rtems_interrupt_entry_initialize( + &xil_ttc_interrupt_entry, + handler, + &xil_ttc_clock_instance, + "Clock" + ); + sc = rtems_interrupt_entry_install( + XIL_CLOCK_TTC_IRQ, + RTEMS_INTERRUPT_UNIQUE, + &xil_ttc_interrupt_entry + ); + if ( sc != RTEMS_SUCCESSFUL ) { + bsp_fatal(XIL_FATAL_TTC_IRQ_INSTALL); + } +} + +#define Clock_driver_support_at_tick(arg) \ + xil_ttc_clock_driver_support_at_tick(arg) + +#define Clock_driver_support_initialize_hardware \ + xil_ttc_clock_driver_support_initialize_hardware + +#define Clock_driver_support_install_isr(isr) \ + xil_ttc_clock_driver_support_install_isr(isr) + +/** @} */ + +#include "../../../shared/dev/clock/clockimpl.h" diff --git a/bsps/shared/dev/cpucounter/cpucounterfrequency.c b/bsps/shared/dev/cpucounter/cpucounterfrequency.c index bbb8c127fe..96a4078889 100644 --- a/bsps/shared/dev/cpucounter/cpucounterfrequency.c +++ b/bsps/shared/dev/cpucounter/cpucounterfrequency.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2018 embedded brains GmbH. All rights reserved. + * Copyright (c) 2018 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems/score/cpu.h> diff --git a/bsps/shared/dev/cpucounter/cpucounterread.c b/bsps/shared/dev/cpucounter/cpucounterread.c index b5dc02a40f..f4e6e77fc1 100644 --- a/bsps/shared/dev/cpucounter/cpucounterread.c +++ b/bsps/shared/dev/cpucounter/cpucounterread.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems/score/cpu.h> diff --git a/bsps/shared/dev/display/disp_fonts.h b/bsps/shared/dev/display/disp_fonts.h index 39e909390a..e6023721ee 100644 --- a/bsps/shared/dev/display/disp_fonts.h +++ b/bsps/shared/dev/display/disp_fonts.h @@ -1,22 +1,35 @@ -/*===============================================================*\ -| Project: display driver for HCMS29xx | -+-----------------------------------------------------------------+ -| File: disp_fonts.h | -+-----------------------------------------------------------------+ -| Copyright (c) 2008 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| http://www.rtems.org/license/LICENSE. | -| | -+-----------------------------------------------------------------+ -| This file declares general data structures for font management | -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Display driver for HCMS29xx. + * + * This file declares general data structures for font management. + */ + +/* + * Copyright (c) 2008 embedded brains GmbH & Co. KG + * + * 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 DISP_FONTS_H #define DISP_FONTS_H diff --git a/bsps/shared/dev/display/disp_hcms29xx.c b/bsps/shared/dev/display/disp_hcms29xx.c index 5ad7063865..4e221a1a94 100644 --- a/bsps/shared/dev/display/disp_hcms29xx.c +++ b/bsps/shared/dev/display/disp_hcms29xx.c @@ -1,22 +1,36 @@ -/*===============================================================*\ -| Project: display driver for HCMS29xx | -+-----------------------------------------------------------------+ -| File: disp_hcms29xx.c | -+-----------------------------------------------------------------+ -| Copyright (c) 2008 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| http://www.rtems.org/license/LICENSE. | -+-----------------------------------------------------------------+ -| this file contains the SPI based driver for a HCMS29xx 4 digit | -| alphanumeric LED display | -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Display driver for HCMS29xx. + * + * This file contains the SPI based driver for a HCMS29xx 4 digit + * alphanumeric LED display. + */ + +/* + * Copyright (c) 2008 embedded brains GmbH & Co. KG + * + * 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 <string.h> #include <stdlib.h> diff --git a/bsps/shared/dev/display/font_hcms29xx.c b/bsps/shared/dev/display/font_hcms29xx.c index e25cca2eca..43596923a8 100644 --- a/bsps/shared/dev/display/font_hcms29xx.c +++ b/bsps/shared/dev/display/font_hcms29xx.c @@ -1,21 +1,35 @@ -/*===============================================================*\ -| Project: display driver for HCMS29xx | -+-----------------------------------------------------------------+ -| File: font_hcms29xx.c | -+-----------------------------------------------------------------+ -| Copyright (c) 2008 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| http://www.rtems.org/license/LICENSE. | -+-----------------------------------------------------------------+ -| This file defines the 5x7 bit font used in disp_hcms29xx | -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Display driver for HCMS29xx. + * + * This file defines the 5x7 bit font used in disp_hcms29xx. + */ + +/* + * Copyright (c) 2008 embedded brains GmbH & Co. KG + * + * 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 <stddef.h> #include "disp_fonts.h" diff --git a/bsps/shared/dev/display/font_hcms29xx.h b/bsps/shared/dev/display/font_hcms29xx.h index 8638fcf600..d390b9c90b 100644 --- a/bsps/shared/dev/display/font_hcms29xx.h +++ b/bsps/shared/dev/display/font_hcms29xx.h @@ -1,21 +1,35 @@ -/*===============================================================*\ -| Project: display driver for HCMS29xx | -+-----------------------------------------------------------------+ -| File: font_hcms29xx.h | -+-----------------------------------------------------------------+ -| Copyright (c) 2008 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| http://www.rtems.org/license/LICENSE. | -+-----------------------------------------------------------------+ -| This file declares the 5x7 bit font used in disp_hcms29xx | -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Display driver for HCMS29xx. + * + * This file declares the 5x7 bit font used in disp_hcms29xx. + */ + +/* + * Copyright (c) 2008 embedded brains GmbH & Co. KG + * + * 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 FONT_HCMS29XX_H #define FONT_HCMS29XX_H diff --git a/bsps/shared/dev/dma/fsl-edma.c b/bsps/shared/dev/dma/fsl-edma.c index b3e1bb2fc5..c8b812c1a5 100644 --- a/bsps/shared/dev/dma/fsl-edma.c +++ b/bsps/shared/dev/dma/fsl-edma.c @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2008-2020 embedded brains GmbH (http://www.embedded-brains.de) + * Copyright (C) 2008, 2020 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +40,7 @@ #include <bsp/fatal.h> #include <bsp/irq.h> #ifdef LIBBSP_ARM_IMXRT_BSP_H -#include <MIMXRT1052.h> +#include <fsl_device_registers.h> #endif #define EDMA_CHANNELS_PER_GROUP 32U diff --git a/bsps/shared/dev/getentropy/getentropy-cpucounter.c b/bsps/shared/dev/getentropy/getentropy-cpucounter.c index 218db8d766..44a2573f50 100644 --- a/bsps/shared/dev/getentropy/getentropy-cpucounter.c +++ b/bsps/shared/dev/getentropy/getentropy-cpucounter.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2017 embedded brains GmbH. All rights reserved. + * Copyright (c) 2017 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ /* diff --git a/bsps/shared/dev/i2c/cadence-i2c.c b/bsps/shared/dev/i2c/cadence-i2c.c index 91774fb926..67dec0da46 100644 --- a/bsps/shared/dev/i2c/cadence-i2c.c +++ b/bsps/shared/dev/i2c/cadence-i2c.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2014 embedded brains GmbH + * Copyright (C) 2014 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,6 @@ #include <dev/i2c/cadence-i2c.h> #include <dev/i2c/cadence-i2c-regs.h> -#include <rtems/irq-extension.h> #include <rtems/score/assert.h> #include <dev/i2c/i2c.h> diff --git a/bsps/shared/dev/i2c/i2c-sc620.c b/bsps/shared/dev/i2c/i2c-sc620.c index 7b30ae56af..ed360086d8 100644 --- a/bsps/shared/dev/i2c/i2c-sc620.c +++ b/bsps/shared/dev/i2c/i2c-sc620.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -5,17 +7,28 @@ */ /* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * Copyright (c) 2013 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <libchip/i2c-sc620.h> diff --git a/bsps/shared/dev/i2c/spi-flash-m25p40.c b/bsps/shared/dev/i2c/spi-flash-m25p40.c index 075a4510b9..9f6189cd3c 100644 --- a/bsps/shared/dev/i2c/spi-flash-m25p40.c +++ b/bsps/shared/dev/i2c/spi-flash-m25p40.c @@ -1,20 +1,33 @@ -/*===============================================================*\ -| Project: SPI driver for M25P40 like spi flash device | -+-----------------------------------------------------------------+ -| Copyright (c) 2007 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| | -| http://www.rtems.org/license/LICENSE. | -| | -+-----------------------------------------------------------------+ -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * SPI driver for M25P40 like spi flash device. + */ + +/* + * Copyright (c) 2007 embedded brains GmbH & Co. KG + * + * 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 <rtems.h> #include <rtems/libi2c.h> diff --git a/bsps/shared/dev/i2c/spi-fram-fm25l256.c b/bsps/shared/dev/i2c/spi-fram-fm25l256.c index 086feb82bb..e1ff15e5b3 100644 --- a/bsps/shared/dev/i2c/spi-fram-fm25l256.c +++ b/bsps/shared/dev/i2c/spi-fram-fm25l256.c @@ -1,20 +1,33 @@ -/*===============================================================*\ -| Project: SPI driver for FM25L256 like spi fram device | -+-----------------------------------------------------------------+ -| Copyright (c) 2008 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| | -| http://www.rtems.org/license/LICENSE. | -| | -+-----------------------------------------------------------------+ -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * SPI driver for FM25L256 like spi fram device. + */ + +/* + * Copyright (c) 2008 embedded brains GmbH & Co. KG + * + * 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 <rtems.h> #include <rtems/libi2c.h> diff --git a/bsps/shared/dev/i2c/spi-memdrv.c b/bsps/shared/dev/i2c/spi-memdrv.c index f3308e8fe1..d890b9e41a 100644 --- a/bsps/shared/dev/i2c/spi-memdrv.c +++ b/bsps/shared/dev/i2c/spi-memdrv.c @@ -1,20 +1,34 @@ -/*===============================================================*\ -| Project: SPI driver for spi memory devices | -+-----------------------------------------------------------------+ -| Copyright (c) 2008 | -| Embedded Brains GmbH | -| Obere Lagerstr. 30 | -| D-82178 Puchheim | -| Germany | -| rtems@embedded-brains.de | -+-----------------------------------------------------------------+ -| The license and distribution terms for this file may be | -| found in the file LICENSE in this distribution or at | -| | -| http://www.rtems.org/license/LICENSE. | -| | -+-----------------------------------------------------------------+ -\*===============================================================*/ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * SPI driver for spi memory devices. + */ + +/* + * Copyright (c) 2008 embedded brains GmbH & Co. KG + * + * 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. + */ + /* * FIXME: currently, this driver only supports read/write accesses * erase accesses are to be completed diff --git a/bsps/shared/dev/i2c/spi-sd-card.c b/bsps/shared/dev/i2c/spi-sd-card.c index bf8ed403a5..36a2721bb9 100644 --- a/bsps/shared/dev/i2c/spi-sd-card.c +++ b/bsps/shared/dev/i2c/spi-sd-card.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -5,17 +7,28 @@ */ /* - * Copyright (c) 2008, 2018 embedded brains GmbH + * Copyright (C) 2008, 2018 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <stdio.h> diff --git a/bsps/shared/dev/ide/ata_util.c b/bsps/shared/dev/ide/ata_util.c index 68e0f0bbe5..5fd286cdc5 100644 --- a/bsps/shared/dev/ide/ata_util.c +++ b/bsps/shared/dev/ide/ata_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 embedded brains GmbH. + * Copyright (c) 2010 embedded brains GmbH & Co. KG * * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru> diff --git a/bsps/shared/dev/irq/arm-gicv2-get-attributes.c b/bsps/shared/dev/irq/arm-gicv2-get-attributes.c index 62aa504678..613174bb3a 100644 --- a/bsps/shared/dev/irq/arm-gicv2-get-attributes.c +++ b/bsps/shared/dev/irq/arm-gicv2-get-attributes.c @@ -3,19 +3,14 @@ /** * @file * - * @ingroup RTEMSBSPsShared + * @ingroup DevIRQGIC * - * @brief This source file contains the interrupt get attribute implementation. + * @brief This source file contains the implementation of + * bsp_interrupt_get_attributes() for the GICv2. */ /* - * Copyright (c) 2013, 2021 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> + * Copyright (C) 2013, 2021 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/bsps/shared/dev/irq/arm-gicv2-zynqmp.c b/bsps/shared/dev/irq/arm-gicv2-zynqmp.c index ee4479155a..bb9bfafb48 100644 --- a/bsps/shared/dev/irq/arm-gicv2-zynqmp.c +++ b/bsps/shared/dev/irq/arm-gicv2-zynqmp.c @@ -3,9 +3,11 @@ /** * @file * - * @ingroup RTEMSBSPsShared + * @ingroup DevIRQGIC * - * @brief This source file contains the interrupt get attribute implementation. + * @brief This source file contains the implementation of + * bsp_interrupt_get_attributes() for the GICv2 of Xilinx Zynq UltraScale+ + * MPSoC and RFSoC devices. */ /* diff --git a/bsps/shared/dev/irq/arm-gicv2.c b/bsps/shared/dev/irq/arm-gicv2.c index b7898e2e97..263278148b 100644 --- a/bsps/shared/dev/irq/arm-gicv2.c +++ b/bsps/shared/dev/irq/arm-gicv2.c @@ -1,23 +1,53 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup DevIRQGIC + * + * @brief This source file contains the implementation of the generic GICv2 + * support. + */ + /* - * Copyright (c) 2013, 2021 embedded brains GmbH. All rights reserved. + * Copyright (C) 2013, 2021 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <dev/irq/arm-gic.h> #include <dev/irq/arm-gic-arch.h> -#include <bsp/irq.h> #include <bsp/irq-generic.h> #include <bsp/start.h> +#include <rtems/score/processormaskimpl.h> + +/* + * The GIC architecture reserves interrupt ID numbers 1020 to 1023 for special + * purposes. + */ +#if BSP_INTERRUPT_VECTOR_COUNT >= 1020 +#error "BSP_INTERRUPT_VECTOR_COUNT is too large" +#endif #define GIC_CPUIF ((volatile gic_cpuif *) BSP_ARM_GIC_CPUIF_BASE) @@ -53,12 +83,19 @@ void bsp_interrupt_dispatch(void) { volatile gic_cpuif *cpuif = GIC_CPUIF; - uint32_t icciar = cpuif->icciar; - rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar); - rtems_vector_number spurious = 1023; - if (vector != spurious) { - arm_interrupt_handler_dispatch(vector); + while (true) { + uint32_t icciar = cpuif->icciar; + rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar); + uint32_t status; + + if (!bsp_interrupt_is_valid_vector(vector)) { + break; + } + + status = arm_interrupt_enable_interrupts(); + bsp_interrupt_handler_dispatch_unchecked(vector); + arm_interrupt_restore_interrupts(status); cpuif->icceoir = icciar; } @@ -307,6 +344,7 @@ rtems_status_code arm_gic_irq_get_group( return sc; } +#ifdef RTEMS_SMP rtems_status_code bsp_interrupt_set_affinity( rtems_vector_number vector, const Processor_mask *affinity @@ -366,6 +404,7 @@ rtems_status_code bsp_interrupt_get_affinity( _Processor_mask_From_uint32_t(affinity, targets, 0); return RTEMS_SUCCESSFUL; } +#endif void arm_gic_trigger_sgi(rtems_vector_number vector, uint32_t targets) { @@ -379,9 +418,11 @@ void arm_gic_trigger_sgi(rtems_vector_number vector, uint32_t targets) | GIC_DIST_ICDSGIR_SGIINTID(vector); } +#ifdef RTEMS_SMP uint32_t arm_gic_irq_processor_count(void) { volatile gic_dist *dist = ARM_GIC_DIST; return GIC_DIST_ICDICTR_CPU_NUMBER_GET(dist->icdictr) + 1; } +#endif diff --git a/bsps/shared/dev/irq/arm-gicv3.c b/bsps/shared/dev/irq/arm-gicv3.c index ea123d325e..958b1061bd 100644 --- a/bsps/shared/dev/irq/arm-gicv3.c +++ b/bsps/shared/dev/irq/arm-gicv3.c @@ -1,6 +1,15 @@ -/* - * SPDX-License-Identifier: BSD-2-Clause +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file * + * @ingroup DevIRQGIC + * + * @brief This source file contains the implementation of the generic GICv3 + * support. + */ + +/* * Copyright (C) 2019 On-Line Applications Research Corporation (OAR) * * Redistribution and use in source and binary forms, with or without @@ -25,140 +34,26 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <dev/irq/arm-gic.h> -#include <dev/irq/arm-gic-arch.h> +#include <dev/irq/arm-gicv3.h> -#include <bsp/irq.h> #include <bsp/irq-generic.h> #include <bsp/start.h> - -#ifdef ARM_MULTILIB_ARCH_V4 -#include <rtems/score/armv4.h> -#else -#include <rtems/score/cpu_irq.h> -#endif - -#define PRIORITY_DEFAULT 127 - -#define MPIDR_AFFINITY2(val) BSP_FLD64(val, 16, 23) -#define MPIDR_AFFINITY2_GET(reg) BSP_FLD64GET(reg, 16, 23) -#define MPIDR_AFFINITY2_SET(reg, val) BSP_FLD64SET(reg, val, 16, 23) -#define MPIDR_AFFINITY1(val) BSP_FLD64(val, 8, 15) -#define MPIDR_AFFINITY1_GET(reg) BSP_FLD64GET(reg, 8, 15) -#define MPIDR_AFFINITY1_SET(reg, val) BSP_FLD64SET(reg, val, 8, 15) -#define MPIDR_AFFINITY0(val) BSP_FLD64(val, 0, 7) -#define MPIDR_AFFINITY0_GET(reg) BSP_FLD64GET(reg, 0, 7) -#define MPIDR_AFFINITY0_SET(reg, val) BSP_FLD64SET(reg, val, 0, 7) - -#define ICC_SGIR_AFFINITY3(val) BSP_FLD64(val, 48, 55) -#define ICC_SGIR_AFFINITY3_GET(reg) BSP_FLD64GET(reg, 48, 55) -#define ICC_SGIR_AFFINITY3_SET(reg, val) BSP_FLD64SET(reg, val, 48, 55) -#define ICC_SGIR_IRM BSP_BIT32(40) -#define ICC_SGIR_AFFINITY2(val) BSP_FLD64(val, 32, 39) -#define ICC_SGIR_AFFINITY2_GET(reg) BSP_FLD64GET(reg, 32, 39) -#define ICC_SGIR_AFFINITY2_SET(reg, val) BSP_FLD64SET(reg, val, 32, 39) -#define ICC_SGIR_INTID(val) BSP_FLD64(val, 24, 27) -#define ICC_SGIR_INTID_GET(reg) BSP_FLD64GET(reg, 24, 27) -#define ICC_SGIR_INTID_SET(reg, val) BSP_FLD64SET(reg, val, 24, 27) -#define ICC_SGIR_AFFINITY1(val) BSP_FLD64(val, 16, 23) -#define ICC_SGIR_AFFINITY1_GET(reg) BSP_FLD64GET(reg, 16, 23) -#define ICC_SGIR_AFFINITY1_SET(reg, val) BSP_FLD64SET(reg, val, 16, 23) -#define ICC_SGIR_CPU_TARGET_LIST(val) BSP_FLD64(val, 0, 15) -#define ICC_SGIR_CPU_TARGET_LIST_GET(reg) BSP_FLD64GET(reg, 0, 15) -#define ICC_SGIR_CPU_TARGET_LIST_SET(reg, val) BSP_FLD64SET(reg, val, 0, 15) - -#ifdef ARM_MULTILIB_ARCH_V4 -/* cpuif->iccicr */ -#define ICC_CTLR "p15, 0, %0, c12, c12, 4" - -/* cpuif->iccpmr */ -#define ICC_PMR "p15, 0, %0, c4, c6, 0" - -/* cpuif->iccbpr */ -#define ICC_BPR0 "p15, 0, %0, c12, c8, 3" -#define ICC_BPR1 "p15, 0, %0, c12, c12, 3" - -/* cpuif->icciar */ -#define ICC_IAR0 "p15, 0, %0, c12, c8, 0" -#define ICC_IAR1 "p15, 0, %0, c12, c12, 0" - -/* cpuif->icceoir */ -#define ICC_EOIR0 "p15, 0, %0, c12, c8, 1" -#define ICC_EOIR1 "p15, 0, %0, c12, c12, 1" - -#define ICC_SRE "p15, 0, %0, c12, c12, 5" - -#define ICC_IGRPEN0 "p15, 0, %0, c12, c12, 6" -#define ICC_IGRPEN1 "p15, 0, %0, c12, c12, 7" - -#define MPIDR "p15, 0, %0, c0, c0, 5" - -#define READ_SR(SR_NAME) \ -({ \ - uint32_t value; \ - __asm__ volatile("mrc " SR_NAME : "=r" (value) ); \ - value; \ -}) - -#define WRITE_SR(SR_NAME, VALUE) \ - __asm__ volatile("mcr " SR_NAME " \n" : : "r" (VALUE) ); - -#define ICC_SGI1 "p15, 0, %Q0, %R0, c12" -#define WRITE64_SR(SR_NAME, VALUE) \ - __asm__ volatile("mcrr " SR_NAME " \n" : : "r" (VALUE) ); - -#else /* ARM_MULTILIB_ARCH_V4 */ - -/* AArch64 GICv3 registers are not named in GCC */ -#define ICC_IGRPEN0 "S3_0_C12_C12_6, %0" -#define ICC_IGRPEN1 "S3_0_C12_C12_7, %0" -#define ICC_IGRPEN1_EL3 "S3_6_C12_C12_7, %0" -#define ICC_PMR "S3_0_C4_C6_0, %0" -#define ICC_EOIR1 "S3_0_C12_C12_1, %0" -#define ICC_SRE "S3_0_C12_C12_5, %0" -#define ICC_BPR0 "S3_0_C12_C8_3, %0" -#define ICC_CTLR "S3_0_C12_C12_4, %0" -#define ICC_IAR1 "%0, S3_0_C12_C12_0" -#define MPIDR "%0, mpidr_el1" -#define MPIDR_AFFINITY3(val) BSP_FLD64(val, 32, 39) -#define MPIDR_AFFINITY3_GET(reg) BSP_FLD64GET(reg, 32, 39) -#define MPIDR_AFFINITY3_SET(reg, val) BSP_FLD64SET(reg, val, 32, 39) - -#define ICC_SGI1 "S3_0_C12_C11_5, %0" -#define WRITE64_SR(SR_NAME, VALUE) \ - __asm__ volatile("msr " SR_NAME " \n" : : "r" (VALUE) ); -#define WRITE_SR(SR_NAME, VALUE) WRITE64_SR(SR_NAME, VALUE) - -#define READ_SR(SR_NAME) \ -({ \ - uint64_t value; \ - __asm__ volatile("mrs " SR_NAME : "=&r" (value) ); \ - value; \ -}) - - -#endif /* ARM_MULTILIB_ARCH_V4 */ - -static volatile gic_redist *gicv3_get_redist(uint32_t cpu_index) -{ - return (volatile gic_redist *) - ((uintptr_t)BSP_ARM_GIC_REDIST_BASE + cpu_index * 0x20000); -} - -static volatile gic_sgi_ppi *gicv3_get_sgi_ppi(uint32_t cpu_index) -{ - return (volatile gic_sgi_ppi *) - ((uintptr_t)BSP_ARM_GIC_REDIST_BASE + cpu_index * 0x20000 + 0x10000); -} +#include <rtems/score/processormaskimpl.h> void bsp_interrupt_dispatch(void) { - uint32_t icciar = READ_SR(ICC_IAR1); - rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar); - rtems_vector_number spurious = 1023; + while (true) { + uint32_t icciar = READ_SR(ICC_IAR1); + rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar); + uint32_t status; - if (vector != spurious) { - arm_interrupt_handler_dispatch(vector); + if (!bsp_interrupt_is_valid_vector(vector)) { + break; + } + + status = arm_interrupt_enable_interrupts(); + bsp_interrupt_handler_dispatch_unchecked(vector); + arm_interrupt_restore_interrupts(status); WRITE_SR(ICC_EOIR1, icciar); } @@ -169,32 +64,7 @@ rtems_status_code bsp_interrupt_get_attributes( rtems_interrupt_attributes *attributes ) { - attributes->is_maskable = true; - attributes->maybe_enable = true; - attributes->maybe_disable = true; - attributes->can_raise = true; - - if ( vector <= ARM_GIC_IRQ_SGI_LAST ) { - /* - * It is implementation-defined whether implemented SGIs are permanently - * enabled, or can be enabled and disabled by writes to GICD_ISENABLER0 and - * GICD_ICENABLER0. - */ - attributes->can_raise_on = true; - attributes->cleared_by_acknowledge = true; - attributes->trigger_signal = RTEMS_INTERRUPT_NO_SIGNAL; - } else { - attributes->can_disable = true; - attributes->can_clear = true; - attributes->trigger_signal = RTEMS_INTERRUPT_UNSPECIFIED_SIGNAL; - - if ( vector > ARM_GIC_IRQ_PPI_LAST ) { - /* SPI */ - attributes->can_get_affinity = true; - attributes->can_set_affinity = true; - } - } - + gicv3_get_attributes(vector, attributes); return RTEMS_SUCCESSFUL; } @@ -207,10 +77,7 @@ rtems_status_code bsp_interrupt_is_pending( bsp_interrupt_assert(pending != NULL); if (vector <= ARM_GIC_IRQ_PPI_LAST) { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - - *pending = (sgi_ppi->icspispendr[0] & (1U << vector)) != 0; + *pending = gicv3_sgi_ppi_is_pending(vector, _SMP_Get_current_processor()); } else { volatile gic_dist *dist = ARM_GIC_DIST; @@ -227,10 +94,7 @@ rtems_status_code bsp_interrupt_raise(rtems_vector_number vector) if (vector <= ARM_GIC_IRQ_SGI_LAST) { arm_gic_trigger_sgi(vector, 1U << _SMP_Get_current_processor()); } else if (vector <= ARM_GIC_IRQ_PPI_LAST) { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - - sgi_ppi->icspispendr[0] = 1U << vector; + gicv3_ppi_set_pending(vector, _SMP_Get_current_processor()); } else { volatile gic_dist *dist = ARM_GIC_DIST; @@ -264,10 +128,7 @@ rtems_status_code bsp_interrupt_clear(rtems_vector_number vector) } if ( vector <= ARM_GIC_IRQ_PPI_LAST ) { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - - sgi_ppi->icspicpendr[0] = 1U << vector; + gicv3_ppi_clear_pending(vector, _SMP_Get_current_processor()); } else { volatile gic_dist *dist = ARM_GIC_DIST; @@ -286,10 +147,7 @@ rtems_status_code bsp_interrupt_vector_is_enabled( bsp_interrupt_assert(enabled != NULL); if ( vector <= ARM_GIC_IRQ_PPI_LAST ) { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - - *enabled = (sgi_ppi->icspiser[0] & (1U << vector)) != 0; + *enabled = gicv3_sgi_ppi_is_enabled(vector, _SMP_Get_current_processor()); } else { volatile gic_dist *dist = ARM_GIC_DIST; @@ -309,19 +167,7 @@ rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector) gic_id_enable(dist, vector); } else { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - - /* Set interrupt group to 1 in the current security mode */ -#if defined(ARM_MULTILIB_ARCH_V4) || defined(AARCH64_IS_NONSECURE) - sgi_ppi->icspigrpr[0] |= 1U << vector; - sgi_ppi->icspigrpmodr[0] &= ~(1U << vector); -#else - sgi_ppi->icspigrpr[0] &= ~(1U << vector); - sgi_ppi->icspigrpmodr[0] |= 1U << vector; -#endif - /* Set enable */ - sgi_ppi->icspiser[0] = 1U << vector; + gicv3_sgi_ppi_enable(vector, _SMP_Get_current_processor()); } return RTEMS_SUCCESSFUL; @@ -336,93 +182,17 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) gic_id_disable(dist, vector); } else { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - - sgi_ppi->icspicer[0] = 1U << vector; + gicv3_sgi_ppi_disable(vector, _SMP_Get_current_processor()); } return RTEMS_SUCCESSFUL; } -static inline uint32_t get_id_count(volatile gic_dist *dist) -{ - uint32_t id_count = GIC_DIST_ICDICTR_IT_LINES_NUMBER_GET(dist->icdictr); - - id_count = 32 * (id_count + 1); - id_count = id_count <= 1020 ? id_count : 1020; - - return id_count; -} - -static void gicv3_init_cpu_interface(void) -{ - uint32_t cpu_index = _SMP_Get_current_processor(); - uint32_t sre_value = 0x7; - WRITE_SR(ICC_SRE, sre_value); - WRITE_SR(ICC_PMR, GIC_CPUIF_ICCPMR_PRIORITY(0xff)); - WRITE_SR(ICC_BPR0, GIC_CPUIF_ICCBPR_BINARY_POINT(0x0)); - - volatile gic_redist *redist = gicv3_get_redist(cpu_index); - uint32_t waker = redist->icrwaker; - uint32_t waker_mask = GIC_REDIST_ICRWAKER_PROCESSOR_SLEEP; - waker &= ~waker_mask; - redist->icrwaker = waker; - - volatile gic_sgi_ppi *sgi_ppi = gicv3_get_sgi_ppi(cpu_index); - /* Set interrupt group to 1 in the current security mode */ -#if defined(ARM_MULTILIB_ARCH_V4) || defined(AARCH64_IS_NONSECURE) - sgi_ppi->icspigrpr[0] = 0xffffffff; - sgi_ppi->icspigrpmodr[0] = 0; -#else - sgi_ppi->icspigrpr[0] = 0x0; - sgi_ppi->icspigrpmodr[0] = 0xffffffff; -#endif - for (int id = 0; id < 32; id++) { - sgi_ppi->icspiprior[id] = PRIORITY_DEFAULT; - } - - /* Enable interrupt groups 0 and 1 */ - WRITE_SR(ICC_IGRPEN0, 0x1); - WRITE_SR(ICC_IGRPEN1, 0x1); - WRITE_SR(ICC_CTLR, 0x0); -} - void bsp_interrupt_facility_initialize(void) { - volatile gic_dist *dist = ARM_GIC_DIST; - uint32_t id_count = get_id_count(dist); - uint32_t id; - arm_interrupt_facility_set_exception_handler(); - - dist->icddcr = GIC_DIST_ICDDCR_ARE_NS | GIC_DIST_ICDDCR_ARE_S - | GIC_DIST_ICDDCR_ENABLE_GRP1S | GIC_DIST_ICDDCR_ENABLE_GRP1NS - | GIC_DIST_ICDDCR_ENABLE_GRP0; - - for (id = 0; id < id_count; id += 32) { - /* Disable all interrupts */ - dist->icdicer[id / 32] = 0xffffffff; - - /* Set interrupt group to 1 in the current security mode */ -#if defined(ARM_MULTILIB_ARCH_V4) || defined(AARCH64_IS_NONSECURE) - dist->icdigr[id / 32] = 0xffffffff; - dist->icdigmr[id / 32] = 0; -#else - dist->icdigr[id / 32] = 0; - dist->icdigmr[id / 32] = 0xffffffff; -#endif - } - - for (id = 0; id < id_count; ++id) { - gic_id_set_priority(dist, id, PRIORITY_DEFAULT); - } - - for (id = 32; id < id_count; ++id) { - gic_id_set_targets(dist, id, 0x01); - } - - gicv3_init_cpu_interface(); + gicv3_init_dist(ARM_GIC_DIST); + gicv3_init_cpu_interface(_SMP_Get_current_processor()); } #ifdef RTEMS_SMP @@ -434,7 +204,7 @@ BSP_START_TEXT_SECTION void arm_gic_irq_initialize_secondary_cpu(void) /* Wait */ } - gicv3_init_cpu_interface(); + gicv3_init_cpu_interface(_SMP_Get_current_processor()); } #endif @@ -450,9 +220,11 @@ rtems_status_code arm_gic_irq_set_priority( volatile gic_dist *dist = ARM_GIC_DIST; gic_id_set_priority(dist, vector, priority); } else { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - sgi_ppi->icspiprior[vector] = priority; + gicv3_sgi_ppi_set_priority( + vector, + priority, + _SMP_Get_current_processor() + ); } } else { sc = RTEMS_INVALID_ID; @@ -473,9 +245,10 @@ rtems_status_code arm_gic_irq_get_priority( volatile gic_dist *dist = ARM_GIC_DIST; *priority = gic_id_get_priority(dist, vector); } else { - volatile gic_sgi_ppi *sgi_ppi = - gicv3_get_sgi_ppi(_SMP_Get_current_processor()); - *priority = sgi_ppi->icspiprior[vector]; + *priority = gicv3_sgi_ppi_get_priority( + vector, + _SMP_Get_current_processor() + ); } } else { sc = RTEMS_INVALID_ID; @@ -484,6 +257,7 @@ rtems_status_code arm_gic_irq_get_priority( return sc; } +#ifdef RTEMS_SMP rtems_status_code bsp_interrupt_set_affinity( rtems_vector_number vector, const Processor_mask *affinity @@ -516,25 +290,14 @@ rtems_status_code bsp_interrupt_get_affinity( _Processor_mask_From_uint32_t(affinity, targets, 0); return RTEMS_SUCCESSFUL; } +#endif void arm_gic_trigger_sgi(rtems_vector_number vector, uint32_t targets) { -#ifndef ARM_MULTILIB_ARCH_V4 - uint64_t mpidr; -#else - uint32_t mpidr; -#endif - mpidr = READ_SR(MPIDR); - uint64_t value = ICC_SGIR_AFFINITY2(MPIDR_AFFINITY2_GET(mpidr)) - | ICC_SGIR_INTID(vector) - | ICC_SGIR_AFFINITY1(MPIDR_AFFINITY1_GET(mpidr)) - | ICC_SGIR_CPU_TARGET_LIST(targets); -#ifndef ARM_MULTILIB_ARCH_V4 - value |= ICC_SGIR_AFFINITY3(MPIDR_AFFINITY3_GET(mpidr)); -#endif - WRITE64_SR(ICC_SGI1, value); + gicv3_trigger_sgi(vector, targets); } +#ifdef RTEMS_SMP uint32_t arm_gic_irq_processor_count(void) { volatile gic_dist *dist = ARM_GIC_DIST; @@ -561,3 +324,4 @@ uint32_t arm_gic_irq_processor_count(void) return cpu_count; } +#endif diff --git a/bsps/shared/dev/nand/VERSION b/bsps/shared/dev/nand/VERSION new file mode 100644 index 0000000000..5e4eb00fe9 --- /dev/null +++ b/bsps/shared/dev/nand/VERSION @@ -0,0 +1,24 @@ +The information in this file describes the source of files in +bsps/shared/dev/nand/ and bsps/include/dev/nand/. + +Import from: + +https://github.com/Xilinx/embeddedsw.git + +commit 5330a64c8efd14f0eef09befdbb8d3d738c33ec2 +Refs: <xilinx_v2022.2> +Author: Nicole Baze <nicole.baze@xilinx.com> +AuthorDate: Mon Oct 3 13:27:19 2022 -0700 +Commit: Siva Addepalli <sivaprasad.addepalli@xilinx.com> +CommitDate: Fri Oct 7 10:26:16 2022 +0530 + + xilpm: versal: server: Fix bug in AIE2 zeroization + + There is a bug in AIE2 zeriozation function when polling for memory + zeroization complete. Currently the entire memory register is being + checked against zero but instead we need to check the bits specific + to the memory tiles. This patch updates the zeroization check by + adding a mask so that only the desired bits are checked for zero. + + Signed-off-by: Nicole Baze <nicole.baze@xilinx.com> + Acked-by: Jesus De Haro <jesus.de-haro@xilinx.com> diff --git a/bsps/shared/dev/nand/xnandpsu.c b/bsps/shared/dev/nand/xnandpsu.c new file mode 100644 index 0000000000..79025f3c04 --- /dev/null +++ b/bsps/shared/dev/nand/xnandpsu.c @@ -0,0 +1,3027 @@ +/****************************************************************************** +* Copyright (C) 2015 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xnandpsu.c +* @addtogroup Overview +* @{ +* +* This file contains the implementation of the interface functions for +* XNandPsu driver. Refer to the header file xnandpsu.h for more detailed +* information. +* +* This module supports for NAND flash memory devices that conform to the +* "Open NAND Flash Interface" (ONFI) 3.0 Specification. This modules +* implements basic flash operations like read, write and erase. +* +* @note Driver has been renamed to nandpsu after change in +* naming convention. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- ---------- ----------------------------------------------- +* 1.0 nm 05/06/2014 First release +* 2.0 sb 01/12/2015 Removed Null checks for Buffer passed +* as parameter to Read API's +* - XNandPsu_Read() +* - XNandPsu_ReadPage +* Modified +* - XNandPsu_SetFeature() +* - XNandPsu_GetFeature() +* and made them public. +* Removed Failure Return for BCF Error check in +* XNandPsu_ReadPage() and added BCH_Error counter +* in the instance pointer structure. +* Added XNandPsu_Prepare_Cmd API +* Replaced +* - XNandPsu_IntrStsEnable +* - XNandPsu_IntrStsClear +* - XNandPsu_IntrClear +* - XNandPsu_SetProgramReg +* with XNandPsu_WriteReg call +* Modified xnandpsu.c file API's with above changes. +* Corrected the program command for Set Feature API. +* Modified +* - XNandPsu_OnfiReadStatus +* - XNandPsu_GetFeature +* - XNandPsu_SetFeature +* to add support for DDR mode. +* Changed Convention for SLC/MLC +* SLC --> HAMMING +* MLC --> BCH +* SlcMlc --> IsBCH +* Removed extra DMA mode initialization from +* the XNandPsu_CfgInitialize API. +* Modified +* - XNandPsu_SetEccAddrSize +* ECC address now is calculated based upon the +* size of spare area +* Modified Block Erase API, removed clearing of +* packet register before erase. +* Clearing Data Interface Register before +* XNandPsu_OnfiReset call. +* Modified XNandPsu_ChangeTimingMode API supporting +* SDR and NVDDR interface for timing modes 0 to 5. +* Modified Bbt Signature and Version Offset value for +* Oob and No-Oob region. +* 1.0 kpc 17/6/2015 Added timer based timeout intsead of sw counter. +* 1.1 mi 09/16/16 Removed compilation warnings with extra compiler flags. +* 1.1 nsk 11/07/16 Change memcpy to Xil_MemCpy to handle word aligned +* data access. +* 1.2 nsk 01/19/17 Fix for the failure of reading nand first redundant +* parameter page. CR#966603 +* 1.3 nsk 08/14/17 Added CCI support +* 1.4 nsk 04/10/18 Added ICCARM compiler support. CR#997552. +* 1.5 mus 11/05/18 Support 64 bit DMA addresses for Microblaze-X platform. +* 1.5 mus 11/05/18 Updated XNandPsu_ChangeClockFreq to fix compilation +* warnings. +* 1.6 sd 06/02/20 Added Clock support +* 1.6 sd 20/03/20 Added compilation flag +* 1.8 sg 03/18/21 Added validation check for parameter page. +* 1.9 akm 07/15/21 Initialize NandInstPtr with Data Interface & Timing mode info. +* 1.10 akm 10/20/21 Fix gcc warnings. +* 1.10 akm 12/21/21 Validate input parameters before use. +* 1.10 akm 01/05/22 Remove assert checks form static and internal APIs. +* 1.11 akm 03/31/22 Fix unused parameter warning. +* 1.11 akm 03/31/22 Fix misleading-indentation warning. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xnandpsu.h" +#include "xnandpsu_bbm.h" +#include "sleep.h" +#include "xil_mem.h" +/************************** Constant Definitions *****************************/ + +static const XNandPsu_EccMatrix EccMatrix[] = { + /* 512 byte page */ + {XNANDPSU_PAGE_SIZE_512, 9U, 1U, XNANDPSU_HAMMING, 0x20DU, 0x3U}, + {XNANDPSU_PAGE_SIZE_512, 9U, 4U, XNANDPSU_BCH, 0x209U, 0x7U}, + {XNANDPSU_PAGE_SIZE_512, 9U, 8U, XNANDPSU_BCH, 0x203U, 0xDU}, + /* 2K byte page */ + {XNANDPSU_PAGE_SIZE_2K, 9U, 1U, XNANDPSU_HAMMING, 0x834U, 0xCU}, + {XNANDPSU_PAGE_SIZE_2K, 9U, 4U, XNANDPSU_BCH, 0x826U, 0x1AU}, + {XNANDPSU_PAGE_SIZE_2K, 9U, 8U, XNANDPSU_BCH, 0x80cU, 0x34U}, + {XNANDPSU_PAGE_SIZE_2K, 9U, 12U, XNANDPSU_BCH, 0x822U, 0x4EU}, + {XNANDPSU_PAGE_SIZE_2K, 10U, 24U, XNANDPSU_BCH, 0x81cU, 0x54U}, + /* 4K byte page */ + {XNANDPSU_PAGE_SIZE_4K, 9U, 1U, XNANDPSU_HAMMING, 0x1068U, 0x18U}, + {XNANDPSU_PAGE_SIZE_4K, 9U, 4U, XNANDPSU_BCH, 0x104cU, 0x34U}, + {XNANDPSU_PAGE_SIZE_4K, 9U, 8U, XNANDPSU_BCH, 0x1018U, 0x68U}, + {XNANDPSU_PAGE_SIZE_4K, 9U, 12U, XNANDPSU_BCH, 0x1044U, 0x9CU}, + {XNANDPSU_PAGE_SIZE_4K, 10U, 24U, XNANDPSU_BCH, 0x1038U, 0xA8U}, + /* 8K byte page */ + {XNANDPSU_PAGE_SIZE_8K, 9U, 1U, XNANDPSU_HAMMING, 0x20d0U, 0x30U}, + {XNANDPSU_PAGE_SIZE_8K, 9U, 4U, XNANDPSU_BCH, 0x2098U, 0x68U}, + {XNANDPSU_PAGE_SIZE_8K, 9U, 8U, XNANDPSU_BCH, 0x2030U, 0xD0U}, + {XNANDPSU_PAGE_SIZE_8K, 9U, 12U, XNANDPSU_BCH, 0x2088U, 0x138U}, + {XNANDPSU_PAGE_SIZE_8K, 10U, 24U, XNANDPSU_BCH, 0x2070U, 0x150U}, + /* 16K byte page */ + {XNANDPSU_PAGE_SIZE_16K, 9U, 1U, XNANDPSU_HAMMING, 0x4460U, 0x60U}, + {XNANDPSU_PAGE_SIZE_16K, 9U, 4U, XNANDPSU_BCH, 0x43f0U, 0xD0U}, + {XNANDPSU_PAGE_SIZE_16K, 9U, 8U, XNANDPSU_BCH, 0x4320U, 0x1A0U}, + {XNANDPSU_PAGE_SIZE_16K, 9U, 12U, XNANDPSU_BCH, 0x4250U, 0x270U}, + {XNANDPSU_PAGE_SIZE_16K, 10U, 24U, XNANDPSU_BCH, 0x4220U, 0x2A0U} +}; + +/**************************** Type Definitions *******************************/ +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr); + +static s32 XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param); + +static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param); + +static void XNandPsu_InitDataInterface(XNandPsu *InstancePtr, OnfiParamPage *Param); + +static void XNandPsu_InitTimingMode(XNandPsu *InstancePtr, OnfiParamPage *Param); + +static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset, + u32 Mask, u32 Timeout); + +static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize, + u32 PktCount); + +static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col); + +static void XNandPsu_SetPageSize(XNandPsu *InstancePtr); + +static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target); + +static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target); + +static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target, + u16 *OnfiStatus); + +static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr, + u32 IdLen, u8 *Buf); + +static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target, + u8 *Buf); + +static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page, + u32 Col, u8 *Buf); + +static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page, + u32 Col, u8 *Buf); + +static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr); + +static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr); + +static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target, + u32 Col, u32 PktSize, u32 PktCount, + u8 *Buf); + +static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target, + u32 Col, u32 PktSize, u32 PktCount, + u8 *Buf); + +static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm); + +static s32 XNandPsu_Data_ReadWrite(XNandPsu *InstancePtr, u8* Buf, u32 PktCount, + u32 PktSize, u32 Operation, u8 DmaMode); + +static s32 XNandPsu_WaitFor_Transfer_Complete(XNandPsu *InstancePtr); + +static s32 XNandPsu_Device_Ready(XNandPsu *InstancePtr, u32 Target); + +static void XNandPsu_Fifo_Read(XNandPsu *InstancePtr, u8* Buf, u32 Size); + +static void XNandPsu_Fifo_Write(XNandPsu *InstancePtr, u8* Buf, u32 Size); + +static void XNandPsu_Update_DmaAddr(XNandPsu *InstancePtr, u8* Buf); +/*****************************************************************************/ +/** +* +* This function initializes a specific XNandPsu instance. This function must +* be called prior to using the NAND flash device to read or write any data. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param ConfigPtr points to XNandPsu device configuration structure. +* @param EffectiveAddr is the base address of NAND flash controller. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note The user needs to first call the XNandPsu_LookupConfig() API +* which returns the Configuration structure pointer which is +* passed as a parameter to the XNandPsu_CfgInitialize() API. +* +******************************************************************************/ +s32 XNandPsu_CfgInitialize(XNandPsu *InstancePtr, XNandPsu_Config *ConfigPtr, + u32 EffectiveAddr) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + s32 Status = XST_FAILURE; + + /* Initialize InstancePtr Config structure */ + InstancePtr->Config.DeviceId = ConfigPtr->DeviceId; + InstancePtr->Config.BaseAddress = EffectiveAddr; + InstancePtr->Config.IsCacheCoherent = ConfigPtr->IsCacheCoherent; +#if defined (XCLOCKING) + InstancePtr->Config.RefClk = ConfigPtr->RefClk; +#endif + /* Operate in Polling Mode */ + InstancePtr->Mode = XNANDPSU_POLLING; + /* Enable MDMA mode by default */ + InstancePtr->DmaMode = XNANDPSU_MDMA; + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + +#ifdef __rtems__ + /* Set page cache to unavailable */ + InstancePtr->PartialDataPageIndex = XNANDPSU_PAGE_CACHE_UNAVAILABLE; +#endif + + /* Initialize the NAND flash targets */ + Status = XNandPsu_FlashInit(InstancePtr); + if (Status != XST_SUCCESS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Flash init failed\r\n",__func__); +#endif + goto Out; + } + /* Set ECC mode */ + if (InstancePtr->Features.EzNand != 0U) { + InstancePtr->EccMode = XNANDPSU_EZNAND; + } else if (InstancePtr->Features.OnDie != 0U) { + InstancePtr->EccMode = XNANDPSU_ONDIE; + } else { + InstancePtr->EccMode = XNANDPSU_HWECC; + } + + /* Initialize Ecc Error flip counters */ + InstancePtr->Ecc_Stat_PerPage_flips = 0U; + InstancePtr->Ecc_Stats_total_flips = 0U; + + /* + * Scan for the bad block table(bbt) stored in the flash & load it in + * memory(RAM). If bbt is not found, create bbt by scanning factory + * marked bad blocks and store it in last good blocks of flash. + */ + XNandPsu_InitBbtDesc(InstancePtr); + Status = XNandPsu_ScanBbt(InstancePtr); + if (Status != XST_SUCCESS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: BBT scan failed\r\n",__func__); +#endif + goto Out; + } + +#ifdef __rtems__ + /* Set page cache to none */ + InstancePtr->PartialDataPageIndex = XNANDPSU_PAGE_CACHE_NONE; +#endif +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function initializes the NAND flash and gets the geometry information. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_FlashInit(XNandPsu *InstancePtr) +{ + u32 Target; + u8 Id[ONFI_SIG_LEN] = {0U}; + OnfiParamPage Param[ONFI_MND_PRM_PGS] = {0U}; + s32 Status = XST_FAILURE; + u32 Index; + u32 Crc; + u32 PrmPgOff; + u32 PrmPgLen; +#ifdef __ICCARM__ +#pragma pack(push, 1) + OnfiExtPrmPage ExtParam = {0U}; +#pragma pack(pop) +#else + OnfiExtPrmPage ExtParam __attribute__ ((aligned(64))) = {0U}; +#endif + + /* Clear Data Interface Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_DATA_INTF_OFFSET, 0U); + + /* Clear DMA Buffer Boundary Register */ + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_DMA_BUF_BND_OFFSET, 0U); + + for (Target = 0U; Target < XNANDPSU_MAX_TARGETS; Target++) { + /* Reset the Target */ + Status = XNandPsu_OnfiReset(InstancePtr, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Read ONFI ID */ + Status = XNandPsu_OnfiReadId(InstancePtr, Target, + ONFI_READ_ID_ADDR, + ONFI_SIG_LEN, + (u8 *)&Id[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + if (!IS_ONFI(Id)) { + if (Target == 0U) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: ONFI ID doesn't match\r\n", + __func__); +#endif + Status = XST_FAILURE; + goto Out; + } + } + + /* Read Parameter Page */ + Status = XNandPsu_OnfiReadParamPage(InstancePtr, + Target, (u8 *)&Param[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + for(Index = 0U; Index < ONFI_MND_PRM_PGS; Index++){ + /* Check CRC */ + Crc = XNandPsu_OnfiParamPageCrc((u8*)&Param[Index], 0U, + ONFI_CRC_LEN); + if (Crc != Param[Index].Crc) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: ONFI parameter page (%d) crc check failed\r\n", + __func__, Index); +#endif + continue; + } else { + break; + } + } + if (Index >= ONFI_MND_PRM_PGS) { + Status = XST_FAILURE; + goto Out; + } + /* Fill Geometry for the first target */ + if (Target == 0U) { + Status = XNandPsu_InitGeometry(InstancePtr, &Param[Index]); + if (Status != XST_SUCCESS) { + goto Out; + } + XNandPsu_InitDataInterface(InstancePtr, &Param[Index]); + XNandPsu_InitTimingMode(InstancePtr, &Param[Index]); + XNandPsu_InitFeatures(InstancePtr, &Param[Index]); + if ((!InstancePtr->Features.EzNand) != 0U) { + Status =XNandPsu_CheckOnDie(InstancePtr); + if (Status != XST_SUCCESS) { + InstancePtr->Features.OnDie = 0U; + } + } + if ((InstancePtr->Geometry.NumBitsECC == 0xFFU) && + (InstancePtr->Features.ExtPrmPage != 0U)) { + /* ONFI 3.1 section 5.7.1.6 & 5.7.1.7 */ + PrmPgLen = (u32)Param[Index].ExtParamPageLen * 16U; + PrmPgOff = (u32)((u32)Param[Index].NumOfParamPages * + ONFI_PRM_PG_LEN) + (Index * (u32)PrmPgLen); + + Status = XNandPsu_ChangeReadColumn( + InstancePtr, Target, + PrmPgOff, PrmPgLen, 1U, + (u8 *)(void *)&ExtParam); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Check CRC */ + Crc = XNandPsu_OnfiParamPageCrc( + (u8 *)&ExtParam, + 2U, PrmPgLen); + if (Crc != ExtParam.Crc) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: ONFI extended parameter page (%d) crc check failed\r\n", + __func__, Index); +#endif + Status = XST_FAILURE; + goto Out; + } + /* Initialize Extended ECC info */ + Status = XNandPsu_InitExtEcc( + InstancePtr, + &ExtParam); + if (Status != XST_SUCCESS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Init extended ecc failed\r\n",__func__); +#endif + goto Out; + } + } + /* Configure ECC settings */ + XNandPsu_SetEccAddrSize(InstancePtr); + } + InstancePtr->Geometry.NumTargets++; + } + /* Calculate total number of blocks and total size of flash */ + InstancePtr->Geometry.NumPages = InstancePtr->Geometry.NumTargets * + InstancePtr->Geometry.NumTargetPages; + InstancePtr->Geometry.NumBlocks = InstancePtr->Geometry.NumTargets * + InstancePtr->Geometry.NumTargetBlocks; + InstancePtr->Geometry.DeviceSize = + (u64)InstancePtr->Geometry.NumTargets * + InstancePtr->Geometry.TargetSize; + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function initializes the geometry information from ONFI parameter page. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Param is pointer to the ONFI parameter page. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_InitGeometry(XNandPsu *InstancePtr, OnfiParamPage *Param) +{ + s32 Status = XST_FAILURE; + + if (Param->BytesPerPage > XNANDPSU_MAX_PAGE_SIZE) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Invalid Bytes Per Page %d\r\n", + __func__, Param->BytesPerPage); +#endif + goto Out; + } + InstancePtr->Geometry.BytesPerPage = Param->BytesPerPage; + + + if (Param->SpareBytesPerPage > XNANDPSU_MAX_SPARE_SIZE) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Invalid Spare Bytes Per Page %d\r\n", + __func__, Param->SpareBytesPerPage); +#endif + goto Out; + } + InstancePtr->Geometry.SpareBytesPerPage = Param->SpareBytesPerPage; + + if (Param->PagesPerBlock > XNANDPSU_MAX_PAGES_PER_BLOCK) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Invalid Page Count Per Block %d\r\n", + __func__, Param->PagesPerBlock); +#endif + goto Out; + } + InstancePtr->Geometry.PagesPerBlock = Param->PagesPerBlock; + + + if (Param->BlocksPerLun > XNANDPSU_MAX_BLOCKS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Invalid block count per LUN %d\r\n", + __func__, Param->BlocksPerLun); +#endif + goto Out; + } + InstancePtr->Geometry.BlocksPerLun = Param->BlocksPerLun; + + if (Param->NumLuns > XNANDPSU_MAX_LUNS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Invalid LUN count %d\r\n", + __func__, Param->NumLuns); +#endif + goto Out; + } + InstancePtr->Geometry.NumLuns = Param->NumLuns; + + InstancePtr->Geometry.RowAddrCycles = Param->AddrCycles & 0xFU; + InstancePtr->Geometry.ColAddrCycles = (Param->AddrCycles >> 4U) & 0xFU; + InstancePtr->Geometry.NumBitsPerCell = Param->BitsPerCell; + InstancePtr->Geometry.NumBitsECC = Param->EccBits; + InstancePtr->Geometry.BlockSize = (Param->PagesPerBlock * + Param->BytesPerPage); + InstancePtr->Geometry.NumTargetBlocks = (Param->BlocksPerLun * + (u32)Param->NumLuns); + InstancePtr->Geometry.NumTargetPages = (Param->BlocksPerLun * + (u32)Param->NumLuns * + Param->PagesPerBlock); + InstancePtr->Geometry.TargetSize = ((u64)Param->BlocksPerLun * + (u64)Param->NumLuns * + (u64)Param->PagesPerBlock * + (u64)Param->BytesPerPage); + InstancePtr->Geometry.EccCodeWordSize = 9U; /* 2 power of 9 = 512 */ + if (InstancePtr->Geometry.NumTargetBlocks > XNANDPSU_MAX_BLOCKS) + xil_printf("!!! Device contains more blocks than the max defined blocks in driver\r\n"); + +#ifdef XNANDPSU_DEBUG + xil_printf("Manufacturer: %s\r\n", Param->DeviceManufacturer); + xil_printf("Device Model: %s\r\n", Param->DeviceModel); + xil_printf("Jedec ID: 0x%x\r\n", Param->JedecManufacturerId); + xil_printf("Bytes Per Page: 0x%x\r\n", Param->BytesPerPage); + xil_printf("Spare Bytes Per Page: 0x%x\r\n", Param->SpareBytesPerPage); + xil_printf("Pages Per Block: 0x%x\r\n", Param->PagesPerBlock); + xil_printf("Blocks Per LUN: 0x%x\r\n", Param->BlocksPerLun); + xil_printf("Number of LUNs: 0x%x\r\n", Param->NumLuns); + xil_printf("Number of bits per cell: 0x%x\r\n", Param->BitsPerCell); + xil_printf("Number of ECC bits: 0x%x\r\n", Param->EccBits); + xil_printf("Block Size: 0x%x\r\n", InstancePtr->Geometry.BlockSize); + + xil_printf("Number of Target Blocks: 0x%x\r\n", + InstancePtr->Geometry.NumTargetBlocks); + xil_printf("Number of Target Pages: 0x%x\r\n", + InstancePtr->Geometry.NumTargetPages); + +#endif + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function initializes the feature list from ONFI parameter page. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Param is pointer to ONFI parameter page buffer. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_InitFeatures(XNandPsu *InstancePtr, OnfiParamPage *Param) +{ + InstancePtr->Features.NvDdr = ((Param->Features & (1U << 5)) != 0U) ? + 1U : 0U; + InstancePtr->Features.EzNand = ((Param->Features & (1U << 9)) != 0U) ? + 1U : 0U; + InstancePtr->Features.ExtPrmPage = ((Param->Features & (1U << 7)) != 0U) ? + 1U : 0U; +} + +/*****************************************************************************/ +/** +* +* This function initializes the Data Interface from ONFI parameter page. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Param is pointer to ONFI parameter page buffer. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_InitDataInterface(XNandPsu *InstancePtr, OnfiParamPage *Param) +{ + if (Param->NVDDRTimingMode) + InstancePtr->DataInterface = XNANDPSU_NVDDR; + else if (Param->SDRTimingMode) + InstancePtr->DataInterface = XNANDPSU_SDR; +} + +/*****************************************************************************/ +/** +* +* This function initializes the Timing mode from ONFI parameter page. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Param is pointer to ONFI parameter page buffer. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_InitTimingMode(XNandPsu *InstancePtr, OnfiParamPage *Param) +{ + s8 Mode; + u8 TimingMode = (u8)(Param->SDRTimingMode); + + if (InstancePtr->DataInterface == XNANDPSU_NVDDR) + TimingMode = Param->NVDDRTimingMode; + + for(Mode = XNANDPSU_MAX_TIMING_MODE; Mode >= 0; Mode--) { + if (TimingMode & (0x01 << Mode)) { + InstancePtr->TimingMode = Mode; + break; + } else { + continue; + } + } +} + +/*****************************************************************************/ +/** +* +* This function checks if the flash supports on-die ECC. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Param is pointer to ONFI parameter page. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_CheckOnDie(XNandPsu *InstancePtr) +{ + s32 Status = XST_FAILURE; + u8 JedecId[2] = {0U}; + u8 EccSetFeature[4] = {0x08U, 0x00U, 0x00U, 0x00U}; + u8 EccGetFeature[4] ={0U}; + + /* + * Check if this flash supports On-Die ECC. + * For more information, refer to Micron TN2945. + * Micron Flash: MT29F1G08ABADA, MT29F1G08ABBDA + * MT29F1G16ABBDA, + * MT29F2G08ABBEA, MT29F2G16ABBEA, + * MT29F2G08ABAEA, MT29F2G16ABAEA, + * MT29F4G08ABBDA, MT29F4G16ABBDA, + * MT29F4G08ABADA, MT29F4G16ABADA, + * MT29F8G08ADBDA, MT29F8G16ADBDA, + * MT29F8G08ADADA, MT29F8G16ADADA + */ + + /* Read JEDEC ID */ + Status = XNandPsu_OnfiReadId(InstancePtr, 0U, 0x00U, 2U, &JedecId[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + if ((JedecId[0] == 0x2CU) && + /* 1 Gb flash devices */ + ((JedecId[1] == 0xF1U) || + (JedecId[1] == 0xA1U) || + (JedecId[1] == 0xB1U) || + /* 2 Gb flash devices */ + (JedecId[1] == 0xAAU) || + (JedecId[1] == 0xBAU) || + (JedecId[1] == 0xDAU) || + (JedecId[1] == 0xCAU) || + /* 4 Gb flash devices */ + (JedecId[1] == 0xACU) || + (JedecId[1] == 0xBCU) || + (JedecId[1] == 0xDCU) || + (JedecId[1] == 0xCCU) || + /* 8 Gb flash devices */ + (JedecId[1] == 0xA3U) || + (JedecId[1] == 0xB3U) || + (JedecId[1] == 0xD3U) || + (JedecId[1] == 0xC3U))) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Ondie flash detected, jedec id 0x%x 0x%x\r\n", + __func__, JedecId[0], JedecId[1]); +#endif + /* On-Die Set Feature */ + Status = XNandPsu_SetFeature(InstancePtr, 0U, 0x90U, + &EccSetFeature[0]); + if (Status != XST_SUCCESS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Ondie set_feature failed\r\n", + __func__); +#endif + goto Out; + } + /* Check to see if ECC feature is set */ + Status = XNandPsu_GetFeature(InstancePtr, 0U, 0x90U, + &EccGetFeature[0]); + if (Status != XST_SUCCESS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Ondie get_feature failed\r\n", + __func__); +#endif + goto Out; + } + if ((EccGetFeature[0] & 0x08U) != 0U) { + InstancePtr->Features.OnDie = 1U; + Status = XST_SUCCESS; + } + } else { + /* On-Die flash not found */ + Status = XST_FAILURE; + } +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function enables DMA mode of controller operation. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +void XNandPsu_EnableDmaMode(XNandPsu *InstancePtr) +{ + /* Assert the input arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->DmaMode = XNANDPSU_MDMA; +} + +/*****************************************************************************/ +/** +* +* This function disables DMA mode of driver/controller operation. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +void XNandPsu_DisableDmaMode(XNandPsu *InstancePtr) +{ + /* Assert the input arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->DmaMode = XNANDPSU_PIO; +} + +/*****************************************************************************/ +/** +* +* This function enables ECC mode of driver/controller operation. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +void XNandPsu_EnableEccMode(XNandPsu *InstancePtr) +{ + /* Assert the input arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->EccMode = XNANDPSU_HWECC; +} + +/*****************************************************************************/ +/** +* +* This function disables ECC mode of driver/controller operation. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +void XNandPsu_DisableEccMode(XNandPsu *InstancePtr) +{ + /* Assert the input arguments. */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->EccMode = XNANDPSU_NONE; +} + +#ifdef __rtems__ +#include <rtems/rtems/clock.h> +static void udelay( void ) +{ + uint64_t time = rtems_clock_get_uptime_nanoseconds() + 1000; + while (1) { + uint64_t newtime = rtems_clock_get_uptime_nanoseconds(); + if (newtime > time) { + break; + } + } +} +#define usleep(x) udelay() +#endif + +/*****************************************************************************/ +/** +* +* This function polls for a register bit set status till the timeout. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param RegOffset is the offset of register. +* @param Mask is the bitmask. +* @param Timeout is the timeout value. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_PollRegTimeout(XNandPsu *InstancePtr, u32 RegOffset, + u32 Mask, u32 Timeout) +{ + s32 Status = XST_FAILURE; + volatile u32 RegVal; + u32 TimeoutVar = Timeout; + + while (TimeoutVar > 0U) { + RegVal = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress, + RegOffset) & Mask; + if (RegVal != 0U) { + break; + } + TimeoutVar--; + usleep(1); + } + + if (TimeoutVar <= 0U) { + Status = XST_FAILURE; + } else { + Status = XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sets packet size and packet count values in packet register. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param PktSize is the packet size. +* @param PktCount is the packet count. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_SetPktSzCnt(XNandPsu *InstancePtr, u32 PktSize, + u32 PktCount) +{ + /* Update Packet Register with pkt size and count */ + XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_PKT_OFFSET, + ((u32)XNANDPSU_PKT_PKT_SIZE_MASK | + (u32)XNANDPSU_PKT_PKT_CNT_MASK), + ((PktSize & XNANDPSU_PKT_PKT_SIZE_MASK) | + ((PktCount << XNANDPSU_PKT_PKT_CNT_SHIFT) & + XNANDPSU_PKT_PKT_CNT_MASK))); +} + +/*****************************************************************************/ +/** +* +* This function sets Page and Column values in the Memory address registers. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Page is the page value. +* @param Col is the column value. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_SetPageColAddr(XNandPsu *InstancePtr, u32 Page, u16 Col) +{ + /* Program Memory Address Register 1 */ + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_MEM_ADDR1_OFFSET, + (((u32)Col & XNANDPSU_MEM_ADDR1_COL_ADDR_MASK) | + ((Page << (u32)XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) & + XNANDPSU_MEM_ADDR1_PG_ADDR_MASK))); + /* Program Memory Address Register 2 */ + XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET, + XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK, + ((Page >> XNANDPSU_MEM_ADDR1_PG_ADDR_SHIFT) & + XNANDPSU_MEM_ADDR2_MEM_ADDR_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function sets the size of page in Command Register. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_SetPageSize(XNandPsu *InstancePtr) +{ + u32 PageSizeMask = 0; + u32 PageSize = InstancePtr->Geometry.BytesPerPage; + + /* Calculate page size mask */ + switch(PageSize) { + case XNANDPSU_PAGE_SIZE_512: + PageSizeMask = (0U << XNANDPSU_CMD_PG_SIZE_SHIFT); + break; + case XNANDPSU_PAGE_SIZE_2K: + PageSizeMask = (1U << XNANDPSU_CMD_PG_SIZE_SHIFT); + break; + case XNANDPSU_PAGE_SIZE_4K: + PageSizeMask = (2U << XNANDPSU_CMD_PG_SIZE_SHIFT); + break; + case XNANDPSU_PAGE_SIZE_8K: + PageSizeMask = (3U << XNANDPSU_CMD_PG_SIZE_SHIFT); + break; + case XNANDPSU_PAGE_SIZE_16K: + PageSizeMask = (4U << XNANDPSU_CMD_PG_SIZE_SHIFT); + break; + case XNANDPSU_PAGE_SIZE_1K_16BIT: + PageSizeMask = (5U << XNANDPSU_CMD_PG_SIZE_SHIFT); + break; + default: + /* Not supported */ + break; + } + /* Update Command Register */ + XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_CMD_OFFSET, + XNANDPSU_CMD_PG_SIZE_MASK, PageSizeMask); +} + +/*****************************************************************************/ +/** +* +* This function setup the Ecc Register. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_SetEccAddrSize(XNandPsu *InstancePtr) +{ + u32 PageSize = InstancePtr->Geometry.BytesPerPage; + u32 CodeWordSize = InstancePtr->Geometry.EccCodeWordSize; + u32 NumEccBits = InstancePtr->Geometry.NumBitsECC; + u32 Index; + u32 Found = 0U; + u8 BchModeVal; + + for (Index = 0U; Index < (sizeof(EccMatrix)/sizeof(XNandPsu_EccMatrix)); + Index++) { + if ((EccMatrix[Index].PageSize == PageSize) && + (EccMatrix[Index].CodeWordSize >= CodeWordSize)) { + if (EccMatrix[Index].NumEccBits >= NumEccBits) { + Found = Index; + break; + } + else { + Found = Index; + } + } + } + + if (Found != 0U) { + if(InstancePtr->Geometry.SpareBytesPerPage < 64U) { + InstancePtr->EccCfg.EccAddr = (u16)PageSize; + } + else { + InstancePtr->EccCfg.EccAddr = ((u16)PageSize + + (InstancePtr->Geometry.SpareBytesPerPage + - EccMatrix[Found].EccSize)); + } + InstancePtr->EccCfg.EccSize = EccMatrix[Found].EccSize; + InstancePtr->EccCfg.NumEccBits = EccMatrix[Found].NumEccBits; + InstancePtr->EccCfg.CodeWordSize = + EccMatrix[Found].CodeWordSize; +#ifdef XNANDPSU_DEBUG + xil_printf("ECC: addr 0x%x size 0x%x numbits %d " + "codesz %d\r\n", + InstancePtr->EccCfg.EccAddr, + InstancePtr->EccCfg.EccSize, + InstancePtr->EccCfg.NumEccBits, + InstancePtr->EccCfg.CodeWordSize); +#endif + if (EccMatrix[Found].IsBCH == XNANDPSU_HAMMING) { + InstancePtr->EccCfg.IsBCH = 0U; + } else { + InstancePtr->EccCfg.IsBCH = 1U; + } + /* Write ECC register */ + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + (u32)XNANDPSU_ECC_OFFSET, + ((u32)InstancePtr->EccCfg.EccAddr | + ((u32)InstancePtr->EccCfg.EccSize << (u32)16) | + ((u32)InstancePtr->EccCfg.IsBCH << (u32)27))); + + if (EccMatrix[Found].IsBCH == XNANDPSU_BCH) { + /* Write memory address register 2 */ + switch(InstancePtr->EccCfg.NumEccBits) { + case 16U: + BchModeVal = 0x0U; + break; + case 12U: + BchModeVal = 0x1U; + break; + case 8U: + BchModeVal = 0x2U; + break; + case 4U: + BchModeVal = 0x3U; + break; + case 24U: + BchModeVal = 0x4U; + break; + default: + BchModeVal = 0x0U; + break; + } + XNandPsu_ReadModifyWrite(InstancePtr, + XNANDPSU_MEM_ADDR2_OFFSET, + XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_MASK, + ((u32)BchModeVal << + (u32)XNANDPSU_MEM_ADDR2_NFC_BCH_MODE_SHIFT)); + } + } +} + +/*****************************************************************************/ +/** +* +* This function setup the Ecc Spare Command Register. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_SetEccSpareCmd(XNandPsu *InstancePtr, u16 SpareCmd, + u8 AddrCycles) +{ + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + (u32)XNANDPSU_ECC_SPR_CMD_OFFSET, + (u32)SpareCmd | ((u32)AddrCycles << 28U)); +} + +/*****************************************************************************/ +/** +* +* This function sets the chip select value in memory address2 register. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_SelectChip(XNandPsu *InstancePtr, u32 Target) +{ +#if defined (XCLOCKING) + Xil_ClockEnable(InstancePtr->Config.RefClk); +#endif + /* Update Memory Address2 register with chip select */ + XNandPsu_ReadModifyWrite(InstancePtr, XNANDPSU_MEM_ADDR2_OFFSET, + XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK, + ((Target << XNANDPSU_MEM_ADDR2_CHIP_SEL_SHIFT) & + XNANDPSU_MEM_ADDR2_CHIP_SEL_MASK)); +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Reset command to the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_OnfiReset(XNandPsu *InstancePtr, u32 Target) +{ + s32 Status = XST_FAILURE; + + /* Enable Transfer Complete Interrupt in Interrupt Status Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK); + /* Program Command Register */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RST, ONFI_CMD_INVALID, 0U, + 0U, 0U); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set Reset in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET, XNANDPSU_PROG_RST_MASK); + + /* Poll for Transfer Complete event */ + Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Read Status command to the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param OnfiStatus is the ONFI status value to return. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_OnfiReadStatus(XNandPsu *InstancePtr, u32 Target, + u16 *OnfiStatus) +{ + s32 Status = XST_FAILURE; + + /* Enable Transfer Complete Interrupt in Interrupt Status Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK); + /* Program Command Register */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_STS, ONFI_CMD_INVALID, + 0U, 0U, 0U); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Program Packet Size and Packet Count */ + if(InstancePtr->DataInterface == XNANDPSU_SDR) + XNandPsu_SetPktSzCnt(InstancePtr, 1U, 1U); + else + XNandPsu_SetPktSzCnt(InstancePtr, 2U, 1U); + + /* Set Read Status in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_STS_MASK); + /* Poll for Transfer Complete event */ + Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr); + /* Read Flash Status */ + *OnfiStatus = (u16) XNandPsu_ReadReg(InstancePtr->Config.BaseAddress, + XNANDPSU_FLASH_STS_OFFSET); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Read ID command to the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Buf is the ONFI ID value to return. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_OnfiReadId(XNandPsu *InstancePtr, u32 Target, u8 IdAddr, + u32 IdLen, u8 *Buf) +{ + s32 Status = XST_FAILURE; + u32 Index; + u32 Rem; + u32 RegVal; + u32 RemIdx; + + u32 *BufPtr = (u32 *)(void *)Buf; + + /* + * Enable Buffer Read Ready Interrupt in Interrupt Status Enable + * Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK); + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_ID, ONFI_CMD_INVALID, 0U, + 0U, ONFI_READ_ID_ADDR_CYCLES); + + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, 0U, IdAddr); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, IdLen, 1U); + /* Set Read ID in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_ID_MASK); + + /* Poll for Buffer Read Ready event */ + Status = XNandPsu_PollRegTimeout( + InstancePtr, + XNANDPSU_INTR_STS_OFFSET, + XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK, + XNANDPSU_INTR_POLL_TIMEOUT); + if (Status != XST_SUCCESS) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Poll for buf read ready timeout\r\n", + __func__); +#endif + goto Out; + } + /* + * Enable Transfer Complete Interrupt in Interrupt + * Status Enable Register + */ + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK); + + /* + * Clear Buffer Read Ready Interrupt in Interrupt Status + * Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET, + XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK); + /* Read Packet Data from Data Port Register */ + for (Index = 0U; Index < (IdLen/4); Index++) { + *(BufPtr+Index) = XNandPsu_ReadReg( + InstancePtr->Config.BaseAddress, + XNANDPSU_BUF_DATA_PORT_OFFSET); + } + Rem = IdLen % 4; + if (Rem != 0U) { + RegVal = XNandPsu_ReadReg( + InstancePtr->Config.BaseAddress, + XNANDPSU_BUF_DATA_PORT_OFFSET); + for (RemIdx = 0U; RemIdx < Rem; RemIdx++) { + *(Buf + (Index * 4U) + RemIdx) = (u8) (RegVal >> + (RemIdx * 8U)) & 0xFFU; + } + } + + Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr); + +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends the ONFI Read Parameter Page command to flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param PrmIndex is the index of parameter page. +* @param Buf is the parameter page information to return. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_OnfiReadParamPage(XNandPsu *InstancePtr, u32 Target, + u8 *Buf) +{ + s32 Status = XST_FAILURE; + + /* + * Enable Buffer Read Ready Interrupt in Interrupt Status Enable + * Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK); + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD_PRM_PG, ONFI_CMD_INVALID, + 0U, 0U, ONFI_PRM_PG_ADDR_CYCLES); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, 0U, 0U); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, ONFI_MND_PRM_PGS*ONFI_PRM_PG_LEN, 1U); + /* Set Read Parameter Page in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_PRM_PG_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, 1U, ONFI_MND_PRM_PGS*ONFI_PRM_PG_LEN, 0, 0); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function returns the length including bad blocks from a given offset and +* length. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Offset is the flash data address to read from. +* @param Length is number of bytes to read. +* +* @return +* - Return actual length including bad blocks. +* +* @note None. +* +******************************************************************************/ +static s32 XNandPsu_CalculateLength(XNandPsu *InstancePtr, u64 Offset, + u64 Length) +{ + s32 Status; + u32 BlockSize; + u32 BlockLen; + u32 Block; + u64 TempLen = 0; + u64 OffsetVar = Offset; + + BlockSize = InstancePtr->Geometry.BlockSize; + + while (TempLen < Length) { + Block = (u32)(OffsetVar/BlockSize); + BlockLen = BlockSize - (u32)(OffsetVar % BlockSize); + if (OffsetVar >= InstancePtr->Geometry.DeviceSize) { + Status = XST_FAILURE; + goto Out; + } + /* Check if the block is bad */ + Status = XNandPsu_IsBlockBad(InstancePtr, Block); + if (Status != XST_SUCCESS) { + /* Good block */ + TempLen += BlockLen; + } + OffsetVar += BlockLen; + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function writes to the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Offset is the starting offset of flash to write. +* @param Length is the number of bytes to write. +* @param SrcBuf is the source data buffer to write. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_Write(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *SrcBuf) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(SrcBuf != NULL); + Xil_AssertNonvoid(Length != 0U); + Xil_AssertNonvoid((Offset + Length) <= + InstancePtr->Geometry.DeviceSize); + + s32 Status = XST_FAILURE; + u32 Page; + u32 Col; + u32 Target; + u32 Block; + u32 PartialBytes = 0; + u32 NumBytes; + u32 RemLen; + u8 *BufPtr; + u8 *SrcBufPtr = (u8 *)SrcBuf; + u64 OffsetVar = Offset; + u64 LengthVar = Length; + + /* + * Check if write operation exceeds flash size when including + * bad blocks. + */ + Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar); + if (Status != XST_SUCCESS) { + goto Out; + } + +#ifdef __rtems__ + if (InstancePtr->PartialDataPageIndex != XNANDPSU_PAGE_CACHE_UNAVAILABLE) { + /* All writes invalidate the page cache */ + InstancePtr->PartialDataPageIndex = XNANDPSU_PAGE_CACHE_NONE; + } +#endif + while (LengthVar > 0U) { + Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize); + /* + * Skip the bad blocks. Increment the offset by block size. + * For better results, always program the flash starting at + * a block boundary. + */ + if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) { + OffsetVar += (u64)InstancePtr->Geometry.BlockSize; + continue; + } + /* Calculate Page and Column address values */ + Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage); + Col = (u32) (OffsetVar & + (InstancePtr->Geometry.BytesPerPage - 1U)); + PartialBytes = 0U; + /* + * Check if partial write. + * If column address is > 0 or Length is < page size + */ + if ((Col > 0U) || + (LengthVar < InstancePtr->Geometry.BytesPerPage)) { + RemLen = InstancePtr->Geometry.BytesPerPage - Col; + PartialBytes = (RemLen < (u32)LengthVar) ? + RemLen : (u32)LengthVar; + } + + Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize); +#ifdef __rtems__ + { +#else + if (Page > InstancePtr->Geometry.NumTargetPages) { +#endif + Page %= InstancePtr->Geometry.NumTargetPages; + } + + /* Check if partial write */ + if (PartialBytes > 0U) { + BufPtr = &InstancePtr->PartialDataBuf[0]; + (void)memset(BufPtr, 0xFF, + InstancePtr->Geometry.BytesPerPage); + (void)Xil_MemCpy(BufPtr + Col, SrcBufPtr, PartialBytes); + + NumBytes = PartialBytes; + } else { + BufPtr = (u8 *)SrcBufPtr; + NumBytes = (InstancePtr->Geometry.BytesPerPage < + (u32)LengthVar) ? + InstancePtr->Geometry.BytesPerPage : + (u32)LengthVar; + } + /* Program page */ + Status = XNandPsu_ProgramPage(InstancePtr, Target, Page, 0U, + BufPtr); + if (Status != XST_SUCCESS) + goto Out; + + Status = XNandPsu_Device_Ready(InstancePtr, Target); + if (Status != XST_SUCCESS) + goto Out; + + SrcBufPtr += NumBytes; + OffsetVar += NumBytes; + LengthVar -= NumBytes; + } + +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function reads from the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Offset is the starting offset of flash to read. +* @param Length is the number of bytes to read. +* @param DestBuf is the destination data buffer to fill in. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_Read(XNandPsu *InstancePtr, u64 Offset, u64 Length, u8 *DestBuf) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(DestBuf != NULL); + Xil_AssertNonvoid(Length != 0U); + Xil_AssertNonvoid((Offset + Length) <= + InstancePtr->Geometry.DeviceSize); + + s32 Status = XST_FAILURE; + u32 Page; + u32 Col; + u32 Target; + u32 Block; + u32 PartialBytes = 0U; + u32 RemLen; + u32 NumBytes; + u8 *BufPtr; + u8 *DestBufPtr = (u8 *)DestBuf; + u64 OffsetVar = Offset; + u64 LengthVar = Length; + + /* + * Check if read operation exceeds flash size when including + * bad blocks. + */ + Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar); + if (Status != XST_SUCCESS) { + goto Out; + } + + while (LengthVar > 0U) { + Block = (u32)(OffsetVar/InstancePtr->Geometry.BlockSize); + /* + * Skip the bad block. Increment the offset by block size. + * The flash programming utility must make sure to start + * writing always at a block boundary and skip blocks if any. + */ + if (XNandPsu_IsBlockBad(InstancePtr, Block) == XST_SUCCESS) { + OffsetVar += (u64)InstancePtr->Geometry.BlockSize; + continue; + } + /* Calculate Page and Column address values */ + Page = (u32) (OffsetVar/InstancePtr->Geometry.BytesPerPage); + Col = (u32) (OffsetVar & + (InstancePtr->Geometry.BytesPerPage - 1U)); + PartialBytes = 0U; + /* + * Check if partial write. + * If column address is > 0 or Length is < page size + */ + if ((Col > 0U) || + (LengthVar < InstancePtr->Geometry.BytesPerPage)) { + RemLen = InstancePtr->Geometry.BytesPerPage - Col; + PartialBytes = ((u32)RemLen < (u32)LengthVar) ? + (u32)RemLen : (u32)LengthVar; + } + + Target = (u32) (OffsetVar/InstancePtr->Geometry.TargetSize); +#ifdef __rtems__ + { +#else + if (Page > InstancePtr->Geometry.NumTargetPages) { +#endif + Page %= InstancePtr->Geometry.NumTargetPages; + } + /* Check if partial read */ + if (PartialBytes > 0U) { + BufPtr = &InstancePtr->PartialDataBuf[0]; + NumBytes = PartialBytes; + } else { + BufPtr = DestBufPtr; + NumBytes = (InstancePtr->Geometry.BytesPerPage < + (u32)LengthVar) ? + InstancePtr->Geometry.BytesPerPage : + (u32)LengthVar; + } +#ifdef __rtems__ + if (Page == InstancePtr->PartialDataPageIndex) { + /* + * This is a whole page read for the currently cached + * page. It will not be taken care of below, so perform + * the copy here. + */ + if (PartialBytes == 0U) { + (void)Xil_MemCpy(DestBufPtr, + &InstancePtr->PartialDataBuf[0], + NumBytes); + } + } else { +#endif + /* Read page */ + Status = XNandPsu_ReadPage(InstancePtr, Target, Page, 0U, + BufPtr); +#ifdef __rtems__ + if (PartialBytes > 0U && + InstancePtr->PartialDataPageIndex != XNANDPSU_PAGE_CACHE_UNAVAILABLE) { + /* + * Partial read into page cache. Update the + * cached page index. + */ + InstancePtr->PartialDataPageIndex = Page; + } + } +#endif + if (Status != XST_SUCCESS) { + goto Out; + } + if (PartialBytes > 0U) { + (void)Xil_MemCpy(DestBufPtr, BufPtr + Col, NumBytes); +#ifdef __rtems__ + /* The destination buffer is touched by hardware, synchronize */ + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheFlushRange((INTPTR)(void *)DestBufPtr, NumBytes); + } +#endif + } + DestBufPtr += NumBytes; + OffsetVar += NumBytes; + LengthVar -= NumBytes; + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function erases the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Offset is the starting offset of flash to erase. +* @param Length is the number of bytes to erase. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note +* The Offset and Length should be aligned to block size boundary +* to get better results. +* +******************************************************************************/ +s32 XNandPsu_Erase(XNandPsu *InstancePtr, u64 Offset, u64 Length) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Length != 0U); + Xil_AssertNonvoid((Offset + Length) <= + InstancePtr->Geometry.DeviceSize); + + s32 Status = XST_FAILURE; + u32 Target = 0; + u32 StartBlock; + u32 NumBlocks = 0; + u32 Block; + u32 AlignOff; + u32 EraseLen; + u32 BlockRemLen; + u64 OffsetVar = Offset; + u64 LengthVar = Length; + + /* + * Check if erase operation exceeds flash size when including + * bad blocks. + */ + Status = XNandPsu_CalculateLength(InstancePtr, OffsetVar, LengthVar); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Calculate number of blocks to erase */ + StartBlock = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize); + + while (LengthVar > 0U) { + Block = (u32) (OffsetVar/InstancePtr->Geometry.BlockSize); + if (XNandPsu_IsBlockBad(InstancePtr, Block) == + XST_SUCCESS) { + OffsetVar += (u64)InstancePtr->Geometry.BlockSize; + NumBlocks++; + continue; + } + + AlignOff = (u32)OffsetVar & + (InstancePtr->Geometry.BlockSize - (u32)1); + if (AlignOff > 0U) { + BlockRemLen = InstancePtr->Geometry.BlockSize - + AlignOff; + EraseLen = (BlockRemLen < (u32)LengthVar) ? + BlockRemLen :(u32)LengthVar; + } else { + EraseLen = (InstancePtr->Geometry.BlockSize < + (u32)LengthVar) ? + InstancePtr->Geometry.BlockSize: + (u32)LengthVar; + } + NumBlocks++; + OffsetVar += EraseLen; + LengthVar -= EraseLen; + } + + for (Block = StartBlock; Block < (StartBlock + NumBlocks); Block++) { + Target = Block/InstancePtr->Geometry.NumTargetBlocks; +#ifdef __rtems__ + u32 ModBlock = Block % InstancePtr->Geometry.NumTargetBlocks; +#else + Block %= InstancePtr->Geometry.NumTargetBlocks; +#endif + /* Don't erase bad block */ + if (XNandPsu_IsBlockBad(InstancePtr, Block) == + XST_SUCCESS) + continue; + /* Block Erase */ +#ifdef __rtems__ + Status = XNandPsu_EraseBlock(InstancePtr, Target, ModBlock); +#else + Status = XNandPsu_EraseBlock(InstancePtr, Target, Block); +#endif + if (Status != XST_SUCCESS) + goto Out; + + Status = XNandPsu_Device_Ready(InstancePtr, Target); + if (Status != XST_SUCCESS) + goto Out; + + } +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Program Page command to flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Page is the page address value to program. +* @param Col is the column address value to program. +* @param Buf is the data buffer to program. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_ProgramPage(XNandPsu *InstancePtr, u32 Target, u32 Page, + u32 Col, u8 *Buf) +{ + u32 PktSize; + u32 PktCount; + s32 Status = XST_FAILURE; + u32 IsrValue; + u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles + + InstancePtr->Geometry.ColAddrCycles; + + if (InstancePtr->EccCfg.CodeWordSize > 9U) { + PktSize = 1024U; + } else { + PktSize = 512U; + } + PktCount = InstancePtr->Geometry.BytesPerPage/PktSize; + + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1, ONFI_CMD_PG_PROG2, + 1U, 1U, (u8)AddrCycles); + + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + IsrValue = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK | + XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK; + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheFlushRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + } + XNandPsu_Update_DmaAddr(InstancePtr, Buf); + } else { + IsrValue = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, IsrValue); + /* Program Page Size */ + XNandPsu_SetPageSize(InstancePtr); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set ECC */ + if (InstancePtr->EccMode == XNANDPSU_HWECC) { + XNandPsu_SetEccSpareCmd(InstancePtr, ONFI_CMD_CHNG_WR_COL, + InstancePtr->Geometry.ColAddrCycles); + } + /* Set Page Program in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK); + + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 1); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Program Page command to flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Page is the page address value to program. +* @param Buf is the data buffer to program. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_WriteSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages); + Xil_AssertNonvoid(Buf != NULL); + + u32 PktCount = 1U; + u16 PreEccSpareCol = 0U; + u16 PreEccSpareWrCnt = 0U; + u16 PostEccSpareCol = 0U; + u16 PostEccSpareWrCnt = 0U; + u32 PostWrite = 0U; + OnfiCmdFormat Cmd; + s32 Status = XST_FAILURE; + u32 RegVal; + u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles + + InstancePtr->Geometry.ColAddrCycles; + u32 Col = InstancePtr->Geometry.BytesPerPage; + u32 Target = Page/InstancePtr->Geometry.NumTargetPages; + u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage; + u32 *BufPtr = (u32 *)(void *)Buf; + u32 PageVar = Page; + + PageVar %= InstancePtr->Geometry.NumTargetPages; + + if (InstancePtr->EccMode == XNANDPSU_HWECC) { + /* Calculate ECC free positions before and after ECC code */ + PreEccSpareCol = 0x0U; + PreEccSpareWrCnt = InstancePtr->EccCfg.EccAddr - + (u16)InstancePtr->Geometry.BytesPerPage; + + PostEccSpareCol = PreEccSpareWrCnt + + InstancePtr->EccCfg.EccSize; + PostEccSpareWrCnt = InstancePtr->Geometry.SpareBytesPerPage - + PostEccSpareCol; + + PreEccSpareWrCnt = (PreEccSpareWrCnt/4U) * 4U; + PostEccSpareWrCnt = (PostEccSpareWrCnt/4U) * 4U; + + if (PreEccSpareWrCnt > 0U) { + PktSize = PreEccSpareWrCnt; + PktCount = 1U; + Col = InstancePtr->Geometry.BytesPerPage + + PreEccSpareCol; + BufPtr = (u32 *)(void *)Buf; + if (PostEccSpareWrCnt > 0U) { + PostWrite = 1U; + } + } else if (PostEccSpareWrCnt > 0U) { + PktSize = PostEccSpareWrCnt; + PktCount = 1U; + Col = InstancePtr->Geometry.BytesPerPage + + PostEccSpareCol; + BufPtr = (u32 *)(Buf + Col); + } else { + /* No free spare bytes available for writing */ + Status = XST_FAILURE; + goto Out; + } + } + + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK; + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheFlushRange((INTPTR)(void *)BufPtr, (PktSize * PktCount)); + } + XNandPsu_Update_DmaAddr(InstancePtr, (u8 *)BufPtr); + } else { + RegVal = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, RegVal); + /* Program Command hack for change write column */ + if (PostWrite > 0U) { + Cmd.Command1 = 0x80U; + Cmd.Command2 = 0x00U; + XNandPsu_Prepare_Cmd(InstancePtr, Cmd.Command1, Cmd.Command2, + 0U , 1U, (u8)AddrCycles); + + } else { + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_PG_PROG1, + ONFI_CMD_PG_PROG2, 0U , 1U, (u8)AddrCycles); + } + /* Program Page Size */ + XNandPsu_SetPageSize(InstancePtr); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set Page Program in Program Register */ + if (PostWrite > 0U) { + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,((u32)XNANDPSU_PROG_PG_PROG_MASK | + (u32)XNANDPSU_PROG_CHNG_ROW_ADDR_MASK)); + } else { + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_PG_PROG_MASK); + } + + Status = XNandPsu_Data_ReadWrite(InstancePtr, (u8 *)BufPtr, PktCount, + PktSize, 1, 1); + + if (InstancePtr->EccMode == XNANDPSU_HWECC) { + if (PostWrite > 0U) { + BufPtr = (u32 *)(Buf + PostEccSpareCol); + Status = XNandPsu_ChangeWriteColumn(InstancePtr, + Target, + PostEccSpareCol, PostEccSpareWrCnt, 1U, + (u8 *)(void *)BufPtr); + if (Status != XST_SUCCESS) { + goto Out; + } + } + } +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Read Page command to flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Page is the page address value to read. +* @param Col is the column address value to read. +* @param Buf is the data buffer to fill in. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_ReadPage(XNandPsu *InstancePtr, u32 Target, u32 Page, + u32 Col, u8 *Buf) +{ + u32 PktSize; + u32 PktCount; + s32 Status = XST_FAILURE; + u32 RegVal; + u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles + + InstancePtr->Geometry.ColAddrCycles; + + if (InstancePtr->EccCfg.CodeWordSize > 9U) { + PktSize = 1024U; + } else { + PktSize = 512U; + } + PktCount = InstancePtr->Geometry.BytesPerPage/PktSize; + + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2, + 1U, 1U, (u8)AddrCycles); + + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK | + XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK; + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + } + XNandPsu_Update_DmaAddr(InstancePtr, Buf); + } else { + RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK; + } + /* Enable Single bit error and Multi bit error */ + if (InstancePtr->EccMode == XNANDPSU_HWECC) + RegVal |= XNANDPSU_INTR_STS_EN_MUL_BIT_ERR_STS_EN_MASK | + XNANDPSU_INTR_STS_EN_ERR_INTR_STS_EN_MASK; + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, RegVal); + /* Program Page Size */ + XNandPsu_SetPageSize(InstancePtr); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, Page, (u16)Col); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set ECC */ + if (InstancePtr->EccMode == XNANDPSU_HWECC) { + XNandPsu_SetEccSpareCmd(InstancePtr, + (ONFI_CMD_CHNG_RD_COL1 | + (ONFI_CMD_CHNG_RD_COL2 << (u8)8U)), + InstancePtr->Geometry.ColAddrCycles); + } + + /* Set Read command in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1); + +#ifdef __rtems__ + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + } + } +#endif + + /* Check ECC Errors */ + if (InstancePtr->EccMode == XNANDPSU_HWECC) { + /* Hamming Multi Bit Errors */ + if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET) & + (u32)XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK) != 0U) { + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET, + XNANDPSU_INTR_STS_MUL_BIT_ERR_STS_EN_MASK); + +#ifdef XNANDPSU_DEBUG + xil_printf("%s: ECC Hamming multi bit error\r\n", + __func__); +#endif + InstancePtr->Ecc_Stat_PerPage_flips = + ((XNandPsu_ReadReg( + InstancePtr->Config.BaseAddress, + XNANDPSU_ECC_ERR_CNT_OFFSET) & + 0x1FF00U) >> 8U); + InstancePtr->Ecc_Stats_total_flips += + InstancePtr->Ecc_Stat_PerPage_flips; + Status = XST_FAILURE; + } + /* Hamming Single Bit or BCH Errors */ + if (((u32)XNandPsu_ReadReg(InstancePtr->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET) & + (u32)XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK) != 0U) { + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET, + XNANDPSU_INTR_STS_ERR_INTR_STS_EN_MASK); + + if (InstancePtr->EccCfg.IsBCH == 1U) { + InstancePtr->Ecc_Stat_PerPage_flips = + ((XNandPsu_ReadReg( + InstancePtr->Config.BaseAddress, + XNANDPSU_ECC_ERR_CNT_OFFSET)& + 0x1FF00U) >> 8U); + InstancePtr->Ecc_Stats_total_flips += + InstancePtr->Ecc_Stat_PerPage_flips; + Status = XST_SUCCESS; + } + } + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function reads spare bytes from flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Page is the page address value to read. +* @param Buf is the data buffer to fill in. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_ReadSpareBytes(XNandPsu *InstancePtr, u32 Page, u8 *Buf) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Page < InstancePtr->Geometry.NumPages); + Xil_AssertNonvoid(Buf != NULL); + + u32 PktCount = 1U; + s32 Status = XST_FAILURE; + u32 RegVal; + u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles + + InstancePtr->Geometry.ColAddrCycles; + u32 Col = InstancePtr->Geometry.BytesPerPage; + u32 Target = Page/InstancePtr->Geometry.NumTargetPages; + u32 PktSize = InstancePtr->Geometry.SpareBytesPerPage; + u32 PageVar = Page; + + PageVar %= InstancePtr->Geometry.NumTargetPages; + + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK; + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + } + XNandPsu_Update_DmaAddr(InstancePtr, Buf); + } else { + RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK; + } + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, RegVal); + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_RD1, ONFI_CMD_RD2, 0U, + 1U, (u8)AddrCycles); + /* Program Page Size */ + XNandPsu_SetPageSize(InstancePtr); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, PageVar, (u16)Col); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set Read command in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1); + +#ifdef __rtems__ + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + } + } +#endif + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI block erase command to the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Block is the block to erase. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_EraseBlock(XNandPsu *InstancePtr, u32 Target, u32 Block) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS); +#ifdef __rtems__ + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumTargetBlocks); +#else + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); +#endif + + s32 Status = XST_FAILURE; + u32 Page; + u32 ErasePage; + u32 EraseCol; + u32 AddrCycles = InstancePtr->Geometry.RowAddrCycles; + + Page = Block * InstancePtr->Geometry.PagesPerBlock; + ErasePage = (Page >> 16U) & 0xFFFFU; + EraseCol = Page & 0xFFFFU; + + /* + * Enable Transfer Complete Interrupt in Interrupt Status Enable + * Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK); + + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_BLK_ERASE1, + ONFI_CMD_BLK_ERASE2, 0U , 0U, (u8)AddrCycles); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, ErasePage, (u16)EraseCol); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set Block Erase in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_BLK_ERASE_MASK); + /* Poll for Transfer Complete event */ + Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr); + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Get Feature command to flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Feature is the feature selector. +* @param Buf is the buffer to fill feature value. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_GetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature, + u8 *Buf) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertNonvoid(Buf != NULL); + Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS); + + s32 Status; + u32 PktSize = 4; + u32 PktCount = 1; + + if (InstancePtr->DataInterface == XNANDPSU_NVDDR) { + PktSize = 8U; + } + + /* + * Enable Buffer Read Ready Interrupt in Interrupt Status + * Enable Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK); + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_GET_FEATURES, + ONFI_CMD_INVALID, 0U, 0U, 1U); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Set Read Parameter Page in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_GET_FEATURES_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 0); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sends ONFI Set Feature command to flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Feature is the feature selector. +* @param Buf is the feature value to send. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_SetFeature(XNandPsu *InstancePtr, u32 Target, u8 Feature, + u8 *Buf) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertNonvoid(Buf != NULL); + Xil_AssertNonvoid(Target < XNANDPSU_MAX_TARGETS); + + s32 Status; + u32 PktSize = 4U; + u32 PktCount = 1U; + + if (InstancePtr->DataInterface == XNANDPSU_NVDDR) { + PktSize = 8U; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, 0U); + + /* + * Enable Buffer Write Ready Interrupt in Interrupt Status + * Enable Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK); + + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_SET_FEATURES, + ONFI_CMD_INVALID, 0U , 0U, 1U); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, 0x0U, Feature); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Set Read Parameter Page in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_SET_FEATURES_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 0); + return Status; +} + +/*****************************************************************************/ +/** +* +* This function changes clock frequency of flash controller. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param ClockFreq is the clock frequency to change. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_ChangeClockFreq(XNandPsu *InstancePtr, u32 ClockFreq) +{ + (void) InstancePtr; + (void) ClockFreq; + + /* Not implemented */ +} +/*****************************************************************************/ +/** +* +* This function changes the data interface and timing mode. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param NewIntf is the new data interface. +* @param NewMode is the new timing mode. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +s32 XNandPsu_ChangeTimingMode(XNandPsu *InstancePtr, + XNandPsu_DataInterface NewIntf, + XNandPsu_TimingMode NewMode) +{ + /* Assert the input arguments. */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + s32 Status = XST_SUCCESS; + u32 Target; + u32 RegVal; + u8 Buf[4] = {0U}; + u32 *Feature = (u32 *)(void *)&Buf[0]; + u32 SetFeature = 0U; + u32 NewModeVar = (u32)NewMode; + + /* Check for valid input arguments */ + if(((NewIntf != XNANDPSU_SDR) && (NewIntf != XNANDPSU_NVDDR)) || + (NewModeVar > 5U)){ + Status = XST_FAILURE; + goto Out; + } + + if(NewIntf == XNANDPSU_NVDDR){ + NewModeVar = NewModeVar | (u32)0x10; + } + /* Get current data interface type and timing mode */ + XNandPsu_DataInterface CurIntf = InstancePtr->DataInterface; + XNandPsu_TimingMode CurMode = InstancePtr->TimingMode; + + /* Check if the flash is in same mode */ + if ((CurIntf == NewIntf) && (CurMode == NewModeVar)) { + Status = XST_SUCCESS; + goto Out; + } + + if ((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_SDR)) { + + NewModeVar = XNANDPSU_SDR0; + + /* Change the clock frequency */ + XNandPsu_ChangeClockFreq(InstancePtr, XNANDPSU_SDR_CLK); + + /* Update Data Interface Register */ + RegVal = ((NewModeVar % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) | + ((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT); + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_DATA_INTF_OFFSET, RegVal); + + for (Target = 0U; Target < InstancePtr->Geometry.NumTargets; + Target++) { + Status = XNandPsu_OnfiReset(InstancePtr, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + /* Set Feature */ + for (Target = 0U; Target < InstancePtr->Geometry.NumTargets; + Target++) { + Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U, + (u8 *)(void *)&NewModeVar); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + InstancePtr->DataInterface = NewIntf; + InstancePtr->TimingMode = NewModeVar; + + for (Target = 0U; Target < InstancePtr->Geometry.NumTargets; + Target++) { + Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Check if set_feature was successful */ + if (*Feature != NewModeVar) { + Status = XST_FAILURE; + goto Out; + } + } + + goto Out; + } + + SetFeature = NewModeVar; + if((CurIntf == XNANDPSU_NVDDR) && (NewIntf == XNANDPSU_NVDDR)){ + SetFeature |= SetFeature << 8U; + } + /* Set Feature */ + for (Target = 0U; Target < InstancePtr->Geometry.NumTargets; + Target++) { + Status = XNandPsu_SetFeature(InstancePtr, Target, 0x01U, + (u8 *)(void *)&SetFeature); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + InstancePtr->DataInterface = NewIntf; + InstancePtr->TimingMode = NewModeVar; + /* Update Data Interface Register */ + RegVal = ((NewMode % 6U) << ((NewIntf == XNANDPSU_NVDDR) ? 3U : 0U)) | + ((u32)NewIntf << XNANDPSU_DATA_INTF_DATA_INTF_SHIFT); + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_DATA_INTF_OFFSET, RegVal); + + /* Get Feature */ + for (Target = 0U; Target < InstancePtr->Geometry.NumTargets; + Target++) { + Status = XNandPsu_GetFeature(InstancePtr, Target, 0x01U, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + /* Check if set_feature was successful */ + if (*Feature != NewModeVar) { + Status = XST_FAILURE; + goto Out; + } + } + +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function issues change read column and reads the data into buffer +* specified by user. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Col is the coulmn address. +* @param PktSize is the number of bytes to read. +* @param PktCount is the number of transactions to read. +* @param Buf is the data buffer to fill in. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_ChangeReadColumn(XNandPsu *InstancePtr, u32 Target, + u32 Col, u32 PktSize, u32 PktCount, + u8 *Buf) +{ + s32 Status = XST_FAILURE; + u32 RegVal; + u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles; + + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK | + XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK; + Xil_DCacheInvalidateRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + XNandPsu_Update_DmaAddr(InstancePtr, Buf); + } else { + RegVal = XNANDPSU_INTR_STS_EN_BUFF_RD_RDY_STS_EN_MASK; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, RegVal); + /* Program Command */ + XNandPsu_Prepare_Cmd(InstancePtr, ONFI_CMD_CHNG_RD_COL1, + ONFI_CMD_CHNG_RD_COL2, 0U , 1U, (u8)AddrCycles); + /* Program Page Size */ + XNandPsu_SetPageSize(InstancePtr); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set Read command in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_RD_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 0, 1); + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function issues change read column and reads the data into buffer +* specified by user. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chip select value. +* @param Col is the coulmn address. +* @param PktSize is the number of bytes to read. +* @param PktCount is the number of transactions to read. +* @param Buf is the data buffer to fill in. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_ChangeWriteColumn(XNandPsu *InstancePtr, u32 Target, + u32 Col, u32 PktSize, u32 PktCount, + u8 *Buf) +{ + s32 Status = XST_FAILURE; + OnfiCmdFormat OnfiCommand; + u32 RegVal; + u32 AddrCycles = InstancePtr->Geometry.ColAddrCycles; + + if (PktCount == 0U) { + return XST_SUCCESS; + } + + if (InstancePtr->DmaMode == XNANDPSU_MDMA) { + RegVal = XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK | + XNANDPSU_INTR_STS_EN_DMA_INT_STS_EN_MASK; +#ifdef __rtems__ + if (InstancePtr->Config.IsCacheCoherent == 0) { + Xil_DCacheFlushRange((INTPTR)(void *)Buf, (PktSize * PktCount)); + } +#endif + XNandPsu_Update_DmaAddr(InstancePtr, Buf); + } else { + RegVal = XNANDPSU_INTR_STS_EN_BUFF_WR_RDY_STS_EN_MASK; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, RegVal); + /* Change write column hack */ + OnfiCommand.Command1 = 0x85U; + OnfiCommand.Command2 = 0x10U; + XNandPsu_Prepare_Cmd(InstancePtr, OnfiCommand.Command1, + OnfiCommand.Command2, 0U , 0U, (u8)AddrCycles); + + /* Program Page Size */ + XNandPsu_SetPageSize(InstancePtr); + /* Program Column, Page, Block address */ + XNandPsu_SetPageColAddr(InstancePtr, 0U, (u16)Col); + /* Program Packet Size and Packet Count */ + XNandPsu_SetPktSzCnt(InstancePtr, PktSize, PktCount); + /* Program Memory Address Register2 for chip select */ + XNandPsu_SelectChip(InstancePtr, Target); + /* Set Page Program in Program Register */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_PROG_OFFSET,XNANDPSU_PROG_CHNG_ROW_ADDR_END_MASK); + + Status = XNandPsu_Data_ReadWrite(InstancePtr, Buf, PktCount, PktSize, 1, 0); + return Status; +} + +/*****************************************************************************/ +/** +* +* This function initializes extended parameter page ECC information. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param ExtPrm is the Extended parameter page buffer. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_InitExtEcc(XNandPsu *InstancePtr, OnfiExtPrmPage *ExtPrm) +{ + s32 Status = XST_FAILURE; + u32 Offset = 0U; + u32 Found = 0U; + OnfiExtEccBlock *EccBlock; + + if (ExtPrm->Section0Type != 0x2U) { + Offset += (u32)ExtPrm->Section0Len; + if (ExtPrm->Section1Type != 0x2U) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Extended ECC section not found\r\n",__func__); +#endif + Status = XST_FAILURE; + } else { + Found = 1U; + } + } else { + Found = 1U; + } + + if (Found != 0U) { + EccBlock = (OnfiExtEccBlock *)&ExtPrm->SectionData[Offset]; + Xil_AssertNonvoid(EccBlock != NULL); + if (EccBlock->CodeWordSize == 0U) { + Status = XST_FAILURE; + } else { + InstancePtr->Geometry.NumBitsECC = + EccBlock->NumEccBits; + InstancePtr->Geometry.EccCodeWordSize = + (u32)EccBlock->CodeWordSize; + Status = XST_SUCCESS; + } + } + return Status; +} + +/*****************************************************************************/ +/** +* +* This function prepares command to be written into command register. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Cmd1 is the first Onfi Command. +* @param Cmd2 is the second Onfi Command. +* @param EccState is the flag to set Ecc State. +* @param DmaMode is the flag to set DMA mode. +* @param AddrCycles is the number of Address Cycles. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +void XNandPsu_Prepare_Cmd(XNandPsu *InstancePtr, u8 Cmd1, u8 Cmd2, u8 EccState, + u8 DmaMode, u8 AddrCycles) +{ + Xil_AssertVoid(InstancePtr != NULL); + + u32 RegValue = 0U; + + RegValue = (u32)Cmd1 | (((u32)Cmd2 << (u32)XNANDPSU_CMD_CMD2_SHIFT) & + (u32)XNANDPSU_CMD_CMD2_MASK); + + if ((EccState != 0U) && (InstancePtr->EccMode == XNANDPSU_HWECC)) { + RegValue |= 1U << XNANDPSU_CMD_ECC_ON_SHIFT; + } + + if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA)) { + RegValue |= XNANDPSU_MDMA << XNANDPSU_CMD_DMA_EN_SHIFT; + } + + if (AddrCycles != 0U) { + RegValue |= (u32)AddrCycles << + (u32)XNANDPSU_CMD_ADDR_CYCLES_SHIFT; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_CMD_OFFSET, RegValue); +} + +/*****************************************************************************/ +/** +* +* This function Read/Writes data from the nand controller. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Buf is the data buffer. +* @param PktCount is the number packet chunks. +* @param PktSize is the size of the packet. +* @param Operation is 1 for write and 0 for read. +* @param DmaMode is 1 for Dma and 0 for PIO. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_Data_ReadWrite(XNandPsu *InstancePtr, u8* Buf, u32 PktCount, + u32 PktSize, u32 Operation, u8 DmaMode) +{ + u32 BufRwCnt = 0U; + s32 Status = XST_FAILURE; + u32 Event = XNANDPSU_INTR_STS_BUFF_RD_RDY_STS_EN_MASK; + + if ((DmaMode != 0U) && (InstancePtr->DmaMode == XNANDPSU_MDMA)) + goto DmaDone; + + if (Operation) + Event = XNANDPSU_INTR_STS_BUFF_WR_RDY_STS_EN_MASK; + + while (BufRwCnt < PktCount) { + /* Poll for Buffer Write Ready event */ + Status = XNandPsu_PollRegTimeout(InstancePtr, + XNANDPSU_INTR_STS_OFFSET, Event, + XNANDPSU_INTR_POLL_TIMEOUT); + if (Status != XST_SUCCESS) { + xil_printf("%s: Poll for buf write ready timeout\r\n", + __func__); + goto Out; + } + + /* Increment Buffer Write Interrupt Count */ + BufRwCnt++; + + if (BufRwCnt == PktCount) + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, + XNANDPSU_INTR_STS_EN_TRANS_COMP_STS_EN_MASK); + + else + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, 0U); + /* + * Clear Buffer Write Ready Interrupt in Interrupt Status + * Register + */ + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET, Event); + /* Write Packet Data to Data Port Register */ + if (Operation) + XNandPsu_Fifo_Write(InstancePtr, Buf, PktSize); + else + XNandPsu_Fifo_Read(InstancePtr, Buf, PktSize); + + Buf += PktSize; + + if (BufRwCnt < PktCount) + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, Event); + else + break; + } + +DmaDone: + Status = XNandPsu_WaitFor_Transfer_Complete(InstancePtr); +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function writes data to the fifo. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Buf is the buffer pointer. +* @param Size of the Buffer. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_Fifo_Write(XNandPsu *InstancePtr, u8* Buffer, u32 Size) +{ + u32 *BufPtr = (u32 *)(void *)Buffer; + u32 Index; + + for (Index = 0U; Index < Size/4U; Index++) + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_BUF_DATA_PORT_OFFSET, + BufPtr[Index]); +} + +/*****************************************************************************/ +/** +* +* This function reads data from the fifo. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Buf is the buffer pointer. +* @param Size of the Buffer. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_Fifo_Read(XNandPsu *InstancePtr, u8* Buf, u32 Size) +{ + u32 *BufPtr = (u32 *)(void *)Buf; + u32 Index; + + for (Index = 0U; Index < Size/4U; Index++) + BufPtr[Index] = XNandPsu_ReadReg(InstancePtr->Config.BaseAddress, + XNANDPSU_BUF_DATA_PORT_OFFSET); +} + +/*****************************************************************************/ +/** +* +* This function configures the given dma address to the controller. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Buf is the buffer pointer. +* +* @return +* None +* +* @note None +* +******************************************************************************/ +static void XNandPsu_Update_DmaAddr(XNandPsu *InstancePtr, u8* Buf) +{ +#if defined(__aarch64__) || defined(__arch64__) + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_DMA_SYS_ADDR1_OFFSET, + (u32) (((INTPTR)Buf >> 32U) & 0xFFFFFFFFU)); +#endif + XNandPsu_WriteReg(InstancePtr->Config.BaseAddress, + XNANDPSU_DMA_SYS_ADDR0_OFFSET, + (u32) ((INTPTR)(void *)Buf & 0xFFFFFFFFU)); + +} + +/*****************************************************************************/ +/** +* +* This function waits for the device ready stataus. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Target is the chipselect value. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None +* +******************************************************************************/ +static s32 XNandPsu_Device_Ready(XNandPsu *InstancePtr, u32 Target) +{ + s32 Status = XST_SUCCESS; + u16 OnfiStatus = 0U; + + do { + Status = XNandPsu_OnfiReadStatus(InstancePtr, Target, + &OnfiStatus); + if (Status != XST_SUCCESS) + goto Out; + if ((OnfiStatus & (1U << 6U)) != 0U) { + if ((OnfiStatus & (1U << 0U)) != 0U) { + Status = XST_FAILURE; + goto Out; + } + } + } while (((OnfiStatus >> 6U) & 0x1U) == 0U); + +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function waits for the transfer complete event. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note Expects that transfer complete event was set before calling +* this function. +* +******************************************************************************/ +static s32 XNandPsu_WaitFor_Transfer_Complete(XNandPsu *InstancePtr) +{ +s32 Status = XST_FAILURE; + + /* Poll for Transfer Complete event */ + Status = XNandPsu_PollRegTimeout( + InstancePtr, + XNANDPSU_INTR_STS_OFFSET, + XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK, + XNANDPSU_INTR_POLL_TIMEOUT); + if (Status != XST_SUCCESS) { + xil_printf("%s: Poll for xfer complete timeout\r\n", __func__); + goto Out; + } + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_EN_OFFSET, 0U); + + XNandPsu_WriteReg((InstancePtr)->Config.BaseAddress, + XNANDPSU_INTR_STS_OFFSET, + XNANDPSU_INTR_STS_TRANS_COMP_STS_EN_MASK); +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif +Out: + return Status; +} +/** @} */ diff --git a/bsps/shared/dev/nand/xnandpsu_bbm.c b/bsps/shared/dev/nand/xnandpsu_bbm.c new file mode 100644 index 0000000000..40cf798965 --- /dev/null +++ b/bsps/shared/dev/nand/xnandpsu_bbm.c @@ -0,0 +1,1001 @@ +/****************************************************************************** +* Copyright (C) 2015 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xnandpsu_bbm.c +* @addtogroup Overview +* @{ +* +* This file implements the Bad Block Management (BBM) functionality. +* See xnandpsu_bbm.h for more details. +* +* @note None +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- ---------- ----------------------------------------------- +* 1.0 nm 05/06/2014 First release +* 2.0 sb 01/12/2015 Added support for writing BBT signature and version +* in page section by enabling XNANDPSU_BBT_NO_OOB. +* Modified Bbt Signature and Version Offset value for +* Oob and No-Oob region. +* 1.1 nsk 11/07/16 Change memcpy to Xil_MemCpy to handle word aligned +* data access. +* 1.4 nsk 04/10/18 Added ICCARM compiler support. +* 1.10 akm 01/05/22 Remove assert checks form static and internal APIs. +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include <string.h> /**< For Xil_MemCpy and memset */ +#include "xil_types.h" +#include "xnandpsu.h" +#include "xnandpsu_bbm.h" +#include "xil_mem.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target); + +static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target); + +static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target); + +static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target); + +static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + XNandPsu_BbtDesc *MirrorDesc, u32 Target); + +static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target); + +#ifndef __rtems__ +static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target); +#endif + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* This function initializes the Bad Block Table(BBT) descriptors with a +* predefined pattern for searching Bad Block Table(BBT) in flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - NONE +* +******************************************************************************/ +void XNandPsu_InitBbtDesc(XNandPsu *InstancePtr) +{ + u32 Index; + + /* Initialize primary Bad Block Table(BBT) */ + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtDesc.PageOffset[Index] = + XNANDPSU_BBT_DESC_PAGE_OFFSET; + } + if (InstancePtr->EccMode == XNANDPSU_ONDIE) { + InstancePtr->BbtDesc.SigOffset = XNANDPSU_ONDIE_SIG_OFFSET; + InstancePtr->BbtDesc.VerOffset = XNANDPSU_ONDIE_VER_OFFSET; + } else { + InstancePtr->BbtDesc.SigOffset = XNANDPSU_BBT_DESC_SIG_OFFSET; + InstancePtr->BbtDesc.VerOffset = XNANDPSU_BBT_DESC_VER_OFFSET; + } + InstancePtr->BbtDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN; + InstancePtr->BbtDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS; + (void)strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0"); + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtDesc.Version[Index] = 0U; + } + InstancePtr->BbtDesc.Valid = 0U; + + /* Assuming that the flash device will have at least 4 blocks. */ + if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr-> + BbtDesc.MaxBlocks){ + InstancePtr->BbtDesc.MaxBlocks = 4U; + } + + /* Initialize mirror Bad Block Table(BBT) */ + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtMirrorDesc.PageOffset[Index] = + XNANDPSU_BBT_DESC_PAGE_OFFSET; + } + if (InstancePtr->EccMode == XNANDPSU_ONDIE) { + InstancePtr->BbtMirrorDesc.SigOffset = + XNANDPSU_ONDIE_SIG_OFFSET; + InstancePtr->BbtMirrorDesc.VerOffset = + XNANDPSU_ONDIE_VER_OFFSET; + } else { + InstancePtr->BbtMirrorDesc.SigOffset = + XNANDPSU_BBT_DESC_SIG_OFFSET; + InstancePtr->BbtMirrorDesc.VerOffset = + XNANDPSU_BBT_DESC_VER_OFFSET; + } + InstancePtr->BbtMirrorDesc.SigLength = XNANDPSU_BBT_DESC_SIG_LEN; + InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPSU_BBT_DESC_MAX_BLOCKS; + (void)strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB"); + for (Index = 0U; Index < XNANDPSU_MAX_TARGETS; Index++) { + InstancePtr->BbtMirrorDesc.Version[Index] = 0U; + } + InstancePtr->BbtMirrorDesc.Valid = 0U; + + /* Assuming that the flash device will have at least 4 blocks. */ + if (InstancePtr->Geometry.NumTargetBlocks <= InstancePtr-> + BbtMirrorDesc.MaxBlocks){ + InstancePtr->BbtMirrorDesc.MaxBlocks = 4U; + } + + /* Initialize Bad block search pattern structure */ + if (InstancePtr->Geometry.BytesPerPage > 512U) { + /* For flash page size > 512 bytes */ + InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE; + InstancePtr->BbPattern.Offset = + XNANDPSU_BB_PTRN_OFF_LARGE_PAGE; + InstancePtr->BbPattern.Length = + XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; + } else { + InstancePtr->BbPattern.Options = XNANDPSU_BBT_SCAN_2ND_PAGE; + InstancePtr->BbPattern.Offset = + XNANDPSU_BB_PTRN_OFF_SML_PAGE; + InstancePtr->BbPattern.Length = + XNANDPSU_BB_PTRN_LEN_SML_PAGE; + } + for(Index = 0U; Index < XNANDPSU_BB_PTRN_LEN_LARGE_PAGE; Index++) { + InstancePtr->BbPattern.Pattern[Index] = XNANDPSU_BB_PATTERN; + } +} + +/*****************************************************************************/ +/** +* This function scans the NAND flash for factory marked bad blocks and creates +* a RAM based Bad Block Table(BBT). +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - NONE +* +******************************************************************************/ +static void XNandPsu_CreateBbt(XNandPsu *InstancePtr, u32 Target) +{ + u32 BlockIndex; + u32 PageIndex; + u32 Length; + u32 BlockOffset; + u8 BlockShift; + u32 NumPages; + u32 Page; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; +#endif + u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks; + u32 NumBlocks = InstancePtr->Geometry.NumTargetBlocks; + s32 Status; + + /* Number of pages to search for bad block pattern */ + if ((InstancePtr->BbPattern.Options & XNANDPSU_BBT_SCAN_2ND_PAGE) != 0U) + { + NumPages = 2U; + } else { + NumPages = 1U; + } + /* Scan all the blocks for factory marked bad blocks */ + for(BlockIndex = StartBlock; BlockIndex < (StartBlock + NumBlocks); + BlockIndex++) { + /* Block offset in Bad Block Table(BBT) entry */ + BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT; + /* Block shift value in the byte */ + BlockShift = XNandPsu_BbtBlockShift(BlockIndex); + Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock; + /* Search for the bad block pattern */ + for(PageIndex = 0U; PageIndex < NumPages; PageIndex++) { + Status = XNandPsu_ReadSpareBytes(InstancePtr, + (Page + PageIndex), &Buf[0]); + + if (Status != XST_SUCCESS) { + /* Marking as bad block */ + InstancePtr->Bbt[BlockOffset] |= + (u8)(XNANDPSU_BLOCK_FACTORY_BAD << + BlockShift); + break; + } + /* + * Read the spare bytes to check for bad block + * pattern + */ + for(Length = 0U; Length < + InstancePtr->BbPattern.Length; Length++) { + if (Buf[InstancePtr->BbPattern.Offset + Length] + != + InstancePtr->BbPattern.Pattern[Length]) + { + /* Bad block found */ + InstancePtr->Bbt[BlockOffset] |= + (u8) + (XNANDPSU_BLOCK_FACTORY_BAD << + BlockShift); + break; + } + } + } + } +} + +/*****************************************************************************/ +/** +* This function reads the Bad Block Table(BBT) if present in flash. If not it +* scans the flash for detecting factory marked bad blocks and creates a bad +* block table and write the Bad Block Table(BBT) into the flash. +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +s32 XNandPsu_ScanBbt(XNandPsu *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + + s32 Status; + u32 Index; + u32 BbtLen; + + /* Zero the RAM based Bad Block Table(BBT) entries */ + BbtLen = InstancePtr->Geometry.NumBlocks >> + XNANDPSU_BBT_BLOCK_SHIFT; + (void)memset(&InstancePtr->Bbt[0], 0, BbtLen); + + for (Index = 0U; Index < InstancePtr->Geometry.NumTargets; Index++) { + + if (XNandPsu_ReadBbt(InstancePtr, Index) != XST_SUCCESS) { + /* Create memory based Bad Block Table(BBT) */ + XNandPsu_CreateBbt(InstancePtr, Index); + /* Write the Bad Block Table(BBT) to the flash */ + Status = XNandPsu_WriteBbt(InstancePtr, + &InstancePtr->BbtDesc, + &InstancePtr->BbtMirrorDesc, Index); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Write the Mirror Bad Block Table(BBT) to the flash */ + Status = XNandPsu_WriteBbt(InstancePtr, + &InstancePtr->BbtMirrorDesc, + &InstancePtr->BbtDesc, Index); + if (Status != XST_SUCCESS) { + goto Out; + } + /* + * Mark the blocks containing Bad Block Table + * (BBT) as Reserved + */ + Status = XNandPsu_MarkBbt(InstancePtr, + &InstancePtr->BbtDesc, + Index); + if (Status != XST_SUCCESS) { + goto Out; + } + Status = XNandPsu_MarkBbt(InstancePtr, + &InstancePtr->BbtMirrorDesc, + Index); + if (Status != XST_SUCCESS) { + goto Out; + } + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function converts the Bad Block Table(BBT) read from the flash to the +* RAM based Bad Block Table(BBT). +* +* @param InstancePtr is a pointer to the XNandPsu instance. +* @param Buf is the buffer which contains BBT read from flash. +* +* @return +* - NONE. +* +******************************************************************************/ +static void XNandPsu_ConvertBbt(XNandPsu *InstancePtr, u8 *Buf, u32 Target) +{ +#ifndef __rtems__ + u32 BlockOffset; + u8 BlockShift; + u32 Data; + u8 BlockType; + u32 BlockIndex; +#endif + u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >> + XNANDPSU_BBT_BLOCK_SHIFT; +#ifdef __rtems__ + u32 BbtOffset = Target * InstancePtr->Geometry.NumTargetBlocks / XNANDPSU_BBT_ENTRY_NUM_BLOCKS; + + for(u32 BbtIndex = 0; BbtIndex < BbtLen; BbtIndex++) { + /* Invert the byte to convert from in-flash BBT to in-memory BBT */ + InstancePtr->Bbt[BbtIndex + BbtOffset] = ~Buf[BbtIndex]; + } +#else + u32 StartBlock = Target * InstancePtr->Geometry.NumTargetBlocks; + + for(BlockOffset = StartBlock; BlockOffset < (StartBlock + BbtLen); + BlockOffset++) { + Data = *(Buf + BlockOffset); + /* Clear the RAM based Bad Block Table(BBT) contents */ + InstancePtr->Bbt[BlockOffset] = 0x0U; + /* Loop through the every 4 blocks in the bitmap */ + for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS; + BlockIndex++) { + BlockShift = XNandPsu_BbtBlockShift(BlockIndex); + BlockType = (u8) ((Data >> BlockShift) & + XNANDPSU_BLOCK_TYPE_MASK); + switch(BlockType) { + case XNANDPSU_FLASH_BLOCK_FAC_BAD: + /* Factory bad block */ + InstancePtr->Bbt[BlockOffset] |= + (u8) + (XNANDPSU_BLOCK_FACTORY_BAD << + BlockShift); + break; + case XNANDPSU_FLASH_BLOCK_RESERVED: + /* Reserved block */ + InstancePtr->Bbt[BlockOffset] |= + (u8) + (XNANDPSU_BLOCK_RESERVED << + BlockShift); + break; + case XNANDPSU_FLASH_BLOCK_BAD: + /* Bad block due to wear */ + InstancePtr->Bbt[BlockOffset] |= + (u8)(XNANDPSU_BLOCK_BAD << + BlockShift); + break; + default: + /* Good block */ + /* The BBT entry already defaults to + * zero */ + break; + } + } + } +#endif +} + +/*****************************************************************************/ +/** +* This function searches the Bad Bloock Table(BBT) in flash and loads into the +* memory based Bad Block Table(BBT). +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_ReadBbt(XNandPsu *InstancePtr, u32 Target) +{ + u64 Offset; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U}; +#endif + s32 Status1; + s32 Status2; + s32 Status; + u32 BufLen; + + XNandPsu_BbtDesc *Desc = &InstancePtr->BbtDesc; + XNandPsu_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc; +#ifdef __rtems__ + BufLen = InstancePtr->Geometry.NumTargetBlocks >> +#else + BufLen = InstancePtr->Geometry.NumBlocks >> +#endif + XNANDPSU_BBT_BLOCK_SHIFT; + /* Search the Bad Block Table(BBT) in flash */ + Status1 = XNandPsu_SearchBbt(InstancePtr, Desc, Target); + Status2 = XNandPsu_SearchBbt(InstancePtr, MirrorDesc, Target); + if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Bad block table not found\r\n",__func__); +#endif + Status = XST_FAILURE; + goto Out; + } +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Bad block table found\r\n",__func__); +#endif + /* Bad Block Table found */ + if ((Desc->Valid != 0U) && (MirrorDesc->Valid != 0U)) { + /* Valid BBT & Mirror BBT found */ + if (Desc->Version[Target] > MirrorDesc->Version[Target]) { + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + MirrorDesc->Version[Target] = Desc->Version[Target]; + + /* Write the BBT to Mirror BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, + Desc, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } else if (Desc->Version[Target] < + MirrorDesc->Version[Target]) { + Offset = (u64)MirrorDesc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + Desc->Version[Target] = MirrorDesc->Version[Target]; + + /* Write the Mirror BBT to BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, Desc, + MirrorDesc, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } else { + /* Both are up-to-date */ + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, + &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + } + } else if (Desc->Valid != 0U) { + /* Valid Primary BBT found */ + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + MirrorDesc->Version[Target] = Desc->Version[Target]; + + /* Write the BBT to Mirror BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, MirrorDesc, Desc, + Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } else { + /* Valid Mirror BBT found */ + Offset = (u64)MirrorDesc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Read(InstancePtr, Offset, BufLen, &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Convert flash BBT to memory based BBT */ + XNandPsu_ConvertBbt(InstancePtr, &Buf[0], Target); + Desc->Version[Target] = MirrorDesc->Version[Target]; + + /* Write the Mirror BBT to BBT location in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, Desc, MirrorDesc, + Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function searches the BBT in flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Desc is the BBT descriptor pattern to search. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_SearchBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target) +{ + u32 StartBlock; + u32 SigOffset; + u32 VerOffset; + u32 MaxBlocks; + u32 PageOff; + u32 SigLength; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] = {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; +#endif + u32 Block; + u32 Offset; + s32 Status; + + StartBlock = ((Target + (u32)1) * + InstancePtr->Geometry.NumTargetBlocks) - (u32)1; + SigOffset = Desc->SigOffset; + VerOffset = Desc->VerOffset; + MaxBlocks = Desc->MaxBlocks; + SigLength = Desc->SigLength; +#ifdef __rtems__ + Desc->Valid = 0; +#endif + + /* Read the last 4 blocks for Bad Block Table(BBT) signature */ + for(Block = 0U; Block < MaxBlocks; Block++) { + PageOff = (StartBlock - Block) * + InstancePtr->Geometry.PagesPerBlock; + + Status = XNandPsu_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]); + if (Status != XST_SUCCESS) { + continue; + } + /* Check the Bad Block Table(BBT) signature */ + for(Offset = 0U; Offset < SigLength; Offset++) { + if (Buf[Offset + SigOffset] != + (u8)(Desc->Signature[Offset])) + { + break; /* Check the next blocks */ + } + } + if (Offset >= SigLength) { + /* Bad Block Table(BBT) found */ + Desc->PageOffset[Target] = PageOff; + Desc->Version[Target] = Buf[VerOffset]; + Desc->Valid = 1U; + + Status = XST_SUCCESS; + goto Out; + } + } + /* Bad Block Table(BBT) not found */ + Status = XST_FAILURE; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function writes Bad Block Table(BBT) from RAM to flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Desc is the BBT descriptor to be written to flash. +* @param MirrorDesc is the mirror BBT descriptor. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_WriteBbt(XNandPsu *InstancePtr, XNandPsu_BbtDesc *Desc, + XNandPsu_BbtDesc *MirrorDesc, u32 Target) +{ + u64 Offset; + u32 Block = {0U}; + u32 EndBlock = ((Target + (u32)1) * + InstancePtr->Geometry.NumTargetBlocks) - (u32)1; +#ifdef __ICCARM__ +#pragma pack(push, 1) + u8 Buf[XNANDPSU_BBT_BUF_LENGTH]= {0U}; + u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE]= {0U}; +#pragma pack(pop) +#else + u8 Buf[XNANDPSU_BBT_BUF_LENGTH] __attribute__ ((aligned(64))) = {0U}; + u8 SpareBuf[XNANDPSU_MAX_SPARE_SIZE] __attribute__ ((aligned(64))) = {0U}; +#endif + +#ifndef __rtems__ + u8 Mask[4] = {0x00U, 0x01U, 0x02U, 0x03U}; + u8 Data; + u32 BlockOffset; + u8 BlockShift; + s32 Status; + u32 BlockIndex; + u32 Index; + u8 BlockType; + u32 BbtLen = InstancePtr->Geometry.NumBlocks >> +#else + s32 Status; + u32 Index; + u32 BbtLen = InstancePtr->Geometry.NumTargetBlocks >> +#endif + XNANDPSU_BBT_BLOCK_SHIFT; + /* Find a valid block to write the Bad Block Table(BBT) */ + if ((!Desc->Valid) != 0U) { + for(Index = 0U; Index < Desc->MaxBlocks; Index++) { + Block = (EndBlock - Index); +#ifdef __rtems__ + if (XNandPsu_IsBlockBad(InstancePtr, Block) != XST_FAILURE) { + continue; + } +#else + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + BlockType = (InstancePtr->Bbt[BlockOffset] >> + BlockShift) & XNANDPSU_BLOCK_TYPE_MASK; + switch(BlockType) + { + case XNANDPSU_BLOCK_BAD: + case XNANDPSU_BLOCK_FACTORY_BAD: + continue; + default: + /* Good Block */ + break; + } +#endif + Desc->PageOffset[Target] = Block * + InstancePtr->Geometry.PagesPerBlock; + if (Desc->PageOffset[Target] != + MirrorDesc->PageOffset[Target]) { + /* Free block found */ + Desc->Valid = 1U; + break; + } + } + + + /* Block not found for writing Bad Block Table(BBT) */ + if (Index >= Desc->MaxBlocks) { +#ifdef XNANDPSU_DEBUG + xil_printf("%s: Blocks unavailable for writing BBT\r\n", + __func__); +#endif + Status = XST_FAILURE; + goto Out; + } + } else { + Block = Desc->PageOffset[Target] / + InstancePtr->Geometry.PagesPerBlock; + } + /* Convert the memory based BBT to flash based table */ + (void)memset(Buf, 0xff, BbtLen); + +#ifdef __rtems__ + u32 BbtTargetOffset = BbtLen * Target; + /* Loop through the BBT entries */ + for(u32 BbtIndex = 0U; BbtIndex < BbtLen; BbtIndex++) { + /* Invert byte to convert from in-memory BBT to in-flash BBT */ + Buf[BbtIndex] = ~InstancePtr->Bbt[BbtIndex + BbtTargetOffset]; + } +#else + /* Loop through the number of blocks */ + for(BlockOffset = 0U; BlockOffset < BbtLen; BlockOffset++) { + Data = InstancePtr->Bbt[BlockOffset]; + /* Calculate the bit mask for 4 blocks at a time in loop */ + for(BlockIndex = 0U; BlockIndex < XNANDPSU_BBT_ENTRY_NUM_BLOCKS; + BlockIndex++) { + BlockShift = XNandPsu_BbtBlockShift(BlockIndex); + Buf[BlockOffset] &= ~(Mask[Data & + XNANDPSU_BLOCK_TYPE_MASK] << + BlockShift); + Data >>= XNANDPSU_BBT_BLOCK_SHIFT; + } + } +#endif + /* Write the Bad Block Table(BBT) to flash */ +#ifdef __rtems__ + Status = XNandPsu_EraseBlock(InstancePtr, Target, + Block % InstancePtr->Geometry.NumTargetBlocks); +#else + Status = XNandPsu_EraseBlock(InstancePtr, 0U, Block); +#endif + if (Status != XST_SUCCESS) { + goto Out; + } + + /* Write the BBT to page offset */ + Offset = (u64)Desc->PageOffset[Target] * + (u64)InstancePtr->Geometry.BytesPerPage; + Status = XNandPsu_Write(InstancePtr, Offset, BbtLen, &Buf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + /* Write the signature and version in the spare data area */ + (void)memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage); + Status = XNandPsu_ReadSpareBytes(InstancePtr, Desc->PageOffset[Target], + &SpareBuf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + (void)Xil_MemCpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0], + Desc->SigLength); + (void)memcpy(SpareBuf + Desc->VerOffset, &Desc->Version[Target], 1U); + + Status = XNandPsu_WriteSpareBytes(InstancePtr, + Desc->PageOffset[Target], &SpareBuf[0]); + if (Status != XST_SUCCESS) { + goto Out; + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function updates the primary and mirror Bad Block Table(BBT) in the +* flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +#ifdef __rtems__ +s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target) +#else +static s32 XNandPsu_UpdateBbt(XNandPsu *InstancePtr, u32 Target) +#endif +{ + s32 Status; + u8 Version; + + /* Update the version number */ + Version = InstancePtr->BbtDesc.Version[Target]; + InstancePtr->BbtDesc.Version[Target] = (u8)(((u16)Version + + (u16)1) % (u16)256U); + + Version = InstancePtr->BbtMirrorDesc.Version[Target]; + InstancePtr->BbtMirrorDesc.Version[Target] = (u8)(((u16)Version + + (u16)1) % (u16)256); + /* Update the primary Bad Block Table(BBT) in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtDesc, + &InstancePtr->BbtMirrorDesc, + Target); + if (Status != XST_SUCCESS) { + goto Out; + } + + /* Update the mirrored Bad Block Table(BBT) in flash */ + Status = XNandPsu_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc, + &InstancePtr->BbtDesc, + Target); + if (Status != XST_SUCCESS) { + goto Out; + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* This function marks the block containing Bad Block Table as reserved +* and updates the BBT. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Desc is the BBT descriptor pointer. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static s32 XNandPsu_MarkBbt(XNandPsu* InstancePtr, XNandPsu_BbtDesc *Desc, + u32 Target) +{ + u32 BlockIndex; + u32 BlockOffset; + u8 BlockShift; + u8 OldVal; + u8 NewVal; + s32 Status; + u32 UpdateBbt = 0U; + u32 Index; + + /* Mark the last four blocks as Reserved */ + BlockIndex = ((Target + (u32)1) * InstancePtr->Geometry.NumTargetBlocks) - +#ifdef __rtems__ + Desc->MaxBlocks; +#else + Desc->MaxBlocks - (u32)1; +#endif + + for(Index = 0U; Index < Desc->MaxBlocks; Index++) { + + BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(BlockIndex); + OldVal = InstancePtr->Bbt[BlockOffset]; + NewVal = (u8) (OldVal | (XNANDPSU_BLOCK_RESERVED << + BlockShift)); + InstancePtr->Bbt[BlockOffset] = NewVal; + + if (OldVal != NewVal) { + UpdateBbt = 1U; + } + BlockIndex++; + } + + /* Update the BBT to flash */ + if (UpdateBbt != 0U) { + Status = XNandPsu_UpdateBbt(InstancePtr, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +/*****************************************************************************/ +/** +* +* This function checks whether a block is bad or not. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* +* @param Block is the block number. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +s32 XNandPsu_IsBlockBad(XNandPsu *InstancePtr, u32 Block) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); + + u8 Data; + u8 BlockShift; + u8 BlockType; + u32 BlockOffset; + s32 Status; + + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ + BlockType = (Data >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK; + + if ((BlockType != XNANDPSU_BLOCK_GOOD) && + (BlockType != XNANDPSU_BLOCK_RESERVED)) { + Status = XST_SUCCESS; + } + else { + Status = XST_FAILURE; + } + return Status; +} + +/*****************************************************************************/ +/** +* This function marks a block as bad in the RAM based Bad Block Table(BBT). It +* also updates the Bad Block Table(BBT) in the flash. +* +* @param InstancePtr is the pointer to the XNandPsu instance. +* @param Block is the block number. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +s32 XNandPsu_MarkBlockBad(XNandPsu *InstancePtr, u32 Block) +#ifdef __rtems__ +{ + return XNandPsu_MarkBlock(InstancePtr, Block, XNANDPSU_BLOCK_BAD ); +} + +s32 XNandPsu_MarkBlock(XNandPsu *InstancePtr, u32 Block, u8 BlockMark) +#endif +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); + +#ifdef __rtems__ + BlockMark &= XNANDPSU_BLOCK_TYPE_MASK; +#endif + + u8 Data; + u8 BlockShift; + u32 BlockOffset; + u8 OldVal; + u8 NewVal; + s32 Status; + u32 Target; + + Target = Block / InstancePtr->Geometry.NumTargetBlocks; + + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ + + /* Mark the block as bad in the RAM based Bad Block Table */ + OldVal = Data; + Data &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift); +#ifdef __rtems__ + Data |= (BlockMark << BlockShift); +#else + Data |= (XNANDPSU_BLOCK_BAD << BlockShift); +#endif + NewVal = Data; + InstancePtr->Bbt[BlockOffset] = Data; + + /* Update the Bad Block Table(BBT) in flash */ + if (OldVal != NewVal) { + Status = XNandPsu_UpdateBbt(InstancePtr, Target); + if (Status != XST_SUCCESS) { + goto Out; + } + } + + Status = XST_SUCCESS; +Out: + return Status; +} + +#ifdef __rtems__ +bool XNandPsu_StageBlockMark(XNandPsu *InstancePtr, u32 Block, u8 BlockMark) +{ + u8 BlockShift; + u32 BlockOffset; + u8 OldVal; + + BlockMark &= XNANDPSU_BLOCK_TYPE_MASK; + + BlockOffset = Block >> XNANDPSU_BBT_BLOCK_SHIFT; + BlockShift = XNandPsu_BbtBlockShift(Block); + OldVal = InstancePtr->Bbt[BlockOffset] >> BlockShift; + OldVal &= XNANDPSU_BLOCK_TYPE_MASK; + InstancePtr->Bbt[BlockOffset] &= ~(XNANDPSU_BLOCK_TYPE_MASK << BlockShift); + InstancePtr->Bbt[BlockOffset] |= (BlockMark << BlockShift); + return BlockMark != OldVal; +} +#endif + +/** @} */ diff --git a/bsps/shared/dev/nand/xnandpsu_onfi.c b/bsps/shared/dev/nand/xnandpsu_onfi.c new file mode 100644 index 0000000000..0009722bfe --- /dev/null +++ b/bsps/shared/dev/nand/xnandpsu_onfi.c @@ -0,0 +1,91 @@ +/****************************************************************************** +* Copyright (C) 2015 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xnandpsu_onfi.c +* @addtogroup Overview +* @{ +* +* This file contains the implementation of ONFI specific functions. +* +* @note None +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- ---------- ----------------------------------------------- +* 1.0 nm 05/06/2014 First release +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xnandpsu_onfi.h" +#include "xnandpsu.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* +* This function calculates ONFI parameter page CRC. +* +* @param ParamBuf is a pointer to the ONFI parameter page buffer. +* @param StartOff is the starting offset in buffer to calculate CRC. +* @param Length is the number of bytes for which CRC is calculated. +* +* @return +* CRC value. +* @note +* None. +* +******************************************************************************/ +u32 XNandPsu_OnfiParamPageCrc(u8 *ParamBuf, u32 StartOff, u32 Length) +{ + const u32 CrcInit = 0x4F4EU; + const u32 Order = 16U; + const u32 Polynom = 0x8005U; + u32 i, j, c, Bit; + u32 Crc = CrcInit; + u32 DataIn; + u32 DataByteCount = 0U; + u32 CrcMask, CrcHighBit; + + CrcMask = ((u32)(((u32)1 << (Order - (u32)1)) -(u32)1) << (u32)1) | (u32)1; + CrcHighBit = (u32)((u32)1 << (Order - (u32)1)); + /* + * CRC covers the data bytes between byte 0 and byte 253 + * (ONFI 1.0, section 5.4.1.36) + */ + for(i = StartOff; i < Length; i++) { + DataIn = *(ParamBuf + i); + c = (u32)DataIn; + DataByteCount++; + j = 0x80U; + while(j != 0U) { + Bit = Crc & CrcHighBit; + Crc <<= 1U; + if ((c & j) != 0U) { + Bit ^= CrcHighBit; + } + if (Bit != 0U) { + Crc ^= Polynom; + } + j >>= 1U; + } + Crc &= CrcMask; + } + return Crc; +} +/** @} */ diff --git a/bsps/shared/dev/rtc/icm7170.c b/bsps/shared/dev/rtc/icm7170.c index 1cc9e980f7..8c8b44ccff 100644 --- a/bsps/shared/dev/rtc/icm7170.c +++ b/bsps/shared/dev/rtc/icm7170.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file interfaces with the real-time clock found in * a Harris ICM7170 @@ -16,9 +18,26 @@ * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/rtc/icm7170_reg.c b/bsps/shared/dev/rtc/icm7170_reg.c index 747f1f218d..da70722f2e 100644 --- a/bsps/shared/dev/rtc/icm7170_reg.c +++ b/bsps/shared/dev/rtc/icm7170_reg.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the icm7170 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/rtc/icm7170_reg2.c b/bsps/shared/dev/rtc/icm7170_reg2.c index 179d76c6f5..f428e16df4 100644 --- a/bsps/shared/dev/rtc/icm7170_reg2.c +++ b/bsps/shared/dev/rtc/icm7170_reg2.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the icm7170 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _ICM7170_MULTIPLIER 2 diff --git a/bsps/shared/dev/rtc/icm7170_reg4.c b/bsps/shared/dev/rtc/icm7170_reg4.c index dada40961c..2735b272ba 100644 --- a/bsps/shared/dev/rtc/icm7170_reg4.c +++ b/bsps/shared/dev/rtc/icm7170_reg4.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the icm7170 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _ICM7170_MULTIPLIER 4 diff --git a/bsps/shared/dev/rtc/icm7170_reg8.c b/bsps/shared/dev/rtc/icm7170_reg8.c index a1fb1a5ea2..36505dcec1 100644 --- a/bsps/shared/dev/rtc/icm7170_reg8.c +++ b/bsps/shared/dev/rtc/icm7170_reg8.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the icm7170 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _ICM7170_MULTIPLIER 8 diff --git a/bsps/shared/dev/rtc/m48t08.c b/bsps/shared/dev/rtc/m48t08.c index 3b600bd995..1933e17ab0 100644 --- a/bsps/shared/dev/rtc/m48t08.c +++ b/bsps/shared/dev/rtc/m48t08.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file interfaces with the real-time clock found in * a Mostek M48T08 or M48T18 or compatibles. @@ -16,9 +18,26 @@ * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/rtc/m48t08_reg.c b/bsps/shared/dev/rtc/m48t08_reg.c index 2174496fda..ef0d6b3b19 100644 --- a/bsps/shared/dev/rtc/m48t08_reg.c +++ b/bsps/shared/dev/rtc/m48t08_reg.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the m48t08 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/rtc/m48t08_reg2.c b/bsps/shared/dev/rtc/m48t08_reg2.c index 87d2041946..b469f9258f 100644 --- a/bsps/shared/dev/rtc/m48t08_reg2.c +++ b/bsps/shared/dev/rtc/m48t08_reg2.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the m48t08 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _M48T08_MULTIPLIER 2 diff --git a/bsps/shared/dev/rtc/m48t08_reg4.c b/bsps/shared/dev/rtc/m48t08_reg4.c index 2203249503..069664b3ba 100644 --- a/bsps/shared/dev/rtc/m48t08_reg4.c +++ b/bsps/shared/dev/rtc/m48t08_reg4.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the m48t08 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _M48T08_MULTIPLIER 4 diff --git a/bsps/shared/dev/rtc/m48t08_reg8.c b/bsps/shared/dev/rtc/m48t08_reg8.c index 83044d752b..8e1bccbf14 100644 --- a/bsps/shared/dev/rtc/m48t08_reg8.c +++ b/bsps/shared/dev/rtc/m48t08_reg8.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the m48t08 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _M48T08_MULTIPLIER 8 diff --git a/bsps/shared/dev/rtc/mc146818a.c b/bsps/shared/dev/rtc/mc146818a.c index 2720ce5e8a..a048c6c606 100644 --- a/bsps/shared/dev/rtc/mc146818a.c +++ b/bsps/shared/dev/rtc/mc146818a.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file interfaces with the real-time clock found in * a Motorola MC146818A (common on PC hardware) @@ -16,9 +18,26 @@ * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> #include <libchip/rtc.h> diff --git a/bsps/shared/dev/rtc/mc146818a_ioreg.c b/bsps/shared/dev/rtc/mc146818a_ioreg.c index 4c438a516a..e51279ed18 100644 --- a/bsps/shared/dev/rtc/mc146818a_ioreg.c +++ b/bsps/shared/dev/rtc/mc146818a_ioreg.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the MC146818A chip if accesses to the chip are as follows: @@ -11,9 +13,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/rtc/mcp7940m.c b/bsps/shared/dev/rtc/mcp7940m.c new file mode 100644 index 0000000000..1abc5faaad --- /dev/null +++ b/bsps/shared/dev/rtc/mcp7940m.c @@ -0,0 +1,361 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2023 embedded brains GmbH & Co. KG + * + * 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. + */ + +/* + * Note: This driver implements only the basic RTC functionality of the + * MCP7940M. It tries not to touch any register fields except for the basic + * date/time fields in the get/set time functions. That way it should be + * possible to re-use the driver for similar RTCs by just replacing the + * initialization function. Suggested method for that: Add a field to the struct + * mcp7940m_rtc with a function pointer that points to the initialization + * function. + * + * All flags that are considered MCP7940M specific have a MCP7940M in the name. + * + * Only 24 hour format is supported. If this driver is the only ones who write + * the RTC, that shouldn't be a problem. + * + * The weekday register is not used. It has a user-defined representation anyway + * and therefore doesn't really matter. + */ + +#include <dev/i2c/i2c.h> +#include <libchip/mcp7940m-rtc.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/todimpl.h> + +#include <fcntl.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#define REG_RTCSEC 0x00u + +#define RTCSEC_SECBCD_SHIFT 0u +#define RTCSEC_SECBCD_MASK (0x7fu << RTCSEC_SECBCD_SHIFT) +#define RTCSEC_SECBCD(x) (((x) << RTCSEC_SECBCD_SHIFT) & RTCSEC_SECBCD_MASK) +#define RTCSEC_SECBCD_GET(x) (((x) & RTCSEC_SECBCD_MASK) >> RTCSEC_SECBCD_SHIFT) + +#define MCP7940M_RTCSEC_ST (0x01u << 7) + +#define REG_RTCMIN 0x01 + +#define RTCMIN_MINBCD_SHIFT 0u +#define RTCMIN_MINBCD_MASK (0x7fu << RTCMIN_MINBCD_SHIFT) +#define RTCMIN_MINBCD(x) (((x) << RTCMIN_MINBCD_SHIFT) & RTCMIN_MINBCD_MASK) +#define RTCMIN_MINBCD_GET(x) (((x) & RTCMIN_MINBCD_MASK) >> RTCMIN_MINBCD_SHIFT) + +#define REG_RTCHOUR 0x02 + +#define RTCHOUR_HRBCD12_SHIFT 0u +#define RTCHOUR_HRBCD12_MASK (0x1fu << RTCHOUR_HRBCD12_SHIFT) +#define RTCHOUR_HRBCD12(x) (((x) << RTCHOUR_HRBCD12_SHIFT) & RTCHOUR_HRBCD12_MASK) +#define RTCHOUR_HRBCD12_GET(x) (((x) & RTCHOUR_HRBCD12_MASK) >> RTCHOUR_HRBCD12_SHIFT) + +#define RTCHOUR_HRBCD24_SHIFT 0u +#define RTCHOUR_HRBCD24_MASK (0x3fu << RTCHOUR_HRBCD24_SHIFT) +#define RTCHOUR_HRBCD24(x) (((x) << RTCHOUR_HRBCD24_SHIFT) & RTCHOUR_HRBCD24_MASK) +#define RTCHOUR_HRBCD24_GET(x) (((x) & RTCHOUR_HRBCD24_MASK) >> RTCHOUR_HRBCD24_SHIFT) + +#define RTCHOUR_AMPM (0x01u << 5) +#define RTCHOUR_1224 (0x01u << 6) + +#define REG_RTCWKDAY 0x03 + +#define RTCWKDAY_WKDAY_SHIFT 0u +#define RTCWKDAY_WKDAY_MASK (0x7u << RTCWKDAY_WKDAY_SHIFT) +#define RTCWKDAY_WKDAY(x) (((x) << RTCWKDAY_WKDAY_SHIFT) & RTCWKDAY_WKDAY_MASK) +#define RTCWKDAY_WKDAY_GET(x) (((x) & RTCWKDAY_WKDAY_MASK) >> RTCWKDAY_WKDAY_SHIFT) + +#define REG_RTCDATE 0x04 + +#define RTCDATE_DATEBCD_SHIFT 0u +#define RTCDATE_DATEBCD_MASK (0x3fu << RTCDATE_DATEBCD_SHIFT) +#define RTCDATE_DATEBCD(x) (((x) << RTCDATE_DATEBCD_SHIFT) & RTCDATE_DATEBCD_MASK) +#define RTCDATE_DATEBCD_GET(x) (((x) & RTCDATE_DATEBCD_MASK) >> RTCDATE_DATEBCD_SHIFT) + +#define REG_RTCMTH 0x05 + +#define RTCMTH_MTHBCD_SHIFT 0u +#define RTCMTH_MTHBCD_MASK (0x1fu << RTCMTH_MTHBCD_SHIFT) +#define RTCMTH_MTHBCD(x) (((x) << RTCMTH_MTHBCD_SHIFT) & RTCMTH_MTHBCD_MASK) +#define RTCMTH_MTHBCD_GET(x) (((x) & RTCMTH_MTHBCD_MASK) >> RTCMTH_MTHBCD_SHIFT) + +#define MCP7940M_RTCMTH_LPYR (0x01u << 5) + +#define REG_RTCYEAR 0x06 + +#define RTCYEAR_YRBCD_SHIFT 0u +#define RTCYEAR_YRBCD_MASK (0xffu << RTCYEAR_YRBCD_SHIFT) +#define RTCYEAR_YRBCD(x) (((x) << RTCYEAR_YRBCD_SHIFT) & RTCYEAR_YRBCD_MASK) +#define RTCYEAR_YRBCD_GET(x) (((x) & RTCYEAR_YRBCD_MASK) >> RTCYEAR_YRBCD_SHIFT) + +#define REG_MCP7940M_CONTROL 0x07 + +#define MCP7940M_CONTROL_OUT (0x1u << 7) +#define MCP7940M_CONTROL_SQWEN (0x1u << 6) +#define MCP7940M_CONTROL_ALM1EN (0x1u << 5) +#define MCP7940M_CONTROL_ALM0EN (0x1u << 4) +#define MCP7940M_CONTROL_EXTOSC (0x1u << 3) +#define MCP7940M_CONTROL_CRSTRIM (0x1u << 2) +#define MCP7940M_CONTROL_SQWFS1 (0x1u << 1) +#define MCP7940M_CONTROL_SQWFS0 (0x1u << 0) + +static inline uint8_t bcd_to_bin(uint8_t bcd) +{ + uint8_t bin; + bin = bcd & 0x0f; + bin += ((bcd >> 4) & 0x0f) * 10; + return bin; +} + +static inline uint8_t bin_to_bcd(uint8_t bin) +{ + uint8_t bcd; + bcd = bin % 10; + bcd |= (bin / 10) << 4; + return bcd; +} + +static struct mcp7940m_rtc *mcp7940m_get_context(int minor) +{ + return (struct mcp7940m_rtc *) RTC_Table[minor].pDeviceParams; +} + +static int mcp7940m_i2c_read( + struct mcp7940m_rtc *ctx, + uint8_t addr, + uint8_t *buf, + size_t len +) +{ + int fd; + int rv; + struct i2c_msg msgs[] = {{ + .addr = ctx->i2c_addr, + .flags = 0, + .buf = &addr, + .len = 1, + }, { + .addr = ctx->i2c_addr, + .flags = I2C_M_RD, + .buf = buf, + .len = len, + }}; + struct i2c_rdwr_ioctl_data payload = { + .msgs = msgs, + .nmsgs = sizeof(msgs)/sizeof(msgs[0]), + }; + + fd = open(ctx->i2c_bus_path, O_RDWR); + if (fd < 0) { + return fd; + } + + rv = ioctl(fd, I2C_RDWR, &payload); + + close(fd); + + return rv; +} + +static int mcp7940m_i2c_write( + struct mcp7940m_rtc *ctx, + uint8_t addr, + const uint8_t *buf, + size_t len +) +{ + int fd; + int rv; + uint8_t writebuf[len + 1]; + struct i2c_msg msgs[] = {{ + .addr = ctx->i2c_addr, + .flags = 0, + .buf = writebuf, + .len = len + 1, + }}; + struct i2c_rdwr_ioctl_data payload = { + .msgs = msgs, + .nmsgs = sizeof(msgs)/sizeof(msgs[0]), + }; + + writebuf[0] = addr; + memcpy(&writebuf[1], buf, len); + + fd = open(ctx->i2c_bus_path, O_RDWR); + if (fd < 0) { + return fd; + } + + rv = ioctl(fd, I2C_RDWR, &payload); + + close(fd); + + return rv; +} + +static int mcp7940m_initialize_once(struct mcp7940m_rtc *ctx) +{ + uint8_t reg; + ssize_t rv; + + if (ctx->initialized) { + return 0; + } + + /* + * Make sure that all alarms and outputs are disabled. Enable or disable + * oscillator. + * + * This makes sure that we can start with an uninitialized device that has a + * random value in the control register. + */ + reg = 0; + if (!ctx->crystal) { + reg |= MCP7940M_CONTROL_EXTOSC; + } + rv = mcp7940m_i2c_write(ctx, REG_MCP7940M_CONTROL, ®, 1); + + if (rv == 0 && ctx->crystal) { + rv = mcp7940m_i2c_read(ctx, REG_RTCSEC, ®, 1); + if (rv == 0 && (reg & MCP7940M_RTCSEC_ST) == 0) { + reg |= MCP7940M_RTCSEC_ST; + rv = mcp7940m_i2c_write(ctx, REG_RTCSEC, ®, 1); + } + } + + ctx->initialized = true; + + return rv; +} + +static int mcp7940m_get_time(int minor, rtems_time_of_day *time) +{ + int rv = 0; + uint8_t buf[REG_RTCYEAR + 1]; + struct mcp7940m_rtc *ctx = mcp7940m_get_context(minor); + + if (!_System_state_Is_up(_System_state_Get())) { + return -1; + } + + rtems_mutex_lock(&ctx->mutex); + + rv = mcp7940m_initialize_once(ctx); + + if (rv == 0) { + rv = mcp7940m_i2c_read(ctx, REG_RTCSEC, buf, sizeof(buf)); + } + + if (rv == 0) { + unsigned year = bcd_to_bin(RTCYEAR_YRBCD_GET(buf[REG_RTCYEAR])) + + (TOD_BASE_YEAR / 100 * 100); + if (year < TOD_BASE_YEAR) { + year += 100; + } + time->year = year; + time->month = bcd_to_bin(RTCMTH_MTHBCD_GET(buf[REG_RTCMTH])); + time->day = bcd_to_bin(RTCDATE_DATEBCD_GET(buf[REG_RTCDATE])); + time->hour = bcd_to_bin(RTCHOUR_HRBCD24_GET(buf[REG_RTCHOUR])); + time->minute = bcd_to_bin(RTCMIN_MINBCD_GET(buf[REG_RTCMIN])); + time->second = bcd_to_bin(RTCSEC_SECBCD_GET(buf[REG_RTCSEC])); + time->ticks = 0; + } + + rtems_mutex_unlock(&ctx->mutex); + + return rv; +} + +static int mcp7940m_set_time(int minor, const rtems_time_of_day *time) +{ + int rv = 0; + uint8_t buf[REG_RTCYEAR + 1]; + struct mcp7940m_rtc *ctx = mcp7940m_get_context(minor); + + if (!_System_state_Is_up(_System_state_Get())) { + return -1; + } + + rtems_mutex_lock(&ctx->mutex); + + rv = mcp7940m_initialize_once(ctx); + + if (rv == 0) { + rv = mcp7940m_i2c_read(ctx, REG_RTCSEC, buf, sizeof(buf)); + } + + if (rv == 0) { + /* Make sure weekday is not 0 (out of range). Otherwise it's not used. */ + if (RTCWKDAY_WKDAY_GET(buf[REG_RTCWKDAY]) < 1) { + buf[REG_RTCWKDAY] &= ~RTCWKDAY_WKDAY_MASK; + buf[REG_RTCWKDAY] |= RTCWKDAY_WKDAY(1); + } + + buf[REG_RTCYEAR] &= ~RTCYEAR_YRBCD_MASK; + buf[REG_RTCYEAR] |= RTCYEAR_YRBCD(bin_to_bcd(time->year % 100)); + + buf[REG_RTCMTH] &= ~RTCMTH_MTHBCD_MASK; + buf[REG_RTCMTH] |= RTCMTH_MTHBCD(bin_to_bcd(time->month)); + + buf[REG_RTCDATE] &= ~RTCDATE_DATEBCD_MASK; + buf[REG_RTCDATE] |= RTCDATE_DATEBCD(bin_to_bcd(time->day)); + + buf[REG_RTCHOUR] &= ~(RTCHOUR_HRBCD24_MASK | RTCHOUR_1224); + buf[REG_RTCHOUR] |= RTCHOUR_HRBCD24(bin_to_bcd(time->hour)); + + buf[REG_RTCMIN] &= ~RTCMIN_MINBCD_MASK; + buf[REG_RTCMIN] |= RTCMIN_MINBCD(bin_to_bcd(time->minute)); + + buf[REG_RTCSEC] &= ~RTCSEC_SECBCD_MASK; + buf[REG_RTCSEC] |= RTCSEC_SECBCD(bin_to_bcd(time->second)); + + rv = mcp7940m_i2c_write(ctx, REG_RTCSEC, buf, sizeof(buf)); + } + + rtems_mutex_unlock(&ctx->mutex); + + return rv; +} + +static void mcp7940m_init(int minor) +{ + (void) minor; +} + +bool rtc_mcp7940m_probe(int minor) +{ + return true; +} + +const rtc_fns rtc_mcp7940m_fns = { + .deviceInitialize = mcp7940m_init, + .deviceGetTime = mcp7940m_get_time, + .deviceSetTime = mcp7940m_set_time, +}; diff --git a/bsps/shared/dev/rtc/rtcprobe.c b/bsps/shared/dev/rtc/rtcprobe.c index 71472ffd7c..0d85831d62 100644 --- a/bsps/shared/dev/rtc/rtcprobe.c +++ b/bsps/shared/dev/rtc/rtcprobe.c @@ -1,12 +1,31 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains the default Real-Time Clock probe routine. * * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/serial/arm-pl011.c b/bsps/shared/dev/serial/arm-pl011.c index c3cbab6f3e..e9a8e3f5a4 100644 --- a/bsps/shared/dev/serial/arm-pl011.c +++ b/bsps/shared/dev/serial/arm-pl011.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved. + * Copyright (C) 2013, 2014 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <dev/serial/arm-pl011.h> diff --git a/bsps/shared/dev/serial/console-output-char.c b/bsps/shared/dev/serial/console-output-char.c index fec204663a..477fd1ffde 100644 --- a/bsps/shared/dev/serial/console-output-char.c +++ b/bsps/shared/dev/serial/console-output-char.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * Copyright (c) 2013 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <libchip/serial.h> diff --git a/bsps/shared/dev/serial/console-polled.c b/bsps/shared/dev/serial/console-polled.c index 26c9817bdb..37ad5b8f18 100644 --- a/bsps/shared/dev/serial/console-polled.c +++ b/bsps/shared/dev/serial/console-polled.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains the hardware independent portion of a polled * console device driver. If a BSP chooses to use this, then it @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <bsp.h> @@ -94,7 +113,7 @@ rtems_device_driver console_open( NULL, /* setAttributes */ NULL, /* stopRemoteTx */ NULL, /* startRemoteTx */ - 0 /* outputUsesInterrupts */ + TERMIOS_POLLED /* outputUsesInterrupts */ }; assert( minor == 0 ); diff --git a/bsps/shared/dev/serial/console-termios-init.c b/bsps/shared/dev/serial/console-termios-init.c index a01a75abf2..c144549cb4 100644 --- a/bsps/shared/dev/serial/console-termios-init.c +++ b/bsps/shared/dev/serial/console-termios-init.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved. + * Copyright (C) 2014, 2016 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <bsp/console-termios.h> diff --git a/bsps/shared/dev/serial/console-termios.c b/bsps/shared/dev/serial/console-termios.c index 1e755d91c9..bdea1a0284 100644 --- a/bsps/shared/dev/serial/console-termios.c +++ b/bsps/shared/dev/serial/console-termios.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved. + * Copyright (C) 2014, 2016 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems/console.h> diff --git a/bsps/shared/dev/serial/getserialmouseps2.c b/bsps/shared/dev/serial/getserialmouseps2.c index dc30deecbf..451a62d716 100644 --- a/bsps/shared/dev/serial/getserialmouseps2.c +++ b/bsps/shared/dev/serial/getserialmouseps2.c @@ -1,15 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * Copyright (c) 2013 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <info@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems/serial_mouse.h> diff --git a/bsps/shared/dev/serial/legacy-console-control.c b/bsps/shared/dev/serial/legacy-console-control.c index 01c6793c67..36497b27be 100644 --- a/bsps/shared/dev/serial/legacy-console-control.c +++ b/bsps/shared/dev/serial/legacy-console-control.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -14,9 +16,26 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <bsp.h> diff --git a/bsps/shared/dev/serial/legacy-console-select.c b/bsps/shared/dev/serial/legacy-console-select.c index 8d545e7737..d398503406 100644 --- a/bsps/shared/dev/serial/legacy-console-select.c +++ b/bsps/shared/dev/serial/legacy-console-select.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -13,9 +15,26 @@ * COPYRIGHT (c) 2011. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <bsp.h> diff --git a/bsps/shared/dev/serial/legacy-console.c b/bsps/shared/dev/serial/legacy-console.c index 998e4aa6fd..698439b247 100644 --- a/bsps/shared/dev/serial/legacy-console.c +++ b/bsps/shared/dev/serial/legacy-console.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -10,9 +12,26 @@ * COPYRIGHT (c) 1989-2011, 2016. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <bsp.h> @@ -215,7 +234,11 @@ rtems_device_driver console_open( Callbacks.stopRemoteTx = NULL; Callbacks.startRemoteTx = NULL; } - Callbacks.outputUsesInterrupts = cptr->pDeviceFns->deviceOutputUsesInterrupts; + if (cptr->pDeviceFns->deviceOutputUsesInterrupts) { + Callbacks.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN; + } else { + Callbacks.outputUsesInterrupts = TERMIOS_POLLED; + } /* XXX what about * Console_Port_Tbl[minor].ulMargin, diff --git a/bsps/shared/dev/serial/legacy-console.h b/bsps/shared/dev/serial/legacy-console.h index 3855e83100..424b55c574 100644 --- a/bsps/shared/dev/serial/legacy-console.h +++ b/bsps/shared/dev/serial/legacy-console.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -10,9 +12,26 @@ * COPYRIGHT (c) 1989-2011, 2016. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 _PC386_CONSOLE_PRIVATE_h diff --git a/bsps/shared/dev/serial/mc68681.c b/bsps/shared/dev/serial/mc68681.c index f4ddbd6a50..62f5cd1fbf 100644 --- a/bsps/shared/dev/serial/mc68681.c +++ b/bsps/shared/dev/serial/mc68681.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains the termios TTY driver for the Motorola MC68681. * @@ -9,9 +11,26 @@ * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/serial/mc68681_p.h b/bsps/shared/dev/serial/mc68681_p.h index 4623276303..eee7613508 100644 --- a/bsps/shared/dev/serial/mc68681_p.h +++ b/bsps/shared/dev/serial/mc68681_p.h @@ -1,11 +1,30 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 _MC68681_P_H_ diff --git a/bsps/shared/dev/serial/mc68681_reg.c b/bsps/shared/dev/serial/mc68681_reg.c index fb92b8fcd3..a1a70ba2e6 100644 --- a/bsps/shared/dev/serial/mc68681_reg.c +++ b/bsps/shared/dev/serial/mc68681_reg.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the mc68681 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/serial/mc68681_reg2.c b/bsps/shared/dev/serial/mc68681_reg2.c index 0e0121eb40..4cd79d93e1 100644 --- a/bsps/shared/dev/serial/mc68681_reg2.c +++ b/bsps/shared/dev/serial/mc68681_reg2.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the mc68681 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _MC68681_MULTIPLIER 2 diff --git a/bsps/shared/dev/serial/mc68681_reg4.c b/bsps/shared/dev/serial/mc68681_reg4.c index e9dd94ce4b..1d46d1a121 100644 --- a/bsps/shared/dev/serial/mc68681_reg4.c +++ b/bsps/shared/dev/serial/mc68681_reg4.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the mc68681 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _MC68681_MULTIPLIER 4 diff --git a/bsps/shared/dev/serial/mc68681_reg8.c b/bsps/shared/dev/serial/mc68681_reg8.c index 402c2ffe1b..e7268b0304 100644 --- a/bsps/shared/dev/serial/mc68681_reg8.c +++ b/bsps/shared/dev/serial/mc68681_reg8.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the mc68681 chip if accesses to the chip are as follows: @@ -8,9 +10,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ #define _MC68681_MULTIPLIER 8 diff --git a/bsps/shared/dev/serial/printk-dummy.c b/bsps/shared/dev/serial/printk-dummy.c index 8273edb83a..4febd8832f 100644 --- a/bsps/shared/dev/serial/printk-dummy.c +++ b/bsps/shared/dev/serial/printk-dummy.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @brief Stub printk() support @@ -10,9 +12,26 @@ * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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. */ /* diff --git a/bsps/shared/dev/serial/uart-output-char.c b/bsps/shared/dev/serial/uart-output-char.c index 0831b8d3ed..6ec58a6588 100644 --- a/bsps/shared/dev/serial/uart-output-char.c +++ b/bsps/shared/dev/serial/uart-output-char.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -7,17 +9,28 @@ */ /* - * Copyright (c) 2010-2011 embedded brains GmbH. All rights reserved. + * Copyright (C) 2010, 2011 embedded brains GmbH & Co. KG * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * 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. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems/bspIo.h> diff --git a/bsps/shared/dev/serial/z85c30_reg.c b/bsps/shared/dev/serial/z85c30_reg.c index 6e7b5d3494..ecc4074538 100644 --- a/bsps/shared/dev/serial/z85c30_reg.c +++ b/bsps/shared/dev/serial/z85c30_reg.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * This file contains a typical set of register access routines which may be * used with the z85c30 chip if accesses to the chip are as follows: @@ -7,9 +9,26 @@ * COPYRIGHT (c) 1989-1997. * On-Line Applications Research Corporation (OAR). * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * 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 <rtems.h> diff --git a/bsps/shared/dev/serial/zynq-uart-kernel-io.c b/bsps/shared/dev/serial/zynq-uart-kernel-io.c new file mode 100644 index 0000000000..61b1043cd2 --- /dev/null +++ b/bsps/shared/dev/serial/zynq-uart-kernel-io.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup zynq_uart + * + * @brief This source file contains the definition of ::BSP_output_char and + * ::BSP_poll_char. + */ + +/* + * Copyright (C) 2013, 2024 embedded brains GmbH & Co. KG + * + * 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 <rtems/bspIo.h> + +#include <bsp.h> +#include <dev/serial/zynq-uart-regs.h> +#include <rtems/sysinit.h> + +static void zynq_uart_kernel_output_char(char c) +{ + volatile zynq_uart *regs = + (volatile zynq_uart *) ZYNQ_UART_KERNEL_IO_BASE_ADDR; + + zynq_uart_write_char_polled(regs, c); +} + +static int zynq_uart_kernel_poll_char(void) +{ + volatile zynq_uart *regs = + (volatile zynq_uart *) ZYNQ_UART_KERNEL_IO_BASE_ADDR; + + return zynq_uart_read_char_polled(regs); +} + +static void zynq_uart_kernel_early_init(char c); + +static void zynq_uart_kernel_init(void) +{ + volatile zynq_uart *regs = + (volatile zynq_uart *) ZYNQ_UART_KERNEL_IO_BASE_ADDR; + + if (BSP_output_char != zynq_uart_kernel_early_init) { + return; + } + + zynq_uart_initialize(regs); + BSP_output_char = zynq_uart_kernel_output_char; +} + +static void zynq_uart_kernel_early_init(char c) +{ + zynq_uart_kernel_init(); + zynq_uart_kernel_output_char(c); +} + +BSP_output_char_function_type BSP_output_char = zynq_uart_kernel_early_init; + +BSP_polling_getchar_function_type BSP_poll_char = zynq_uart_kernel_poll_char; + +RTEMS_SYSINIT_ITEM( + zynq_uart_kernel_init, + RTEMS_SYSINIT_BSP_START, + RTEMS_SYSINIT_ORDER_LAST_BUT_5 +); diff --git a/bsps/shared/dev/serial/zynq-uart-polled.c b/bsps/shared/dev/serial/zynq-uart-polled.c index 6865fa8d6f..dbf75539f6 100644 --- a/bsps/shared/dev/serial/zynq-uart-polled.c +++ b/bsps/shared/dev/serial/zynq-uart-polled.c @@ -1,7 +1,16 @@ -/* - * SPDX-License-Identifier: BSD-2-Clause +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file * - * Copyright (C) 2013, 2017 embedded brains GmbH + * @ingroup RTEMSBSPsARMZynq + * + * @brief This source file contains the implementation of the polled Zynq UART + * support. + */ + +/* + * Copyright (C) 2013, 2017 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -115,10 +124,8 @@ int zynq_cal_baud_rate(uint32_t baudrate, return 0; } -void zynq_uart_initialize(rtems_termios_device_context *base) +void zynq_uart_initialize(volatile zynq_uart *regs) { - zynq_uart_context *ctx = (zynq_uart_context *) base; - volatile zynq_uart *regs = ctx->regs; uint32_t brgr = 0x3e; uint32_t bauddiv = 0x6; uint32_t mode_clks = regs->mode & ZYNQ_UART_MODE_CLKS; @@ -145,18 +152,15 @@ void zynq_uart_initialize(rtems_termios_device_context *base) | ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8) | mode_clks; - while (zynq_uart_read_polled(base) >= 0) { + while (zynq_uart_read_char_polled(regs) >= 0) { /* Drop */ } - zynq_uart_reset_tx_flush(ctx); + zynq_uart_reset_tx_flush(regs); } -int zynq_uart_read_polled(rtems_termios_device_context *base) +int zynq_uart_read_char_polled(volatile zynq_uart *regs) { - zynq_uart_context *ctx = (zynq_uart_context *) base; - volatile zynq_uart *regs = ctx->regs; - if ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) != 0) { return -1; } else { @@ -164,14 +168,8 @@ int zynq_uart_read_polled(rtems_termios_device_context *base) } } -void zynq_uart_write_polled( - rtems_termios_device_context *base, - char c -) +void zynq_uart_write_char_polled(volatile zynq_uart *regs, char c) { - zynq_uart_context *ctx = (zynq_uart_context *) base; - volatile zynq_uart *regs = ctx->regs; - while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TNFUL) != 0) { /* Wait */ } @@ -179,13 +177,12 @@ void zynq_uart_write_polled( regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(c); } -void zynq_uart_reset_tx_flush(zynq_uart_context *ctx) +void zynq_uart_reset_tx_flush(volatile zynq_uart *regs) { - volatile zynq_uart *regs = ctx->regs; - int c = 4; + int c = 4; while (c-- > 0) - zynq_uart_write_polled(&ctx->base, '\r'); + zynq_uart_write_char_polled(regs, '\r'); while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0 || (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TACTIVE) != 0) { diff --git a/bsps/shared/dev/serial/zynq-uart.c b/bsps/shared/dev/serial/zynq-uart.c index 8ff1d25da0..0489288271 100644 --- a/bsps/shared/dev/serial/zynq-uart.c +++ b/bsps/shared/dev/serial/zynq-uart.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (C) 2013, 2017 embedded brains GmbH + * Copyright (C) 2013, 2017 embedded brains GmbH & Co. KG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,7 @@ #include <dev/serial/zynq-uart.h> #include <dev/serial/zynq-uart-regs.h> #include <bsp/irq.h> +#include <rtems/termiostypes.h> #include <bspopts.h> @@ -66,14 +67,14 @@ static bool zynq_uart_first_open( rtems_libio_open_close_args_t *args ) { -#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS zynq_uart_context *ctx = (zynq_uart_context *) base; volatile zynq_uart *regs = ctx->regs; +#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS rtems_status_code sc; #endif rtems_termios_set_initial_baud(tty, ZYNQ_UART_DEFAULT_BAUD); - zynq_uart_initialize(base); + zynq_uart_initialize(regs); #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS regs->rx_fifo_trg_lvl = 1; @@ -108,15 +109,23 @@ static void zynq_uart_last_close( } #endif +#ifndef ZYNQ_CONSOLE_USE_INTERRUPTS +static int zynq_uart_read_polled(rtems_termios_device_context *base) +{ + zynq_uart_context *ctx = (zynq_uart_context *) base; + return zynq_uart_read_char_polled(ctx->regs); +} +#endif + static void zynq_uart_write_support( rtems_termios_device_context *base, const char *buf, size_t len ) { -#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS zynq_uart_context *ctx = (zynq_uart_context *) base; volatile zynq_uart *regs = ctx->regs; +#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS regs->irq_dis = ZYNQ_UART_TEMPTY; @@ -134,9 +143,9 @@ static void zynq_uart_write_support( regs->irq_en = ZYNQ_UART_TEMPTY; } #else - ssize_t i; + size_t i; for (i = 0; i < len; ++i) { - zynq_uart_write_polled(base, buf[i]); + zynq_uart_write_char_polled(regs, buf[i]); } #endif } diff --git a/bsps/shared/dev/spi/VERSION b/bsps/shared/dev/spi/VERSION new file mode 100644 index 0000000000..a0acb181b6 --- /dev/null +++ b/bsps/shared/dev/spi/VERSION @@ -0,0 +1,29 @@ +The information in this file describes the source of the following files in +bsps/shared/dev/spi/ and bsps/include/dev/spi/: + +- xqspipsu_control.c +- xqspipsu_control.h +- xqspipsu_flash_config.h +- xqspipsu_hw.c +- xqspipsu_hw.h +- xqspipsu_options.c +- xqspipsu.c +- xqspipsu.h + +Import from: + +https://github.com/Xilinx/embeddedsw.git + +commit 8a89579489c88ea5acd23d7d439ac928659c26cf +Author: msreeram <manikanta.sreeram@xilinx.com> +AuthorDate: Wed Apr 6 23:24:38 2022 -0600 +Commit: Siva Addepalli <sivaprasad.addepalli@xilinx.com> +CommitDate: Fri Apr 8 16:47:15 2022 +0530 + + update license file for EmbeddedSW 2022.1 release + + Update license file for EmbeddedSW 2022.1 release + + Signed-off-by: Manikanta Sreeram <msreeram@xilinx.com> + + Acked-by : Meena Paleti <meena.paleti@xilinx.com> diff --git a/bsps/shared/dev/spi/xqspipsu-flash-helper.c b/bsps/shared/dev/spi/xqspipsu-flash-helper.c new file mode 100644 index 0000000000..10e1066173 --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu-flash-helper.c @@ -0,0 +1,2341 @@ +/****************************************************************************** +* Copyright (C) 2018 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/** + * @file xqspipsu_flash_helper.c + * + * This file contains flash helper functions for the QSPIPSU driver. It + * consists of modified functions from Xilinx's flash example in + * examples/xqspipsu_generic_flash_interrupt_example.c of the qspipsu driver. + * + */ + +#include "xqspipsu_flash_config.h" +#include "xqspipsu-flash-helper.h" + +#include <rtems.h> + +/* + * Number of flash pages to be written. + */ +#define PAGE_COUNT 32 + +/* + * Max page size to initialize write and read buffer + */ +#define MAX_PAGE_SIZE 1024 + +#define TEST_ADDRESS 0x000000 + +#define ENTER_4B 1 +#define EXIT_4B 0 + +u8 ReadCmd; +u8 WriteCmd; +u8 StatusCmd; +u8 SectorEraseCmd; +u8 FSRFlag; + +static int FlashReadID(XQspiPsu *QspiPsuPtr); + +static int MultiDieRead( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 Command, + u8 *WriteBfrPtr, + u8 *ReadBfrPtr +); + +static u32 GetRealAddr( + XQspiPsu *QspiPsuPtr, + u32 Address +); + +static int BulkErase( + XQspiPsu *QspiPsuPtr, + u8 *WriteBfrPtr +); + +static int DieErase( + XQspiPsu *QspiPsuPtr, + u8 *WriteBfrPtr +); + +static int QspiPsuSetupIntrSystem( + XQspiPsu *QspiPsuInstancePtr, + u16 QspiPsuIntrId +); + +static void QspiPsuHandler( + void *CallBackRef, + u32 StatusEvent, + unsigned int ByteCount +); + +static int FlashEnterExit4BAddMode( + XQspiPsu *QspiPsuPtr, + unsigned int Enable +); + +static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr); + +u8 TxBfrPtr; +u8 ReadBfrPtr[3]; +u32 FlashMake; +u32 FCTIndex; /* Flash configuration table index */ + +static XQspiPsu_Msg FlashMsg[5]; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing + */ +int Error; + +/* + * The following variable allows a test value to be added to the values that + * are written to the Flash such that unique values can be generated to + * guarantee the writes to the Flash were successful + */ +int Test = 1; + +/* + * The following variables are used to read and write to the flash and they + * are global to avoid having large buffers on the stack + * The buffer size accounts for maximum page size and maximum banks - + * for each bank separate read will be performed leading to that many + * (overhead+dummy) bytes + */ +#ifdef __ICCARM__ +#pragma data_alignment = 32 +u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8]; +#else +u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64))); +#endif +u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET]; +u8 CmdBfr[8]; + +/* + * The following constants specify the max amount of data and the size of the + * the buffer required to hold the data and overhead to transfer the data to + * and from the Flash. Initialized to single flash page size. + */ +u32 MaxData = PAGE_COUNT*256; + +int QspiPsu_NOR_Initialize( + XQspiPsu *QspiPsuInstancePtr, + u16 QspiPsuIntrId +) +{ + int Status; + + if (QspiPsuInstancePtr == NULL) { + return XST_FAILURE; + } + + /* + * Connect the QspiPsu device to the interrupt subsystem such that + * interrupts can occur. This function is application specific + */ + Status = QspiPsuSetupIntrSystem(QspiPsuInstancePtr, QspiPsuIntrId); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the QSPIPSU that will be called from the + * interrupt context when an QSPIPSU status occurs, specify a pointer to + * the QSPIPSU driver instance as the callback reference + * so the handler is able to access the instance data + */ + XQspiPsu_SetStatusHandler(QspiPsuInstancePtr, QspiPsuInstancePtr, + (XQspiPsu_StatusHandler) QspiPsuHandler); + + /* + * Set Manual Start + */ + XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION); + + /* + * Set the prescaler for QSPIPSU clock + */ + XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8); + + XQspiPsu_SelectFlash(QspiPsuInstancePtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + /* + * Read flash ID and obtain all flash related information + * It is important to call the read id function before + * performing proceeding to any operation, including + * preparing the WriteBuffer + */ + + Status = FlashReadID(QspiPsuInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Some flash needs to enable Quad mode before using + * quad commands. + */ + Status = FlashEnableQuadMode(QspiPsuInstancePtr); + if (Status != XST_SUCCESS) + return XST_FAILURE; + + /* + * Address size and read command selection + * Micron flash on REMUS doesn't support these 4B write/erase commands + */ + if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE) + ReadCmd = FAST_READ_CMD; + else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE) + ReadCmd = DUAL_READ_CMD; + else + ReadCmd = QUAD_READ_CMD; + + WriteCmd = WRITE_CMD; + SectorEraseCmd = SEC_ERASE_CMD; + + if ((Flash_Config_Table[FCTIndex].NumDie > 1) && + (FlashMake == MICRON_ID_BYTE0)) { + StatusCmd = READ_FLAG_STATUS_CMD; + FSRFlag = 1; + } else { + StatusCmd = READ_STATUS_CMD; + FSRFlag = 0; + } + + if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + Status = FlashEnterExit4BAddMode(QspiPsuInstancePtr, ENTER_4B); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + if (FlashMake == SPANSION_ID_BYTE0) { + if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE) + ReadCmd = FAST_READ_CMD_4B; + else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE) + ReadCmd = DUAL_READ_CMD_4B; + else + ReadCmd = QUAD_READ_CMD_4B; + + WriteCmd = WRITE_CMD_4B; + SectorEraseCmd = SEC_ERASE_CMD_4B; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * + * Callback handler. + * + * @param CallBackRef is the upper layer callback reference passed back + * when the callback function is invoked. + * @param StatusEvent is the event that just occurred. + * @param ByteCount is the number of bytes transferred up until the event + * occurred. + * + * @return None + * + * @note None. + * + *****************************************************************************/ +static void QspiPsuHandler( + void *CallBackRef, + u32 StatusEvent, + unsigned int ByteCount +) +{ + /* + * Indicate the transfer on the QSPIPSU bus is no longer in progress + * regardless of the status event + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + Error++; + } +} + +int QspiPsu_NOR_RDSFDP( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 **ReadBfrPtr +) +{ + int Status; + + *ReadBfrPtr = ReadBuffer; + + CmdBfr[COMMAND_OFFSET] = READ_SFDP; + CmdBfr[ADDRESS_1_OFFSET] = + (u8)((Address & 0xFF0000) >> 16); + CmdBfr[ADDRESS_2_OFFSET] = + (u8)((Address & 0xFF00) >> 8); + CmdBfr[ADDRESS_3_OFFSET] = + (u8)(Address & 0xFF); + + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].TxBfrPtr = CmdBfr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 4; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = DUMMY_CLOCKS; + FlashMsg[1].Flags = 0; + + FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[2].TxBfrPtr = NULL; + FlashMsg[2].RxBfrPtr = *ReadBfrPtr; + FlashMsg[2].ByteCount = ByteCount; + FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 3); + if (Status != XST_SUCCESS) + return XST_FAILURE; + + while (TransferInProgress); + + rtems_cache_invalidate_multiple_data_lines(ReadBuffer, ByteCount); + return 0; +} + +int QspiPsu_NOR_RDID(XQspiPsu *QspiPsuPtr, u8 *ReadBfrPtr, u32 ReadLen) +{ + int Status; + + /* + * Read ID + */ + TxBfrPtr = READ_ID; + FlashMsg[0].TxBfrPtr = &TxBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = ReadBfrPtr; + FlashMsg[1].ByteCount = ReadLen; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + rtems_cache_invalidate_multiple_data_lines(ReadBfrPtr, ReadLen); + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * + * Reads the flash ID and identifies the flash in FCT table. + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * + * @return XST_SUCCESS if successful, else XST_FAILURE. + * + * @note None. + * + *****************************************************************************/ +static int FlashReadID(XQspiPsu *QspiPsuPtr) +{ + u32 ReadId = 0; + u32 ReadLen = 3; + int Status; + + Status = QspiPsu_NOR_RDID(QspiPsuPtr, ReadBfrPtr, ReadLen); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* In case of dual, read both and ensure they are same make/size */ + + /* + * Deduce flash make + */ + FlashMake = ReadBfrPtr[0]; + + ReadId = ((ReadBfrPtr[0] << 16) | (ReadBfrPtr[1] << 8) | ReadBfrPtr[2]); + /* + * Assign corresponding index in the Flash configuration table + */ + Status = CalculateFCTIndex(ReadId, &FCTIndex); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +int QspiPsu_NOR_Write_Page( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 *WriteBfrPtr +) +{ + u8 WriteEnableCmd; + u8 ReadStatusCmd; + u8 FlashStatus[2]; + u8 WriteCmdBfr[5]; + u32 RealAddr; + u32 CmdByteCount; + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + while (TransferInProgress); + + WriteCmdBfr[COMMAND_OFFSET] = WriteCmd; + + /* To be used only if 4B address program cmd is supported by flash */ + if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteCmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + WriteCmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteCmdBfr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteCmdBfr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xFF); + CmdByteCount = 5; + } else { + WriteCmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteCmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteCmdBfr[ADDRESS_3_OFFSET] = + (u8)(RealAddr & 0xFF); + CmdByteCount = 4; + } + + FlashMsg[0].TxBfrPtr = WriteCmdBfr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = CmdByteCount; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = WriteBfrPtr; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = ByteCount; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + while (TransferInProgress); + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + + if (FSRFlag) { + if ((FlashStatus[1] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[1] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +int QspiPsu_NOR_Write( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 *WriteBfrPtr +) +{ + int Status; + size_t ByteCountRemaining = ByteCount; + unsigned char *WriteBfrPartial = WriteBfrPtr; + uint32_t AddressPartial = Address; + uint32_t PageSize = Flash_Config_Table[FCTIndex].PageSize; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) { + PageSize *= 2; + } + + while (ByteCountRemaining > 0) { + /* Get write boundary */ + size_t WriteChunkLen = RTEMS_ALIGN_UP(AddressPartial + 1, PageSize); + + /* Get offset to write boundary */ + WriteChunkLen -= (size_t)AddressPartial; + + /* Cap short writes */ + if (WriteChunkLen > ByteCountRemaining) { + WriteChunkLen = ByteCountRemaining; + } + + Status = QspiPsu_NOR_Write_Page( + QspiPsuPtr, + AddressPartial, + WriteChunkLen, + WriteBfrPartial + ); + if ( Status != XST_SUCCESS ) { + return Status; + } + + ByteCountRemaining -= WriteChunkLen; + AddressPartial += WriteChunkLen; + WriteBfrPartial += WriteChunkLen; + } + return Status; +} + +int QspiPsu_NOR_Erase( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount +) +{ + u8 WriteEnableCmd; + u8 ReadStatusCmd; + u8 FlashStatus[2]; + int Sector; + u32 RealAddr; + u32 NumSect; + int Status; + u32 SectSize; + + WriteEnableCmd = WRITE_ENABLE_CMD; + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) { + SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2; + NumSect = (Flash_Config_Table[FCTIndex]).NumSect; + } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) { + NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2; + SectSize = (Flash_Config_Table[FCTIndex]).SectSize; + } else { + SectSize = (Flash_Config_Table[FCTIndex]).SectSize; + NumSect = (Flash_Config_Table[FCTIndex]).NumSect; + } + + /* + * If erase size is same as the total size of the flash, use bulk erase + * command or die erase command multiple times as required + */ + if (ByteCount == NumSect * SectSize) { + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_STACKED) { + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + } + + if (Flash_Config_Table[FCTIndex].NumDie == 1) { + /* + * Call Bulk erase + */ + BulkErase(QspiPsuPtr, CmdBfr); + } + + if (Flash_Config_Table[FCTIndex].NumDie > 1) { + /* + * Call Die erase + */ + DieErase(QspiPsuPtr, CmdBfr); + } + /* + * If stacked mode, bulk erase second flash + */ + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_STACKED) { + + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_UPPER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + if (Flash_Config_Table[FCTIndex].NumDie == 1) { + /* + * Call Bulk erase + */ + BulkErase(QspiPsuPtr, CmdBfr); + } + + if (Flash_Config_Table[FCTIndex].NumDie > 1) { + /* + * Call Die erase + */ + DieErase(QspiPsuPtr, CmdBfr); + } + } + + return 0; + } + + /* + * If the erase size is less than the total size of the flash, use + * sector erase command + */ + + /* + * Calculate no. of sectors to erase based on byte count + */ + u32 SectorStartBase = RTEMS_ALIGN_DOWN(Address, SectSize); + u32 SectorEndTop = RTEMS_ALIGN_UP(Address + ByteCount, SectSize); + NumSect = (SectorEndTop - SectorStartBase)/SectSize; + + for (Sector = 0; Sector < NumSect; Sector++) { + + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate + * transfer before the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + CmdBfr[COMMAND_OFFSET] = SectorEraseCmd; + + /* + * To be used only if 4B address sector erase cmd is + * supported by flash + */ + if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + CmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + CmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + CmdBfr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + CmdBfr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 5; + } else { + CmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + CmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + CmdBfr[ADDRESS_3_OFFSET] = + (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 4; + } + + FlashMsg[0].TxBfrPtr = CmdBfr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + /* + * Wait for the erase command to be completed + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, + FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + + if (FSRFlag) { + if ((FlashStatus[1] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[1] & 0x01) == 0) { + break; + } + } + } + Address += SectSize; + } + + return 0; +} + +int QspiPsu_NOR_Read( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 **ReadBfrPtr +) +{ + u32 RealAddr; + u32 DiscardByteCnt; + u32 FlashMsgCnt; + int Status; + + *ReadBfrPtr = ReadBuffer; + + /* Check die boundary conditions if required for any flash */ + if (Flash_Config_Table[FCTIndex].NumDie > 1) { + + Status = MultiDieRead(QspiPsuPtr, Address, ByteCount, ReadCmd, + CmdBfr, *ReadBfrPtr); + if (Status != XST_SUCCESS) + return XST_FAILURE; + } else { + /* For Dual Stacked, split and read for boundary crossing */ + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + CmdBfr[COMMAND_OFFSET] = ReadCmd; + if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + CmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + CmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + CmdBfr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + CmdBfr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xFF); + DiscardByteCnt = 5; + } else { + CmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + CmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + CmdBfr[ADDRESS_3_OFFSET] = + (u8)(RealAddr & 0xFF); + DiscardByteCnt = 4; + } + + FlashMsg[0].TxBfrPtr = CmdBfr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = DiscardByteCnt; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsgCnt = 1; + + /* It is recommended to have a separate entry for dummy */ + if (ReadCmd == FAST_READ_CMD || ReadCmd == DUAL_READ_CMD || + ReadCmd == QUAD_READ_CMD || ReadCmd == FAST_READ_CMD_4B || + ReadCmd == DUAL_READ_CMD_4B || + ReadCmd == QUAD_READ_CMD_4B) { + /* Update Dummy cycles as per flash specs for QUAD IO */ + + /* + * It is recommended that Bus width value during dummy + * phase should be same as data phase + */ + if (ReadCmd == FAST_READ_CMD || + ReadCmd == FAST_READ_CMD_4B) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + } + + if (ReadCmd == DUAL_READ_CMD || + ReadCmd == DUAL_READ_CMD_4B) { + FlashMsg[1].BusWidth = + XQSPIPSU_SELECT_MODE_DUALSPI; + } + + if (ReadCmd == QUAD_READ_CMD || + ReadCmd == QUAD_READ_CMD_4B) { + FlashMsg[1].BusWidth = + XQSPIPSU_SELECT_MODE_QUADSPI; + } + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = DUMMY_CLOCKS; + FlashMsg[1].Flags = 0; + + FlashMsgCnt++; + } + + /* Dummy cycles need to be changed as per flash specs + * for QUAD IO + */ + if (ReadCmd == FAST_READ_CMD || ReadCmd == FAST_READ_CMD_4B) + FlashMsg[FlashMsgCnt].BusWidth = + XQSPIPSU_SELECT_MODE_SPI; + + if (ReadCmd == DUAL_READ_CMD || ReadCmd == DUAL_READ_CMD_4B) + FlashMsg[FlashMsgCnt].BusWidth = + XQSPIPSU_SELECT_MODE_DUALSPI; + + if (ReadCmd == QUAD_READ_CMD || ReadCmd == QUAD_READ_CMD_4B) + FlashMsg[FlashMsgCnt].BusWidth = + XQSPIPSU_SELECT_MODE_QUADSPI; + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = *ReadBfrPtr; + FlashMsg[FlashMsgCnt].ByteCount = ByteCount; + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX; + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, + FlashMsgCnt + 1); + if (Status != XST_SUCCESS) + return XST_FAILURE; + + while (TransferInProgress); + + } + rtems_cache_invalidate_multiple_data_lines(ReadBuffer, ByteCount); + return 0; +} + +/*****************************************************************************/ +/** + * + * This function performs a read operation for multi die flash devices. + * Default setting is in DMA mode. + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * @param Address contains the address of the first sector which needs to + * be erased. + * @param ByteCount contains the total size to be erased. + * @param Command is the command used to read data from the flash. + * Supports normal, fast, dual and quad read commands. + * @param WriteBfrPtr is pointer to the write buffer which contains data to be + * transmitted + * @param ReadBfrPtr is pointer to the read buffer to which valid received data + * should be written + * + * @return XST_SUCCESS if successful, else XST_FAILURE. + * + * @note None. + * + ******************************************************************************/ +static int MultiDieRead( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 Command, + u8 *WriteBfrPtr, + u8 *ReadBfrPtr +) +{ + u32 RealAddr; + u32 DiscardByteCnt; + u32 FlashMsgCnt; + int Status; + u32 cur_bank = 0; + u32 nxt_bank = 0; + u32 bank_size; + u32 remain_len = ByteCount; + u32 data_len; + u32 transfer_len; + u8 *ReadBuffer = ReadBfrPtr; + + /* + * Some flash devices like N25Q512 have multiple dies + * in it. Read operation in these devices is bounded + * by its die segment. In a continuous read, across + * multiple dies, when the last byte of the selected + * die segment is read, the next byte read is the + * first byte of the same die segment. This is Die + * cross over issue. So to handle this issue, split + * a read transaction, that spans across multiple + * banks, into one read per bank. Bank size is 16MB + * for single and dual stacked mode and 32MB for dual + * parallel mode. + */ + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) + bank_size = SIXTEENMB << 1; + else + bank_size = SIXTEENMB; + + while (remain_len) { + cur_bank = Address / bank_size; + nxt_bank = (Address + remain_len) / bank_size; + + if (cur_bank != nxt_bank) { + transfer_len = (bank_size * (cur_bank + 1)) - Address; + if (remain_len < transfer_len) + data_len = remain_len; + else + data_len = transfer_len; + } else { + data_len = remain_len; + } + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + WriteBfrPtr[COMMAND_OFFSET] = Command; + if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteBfrPtr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xFF); + DiscardByteCnt = 5; + } else { + WriteBfrPtr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_3_OFFSET] = + (u8)(RealAddr & 0xFF); + DiscardByteCnt = 4; + } + + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = DiscardByteCnt; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsgCnt = 1; + + /* It is recommended to have a separate entry for dummy */ + if (Command == FAST_READ_CMD || Command == DUAL_READ_CMD || + Command == QUAD_READ_CMD || Command == FAST_READ_CMD_4B || + Command == DUAL_READ_CMD_4B || + Command == QUAD_READ_CMD_4B) { + /* Update Dummy cycles as per flash specs for QUAD IO */ + + /* + * It is recommended that Bus width value during dummy + * phase should be same as data phase + */ + if (Command == FAST_READ_CMD || + Command == FAST_READ_CMD_4B) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + } + + if (Command == DUAL_READ_CMD || + Command == DUAL_READ_CMD_4B) { + FlashMsg[1].BusWidth = + XQSPIPSU_SELECT_MODE_DUALSPI; + } + + if (Command == QUAD_READ_CMD || + Command == QUAD_READ_CMD_4B) { + FlashMsg[1].BusWidth = + XQSPIPSU_SELECT_MODE_QUADSPI; + } + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = DUMMY_CLOCKS; + FlashMsg[1].Flags = 0; + + FlashMsgCnt++; + } + + /* Dummy cycles need to be changed as per flash + * specs for QUAD IO + */ + if (Command == FAST_READ_CMD || Command == FAST_READ_CMD_4B) + FlashMsg[FlashMsgCnt].BusWidth = + XQSPIPSU_SELECT_MODE_SPI; + + if (Command == DUAL_READ_CMD || Command == DUAL_READ_CMD_4B) + FlashMsg[FlashMsgCnt].BusWidth = + XQSPIPSU_SELECT_MODE_DUALSPI; + + if (Command == QUAD_READ_CMD || Command == QUAD_READ_CMD_4B) + FlashMsg[FlashMsgCnt].BusWidth = + XQSPIPSU_SELECT_MODE_QUADSPI; + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer; + FlashMsg[FlashMsgCnt].ByteCount = data_len; + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX; + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) + FlashMsg[FlashMsgCnt].Flags |= + XQSPIPSU_MSG_FLAG_STRIPE; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, + FlashMsgCnt + 1); + if (Status != XST_SUCCESS) + return XST_FAILURE; + + while (TransferInProgress); + + + ReadBuffer += data_len; + Address += data_len; + remain_len -= data_len; + } + rtems_cache_invalidate_multiple_data_lines(ReadBfrPtr, ByteCount); + return 0; +} + +/*****************************************************************************/ +/** + * + * This functions performs a bulk erase operation when the + * flash device has a single die. Works for both Spansion and Micron + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * @param WriteBfrPtr is the pointer to command+address to be sent + * + * @return XST_SUCCESS if successful, else XST_FAILURE. + * + * @note None. + * + ******************************************************************************/ +static int BulkErase( + XQspiPsu *QspiPsuPtr, + u8 *WriteBfrPtr +) +{ + u8 WriteEnableCmd; + u8 ReadStatusCmd; + u8 FlashStatus[2]; + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + WriteBfrPtr[COMMAND_OFFSET] = BULK_ERASE_CMD; + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + + if (FSRFlag) { + if ((FlashStatus[1] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[1] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +/*****************************************************************************/ +/** + * + * This functions performs a die erase operation on all the die in + * the flash device. This function uses the die erase command for + * Micron 512Mbit and 1Gbit + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * @param WriteBfrPtr is the pointer to command+address to be sent + * + * @return XST_SUCCESS if successful, else XST_FAILURE. + * + * @note None. + * + ******************************************************************************/ +static int DieErase( + XQspiPsu *QspiPsuPtr, + u8 *WriteBfrPtr +) +{ + u8 WriteEnableCmd; + u8 DieCnt; + u8 ReadStatusCmd; + u8 FlashStatus[2]; + int Status; + u32 DieSize = 0; + u32 Address; + u32 RealAddr; + u32 SectSize = 0; + u32 NumSect = 0; + + WriteEnableCmd = WRITE_ENABLE_CMD; + + if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) { + SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2; + } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) { + NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2; + } else { + SectSize = (Flash_Config_Table[FCTIndex]).SectSize; + NumSect = (Flash_Config_Table[FCTIndex]).NumSect; + } + DieSize = (NumSect * SectSize) / Flash_Config_Table[FCTIndex].NumDie; + + for (DieCnt = 0; + DieCnt < Flash_Config_Table[FCTIndex].NumDie; + DieCnt++) { + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer + * before the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + WriteBfrPtr[COMMAND_OFFSET] = DIE_ERASE_CMD; + + Address = DieSize * DieCnt; + RealAddr = GetRealAddr(QspiPsuPtr, Address); + /* + * To be used only if 4B address sector erase cmd is + * supported by flash + */ + if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteBfrPtr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 5; + } else { + WriteBfrPtr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_3_OFFSET] = + (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 4; + } + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + /* + * Wait for the write command to the Flash to be completed, + * it takes some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, + FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + + if (FSRFlag) { + if ((FlashStatus[1] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[1] & 0x01) == 0) { + break; + } + } + } + } + + return 0; +} + +/*****************************************************************************/ +/** + * + * This functions translates the address based on the type of interconnection. + * In case of stacked, this function asserts the corresponding slave select. + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * @param Address which is to be accessed (for erase, write or read) + * + * @return RealAddr is the translated address - for single it is unchanged; + * for stacked, the lower flash size is subtracted; + * for parallel the address is divided by 2. + * + * @note In addition to get the actual address to work on flash this + * function also selects the CS and BUS based on the configuration + * detected. + * + ******************************************************************************/ +static u32 GetRealAddr( + XQspiPsu *QspiPsuPtr, + u32 Address +) +{ + u32 RealAddr = 0; + + switch (QspiPsuPtr->Config.ConnectionMode) { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + RealAddr = Address; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + /* Select lower or upper Flash based on sector address */ + if (Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) { + + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_UPPER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + /* + * Subtract first flash size when accessing second flash + */ + RealAddr = Address & + (~Flash_Config_Table[FCTIndex].FlashDeviceSize); + }else{ + /* + * Set selection to L_PAGE + */ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + RealAddr = Address; + + } + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + /* + * The effective address in each flash is the actual + * address / 2 + */ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_BOTH, + XQSPIPSU_SELECT_FLASH_BUS_BOTH); + RealAddr = Address / 2; + break; + default: + /* RealAddr wont be assigned in this case; */ + break; + + } + + return(RealAddr); +} + +/*****************************************************************************/ +/** + * + * This function setups the interrupt system for a QspiPsu device. + * + * @param QspiPsuInstancePtr is a pointer to the instance of the + * QspiPsu device. + * @param QspiPsuIntrId is the interrupt Id for an QSPIPSU device. + * + * @return XST_SUCCESS if successful, otherwise XST_FAILURE. + * + * @note None. + * + ******************************************************************************/ +static int QspiPsuSetupIntrSystem( + XQspiPsu *QspiPsuInstancePtr, + u16 QspiPsuIntrId +) +{ + return rtems_interrupt_handler_install( + QspiPsuIntrId, + NULL, + RTEMS_INTERRUPT_UNIQUE, + (rtems_interrupt_handler) XQspiPsu_InterruptHandler, + QspiPsuInstancePtr + ); +} + +/*****************************************************************************/ +/** + * @brief + * This API enters the flash device into 4 bytes addressing mode. + * As per the Micron and ISSI spec, before issuing the command + * to enter into 4 byte addr mode, a write enable command is issued. + * For Macronix and Winbond flash parts write + * enable is not required. + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * @param Enable is a either 1 or 0 if 1 then enters 4 byte if 0 exits. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if it fails. + * + * + ******************************************************************************/ +static int FlashEnterExit4BAddMode( + XQspiPsu *QspiPsuPtr, + unsigned int Enable +) +{ + int Status; + u8 WriteEnableCmd; + u8 Cmd; + u8 WriteDisableCmd; + u8 ReadStatusCmd; + u8 WriteBuffer[2] = {0}; + u8 FlashStatus[2] = {0}; + + if (Enable) { + Cmd = ENTER_4B_ADDR_MODE; + } else { + if (FlashMake == ISSI_ID_BYTE0) + Cmd = EXIT_4B_ADDR_MODE_ISSI; + else + Cmd = EXIT_4B_ADDR_MODE; + } + + switch (FlashMake) { + case ISSI_ID_BYTE0: + case MICRON_ID_BYTE0: + WriteEnableCmd = WRITE_ENABLE_CMD; + GetRealAddr(QspiPsuPtr, TEST_ADDRESS); + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer + * before the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + break; + + case SPANSION_ID_BYTE0: + + /* Read Extended Addres Register */ + WriteBuffer[0] = BANK_REG_RD; + FlashMsg[0].TxBfrPtr = &WriteBuffer[0]; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = &WriteBuffer[1]; + FlashMsg[1].ByteCount = 1; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + if (Enable) { + WriteBuffer[0] = BANK_REG_WR; + WriteBuffer[1] |= 1 << 7; + } else { + WriteBuffer[0] = BANK_REG_WR; + WriteBuffer[1] &= ~(0x01 << 7); + } + + FlashMsg[0].TxBfrPtr = &WriteBuffer[0]; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + FlashMsg[0].ByteCount = 1; + FlashMsg[1].TxBfrPtr = &WriteBuffer[1]; + FlashMsg[2].RxBfrPtr = NULL; + FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_TX; + FlashMsg[2].ByteCount = 1; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + WriteBuffer[0] = BANK_REG_RD; + FlashMsg[0].TxBfrPtr = &WriteBuffer[0]; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = &FlashStatus[0]; + FlashMsg[1].ByteCount = 1; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + return Status; + + default: + /* + * For Macronix and Winbond flash parts + * Write enable command is not required. + */ + break; + } + + GetRealAddr(QspiPsuPtr, TEST_ADDRESS); + + FlashMsg[0].TxBfrPtr = &Cmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + while (1) { + ReadStatusCmd = StatusCmd; + + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + + if (FSRFlag) { + if ((FlashStatus[1] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[1] & 0x01) == 0) { + break; + } + } + } + + switch (FlashMake) { + case ISSI_ID_BYTE0: + case MICRON_ID_BYTE0: + WriteDisableCmd = WRITE_DISABLE_CMD; + GetRealAddr(QspiPsuPtr, TEST_ADDRESS); + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer + * before the write + */ + FlashMsg[0].TxBfrPtr = &WriteDisableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + break; + + default: + /* + * For Macronix and Winbond flash parts + * Write disable command is not required. + */ + break; + } + return Status; +} + +/*****************************************************************************/ +/** + * @brief + * This API enables Quad mode for the flash parts which require to enable quad + * mode before using Quad commands. + * For S25FL-L series flash parts this is required as the default configuration + * is x1/x2 mode. + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if it fails. + * + * + ******************************************************************************/ +static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr) +{ + int Status; + u8 WriteEnableCmd; + u8 ReadStatusCmd; + u8 FlashStatus[2]; + u8 StatusRegVal; + u8 WriteBuffer[3] = {0}; + + switch (FlashMake) { + case SPANSION_ID_BYTE0: + TxBfrPtr = READ_CONFIG_CMD; + FlashMsg[0].TxBfrPtr = &TxBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = &WriteBuffer[2]; + FlashMsg[1].ByteCount = 1; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, + FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Send the write enable command to the Flash + * so that it can be written to, this needs + * to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, + FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + GetRealAddr(QspiPsuPtr, TEST_ADDRESS); + + WriteBuffer[0] = WRITE_CONFIG_CMD; + WriteBuffer[1] |= 0x02; + WriteBuffer[2] |= 0x01 << 1; + + FlashMsg[0].TxBfrPtr = &WriteBuffer[0]; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + FlashMsg[0].ByteCount = 1; + FlashMsg[1].TxBfrPtr = &WriteBuffer[1]; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, + FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + while (1) { + TxBfrPtr = READ_STATUS_CMD; + FlashMsg[0].TxBfrPtr = &TxBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, + FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + }else { + FlashStatus[1] |= FlashStatus[0]; + } + } + + if ((FlashStatus[1] & 0x01) == 0x00) + break; + } + TxBfrPtr = READ_CONFIG_CMD; + FlashMsg[0].TxBfrPtr = &TxBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = ReadBfrPtr; + FlashMsg[1].ByteCount = 1; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + break; + case ISSI_ID_BYTE0: + /* + * Read Status Register to a buffer + */ + ReadStatusCmd = READ_STATUS_CMD; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + /* + * Set Quad Enable Bit in the buffer + */ + StatusRegVal = FlashStatus[1]; + StatusRegVal |= 0x1 << QUAD_MODE_ENABLE_BIT; + + /* + * Write enable + */ + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer + * before the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + /* + * Write Status register + */ + WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_CMD; + FlashMsg[0].TxBfrPtr = WriteBuffer; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = &StatusRegVal; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = 1; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX; + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + /* + * Write Disable + */ + WriteEnableCmd = WRITE_DISABLE_CMD; + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + break; + + case WINBOND_ID_BYTE0: + ReadStatusCmd = READ_STATUS_REG_2_CMD; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + /* + * Set Quad Enable Bit in the buffer + */ + StatusRegVal = FlashStatus[1]; + StatusRegVal |= 0x1 << WB_QUAD_MODE_ENABLE_BIT; + /* + * Write Enable + */ + WriteEnableCmd = WRITE_ENABLE_CMD; + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + /* + * Write Status register + */ + WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_REG_2_CMD; + FlashMsg[0].TxBfrPtr = WriteBuffer; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsg[1].TxBfrPtr = &StatusRegVal; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = 1; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + while (1) { + ReadStatusCmd = READ_STATUS_CMD; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 2; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + if (FSRFlag) { + FlashStatus[1] &= FlashStatus[0]; + } else { + FlashStatus[1] |= FlashStatus[0]; + } + } + if ((FlashStatus[1] & 0x01) == 0x00) { + break; + } + } + /* + * Write Disable + */ + WriteEnableCmd = WRITE_DISABLE_CMD; + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while (TransferInProgress); + break; + + default: + /* + * Currently only S25FL-L series requires the + * Quad enable bit to be set to 1. + */ + Status = XST_SUCCESS; + break; + } + + return Status; +} + +static int MultiDieReadEcc( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 *WriteBfrPtr, + u8 *ReadBfrPtr +); + +int QspiPsu_NOR_Read_Ecc( + XQspiPsu *QspiPsuPtr, + u32 Address, + u8 *ReadBfrPtr +) +{ + u32 RealAddr; + u32 DiscardByteCnt; + u32 FlashMsgCnt; + u8 EccBuffer[16]; + int ByteCount = sizeof(EccBuffer); + int Status; + + /* Check die boundary conditions if required for any flash */ + if (Flash_Config_Table[FCTIndex].NumDie > 1) { + + Status = MultiDieReadEcc(QspiPsuPtr, Address, ByteCount, + CmdBfr, EccBuffer); + if (Status == XST_SUCCESS) { + /* All bytes are the same, so copy one return byte into the output buffer */ + *ReadBfrPtr = EccBuffer[0]; + } + return Status; + } + + /* For Dual Stacked, split and read for boundary crossing */ + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + CmdBfr[COMMAND_OFFSET] = READ_ECCSR; + CmdBfr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + CmdBfr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + CmdBfr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + CmdBfr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xF0); + DiscardByteCnt = 5; + + FlashMsgCnt = 0; + + FlashMsg[FlashMsgCnt].TxBfrPtr = CmdBfr; + FlashMsg[FlashMsgCnt].RxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt; + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsgCnt++; + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS; + FlashMsg[FlashMsgCnt].Flags = 0; + + FlashMsgCnt++; + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = EccBuffer; + FlashMsg[FlashMsgCnt].ByteCount = ByteCount; + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX; + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) { + FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, + FlashMsgCnt + 1); + if (Status == XST_SUCCESS) { + while (TransferInProgress); + + /* All bytes are the same, so copy one return byte into the output buffer */ + *ReadBfrPtr = EccBuffer[0]; + } + + return Status; +} + +/*****************************************************************************/ +/** + * + * This function performs an ECC read operation for multi die flash devices. + * Default setting is in DMA mode. + * + * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. + * @param Address contains the address of the first sector which needs to + * be erased. + * @param ByteCount contains the total size to be erased. + * @param WriteBfrPtr is pointer to the write buffer which contains data to be + * transmitted + * @param ReadBfrPtr is pointer to the read buffer to which valid received data + * should be written + * + * @return XST_SUCCESS if successful, else XST_FAILURE. + * + * @note None. + * + ******************************************************************************/ +static int MultiDieReadEcc( + XQspiPsu *QspiPsuPtr, + u32 Address, + u32 ByteCount, + u8 *WriteBfrPtr, + u8 *ReadBuffer +) +{ + u32 RealAddr; + u32 DiscardByteCnt; + u32 FlashMsgCnt; + int Status; + u32 cur_bank = 0; + u32 nxt_bank = 0; + u32 bank_size; + u32 remain_len = ByteCount; + u32 data_len; + u32 transfer_len; + + /* + * Some flash devices like N25Q512 have multiple dies + * in it. Read operation in these devices is bounded + * by its die segment. In a continuous read, across + * multiple dies, when the last byte of the selected + * die segment is read, the next byte read is the + * first byte of the same die segment. This is Die + * cross over issue. So to handle this issue, split + * a read transaction, that spans across multiple + * banks, into one read per bank. Bank size is 16MB + * for single and dual stacked mode and 32MB for dual + * parallel mode. + */ + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) + bank_size = SIXTEENMB << 1; + else + bank_size = SIXTEENMB; + + while (remain_len) { + cur_bank = Address / bank_size; + nxt_bank = (Address + remain_len) / bank_size; + + if (cur_bank != nxt_bank) { + transfer_len = (bank_size * (cur_bank + 1)) - Address; + if (remain_len < transfer_len) + data_len = remain_len; + else + data_len = transfer_len; + } else { + data_len = remain_len; + } + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + WriteBfrPtr[COMMAND_OFFSET] = READ_ECCSR; + WriteBfrPtr[ADDRESS_1_OFFSET] = + (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = + (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = + (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = + (u8)(RealAddr & 0xF0); + DiscardByteCnt = 5; + + FlashMsgCnt = 0; + + FlashMsg[FlashMsgCnt].TxBfrPtr = WriteBfrPtr; + FlashMsg[FlashMsgCnt].RxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt; + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX; + + FlashMsgCnt++; + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS; + FlashMsg[FlashMsgCnt].Flags = 0; + + FlashMsgCnt++; + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer; + FlashMsg[FlashMsgCnt].ByteCount = data_len; + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX; + + if (QspiPsuPtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_PARALLEL) + FlashMsg[FlashMsgCnt].Flags |= + XQSPIPSU_MSG_FLAG_STRIPE; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, + FlashMsgCnt + 1); + if (Status != XST_SUCCESS) + return XST_FAILURE; + + while (TransferInProgress); + + ReadBuffer += data_len; + Address += data_len; + remain_len -= data_len; + } + return 0; +} + +u32 QspiPsu_NOR_Get_Sector_Size(XQspiPsu *QspiPsuPtr) +{ + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) { + return Flash_Config_Table[FCTIndex].SectSize * 2; + } + return Flash_Config_Table[FCTIndex].SectSize; +} + +u32 QspiPsu_NOR_Get_Device_Size(XQspiPsu *QspiPsuPtr) +{ + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED + || QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) { + return Flash_Config_Table[FCTIndex].FlashDeviceSize * 2; + } + return Flash_Config_Table[FCTIndex].FlashDeviceSize; +} diff --git a/bsps/shared/dev/spi/xqspipsu.c b/bsps/shared/dev/spi/xqspipsu.c new file mode 100644 index 0000000000..93d3fa4c98 --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu.c @@ -0,0 +1,1086 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu.c + * @addtogroup Overview + * @{ + * + * This file implements the functions required to use the QSPIPSU hardware to + * perform a transfer. These are accessible to the user via xqspipsu.h. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- ----------------------------------------------- + * 1.0 hk 08/21/14 First release + * sk 03/13/15 Added IO mode support. + * hk 03/18/15 Switch to I/O mode before clearing RX FIFO. + * Clear and disable DMA interrupts/status in abort. + * Use DMA DONE bit instead of BUSY as recommended. + * sk 04/24/15 Modified the code according to MISRAC-2012. + * sk 06/17/15 Removed NULL checks for Rx/Tx buffers. As + * writing/reading from 0x0 location is permitted. + * 1.1 sk 04/12/16 Added debug message prints. + * 1.2 nsk 07/01/16 Changed XQspiPsu_Select to support GQSPI and LQSPI + * selection. + * rk 07/15/16 Added support for TapDelays at different frequencies. + * nsk 08/05/16 Added example support PollData and PollTimeout + * 1.3 nsk 09/16/16 Update PollData and PollTimeout support for dual + * parallel configurations, modified XQspiPsu_PollData() + * and XQspiPsu_Create_PollConfigData() + * 1,5 nsk 08/14/17 Added CCI support + * 1.7 tjs 01/16/18 Removed the check for DMA MSB to be written. (CR#992560) + * 1.7 tjs 01/17/18 Added a support to toggle WP pin of the flash. + * 1.7 tjs 03/14/18 Added support in EL1 NS mode (CR#974882) + * 1.8 tjs 06/26/18 Added an example for accessing 64bit dma within + * 32 bit application. CR#1004701 + * 1.8 tjs 06/26/18 Removed checkpatch warnings. + * 1.8 tjs 07/09/18 Fixed cppcheck and doxygen warnings. (CR#1006336) + * 1.8 tjs 07/18/18 Setup64BRxDma() should be called only if the RxAddress is + * greater than 32 bit address space. (CR#1006862) + * 1.8 tjs 09/06/18 Fixed the code in XQspiPsu_GenFifoEntryData() for data + * transfer length up to 255 for reducing the extra loop. + * 1.8 mus 11/05/18 Support 64 bit DMA addresses for Microblaze-X platform. + * 1.9 tjs 11/22/17 Added the check for A72 and R5 processors (CR-987075) + * 1.9 tjs 04/17/18 Updated register addresses as per the latest revision + * of versal (CR#999610) + * 1.9 aru 01/17/19 Fixes violations according to MISRAC-2012 + * in safety mode and modified the code such as + * Added UNITPTR inplace of INTPTR,Declared the pointer param + * as Pointer to const . + * 1.9 nsk 02/01/19 Clear DMA_DST_ADDR_MSB register on 32bit machine, if the + * address is of only 32bit (CR#1020031) + * 1.9 nsk 02/01/19 Added QSPI idling support. + * 1.9 rama 03/13/19 Fixed MISRA violations related to UR data anamoly, + * expression is not a boolean + * 1.9 nsk 03/27/19 Update 64bit dma support + * 1.10 sk 08/20/19 Fixed issues in poll timeout feature. + * 1.11 akm 02/19/20 Added XQspiPsu_StartDmaTransfer() and XQspiPsu_CheckDmaDone() + * APIs for non-blocking transfer. + * 1.11 sd 01/02/20 Added clocking support + * 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and + * interrupts in XQspiPsu_CfgInitialize() API. + * 1.11 akm 03/26/20 Fixed issue by updating XQspiPsu_CfgInitialize to return + * XST_DEVICE_IS_STARTED instead of asserting, when the + * instance is already configured. + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.14 akm 06/24/21 Allow enough time for the controller to reset the FIFOs. + * 1.14 akm 08/12/21 Perform Dcache invalidate at the end of the DMA transfer. + * 1.15 akm 10/21/21 Fix MISRA-C violations. + * + * </pre> + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" +#include "xqspipsu_control.h" +#include "sleep.h" +#ifdef __rtems__ +#include <rtems/rtems/cache.h> +#endif + +/************************** Constant Definitions *****************************/ +#define MAX_DELAY_CNT 10000000U /**< Max delay count */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** + * + * Initializes a specific XQspiPsu instance as such the driver is ready to use. + * + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param ConfigPtr is a reference to a structure containing information + * about a specific QSPIPSU device. This function initializes an + * InstancePtr object for a specific device specified by the + * contents of Config. + * @param EffectiveAddr is the device base address in the virtual memory + * address space. The caller is responsible for keeping the address + * mapping from EffectiveAddr to the device physical base address + * unchanged once this function is invoked. Unexpected errors may + * occur if the address mapping changes after this function is + * called. If address translation is not used, use + * ConfigPtr->Config.BaseAddress for this device. + * + * @return + * - XST_SUCCESS if successful. + * - XST_DEVICE_IS_STARTED if the device is already started. + * It must be stopped to re-initialize. + * + * @note None. + * + ******************************************************************************/ +s32 XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, + const XQspiPsu_Config *ConfigPtr, + UINTPTR EffectiveAddr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + s32 Status; + + /* + * If the device is busy, disallow the initialize and return a status + * indicating it is already started. This allows the user to stop the + * device and re-initialize, but prevents a user from inadvertently + * initializing. This assumes the busy flag is cleared at startup. + */ + if ((InstancePtr->IsBusy == (u32)TRUE) || + (InstancePtr->IsReady == XIL_COMPONENT_IS_READY)) { + Status = (s32)XST_DEVICE_IS_STARTED; + } else { + /* Set some default values. */ + InstancePtr->IsBusy = (u32)FALSE; + InstancePtr->Config.BaseAddress = + EffectiveAddr + XQSPIPSU_OFFSET; + InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode; + InstancePtr->StatusHandler = StubStatusHandler; + InstancePtr->Config.BusWidth = ConfigPtr->BusWidth; + InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz; +#if defined (XCLOCKING) + InstancePtr->Config.RefClk = ConfigPtr->RefClk; +#endif + InstancePtr->Config.IsCacheCoherent = + ConfigPtr->IsCacheCoherent; + /* Other instance variable initializations */ + InstancePtr->SendBufferPtr = NULL; + InstancePtr->RecvBufferPtr = NULL; + InstancePtr->GenFifoBufferPtr = NULL; + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->GenFifoEntries = 0; + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + InstancePtr->IsUnaligned = 0; + InstancePtr->IsManualstart = (u8)TRUE; + + /* Select QSPIPSU */ + XQspiPsu_Select(InstancePtr, XQSPIPSU_SEL_GQSPI_MASK); + /* + * Reset the QSPIPSU device to get it into its initial state. + * It is expected that device configuration will take place + * after this initialization is done, but before the device + * is started. + */ + XQspiPsu_Reset(InstancePtr); + /* Enable */ + XQspiPsu_Enable(InstancePtr); + + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + Status = (s32)XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** + * + * Stops the transfer of data to internal DST FIFO from stream interface and + * also stops the issuing of new write commands to memory. + * + * By calling this API, any ongoing Dma transfers will be paused and DMA will + * not issue AXI write commands to memory + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Idle(const XQspiPsu *InstancePtr) +{ + u32 RegEn; + u32 DmaStatus; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Check for QSPI enable */ + RegEn = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_EN_OFFSET); + if ((RegEn & XQSPIPSU_EN_MASK) != 0U) { + DmaStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET); + DmaStatus |= XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_MASK; + DmaStatus |= XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_MASK; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET, DmaStatus); + } +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif +} + +/*****************************************************************************/ +/** + * + * Resets the QSPIPSU device. Reset must only be called after the driver has + * been initialized. Any data transfer that is in progress is aborted. + * + * The upper layer software is responsible for re-configuring (if necessary) + * and restarting the QSPIPSU device after the reset. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Reset(XQspiPsu *InstancePtr) +{ + Xil_AssertVoid(InstancePtr != NULL); +#ifdef DEBUG + xil_printf("\nXQspiPsu_Reset\r\n"); +#endif + + /* Abort any transfer that is in progress */ + XQspiPsu_Abort(InstancePtr); + + /* Default value to config register */ + XQspiPsu_SetDefaultConfig(InstancePtr); + +} + +/*****************************************************************************/ +/** + * + * Aborts a transfer in progress. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Abort(XQspiPsu *InstancePtr) +{ + u32 IntrStatus, ConfigReg, FifoStatus; + u32 DelayCount = 0U; + +#ifdef __rtems__ + u32 FifoStatusMask = XQSPIPSU_ISR_RXEMPTY_MASK; + FifoStatusMask |= XQSPIPSU_ISR_TXEMPTY_MASK; + FifoStatusMask |= XQSPIPSU_ISR_GENFIFOEMPTY_MASK; +#endif + + Xil_AssertVoid(InstancePtr != NULL); +#ifdef DEBUG + xil_printf("\nXQspiPsu_Abort\r\n"); +#endif + IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET); + + /* Clear and disable interrupts */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET, IntrStatus | XQSPIPSU_ISR_WR_TO_CLR_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET)); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_STS_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_STS_OFFSET) | + XQSPIPSU_QSPIDMA_DST_STS_WTC); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET, + XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK); + + /* + * Clear GEN FIFO, TX FIFO & RX FIFO. Switch to IO mode to Clear + * RX FIFO. This is because of DMA behaviour where it waits on + * RX empty and goes busy assuming there is data to be transferred + * even if there is no request. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_FIFO_CTRL_OFFSET, + XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK | + XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK | + XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK); + /* + * QSPI Controller takes few clock cycles to update the RX_FIFO_Empty, + * TX_FIFO_Empty and GEN_FIFO_Empty status bit. Checking the GQSPI FIFO + * Control register bits gives enough time for the QSPI controller to + * update the status bit. The opeartion timesout, if the status bit are + * not updated after 10secs. + */ + + FifoStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, +#ifdef __rtems__ + XQSPIPSU_ISR_OFFSET) & FifoStatusMask; + while(FifoStatus != FifoStatusMask) { +#else + XQSPIPSU_FIFO_CTRL_OFFSET); + while(FifoStatus != 0U) { +#endif + if (DelayCount == MAX_DELAY_CNT) { +#ifdef DEBUG + xil_printf("Timeout error, FIFO reset failed.\r\n"); +#endif + } else { + /* Wait for 1 usec */ + usleep(1); + DelayCount++; + FifoStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, +#ifdef __rtems__ + XQSPIPSU_ISR_OFFSET) & FifoStatusMask; +#else + XQSPIPSU_FIFO_CTRL_OFFSET); +#endif + } + } + + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + } + + + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->GenFifoEntries = 0; + InstancePtr->IsBusy = (u32)FALSE; +} + +/*****************************************************************************/ +/** + * This is the handler for polling functionality of controller. It reads data + * from RXFIFO, since when data from the flash device (status data) matched + * with configured value in poll_cfg, then controller writes the matched data + * into RXFIFO. + * + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param StatusReg is the Interrupt status Register value. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_PollDataHandler(XQspiPsu *InstancePtr, u32 StatusReg) +{ + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_PollDataHandler\r\n"); +#endif + + if ((StatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != (u32)FALSE) { + /* + * Read data from RXFIFO, since when data from the + * flash device (status data) matched with configured + * value in poll_cfg, then controller writes the + * matched data into RXFIFO. + */ + (void)XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RXD_OFFSET); + + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_POLL_DONE, 0); + } + if ((StatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK) != (u32)FALSE) { + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_FLASH_TIMEOUT_ERROR, 0); + } + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET, + (u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK); + InstancePtr->IsBusy = (u32)FALSE; + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + XQspiPsu_SetReadMode(InstancePtr, XQSPIPSU_READMODE_DMA); + } + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + XQspiPsu_ManualStartEnable(InstancePtr); +} + +/*****************************************************************************/ +/** + * + * This function performs a transfer on the bus in polled mode. The messages + * passed are all transferred on the bus between one CS assert and de-assert. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param NumMsg is the number of messages to be transferred. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg) +{ + s32 Index; + u32 QspiPsuStatusReg; + u32 IOPending = (u32)FALSE; + u32 DmaIntrSts; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Msg != NULL); + Xil_AssertNonvoid(NumMsg > 0U); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (Index = 0; Index < (s32)NumMsg; Index++) { + Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); +#ifdef __rtems__ + if (Msg[Index].TxBfrPtr != NULL) { + rtems_cache_flush_multiple_data_lines(Msg[Index].TxBfrPtr, Msg[Index].ByteCount); + } +#endif + } +#ifdef __rtems__ + rtems_cache_flush_multiple_data_lines(Msg, NumMsg * sizeof(*Msg)); +#endif + + /* + * Check whether there is another transfer in progress. + * Not thread-safe + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + goto END; + } + /* Check for ByteCount upper limit - 2^28 for DMA */ + for (Index = 0; Index < (s32)NumMsg; Index++) { + if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + Status = (s32)XST_FAILURE; + goto END; + } + } + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = (u32)TRUE; + +#if defined (XCLOCKING) + Xil_ClockEnable(InstancePtr->Config.RefClk); +#endif + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + /* list */ + Index = 0; + while (Index < (s32)NumMsg) { + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[Index]); + XQspiPsu_ManualStartEnable(InstancePtr); + /* Use thresholds here */ + /* If there is more data to be transmitted */ + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET); + /* Transmit more data if left */ + if (((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != (u32)FALSE) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + (InstancePtr->TxBytes > 0)) { + XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index], + (u32)XQSPIPSU_TXD_DEPTH); + } + + if ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE) { + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + /* Check if DMA RX is complete and update RxBytes */ + DmaIntrSts = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + if ((DmaIntrSts & + XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts); + /* DMA transfer done, Invalidate Data Cache */ + if (!((Msg[Index].RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (Msg[Index].Xfer64bit != (u8)0U)) && + (InstancePtr->Config.IsCacheCoherent == 0U)) { + Xil_DCacheInvalidateRange((INTPTR)Msg[Index].RxBfrPtr, + (INTPTR)Msg[Index].ByteCount); + } + IOPending = XQspiPsu_SetIOMode(InstancePtr, &Msg[Index]); + InstancePtr->RxBytes = 0; + if (IOPending == (u32)TRUE) { + break; + } + } + } else { + XQspiPsu_IORead(InstancePtr, &Msg[Index], QspiPsuStatusReg); + } + } + } while (((QspiPsuStatusReg & + XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE) || + (InstancePtr->TxBytes != 0) || + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == (u32)FALSE) || + (InstancePtr->RxBytes != 0)); + + if ((InstancePtr->IsUnaligned != 0) && (IOPending == (u32)FALSE)) { + InstancePtr->IsUnaligned = 0; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + (XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_MODE_EN_DMA_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + } + if (IOPending == (u32)TRUE) { + IOPending = (u32)FALSE; + } else { + Index++; + } + } + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + XQspiPsu_ManualStartEnable(InstancePtr); + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + } while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE); + + /* Clear the busy flag. */ + InstancePtr->IsBusy = (u32)FALSE; + + Status = (s32)XST_SUCCESS; + +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif + END: + return Status; +} + +/*****************************************************************************/ +/** + * + * This function initiates a transfer on the bus and enables interrupts. + * The transfer is completed by the interrupt handler. The messages passed are + * all transferred on the bus between one CS assert and de-assert. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param NumMsg is the number of messages to be transferred. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg) +{ + s32 Index; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (Index = 0; Index < (s32)NumMsg; Index++) +#ifdef __rtems__ + { +#endif + Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); +#ifdef __rtems__ + if (Msg[Index].TxBfrPtr != NULL) { + rtems_cache_flush_multiple_data_lines(Msg[Index].TxBfrPtr, Msg[Index].ByteCount); + } + } + rtems_cache_flush_multiple_data_lines(Msg, NumMsg * sizeof(*Msg)); +#endif + + /* + * Check whether there is another transfer in progress. + * Not thread-safe + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + goto END; + } +#if defined (XCLOCKING) + Xil_ClockEnable(InstancePtr->Config.RefClk); +#endif + + if ((Msg[0].Flags & XQSPIPSU_MSG_FLAG_POLL) != (u32)FALSE) { + InstancePtr->IsBusy = (u32)TRUE; + XQspiPsu_PollDataConfig(InstancePtr, Msg); + } else { + /* Check for ByteCount upper limit - 2^28 for DMA */ + for (Index = 0; Index < (s32)NumMsg; Index++) { + if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + Status = (s32)XST_FAILURE; + goto END; + } + } + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = (u32)TRUE; + + InstancePtr->Msg = Msg; + InstancePtr->NumMsg = (s32)NumMsg; + InstancePtr->MsgCnt = 0; + + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + /* This might not work if not manual start */ + /* Put first message in FIFO along with the above slave select */ + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[0]); + XQspiPsu_ManualStartEnable(InstancePtr); + + /* Enable interrupts */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET, + (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | + (u32)XQSPIPSU_IER_TXEMPTY_MASK | + (u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK | + (u32)XQSPIPSU_IER_RXEMPTY_MASK); + + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET, + XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); + } + } + Status = (s32)XST_SUCCESS; + + END: + return Status; +} + +/*****************************************************************************/ +/** + * + * Handles interrupt based transfers by acting on GENFIFO and DMA interurpts. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * + * @note None. + * + ******************************************************************************/ +s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr) +{ + u32 QspiPsuStatusReg, DmaIntrStatusReg = 0; + XQspiPsu_Msg *Msg; + s32 NumMsg; + s32 MsgCnt; + u8 DeltaMsgCnt = 0; + u32 TxRxFlag; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(InstancePtr->NumMsg > 0); + Xil_AssertNonvoid(InstancePtr->Msg != NULL); + + Msg = InstancePtr->Msg; + NumMsg = InstancePtr->NumMsg; + MsgCnt = InstancePtr->MsgCnt; + TxRxFlag = Msg[MsgCnt].Flags; + + /* QSPIPSU Intr cleared on read */ + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + /* DMA Intr write to clear */ + DmaIntrStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, + DmaIntrStatusReg); + } + if (((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK) != (u32)FALSE)) { + /* Call status handler to indicate error */ + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_COMMAND_ERROR, 0); + } + /* Fill more data to be txed if required */ + if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != (u32)FALSE) && + (InstancePtr->TxBytes > 0)) { + XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt], (u32)XQSPIPSU_TXD_DEPTH); + } + /* + * Check if the entry is ONLY TX and increase MsgCnt. + * This is to allow TX and RX together in one entry - corner case. + */ + if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) != (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE) && + (InstancePtr->TxBytes == 0) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) { + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + + if ((MsgCnt < NumMsg) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + if ((DmaIntrStatusReg & + XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) { + /* DMA transfer done, Invalidate Data Cache */ + if (!((Msg[MsgCnt].RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (Msg[MsgCnt].Xfer64bit != (u8)0U)) && + (InstancePtr->Config.IsCacheCoherent == 0U)) { + Xil_DCacheInvalidateRange((INTPTR)Msg[MsgCnt].RxBfrPtr, (INTPTR)Msg[MsgCnt].ByteCount); + } + if (XQspiPsu_SetIOMode(InstancePtr, &Msg[MsgCnt]) == (u32)TRUE) { + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[MsgCnt]); + XQspiPsu_ManualStartEnable(InstancePtr); + } else { + InstancePtr->RxBytes = 0; + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + } + } else { + if (InstancePtr->RxBytes != 0) { + XQspiPsu_IORead(InstancePtr, &Msg[MsgCnt], QspiPsuStatusReg); + if (InstancePtr->RxBytes == 0) { + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + } + } + } + + /* + * Dummy byte transfer + * MsgCnt < NumMsg check is to ensure is it a valid dummy cycle message + * If one of the above conditions increased MsgCnt, then + * the new message is yet to be placed in the FIFO; hence !DeltaMsgCnt. + */ + if ((MsgCnt < NumMsg) && (DeltaMsgCnt == (u8)FALSE) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) == (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE)) { + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + InstancePtr->MsgCnt = MsgCnt; + /* + * DeltaMsgCnt is to handle conditions where genfifo empty can be set + * while tx is still not empty or rx dma is not yet done. + * MsgCnt > NumMsg indicates CS de-assert entry was also executed. + */ + if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE) && + ((DeltaMsgCnt != (u8)FALSE) || (MsgCnt > NumMsg))) { + if (MsgCnt < NumMsg) { + if (InstancePtr->IsUnaligned != 0) { + InstancePtr->IsUnaligned = 0; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg( + InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_MODE_EN_DMA_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + } + /* This might not work if not manual start */ + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[MsgCnt]); + XQspiPsu_ManualStartEnable(InstancePtr); + } else if (MsgCnt == NumMsg) { + /* This is just to keep track of the de-assert entry */ + MsgCnt += 1; + InstancePtr->MsgCnt = MsgCnt; + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + XQspiPsu_ManualStartEnable(InstancePtr); + } else { + /* Disable interrupts */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET, + (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | + (u32)XQSPIPSU_IER_TXEMPTY_MASK | + (u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK | + (u32)XQSPIPSU_IER_RXEMPTY_MASK); + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET, + XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); + } + /* Clear the busy flag. */ + InstancePtr->IsBusy = (u32)FALSE; +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif + /* Call status handler to indicate completion */ + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_TRANSFER_DONE, 0); + } + } + if ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) != (u32)FALSE) { + XQspiPsu_PollDataHandler(InstancePtr, QspiPsuStatusReg); + } + return (s32)XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * + * Sets the status callback function, the status handler, which the driver + * calls when it encounters conditions that should be reported to upper + * layer software. The handler executes in an interrupt context, so it must + * minimize the amount of processing performed. One of the following status + * events is passed to the status handler. + * + * <pre> + * + * XST_SPI_TRANSFER_DONE The requested data transfer is done + * + * XST_SPI_TRANSMIT_UNDERRUN As a slave device, the master clocked data + * but there were none available in the transmit + * register/FIFO. This typically means the slave + * application did not issue a transfer request + * fast enough, or the processor/driver could not + * fill the transmit register/FIFO fast enough. + * + * XST_SPI_RECEIVE_OVERRUN The QSPIPSU device lost data. Data was received + * but the receive data register/FIFO was full. + * + * </pre> + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param CallBackRef is the upper layer callback reference passed back + * when the callback function is invoked. + * @param FuncPointer is the pointer to the callback function. + * + * @return None. + * + * @note + * + * The handler is called within interrupt context, so it should do its work + * quickly and queue potentially time-consuming work to a task-level thread. + * + ******************************************************************************/ +void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef, + XQspiPsu_StatusHandler FuncPointer) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPointer != NULL); + Xil_AssertVoid(CallBackRef != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->StatusHandler = FuncPointer; + InstancePtr->StatusRef = CallBackRef; +} + +/*****************************************************************************/ +/** + * @brief + * This API enables/ disables Write Protect pin on the flash parts. + * + * @param InstancePtr is a pointer to the QSPIPSU driver component to use. + * + * @param Toggle is a value of the GPIO pin + * + * @return None + * + * @note By default WP pin as per the QSPI controller is driven High + * which means no write protection. Calling this function once + * will enable the protection. + * + ******************************************************************************/ +void XQspiPsu_WriteProtectToggle(const XQspiPsu *InstancePtr, u32 Toggle) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + /* For Single and Stacked flash configuration with x1 or x2 mode*/ + if (InstancePtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_SINGLE) { + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GPIO_OFFSET, Toggle); + + } else { +#ifdef DEBUG + xil_printf("Dual Parallel/Stacked configuration "); + xil_printf("is not supported by this API\r\n"); +#endif + } +} + +/*****************************************************************************/ +/** +* +* This function start a DMA transfer. +* + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param NumMsg is the number of messages to be transferred. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if ByteCount is greater than + * XQSPIPSU_DMA_BYTES_MAX. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * +* +******************************************************************************/ +s32 XQspiPsu_StartDmaTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg) +{ + s32 Index; + u32 QspiPsuStatusReg = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Msg != NULL); + Xil_AssertNonvoid(NumMsg > 0U); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + for (Index = 0; Index < (s32)NumMsg; Index++) { + Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); + } + + /* + * Check whether there is another transfer in progress. + * Not thread-safe + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + return (s32)XST_DEVICE_BUSY; + } + + /* Check for ByteCount upper limit - 2^28 for DMA */ + for (Index = 0; Index < (s32)NumMsg; Index++) { + if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + return (s32)XST_FAILURE; + } + } + + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = (u32)TRUE; + + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + /* list */ + Index = 0; + while (Index < (s32)NumMsg) { + InstancePtr->Msg = &Msg[Index]; + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[Index]); + if (InstancePtr->IsManualstart == (u32)TRUE) { +#ifdef DEBUG + xil_printf("\nManual Start\r\n"); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + do { + if((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + break; + } + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + + } while (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE) || + (InstancePtr->TxBytes != 0) || + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == (u32)FALSE)); + + if(InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg( + InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_MODE_EN_DMA_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + } + Index++; + } + return (s32)XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function check for DMA transfer complete. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return +* - XST_SUCCESS if DMA transfer complete. +* - XST_FAILURE if DMA transfer is not completed. +* +* @note None. +* +******************************************************************************/ +s32 XQspiPsu_CheckDmaDone(XQspiPsu *InstancePtr) +{ + u32 QspiPsuStatusReg; + u32 DmaIntrSts; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + DmaIntrSts = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + if ((DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts); + /* DMA transfer done, Invalidate Data Cache */ + if (!((InstancePtr->Msg->RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (InstancePtr->Msg->Xfer64bit != (u8)0U)) && + (InstancePtr->Config.IsCacheCoherent == 0U)) { + Xil_DCacheInvalidateRange((INTPTR)InstancePtr->Msg->RxBfrPtr, (INTPTR)InstancePtr->RxBytes); + } + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + if (InstancePtr->IsManualstart == (u8)TRUE) { +#ifdef DEBUG + xil_printf("\nManual Start\r\n"); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + } while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE); + + /* Clear the busy flag. */ + InstancePtr->IsBusy = (u32)FALSE; + + return (s32)XST_SUCCESS; + } + else { + return (s32)XST_FAILURE; + } + +} +/** @} */ diff --git a/bsps/shared/dev/spi/xqspipsu_control.c b/bsps/shared/dev/spi/xqspipsu_control.c new file mode 100644 index 0000000000..af2400bf4c --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_control.c @@ -0,0 +1,282 @@ +/****************************************************************************** +* Copyright (C) 2020 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu_control.c + * @addtogroup Overview + * @{ + * + * This file contains intermediate control functions used by functions + * in xqspipsu.c and xqspipsu_options.c files. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- ----------------------------------------------- + * 1.11 akm 03/09/20 First release + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.15 akm 10/21/21 Fix MISRA-C violations. + * 1.15 akm 03/03/22 Enable tapdelay settings for applications on + * Microblaze platform. + * </pre> + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu_control.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ + +/*****************************************************************************/ +/** + * + * This function writes the GENFIFO entries to transmit the messages requested. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + u32 GenFifoEntry; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_GenFifoEntryData\r\n"); +#endif + + GenFifoEntry = 0x0U; + /* Bus width */ + GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_MODE_MASK; + GenFifoEntry |= XQspiPsu_SelectSpiMode((u8)Msg->BusWidth); + + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_BUS_MASK; + GenFifoEntry |= InstancePtr->GenFifoBus; + + /* Data */ + if (((Msg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != (u32)FALSE) { + GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE; + } else { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE; + } + /* If Byte Count is less than 8 bytes do the transfer in IO mode */ + if ((Msg->ByteCount < 8U) && + (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA)) { + InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + (XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) & + ~XQSPIPSU_CFG_MODE_EN_MASK)); + InstancePtr->IsUnaligned = 1; + } + + XQspiPsu_TXRXSetup(InstancePtr, Msg, &GenFifoEntry); + + XQspiPsu_GenFifoEntryDataLen(InstancePtr, Msg, &GenFifoEntry); + + /* One dummy GenFifo entry in case of IO mode */ + if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + GenFifoEntry = 0x0U; +#ifdef DEBUG + xil_printf("\nDummy FifoEntry=%08x\r\n", GenFifoEntry); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); + } +} + +/*****************************************************************************/ +/** + * + * This function enables the polling functionality of controller + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * + * @param FlashMsg is a pointer to the structure containing transfer data + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_PollDataConfig(XQspiPsu *InstancePtr, XQspiPsu_Msg *FlashMsg) +{ + + u32 GenFifoEntry; + u32 Value; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FlashMsg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_PollDataConfig\r\n"); +#endif + + Value = XQspiPsu_CreatePollDataConfig(InstancePtr, FlashMsg); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_POLL_CFG_OFFSET, Value); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_P_TO_OFFSET, FlashMsg->PollTimeout); + + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + GenFifoEntry = (u32)0; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_TX; + GenFifoEntry |= InstancePtr->GenFifoBus; + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI; + GenFifoEntry |= (u32)FlashMsg->PollStatusCmd; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); + + GenFifoEntry = (u32)0; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_POLL; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_RX; + GenFifoEntry |= InstancePtr->GenFifoBus; + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI; + if (((FlashMsg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != (u32)FALSE) { + GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE; + } else { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE; + } + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + GenFifoEntry); + + /* One Dummy entry required for IO mode */ + GenFifoEntry = 0x0U; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + GenFifoEntry); + + InstancePtr->Msg = FlashMsg; + InstancePtr->NumMsg = (s32)1; + InstancePtr->MsgCnt = 0; + + Value = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + Value &= ~XQSPIPSU_CFG_MODE_EN_MASK; + Value |= (XQSPIPSU_CFG_START_GEN_FIFO_MASK | + XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK | + XQSPIPSU_CFG_EN_POLL_TO_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + Value); + + /* Enable interrupts */ + Value = ((u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK); + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET, + Value); + +} + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) +/*****************************************************************************/ +/** +* +* Configures the clock according to the prescaler passed. +* +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Prescaler - clock prescaler. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting Tapdelay. +* +* @note None. +* +******************************************************************************/ +s32 XQspipsu_Calculate_Tapdelay(const XQspiPsu *InstancePtr, u8 Prescaler) +{ + u32 FreqDiv, Divider; + u32 Tapdelay = 0; + u32 LBkModeReg = 0; + u32 delayReg = 0; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM); + + /* + * Do not allow the slave select to change while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + goto END; + } else { + + Divider = (u32)1U << (Prescaler+1U); + + FreqDiv = (InstancePtr->Config.InputClockHz)/Divider; + +#if defined (versal) + if (FreqDiv <= XQSPIPSU_FREQ_37_5MHZ) { +#else + if (FreqDiv <= XQSPIPSU_FREQ_40MHZ) { +#endif + Tapdelay |= (TAPDLY_BYPASS_VALVE_40MHZ << + IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT); + } else if (FreqDiv <= XQSPIPSU_FREQ_100MHZ) { + Tapdelay |= (TAPDLY_BYPASS_VALVE_100MHZ << + IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT); + LBkModeReg |= (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT); +#if defined (versal) + delayReg |= (u32)USE_DATA_DLY_ADJ << + XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT; +#else + delayReg |= ((u32)USE_DATA_DLY_ADJ << + XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT) | + ((u32)DATA_DLY_ADJ_DLY << XQSPIPSU_DATA_DLY_ADJ_DLY_SHIFT); +#endif + } else if (FreqDiv <= XQSPIPSU_FREQ_150MHZ) { +#if defined (versal) + LBkModeReg |= (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT) | + (LPBK_DLY_ADJ_DLY1 << XQSPIPSU_LPBK_DLY_ADJ_DLY1_SHIFT); +#else + LBkModeReg |= USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT; +#endif + } else { + Status = (s32)XST_FAILURE; + goto END; + } + + Status = XQspipsu_Set_TapDelay(InstancePtr, Tapdelay, LBkModeReg, delayReg); + } + + END: + return Status; +} +#endif +/** @} */ diff --git a/bsps/shared/dev/spi/xqspipsu_hw.c b/bsps/shared/dev/spi/xqspipsu_hw.c new file mode 100644 index 0000000000..6f7708893f --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_hw.c @@ -0,0 +1,768 @@ +/****************************************************************************** +* Copyright (C) 2020 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu_hw.c + * @addtogroup Overview + * @{ + * + * This file contains functions to reads RXFifo, writes TXFifo and setup + * RX DMA operation, used by xqspipsu_control.c and xqspipsu_lowlevel.c files. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- ----------------------------------------------- + * 1.11 akm 03/09/20 First release + * mn 03/30/20 Add xil_smc.h include for Xil_Smc calls + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.15 akm 10/21/21 Fix MISRA-C violations. + * 1.15 akm 11/16/21 Typecast function parameter with appropriate + * data type. + * 1.15 akm 11/30/21 Fix compilation warnings reported with -Wundef flag + * 1.15 akm 03/03/22 Enable tapdelay settings for applications on + * Microblaze platform. + * + * </pre> + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" +#include "xqspipsu_control.h" +#if defined (__aarch64__) +#include "xil_smc.h" +#endif +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ + +/*****************************************************************************/ +/** + * + * Fills the TX FIFO as long as there is room in the FIFO or the bytes required + * to be transmitted. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param Size is the number of bytes to be transmitted. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 Size) +{ + u32 Count = 0; + u32 Data = 0U; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(Size != 0U); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_FillTxFifo\r\n"); +#endif + while ((InstancePtr->TxBytes > 0) && (Count < Size)) { + if (InstancePtr->TxBytes >= 4) { + (void)Xil_MemCpy((u8 *)&Data, Msg->TxBfrPtr, 4); + Msg->TxBfrPtr += 4; + InstancePtr->TxBytes -= 4; + Count += 4U; + } else { + (void)Xil_MemCpy((u8 *)&Data, Msg->TxBfrPtr, + (u32)InstancePtr->TxBytes); + Msg->TxBfrPtr += InstancePtr->TxBytes; + Count += (u32)InstancePtr->TxBytes; + InstancePtr->TxBytes = 0; + } + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_TXD_OFFSET, Data); +#ifdef DEBUG + xil_printf("\nData is %08x\r\n", Data); +#endif + + } + if (InstancePtr->TxBytes < 0) { + InstancePtr->TxBytes = 0; + } +} + +/*****************************************************************************/ +/** + * + * This function checks the TX buffer in the message and setup the + * TX FIFO as required. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_TXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_TXSetup\r\n"); +#endif + InstancePtr->TxBytes = (s32)Msg->ByteCount; + InstancePtr->SendBufferPtr = Msg->TxBfrPtr; + + XQspiPsu_FillTxFifo(InstancePtr, Msg, (u32)XQSPIPSU_TXD_DEPTH); +} + +/*****************************************************************************/ +/** + * + * This function sets up the RX DMA operation. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_SetupRxDma(const XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg) +{ + s32 Remainder; + s32 DmaRxBytes; + UINTPTR AddrTemp; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetupRxDma\r\n"); +#endif + + AddrTemp = ((UINTPTR)(Msg->RxBfrPtr) & XQSPIPSU_QSPIDMA_DST_ADDR_MASK); + /* Check for RXBfrPtr to be word aligned */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET, (u32)AddrTemp); + +#if defined(__aarch64__) || defined(__arch64__) + AddrTemp = ((UINTPTR)(Msg->RxBfrPtr) >> 32U); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, (u32)AddrTemp & + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK); +#else + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, 0U); +#endif + + Remainder = InstancePtr->RxBytes % 4; + DmaRxBytes = InstancePtr->RxBytes; + if (Remainder != 0) { + /* This is done to make Dma bytes aligned */ + DmaRxBytes = InstancePtr->RxBytes - Remainder; + Msg->ByteCount = (u32)DmaRxBytes; + } + if (InstancePtr->Config.IsCacheCoherent == 0U) { + Xil_DCacheInvalidateRange((INTPTR)Msg->RxBfrPtr, (INTPTR)Msg->ByteCount); + } + /* Write no. of words to DMA DST SIZE */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes); +} + +/*****************************************************************************/ +/** + * + * This function sets up the RX DMA operation on a 32bit Machine + * For 64bit Dma transfers. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Setup64BRxDma(const XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg) +{ + s32 Remainder; + s32 DmaRxBytes; + u64 AddrTemp; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_Setup64BRxDma\r\n"); +#endif + AddrTemp = Msg->RxAddr64bit & XQSPIPSU_QSPIDMA_DST_ADDR_MASK; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET, (u32)AddrTemp); + + AddrTemp = (Msg->RxAddr64bit >> 32); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, (u32)AddrTemp & + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK); + + Remainder = InstancePtr->RxBytes % 4; + DmaRxBytes = InstancePtr->RxBytes; + if (Remainder != 0) { + /* This is done to make Dma bytes aligned */ + DmaRxBytes = InstancePtr->RxBytes - Remainder; + Msg->ByteCount = (u32)DmaRxBytes; + } + + /* Write no. of words to DMA DST SIZE */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes); + +} + +/*****************************************************************************/ +/** + * + * This function reads remaining bytes, after the completion of a DMA transfer, + * using IO mode + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +u32 XQspiPsu_SetIOMode(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Msg != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_DMARXComplete\r\n"); +#endif + + /* Read remaining bytes using IO mode */ + if ((InstancePtr->RxBytes % 4) != 0) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + (XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) & + ~XQSPIPSU_CFG_MODE_EN_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; + Msg->ByteCount = (u32)InstancePtr->RxBytes % 4U; + Msg->RxBfrPtr += (InstancePtr->RxBytes - (InstancePtr->RxBytes % 4)); + InstancePtr->IsUnaligned = 1; + return (u32) TRUE; + } + return (u32) FALSE; +} + +/*****************************************************************************/ +/** + * + * This function checks the RX buffers in the message and setup the + * RX DMA as required. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_RXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_RXSetup\r\n"); +#endif + InstancePtr->RxBytes = (s32)Msg->ByteCount; + + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + if ((Msg->RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (Msg->Xfer64bit != (u8)0U)) { + XQspiPsu_Setup64BRxDma(InstancePtr, Msg); + } else { + XQspiPsu_SetupRxDma(InstancePtr, Msg); + } + } +} + +/*****************************************************************************/ +/** + * + * This function checks the TX/RX buffers in the message and setups up the + * GENFIFO entries, TX FIFO or RX DMA as required. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param GenFifoEntry is pointer to the variable in which GENFIFO mask + * is returned to calling function + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(GenFifoEntry != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_TXRXSetup\r\n"); +#endif + /* Transmit */ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) { + + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= XQSPIPSU_GENFIFO_TX; + /* Discard RX data */ + *GenFifoEntry &= ~XQSPIPSU_GENFIFO_RX; + + /* Setup data to be TXed */ + XQspiPsu_TXSetup(InstancePtr, Msg); + + InstancePtr->RecvBufferPtr = NULL; + InstancePtr->RxBytes = 0; + } + /*Receive*/ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE)) { + + /* TX auto fill */ + *GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX; + /* Setup RX */ + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= XQSPIPSU_GENFIFO_RX; + + /* Setup DMA for data to be RXed */ + XQspiPsu_RXSetup(InstancePtr, Msg); + + InstancePtr->SendBufferPtr = NULL; + InstancePtr->TxBytes = 0; + } + /* If only dummy is requested as a separate entry */ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) { + + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX); + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->SendBufferPtr = NULL; + InstancePtr->RecvBufferPtr = NULL; + } + /* Dummy and cmd sent by upper layer to received data */ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= (XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX); + + /* Setup data to be TXed */ + XQspiPsu_TXSetup(InstancePtr, Msg); + /* Setup DMA for data to be RXed */ + XQspiPsu_RXSetup(InstancePtr, Msg); + } +} +/*****************************************************************************/ +/** + * + * This function writes the Data length to GENFIFO entries that need to be + * transmitted or received. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param GenFifoEntry is index of the current message to be handled. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_GenFifoEntryDataLen(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry) +{ + u32 TempCount; + u32 ImmData; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(GenFifoEntry != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_GenFifoEntryDataLen\r\n"); +#endif + + if (Msg->ByteCount <= XQSPIPSU_GENFIFO_IMM_DATA_MASK) { + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK; + *GenFifoEntry |= Msg->ByteCount; + #ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", *GenFifoEntry); + #endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + *GenFifoEntry); + } else { + TempCount = Msg->ByteCount; + u32 Exponent = 8; /* 2^8 = 256 */ + ImmData = TempCount & 0xFFU; + /* Exponent entries */ + *GenFifoEntry |= XQSPIPSU_GENFIFO_EXP; + while (TempCount != 0U) { + if ((TempCount & XQSPIPSU_GENFIFO_EXP_START) != (u32)FALSE) { + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK; + *GenFifoEntry |= Exponent; + #ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", + *GenFifoEntry); + #endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + *GenFifoEntry); + } + TempCount = TempCount >> 1; + Exponent++; + } + /* Immediate entry */ + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_EXP; + if ((ImmData & 0xFFU) != (u32)FALSE) { + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK; + *GenFifoEntry |= ImmData & 0xFFU; + #ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", *GenFifoEntry); + #endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + *GenFifoEntry); + } + } +} + +/*****************************************************************************/ +/** + * + * This function creates Poll config register data to write + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @param FlashMsg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +u32 XQspiPsu_CreatePollDataConfig(const XQspiPsu *InstancePtr, + const XQspiPsu_Msg *FlashMsg) +{ + u32 ConfigData = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(FlashMsg != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_CreatePollDataConfig\r\n"); +#endif + + if ((InstancePtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_UPPER) != (u32)FALSE) { + ConfigData = (u32)XQSPIPSU_SELECT_FLASH_BUS_LOWER << + XQSPIPSU_POLL_CFG_EN_MASK_UPPER_SHIFT; + } + if ((InstancePtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_LOWER) != (u32)FALSE) { + ConfigData |= (u32)XQSPIPSU_SELECT_FLASH_BUS_LOWER << + XQSPIPSU_POLL_CFG_EN_MASK_LOWER_SHIFT; + } + ConfigData |= (u32)(((u32)FlashMsg->PollBusMask << + XQSPIPSU_POLL_CFG_MASK_EN_SHIFT) & XQSPIPSU_POLL_CFG_MASK_EN_MASK); + ConfigData |= (u32)(((u32)FlashMsg->PollData << + XQSPIPSU_POLL_CFG_DATA_VALUE_SHIFT) + & XQSPIPSU_POLL_CFG_DATA_VALUE_MASK); + return ConfigData; +} + +/*****************************************************************************/ +/** + * + * Selects SPI mode - x1 or x2 or x4. + * + * @param SpiMode - spi or dual or quad. + * @return Mask to set desired SPI mode in GENFIFO entry. + * + * @note None. + * + ******************************************************************************/ +u32 XQspiPsu_SelectSpiMode(u8 SpiMode) +{ + u32 Mask; + + Xil_AssertNonvoid(SpiMode > 0U); +#ifdef DEBUG + xil_printf("\nXQspiPsu_SelectSpiMode\r\n"); +#endif + + switch (SpiMode) { + case XQSPIPSU_SELECT_MODE_DUALSPI: + Mask = XQSPIPSU_GENFIFO_MODE_DUALSPI; + break; + case XQSPIPSU_SELECT_MODE_QUADSPI: + Mask = XQSPIPSU_GENFIFO_MODE_QUADSPI; + break; + case XQSPIPSU_SELECT_MODE_SPI: + Mask = XQSPIPSU_GENFIFO_MODE_SPI; + break; + default: + Mask = XQSPIPSU_GENFIFO_MODE_SPI; + break; + } +#ifdef DEBUG + xil_printf("\nSPIMode is %08x\r\n", SpiMode); +#endif + return Mask; +} + +/*****************************************************************************/ +/** + * + * Enable and initialize DMA Mode, set little endain, disable poll timeout, + * clear prescalar bits and reset thresholds + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_SetDefaultConfig(XQspiPsu *InstancePtr) +{ + u32 ConfigReg; + + Xil_AssertVoid(InstancePtr != NULL); +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetDefaultConfig\r\n"); +#endif + + /* Default value to config register */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* DMA mode */ + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + /* Manual start */ + ConfigReg |= XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK; + /* Little endain by default */ + ConfigReg &= ~XQSPIPSU_CFG_ENDIAN_MASK; + /* Disable poll timeout */ + ConfigReg &= ~XQSPIPSU_CFG_EN_POLL_TO_MASK; + /* Set hold bit */ + ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK; + /* Clear prescalar by default */ + ConfigReg &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + /* CPOL CPHA 00 */ + ConfigReg &= ~(u32)XQSPIPSU_CFG_CLK_PHA_MASK; + ConfigReg &= ~(u32)XQSPIPSU_CFG_CLK_POL_MASK; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + + /* Set by default to allow for high frequencies */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_LPBK_DLY_ADJ_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_LPBK_DLY_ADJ_OFFSET) | + XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK); + + /* Reset thresholds */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_TX_THRESHOLD_OFFSET, XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RX_THRESHOLD_OFFSET, XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GF_THRESHOLD_OFFSET, XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL); + + /* DMA init */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET, + XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL); +} + +/*****************************************************************************/ +/** + * + * Read the specified number of bytes from RX FIFO + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param Size is the number of bytes to be read. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, s32 Size) +{ + s32 Count = 0; + u32 Data; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(Size > 0); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_ReadRxFifo\r\n"); +#endif + while ((InstancePtr->RxBytes != 0) && (Count < Size)) { + Data = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RXD_OFFSET); +#ifdef DEBUG + xil_printf("\nData is %08x\r\n", Data); +#endif + if (InstancePtr->RxBytes >= 4) { + (void)Xil_MemCpy(Msg->RxBfrPtr, (u8 *)&Data, 4); + InstancePtr->RxBytes -= 4; + Msg->RxBfrPtr += 4; + Count += 4; + } else { + /* Read unaligned bytes (< 4 bytes) */ + (void)Xil_MemCpy(Msg->RxBfrPtr, (u8 *)&Data, + (u32)InstancePtr->RxBytes); + Msg->RxBfrPtr += InstancePtr->RxBytes; + Count += InstancePtr->RxBytes; + InstancePtr->RxBytes = 0; + } + } +} + +/*****************************************************************************/ +/** + * + * This function reads data from RXFifo in IO mode. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param StatusReg is the Interrupt status Register value. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_IORead(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 StatusReg) +{ + s32 RxThr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_IORXComplete\r\n"); +#endif + + if ((StatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != 0U) { + /* + * Check if PIO RX is complete and + * update RxBytes + */ + RxThr = (s32)XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RX_THRESHOLD_OFFSET); + RxThr = RxThr*4; + XQspiPsu_ReadRxFifo(InstancePtr, Msg, RxThr); + + return; + } + + if ((StatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) { + XQspiPsu_ReadRxFifo(InstancePtr, Msg, InstancePtr->RxBytes); + } +} + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) +/*****************************************************************************/ +/** +* +* This function sets the Tapdelay values for the QSPIPSU device driver.The device +* must be idle rather than busy transferring data before setting Tapdelay. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param TapdelayBypss contains the IOU_TAPDLY_BYPASS register value. +* @param LPBKDelay contains the GQSPI_LPBK_DLY_ADJ register value. +* @param Datadelay contains the QSPI_DATA_DLY_ADJ register value. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting TapDelay. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspipsu_Set_TapDelay(const XQspiPsu *InstancePtr, u32 TapdelayBypass, + u32 LPBKDelay, u32 Datadelay) +{ + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { +#if defined (__aarch64__) && (EL1_NONSECURE == 1) && !defined (versal) + Xil_Smc(MMIO_WRITE_SMC_FID, (u64)(XPS_SYS_CTRL_BASEADDR + + IOU_TAPDLY_BYPASS_OFFSET) | ((u64)(0x4) << 32), + (u64)TapdelayBypass, 0, 0, 0, 0, 0); +#elif defined (versal) + XQspiPsu_WriteReg(XQSPIPS_BASEADDR, IOU_TAPDLY_BYPASS_OFFSET, + TapdelayBypass); +#else + XQspiPsu_WriteReg(XPS_SYS_CTRL_BASEADDR, IOU_TAPDLY_BYPASS_OFFSET, + TapdelayBypass); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_LPBK_DLY_ADJ_OFFSET, LPBKDelay); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_DATA_DLY_ADJ_OFFSET, Datadelay); + + Status = (s32)XST_SUCCESS; + } + return Status; +} +#endif +/** @} */ diff --git a/bsps/shared/dev/spi/xqspipsu_options.c b/bsps/shared/dev/spi/xqspipsu_options.c new file mode 100644 index 0000000000..c889d64abb --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_options.c @@ -0,0 +1,532 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xqspipsu_options.c +* @addtogroup Overview +* @{ +* +* This file implements functions to configure the QSPIPSU component, +* specifically some optional settings, clock and flash related information. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.0 hk 08/21/14 First release +* sk 03/13/15 Added IO mode support. +* sk 04/24/15 Modified the code according to MISRAC-2012. +* 1.1 sk 04/12/16 Added debug message prints. +* 1.2 nsk 07/01/16 Modified XQspiPsu_SetOptions() to support +* LQSPI options and updated OptionsTable +* rk 07/15/16 Added support for TapDelays at different frequencies. +* 1.7 tjs 01/17/18 Added support to toggle the WP pin of flash. (PR#2448) +* 1.7 tjs 03/14/18 Added support in EL1 NS mode. (CR#974882) +* 1.8 tjs 05/02/18 Added support for IS25LP064 and IS25WP064. +* 1.8 tjs 07/26/18 Resolved cppcheck errors. (CR#1006336) +* 1.9 tjs 04/17/18 Updated register addresses as per the latest revision +* of versal (CR#999610) +* 1.9 aru 01/17/19 Fixes violations according to MISRAC-2012 +* in safety mode and modified the code such as +* Added Xil_MemCpy inplace of memcpy,Declared the pointer param +* as Pointer to const, declared XQspi_Set_TapDelay() as static. +* 1.9 akm 03/08/19 Set recommended clock and data tap delay values for 40MHZ, +* 100MHZ and 150MHZ frequencies(CR#1023187) +* 1.10 akm 08/22/19 Set recommended tap delay values for 37.5MHZ, 100MHZ and +* 150MHZ frequencies in Versal. +* 1.11 akm 11/07/19 Removed LQSPI register access in Versal. +* 1.11 akm 11/15/19 Fixed Coverity deadcode warning in +* XQspipsu_Calculate_Tapdelay(). +* 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and +* interrupts in XQspiPsu_CfgInitialize() API. +* 1.13 akm 01/04/21 Fix MISRA-C violations. +* 1.15 akm 03/03/22 Enable tapdelay settings for applications on Microblaze +* platform. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu_control.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/** + * Create the table of options which are processed to get/set the device + * options. These options are table driven to allow easy maintenance and + * expansion of the options. + */ +typedef struct { + u32 Option; /**< Get/Set the device option */ + u32 Mask; /**< Mask */ +} OptionsMap; + +static OptionsMap OptionsTable[] = { + {XQSPIPSU_CLK_ACTIVE_LOW_OPTION, XQSPIPSU_CFG_CLK_POL_MASK}, + {XQSPIPSU_CLK_PHASE_1_OPTION, XQSPIPSU_CFG_CLK_PHA_MASK}, + {XQSPIPSU_MANUAL_START_OPTION, XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK}, +#if !defined (versal) + {XQSPIPSU_LQSPI_MODE_OPTION, XQSPIPSU_CFG_WP_HOLD_MASK}, +#endif +}; + +/** + * Number of options in option table + */ +#define XQSPIPSU_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionsMap)) + +/*****************************************************************************/ +/** +* +* This function sets the options for the QSPIPSU device driver.The options +* control how the device behaves relative to the QSPIPSU bus. The device must be +* idle rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 indicates the option should be turned ON and +* a 0 indicates no action. One or more bit values may be +* contained in the mask. See the bit definitions named +* XQSPIPSU_*_OPTIONS in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + u32 Index; +#if !defined (versal) + u32 QspiPsuOptions; +#endif + s32 Status; + u32 OptionsVal; + OptionsVal = Options; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); +#if !defined (versal) + QspiPsuOptions = OptionsVal & XQSPIPSU_LQSPI_MODE_OPTION; + OptionsVal &= (~XQSPIPSU_LQSPI_MODE_OPTION); +#endif + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if ((OptionsVal & OptionsTable[Index].Option) == + OptionsTable[Index].Option) { + /* Turn it on */ + ConfigReg |= OptionsTable[Index].Mask; + } else { + /* Turn it off */ + ConfigReg &= ~(OptionsTable[Index].Mask); + } + } + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + if ((OptionsVal & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) { + InstancePtr->IsManualstart = (u8)TRUE; + } +#if !defined (versal) + if ((QspiPsuOptions & XQSPIPSU_LQSPI_MODE_OPTION) != (u32)FALSE) { + if ((Options & XQSPIPSU_LQSPI_LESS_THEN_SIXTEENMB) != (u32)FALSE) { + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_RST_STATE); + } else { + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_4_BYTE_STATE); + } + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_CFG_OFFSET,XQSPIPS_LQSPI_CFG_RST_STATE); + /* Enable the QSPI controller */ + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_EN_OFFSET,XQSPIPSU_EN_MASK); + } else { + /* + * Check for the LQSPI configuration options. + */ + ConfigReg = XQspiPsu_ReadReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET); + ConfigReg &= ~(XQSPIPSU_LQSPI_CR_LINEAR_MASK); + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET, ConfigReg); + } +#endif + Status = (s32)XST_SUCCESS; + } + return Status; +} + +/*****************************************************************************/ +/** +* +* This function resets the options for the QSPIPSU device driver.The options +* control how the device behaves relative to the QSPIPSU bus. The device must be +* idle rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 indicates the option should be turned OFF and +* a 0 indicates no action. One or more bit values may be +* contained in the mask. See the bit definitions named +* XQSPIPSU_*_OPTIONS in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + u32 Index; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if ((Options & OptionsTable[Index].Option) != (u32)FALSE) { + /* Turn it off */ + ConfigReg &= ~OptionsTable[Index].Mask; + } + } + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + if ((Options & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) { + InstancePtr->IsManualstart = (u8)FALSE; + } + + Status = (s32)XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function gets the options for the QSPIPSU device. The options control how +* the device behaves relative to the QSPIPSU bus. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return +* +* Options contains the specified options currently set. This is a bit value +* where a 1 means the option is on, and a 0 means the option is off. +* See the bit definitions named XQSPIPSU_*_OPTIONS in file xqspipsu.h. +* +* @note None. +* +******************************************************************************/ +u32 XQspiPsu_GetOptions(const XQspiPsu *InstancePtr) +{ + u32 OptionsFlag = 0; + u32 ConfigReg; + u32 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Loop through the options table to grab options */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + /* + * Get the current options from QSPIPSU configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + if ((ConfigReg & OptionsTable[Index].Mask) != (u32)FALSE) { + OptionsFlag |= OptionsTable[Index].Option; + } + } + return OptionsFlag; +} + +/*****************************************************************************/ +/** +* +* Configures the clock according to the prescaler passed. +* +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Prescaler - clock prescaler to be set. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* It must be stopped to re-initialize. +* +* @note None. +* +******************************************************************************/ +s32 XQspiPsu_SetClkPrescaler(const XQspiPsu *InstancePtr, u8 Prescaler) +{ + u32 ConfigReg; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM); + + /* + * Do not allow the slave select to change while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + /* + * Read the configuration register, mask out the relevant bits, and set + * them with the shifted value passed into the function. Write the + * results back to the configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + ConfigReg &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + ConfigReg |= (u32) ((u32)Prescaler & (u32)XQSPIPSU_CR_PRESC_MAXIMUM) << + XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) + Status = XQspipsu_Calculate_Tapdelay(InstancePtr,Prescaler); +#else + Status = (s32)XST_SUCCESS; +#endif + } + return Status; +} + +/*****************************************************************************/ +/** +* +* This function should be used to tell the QSPIPSU driver the HW flash +* configuration being used. This API should be called at least once in the +* application. If desired, it can be called multiple times when switching +* between communicating to different flahs devices/using different configs. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param FlashCS - Flash Chip Select. +* @param FlashBus - Flash Bus (Upper, Lower or Both). +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note If this function is not called at least once in the application, +* the driver assumes there is a single flash connected to the +* lower bus and CS line. +* +******************************************************************************/ +void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FlashCS > 0U); + Xil_AssertVoid(FlashBus > 0U); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifdef DEBUG + xil_printf("\nXQspiPsu_SelectFlash\r\n"); +#endif + + /* + * Bus and CS lines selected here will be updated in the instance and + * used for subsequent GENFIFO entries during transfer. + */ + + /* Choose slave select line */ + switch (FlashCS) { + case XQSPIPSU_SELECT_FLASH_CS_BOTH: + InstancePtr->GenFifoCS = (u32)XQSPIPSU_GENFIFO_CS_LOWER | + (u32)XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_UPPER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_LOWER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + break; + default: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + break; + } + + /* Choose bus */ + switch (FlashBus) { + case XQSPIPSU_SELECT_FLASH_BUS_BOTH: + InstancePtr->GenFifoBus = (u32)XQSPIPSU_GENFIFO_BUS_LOWER | + (u32)XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_UPPER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_LOWER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + break; + default: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + break; + } +#ifdef DEBUG + xil_printf("\nGenFifoCS is %08x and GenFifoBus is %08x\r\n", + InstancePtr->GenFifoCS, InstancePtr->GenFifoBus); +#endif + +} + +/*****************************************************************************/ +/** +* +* This function sets the Read mode for the QSPIPSU device driver.The device +* must be idle rather than busy transferring data before setting Read mode +* options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Mode contains the specified Mode to be set. See the +* bit definitions named XQSPIPSU_READMODE_* in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting Mode. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_SetReadMode(XQspiPsu *InstancePtr, u32 Mode) +{ + u32 ConfigReg; + s32 Status; + +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetReadMode\r\n"); +#endif + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Mode == XQSPIPSU_READMODE_DMA) || (Mode == XQSPIPSU_READMODE_IO)); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + + InstancePtr->ReadMode = Mode; + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + if (Mode == XQSPIPSU_READMODE_DMA) { + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + } else { + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + } + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + Status = (s32)XST_SUCCESS; + } +#ifdef DEBUG + xil_printf("\nRead Mode is %08x\r\n", InstancePtr->ReadMode); +#endif + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sets the Write Protect and Hold options for the QSPIPSU device +* driver.The device must be idle rather than busy transferring data before +* setting Write Protect and Hold options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Value of the WP_HOLD bit in configuration register +* +* @return None +* +* @note +* This function is not thread-safe. This function can only be used with single +* flash configuration and x1/x2 data mode. This function cannot be used with +* x4 data mode and dual parallel and stacked flash configuration. +* +******************************************************************************/ +void XQspiPsu_SetWP(const XQspiPsu *InstancePtr, u8 Value) +{ + u32 ConfigReg; + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr->IsBusy != TRUE); + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + ConfigReg |= (u32)((u32)Value << XQSPIPSU_CFG_WP_HOLD_SHIFT); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); +} +/** @} */ |