[PATCH v7 08/11] ARM: OMAP2+: gpmc: generic timing calculation

Jon Hunter jon-hunter at ti.com
Thu Sep 27 11:16:12 EDT 2012


Hi Afzal,

On 09/27/2012 05:07 AM, Mohammed, Afzal wrote:
> Hi Jon,
> 
> On Thu, Sep 27, 2012 at 08:54:22, Hunter, Jon wrote:
>> On 09/19/2012 08:23 AM, Afzal Mohammed wrote:
> 
>>> +Dependency of peripheral timings on gpmc timings:
>>> +
>>> +cs_on: t_ceasu
>>
>> Thanks for adding these details. Could be good to clarify that the
>> left-hand side parameters are the gpmc register fields and the
>> right-hand side are the timing parameters these are calculated using.
> 
> Ok
> 
>>
>> Also, given that this is in documentation for completeness it could be
>> good to somewhere state what "t_ceasu" means. For the gpmc register
>> field description may be we could give a reference to an OMAP document.
> 
> Yes, it has been mentioned, as quoted below, reason it has not been
> mentioned here is to avoid duplication. I will add TRM reference.
> 
> "
>>> +Note: Many of gpmc timings are dependent on other gpmc timings (a few
> 
>>> +mentioned above, refer timing routine for more details. To know what
>>> +these peripheral timings correspond to, please see explanations in
>>> +struct gpmc_device_timings definition.
> 
>>> +struct gpmc_device_timings {
>>> +	u32 t_ceasu;	/* address setup to CS valid */
> "
> 
>>> +adv_rd_off: t_avdp_r, t_avdh(s*)
>>> +oe_on: t_oeasu, t_aavdh(a**), t_ach(s), cyc_aavdh_oe(s)
>>
>> Would it be better to have ...
>>
>> oe_on (sync):	t_oeasu, t_ach(*), cyc_aavdh_oe
>> oe_on (async):	t_oeasu, t_aavdh(*)
> 
> Ok
> 
>> * - optional
>>
>> I assume that the hold times from the clock (t_ach and t_aavdh) are used
>> for fine tuning if the peripheral requires this, but a user adding a new
>> device would not be required to specify these, where as t_oeasu is
>> mandatory.
> 
> It depends on the peripheral, t_oeasu in not used for OneNAND, tusb sync,
> so I prefer not mentioning any timing as optional or mandatory.

Ok.

>> Or maybe should the timings be grouped as ...
>>
>> General
>> Read Async
>> Read Async Address/Data Multiplexed
>> Read Sync
>> Read Sync Address/Data Multiplexed
>> Write Async
>> Write Async Address/Data Multiplexed
>> Write Sync
>> Write Sync Address/Data Multiplexed
>>
>> There may be some duplication but it will be clear where things like ADV
>> timing applies.
> 
> I would prefer to keep it concise, but no strong opinion on it, if you
> prefer as above, I will change it.

I think that if these represent the main use-case configurations this
could add some value.

>>> +/* can the cycles be avoided ? */
>>
>> Nit should this be marked with a TODO?
> 
>>> +	/* mux check required ? */
>>
>> Nit should this be marked with a TODO?
> 
> Marking XXX should Ok, right ?, reason is that they are not
> kept as TODO, but rather as pointers to may be possible
> improvements

Sure, I don't have strong feelings about it but I would hope that at
some point this comment be removed.

>>> +	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
> 
>> Any reason why we can't return ns in the above function? Or make this
>> function gpmc_round_ps_to_ns()? Then we could avoid having
>> gpmc_convert_ps_to_ns() below.
> 
> Calculation in ps is required to get more accurate results.
> 
> Calculating in ns was the reason for issue faced on N800 for Tony
> with previous version.
> 
> I will explain what would have happened with v6 on N800,
> i.e. using ns values,
> Based on logs from Tony, gpmc clk was 9ns, actually it would
> have been somewhere around 9115ps.
> 
> Take below timings of previous version in tusb async case
> 
>         gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp) / 1000;
> 
>         /* access */
>         temp = max_t(u32, dev_t->t_iaa, /* remove t_iaa in async ? */
>                                 gpmc_t->oe_on * 1000 + dev_t->t_oe);
>         temp = max_t(u32, temp,
>                                 gpmc_t->cs_on * 1000 + dev_t->t_ce);
>         temp = max_t(u32, temp,
>                                 gpmc_t->adv_on * 1000 + dev_t->t_aa);
>         gpmc_t->access = gpmc_round_ps_to_ticks(temp) / 1000;
> 
> Upon calculating we get,
> 
> oe_on = 63805 / 1000 = 63
> 
> and for access (t_oe = 300, t_ce = t_aa = t_iaa = 0),
> 
> temp = 63 * 1000 + 300 = 63300
> access = 63300 / 1000 = 63
> 
> Here we get oe_on as well as access as 7 ticks, but access should
> have been 8 ticks, which is what we will get by using ps values,
> i.e. as in this version, as below,
> 
>         gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
> 
>         /* access */
>         temp = max_t(u32, dev_t->t_iaa, /* remove t_iaa in async ? */
>                                 gpmc_t->oe_on + dev_t->t_oe);
>         temp = max_t(u32, temp,
>                                 gpmc_t->cs_on + dev_t->t_ce);
>         temp = max_t(u32, temp,
>                                 gpmc_t->adv_on + dev_t->t_aa);
>         gpmc_t->access = gpmc_round_ps_to_ticks(temp);
> 
> I believe it is always better to go with higher resolution.

Ok, thanks for clarifying.

>>> +	gpmc_convert_ps_to_ns(gpmc_t);
> 
>> I am wondering if we could avoid this above function and then ...
> 
> This will be removed once it is confirmed that all the peripherals
> using custom runtime calculation can work with this generic
> routine. Then all calculation would be purely in ps.

Ok, great. May be add a TODO here to make this clear that this is temporary.

> Right now converting ps to ns has been kept only to be compatible
> with custom routines and so that we can easily go back to custom
> routines in case of any issues, quoting relevant commit message below,
> 
> "
>     Timings are calculated in ps to prevent rounding errors and
>     converted to ns at final stage so that these values can be
>     directly fed to gpmc_cs_set_timings(). gpmc_cs_set_timings()
>     would be modified to take ps once all custom timing routines
>     are replaced by the generic routine, at the same time
>     generic timing routine would be modified to provide timings
>     in ps. struct gpmc_timings field types are upgraded from
>     u16 => u32 so that it can hold ps values.
> "

Ok.

>>> @@ -116,42 +116,103 @@ struct gpmc_timings {
> 
>>> -	u16 wr_access;		/* WRACCESSTIME */
>>> -	u16 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
>>> +	u32 wr_access;		/* WRACCESSTIME */
>>> +	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
>>
>>  ... we could keep the above u16.
> 
> Due to the reasons mentioned above u32 is required.
> 
>>> +	u32 t_aavdh;	/* address hold time */
> 
>>> +	u32 t_iaa;	/* initial access time */
> 
>>> +	u32 t_oe;	/* access time from OE assertion */
> 
>>> +	u32 t_wpl;	/* write assertion time */
> 
>>> +	u8 cyc_aavdh_oe;
>>> +	u8 cyc_aavdh_we;
>>> +	u8 cyc_oe;
>>> +	u8 cyc_wpl;
>>> +	u32 cyc_iaa;
>>
>> May be I should look at an example, but it would be good to document
>> what these cyc_xxx parameters are/represent.
> 
> These are cycles counterpart of that of time, I will update it too.

Thanks!
Jon



More information about the linux-arm-kernel mailing list