/**
 * gpmi_set_timings - set GPMI timings
 * @pdev: pointer to GPMI platform device
 * @tm: pointer to structure &gpmi_nand_timing with new timings
 *
 * During initialization, GPMI uses safe sub-optimal timings, which
 * can be changed after reading boot control blocks
 */
void gpmi_set_timings(struct lba_data *data, struct gpmi_nand_timing *tm)
{
	u32 period_ns = 1000000 / clk_get_rate(data->clk) + 1;
	u32 address_cycles, data_setup_cycles;
	u32 data_hold_cycles, data_sample_cycles;
	u32 busy_timeout;
	u32 t0;

	address_cycles = gpmi_cycles_ceil(tm->address_setup, period_ns);
	data_setup_cycles = gpmi_cycles_ceil(tm->data_setup, period_ns);
	data_hold_cycles = gpmi_cycles_ceil(tm->data_hold, period_ns);
	data_sample_cycles = gpmi_cycles_ceil(tm->dsample_time + period_ns / 4,
			period_ns / 2);
	busy_timeout = gpmi_cycles_ceil(10000000 / 4096, period_ns);

	t0 = BF_GPMI_TIMING0_ADDRESS_SETUP(address_cycles) |
	    BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles) |
	    BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles);
	HW_GPMI_TIMING0_WR(t0);

	HW_GPMI_TIMING1_WR(BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(busy_timeout));

#ifdef CONFIG_ARCH_STMP378X
	HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_RDN_DELAY);
	HW_GPMI_CTRL1_SET(BF_GPMI_CTRL1_RDN_DELAY(data_sample_cycles));
#else
	HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_DSAMPLE_TIME);
	HW_GPMI_CTRL1_SET(BF_GPMI_CTRL1_DSAMPLE_TIME(data_sample_cycles));
