mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 02:09:42 +00:00
![Afzal Mohammed](/assets/img/avatar_default.png)
Presently there are three peripherals that gets it timing by runtime calculation. Those peripherals can work with frequency scaling that affects gpmc clock. But timing calculation for them are in different ways. Here a generic runtime calculation method is proposed. Input to this function were selected so that they represent timing variables that are present in peripheral datasheets. Motive behind this was to achieve DT bindings for the inputs as is. Even though a few of the tusb6010 timings could not be made directly related to timings normally found on peripherals, expressions used were translated to those that could be justified. There are possibilities of improving the calculations, like calculating timing for read & write operations in a more similar way. Expressions derived here were tested for async onenand on omap3evm (as vanilla Kernel does not have omap3evm onenand support, local patch was used). Other peripherals, tusb6010, smc91x calculations were validated by simulating on omap3evm. Regarding "we_on" for onenand async, it was found that even for muxed address/data, it need not be greater than "adv_wr_off", but rather could be derived from write setup time for peripheral from start of access time, hence would more be in line with peripheral timings. With this method it was working fine. If it is required in some cases to have "we_on" same as "wr_data_mux_bus" (i.e. greater than "adv_wr_off"), another variable could be added to indicate it. But such a requirement is not expected though. It has been observed that "adv_rd_off" & "adv_wr_off" are currently calculated by adding an offset over "oe_on" and "we_on" respectively in the case of smc91x. But peripheral datasheet does not specify so and so "adv_rd(wr)_off" has been derived (to be specific, made ignorant of "oe_on" and "we_on") observing datasheet rather than adding an offset. Hence this generic routine is expected to work for smc91x (91C96 RX51 board). This was verified on smsc911x (9220 on OMAP3EVM) - a similar ethernet controller. 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. Whole of this exercise is being done to achieve driver and DT conversion. If timings could not be calculated in a peripheral agnostic way, either gpmc driver would have to be peripheral gnostic or a wrapper arrangement over gpmc driver would be required. Signed-off-by: Afzal Mohammed <afzal@ti.com>
122 lines
4.2 KiB
Text
122 lines
4.2 KiB
Text
GPMC (General Purpose Memory Controller):
|
|
=========================================
|
|
|
|
GPMC is an unified memory controller dedicated to interfacing external
|
|
memory devices like
|
|
* Asynchronous SRAM like memories and application specific integrated
|
|
circuit devices.
|
|
* Asynchronous, synchronous, and page mode burst NOR flash devices
|
|
NAND flash
|
|
* Pseudo-SRAM devices
|
|
|
|
GPMC is found on Texas Instruments SoC's (OMAP based)
|
|
IP details: http://www.ti.com/lit/pdf/spruh73 section 7.1
|
|
|
|
|
|
GPMC generic timing calculation:
|
|
================================
|
|
|
|
GPMC has certain timings that has to be programmed for proper
|
|
functioning of the peripheral, while peripheral has another set of
|
|
timings. To have peripheral work with gpmc, peripheral timings has to
|
|
be translated to the form gpmc can understand. The way it has to be
|
|
translated depends on the connected peripheral. Also there is a
|
|
dependency for certain gpmc timings on gpmc clock frequency. Hence a
|
|
generic timing routine was developed to achieve above requirements.
|
|
|
|
Generic routine provides a generic method to calculate gpmc timings
|
|
from gpmc peripheral timings. struct gpmc_device_timings fields has to
|
|
be updated with timings from the datasheet of the peripheral that is
|
|
connected to gpmc. A few of the peripheral timings can be fed either
|
|
in time or in cycles, provision to handle this scenario has been
|
|
provided (refer struct gpmc_device_timings definition). It may so
|
|
happen that timing as specified by peripheral datasheet is not present
|
|
in timing structure, in this scenario, try to correlate peripheral
|
|
timing to the one available. If that doesn't work, try to add a new
|
|
field as required by peripheral, educate generic timing routine to
|
|
handle it, make sure that it does not break any of the existing.
|
|
Then there may be cases where peripheral datasheet doesn't mention
|
|
certain fields of struct gpmc_device_timings, zero those entries.
|
|
|
|
Generic timing routine has been verified to work properly on
|
|
multiple onenand's and tusb6010 peripherals.
|
|
|
|
A word of caution: generic timing routine has been developed based
|
|
on understanding of gpmc timings, peripheral timings, available
|
|
custom timing routines, a kind of reverse engineering without
|
|
most of the datasheets & hardware (to be exact none of those supported
|
|
in mainline having custom timing routine) and by simulation.
|
|
|
|
gpmc timing dependency on peripheral timings:
|
|
[<gpmc_timing>: <peripheral timing1>, <peripheral timing2> ...]
|
|
|
|
1. common
|
|
cs_on: t_ceasu
|
|
adv_on: t_avdasu, t_ceavd
|
|
|
|
2. sync common
|
|
sync_clk: clk
|
|
page_burst_access: t_bacc
|
|
clk_activation: t_ces, t_avds
|
|
|
|
3. read async muxed
|
|
adv_rd_off: t_avdp_r
|
|
oe_on: t_oeasu, t_aavdh
|
|
access: t_iaa, t_oe, t_ce, t_aa
|
|
rd_cycle: t_rd_cycle, t_cez_r, t_oez
|
|
|
|
4. read async non-muxed
|
|
adv_rd_off: t_avdp_r
|
|
oe_on: t_oeasu
|
|
access: t_iaa, t_oe, t_ce, t_aa
|
|
rd_cycle: t_rd_cycle, t_cez_r, t_oez
|
|
|
|
5. read sync muxed
|
|
adv_rd_off: t_avdp_r, t_avdh
|
|
oe_on: t_oeasu, t_ach, cyc_aavdh_oe
|
|
access: t_iaa, cyc_iaa, cyc_oe
|
|
rd_cycle: t_cez_r, t_oez, t_ce_rdyz
|
|
|
|
6. read sync non-muxed
|
|
adv_rd_off: t_avdp_r
|
|
oe_on: t_oeasu
|
|
access: t_iaa, cyc_iaa, cyc_oe
|
|
rd_cycle: t_cez_r, t_oez, t_ce_rdyz
|
|
|
|
7. write async muxed
|
|
adv_wr_off: t_avdp_w
|
|
we_on, wr_data_mux_bus: t_weasu, t_aavdh, cyc_aavhd_we
|
|
we_off: t_wpl
|
|
cs_wr_off: t_wph
|
|
wr_cycle: t_cez_w, t_wr_cycle
|
|
|
|
8. write async non-muxed
|
|
adv_wr_off: t_avdp_w
|
|
we_on, wr_data_mux_bus: t_weasu
|
|
we_off: t_wpl
|
|
cs_wr_off: t_wph
|
|
wr_cycle: t_cez_w, t_wr_cycle
|
|
|
|
9. write sync muxed
|
|
adv_wr_off: t_avdp_w, t_avdh
|
|
we_on, wr_data_mux_bus: t_weasu, t_rdyo, t_aavdh, cyc_aavhd_we
|
|
we_off: t_wpl, cyc_wpl
|
|
cs_wr_off: t_wph
|
|
wr_cycle: t_cez_w, t_ce_rdyz
|
|
|
|
10. write sync non-muxed
|
|
adv_wr_off: t_avdp_w
|
|
we_on, wr_data_mux_bus: t_weasu, t_rdyo
|
|
we_off: t_wpl, cyc_wpl
|
|
cs_wr_off: t_wph
|
|
wr_cycle: t_cez_w, t_ce_rdyz
|
|
|
|
|
|
Note: Many of gpmc timings are dependent on other gpmc timings (a few
|
|
gpmc timings purely dependent on other gpmc timings, a reason that
|
|
some of the gpmc timings are missing above), and it will result in
|
|
indirect dependency of peripheral timings to gpmc timings other than
|
|
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. And for gpmc timings refer
|
|
IP details (link above).
|