/** * 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 }
//////////////////////////////////////////////////////////////////////////////// //! @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; }