#endif

}
Ejemplo n.º 2
0
////////////////////////////////////////////////////////////////////////////////
//! @brief Compute and setup the NAND clocks.
//!
//! This function sets the GPMI NAND timing based upon the desired NAND timings that
//! are passed in. If the GPMI clock period is non-zero it is used in the
//! calculation of the new register values. If zero is passed instead, the
//! current GPMI_CLK frequency is obtained and used to calculate the period
//! in nanoseconds.
//!
//! @param[in] theTimings  Pointer to a nand-timing Structure with Address Setup, Data Setup and Hold, etc.
//!                             This structure must be one of those that contains an eState element,
//!                             so this function can tell how to crack it and process it.
//! @param[in]  u32GpmiPeriod_ns GPMI Clock Period in nsec. May be zero, in
//!                             which case the actual current GPMI_CLK period is used.
//! @param[in] u32PropDelayMin_ns Minimum propagation delay in nanoseconds.
//! @param[in] u32PropDelayMax_ns Maximum propagation delay in nanoseconds.
////////////////////////////////////////////////////////////////////////////////
void gpmi_set_timing_internal(const GpmiNandTimings_t * theTimings, 
                                    uint32_t u32GpmiPeriod_ns, 
                                    uint32_t u32PropDelayMin_ns, 
                                    uint32_t u32PropDelayMax_ns)
{
    uint32_t u32GpmiDelayFraction;
    int32_t u32GpmiMaxDelay_ns;
    uint32_t u32AddressSetupCycles;
    uint32_t u32DataSetupCycles;
    uint32_t u32DataHoldCycles;
    uint32_t u32DataSampleDelayCycles;
    uint32_t u32DataSetup_ns;
    int32_t  i32tEYE;
    int32_t  i32DelayTime_ns;
#if GPMI_PRINT_TIMINGS
    char bPrintInterimTimings = false;
#endif
	
    assert(theTimings);
	
    // If u32GpmiPeriod is passed in as 0, we get the current GPMI_CLK frequency
    // and compute the period in ns.
    if (u32GpmiPeriod_ns == 0)
    {
        u32GpmiPeriod_ns = gpmi_get_clock_period_ns();
    }
	
    u32GpmiDelayFraction = gpmi_init_data_sample_delay(u32GpmiPeriod_ns);
                    
    u32GpmiMaxDelay_ns = GPMI_GET_MAX_DELAY_NS(u32GpmiPeriod_ns);
    
	
#if GPMI_PRINT_TIMINGS
    printf("NAND GPMI timings:@n");
#endif
    
    /* *******************************************************************
        Process the given AddressSetup, DataSetup, and DataHold
        parameters
    ******************************************************************* */
                    
    // The chip hardware quantizes the setup and hold parameters to intervals of
    // the GPMI clock period.
    // Quantize the setup and hold parameters to the next-highest GPMI clock period to
    // make sure we use at least the requested times.
    //
    // For DataSetup and DataHold, the chip interprets a value of zero as the largest
    // amount of delay supported.  This is not what's intended by a zero
    // in the input parameter, so we modify the zero input parameter to
    // the smallest supported value.
    
    u32AddressSetupCycles = gpmi_find_cycles_ceiling(theTimings->tSU, u32GpmiPeriod_ns, 0);
    u32DataSetupCycles    = gpmi_find_cycles_ceiling(theTimings->tDS, u32GpmiPeriod_ns, 1);
    u32DataHoldCycles     = gpmi_find_cycles_ceiling(theTimings->tDH, u32GpmiPeriod_ns, 1);
                    
	
//     switch (theTimings->eState)
//     {
//         case e_NAND_Timing_State_STATIC_DSAMPLE_TIME:
//         {
//             // Get delay time and include required chip read setup time
//             i32DelayTime_ns = theTimings->u8DSAMPLE_TIME + GPMI_DATA_SETUP_NS;
//     
//             // Extend the Data Setup time as needed to reduce delay time below 
//             // the max supported by hardware.  Also keep DataSetup in allowable range
//             while ((i32DelayTime_ns > u32GpmiMaxDelay_ns) && (u32DataSetupCycles  < MAX_DATA_SETUP_CYCLES))
//             {
//                 u32DataSetupCycles++;
//                 i32DelayTime_ns -= u32GpmiPeriod_ns;
//                 if (i32DelayTime_ns < 0)
//                 {
//                     i32DelayTime_ns = 0;
//                 }
//             }
//                     
//             u32DataSampleDelayCycles = std::min( gpmi_find_cycles_ceiling( (u32GpmiDelayFraction * i32DelayTime_ns), u32GpmiPeriod_ns, 0), MAX_DATA_SAMPLE_DELAY_CYCLES);
// 	
// #if GPMI_PRINT_TIMINGS
//             printf("(--static--)@n");
// #endif
//             break;
//         } // case e_NAND_Timing_State_STATIC_DSAMPLE_TIME:
//     
//         case e_NAND_Timing_State_DYNAMIC_DSAMPLE_TIME:
//         {
	
    
            // Compute the times associated with the quantized number of GPMI cycles.
            u32DataSetup_ns = u32GpmiPeriod_ns * u32DataSetupCycles;
                    
            // This accounts for chip specific GPMI read setup time on the data sample 
            // circuit.  See 378x datasheet "14.3.4. High-Speed NAND Timing"
            u32PropDelayMax_ns += GPMI_DATA_SETUP_NS;
                    
         /* *******************************************************************
                Compute tEYE, the width of the data eye when reading from the NAND.
            ******************************************************************* */
    
            // Note that we use the quantized versions of setup and hold, because the chip
            // uses these quantized values, and these timings create the eye.
            //
            // end of the eye = u32PropDelayMin_ns + theTimings->tRHOH + u32DataSetup_ns
            // start of the eye = u32PropDelayMax_ns + theTimings->tREA
            i32tEYE = ( (int)u32PropDelayMin_ns + (int)theTimings->tRHOH + (int)u32DataSetup_ns ) - ( (int)u32PropDelayMax_ns + (int)theTimings->tREA );
                    
                         
            // The eye has to be open.  Constrain tEYE to be greater than zero
            // and the number of DataSetup cycles to fit in the timing register.
            while ( (i32tEYE <= 0) && (u32DataSetupCycles  < MAX_DATA_SETUP_CYCLES) )
            {
                // The eye is not open.  An increase in data-setup time 
                // causes a coresponding increase to size of the eye.
                u32DataSetupCycles++;                               // Give an additional DataSetup cycle
                u32DataSetup_ns += u32GpmiPeriod_ns;                // Keep DataSetup time in step with cycles
                i32tEYE += u32GpmiPeriod_ns;                        // And adjust the tEYE accordingly
    
            } // while ( i32tEYE
	
   
         /* *******************************************************************
                Compute the ideal point at which to sample the data
                at the center of tEYE.
            ******************************************************************* */
    
            // Find the delay to get the center in time-units.
            // Delay for center of the eye = ((end of the eye + start of the eye) / 2) - DataSetup
            // This simplifies to the following:
            i32DelayTime_ns = ( (int)u32PropDelayMax_ns + (int)theTimings->tREA + (int)u32PropDelayMin_ns + (int)theTimings->tRHOH - (int)u32DataSetup_ns ) >> 1;
    
            // The chip can't accomodate a negative parameter for the sample point.
            if ( i32DelayTime_ns < 0 ) i32DelayTime_ns = 0;
    
            //  Make sure the required DelayTime does not exceed the max allowed value.
            //  Also make sure the quantized DelayTime (at u32DataSampleDelayCycles) is 
            //  within the eye.  
            //
            //  Increasing DataSetup decreases the length of DelayTime 
            //  required to get to into the eye.  Increasing DataSetup also moves the rear 
            //  of the eye back, enlarges the eye (helpful in the case where quantized 
            //  DelayTime does not fall inside the initial eye).
            //          
            //          ____                   __________________________________________
            //  RDN         \_________________/
            //
            //                                               <----- tEYE ---->
            //                                             /--------------------\                    x
            //  Read Data --------------------------------<                      >-------
            //                                             \--------------------/
            //              ^                 ^                      ^   tEYE/2     ^
            //              |                 |                      |              |
            //              |<---DataSetup--->|<-----DelayTime------>|              |
            //              |                 |                      |              |
            //              |                 |                                     |
            //              |                 |<------quantized DelayTime---------->|
            //              |                 |                                     |
            //                                      
    
            #if GPMI_PRINT_TIMINGS
            printf("(--dynamic--)(--Start--)@n");
            _print_dynamic_timing_summary(
                u32GpmiPeriod_ns,
                u32GpmiDelayFraction,
                i32tEYE,
                i32DelayTime_ns,
                u32GpmiMaxDelay_ns,
                u32DataSetupCycles,
                u32DataSetup_ns);
            #endif
            
            // Extend the Data Setup time as needed to reduce delay time below 
            // the max allowable value.  Also keep DataSetup in allowable range
            while ((i32DelayTime_ns > u32GpmiMaxDelay_ns) && (u32DataSetupCycles  < MAX_DATA_SETUP_CYCLES))
            {
                #if GPMI_PRINT_TIMINGS
                if ( !bPrintInterimTimings )
                {
                    // Print an explanation once now...
                    printf("(DelayTime > GPMI max %d) and DataSetupCycles < max %d. Adjusting DelayTime.@n",u32GpmiMaxDelay_ns,MAX_DATA_SETUP_CYCLES );
                    // ...and print an interim list of timings afterward.
                    bPrintInterimTimings = true;
                }
                #endif
                u32DataSetupCycles++;                               // Give an additional DataSetup cycle
                u32DataSetup_ns += u32GpmiPeriod_ns;                // Keep DataSetup time in step with cycles
                i32tEYE += u32GpmiPeriod_ns;                        // And adjust the tEYE accordingly
                i32DelayTime_ns -= (u32GpmiPeriod_ns >> 1);         // decrease DelayTime by one half DataSetup cycle worth, to keep in the middle of the eye
                if (i32DelayTime_ns < 0)
                {
                    i32DelayTime_ns = 0;                            // Do not allow DelayTime less than zero
                }
            }

            // The DelayTime parameter is expressed in the chip in units of fractions of GPMI clocks.
            // Convert DelayTime to an integer quantity of fractional GPMI cycles..
            u32DataSampleDelayCycles = std::min( gpmi_find_cycles_ceiling( (u32GpmiDelayFraction * i32DelayTime_ns), u32GpmiPeriod_ns, 0), MAX_DATA_SAMPLE_DELAY_CYCLES);

            #if GPMI_PRINT_TIMINGS
            if ( bPrintInterimTimings )
            {
                _print_dynamic_timing_summary(
                    u32GpmiPeriod_ns,
                    u32GpmiDelayFraction,
                    i32tEYE,
                    i32DelayTime_ns,
                    u32GpmiMaxDelay_ns,
                    u32DataSetupCycles,
                    u32DataSetup_ns);
                bPrintInterimTimings = false;
            }
	
            #endif
            #define DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE  ( i32tEYE>>1 < std::abs( (int32_t)((u32DataSampleDelayCycles * u32GpmiPeriod_ns) / u32GpmiDelayFraction) - i32DelayTime_ns ))
                    
            // While the quantized DelayTime is out of the eye reduce the DelayTime or extend 
            // the DataSetup to get in the eye.  Do not allow the number of DataSetup cycles to 
            // exceed the max supported by hardware.
            while ( DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE
                    && (u32DataSetupCycles  < MAX_DATA_SETUP_CYCLES) )
            {
                #if GPMI_PRINT_TIMINGS
                if ( !bPrintInterimTimings )
                {
                    // Print an explanation once now.
                    printf("Data sample point not within data eye.  Adjusting.@n" );
                    bPrintInterimTimings = true;
                }
                #endif
                if ( (int32_t)((u32DataSampleDelayCycles * u32GpmiPeriod_ns) / u32GpmiDelayFraction) > i32DelayTime_ns )
                {
                    // If quantized DelayTime is greater than max reach of the eye decrease quantized 
                    // DelayTime to get it into the eye or before the eye
	
                    if (u32DataSampleDelayCycles != 0)
                    {
                        u32DataSampleDelayCycles--;
                    }
                }
                else
                {
                    // If quantized DelayTime is less than min reach of the eye, shift up the sample 
                    // point by increasing DataSetup.  This will also open the eye (helping get 
                    // quantized DelayTime in the eye)
                    u32DataSetupCycles++;                           // Give an additional DataSetup cycle
                    u32DataSetup_ns += u32GpmiPeriod_ns;            // Keep DataSetup time in step with cycles
                    i32tEYE         += u32GpmiPeriod_ns;            // And adjust the tEYE accordingly
                    i32DelayTime_ns -= (u32GpmiPeriod_ns >> 1);     // decrease DelayTime by one half DataSetup cycle worth, to keep in the middle of the eye
                    i32DelayTime_ns -= u32GpmiPeriod_ns;            // ...and one less period for DelayTime.
    
                    if ( i32DelayTime_ns < 0 ) i32DelayTime_ns = 0; // keep DelayTime from going negative
                    
                    // Convert time to GPMI cycles and make sure the number of 
                    // cycles fit in the coresponding hardware register...
                    u32DataSampleDelayCycles = std::min( gpmi_find_cycles_ceiling( (u32GpmiDelayFraction * i32DelayTime_ns), u32GpmiPeriod_ns, 0), MAX_DATA_SAMPLE_DELAY_CYCLES);
                }
	
            }   // while ( DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE )
    
#if GPMI_PRINT_TIMINGS
            printf("(--Final--)@n");
            _print_dynamic_timing_summary(
                u32GpmiPeriod_ns,
                u32GpmiDelayFraction,
                i32tEYE,
                i32DelayTime_ns,
                u32GpmiMaxDelay_ns,
                u32DataSetupCycles,
                u32DataSetup_ns);
//            hal_delay_us(GPMI_PRINT_DELAY);
#endif
                    
//             break;
//         } //case e_NAND_Timing_State_DYNAMIC_DSAMPLE_TIME:
// 	
//         default:
// #if GPMI_PRINT_TIMINGS
//             printf("(--unchanged--)@n");
// #endif
//             return;
//     }
    
#if GPMI_PRINT_TIMINGS
    printf("GPMI (tDS, tDH, tAS, DelayT) = (%d, %d, %d, %d) ns@n",
                    u32GpmiPeriod_ns * u32DataSetupCycles,
                    u32GpmiPeriod_ns * u32DataHoldCycles,
                    u32GpmiPeriod_ns * u32AddressSetupCycles,
                    ((u32GpmiPeriod_ns * u32DataSampleDelayCycles) / u32GpmiDelayFraction) );
//    hal_delay_us(GPMI_PRINT_DELAY);
	
    printf("(DataSetup, DataHold, AddressSetup, DelayTime) = (%d, %d, %d, %d) Count@n",
                    u32DataSetupCycles,
                    u32DataHoldCycles,
                    u32AddressSetupCycles,
                    u32DataSampleDelayCycles );
    
//    hal_delay_us(GPMI_PRINT_DELAY);
#endif
                    
    // Set the values in the registers.
    HW_GPMI_TIMING0_WR( BF_GPMI_TIMING0_ADDRESS_SETUP(u32AddressSetupCycles)
                        | BF_GPMI_TIMING0_DATA_SETUP(u32DataSetupCycles)
                        | BF_GPMI_TIMING0_DATA_HOLD(u32DataHoldCycles));
                         
    gpmi_set_and_enable_data_sample_delay(u32DataSampleDelayCycles, u32GpmiPeriod_ns);
    
    return;
}