Re: [PATCH V3] ARM: GIC: Convert GIC library to use the IO relaxed operations
On 5/4/2011 10:34 PM, Will Deacon wrote: Hi Santosh, On Wed, 2011-05-04 at 12:02 +0100, Santosh Shilimkar wrote: Will, Can you queue this patch part of your series please? Yes, providing that Russell is happy to pull the IRQ stuff (fasteoi, Tegra changes and this) from me. Thanks. Regards Santosh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Common clock and dvfs
On Wed, May 4, 2011 at 10:08 PM, Cousson, Benoit b-cous...@ti.com wrote: (Cc folks with some DVFS interest) Hi Colin, On Fri, 22 Apr 2011, Colin Cross wrote: Now that we are approaching a common clock management implementation, I was thinking it might be the right place to put a common dvfs implementation as well. It is very common for SoC manufacturers to provide a table of the minimum voltage required on a voltage rail for a clock to run at a given frequency. There may be multiple clocks in a voltage rail that each can specify their own minimum voltage, and one clock may affect multiple voltage rails. I have seen two ways to handle keeping the clocks and voltages within spec: The Tegra way is to put everything dvfs related under the clock framework. Enabling (or preparing, in the new clock world) or raising the frequency calls dvfs_set_rate before touching the clock, which looks up the required voltage on a voltage rail, aggregates it with the other voltage requests, and passes the minimum voltage required to the regulator api. Disabling or unpreparing, or lowering the frequency changes the clock first, and then calls dvfs_set_rate. For a generic implementation, an SoC would provide the clock/dvfs framework with a list of clocks, the voltages required for each frequency step on the clock, and the regulator name to change. The frequency/voltage tables are similar to OPP, except that OPP gets voltages for a device instead of a clock. In a few odd cases (Tegra always has a few odd cases), a clock that is internal to a device and not exposed to the clock framework (pclk output on the display, for example) has a voltage requirement, which requires some devices to manually call dvfs_set_rate directly, but with a common clock framework it would probably be possible for the display driver to export pclk as a real clock. Those kinds of exceptions are somehow the rules for an OMAP4 device. Most scalable devices are using some internal dividers or even internal PLL to control the scalable clock rate (DSS, HSI, MMC, McBSP... the OMAP4430 Data Manual [1] is providing the various clock rate limitation depending of the OPP). And none of these internal dividers are handled by the clock fmwk today. For sure, it should be possible to extend the clock data with internal devices clock nodes (like the UART baud rate divider for example), but then we will have to handle a bunch of nodes that may not be always available depending of device state. In order to do that, you have to tie these clocks node to the device that contains them. I agree there are cases where the clock framework may not be a fit for a specific divider, but it would be simple to export the same dvfs_set_rate functions that the generic clk_set_rate calls, and allow drivers that need to scale their own clocks to take advantage of the common tables. And for the clocks that do not belong to any device, like most PRCM source clocks or DPLL inside OMAP, we can easily define a PRCM device or several CM (Clock Manager) devices that will handle all these clock nodes. The proposed OMAP4 way (I believe, correct me if I am wrong) is to create a new api outside the clock api that calls into both the clock api and the regulator api in the correct order for each operation, using OPP to determine the voltage. This has a few disadvantages (obviously, I am biased, having written the Tegra code) - clocks and voltages are tied to a device, which is not always the case for platforms outside of OMAP, and drivers must know if their hardware requires voltage scaling. The clock api becomes unsafe to use on any device that requires dvfs, as it could change the frequency higher than the supported voltage. You have to tie clock and voltage to a device. Most of the time a clock does not have any clear relation with a voltage domain. It can even cross power / voltage domain without any issue. The efficiency of the DVFS technique is mainly due to the reduction of the voltage rail that supply a device. In order to achieve that you have to reduce the clock rate of one or several clocks nodes that supply the critical path inside the HW. A clock crossing a voltage domain is not a problem, a single clock can have relationships to multiple regulators. But a clock does not need to be tied to a device. From the silicon perspective, it doesn't matter how you divide up the devices in the kernel, a clock is just a line toggling at a rate, and the maximum speed it can toggle is determined by the silicon it feeds and the voltage that silicon is operating at. If a device can be turned on or off, that's a clock gate, and the line downstream from the clock gate is a separate clock. The clock node itself does not know anything about the device and that's why it should not be the proper structure to do DVFS. One of us is confused here. The clock node does not know about the device, and it doesn't need to. All the
Re: Common clock and dvfs
On Thu, 5 May 2011, Cousson, Benoit wrote: Those kinds of exceptions are somehow the rules for an OMAP4 device. Most scalable devices are using some internal dividers or even internal PLL to control the scalable clock rate (DSS, HSI, MMC, McBSP... the OMAP4430 Data Manual [1] is providing the various clock rate limitation depending of the OPP). And none of these internal dividers are handled by the clock fmwk today. That's mostly because no one has taken the time to implement them, not really for any technical reason. For sure, it should be possible to extend the clock data with internal devices clock nodes (like the UART baud rate divider for example), but then we will have to handle a bunch of nodes that may not be always available depending of device state. In order to do that, you have to tie these clocks node to the device that contains them. It's only necessary to do that for the device where the clock's control registers are located. In many cases (almost all on OMAP), this is a different device from the device that the clock actually drives. And for the clocks that do not belong to any device, like most PRCM source clocks or DPLL inside OMAP, we can easily define a PRCM device or several CM (Clock Manager) devices that will handle all these clock nodes. The proposed OMAP4 way (I believe, correct me if I am wrong) is to create a new api outside the clock api that calls into both the clock api and the regulator api in the correct order for each operation, using OPP to determine the voltage. This has a few disadvantages (obviously, I am biased, having written the Tegra code) - clocks and voltages are tied to a device, which is not always the case for platforms outside of OMAP, and drivers must know if their hardware requires voltage scaling. The clock api becomes unsafe to use on any device that requires dvfs, as it could change the frequency higher than the supported voltage. You have to tie clock and voltage to a device. As you mentioned above, there are several clocks that aren't associated with any specific device outside of the clock itself, or which are associated with multiple devices. Most of the time a clock does not have any clear relation with a voltage domain. It can even cross power / voltage domain without any issue. Each instance of a clock signal -- a conductor on a chip that carries an AC signal that is used to drive some gates -- can only be driven by one voltage rail. How could it be otherwise? In the unusual instances where a clock crosses voltage rails (by virtue of some gates between the rails that handle the translation) and it is important for Linux to know this, then in the Linux-OMAP code, the intention is for separate struct clks to be used for the clock signals on either side of the voltage rail crossing. The clock node itself does not know anything about the device and that's why it should not be the proper structure to do DVFS. What aspects of the device are you referring to that the clock node would need to know? OMAP moved away from using the clock nodes to represent IP blocks because the clock abstraction was not enough to represent the way an IP is interacting with clocks. That's why omap_hwmod was introduced to represent an IP block. omap_hwmod was introduced to represent IP blocks and their interconnection. Separating IP block gating from individual clock gating was one part of this, but not the only one; and gating isn't really related to DVFS. Because the clock is not the central piece of the DVFS sequence, I don't think it deserves to handle the whole sequence including voltage scaling. A change to a clock rate might trigger a voltage change, but the opposite is true as well. A reduction of the voltage could trigger the clock rate change inside all the devices that belong to the voltage domain. Because of that, both fmwks are siblings. This is not a parent-child relationship. What's the use case for voltage reduction that isn't triggered by a clock rate reduction? Another important point is that in order to trigger a DVFS sequence you have to do some voting to take into account shared clock and shared voltage domains. Moreover, playing directly with a clock rate is not necessarily appropriate or sufficient for some devices. For example, the interconnect should expose a BW knob instead of a clock rate one. In general, some more abstract information like BW, latency or performance level (P-state) should be the ones to be exposed at driver level. It's definitely true, that, say, the SDMA driver should not specify its interconnect bandwidth requirements in terms of an interconnect clock frequency. It should specify some variant of bytes per second. But that's only possible because the goal is to provide the interconnect driver with have enough information to convert the bandwidth constraint to a clock rate
Re: Common clock and dvfs
On Wed, 4 May 2011, Colin Cross wrote: Imagine a chip where a clock can feed devices A, B, and C. If the devices are always clocked at the same rate, and can't gate their clocks, the minimum voltage that can be applied to a rail is determined ONLY by the rate of the clock. That's not so -- although admittedly it's a side issue, and not particularly related to DVFS. For example, the device may have some external I/O lines which need to be at least some minimum voltage level for the externally-connected device to function. This minimum voltage level can be unrelated to the device's clock frequency. - Paul -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Common clock and dvfs
On Wed, May 4, 2011 at 11:35 PM, Paul Walmsley p...@pwsan.com wrote: On Wed, 4 May 2011, Colin Cross wrote: Imagine a chip where a clock can feed devices A, B, and C. If the devices are always clocked at the same rate, and can't gate their clocks, the minimum voltage that can be applied to a rail is determined ONLY by the rate of the clock. That's not so -- although admittedly it's a side issue, and not particularly related to DVFS. For example, the device may have some external I/O lines which need to be at least some minimum voltage level for the externally-connected device to function. This minimum voltage level can be unrelated to the device's clock frequency. True, that was an oversimplificaiton. I meant the minimum voltage that scales with clock frequencies only depends on the clock frequency, not the device. Devices do need to be able to specify a higher minimum voltage, and the regulator api needs to handle it. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/5] OMAP4: DSS2: HDMI: Add support for audio
This is to add support for HDMI audio on OMAP4 chips. This work has two parts: DSS implementation and ASoC implementation. This set of patches presents the DSS implementation. The approach is to utilize the DSS HDMI driver to act as an ASoC codec. Then, functionality and data structures are added to the DSS HDMI driver to configure parameters relevant to audio such as sample rate and frequency and DMA. The ASoC implementation adds an HDMI audio card that will utilize this HDMI ASoC codec. The ASoC implementation is also under review in the alsa-devel list. This implementation is for Basic Audio as defined in CEA-861-D: 16 bit/sample linear PCM 2-channel audio with sample rates of 32, 44.1 and 48kHz. As described in the HDMI specification, support for Basic Audio is mandatory for HDMI sinks and does not require of EDID parsing. Additionally, this implementation supports 24-bit samples in 32-bit words. Further audio capabilities such as more sample rates and multichannel audio will be added in the future when EDID parsing is available for HDMI driver. This implementation is based on on: * OMAP4: DSS2: Add dss_dss_clk opt clock for OMAP4, by Sumit Semwal (http://gitorious.org/linux-omap-dss2/linux/commit/0da5637569bb9bf93e6930cd1c3b452eede50ba2) * Kernel 2.6.39-rc6 (git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git v2.6.39-rc6) In order to validate functionality, it is necessary to utilize the ASoC HDMI CPU and machine drivers for HDMI on OMAP4. The complete implementation, DSS and ASoC parts, is available at: git://gitorious.org/omap-audio/linux-audio.git ricardon/topic/hdmi-audio-v1 Verification: Penguins on HDMI display with audio playback with sample rates of 32, 44.1 and 48kHz and 16-bit and 24-bit (in 32-bit word) sample format. Audio playback verified using ALSA aplay. Validation was performed on SDP4430 ES2.1 and Panda ES2.1 and ES2.0. Ricardo Neri (5): OMAP4: DSS2: Create a DSS features structure for OMAP4430 ES1.0 OMAP4: DSS2: HDMI: Add DSS feature for CTS calculation OMAP4: DSS2: HDMI: Add enums and structures for audio OMAP4: DSS2: HDMI: Add functionality for audio configuration OMAP4: DSS2: HDMI: Implement ASoC Codec driver for HDMI audio drivers/video/omap2/dss/dss_features.c | 29 ++- drivers/video/omap2/dss/dss_features.h |1 + drivers/video/omap2/dss/hdmi.c | 432 drivers/video/omap2/dss/hdmi.h | 220 - 4 files changed, 678 insertions(+), 4 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/5] OMAP4: DSS2: HDMI: Add DSS feature for CTS calculation
CTS and N parameters are used to regenerate the audio clock from the TMDS clock at the HDMI sink. In OMAP4430 ES1.0 version the calculation of the CTS parameter is done by the HDMI IP (hardware mode) while in others it must be done by the HDMI driver (software mode). A DSS feature is used to indicate the HDMI driver which mode is used. Signed-off-by: Ricardo Neri ricardo.n...@ti.com --- drivers/video/omap2/dss/dss_features.c |3 ++- drivers/video/omap2/dss/dss_features.h |1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 6c57af4..cfcc12b 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -308,7 +308,8 @@ static struct omap_dss_features omap4_dss_features = { .has_feature= FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | - FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC, + FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | + FEAT_HDMI_CTS_SWMODE, .num_mgrs = 3, .num_ovls = 3, diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 12e9c4e..a732c24 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -40,6 +40,7 @@ enum dss_feat_id { /* Independent core clk divider */ FEAT_CORE_CLK_DIV = 1 11, FEAT_LCD_CLK_SRC= 1 12, + FEAT_HDMI_CTS_SWMODE = 1 13, }; /* DSS register field id */ -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/5] OMAP4: DSS2: Create a DSS features structure for OMAP4430 ES1.0
Create a separate DSS features structure for OMAP4430 ES1.0. This structure is used to expose features only present in such silicon version. Specifically, this is required to handle how the HDMI IP calculates the CTS parameter for audio clock regeneration packets. OMAP4430 ES1.0 is the only one that supports computation of the CTS parameter by the HDMI IP (hardware mode). The rest of the revisions require the HDMI driver to perform the computation. Signed-off-by: Ricardo Neri ricardo.n...@ti.com --- drivers/video/omap2/dss/dss_features.c | 26 +- 1 files changed, 25 insertions(+), 1 deletions(-) diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index aa16222..6c57af4 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -282,6 +282,25 @@ static struct omap_dss_features omap3630_dss_features = { }; /* OMAP4 DSS Features */ +/* For OMAP4430 ES 1.0 revision */ +static struct omap_dss_features omap4430_es1_0_dss_features = { + .reg_fields = omap4_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), + + .has_feature= + FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | + FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | + FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC, + + .num_mgrs = 3, + .num_ovls = 3, + .supported_displays = omap4_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, + .clksrc_names = omap4_dss_clk_source_names, + .dss_params = omap4_dss_param_range, +}; + +/* For all the other OMAP4 versions */ static struct omap_dss_features omap4_dss_features = { .reg_fields = omap4_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), @@ -299,6 +318,7 @@ static struct omap_dss_features omap4_dss_features = { .dss_params = omap4_dss_param_range, }; + /* Functions returning values related to a DSS feature */ int dss_feat_get_num_mgrs(void) { @@ -365,6 +385,10 @@ void dss_features_init(void) omap_current_dss_features = omap3630_dss_features; else if (cpu_is_omap34xx()) omap_current_dss_features = omap3430_dss_features; - else + else if (omap_rev() == OMAP4430_REV_ES1_0) + omap_current_dss_features = omap4430_es1_0_dss_features; + else if (cpu_is_omap44xx()) omap_current_dss_features = omap4_dss_features; + else + DSSWARN(Unsupported OMAP version); } -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/5] OMAP4: DSS2: HDMI: Add functionality for audio configuration
Add functionality for relevant audio configuration. Functions to configure the audio FIFO and DMA as well as functions for the audio core and Audio Info frame are included. This functionality is to be used by the ASoC HDMI audio codec. Signed-off-by: Ricardo Neri ricardo.n...@ti.com --- drivers/video/omap2/dss/hdmi.c | 215 1 files changed, 215 insertions(+), 0 deletions(-) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a981def..c5676ee 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -1275,6 +1275,221 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) mutex_unlock(hdmi.lock); } +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +static void hdmi_wp_audio_config_format( + struct hdmi_audio_format *aud_fmt) +{ + u32 r; + + DSSDBG(Enter hdmi_wp_audio_config_format\n); + + r = hdmi_read_reg(HDMI_WP_AUDIO_CFG); + r = FLD_MOD(r, aud_fmt-stereo_channels, 26, 24); + r = FLD_MOD(r, aud_fmt-active_chnnls_msk, 23, 16); + r = FLD_MOD(r, aud_fmt-en_sig_blk_strt_end, 5, 5); + r = FLD_MOD(r, aud_fmt-type, 4, 4); + r = FLD_MOD(r, aud_fmt-justification, 3, 3); + r = FLD_MOD(r, aud_fmt-sample_order, 2, 2); + r = FLD_MOD(r, aud_fmt-samples_per_word, 1, 1); + r = FLD_MOD(r, aud_fmt-sample_size, 0, 0); + hdmi_write_reg(HDMI_WP_AUDIO_CFG, r); +} + +static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma) +{ + u32 r; + + DSSDBG(Enter hdmi_wp_audio_config_dma\n); + + r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2); + r = FLD_MOD(r, aud_dma-transfer_size, 15, 8); + r = FLD_MOD(r, aud_dma-block_size, 7, 0); + hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r); + + r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL); + r = FLD_MOD(r, aud_dma-mode, 9, 9); + r = FLD_MOD(r, aud_dma-fifo_threshold, 8, 0); + hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r); +} + +static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg) +{ + u32 r; + + /* audio clock recovery parameters */ + r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL); + r = FLD_MOD(r, cfg-use_mclk, 2, 2); + r = FLD_MOD(r, cfg-en_acr_pkt, 1, 1); + r = FLD_MOD(r, cfg-cts_mode, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r); + + REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg-n, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg-n 8, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg-n 16, 7, 0); + + if (cfg-cts_mode == HDMI_AUDIO_CTS_MODE_SW) { + REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg-cts, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg-cts 8, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg-cts 16, 7, 0); + } else { + /* +* HDMI IP uses this configuration to divide the MCLK to +* update CTS value. +*/ + REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg-mclk_mode, 2, 0); + + /* Configure clock for audio packets */ + REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1, + cfg-aud_par_busclk, 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2, + (cfg-aud_par_busclk 8), 7, 0); + REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3, + (cfg-aud_par_busclk 16), 7, 0); + } + + /* Override of SPDIF sample frequency with value in I2S_CHST4 */ + REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg-fs_override, 1, 1); + + /* I2S parameters */ + REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg-freq_sample, 3, 0); + + r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL); + r = FLD_MOD(r, cfg-i2s_cfg.en_high_bitrate_aud, 7, 7); + r = FLD_MOD(r, cfg-i2s_cfg.sck_edge_mode, 6, 6); + r = FLD_MOD(r, cfg-i2s_cfg.cbit_order, 5, 5); + r = FLD_MOD(r, cfg-i2s_cfg.vbit, 4, 4); + r = FLD_MOD(r, cfg-i2s_cfg.ws_polarity, 3, 3); + r = FLD_MOD(r, cfg-i2s_cfg.justification, 2, 2); + r = FLD_MOD(r, cfg-i2s_cfg.direction, 1, 1); + r = FLD_MOD(r, cfg-i2s_cfg.shift, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r); + + r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5); + r = FLD_MOD(r, cfg-freq_sample, 7, 4); + r = FLD_MOD(r, cfg-i2s_cfg.word_length, 3, 1); + r = FLD_MOD(r, cfg-i2s_cfg.word_max_length, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r); + + REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg-i2s_cfg.in_length_bits, 3, 0); + + /* Audio channels and mode parameters */ + REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg-layout, 2, 1); + r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE); + r = FLD_MOD(r, cfg-i2s_cfg.active_sds, 7, 4); + r = FLD_MOD(r, cfg-en_dsd_audio, 3, 3); + r = FLD_MOD(r, cfg-en_parallel_aud_input, 2, 2); +
[PATCH 5/5] OMAP4: DSS2: HDMI: Implement ASoC Codec driver for HDMI audio
Implement an ASoC Codec Driver to handle audio configuration. The implementation offers an interface for audio configuration and control to be exposed to ALSA while hidding the HDMI details. The ASoC driver supports the Basic Audio configuration as described in CEA-861-D: 2-channel linear PCM with 32, 44.1 and 48kHz sample rates and 16 bits/sample. It additionally supports 24 bit/sample in 32-bit words. Signed-off-by: Ricardo Neri ricardo.n...@ti.com --- drivers/video/omap2/dss/hdmi.c | 217 1 files changed, 217 insertions(+), 0 deletions(-) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index c5676ee..91b11a1 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -30,9 +30,15 @@ #include linux/delay.h #include linux/string.h #include plat/display.h +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +#include sound/soc.h +#include sound/pcm_params.h +#endif #include dss.h #include hdmi.h +#include dss_features.h static struct { struct mutex lock; @@ -1488,12 +1494,207 @@ static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts) return 0; } + +static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdmi_audio_format audio_format; + struct hdmi_audio_dma audio_dma; + struct hdmi_core_audio_config core_cfg; + struct hdmi_core_infoframe_audio aud_if_cfg; + int err, n, cts; + enum hdmi_core_audio_sample_freq sample_freq; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + core_cfg.i2s_cfg.word_max_length = + HDMI_AUDIO_I2S_MAX_WORD_20BITS; + core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; + core_cfg.i2s_cfg.in_length_bits = + HDMI_AUDIO_I2S_INPUT_LENGTH_16; + core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; + audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; + audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; + audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; + audio_dma.transfer_size = 0x10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + core_cfg.i2s_cfg.word_max_length = + HDMI_AUDIO_I2S_MAX_WORD_24BITS; + core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; + core_cfg.i2s_cfg.in_length_bits = + HDMI_AUDIO_I2S_INPUT_LENGTH_24; + audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; + audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; + audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; + core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; + audio_dma.transfer_size = 0x20; + break; + default: + return -EINVAL; + } + + switch (params_rate(params)) { + case 32000: + sample_freq = HDMI_AUDIO_FS_32000; + break; + case 44100: + sample_freq = HDMI_AUDIO_FS_44100; + break; + case 48000: + sample_freq = HDMI_AUDIO_FS_48000; + break; + default: + return -EINVAL; + } + + err = hdmi_config_audio_acr(params_rate(params), n, cts); + if (err 0) + return err; + + /* Audio wrapper config */ + audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; + audio_format.active_chnnls_msk = 0x03; + audio_format.type = HDMI_AUDIO_TYPE_LPCM; + audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; + /* Disable start/stop signals of IEC 60958 blocks */ + audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; + + audio_dma.block_size = 0xC0; + audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; + audio_dma.fifo_threshold = 0x20; /* in number of samples */ + + hdmi_wp_audio_config_dma(audio_dma); + hdmi_wp_audio_config_format(audio_format); + + /* +* I2S config +*/ + core_cfg.i2s_cfg.en_high_bitrate_aud = false; + /* Only used with high bitrate audio */ + core_cfg.i2s_cfg.cbit_order = false; + /* Serial data and word select should change on sck rising edge */ + core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; + core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; + /* Set I2S word select polarity */ + core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; + core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; + /* Set serial
[PATCH 3/5] OMAP4: DSS2: HDMI: Add enums and structures for audio
Add enurations and structures for audio configuration. This includes enumerations for the Audio InfoFrame, I2S, audio FIFO and audio core. Signed-off-by: Ricardo Neri ricardo.n...@ti.com --- drivers/video/omap2/dss/hdmi.h | 220 +++- 1 files changed, 218 insertions(+), 2 deletions(-) diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h index 9887ab9..1a5da3c 100644 --- a/drivers/video/omap2/dss/hdmi.h +++ b/drivers/video/omap2/dss/hdmi.h @@ -48,6 +48,10 @@ struct hdmi_reg { u16 idx; }; #define HDMI_WP_VIDEO_TIMING_H HDMI_WP_REG(0x68) #define HDMI_WP_VIDEO_TIMING_V HDMI_WP_REG(0x6C) #define HDMI_WP_WP_CLK HDMI_WP_REG(0x70) +#define HDMI_WP_AUDIO_CFG HDMI_WP_REG(0x80) +#define HDMI_WP_AUDIO_CFG2 HDMI_WP_REG(0x84) +#define HDMI_WP_AUDIO_CTRL HDMI_WP_REG(0x88) +#define HDMI_WP_AUDIO_DATA HDMI_WP_REG(0x8C) /* HDMI IP Core System */ #define HDMI_CORE_SYS_REG(idx) HDMI_REG(HDMI_CORE_SYS + idx) @@ -105,6 +109,8 @@ struct hdmi_reg { u16 idx; }; #define HDMI_CORE_AV_AVI_DBYTE_NELEMS HDMI_CORE_AV_REG(15) #define HDMI_CORE_AV_SPD_DBYTE HDMI_CORE_AV_REG(0x190) #define HDMI_CORE_AV_SPD_DBYTE_NELEMS HDMI_CORE_AV_REG(27) +#define HDMI_CORE_AV_AUD_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x210) +#define HDMI_CORE_AV_AUD_DBYTE_NELEMS HDMI_CORE_AV_REG(10) #define HDMI_CORE_AV_MPEG_DBYTEHDMI_CORE_AV_REG(0x290) #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS HDMI_CORE_AV_REG(27) #define HDMI_CORE_AV_GEN_DBYTE HDMI_CORE_AV_REG(0x300) @@ -153,6 +159,10 @@ struct hdmi_reg { u16 idx; }; #define HDMI_CORE_AV_SPD_VERS HDMI_CORE_AV_REG(0x184) #define HDMI_CORE_AV_SPD_LEN HDMI_CORE_AV_REG(0x188) #define HDMI_CORE_AV_SPD_CHSUM HDMI_CORE_AV_REG(0x18C) +#define HDMI_CORE_AV_AUDIO_TYPEHDMI_CORE_AV_REG(0x200) +#define HDMI_CORE_AV_AUDIO_VERSHDMI_CORE_AV_REG(0x204) +#define HDMI_CORE_AV_AUDIO_LEN HDMI_CORE_AV_REG(0x208) +#define HDMI_CORE_AV_AUDIO_CHSUM HDMI_CORE_AV_REG(0x20C) #define HDMI_CORE_AV_MPEG_TYPE HDMI_CORE_AV_REG(0x280) #define HDMI_CORE_AV_MPEG_VERS HDMI_CORE_AV_REG(0x284) #define HDMI_CORE_AV_MPEG_LEN HDMI_CORE_AV_REG(0x288) @@ -272,7 +282,7 @@ enum hdmi_core_packet_ctrl { HDMI_PACKETREPEATOFF = 0 }; -/* INFOFRAME_AVI_ definitions */ +/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */ enum hdmi_core_infoframe { HDMI_INFOFRAME_AVI_DB1Y_RGB = 0, HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1, @@ -317,7 +327,36 @@ enum hdmi_core_infoframe { HDMI_INFOFRAME_AVI_DB5PR_7 = 6, HDMI_INFOFRAME_AVI_DB5PR_8 = 7, HDMI_INFOFRAME_AVI_DB5PR_9 = 8, - HDMI_INFOFRAME_AVI_DB5PR_10 = 9 + HDMI_INFOFRAME_AVI_DB5PR_10 = 9, + HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0, + HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1, + HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2, + HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3, + HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4, + HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5, + HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6, + HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7, + HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8, + HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9, + HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10, + HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11, + HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12, + HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13, + HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14, + HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0, + HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1, + HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2, + HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3, + HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4, + HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5, + HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6, + HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7, + HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0, + HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1, + HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2, + HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3, + HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0, + HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1 }; enum hdmi_packing_mode { @@ -327,6 +366,121 @@ enum hdmi_packing_mode { HDMI_PACK_ALREADYPACKED = 7 }; +enum hdmi_core_audio_sample_freq { + HDMI_AUDIO_FS_32000 = 0x3, + HDMI_AUDIO_FS_44100 = 0x0, + HDMI_AUDIO_FS_48000 = 0x2, + HDMI_AUDIO_FS_88200 = 0x8, + HDMI_AUDIO_FS_96000 = 0xA, + HDMI_AUDIO_FS_176400 = 0xC, + HDMI_AUDIO_FS_192000 = 0xE, + HDMI_AUDIO_FS_NOT_INDICATED = 0x1 +}; + +enum hdmi_core_audio_layout { + HDMI_AUDIO_LAYOUT_2CH = 0, + HDMI_AUDIO_LAYOUT_8CH =
RE: [PATCH] rtc-twl: Switch to using threaded irq
Hi, Tony and John: What would be the appropriate path for this patch? Cheers, Ilkka On Apr 13, 2011 Krishnamoorthy, Balaji T wrote: On Wed, Mar 16, 2011 at 9:37 PM, Ilkka Koskinen ilkka.koski...@nokia.com wrote: The driver is accessing to i2c bus in interrupt handler. Therefore, it should use threaded irq. Acked-by: Balaji T K balaj...@ti.com Signed-off-by: Ilkka Koskinen ilkka.koski...@nokia.com --- drivers/rtc/rtc-twl.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index ed1b868..2715b96 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -475,7 +475,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) if (ret 0) goto out1; - ret = request_irq(irq, twl_rtc_interrupt, + ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt, IRQF_TRIGGER_RISING, dev_name(rtc-dev), rtc); if (ret 0) { -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[Patch v1] AM35xx-Craneboard:Update
From: Srinath.R srin...@mistralsolutions.com Replaced gpio_request()/gpio_direction_output() with gpio_request_one() in am3517_crane_init. Signed-off-by: Srinath.R srin...@mistralsolutions.com --- arch/arm/mach-omap2/board-am3517crane.c | 10 ++ 1 files changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c index a890d24..b8c7150 100644 --- a/arch/arm/mach-omap2/board-am3517crane.c +++ b/arch/arm/mach-omap2/board-am3517crane.c @@ -89,19 +89,13 @@ static void __init am3517_crane_init(void) return; } - ret = gpio_request(GPIO_USB_POWER, usb_ehci_enable); + ret = gpio_request_one(GPIO_USB_POWER, GPIOF_OUT_INIT_HIGH, + usb_ehci_enable); if (ret 0) { pr_err(Can not request GPIO %d\n, GPIO_USB_POWER); return; } - ret = gpio_direction_output(GPIO_USB_POWER, 1); - if (ret 0) { - gpio_free(GPIO_USB_POWER); - pr_err(Unable to initialize EHCI power\n); - return; - } - usbhs_init(usbhs_bdata); } -- 1.5.3.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [Patch v1] AM35xx-Craneboard:Update
Hi Srinath, On 05/05/11 10:15, srin...@mistralsolutions.com wrote: From: Srinath.R srin...@mistralsolutions.com Replaced gpio_request()/gpio_direction_output() with gpio_request_one() in am3517_crane_init. This has been already done and waits for Tony to apply. Please, see: http://www.spinics.net/lists/arm-kernel/msg123823.html -- Regards, Igor. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] OMAP: DSS2: Add new color formats
Added new color formats supported by OMAP4. Signed-off-by: Amber Jain am...@ti.com --- arch/arm/plat-omap/include/plat/display.h |5 ++ drivers/video/omap2/dss/dispc.c | 107 - drivers/video/omap2/dss/dss_features.c| 43 +++- drivers/video/omap2/dss/manager.c |7 ++ 4 files changed, 129 insertions(+), 33 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 43b887b..1b8d83a 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -88,6 +88,11 @@ enum omap_color_mode { OMAP_DSS_COLOR_ARGB32 = 1 11, /* ARGB32 */ OMAP_DSS_COLOR_RGBA32 = 1 12, /* RGBA32 */ OMAP_DSS_COLOR_RGBX32 = 1 13, /* RGBx32 */ + OMAP_DSS_COLOR_NV12 = 1 14, /* NV12 format: YUV 4:2:0 */ + OMAP_DSS_COLOR_RGBA16 = 1 15, /* RGBA16 - */ + OMAP_DSS_COLOR_RGBX16 = 1 16, /* RGBx16 - */ + OMAP_DSS_COLOR_ARGB16_1555 = 1 17, /* ARGB16 - 1555 */ + OMAP_DSS_COLOR_XRGB16_1555 = 1 18, /* xRGB16 - 1555 */ }; enum omap_lcd_display_type { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 4ed2ecf..f5a15dc 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -896,38 +896,76 @@ static void _dispc_set_color_mode(enum omap_plane plane, enum omap_color_mode color_mode) { u32 m = 0; - - switch (color_mode) { - case OMAP_DSS_COLOR_CLUT1: - m = 0x0; break; - case OMAP_DSS_COLOR_CLUT2: - m = 0x1; break; - case OMAP_DSS_COLOR_CLUT4: - m = 0x2; break; - case OMAP_DSS_COLOR_CLUT8: - m = 0x3; break; - case OMAP_DSS_COLOR_RGB12U: - m = 0x4; break; - case OMAP_DSS_COLOR_ARGB16: - m = 0x5; break; - case OMAP_DSS_COLOR_RGB16: - m = 0x6; break; - case OMAP_DSS_COLOR_RGB24U: - m = 0x8; break; - case OMAP_DSS_COLOR_RGB24P: - m = 0x9; break; - case OMAP_DSS_COLOR_YUV2: - m = 0xa; break; - case OMAP_DSS_COLOR_UYVY: - m = 0xb; break; - case OMAP_DSS_COLOR_ARGB32: - m = 0xc; break; - case OMAP_DSS_COLOR_RGBA32: - m = 0xd; break; - case OMAP_DSS_COLOR_RGBX32: - m = 0xe; break; - default: - BUG(); break; + if (plane != OMAP_DSS_GFX) { + switch (color_mode) { + case OMAP_DSS_COLOR_NV12: + m = 0x0; break; + case OMAP_DSS_COLOR_RGB12U: + m = 0x1; break; + case OMAP_DSS_COLOR_RGBA16: + m = 0x2; break; + case OMAP_DSS_COLOR_RGBX16: + m = 0x4; break; + case OMAP_DSS_COLOR_ARGB16: + m = 0x5; break; + case OMAP_DSS_COLOR_RGB16: + m = 0x6; break; + case OMAP_DSS_COLOR_ARGB16_1555: + m = 0x7; break; + case OMAP_DSS_COLOR_RGB24U: + m = 0x8; break; + case OMAP_DSS_COLOR_RGB24P: + m = 0x9; break; + case OMAP_DSS_COLOR_YUV2: + m = 0xA; break; + case OMAP_DSS_COLOR_UYVY: + m = 0xB; break; + case OMAP_DSS_COLOR_ARGB32: + m = 0xC; break; + case OMAP_DSS_COLOR_RGBA32: + m = 0xD; break; + case OMAP_DSS_COLOR_RGBX32: + m = 0xE; break; + case OMAP_DSS_COLOR_XRGB16_1555: + m = 0xF; break; + default: + BUG(); break; + } + } else { + switch (color_mode) { + case OMAP_DSS_COLOR_CLUT1: + m = 0x0; break; + case OMAP_DSS_COLOR_CLUT2: + m = 0x1; break; + case OMAP_DSS_COLOR_CLUT4: + m = 0x2; break; + case OMAP_DSS_COLOR_CLUT8: + m = 0x3; break; + case OMAP_DSS_COLOR_RGB12U: + m = 0x4; break; + case OMAP_DSS_COLOR_ARGB16: + m = 0x5; break; + case OMAP_DSS_COLOR_RGB16: + m = 0x6; break; + case OMAP_DSS_COLOR_ARGB16_1555: + m = 0x7; break; + case OMAP_DSS_COLOR_RGB24U: + m = 0x8; break; + case OMAP_DSS_COLOR_RGB24P: + m = 0x9; break; + case OMAP_DSS_COLOR_YUV2: + m = 0xa; break; + case
[PATCH] arm: omap3: cm-t35: add support for cm-t3730
cm-t3730 is basically the same board as cm-t35, but has DM3730 SoC assembled and therefore some changes are required. Signed-off-by: Igor Grinberg grinb...@compulab.co.il --- arch/arm/mach-omap2/Kconfig|2 +- arch/arm/mach-omap2/board-cm-t35.c | 62 +++- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index b997a35..920b6bc 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -266,7 +266,7 @@ config MACH_OMAP_ZOOM3 select REGULATOR_FIXED_VOLTAGE config MACH_CM_T35 - bool CompuLab CM-T35 module + bool CompuLab CM-T35/CM-T3730 modules depends on ARCH_OMAP3 default y select OMAP_PACKAGE_CUS diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 6063be8..c0f6ce0 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -524,7 +524,7 @@ static void __init cm_t35_init_early(void) } #ifdef CONFIG_OMAP_MUX -static struct omap_board_mux board_mux[] __initdata = { +static struct omap_board_mux cm_t35_common_board_mux[] __initdata = { /* nCS and IRQ for CM-T35 ethernet */ OMAP3_MUX(GPMC_NCS5, OMAP_MUX_MODE0), OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP), @@ -580,17 +580,12 @@ static struct omap_board_mux board_mux[] __initdata = { OMAP3_MUX(UART1_TX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(UART1_RX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), - /* DSS */ + /* common DSS */ OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), @@ -603,12 +598,6 @@ static struct omap_board_mux board_mux[] __initdata = { OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA20, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), /* display controls */ OMAP3_MUX(MCBSP1_FSR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), @@ -621,6 +610,39 @@ static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, }; + +static void cm_t35_mux_init(void) +{ + int mux_mode = OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT; + + omap3_mux_init(cm_t35_common_board_mux, OMAP_PACKAGE_CUS); + + if (cpu_is_omap34xx()) { + omap_mux_init_signal(gpio_70, mux_mode); + omap_mux_init_signal(gpio_71, mux_mode); + omap_mux_init_signal(gpio_72, mux_mode); + omap_mux_init_signal(gpio_73, mux_mode); + omap_mux_init_signal(gpio_74, mux_mode); + omap_mux_init_signal(gpio_75, mux_mode); + } else if (cpu_is_omap3630()) { + mux_mode = OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT; + omap_mux_init_signal(sys_boot0, mux_mode); + omap_mux_init_signal(sys_boot1, mux_mode); + omap_mux_init_signal(sys_boot3, mux_mode); + omap_mux_init_signal(sys_boot4, mux_mode); + omap_mux_init_signal(sys_boot5, mux_mode); + omap_mux_init_signal(sys_boot6, mux_mode); + } + + omap_mux_init_signal(dss_data18, mux_mode); + omap_mux_init_signal(dss_data19, mux_mode); + omap_mux_init_signal(dss_data20, mux_mode); + omap_mux_init_signal(dss_data21, mux_mode); + omap_mux_init_signal(dss_data22, mux_mode); + omap_mux_init_signal(dss_data23, mux_mode); +} +#else +static inline void cm_t35_mux_init(void) {} #endif static struct omap_board_config_kernel cm_t35_config[] __initdata = { @@ -630,7 +652,7 @@ static void __init cm_t35_init(void) { omap_board_config = cm_t35_config; omap_board_config_size = ARRAY_SIZE(cm_t35_config); -
RE: [PATCH v2 5/7] OMAP: DSS: Adding initialization routine to picodlp panel
On Wed, 2011-05-04 at 20:01 +0530, Janorkar, Mayuresh wrote: -Original Message- From: Valkeinen, Tomi Sent: Wednesday, May 04, 2011 12:28 AM To: Janorkar, Mayuresh Cc: linux-omap@vger.kernel.org; K, Mythri P Subject: Re: [PATCH v2 5/7] OMAP: DSS: Adding initialization routine to picodlp panel On Mon, 2011-05-02 at 20:22 +0530, Mayuresh Janorkar wrote: From: Mythri P K mythr...@ti.com picodlp_i2c_client needs to send commands over i2c as a part of initialiazation. system controller dlp pico processor dpp2600 is used. It configures the splash screen of picodlp using a sequence of commands. A programmer's guide is available at: http://focus.ti.com/lit/ug/dlpu002a/dlpu002a.pdf API is defined for sending command over i2c as an i2c_write operation. Signed-off-by: Mythri P K mythr...@ti.com Signed-off-by: Mayuresh Janorkar ma...@ti.com --- Changes since v1: 1. Removed initial splash screen 2. i2c_commands regrouped 3. Removed long msleep 4. Added try-after-sleep in i2c_write drivers/video/omap2/displays/panel-picodlp.c | 212 ++ 1 files changed, 212 insertions(+), 0 deletions(-) diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index fdbfdcf..493a411 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -32,7 +32,15 @@ #include plat/display.h #include plat/panel-picodlp.h +#include panel-picodlp.h + #define DRIVER_NAME picodlp_i2c_driver + +/* This defines the minit of data which is allowed into single write block */ +#define MAX_I2C_WRITE_BLOCK_SIZE 32 +#define PICO_MAJOR 1 /* 2 bits */ +#define PICO_MINOR 1 /* 2 bits */ + struct picodlp_data { struct mutex lock; struct i2c_client *picodlp_i2c_client; @@ -50,6 +58,11 @@ struct i2c_device_id picodlp_i2c_id[] = { { picodlp_i2c_driver, 0 }, }; +struct picodlp_i2c_command { + u8 reg; + u32 value; +}; + static struct omap_video_timings pico_ls_timings = { .x_res = 864, .y_res = 480, @@ -70,6 +83,197 @@ static inline struct picodlp_panel_data return (struct picodlp_panel_data *) dssdev-data; } +static int picodlp_i2c_write_block(struct i2c_client *client, + u8 *data, int len) +{ + struct i2c_msg msg; + int i, r, msg_count = 1, trial = 4; + + struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); + + if (len 1 || len MAX_I2C_WRITE_BLOCK_SIZE) { + dev_err(client-dev, + too long syn_write_block len %d\n, len); + return -EIO; + } +retry: + mutex_lock(picodlp_i2c_data-xfer_lock); + + msg.addr = client-addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + r = i2c_transfer(client-adapter, msg, msg_count); + mutex_unlock(picodlp_i2c_data-xfer_lock); + + /* + * i2c_transfer returns: + * number of messages sent in case of success + * a negative error number in case of failure + * i2c controller might timeout, in such a case sleep for sometime + * and then retry + */ + if (r != msg_count) { + msleep(2); + if (trial--) + goto retry; This is not good. Hacks like these should only be used as a last option. I'm still saying that you should find the document mentioned in the documents you have. I refuse to believe that we (TI) do not know what our hardware does, especially in a basic issue like this. I'm 99% sure there is documentation telling the required power-up sequence. And if that 1% happens, we should find the HW designers and yell at them until they make the documents. Yes it is mentioned. You can check it here: https://focus.ti.com/myti/docs/extranet.tsp?sectionId=403 A delay is required after i2c client creation and it is 1 second. So this part of code would be removed. The document says that time between when PWRGOOD goes high and when the first i2c command can be sent is 1 second. (although I have no idea what PWRGOOD is since the gpio names in the code do not match any documents). In that case you should probably store the current time when PWRGOOD is set high, and wait before sending the first i2c commands so that one second has passed since PWRGOOD. If that happens in the same function it's most likely just the same to use msleep(1) there. Tomi -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] arm: omap3: cm-t35: add support for cm-t3730
On 05/05/11 11:53, Igor Grinberg wrote: cm-t3730 is basically the same board as cm-t35, but has DM3730 SoC assembled and therefore some changes are required. Signed-off-by: Igor Grinberg grinb...@compulab.co.il --- arch/arm/mach-omap2/Kconfig|2 +- arch/arm/mach-omap2/board-cm-t35.c | 62 +++- 2 files changed, 48 insertions(+), 16 deletions(-) Acked-by: Mike Rapoport m...@compulab.co.il diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index b997a35..920b6bc 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -266,7 +266,7 @@ config MACH_OMAP_ZOOM3 select REGULATOR_FIXED_VOLTAGE config MACH_CM_T35 - bool CompuLab CM-T35 module + bool CompuLab CM-T35/CM-T3730 modules depends on ARCH_OMAP3 default y select OMAP_PACKAGE_CUS diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 6063be8..c0f6ce0 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -524,7 +524,7 @@ static void __init cm_t35_init_early(void) } #ifdef CONFIG_OMAP_MUX -static struct omap_board_mux board_mux[] __initdata = { +static struct omap_board_mux cm_t35_common_board_mux[] __initdata = { /* nCS and IRQ for CM-T35 ethernet */ OMAP3_MUX(GPMC_NCS5, OMAP_MUX_MODE0), OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP), @@ -580,17 +580,12 @@ static struct omap_board_mux board_mux[] __initdata = { OMAP3_MUX(UART1_TX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(UART1_RX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), - /* DSS */ + /* common DSS */ OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), @@ -603,12 +598,6 @@ static struct omap_board_mux board_mux[] __initdata = { OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA20, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), - OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), /* display controls */ OMAP3_MUX(MCBSP1_FSR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), @@ -621,6 +610,39 @@ static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, }; + +static void cm_t35_mux_init(void) +{ + int mux_mode = OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT; + + omap3_mux_init(cm_t35_common_board_mux, OMAP_PACKAGE_CUS); + + if (cpu_is_omap34xx()) { + omap_mux_init_signal(gpio_70, mux_mode); + omap_mux_init_signal(gpio_71, mux_mode); + omap_mux_init_signal(gpio_72, mux_mode); + omap_mux_init_signal(gpio_73, mux_mode); + omap_mux_init_signal(gpio_74, mux_mode); + omap_mux_init_signal(gpio_75, mux_mode); + } else if (cpu_is_omap3630()) { + mux_mode = OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT; + omap_mux_init_signal(sys_boot0, mux_mode); + omap_mux_init_signal(sys_boot1, mux_mode); + omap_mux_init_signal(sys_boot3, mux_mode); + omap_mux_init_signal(sys_boot4, mux_mode); + omap_mux_init_signal(sys_boot5, mux_mode); + omap_mux_init_signal(sys_boot6, mux_mode); + } + + omap_mux_init_signal(dss_data18, mux_mode); + omap_mux_init_signal(dss_data19, mux_mode); + omap_mux_init_signal(dss_data20, mux_mode); + omap_mux_init_signal(dss_data21, mux_mode); + omap_mux_init_signal(dss_data22, mux_mode); + omap_mux_init_signal(dss_data23, mux_mode); +} +#else +static inline void cm_t35_mux_init(void) {} #endif static struct omap_board_config_kernel cm_t35_config[] __initdata = { @@ -630,7 +652,7 @@ static void __init cm_t35_init(void) { omap_board_config = cm_t35_config;
Re: Is there boot logo support for OMAP3530?
Hi Elvis, Thanks for the information.. On Wednesday 04 May 2011 04:44 PM, Elvis Dowson wrote: Hi, On May 4, 2011, at 12:59 PM, Mohamed Thalib H wrote: Is boot logo not supported in OMAP3530? There are two ways you can add a boot logo to your target platform (Overo or BeagleBoard), one is to modify u-boot so that a boot logo is display immediately after powering on the system. The other is to add the boot logo to the kernel, in which case you have run 'make menuconfig', go to Device Drivers - Graphics - OMAP 2/3 display subysystem and somewhere in those options, you will see a boot logo option. I prefer the u-boot option. The standard Overo distribution images have the linux boot option (you'll see a penguin on boot) I was missing some options in the kernel config. after setting those I can see the penguin on boot. To embed your logo within u-boot, you will need to modify the Denx u-boot sources. v2010.06 works from the denx git repo. I had some issues with v2011.03 with the Overo. http://git.denx.de/?p=u-boot.git;a=summary What you will need to do is to use the linux gimp program to open a boot logo image file and save it as a C header file. After that, you can copy the *header_data array to the logo.h file for the target board; and adjust the beagle/overo_width and beagle/overo_height values to correctly reflect to your logo image size. Thanks for this pointer, I really need this since the logo can be shown very earlier. Elvis Dowson Best Regards, Mohamed Thalib H -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [Q] USB OTG host
Hi, On Wednesday 04 May 2011 07:33 PM, Jan Weitzel wrote: Hello, I am using drivers/usb/musb/omap2430.c for a board configured in MUSB_OTG mode. Is it correct that I need to load gadget driver to get it working as host? No. Host mode don't need gadget driver. Once OTG mode needs them. I got an USB_EVENT_ID event, but in musb_otg_notifications vbus will not switched on if !musb-gadget_driver. Any ideas? Kind regards, Jan Weitzel -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Mohamed Thalib H. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/22] OMAP: DMA: add omap_dma_has_sglist()
Simplify detection of the sglist feature and add a define for the super block end event that occurs with sglist transfers. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com CC: Venkatraman S svenk...@ti.com CC: Madhusudhan C madhu...@ti.com CC: Shilimkar Santosh santosh.shilim...@ti.com CC: Tony Lindgren t...@atomide.com --- arch/arm/plat-omap/dma.c |5 + arch/arm/plat-omap/include/plat/dma.h |3 +++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 7f64366..32a923a 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1862,6 +1862,11 @@ int omap_get_dma_chain_src_pos(int chain_id) EXPORT_SYMBOL(omap_get_dma_chain_src_pos); #endif /* ifndef CONFIG_ARCH_OMAP1 */ +int omap_dma_has_sglist_mode(void) +{ + return dma_caps0_status DMA_CAPS_SGLIST_SUPPORT; +} + int omap_set_dma_sglist_mode(int lch, struct omap_dma_sglist_node *sgparams, dma_addr_t padd, int nelem, struct omap_dma_channel_params *chparams) { diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h index 4d73eb1..3536eb4 100644 --- a/arch/arm/plat-omap/include/plat/dma.h +++ b/arch/arm/plat-omap/include/plat/dma.h @@ -209,6 +209,7 @@ #define OMAP2_DMA_SECURE_ERR_IRQ (1 9) #define OMAP2_DMA_SUPERVISOR_ERR_IRQ (1 10) #define OMAP2_DMA_MISALIGNED_ERR_IRQ (1 11) +#define OMAP2_DMA_SUPER_BLOCK_IRQ (1 14) #define OMAP_DMA_CCR_EN(1 7) #define OMAP_DMA_CCR_RD_ACTIVE (1 9) @@ -616,6 +617,8 @@ static inline int omap_lcd_dma_running(void) } #endif +extern int omap_dma_has_sglist_mode(void); + /** * omap_set_dma_sglist_mode() Switch channel to scatter gather mode * @lch: Logical channel to switch to sglist mode -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/22] mmc: omap hsmmc: adaptation of sdma descriptor
From: Venkatraman S svenk...@ti.com autoloading feature Start to use the sDMA descriptor autoloading feature. For large datablocks, the MMC driver has to repeatedly setup, program and teardown the dma channel for each element of the sglist received in omap_hsmmc_request. By using descriptor autoloading, transfers from / to each element of the sglist is pre programmed into a linked list. The sDMA driver completes the entire transaction and provides a single interrupt. Due to this, number of dma interrupts for a typical 100MB transfer on the MMC is reduced from 25000 to about 400 (approximate). Transfer speeds are improved by ~5%. (Though it varies on the size of read / write improves on huge transfers) Descriptor autoloading is available only in 3630 and 4430 (as of now). Hence normal DMA mode is also retained. Signed-off-by: Venkatraman S svenk...@ti.com CC: Madhusudhan C madhu...@ti.com CC: Shilimkar Santosh santosh.shilim...@ti.com CC: Tony Lindgren t...@atomide.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 147 ++-- 1 files changed, 125 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 259ece0..ebcef31 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -104,6 +104,8 @@ #define SRD(1 26) #define SOFTRESET (1 1) #define RESETDONE (1 0) +/* End of superblock indicator for sglist transfers */ +#define DMA_ICR_SGLIST_END 0x4D00 /* * FIXME: Most likely all the data using these _DEVID defines should come @@ -120,6 +122,12 @@ #define OMAP_MMC_MASTER_CLOCK 9600 #define DRIVER_NAMEomap_hsmmc +#define DMA_TYPE_NODMA 0 +#define DMA_TYPE_SDMA 1 +#define DMA_TYPE_SDMA_DLOAD 2 + +#define DMA_CTRL_BUF_SIZE (PAGE_SIZE * 3) + /* Timeouts for entering power saving states on inactivity, msec */ #define OMAP_MMC_DISABLED_TIMEOUT 100 #define OMAP_MMC_SLEEP_TIMEOUT 1000 @@ -172,7 +180,11 @@ struct omap_hsmmc_host { u32 bytesleft; int suspended; int irq; - int use_dma, dma_ch; + int dma_caps; + int dma_in_use; + int dma_ch; + void*dma_ctrl_buf; + dma_addr_t dma_ctrl_buf_phy; int dma_line_tx, dma_line_rx; int slot_id; int got_dbclk; @@ -561,7 +573,7 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, { unsigned int irq_mask; - if (host-use_dma) + if (host-dma_in_use) irq_mask = INT_EN_MASK ~(BRR_ENABLE | BWR_ENABLE); else irq_mask = INT_EN_MASK; @@ -851,7 +863,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, cmdreg = ~(DDIR); } - if (host-use_dma) + if (host-dma_in_use) cmdreg |= DMA_EN; host-req_in_progress = 1; @@ -880,7 +892,7 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ - if (mrq-data host-use_dma dma_ch != -1) + if (mrq-data host-dma_in_use dma_ch != -1) return; host-mrq = NULL; mmc_request_done(host-mmc, mrq); @@ -958,7 +970,7 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) host-dma_ch = -1; spin_unlock(host-irq_lock); - if (host-use_dma dma_ch != -1) { + if (host-dma_in_use dma_ch != -1) { dma_unmap_sg(mmc_dev(host-mmc), host-data-sg, host-dma_len, omap_hsmmc_get_dma_dir(host, host-data)); omap_free_dma(dma_ch); @@ -1310,7 +1322,6 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host, omap_hsmmc_get_dma_sync_dev(host, data), !(data-flags MMC_DATA_WRITE)); - omap_start_dma(dma_ch); } /* @@ -1334,13 +1345,16 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) return; } - host-dma_sg_idx++; - if (host-dma_sg_idx host-dma_len) { - /* Fire up the next transfer. */ - omap_hsmmc_config_dma_params(host, data, - data-sg + host-dma_sg_idx); - spin_unlock(host-irq_lock); - return; + if (host-dma_in_use == DMA_TYPE_SDMA) { + host-dma_sg_idx++; + if (host-dma_sg_idx host-dma_len) { + /* Fire up the next transfer. */ +
[PATCH 01/22] OMAP: sDMA: descriptor autoloading feature
From: Venkatraman S svenk...@ti.com Add sDMA driver support for descriptor autoloading feature. Descriptor autoloading is OMAP sDMA v5 hardware capability that can be exploited for scatter gather scenarios, currently available in OMAP3630 and OMAP4430. The feature works as described below. 1) A sDMA channel is programmed to be in 'linked list' mode. 2) The client (sDMA user) provides a list of descriptors in a linked list format. 3) Each of the 'descriptor' (element in the linked list) contains an updated set of DMA configuration register values. 4) Client starts DMA transfer. 5) sDMA controller loads the first element to its register configuration memory and executes the transfer. 6) After completion, loads the next element (in linked list) to configuration memory and executes the transfer, without MCU intervention. 7) Interrupt is generated after all transfers are completed; this can be configured to be done differently. Configurations and additional features 1) Fast mode non-fast mode Fast mode/non-fast decides on how the first transfer begins. In non-fast mode, the first element in the linked list is loaded only after completing the transfer according to the configurations already in the sDMA channel registers. In fast mode, the loading of the first element precedes the transfer. 2) Pause / resume of transfers A transfer can be paused after a descriptor set has been loaded, provided the 'pause bit' is set in the linked list element. An ongoing transfer cannot be paused. If the 'pause bit' is set, transfer is not started after loading the register set from memory. Such a transfer can be resumed later. 3) Descriptor types 3 possible configurations of descriptors (initialized as linked list elements) are possible. Type 1 provides the maximum flexibility, which contains most register definitions of a DMA logical channel. Fewer options are present in type 2. Type 3 can just modify source/destinations address of transfers. In all transfers, unmodified registers settings are maintained for the next transfer. Patch provides options / API for 1) Setting up a descriptor loading for DMA channel for sg type transfers 2) configuration with linked list elements 3) Starting / pause and resume of the said transfers, query state 4) Clearing the sglist mode Signed-off-by: Venkatraman S svenk...@ti.com CC: Madhusudhan C madhu...@ti.com CC: Shilimkar Santosh santosh.shilim...@ti.com CC: Tony Lindgren t...@atomide.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- arch/arm/plat-omap/dma.c | 279 + arch/arm/plat-omap/include/plat/dma.h | 173 2 files changed, 452 insertions(+), 0 deletions(-) diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index c22217c..7f64366 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -52,16 +52,37 @@ enum { DMA_CH_ALLOC_DONE, DMA_CH_PARAMS_SET_DONE, DMA_CH_STARTED, enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED }; #endif +/* CDP Register bitmaps */ +#define DMA_LIST_CDP_DST_VALID BIT(0) +#define DMA_LIST_CDP_SRC_VALID BIT(2) +#define DMA_LIST_CDP_TYPE1 BIT(4) +#define DMA_LIST_CDP_TYPE2 BIT(5) +#define DMA_LIST_CDP_TYPE3 (BIT(4) | BIT(5)) +#define DMA_LIST_CDP_PAUSEMODE BIT(7) +#define DMA_LIST_CDP_LISTMODE BIT(8) +#define DMA_LIST_CDP_FASTMODE BIT(10) +/* CAPS register bitmaps */ +#define DMA_CAPS_SGLIST_SUPPORTBIT(20) + +#define DMA_LIST_DESC_PAUSEBIT(0) +#define DMA_LIST_DESC_SRC_VALIDBIT(24) +#define DMA_LIST_DESC_DST_VALIDBIT(26) +#define DMA_LIST_DESC_BLK_END BIT(28) + #define OMAP_DMA_ACTIVE0x01 #define OMAP2_DMA_CSR_CLEAR_MASK 0x #define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec) +#define OMAP_DMA_INVALID_FRAME_COUNT 0x +#define OMAP_DMA_INVALID_ELEM_COUNT0xff +#define OMAP_DMA_INVALID_DESCRIPTOR_POINTER0xfffc static struct omap_system_dma_plat_info *p; static struct omap_dma_dev_attr *d; static int enable_1510_mode; static u32 errata; +static int dma_caps0_status; static struct omap_dma_global_context_registers { u32 dma_irqenable_l0; @@ -166,6 +187,76 @@ static inline void set_gdma_dev(int req, int dev) #define set_gdma_dev(req, dev) do {} while (0) #endif +static inline void omap_dma_list_set_ntype(struct omap_dma_sglist_node *node, + int value) +{ + node-num_of_elem |= ((value) 29); +} + +static void omap_set_dma_sglist_pausebit( + struct omap_dma_list_config_params *lcfg, int nelem, int set) +{ + struct omap_dma_sglist_node *sgn = lcfg-sghead; + + if (nelem 0 nelem lcfg-num_elem) { + lcfg-pausenode = nelem; +
[PATCH 16/22] OMAP: board-rm680: set MMC nomux flag
Let the bootloader do all the pad configuration. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- arch/arm/mach-omap2/board-rm680.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c index 2af8b05..2dba9d0 100644 --- a/arch/arm/mach-omap2/board-rm680.c +++ b/arch/arm/mach-omap2/board-rm680.c @@ -125,6 +125,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = { .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, .gpio_cd= -EINVAL, .gpio_wp= -EINVAL, + .nomux = true, }, { /* Terminator */ } }; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 15/22] OMAP: hsmmc: Do not mux the slot if non default muxing is already done
From: Jarkko Lavinen jarkko.lavi...@nokia.com Allow the bootloader do all the muxing. Signed-off-by: Jarkko Lavinen jarkko.lavi...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- arch/arm/mach-omap2/hsmmc.c |3 ++- arch/arm/mach-omap2/hsmmc.h |1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index b2f30be..6b97fae 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -440,7 +440,8 @@ void __init omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr) pr_err(%s fails!\n, __func__); goto done; } - omap_hsmmc_mux(mmc_data, (ctrl_nr - 1)); + if (!hsmmcinfo-nomux) + omap_hsmmc_mux(mmc_data, (ctrl_nr - 1)); name = omap_hsmmc; ohl = omap_hsmmc_latency; diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index f119348..0f2a87e 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -19,6 +19,7 @@ struct omap2_hsmmc_info { boolpower_saving; /* Try to sleep or power off when possible */ boolno_off; /* power_saving and power is not to go off */ boolvcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */ + boolnomux; /* No default muxing for this slot */ int gpio_cd;/* or -EINVAL */ int gpio_wp;/* or -EINVAL */ char*name; /* or NULL for default */ -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/22] mmc: omap_hsmmc: move hardcoded frequency constants to definition block
From: Andy Shevchenko ext-andriy.shevche...@nokia.com Move the min and max frequency constants to the definition block in the source file. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c |6 -- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index a1a1101..a727bf8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -120,6 +120,8 @@ #define MMC_TIMEOUT_MS 20 #define OMAP_MMC_MASTER_CLOCK 9600 +#define OMAP_MMC_MIN_CLOCK 40 +#define OMAP_MMC_MAX_CLOCK 5200 #define DRIVER_NAMEomap_hsmmc #define DMA_TYPE_NODMA 0 @@ -2176,8 +2178,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) if (mmc_slot(host).vcc_aux_disable_is_sleep) mmc_slot(host).no_off = 1; - mmc-f_min = 40; - mmc-f_max = 5200; + mmc-f_min = OMAP_MMC_MIN_CLOCK; + mmc-f_max = OMAP_MMC_MAX_CLOCK; spin_lock_init(host-irq_lock); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/22] mmc: omap_hsmmc: introduce start_clock and re-use stop_clock
From: Andy Shevchenko ext-andriy.shevche...@nokia.com There is similar piece of code in two functions which enables clock. Split this code to omap_hsmmc_start_clock(). Re-use omap_hsmmc_stop_clock() in omap_hsmmc_context_restore() as well. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 19 +-- 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 045c581..ae6d204 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -560,6 +560,15 @@ static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) } /* + * Start clock to the card + */ +static void omap_hsmmc_start_clock(struct omap_hsmmc_host *host) +{ + OMAP_HSMMC_WRITE(host-base, SYSCTL, + OMAP_HSMMC_READ(host-base, SYSCTL) | CEN); +} + +/* * Stop clock to the card */ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host) @@ -700,8 +709,8 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) break; } - OMAP_HSMMC_WRITE(host-base, SYSCTL, - OMAP_HSMMC_READ(host-base, SYSCTL) ~CEN); + omap_hsmmc_stop_clock(host); + OMAP_HSMMC_WRITE(host-base, SYSCTL, (calc_divisor(ios) 6) | (DTO 16)); OMAP_HSMMC_WRITE(host-base, SYSCTL, @@ -712,8 +721,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) time_before(jiffies, timeout)) ; - OMAP_HSMMC_WRITE(host-base, SYSCTL, - OMAP_HSMMC_READ(host-base, SYSCTL) | CEN); + omap_hsmmc_start_clock(host); con = OMAP_HSMMC_READ(host-base, CON); if (ios-bus_mode == MMC_BUSMODE_OPENDRAIN) @@ -1692,8 +1700,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) time_before(jiffies, timeout)) msleep(1); - OMAP_HSMMC_WRITE(host-base, SYSCTL, - OMAP_HSMMC_READ(host-base, SYSCTL) | CEN); + omap_hsmmc_start_clock(host); if (do_send_init_stream) send_init_stream(host); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/22] mmc: omap_hsmmc: limit scatterlist size for sDMA autoloading
The sDMA descriptor autoloading feature uses a fixed size buffer to store descriptors for scatterlist segments. That limits the scatterlist size to the maximum number of descriptors that fit in the buffer. The driver must set this limit for upper layers to obey. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 15 --- 1 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 114cd68..bab25ff 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2239,9 +2239,18 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) host-dma_caps |= DMA_TYPE_SDMA_DLOAD; } - /* Since we do only SG emulation, we can have as many segs -* as we want. */ - mmc-max_segs = 1024; + if (host-dma_caps DMA_TYPE_SDMA_DLOAD) { + unsigned int max = DMA_CTRL_BUF_SIZE / + sizeof(struct omap_dma_sglist_node); + + mmc-max_segs = 1 (fls(max) - 1); + } else { + /* +* Since we do only SG emulation, we can have as many segs as we +* want. +*/ + mmc-max_segs = 1024; + } mmc-max_blk_size = 512; /* Block Length at max can be 1024 */ mmc-max_blk_count = 0x;/* No. of Blocks is 16 bits */ -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/22] mmc: omap_hsmmc: fix missing mmc_release_host() in no_off case
From: Sudhir Bera ext-sudhir.b...@nokia.com In fact the no_off check here will not be hit because 'omap_hsmmc_disabled_to_sleep()' won't schedule a deeper disable in the no_off case. Signed-off-by: Sudhir Bera ext-sudhir.b...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c |7 +++ 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bab25ff..bd52849 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1852,14 +1852,13 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) return 0; if (mmc_slot(host).no_off) - return 0; + goto out; if (!((host-mmc-caps MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state mmc_slot(host).get_cover_state(host-dev, host-slot_id { - mmc_release_host(host-mmc); - return 0; + goto out; } mmc_slot(host).set_power(host-dev, host-slot_id, 0, 0); @@ -1870,7 +1869,7 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) host-dpm_state == CARDSLEEP ? CARDSLEEP : REGSLEEP); host-dpm_state = OFF; - +out: mmc_release_host(host-mmc); return 0; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/22] mmc: omap_hsmmc: split duplicate code to calc_divisor() function
From: Andy Shevchenko ext-andriy.shevche...@nokia.com There are two places where the same calculations are done. Let's split them to separate function. In addition the new function is simplified by usage DIV_ROUND_UP kernel macro. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 45 1 files changed, 18 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 7a153af..045c581 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -596,6 +596,20 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) OMAP_HSMMC_WRITE(host-base, STAT, STAT_CLEAR); } +/* Calculate divisor for the given clock frequency */ +static u16 calc_divisor(struct mmc_ios *ios) +{ + u16 dsor = 0; + + if (ios-clock) { + dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios-clock); + if (dsor 250) + dsor = 250; + } + + return dsor; +} + #ifdef CONFIG_PM /* @@ -608,7 +622,6 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) struct omap_mmc_platform_data *pdata = host-pdata; int context_loss = 0; u32 hctl, capa, con; - u16 dsor = 0; unsigned long timeout; if (pdata-get_context_loss_count) { @@ -687,21 +700,10 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) break; } - if (ios-clock) { - dsor = OMAP_MMC_MASTER_CLOCK / ios-clock; - if (dsor 1) - dsor = 1; - - if (OMAP_MMC_MASTER_CLOCK / dsor ios-clock) - dsor++; - - if (dsor 250) - dsor = 250; - } - OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) ~CEN); - OMAP_HSMMC_WRITE(host-base, SYSCTL, (dsor 6) | (DTO 16)); + OMAP_HSMMC_WRITE(host-base, SYSCTL, + (calc_divisor(ios) 6) | (DTO 16)); OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); @@ -1612,7 +1614,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct omap_hsmmc_host *host = mmc_priv(mmc); - u16 dsor = 0; unsigned long regval; unsigned long timeout; u32 con; @@ -1676,21 +1677,11 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } - if (ios-clock) { - dsor = OMAP_MMC_MASTER_CLOCK / ios-clock; - if (dsor 1) - dsor = 1; - - if (OMAP_MMC_MASTER_CLOCK / dsor ios-clock) - dsor++; - - if (dsor 250) - dsor = 250; - } omap_hsmmc_stop_clock(host); + regval = OMAP_HSMMC_READ(host-base, SYSCTL); regval = regval ~(CLKD_MASK); - regval = regval | (dsor 6) | (DTO 16); + regval = regval | (calc_divisor(ios) 6) | (DTO 16); OMAP_HSMMC_WRITE(host-base, SYSCTL, regval); OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/22] mmc: omap_hsmmc: correct debug report error status mnemonics
CERR and BADA were in the wrong place and there are only 32 not 35. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 19 +++ 1 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bd52849..a1a1101 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -982,14 +982,14 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) * Readable error output */ #ifdef CONFIG_MMC_DEBUG -static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status) +static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status) { /* --- means reserved bit without definition at documentation */ static const char *omap_hsmmc_status_bits[] = { - CC, TC, BGE, ---, BWR, BRR, ---, ---, CIRQ, - OBI, ---, ---, ---, ---, ---, ERRI, CTO, CCRC, - CEB, CIE, DTO, DCRC, DEB, ---, ACE, ---, - ---, ---, ---, CERR, CERR, BADA, ---, ---, --- + CC , TC , BGE, ---, BWR , BRR , --- , --- , + CIRQ, OBI , ---, ---, --- , --- , --- , ERRI, + CTO , CCRC, CEB, CIE, DTO , DCRC, DEB , --- , + ACE , --- , ---, ---, CERR, BADA, --- , --- }; char res[256]; char *buf = res; @@ -1006,6 +1006,11 @@ static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status) dev_dbg(mmc_dev(host-mmc), %s\n, res); } +#else +static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, +u32 status) +{ +} #endif /* CONFIG_MMC_DEBUG */ /* @@ -1064,9 +1069,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) dev_dbg(mmc_dev(host-mmc), IRQ Status is %x\n, status); if (status ERR) { -#ifdef CONFIG_MMC_DEBUG - omap_hsmmc_report_irq(host, status); -#endif + omap_hsmmc_dbg_report_irq(host, status); if ((status CMD_TIMEOUT) || (status CMD_CRC)) { if (host-cmd) { -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 13/22] mmc: omap_hsmmc: fix few bugs when set the clock divisor
From: Andy Shevchenko ext-andriy.shevche...@nokia.com There are two pieces of code which similar, but not the same. Each of them contains a bug. The SYSCTL register should be read before write in the omap_hsmmc_context_restore() to remain the state of the reserved bits. Before set the clock divisor and DTO bits the value from the SYSCTL register should be masked properly. We were lucky to have no problems with DTO bits. So, make sure we have clear DTO bits properly in the omap_hsmmc_set_ios(). Additionally get rid of msleep(1). The actual time rare higher than 30us on OMAP 3630. The result pieces of code are split to omap_hsmmc_set_clock() function. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 59 +++- 1 files changed, 28 insertions(+), 31 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index ae6d204..3c76911 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -619,6 +619,32 @@ static u16 calc_divisor(struct mmc_ios *ios) return dsor; } +static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) +{ + struct mmc_ios *ios = host-mmc-ios; + unsigned long regval; + unsigned long timeout; + + dev_dbg(mmc_dev(host-mmc), Set clock to %uHz\n, ios-clock); + + omap_hsmmc_stop_clock(host); + + regval = OMAP_HSMMC_READ(host-base, SYSCTL); + regval = regval ~(CLKD_MASK | DTO_MASK); + regval = regval | (calc_divisor(ios) 6) | (DTO 16); + OMAP_HSMMC_WRITE(host-base, SYSCTL, regval); + OMAP_HSMMC_WRITE(host-base, SYSCTL, + OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); + + /* Wait till the ICS bit is set */ + timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); + while ((OMAP_HSMMC_READ(host-base, SYSCTL) ICS) != ICS +time_before(jiffies, timeout)) + ; + + omap_hsmmc_start_clock(host); +} + #ifdef CONFIG_PM /* @@ -709,19 +735,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) break; } - omap_hsmmc_stop_clock(host); - - OMAP_HSMMC_WRITE(host-base, SYSCTL, - (calc_divisor(ios) 6) | (DTO 16)); - OMAP_HSMMC_WRITE(host-base, SYSCTL, - OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); - - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((OMAP_HSMMC_READ(host-base, SYSCTL) ICS) != ICS -time_before(jiffies, timeout)) - ; - - omap_hsmmc_start_clock(host); + omap_hsmmc_set_clock(host); con = OMAP_HSMMC_READ(host-base, CON); if (ios-bus_mode == MMC_BUSMODE_OPENDRAIN) @@ -1622,8 +1636,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct omap_hsmmc_host *host = mmc_priv(mmc); - unsigned long regval; - unsigned long timeout; u32 con; int do_send_init_stream = 0; @@ -1685,22 +1697,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } - omap_hsmmc_stop_clock(host); - - regval = OMAP_HSMMC_READ(host-base, SYSCTL); - regval = regval ~(CLKD_MASK); - regval = regval | (calc_divisor(ios) 6) | (DTO 16); - OMAP_HSMMC_WRITE(host-base, SYSCTL, regval); - OMAP_HSMMC_WRITE(host-base, SYSCTL, - OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); - - /* Wait till the ICS bit is set */ - timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((OMAP_HSMMC_READ(host-base, SYSCTL) ICS) != ICS -time_before(jiffies, timeout)) - msleep(1); - - omap_hsmmc_start_clock(host); + omap_hsmmc_set_clock(host); if (do_send_init_stream) send_init_stream(host); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 14/22] mmc: omap_hsmmc: split same pieces of code to separate functions
From: Andy Shevchenko ext-andriy.shevche...@nokia.com There are few places with the same functionality. This patch creates two functions omap_hsmmc_set_bus_width() and omap_hsmmc_set_bus_mode() to do the job. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 85 - 1 files changed, 41 insertions(+), 44 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3c76911..e7c181a 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -645,6 +645,41 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) omap_hsmmc_start_clock(host); } +static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) +{ + struct mmc_ios *ios = host-mmc-ios; + u32 con; + + con = OMAP_HSMMC_READ(host-base, CON); + switch (ios-bus_width) { + case MMC_BUS_WIDTH_8: + OMAP_HSMMC_WRITE(host-base, CON, con | DW8); + break; + case MMC_BUS_WIDTH_4: + OMAP_HSMMC_WRITE(host-base, CON, con ~DW8); + OMAP_HSMMC_WRITE(host-base, HCTL, + OMAP_HSMMC_READ(host-base, HCTL) | FOUR_BIT); + break; + case MMC_BUS_WIDTH_1: + OMAP_HSMMC_WRITE(host-base, CON, con ~DW8); + OMAP_HSMMC_WRITE(host-base, HCTL, + OMAP_HSMMC_READ(host-base, HCTL) ~FOUR_BIT); + break; + } +} + +static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host) +{ + struct mmc_ios *ios = host-mmc-ios; + u32 con; + + con = OMAP_HSMMC_READ(host-base, CON); + if (ios-bus_mode == MMC_BUSMODE_OPENDRAIN) + OMAP_HSMMC_WRITE(host-base, CON, con | OD); + else + OMAP_HSMMC_WRITE(host-base, CON, con ~OD); +} + #ifdef CONFIG_PM /* @@ -656,7 +691,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) struct mmc_ios *ios = host-mmc-ios; struct omap_mmc_platform_data *pdata = host-pdata; int context_loss = 0; - u32 hctl, capa, con; + u32 hctl, capa; unsigned long timeout; if (pdata-get_context_loss_count) { @@ -718,30 +753,12 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) if (host-power_mode == MMC_POWER_OFF) goto out; - con = OMAP_HSMMC_READ(host-base, CON); - switch (ios-bus_width) { - case MMC_BUS_WIDTH_8: - OMAP_HSMMC_WRITE(host-base, CON, con | DW8); - break; - case MMC_BUS_WIDTH_4: - OMAP_HSMMC_WRITE(host-base, CON, con ~DW8); - OMAP_HSMMC_WRITE(host-base, HCTL, - OMAP_HSMMC_READ(host-base, HCTL) | FOUR_BIT); - break; - case MMC_BUS_WIDTH_1: - OMAP_HSMMC_WRITE(host-base, CON, con ~DW8); - OMAP_HSMMC_WRITE(host-base, HCTL, - OMAP_HSMMC_READ(host-base, HCTL) ~FOUR_BIT); - break; - } + omap_hsmmc_set_bus_width(host); omap_hsmmc_set_clock(host); - con = OMAP_HSMMC_READ(host-base, CON); - if (ios-bus_mode == MMC_BUSMODE_OPENDRAIN) - OMAP_HSMMC_WRITE(host-base, CON, con | OD); - else - OMAP_HSMMC_WRITE(host-base, CON, con ~OD); + omap_hsmmc_set_bus_mode(host); + out: host-context_loss = context_loss; @@ -1636,7 +1653,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct omap_hsmmc_host *host = mmc_priv(mmc); - u32 con; int do_send_init_stream = 0; mmc_host_enable(host-mmc); @@ -1662,22 +1678,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* FIXME: set registers based only on changes to ios */ - con = OMAP_HSMMC_READ(host-base, CON); - switch (mmc-ios.bus_width) { - case MMC_BUS_WIDTH_8: - OMAP_HSMMC_WRITE(host-base, CON, con | DW8); - break; - case MMC_BUS_WIDTH_4: - OMAP_HSMMC_WRITE(host-base, CON, con ~DW8); - OMAP_HSMMC_WRITE(host-base, HCTL, - OMAP_HSMMC_READ(host-base, HCTL) | FOUR_BIT); - break; - case MMC_BUS_WIDTH_1: - OMAP_HSMMC_WRITE(host-base, CON, con ~DW8); - OMAP_HSMMC_WRITE(host-base, HCTL, - OMAP_HSMMC_READ(host-base, HCTL) ~FOUR_BIT); - break; - } + omap_hsmmc_set_bus_width(host); if (host-pdata-controller_flags OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { /* Only MMC1 can interface at 3V without some flavor @@ -1702,11 +1703,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct
[PATCH 10/22] mmc: omap_hsmmc: reduce a bit the error handlers in probe()
From: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 17 ++--- 1 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index a727bf8..7a153af 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2204,18 +2204,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) /* we start off in DISABLED state */ host-dpm_state = DISABLED; - if (clk_enable(host-iclk) != 0) { - clk_put(host-iclk); - clk_put(host-fclk); - goto err1; - } + if (clk_enable(host-iclk) != 0) + goto err2; - if (mmc_host_enable(host-mmc) != 0) { - clk_disable(host-iclk); - clk_put(host-iclk); - clk_put(host-fclk); - goto err1; - } + if (mmc_host_enable(host-mmc) != 0) + goto err3; if (cpu_is_omap2430()) { host-dbclk = clk_get(pdev-dev, mmchsdb_fck); @@ -2382,7 +2375,9 @@ err_irq: host-dma_ctrl_buf, host-dma_ctrl_buf_phy); mmc_host_disable(host-mmc); +err3: clk_disable(host-iclk); +err2: clk_put(host-fclk); clk_put(host-iclk); if (host-got_dbclk) { -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 20/22] mmc: omap_hsmmc: adjust host controller clock in regard to current OPP
From: Andy Shevchenko ext-andriy.shevche...@nokia.com We should like to adjust MMC host controller clock whenever the OPP is changed. OPP affects to L3/L4 bus frequency. Due to this we update the maximum frequency limits before each upcoming request and when the divisor is calculated. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 65 + 1 files changed, 59 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2c8fa01..8c5e7d3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -199,6 +199,9 @@ struct omap_hsmmc_host { int use_reg; int req_in_progress; + /* Actual output frequency of host controller */ + unsigned intfreq; + struct omap_mmc_platform_data *pdata; }; @@ -604,13 +607,31 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) OMAP_HSMMC_WRITE(host-base, STAT, STAT_CLEAR); } +/* + * Recalculate desired clock frequency with regard to maximum possible + * frequency at current OPP. + * + * Choose either target frequency (ios-clock) or maximum possible frequency at + * current OPP (get_max_freq() returns this limit) + */ +static void omap_hsmmc_recalc_freq(struct omap_hsmmc_host *host, + struct mmc_ios *ios) +{ + struct omap_mmc_platform_data *pdata = host-pdata; + + if (pdata-get_max_freq) + host-freq = min(ios-clock, pdata-get_max_freq(host-dev)); + else + host-freq = ios-clock; +} + /* Calculate divisor for the given clock frequency */ -static u16 calc_divisor(struct mmc_ios *ios) +static u16 calc_divisor(struct omap_hsmmc_host *host) { u16 dsor = 0; - if (ios-clock) { - dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios-clock); + if (host-freq) { + dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, host-freq); if (dsor 250) dsor = 250; } @@ -620,17 +641,16 @@ static u16 calc_divisor(struct mmc_ios *ios) static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) { - struct mmc_ios *ios = host-mmc-ios; unsigned long regval; unsigned long timeout; - dev_dbg(mmc_dev(host-mmc), Set clock to %uHz\n, ios-clock); + dev_dbg(mmc_dev(host-mmc), Set clock to %uHz\n, host-freq); omap_hsmmc_stop_clock(host); regval = OMAP_HSMMC_READ(host-base, SYSCTL); regval = regval ~(CLKD_MASK | DTO_MASK); - regval = regval | (calc_divisor(ios) 6) | (DTO 16); + regval = regval | (calc_divisor(host) 6) | (DTO 16); OMAP_HSMMC_WRITE(host-base, SYSCTL, regval); OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); @@ -754,6 +774,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) omap_hsmmc_set_bus_width(host); + omap_hsmmc_recalc_freq(host, ios); omap_hsmmc_set_clock(host); omap_hsmmc_set_bus_mode(host); @@ -937,6 +958,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req if (mrq-data host-dma_in_use dma_ch != -1) return; host-mrq = NULL; + if (host-pdata-inactive) + host-pdata-inactive(host-dev); mmc_request_done(host-mmc, mrq); } @@ -996,6 +1019,9 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) } if ((host-data == NULL !host-response_busy) || cmd-error) omap_hsmmc_request_done(host, cmd-mrq); + else if (host-data == NULL host-response_busy +host-pdata-inactive) + host-pdata-inactive(host-dev); } /* @@ -1418,6 +1444,8 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) struct mmc_request *mrq = host-mrq; host-mrq = NULL; + if (host-pdata-inactive) + host-pdata-inactive(host-dev); mmc_request_done(host-mmc, mrq); } } @@ -1615,6 +1643,26 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) BUG_ON(host-req_in_progress); BUG_ON(host-dma_ch != -1); + + if (host-pdata-active) { + unsigned int new_freq; + + /* +* active() returns minimum of two (target, maximum) +* frequencies. +*/ + new_freq = host-pdata-active(host-dev, mmc-ios.clock); + + /* +* We need to update actual frequency if it is not equal to the +* minimum of two (target and maximum) frequencies +*/ + if (host-freq !=
[PATCH 19/22] OMAP: hsmmc: implement clock switcher
From: Andy Shevchenko ext-andriy.shevche...@nokia.com There are 3 new platform data methods which should help us to do a clock switching when notification is happened or request is started. The purpose of the patch is to avoid high frequency of MMC controller on low OPPs due to an HW bug in OMAP 3630. The algorithm: - the PM governor switches the clock of L3 (and therefore L4) bus on demand - the MMC controller clock should follow the change We have considered two OPPs for L3/L4 bus. Thus, we have corresponding flow: - OPP1 - OPP2 (in case of abort - OPP1) - OPP2 - OPP1 (in case of abort - OPP2) During idle the MMC gates functional clock and we don't care about the frequency. Most important to get proper solution when notification comes during request. Then: - in case of OPP1 - OPP2 we update frequency limit and it will be used for new coming requests (it assumes the current frequency of the controller is lower then new one) - otherwise we wait until no device has used higher frequency then upcoming one Known issues and limitations: - originally a clock notifier was used for the core L4 iclk but for upstream Adrian changed to a cpufreq notifier where we assume OPP1 below 400MHz and OPP2 above 400MHz Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- arch/arm/mach-omap2/hsmmc.c | 180 - arch/arm/plat-omap/include/plat/mmc.h |8 ++ 2 files changed, 187 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 6b97fae..34cba89 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -10,10 +10,15 @@ * published by the Free Software Foundation. */ #include linux/kernel.h +#include linux/err.h #include linux/slab.h #include linux/string.h #include linux/delay.h +#include linux/platform_device.h +#include linux/clk.h +#include linux/mmc/card.h #include mach/hardware.h +#include plat/clock.h #include plat/mmc.h #include plat/omap-pm.h #include plat/mux.h @@ -23,6 +28,8 @@ #include hsmmc.h #include control.h +#define HSMMC_MAX_FREQ 4800 + #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) static u16 control_pbias_offset; @@ -203,6 +210,155 @@ static int nop_mmc_set_power(struct device *dev, int slot, int power_on, return 0; } +#ifdef CONFIG_ARCH_OMAP3 +static struct hsmmc_max_freq_info { + struct device *dev; + int freq; + int high_speed; +} hsmmc_max_freq_info[OMAP34XX_NR_MMC]; + +static unsigned int hsmmc_max_freq = HSMMC_MAX_FREQ; +static DEFINE_SPINLOCK(hsmmc_max_freq_lock); + +static DECLARE_WAIT_QUEUE_HEAD(hsmmc_max_freq_wq); + +static int hsmmc_high_speed(struct device *dev) +{ + void *drvdata = platform_get_drvdata(to_platform_device(dev)); + struct mmc_host *mmc = container_of(drvdata, struct mmc_host, private); + + return mmc-card ? mmc_card_highspeed(mmc-card) : 0; +} + +static unsigned int hsmmc_get_max_freq_hs(struct device *dev, int high_speed) +{ + return high_speed ? hsmmc_max_freq : hsmmc_max_freq 1; +} + +static unsigned int hsmmc_get_max_freq(struct device *dev) +{ + return hsmmc_get_max_freq_hs(dev, hsmmc_high_speed(dev)); +} + +static unsigned int hsmmc_active(struct device *dev, unsigned int target_freq) +{ + int high_speed = hsmmc_high_speed(dev); + int i; + unsigned int max_freq, freq; + unsigned long flags; + + spin_lock_irqsave(hsmmc_max_freq_lock, flags); + max_freq = hsmmc_get_max_freq_hs(dev, high_speed); + freq = min(target_freq, max_freq); + for (i = 0; i ARRAY_SIZE(hsmmc_max_freq_info); i++) { + if (!hsmmc_max_freq_info[i].dev) { + hsmmc_max_freq_info[i].dev = dev; + hsmmc_max_freq_info[i].freq = freq; + hsmmc_max_freq_info[i].high_speed = high_speed; + break; + } + } + spin_unlock_irqrestore(hsmmc_max_freq_lock, flags); + return freq; +} + +static void hsmmc_inactive(struct device *dev) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(hsmmc_max_freq_lock, flags); + for (i = 0; i ARRAY_SIZE(hsmmc_max_freq_info); i++) { + if (hsmmc_max_freq_info[i].dev == dev) { + hsmmc_max_freq_info[i].dev = NULL; + spin_unlock_irqrestore(hsmmc_max_freq_lock, flags); + /* +* Wake up the queue only in case we deactivated a +* device. +*/ + wake_up(hsmmc_max_freq_wq); + return; + } + } + spin_unlock_irqrestore(hsmmc_max_freq_lock, flags); +} + +static bool hsmmc_max_freq_ok(void) +{ + int i; + bool ret = true; + unsigned long flags; + +
[PATCH 21/22] OMAP: hsmmc: add platform data for eMMC hardware reset gpio
eMMC may have a hardware reset line connected to a gpio, so pass it to the driver. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- arch/arm/mach-omap2/hsmmc.c |5 + arch/arm/mach-omap2/hsmmc.h |1 + arch/arm/plat-omap/include/plat/mmc.h |1 + 3 files changed, 7 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 34cba89..85f27af 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -472,6 +472,11 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc-slots[0].switch_pin = c-gpio_cd; mmc-slots[0].gpio_wp = c-gpio_wp; + if (c-gpio_hw_reset) + mmc-slots[0].gpio_hw_reset = c-gpio_hw_reset; + else + mmc-slots[0].gpio_hw_reset = -EINVAL; + mmc-slots[0].remux = c-remux; mmc-slots[0].init_card = c-init_card; diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index 0f2a87e..b78ed41 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -22,6 +22,7 @@ struct omap2_hsmmc_info { boolnomux; /* No default muxing for this slot */ int gpio_cd;/* or -EINVAL */ int gpio_wp;/* or -EINVAL */ + int gpio_hw_reset; /* hardware reset */ char*name; /* or NULL for default */ struct device *dev; /* returned: pointer to mmc adapter */ int ocr_mask; /* temporary HACK */ diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index e3c9b20..9b69b7e 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -119,6 +119,7 @@ struct omap_mmc_platform_data { int switch_pin; /* gpio (card detect) */ int gpio_wp;/* gpio (write protect) */ + int gpio_hw_reset; /* gpio (hardware reset) */ int (*set_bus_mode)(struct device *dev, int slot, int bus_mode); int (*set_power)(struct device *dev, int slot, -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 18/22] mmc: omap_hsmmc: fix oops in omap_hsmmc_dma_cb
In the case of an I/O error, the DMA will have been cleaned up in the MMC interrupt and the request structure pointer will be null. In that case, it is essential to check if the DMA DMA is over before dereferencing host-mrq-data. Oops as follows: 3[ 2293.695281] wl1271: ERROR sdio read failed (-110) 1[ 2293.695739] Unable to handle kernel NULL pointer dereference at virtual address 0004 1[ 2293.703094] pgd = b0004000 1[ 2293.705780] [0004] *pgd= 0[ 2293.709381] Internal error: Oops: 17 [#1] PREEMPT 0[ 2293.714080] last sysfs file: /sys/devices/platform/omapdss/manager0/cpr_enable 4[ 2293.721313] Modules linked in: ext2 dm_crypt xt_NFLOG xt_rateest xt_RATEEST xt_condition iptable_filter ip_tables dm_mod xt_IDLETIMER nfnetlink_log nfnetlink as3645a ad58xx smiapp smiapp_power omap3_isp iovmm omap3_iommu iommu2 iommu wl12xx_spi bnep omaplfb bridgedriver g_file_storage cmt_speech ssi_protocol phonet hsi_char wl12xx_sdio wl12xx pvrsrvkm omap_ssi mailbox_mach vibra_spi radio_wl1273 mailbox bcm4751_gps lis3lv02d_i2c ak8975 lis3lv02d leds_lp5521 apds990x pn544 rtc_twl4030 twl4030_keypad twl4030_pwrbutton cmt twl5031_aci hci_h4p 4[ 2293.769287] CPU: 0Not tainted (2.6.32.36-dfl61-20111603 #1) 4[ 2293.775329] PC is at omap_hsmmc_dma_cb+0x18/0x140 4[ 2293.780029] LR is at omap2_dma_irq_handler+0x244/0x28c 4[ 2293.785156] pc : [b024e180]lr : [b0049ed0]psr: a1d3 4[ 2293.785186] sp : edfb3c48 ip : edfb3bf8 fp : edfb3d3c 4[ 2293.796661] r10: fa05632c r9 : fa056000 r8 : ee4889c0 4[ 2293.801910] r7 : 0020 r6 : 0001 r5 : edfb2000 r4 : ee53e1c0 4[ 2293.808441] r3 : r2 : edfb3c48 r1 : 0020 r0 : 0007 4[ 2293.814971] Flags: NzCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel 4[ 2293.822479] Control: 10c5387d Table: bc9f4019 DAC: 0017 0[ 2293.828247] Process phy0 (pid: 313, stack limit = 0xedfb22e8) 0[ 2293.833984] Stack: (0xedfb3c48 to 0xedfb4000) ... 4[ 2294.084320] [b024e180] (omap_hsmmc_dma_cb+0x18/0x140) from [b0049ed0] (omap2_dma_irq_handler+0x244/0x28c) 4[ 2294.094268] [b0049ed0] (omap2_dma_irq_handler+0x244/0x28c) from [b0093d44] (handle_IRQ_event+0x34/0xf0) 4[ 2294.104034] [b0093d44] (handle_IRQ_event+0x34/0xf0) from [b0095bec] (handle_level_irq+0xcc/0x170) 4[ 2294.113250] [b0095bec] (handle_level_irq+0xcc/0x170) from [b002c068] (asm_do_IRQ+0x68/0x84) 4[ 2294.121978] [b002c068] (asm_do_IRQ+0x68/0x84) from [b002ca84] (__irq_svc+0x44/0xa8) 4[ 2294.129974] Exception stack(0xedfb3cc0 to 0xedfb3d08) 4[ 2294.135040] 3cc0: 0021d5cd 3d20cc2d 0002 edf7dd40 edfb2000 edf7dee8 edf7ddd8 4[ 2294.143249] 3ce0: 0001 ee516080 edfb3d3c b04880b8 edfb3d08 b0059e5c b0344184 4[ 2294.151428] 3d00: 0053 4[ 2294.154968] [b002ca84] (__irq_svc+0x44/0xa8) from [b0344184] (schedule+0x248/0x3a8) 4[ 2294.162963] [b0344184] (schedule+0x248/0x3a8) from [b03448ac] (schedule_timeout+0x1c/0x224) 4[ 2294.171691] [b03448ac] (schedule_timeout+0x1c/0x224) from [b0344738] (wait_for_common+0xe8/0x1a8) 4[ 2294.180938] [b0344738] (wait_for_common+0xe8/0x1a8) from [b02459f8] (mmc_wait_for_req+0x110/0x120) 4[ 2294.190277] [b02459f8] (mmc_wait_for_req+0x110/0x120) from [b0249bac] (mmc_io_rw_extended+0x178/0x1e0) 4[ 2294.199951] [b0249bac] (mmc_io_rw_extended+0x178/0x1e0) from [b024ab54] (sdio_io_rw_ext_helper+0x164/0x190) 4[ 2294.210052] [b024ab54] (sdio_io_rw_ext_helper+0x164/0x190) from [b024aba0] (sdio_writesb+0x20/0x24) 4[ 2294.219512] [b024aba0] (sdio_writesb+0x20/0x24) from [af0d50e0] (wl1271_sdio_raw_write+0x64/0xa4 [wl12xx_sdio]) 4[ 2294.230041] [af0d50e0] (wl1271_sdio_raw_write+0x64/0xa4 [wl12xx_sdio]) from [af0bd4bc] (wl1271_tx_work_locked+0x548/0x5fc [wl12xx]) 4[ 2294.242218] [af0bd4bc] (wl1271_tx_work_locked+0x548/0x5fc [wl12xx]) from [af0ba944] (wl1271_irq_work+0x230/0x314 [wl12xx]) 4[ 2294.253631] [af0ba944] (wl1271_irq_work+0x230/0x314 [wl12xx]) from [b00725ac] (worker_thread+0x174/0x224) 4[ 2294.263519] [b00725ac] (worker_thread+0x174/0x224) from [b0075bac] (kthread+0x7c/0x84) 4[ 2294.271820] [b0075bac] (kthread+0x7c/0x84) from [b002d950] (kernel_thread_exit+0x0/0x8) 0[ 2294.280181] Code: e5923008 e1a0200d e3c25d7f e3c5503f (e5936004) 4[ 2294.286529] ---[ end trace e8fb05c679bd87ff ]--- Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index de7f15c..2c8fa01 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1375,7 +1375,7 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host, static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) { struct omap_hsmmc_host *host = cb_data; - struct mmc_data *data = host-mrq-data; + struct mmc_data *data; int dma_ch, req_in_progress; if (!(ch_status (OMAP_DMA_BLOCK_IRQ | OMAP2_DMA_SUPER_BLOCK_IRQ))) { @@ -1390,6
[PATCH 17/22] mmc: omap_hsmmc: ensure pbias configuration is always done
Go through the driver's set_power() functions rather than calling regulator_enable/disable() directly because otherwise pbias configuration for MMC1 is not done. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 17 - 1 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e7c181a..de7f15c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -457,15 +457,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) * framework is fixed, we need a workaround like this * (which is safe for MMC, but not in general). */ - if (regulator_is_enabled(host-vcc) 0) { - regulator_enable(host-vcc); - regulator_disable(host-vcc); - } - if (host-vcc_aux) { - if (regulator_is_enabled(reg) 0) { - regulator_enable(reg); - regulator_disable(reg); - } + if (regulator_is_enabled(host-vcc) 0 || + (host-vcc_aux regulator_is_enabled(host-vcc_aux))) { + int vdd = ffs(mmc_slot(host).ocr_mask) - 1; + + mmc_slot(host).set_power(host-dev, host-slot_id, +1, vdd); + mmc_slot(host).set_power(host-dev, host-slot_id, +0, 0); } } -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 22/22] mmc: omap_hsmmc: add a hardware reset before initialization
After a warm restart, an eMMC which cannot be powered off is in an unknown state, so reset it to be sure it will initialize. Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 38 +- 1 files changed, 37 insertions(+), 1 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 8c5e7d3..c791230 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -542,10 +542,25 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) } else pdata-slots[0].gpio_wp = -EINVAL; + if (gpio_is_valid(pdata-slots[0].gpio_hw_reset)) { + ret = gpio_request(pdata-slots[0].gpio_hw_reset, + mmc_hw_reset); + if (ret) + goto err_free_wp; + ret = gpio_direction_output(pdata-slots[0].gpio_hw_reset, 1); + if (ret) + goto err_free_hw_reset; + } else + pdata-slots[0].gpio_hw_reset = -EINVAL; + return 0; + +err_free_hw_reset: + gpio_free(pdata-slots[0].gpio_hw_reset); err_free_wp: - gpio_free(pdata-slots[0].gpio_wp); + if (gpio_is_valid(pdata-slots[0].gpio_wp)) + gpio_free(pdata-slots[0].gpio_wp); err_free_cd: if (gpio_is_valid(pdata-slots[0].switch_pin)) err_free_sp: @@ -555,6 +570,8 @@ err_free_sp: static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) { + if (gpio_is_valid(pdata-slots[0].gpio_hw_reset)) + gpio_free(pdata-slots[0].gpio_hw_reset); if (gpio_is_valid(pdata-slots[0].gpio_wp)) gpio_free(pdata-slots[0].gpio_wp); if (gpio_is_valid(pdata-slots[0].switch_pin)) @@ -815,6 +832,18 @@ static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) #endif +static void omap_hsmmc_do_hw_reset(struct omap_hsmmc_host *host) +{ + if (!gpio_is_valid(mmc_slot(host).gpio_hw_reset)) + return; + + gpio_set_value_cansleep(mmc_slot(host).gpio_hw_reset, 0); + udelay(9); + gpio_set_value_cansleep(mmc_slot(host).gpio_hw_reset, 1); + usleep_range(1000, 2000); + printk(KERN_INFO %s: hardware reset done\n, mmc_hostname(host-mmc)); +} + /* * Send init stream sequence to card * before sending IDLE command @@ -827,6 +856,13 @@ static void send_init_stream(struct omap_hsmmc_host *host) if (host-protect_card) return; + /* +* After a warm restart, an eMMC which cannot be powered off is in an +* unknown state so reset it to be sure it will initialize. +*/ + if (mmc_slot(host).no_off) + omap_hsmmc_do_hw_reset(host); + disable_irq(host-irq); OMAP_HSMMC_WRITE(host-base, IE, INT_EN_MASK); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/9] OMAP: DSS2: Change DSI platform device name from omapdss_dsi1 to omapdss_dsi
On Thu, 2011-05-05 at 04:50 -0700, Tony Lindgren wrote: * Tomi Valkeinen tomi.valkei...@ti.com [110505 04:33]: On Wed, 2011-05-04 at 12:40 +0300, Tony Lindgren wrote: Looks like we should first combine all this cut and paste data for each board file into some common init function to cut down the crazy churn. Sorry, I don't see how this would be possible with the regulator framework. What we would need is to setup some regulator_consumer_supplies dynamically depending on the omap and on the given parameters. Adding Liam and Mark for possible comments. A short summary of the situation: OMAP display subsystem (DSS) HW needs a few power supplies (vdds_dsi, vdds_sdi, vdda_dac), depending on the OMAP version. All the known boards have the standard TWL power chip which provides these powers, and they are connected almost always the same way. However, there's no reason that the powers for DSS couldn't be provided from some other source. As an example, on OMAP3 we could have: (regulator - name - driver) VDDA_DAC - vdda_dac - omapdss_venc VPLL2 - vdds_dsi - omapdss VPLL2 - vdds_dsi - omapdss_dsi So currently we have REGULATOR_SUPPLY defines for each board in all the board files which support display. It would be much better to have an overrideable standard setup for the DSS powers, but this would require dynamically setting up the regulator_consumer_supplies. And I can't see how this could be done, except dynamically creating the regulator_consumer_supply array before initializing the TWL chip, but as DSS is not the only user of those powers the end result could be quite a mess with changes needed in every board file. What if you just do all common DSS REGULATOR_SUPPLY entries in the common platform init code for DSS? Then just set the regulator_init_data pointers based on the desired configuration. Or maybe I misunderstood your problem.. The problem with that approach is that there could be other users for the same regulator, so the consumer_supplies list could also need to contain some other entries than dss. Then again, I guess those cases are minority, so we would still get majority of the board files cleaned up. Thanks for the idea, I'll try this approach. Tomi -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 13/22] mmc: omap_hsmmc: fix few bugs when set the clock divisor
On Thu, May 5, 2011 at 2:51 PM, Adrian Hunter adrian.hun...@nokia.com wrote: From: Andy Shevchenko ext-andriy.shevche...@nokia.com There are two pieces of code which similar, but not the same. Each of them contains a bug. The SYSCTL register should be read before write in the omap_hsmmc_context_restore() to remain the state of the reserved bits. Before set the clock divisor and DTO bits the value from the SYSCTL register should be masked properly. We were lucky to have no problems with DTO bits. So, make sure we have clear DTO bits properly in the omap_hsmmc_set_ios(). Additionally get rid of msleep(1). The actual time rare higher than 30us on OMAP 3630. The result pieces of code are split to omap_hsmmc_set_clock() function. Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c | 59 +++- 1 files changed, 28 insertions(+), 31 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index ae6d204..3c76911 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -619,6 +619,32 @@ static u16 calc_divisor(struct mmc_ios *ios) return dsor; } +static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) +{ + struct mmc_ios *ios = host-mmc-ios; + unsigned long regval; + unsigned long timeout; + + dev_dbg(mmc_dev(host-mmc), Set clock to %uHz\n, ios-clock); + + omap_hsmmc_stop_clock(host); + + regval = OMAP_HSMMC_READ(host-base, SYSCTL); + regval = regval ~(CLKD_MASK | DTO_MASK); + regval = regval | (calc_divisor(ios) 6) | (DTO 16); + OMAP_HSMMC_WRITE(host-base, SYSCTL, regval); + OMAP_HSMMC_WRITE(host-base, SYSCTL, + OMAP_HSMMC_READ(host-base, SYSCTL) | ICE); + + /* Wait till the ICS bit is set */ + timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); + while ((OMAP_HSMMC_READ(host-base, SYSCTL) ICS) != ICS + time_before(jiffies, timeout)) + ; Since you are busywaiting now, cpu_relax() is advisable I guess. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/9] OMAP: DSS2: Change DSI platform device name from omapdss_dsi1 to omapdss_dsi
On Thu, May 05, 2011 at 02:36:48PM +0300, Tomi Valkeinen wrote: So currently we have REGULATOR_SUPPLY defines for each board in all the board files which support display. It would be much better to have an overrideable standard setup for the DSS powers, but this would require dynamically setting up the regulator_consumer_supplies. And I can't see how this could be done, except dynamically creating the regulator_consumer_supply array before initializing the TWL chip, but as DSS is not the only user of those powers the end result could be quite a mess with changes needed in every board file. I'm not sure I see a problem that needs solving here? This wiring is all totally system specific. Once we have viable device tree for relevant platforms I'd expect to see these things mapped in the device tree for the system with a standard regulator API device tree mapping. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/9] OMAP: DSS2: Change DSI platform device name from omapdss_dsi1 to omapdss_dsi
On Thu, 2011-05-05 at 04:50 -0700, Tony Lindgren wrote: * Tomi Valkeinen tomi.valkei...@ti.com [110505 04:33]: On Wed, 2011-05-04 at 12:40 +0300, Tony Lindgren wrote: Looks like we should first combine all this cut and paste data for each board file into some common init function to cut down the crazy churn. Sorry, I don't see how this would be possible with the regulator framework. What we would need is to setup some regulator_consumer_supplies dynamically depending on the omap and on the given parameters. Adding Liam and Mark for possible comments. A short summary of the situation: OMAP display subsystem (DSS) HW needs a few power supplies (vdds_dsi, vdds_sdi, vdda_dac), depending on the OMAP version. All the known boards have the standard TWL power chip which provides these powers, and they are connected almost always the same way. However, there's no reason that the powers for DSS couldn't be provided from some other source. As an example, on OMAP3 we could have: (regulator - name - driver) VDDA_DAC - vdda_dac - omapdss_venc VPLL2 - vdds_dsi - omapdss VPLL2 - vdds_dsi - omapdss_dsi So currently we have REGULATOR_SUPPLY defines for each board in all the board files which support display. It would be much better to have an overrideable standard setup for the DSS powers, but this would require dynamically setting up the regulator_consumer_supplies. And I can't see how this could be done, except dynamically creating the regulator_consumer_supply array before initializing the TWL chip, but as DSS is not the only user of those powers the end result could be quite a mess with changes needed in every board file. What if you just do all common DSS REGULATOR_SUPPLY entries in the common platform init code for DSS? Then just set the regulator_init_data pointers based on the desired configuration. Or maybe I misunderstood your problem.. I made a test patch for this (below), but after looking at OMAP3 and 4 TRMs, I don't think this is going to be very good solution. It looks like on OMAP3 the VPLL2 is used (at least) for DSI and CSI. On OMAP4 VCXIO is used for vdda_dpll_mpu, vdda_dpll_core_audio, vdda_dpll_iva_per, vdda_dsi[1:2], vdda_csi2[1:2], vdda_usba0otg_1p8v. VPLL2 and VCXIO do not look like to be dedicated for DSS, so I'm guessing it's more than normal to have more users for the regulators than just DSS (but they just aren't implemented currently). Another option that came to my mind is defining simple macros like: #define OMAP_DSS_REG_SUPPLY_DSS REGULATOR_SUPPLY(vdds_dsi, omapdss) #define OMAP_DSS_REG_SUPPLY_DSI1 REGULATOR_SUPPLY(vdds_dsi, omapdss_dsi1) And then use them instead: static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = { OMAP_DSS_REG_SUPPLY_DSS, OMAP_DSS_REG_SUPPLY_DSI1, }; But that is quite minor improvement, and I'm not even sure if it's an improvement... Tomi diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 9afd087..dedc150 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -394,16 +394,6 @@ static struct regulator_consumer_supply sdp3430_vaux3_supplies[] = { REGULATOR_SUPPLY(vcc, spi1.0), }; -static struct regulator_consumer_supply sdp3430_vdda_dac_supplies[] = { - REGULATOR_SUPPLY(vdda_dac, omapdss_venc), -}; - -/* VPLL2 for digital video outputs */ -static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = { - REGULATOR_SUPPLY(vdds_dsi, omapdss), - REGULATOR_SUPPLY(vdds_dsi, omapdss_dsi1), -}; - static struct regulator_consumer_supply sdp3430_vmmc1_supplies[] = { REGULATOR_SUPPLY(vmmc, omap_hsmmc.0), }; @@ -531,8 +521,8 @@ static struct regulator_init_data sdp3430_vdac = { .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, }, - .num_consumer_supplies = ARRAY_SIZE(sdp3430_vdda_dac_supplies), - .consumer_supplies = sdp3430_vdda_dac_supplies, + .num_consumer_supplies = ARRAY_SIZE(omap_std_vdda_dac_supplies), + .consumer_supplies = omap_std_vdda_dac_supplies, }; static struct regulator_init_data sdp3430_vpll2 = { @@ -546,8 +536,8 @@ static struct regulator_init_data sdp3430_vpll2 = { .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, }, - .num_consumer_supplies = ARRAY_SIZE(sdp3430_vpll2_supplies), - .consumer_supplies = sdp3430_vpll2_supplies, + .num_consumer_supplies = ARRAY_SIZE(omap_std_vdds_dsi_supplies), + .consumer_supplies = omap_std_vdds_dsi_supplies, }; static struct twl4030_codec_audio_data sdp3430_audio; diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 570e83f..bef42bb 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++
Re: [PATCH 07/22] mmc: omap_hsmmc: fix missing mmc_release_host() in no_off case
Hello. On 05-05-2011 15:51, Adrian Hunter wrote: From: Sudhir Bera ext-sudhir.b...@nokia.com In fact the no_off check here will not be hit because 'omap_hsmmc_disabled_to_sleep()' won't schedule a deeper disable in the no_off case. Signed-off-by: Sudhir Bera ext-sudhir.b...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- drivers/mmc/host/omap_hsmmc.c |7 +++ 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bab25ff..bd52849 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1852,14 +1852,13 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) return 0; if (mmc_slot(host).no_off) - return 0; + goto out; if (!((host-mmc-caps MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state mmc_slot(host).get_cover_state(host-dev, host-slot_id { - mmc_release_host(host-mmc); - return 0; + goto out; } This has become a single statement, so {} shpould be removed, no? checkpatch.pl probably warns here?.. WBR, Sergei -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 19/22] OMAP: hsmmc: implement clock switcher
On Thu, May 5, 2011 at 2:51 PM, Adrian Hunter adrian.hun...@nokia.com wrote: From: Andy Shevchenko ext-andriy.shevche...@nokia.com There are 3 new platform data methods which should help us to do a clock switching when notification is happened or request is started. The purpose of the patch is to avoid high frequency of MMC controller on low OPPs due to an HW bug in OMAP 3630. The algorithm: - the PM governor switches the clock of L3 (and therefore L4) bus on demand - the MMC controller clock should follow the change We have considered two OPPs for L3/L4 bus. Thus, we have corresponding flow: - OPP1 - OPP2 (in case of abort - OPP1) - OPP2 - OPP1 (in case of abort - OPP2) During idle the MMC gates functional clock and we don't care about the frequency. Most important to get proper solution when notification comes during request. Then: - in case of OPP1 - OPP2 we update frequency limit and it will be used for new coming requests (it assumes the current frequency of the controller is lower then new one) - otherwise we wait until no device has used higher frequency then upcoming one Known issues and limitations: - originally a clock notifier was used for the core L4 iclk but for upstream Adrian changed to a cpufreq notifier where we assume OPP1 below 400MHz and OPP2 above 400MHz Signed-off-by: Andy Shevchenko ext-andriy.shevche...@nokia.com Signed-off-by: Adrian Hunter adrian.hun...@nokia.com --- arch/arm/mach-omap2/hsmmc.c | 180 - arch/arm/plat-omap/include/plat/mmc.h | 8 ++ 2 files changed, 187 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 6b97fae..34cba89 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c snip + +static int hsmmc_clk_notifier(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct cpufreq_freqs *freqs = data; + unsigned int threshold = 40; /* between opp1 and opp2 */ + + switch (event) { + case CPUFREQ_PRECHANGE: + if (freqs-new threshold freqs-old threshold) { What if we go from 40 to, say, 20? + /* opp2 - opp1 */ + hsmmc_max_freq = HSMMC_MAX_FREQ 1; + + /* Timeout is 1 sec */ + if (!wait_event_timeout(hsmmc_max_freq_wq, + hsmmc_max_freq_ok(), + msecs_to_jiffies(1000))) + pr_err(MMC violates maximum frequency + constraint\n); + } + break; + case CPUFREQ_POSTCHANGE: + if (freqs-old threshold freqs-new threshold) { Same here, you could go from 20 to 40 and then 60 and code would never notice it. + /* opp1 - opp2 */ + hsmmc_max_freq = HSMMC_MAX_FREQ; + } -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 03/10] OMAP4 : DSS2 : HDMI: Dispc gamma enable set/reset function for TV.
Hi Mythri, Sorry for the late reply, I've only noticed this issue today. On Thursday 10 March 2011 11:44:11 Mythri P K wrote: Adding function to reset/set gamma table bit for TV interface currentl only support for disabled is added. Signed-off-by: Mythri P K mythr...@ti.com --- drivers/video/omap2/dss/dispc.c | 13 + drivers/video/omap2/dss/dss.h |1 + 2 files changed, 14 insertions(+), 0 deletions(-) diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b8c576a..9b86f5f 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1008,6 +1008,19 @@ void dispc_set_burst_size(enum omap_plane plane, enable_clocks(0); } +void dispc_enable_gamma_table(bool enable) +{ + /* This is partially implemented to support only + * disabling of the gamma table. + */ + if (enable) { + DSSWARN(Gamma table enabling for TV not yet supported); + return; + } + + REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); Bit 9 in the DISPC_CONFIG register is as FUNCGATED for the OMAP3. From a quick glance at the OMAP36xx and OMAP4430 public TRMs, that's the only DISPC_CONFIG bit that has been changed between OMAP3 and OMAP4. +} + static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) { u32 val; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index c2c0fcf..9f563a6 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -376,6 +376,7 @@ void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height); void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out); +void dispc_enable_gamma_table(bool enable); int dispc_setup_plane(enum omap_plane plane, u32 paddr, u16 screen_width, u16 pos_x, u16 pos_y, -- Regards, Laurent Pinchart -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Common clock and dvfs
On Wed, May 04, 2011 at 11:50:52PM -0700, Colin Cross wrote: True, that was an oversimplificaiton. I meant the minimum voltage that scales with clock frequencies only depends on the clock frequency, not the device. Devices do need to be able to specify a higher minimum voltage, and the regulator api needs to handle it. The regulator API already supports this so we're fine there. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] omap : nand : fix subpage ecc issue with prefetch
Hi Artem, Can you please give a look on this patch? This patch fixes is required for anyone who wants to use this driver without using HW ECC. -- Vimal On Mon, May 2, 2011 at 4:40 PM, Kishore Kadiyala kishore.kadiy...@ti.com wrote: For prefetch engine, read and write got broken in commit '2c01946c'. We never hit a scenario of not getting 'gpmc_prefetch_enable' call success. When reading/writing a subpage with a non divisible by 4 ecc number of bytes, the mis-aligned bytes gets handled first before enabling the Prefetch engine, then it reads/writes rest of the bytes. Signed-off-by: Kishore Kadiyala kishore.kadiy...@ti.com Signed-off-by: Vimal Singh vimal.neww...@gmail.com Reported-by: Bryan DE FARIA bdefa...@adeneo-embedded.com --- drivers/mtd/nand/omap2.c | 12 +--- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index da9a351..2c8040f 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -263,11 +263,10 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) if (ret) { /* PFPW engine is busy, use cpu copy method */ if (info-nand.options NAND_BUSWIDTH_16) - omap_read_buf16(mtd, buf, len); + omap_read_buf16(mtd, (u_char *)p, len); else - omap_read_buf8(mtd, buf, len); + omap_read_buf8(mtd, (u_char *)p, len); } else { - p = (u32 *) buf; do { r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); r_count = r_count 2; @@ -293,7 +292,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, struct omap_nand_info, mtd); uint32_t w_count = 0; int i = 0, ret = 0; - u16 *p; + u16 *p = (u16 *)buf; unsigned long tim, limit; /* take care of subpage writes */ @@ -309,11 +308,10 @@ static void omap_write_buf_pref(struct mtd_info *mtd, if (ret) { /* PFPW engine is busy, use cpu copy method */ if (info-nand.options NAND_BUSWIDTH_16) - omap_write_buf16(mtd, buf, len); + omap_write_buf16(mtd, (u_char *)p, len); else - omap_write_buf8(mtd, buf, len); + omap_write_buf8(mtd, (u_char *)p, len); } else { - p = (u16 *) buf; while (len) { w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); w_count = w_count 1; -- 1.7.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 05/12] OMAP: Serial: Hold console lock for console usage.
Govindraj govindraj...@gmail.com writes: On Thu, May 5, 2011 at 2:13 AM, Kevin Hilman khil...@ti.com wrote: Govindraj.R govindraj.r...@ti.com writes: Acquire console lock before enabling and writing to console-uart to avoid any recursive prints from console write. for ex: -- printk -- uart_console_write -- get_sync -- printk from omap_device enable -- uart_console write By this time, since the device's runtime PM hooks have been called, the device's rutime PM state should be set to RPM_SUSPENDING (not yet RPM_SUSPENDED). In addition to the console lock, you should be able to use that flag to avoid console writes while the console is in the process of suspending. Yes RPM_SUSPENDING check helps along with console lock Great! Changes as below --- diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 59f548f..71964c3 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1040,6 +1040,18 @@ serial_omap_console_write(struct console *co, const char *s, if (console_trylock()) console_lock = 1; + /* +* If console_lock is not available and we are in suspending +* state then we can avoid the console usage scenario +* as this may introduce recursive prints. +* Basically this scenario occurs during boot while +* printing debug bootlogs. +*/ + + if (!console_lock + up-pdev-dev.power.runtime_status == RPM_SUSPENDING) + return; + local_irq_save(flags); if (up-port.sysrq) locked = 0; Is it ok to check the RPM_SUSPENDING flag in driver ? I can't find any API currently available under runtime.h to use. I would propose a new API in pm_runtime.h similar to pm_runtime_suspended() that checks for this. Kevin -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 11/12] OMAP: Serial: Use resume call from prcm to enable uart
Govindraj govindraj...@gmail.com writes: [...] ... this is just putting back basically the same thing that was removed in patch 1. IOW, this is now being checked for *every* PRCM wakeup, which is no different than having it in the idle path. I thought I understood that you had the SW IRQ triggering working, so this part should not be necessary. Actually I tried few experiments but couldn't get it working. What exactly is not working? The interrupt is not firing at all? The driver's ISR is not being called? Tried below but didn't help. diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 3960330..2c1dfc2 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -288,6 +288,16 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) do { if (irqstatus_mpu (OMAP3430_WKUP_ST_MASK | OMAP3430_IO_ST_MASK)) { +#if 1 + /* +* EXP-1: SET UART1 SOFT IRQ BIT +* 3430 -SDP UART1 console. +* M_IRQ_72, INTCPS_ISR_SET +* 0x4820 0090 + (0x20 * n) +* bit-8 n = 2 +*/ + __raw_writel(0x100 , 0x482000D0); +#endif c = _prcm_int_handle_wakeup(); /* --- Currently we are planning to integrate irq_chaining patches on top uart_runtime patches which is work-in-progress. Will remove resume_idle once we have irq_chaining patches available. Well, I'm not OK with $SUBJECT patch as it is since it's just moving an ugly hack from serial.c to the PRCM ISR. If the hack is going to stay, then it should stay where it is until it can be fixed for real. Kevin -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/4] OMAP: cpuidle code clean-up
From: Jean Pihet j-pi...@ti.com Rework of the OMAP2+ cpuidle code v2: rework after comments on linux-omap ML: - remove useless macros, - replace the C-state common data fill-in helper macro by an inline function, for better readability, - update commits description. v1: - optimize the cpuidle C-states data registration and storage, - change the interaction with the debugfs 'enable_off_mode' knob and the use of the C-states 'valid' internal field, - remove dead code, - improve code readability. Tested on Beagleboard B5 with cpuidle in RET and OFF modes. Another 145 lines of OMAP code gone ;p Notes: 1) the debugfs 'enable_off_mode' knob will be deprecated by the use of the devices constraints framework to restrict the power domains power modes. 2) the MPU and CORE power domains low power modes are controlled by cpuidle, based on the allowed overall sleep+wake-up latencies and the wake-up latency constraints on the MPU. This is incorrect. The devices constraints framework shall be used instead to control all power domains. ToDo: - integrate cpuidle with the devices constraints framework, when merged in, - refine the latency figures and express them in term of available data from other frameworks (OMAP PM, constaints framework, omap_devices, new VC/VP voltage and DVFS code ...), Rebased on khilman's for_2.6.40/pm-cleanup branch Jean Pihet (4): OMAP3: clean-up mach specific cpuidle data structures OMAP3: cpuidle: re-organize the C-states data OMAP3: cpuidle: code rework for improved readability OMAP3: cpuidle: change the power domains modes determination logic arch/arm/mach-omap2/board-rx51.c | 18 +- arch/arm/mach-omap2/cpuidle34xx.c | 426 + arch/arm/mach-omap2/pm.h | 17 +- arch/arm/mach-omap2/pm34xx.c | 12 - 4 files changed, 164 insertions(+), 309 deletions(-) -- 1.7.2.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/4] OMAP3: clean-up mach specific cpuidle data structures
From: Jean Pihet j-pi...@ti.com - sleep_latency and wake_latency are not used, replace them by exit_latency which is used by cpuidle. exit_latency simply is the sum of sleep_latency and wake_latency, - replace threshold by target_residency, - changed the OMAP3 specific cpuidle code accordingly, - changed the OMAP3 board code accordingly. Signed-off-by: Jean Pihet j-pi...@ti.com --- arch/arm/mach-omap2/board-rx51.c | 18 --- arch/arm/mach-omap2/cpuidle34xx.c | 103 +++- arch/arm/mach-omap2/pm.h | 13 +++-- 3 files changed, 63 insertions(+), 71 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index e964895..3629f9e 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -58,21 +58,25 @@ static struct platform_device leds_gpio = { }, }; +/* + * cpuidle C-states definition override from the default values. + * The 'exit_latency' field is the sum of sleep and wake-up latencies. + */ static struct cpuidle_params rx51_cpuidle_params[] = { /* C1 */ - {1, 110, 162, 5}, + {110 + 162, 5 , 1}, /* C2 */ - {1, 106, 180, 309}, + {106 + 180, 309, 1}, /* C3 */ - {0, 107, 410, 46057}, + {107 + 410, 46057, 0}, /* C4 */ - {0, 121, 3374, 46057}, + {121 + 3374, 46057, 0}, /* C5 */ - {1, 855, 1146, 46057}, + {855 + 1146, 46057, 1}, /* C6 */ - {0, 7580, 4134, 484329}, + {7580 + 4134, 484329, 0}, /* C7 */ - {1, 7505, 15274, 484329}, + {7505 + 15274, 484329, 1}, }; static struct omap_lcd_config rx51_lcd_config = { diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 1c240ef..d7bc31a 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -52,11 +52,10 @@ struct omap3_processor_cx { u8 valid; u8 type; - u32 sleep_latency; - u32 wakeup_latency; + u32 exit_latency; u32 mpu_state; u32 core_state; - u32 threshold; + u32 target_residency; u32 flags; const char *desc; }; @@ -75,19 +74,19 @@ struct powerdomain *cam_pd; */ static struct cpuidle_params cpuidle_params_table[] = { /* C1 */ - {1, 2, 2, 5}, + {2 + 2, 5, 1}, /* C2 */ - {1, 10, 10, 30}, + {10 + 10, 30, 1}, /* C3 */ - {1, 50, 50, 300}, + {50 + 50, 300, 1}, /* C4 */ - {1, 1500, 1800, 4000}, + {1500 + 1800, 4000, 1}, /* C5 */ - {1, 2500, 7500, 12000}, + {2500 + 7500, 12000, 1}, /* C6 */ - {1, 3000, 8500, 15000}, + {3000 + 8500, 15000, 1}, /* C7 */ - {1, 1, 3, 30}, + {1 + 3, 30, 1}, }; static int omap3_idle_bm_check(void) @@ -330,12 +329,10 @@ void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params) for (i = OMAP3_STATE_C1; i OMAP3_MAX_STATES; i++) { cpuidle_params_table[i].valid = cpuidle_board_params[i].valid; - cpuidle_params_table[i].sleep_latency = - cpuidle_board_params[i].sleep_latency; - cpuidle_params_table[i].wake_latency = - cpuidle_board_params[i].wake_latency; - cpuidle_params_table[i].threshold = - cpuidle_board_params[i].threshold; + cpuidle_params_table[i].exit_latency = + cpuidle_board_params[i].exit_latency; + cpuidle_params_table[i].target_residency = + cpuidle_board_params[i].target_residency; } return; } @@ -357,12 +354,10 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C1].valid = cpuidle_params_table[OMAP3_STATE_C1].valid; omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1; - omap3_power_states[OMAP3_STATE_C1].sleep_latency = - cpuidle_params_table[OMAP3_STATE_C1].sleep_latency; - omap3_power_states[OMAP3_STATE_C1].wakeup_latency = - cpuidle_params_table[OMAP3_STATE_C1].wake_latency; - omap3_power_states[OMAP3_STATE_C1].threshold = - cpuidle_params_table[OMAP3_STATE_C1].threshold; + omap3_power_states[OMAP3_STATE_C1].exit_latency = + cpuidle_params_table[OMAP3_STATE_C1].exit_latency; + omap3_power_states[OMAP3_STATE_C1].target_residency = + cpuidle_params_table[OMAP3_STATE_C1].target_residency; omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID; @@ -372,12 +367,10 @@ void omap_init_power_states(void)
[PATCH 2/4] OMAP3: cpuidle: re-organize the C-states data
From: Jean Pihet j-pi...@ti.com The current implementation defines an internal structure and a C-states array. Using those structures is redundant to the structs used by the cpuidle framework. This patch provides a clean-up of the internal struct, removes the internal C-states array, stores the data using the existing cpuidle per C-state struct and registers the mach specific data to cpuidle C-state driver_data (accessed using cpuidle_[gs]et_statedata). Also removes unused macros, fields and code and compacts the repeating code using an inline helper function. The result is more compact and more readable code as well as reduced data RAM usage. Signed-off-by: Jean Pihet j-pi...@ti.com --- arch/arm/mach-omap2/cpuidle34xx.c | 291 1 files changed, 97 insertions(+), 194 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index d7bc31a..816b483 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -36,34 +36,19 @@ #ifdef CONFIG_CPU_IDLE -#define OMAP3_MAX_STATES 7 -#define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */ -#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */ -#define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */ -#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */ -#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */ -#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */ -#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */ +#define OMAP3_STATE_MIN0 +#define OMAP3_STATE_MAX6 /* Deepest sleep C-state */ +#define OMAP3_NB_STATES(OMAP3_STATE_MAX + 1) -#define OMAP3_STATE_MAX OMAP3_STATE_C7 - -#define CPUIDLE_FLAG_CHECK_BM 0x1 /* use omap3_enter_idle_bm() */ - -struct omap3_processor_cx { - u8 valid; - u8 type; - u32 exit_latency; +/* Mach specific information to be recorded in the C-state driver_data */ +struct omap3_idle_statedata { u32 mpu_state; u32 core_state; - u32 target_residency; - u32 flags; - const char *desc; + u8 valid; }; +struct omap3_idle_statedata omap3_idle_data[OMAP3_NB_STATES]; -struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; -struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd, *per_pd; -struct powerdomain *cam_pd; +struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; /* * The latencies/thresholds for various C states have @@ -72,7 +57,7 @@ struct powerdomain *cam_pd; * the best power savings) used on boards which do not * pass these details from the board file. */ -static struct cpuidle_params cpuidle_params_table[] = { +static struct cpuidle_params cpuidle_params_table[OMAP3_NB_STATES] = { /* C1 */ {2 + 2, 5, 1}, /* C2 */ @@ -121,12 +106,10 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { - struct omap3_processor_cx *cx = cpuidle_get_statedata(state); + struct omap3_idle_statedata *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx-mpu_state, core_state = cx-core_state; - current_cx_state = *cx; - /* Used to keep track of the total time in idle */ getnstimeofday(ts_preidle); @@ -139,7 +122,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev, if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { + /* Deny idle for C1 */ + if (state == dev-states[0]) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); } @@ -147,7 +131,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev, /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { + /* Re-allow idle for C1 */ + if (state == dev-states[0]) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); } @@ -169,15 +154,15 @@ return_sleep_time: * * If the current state is valid, it is returned back to the caller. * Else, this function searches for a lower c-state which is still - * valid (as defined in omap3_power_states[]). + * valid. */ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, - struct cpuidle_state *curr) + struct cpuidle_state *curr) { struct cpuidle_state *next = NULL; - struct omap3_processor_cx *cx; + struct omap3_idle_statedata *cx; - cx = (struct omap3_processor_cx *)cpuidle_get_statedata(curr); + cx = cpuidle_get_statedata(curr); /* Check if
[PATCH 3/4] OMAP3: cpuidle: code rework for improved readability
From: Jean Pihet j-pi...@ti.com - fix single and multi-lines comments format - removed the omap3_idle_bm_check function and replaced the test in omap3_enter_idle_bm by the equivalent code - re-organize omap3_enter_idle_bm code path, assign local variables only when needed - reword some comments Signed-off-by: Jean Pihet j-pi...@ti.com --- arch/arm/mach-omap2/cpuidle34xx.c | 52 +--- 1 files changed, 19 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 816b483..5621b6e 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -74,13 +74,6 @@ static struct cpuidle_params cpuidle_params_table[OMAP3_NB_STATES] = { {1 + 3, 30, 1}, }; -static int omap3_idle_bm_check(void) -{ - if (!omap3_can_sleep()) - return 1; - return 0; -} - static int _cpuidle_allow_idle(struct powerdomain *pwrdm, struct clockdomain *clkdm) { @@ -160,9 +153,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, struct cpuidle_state *curr) { struct cpuidle_state *next = NULL; - struct omap3_idle_statedata *cx; - - cx = cpuidle_get_statedata(curr); + struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); /* Check if current state is valid */ if (cx-valid) { @@ -170,9 +161,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, } else { u8 idx = OMAP3_STATE_MAX; - /* -* Reach the current state starting at highest C-state -*/ + /* Reach the current state starting at highest C-state */ for (; idx = OMAP3_STATE_MIN; idx--) { if (dev-states[idx] == curr) { next = dev-states[idx]; @@ -180,9 +169,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, } } - /* -* Should never hit this condition. -*/ + /* Should never hit this condition */ WARN_ON(next == NULL); /* @@ -217,29 +204,16 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { - struct cpuidle_state *new_state = next_valid_state(dev, state); - u32 core_next_state, per_next_state = 0, per_saved_state = 0; - u32 cam_state; + struct cpuidle_state *new_state; + u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; struct omap3_idle_statedata *cx; int ret; - if (omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); + if (!omap3_can_sleep()) { new_state = dev-safe_state; goto select_state; } - cx = cpuidle_get_statedata(state); - core_next_state = cx-core_state; - - /* -* FIXME: we currently manage device-specific idle states -*for PER and CORE in combination with CPU-specific -*idle states. This is wrong, and device-specific -*idle management needs to be separated out into -*its own code. -*/ - /* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. @@ -251,9 +225,19 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, } /* +* FIXME: we currently manage device-specific idle states +*for PER and CORE in combination with CPU-specific +*idle states. This is wrong, and device-specific +*idle management needs to be separated out into +*its own code. +*/ + + /* * Prevent PER off if CORE is not in retention or off as this * would disable PER wakeups completely. */ + cx = cpuidle_get_statedata(state); + core_next_state = cx-core_state; per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); if ((per_next_state == PWRDM_POWER_OFF) (core_next_state PWRDM_POWER_RET)) @@ -263,6 +247,8 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); + new_state = next_valid_state(dev, state); + select_state: dev-last_state = new_state; ret = omap3_enter_idle(dev, new_state); @@ -323,7 +309,7 @@ struct cpuidle_driver omap3_idle_driver = { .owner =THIS_MODULE, }; -/* Fill in the state data from the mach tables and register the driver_data */ +/* Helper
[PATCH 4/4] OMAP3: cpuidle: change the power domains modes determination logic
From: Jean Pihet j-pi...@ti.com The achievable power modes of the power domains in cpuidle depends on the system wide 'enable_off_mode' knob in debugfs. Upon changing enable_off_mode, do not change the C-states 'valid' field but instead dynamically restrict the power modes when entering idle. The C-states 'valid' field is just used to enable/disable some C-states at init and shall not be changed later on. Signed-off-by: Jean Pihet j-pi...@ti.com --- arch/arm/mach-omap2/cpuidle34xx.c | 58 +++- arch/arm/mach-omap2/pm.h |4 -- arch/arm/mach-omap2/pm34xx.c | 12 --- 3 files changed, 24 insertions(+), 50 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 5621b6e..402fd4d 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -141,22 +141,40 @@ return_sleep_time: } /** - * next_valid_state - Find next valid c-state + * next_valid_state - Find next valid C-state * @dev: cpuidle device - * @state: Currently selected c-state + * @state: Currently selected C-state * * If the current state is valid, it is returned back to the caller. * Else, this function searches for a lower c-state which is still * valid. + * + * A state is valid if the 'valid' field is enabled and + * if it satisfies the enable_off_mode condition. */ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, struct cpuidle_state *curr) { struct cpuidle_state *next = NULL; struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); + u32 mpu_deepest_state = PWRDM_POWER_RET; + u32 core_deepest_state = PWRDM_POWER_RET; + + if (enable_off_mode) { + mpu_deepest_state = PWRDM_POWER_OFF; + /* +* Erratum i583: valable for ES rev Es1.2 on 3630. +* CORE OFF mode is not supported in a stable form, restrict +* instead the CORE state to RET. +*/ + if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) + core_deepest_state = PWRDM_POWER_OFF; + } /* Check if current state is valid */ - if (cx-valid) { + if ((cx-valid) + (cx-mpu_state = mpu_deepest_state) + (cx-core_state = core_deepest_state)) { return curr; } else { u8 idx = OMAP3_STATE_MAX; @@ -179,7 +197,9 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, idx--; for (; idx = OMAP3_STATE_MIN; idx--) { cx = cpuidle_get_statedata(dev-states[idx]); - if (cx-valid) { + if ((cx-valid) + (cx-mpu_state = mpu_deepest_state) + (cx-core_state = core_deepest_state)) { next = dev-states[idx]; break; } @@ -262,31 +282,6 @@ select_state: DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); -/** - * omap3_cpuidle_update_states() - Update the cpuidle states - * @mpu_deepest_state: Enable states up to and including this for mpu domain - * @core_deepest_state:Enable states up to and including this for core domain - * - * This goes through the list of states available and enables and disables the - * validity of C states based on deepest state that can be achieved for the - * variable domain - */ -void omap3_cpuidle_update_states(u32 mpu_deepest_state, u32 core_deepest_state) -{ - int i; - - for (i = OMAP3_STATE_MIN; i OMAP3_NB_STATES; i++) { - struct omap3_idle_statedata *cx = omap3_idle_data[i]; - - if ((cx-mpu_state = mpu_deepest_state) - (cx-core_state = core_deepest_state)) { - cx-valid = 1; - } else { - cx-valid = 0; - } - } -} - void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params) { int i; @@ -400,11 +395,6 @@ int __init omap3_idle_init(void) dev-state_count = OMAP3_NB_STATES; - if (enable_off_mode) - omap3_cpuidle_update_states(PWRDM_POWER_OFF, PWRDM_POWER_OFF); - else - omap3_cpuidle_update_states(PWRDM_POWER_RET, PWRDM_POWER_RET); - if (cpuidle_register_device(dev)) { printk(KERN_ERR %s: CPUidle register device failed\n, __func__); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 32dbc13..45bcfce 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -78,10 +78,6 @@ extern u32 sleep_while_idle; #define sleep_while_idle 0 #endif -#if defined(CONFIG_CPU_IDLE) -extern void omap3_cpuidle_update_states(u32, u32); -#endif - #if defined(CONFIG_PM_DEBUG)
DSS pm_runtime problem
Hi Paul, Benoit, I've started testing pm runtime with DSS, and I encountered a problem. I'm using latest -rc5 as a base, and it looks like omap_hwmod:_wait_target_ready() does not succeed for dss_core hwmod. This causes _enable() to fail, but omap_device_enable_hwmods() does not check the return values so it looks like everything went well, until the driver crashes as the DSS HW module was off. Ideas about _wait_target_ready()? And omap_device_enable_hwmods() would need some fixing, I wasted quite a while debugging this =). Tomi -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Module + offset calculations have to be signed in arch/arm/mach-omap2/pm-debug.c
I've been working on getting the TI OMAPPSP-03.00.01.06 kernel to properly suspend/resume on my DM37x board and all was going well until I added OTG support to the kernel and on suspend, the IVA2 and CORE pwrdms would not properly go into suspend. When comparing output from /debug/pm-debug/registers/current to the TRM, I noticed the following: MOD: CM_IVA2 (48014000) 04 = 0017 20 = 0001 24 = 0001 34 = 0001 40 = 00080a00 44 = 0001 48 = 0003 MOD: PRM_IVA2 (48316000) 50 = 0007 e0 = 00ff0f05 e4 = 0ff7 e8 = 0ff7 f8 = 0001 Looking at the TRM, the PRM_IVA2 registers are at 0x48306000, not 0x48316000. OMAP3430_IVA2_MOD is defined in prcm-common.h as -0x800 which means any module + reg_offset address calculation has to be signed. Once I corrected the unsigned short offset declaration in pm_module_def, rebuilt and tested again, IVA2/core pwrdms go into suspend correctly (and addresses look correct): Signed-off-by: Peter Barada peter.bar...@logicpd.com diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 125f565..b731ef3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -199,7 +199,7 @@ enum { struct pm_module_def { char name[8]; /* Name of the module */ short type; /* CM or PRM */ -unsigned short offset; +short offset; int low; /* First register address on this module */ int high; /* Last register address on this module */ }; -- Peter Barada peter.bar...@gmail.com -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: DSS pm_runtime problem
On Thu, 2011-05-05 at 18:59 +0300, Tomi Valkeinen wrote: Hi Paul, Benoit, I've started testing pm runtime with DSS, and I encountered a problem. I'm using latest -rc5 as a base, and it looks like omap_hwmod:_wait_target_ready() does not succeed for dss_core hwmod. This causes _enable() to fail, but omap_device_enable_hwmods() does not check the return values so it looks like everything went well, until the driver crashes as the DSS HW module was off. Ideas about _wait_target_ready()? And omap_device_enable_hwmods() would need some fixing, I wasted quite a while debugging this =). Ah, the HW needs dss_dss_clk to be enabled before calling pm_runtime_get, otherwise _wait_target_ready() fails. Now that I think, I guess Sumit mentioned this at some point. Too bad, I was hoping I could enable the required opt clocks in runtime_resume callback. Shouldn't the hwmod code be able to enable/reset/etc the HW module independently? I wonder if this goes for all other DSS modules also... Tomi -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: DSS pm_runtime problem
Hi Tomi, On 5/5/2011 5:59 PM, Valkeinen, Tomi wrote: Hi Paul, Benoit, I've started testing pm runtime with DSS, and I encountered a problem. I'm using latest -rc5 as a base, and it looks like omap_hwmod:_wait_target_ready() does not succeed for dss_core hwmod. This causes _enable() to fail, but omap_device_enable_hwmods() does not check the return values so it looks like everything went well, until the driver crashes as the DSS HW module was off. Ideas about _wait_target_ready()? And omap_device_enable_hwmods() would need some fixing, I wasted quite a while debugging this =). The wait_target_ready is waiting for the PRCM status. It the status does not change, it is probably because some inputs clocks... like the optional ones are not enabled. In your case, you have to enable the DSS fck before calling into PM runtime because hwmod does mark this clock as optional:-( Regards, Benoit -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Module + offset calculations have to be signed in arch/arm/mach-omap2/pm-debug.c
Peter Barada peter.bar...@gmail.com writes: I've been working on getting the TI OMAPPSP-03.00.01.06 kernel to properly suspend/resume on my DM37x board and all was going well until I added OTG support to the kernel and on suspend, the IVA2 and CORE pwrdms would not properly go into suspend. When comparing output from /debug/pm-debug/registers/current to the TRM, I noticed the following: MOD: CM_IVA2 (48014000) 04 = 0017 20 = 0001 24 = 0001 34 = 0001 40 = 00080a00 44 = 0001 48 = 0003 MOD: PRM_IVA2 (48316000) 50 = 0007 e0 = 00ff0f05 e4 = 0ff7 e8 = 0ff7 f8 = 0001 Looking at the TRM, the PRM_IVA2 registers are at 0x48306000, not 0x48316000. OMAP3430_IVA2_MOD is defined in prcm-common.h as -0x800 which means any module + reg_offset address calculation has to be signed. Once I corrected the unsigned short offset declaration in pm_module_def, rebuilt and tested again, IVA2/core pwrdms go into suspend correctly (and addresses look correct): Just to be clear, this should only affect the display of the registers, not whether or not the power domains actually suspend correctly, right? Or, did you actually notice via some other method that this powerdomain was not hitting retention/off? Kevin Signed-off-by: Peter Barada peter.bar...@logicpd.com diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 125f565..b731ef3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -199,7 +199,7 @@ enum { struct pm_module_def { char name[8]; /* Name of the module */ short type; /* CM or PRM */ -unsigned short offset; +short offset; int low; /* First register address on this module */ int high; /* Last register address on this module */ }; -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: DSS pm_runtime problem
You were faster than me :-) On 5/5/2011 7:02 PM, Valkeinen, Tomi wrote: On Thu, 2011-05-05 at 18:59 +0300, Tomi Valkeinen wrote: Hi Paul, Benoit, I've started testing pm runtime with DSS, and I encountered a problem. I'm using latest -rc5 as a base, and it looks like omap_hwmod:_wait_target_ready() does not succeed for dss_core hwmod. This causes _enable() to fail, but omap_device_enable_hwmods() does not check the return values so it looks like everything went well, until the driver crashes as the DSS HW module was off. Ideas about _wait_target_ready()? And omap_device_enable_hwmods() would need some fixing, I wasted quite a while debugging this =). Ah, the HW needs dss_dss_clk to be enabled before calling pm_runtime_get, otherwise _wait_target_ready() fails. Now that I think, I guess Sumit mentioned this at some point. Too bad, I was hoping I could enable the required opt clocks in runtime_resume callback. I guess we should at some point control that clock from the fmwk. Unfortunately, we still do not have the good hwmod representation for the DSS for the moment. I'm working on something for all these big subsystems like DSS, ISS, c2c to try to fix that. It will unfortunately not be there for 2.6.40 :-( Shouldn't the hwmod code be able to enable/reset/etc the HW module independently? Yes, it should, but we have to change the fck / modulemode / opt_clk management for the DSS hwmod. I wonder if this goes for all other DSS modules also... We do have some dependency between all DSS modules and the dss_core that are not handled today by the fmwk:-( Regards, Benoit -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Module + offset calculations have to be signed in arch/arm/mach-omap2/pm-debug.c
On 05/05/2011 01:11 PM, Kevin Hilman wrote: Peter Baradapeter.bar...@gmail.com writes: I've been working on getting the TI OMAPPSP-03.00.01.06 kernel to properly suspend/resume on my DM37x board and all was going well until I added OTG support to the kernel and on suspend, the IVA2 and CORE pwrdms would not properly go into suspend. When comparing output from /debug/pm-debug/registers/current to the TRM, I noticed the following: MOD: CM_IVA2 (48014000) 04 = 0017 20 = 0001 24 = 0001 34 = 0001 40 = 00080a00 44 = 0001 48 = 0003 MOD: PRM_IVA2 (48316000) 50 = 0007 e0 = 00ff0f05 e4 = 0ff7 e8 = 0ff7 f8 = 0001 Looking at the TRM, the PRM_IVA2 registers are at 0x48306000, not 0x48316000. OMAP3430_IVA2_MOD is defined in prcm-common.h as -0x800 which means any module + reg_offset address calculation has to be signed. Once I corrected the unsigned short offset declaration in pm_module_def, rebuilt and tested again, IVA2/core pwrdms go into suspend correctly (and addresses look correct): Just to be clear, this should only affect the display of the registers, not whether or not the power domains actually suspend correctly, right? Or, did you actually notice via some other method that this powerdomain was not hitting retention/off? Yes the change affects the registers displayed, but since the address calculation is incorrect with CONFIG_PM_DEBUG enabled, the PM_DEBUG code is reading the CM_IVA2/PRM_IVA2 registers at incorrect addresses. On my DM37x board when I suspended with OTG enabled (and without the patch), I see the following on resume: [ 496.168151] Powerdomain (iva2_pwrdm) didn't enter target state 1 (last power state 3) [ 496.176025] Powerdomain (core_pwrdm) didn't enter target state 1 (last power state 3) [ 496.183898] Could not enter target state in pm_suspend With the patch (and same kernel config) I see the following on resume: [ 234.867889] Successfully put all powerdomains to target state Before enabling the OTG code all powerdomains went into suspend. It could be that accessing registers at the incorrect addresses is causing DM37x to keep those domains out of retention... Kevin Signed-off-by: Peter Baradapeter.bar...@logicpd.com diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 125f565..b731ef3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -199,7 +199,7 @@ enum { struct pm_module_def { char name[8]; /* Name of the module */ short type; /* CM or PRM */ -unsigned short offset; +short offset; int low; /* First register address on this module */ int high; /* Last register address on this module */ }; -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- Peter Barada peter.bar...@gmail.com -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 12/12] OMAP2: Serial: Add no async wake flag.
Govindraj.R govindraj.r...@ti.com writes: For omap2 cpu_idle thread will not be available Why not? and uart_clock cutting happens only in suspend path. Aren't clocks also cut after runtime PM autosuspend? Prior to this patch the uart_clock was cut using prepare/resume calls since these funcs are no more available with runtime changes use no_async_wake flag to keep clock active during bootup otherwise uart port will disabled during boot-up and cannot be enabled back. This doesn't just keep clock active during bootup, but it keeps clock active always, except during suspend. Also based on this flag we can disable uart port during suspend and enable back during resume. I think disabling UART port during suspend should already be part of an earlier patch. This patch should then only make it conditional. Signed-off-by: Govindraj.R govindraj.r...@ti.com --- arch/arm/mach-omap2/serial.c |7 +++ arch/arm/plat-omap/include/plat/omap-serial.h |3 +++ drivers/tty/serial/omap-serial.c | 14 ++ 3 files changed, 24 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index d4ef370..1af9fd5 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -245,6 +245,12 @@ static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable) static void omap_uart_idle_init(struct omap_uart_port_info *uart, unsigned short num) { + /* On omap2 no cpu_idle and async wakeup from prcm_module. Please remove comments about CPU idle, as the need for this has nothing to do with CPU idle. + * This flag can be used to cut clocks only in suspend path. + * to avoid boot break due to aggressive clock cutting from + * omap-serial driver. + */ fix multi-line comment style throughout + uart-no_async_wake = true; If needed (which I still don't think I understand), for readability sake this flag should be called 'has_async_wake', and default to false. It should then be set to true on available SoCs. Kevin if (cpu_is_omap34xx()) { u32 mod = num 1 ? OMAP3430_PER_MOD : CORE_MOD; u32 wk_mask = 0; @@ -266,6 +272,7 @@ static void omap_uart_idle_init(struct omap_uart_port_info *uart, break; } uart-wk_mask = wk_mask; + uart-no_async_wake = false; } else if (cpu_is_omap24xx()) { u32 wk_mask = 0; u32 wk_en = PM_WKEN1, wk_st = PM_WKST1; diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index b5117bd..1de5bc4 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -79,6 +79,7 @@ struct omap_uart_port_info { void __iomem *wk_st; void __iomem *wk_en; u32 wk_mask; + boolno_async_wake; }; struct uart_omap_dma { @@ -134,6 +135,8 @@ struct uart_omap_port { unsigned interrata; void (*enable_wakeup)(struct platform_device *, bool); bool (*chk_wakeup)(struct platform_device *); + + boolno_async_wake; }; #endif /* __OMAP_SERIAL_H__ */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index eea478c..59f548f 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1168,6 +1168,13 @@ static int serial_omap_suspend(struct device *dev) uart_suspend_port(serial_omap_reg, up-port); console_trylock(); serial_omap_pm(up-port, 3, 0); + + /* OMAP2 dont have cpu_idle thread and async wakeup from prcm. + * For such socs clocks will be kept active from probe and + * cut only in suspend path. + */ + if (up-no_async_wake) + serial_omap_port_disable(up); } return 0; } @@ -1179,6 +1186,9 @@ static int serial_omap_resume(struct device *dev) if (up) { uart_resume_port(serial_omap_reg, up-port); console_unlock(); + + if (up-no_async_wake) + serial_omap_port_enable(up); } return 0; @@ -1402,6 +1412,7 @@ static int serial_omap_probe(struct platform_device *pdev) up-errata = omap_up_info-errata; up-enable_wakeup = omap_up_info-enable_wakeup; up-chk_wakeup = omap_up_info-chk_wakeup; + up-no_async_wake = omap_up_info-no_async_wake; if (omap_up_info-dma_enabled) { up-uart_dma.uart_dma_tx = dma_tx-start; @@ -1430,6 +1441,9 @@ static int serial_omap_probe(struct platform_device *pdev) serial_omap_port_disable(up); } + if (up-no_async_wake) + serial_omap_port_enable(up); +
Re: [PATCH 2/4] OMAP3: cpuidle: re-organize the C-states data
Hi Jean, jean.pi...@newoldbits.com writes: From: Jean Pihet j-pi...@ti.com The current implementation defines an internal structure and a C-states array. Using those structures is redundant to the structs used by the cpuidle framework. This patch provides a clean-up of the internal struct, removes the internal C-states array, stores the data using the existing cpuidle per C-state struct and registers the mach specific data to cpuidle C-state driver_data (accessed using cpuidle_[gs]et_statedata). Also removes unused macros, fields and code and compacts the repeating code using an inline helper function. The result is more compact and more readable code as well as reduced data RAM usage. Signed-off-by: Jean Pihet j-pi...@ti.com Some minor comments below... --- arch/arm/mach-omap2/cpuidle34xx.c | 291 1 files changed, 97 insertions(+), 194 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index d7bc31a..816b483 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -36,34 +36,19 @@ #ifdef CONFIG_CPU_IDLE -#define OMAP3_MAX_STATES 7 -#define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */ -#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */ -#define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */ -#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */ -#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */ -#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */ -#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */ +#define OMAP3_STATE_MIN 0 +#define OMAP3_STATE_MAX 6 /* Deepest sleep C-state */ +#define OMAP3_NB_STATES (OMAP3_STATE_MAX + 1) How about droping MIN and MAX all together. Min is always zero, just use zero in the code. Then later, static struct cpuidle_params cpuidle_params_table[] = { /* C1 */ {2 + 2, 5, 1}, ... }; #define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table); This way is less error prone, since when adding/removing states, you don't also have to manually update NUM_STATES. -#define OMAP3_STATE_MAX OMAP3_STATE_C7 - -#define CPUIDLE_FLAG_CHECK_BM0x1 /* use omap3_enter_idle_bm() */ - -struct omap3_processor_cx { - u8 valid; - u8 type; - u32 exit_latency; +/* Mach specific information to be recorded in the C-state driver_data */ +struct omap3_idle_statedata { u32 mpu_state; u32 core_state; - u32 target_residency; - u32 flags; - const char *desc; + u8 valid; }; +struct omap3_idle_statedata omap3_idle_data[OMAP3_NB_STATES]; -struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; -struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd, *per_pd; -struct powerdomain *cam_pd; +struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; /* * The latencies/thresholds for various C states have @@ -72,7 +57,7 @@ struct powerdomain *cam_pd; * the best power savings) used on boards which do not * pass these details from the board file. */ -static struct cpuidle_params cpuidle_params_table[] = { +static struct cpuidle_params cpuidle_params_table[OMAP3_NB_STATES] = { /* C1 */ {2 + 2, 5, 1}, /* C2 */ @@ -121,12 +106,10 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { - struct omap3_processor_cx *cx = cpuidle_get_statedata(state); + struct omap3_idle_statedata *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx-mpu_state, core_state = cx-core_state; - current_cx_state = *cx; - /* Used to keep track of the total time in idle */ getnstimeofday(ts_preidle); @@ -139,7 +122,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev, if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { + /* Deny idle for C1 */ + if (state == dev-states[0]) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); } @@ -147,7 +131,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev, /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { + /* Re-allow idle for C1 */ + if (state == dev-states[0]) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); } @@ -169,15 +154,15 @@ return_sleep_time: * * If the current state is valid, it is returned back to the caller. * Else, this function searches for a lower c-state which is still - * valid (as defined in omap3_power_states[]). +
Re: Module + offset calculations have to be signed in arch/arm/mach-omap2/pm-debug.c
Peter Barada peter.bar...@gmail.com writes: On 05/05/2011 01:11 PM, Kevin Hilman wrote: Peter Baradapeter.bar...@gmail.com writes: I've been working on getting the TI OMAPPSP-03.00.01.06 kernel to properly suspend/resume on my DM37x board and all was going well until I added OTG support to the kernel and on suspend, the IVA2 and CORE pwrdms would not properly go into suspend. When comparing output from /debug/pm-debug/registers/current to the TRM, I noticed the following: MOD: CM_IVA2 (48014000) 04 = 0017 20 = 0001 24 = 0001 34 = 0001 40 = 00080a00 44 = 0001 48 = 0003 MOD: PRM_IVA2 (48316000) 50 = 0007 e0 = 00ff0f05 e4 = 0ff7 e8 = 0ff7 f8 = 0001 Looking at the TRM, the PRM_IVA2 registers are at 0x48306000, not 0x48316000. OMAP3430_IVA2_MOD is defined in prcm-common.h as -0x800 which means any module + reg_offset address calculation has to be signed. Once I corrected the unsigned short offset declaration in pm_module_def, rebuilt and tested again, IVA2/core pwrdms go into suspend correctly (and addresses look correct): Just to be clear, this should only affect the display of the registers, not whether or not the power domains actually suspend correctly, right? Or, did you actually notice via some other method that this powerdomain was not hitting retention/off? Yes the change affects the registers displayed, but since the address calculation is incorrect with CONFIG_PM_DEBUG enabled, the PM_DEBUG code is reading the CM_IVA2/PRM_IVA2 registers at incorrect addresses. On my DM37x board when I suspended with OTG enabled (and without the patch), I see the following on resume: [ 496.168151] Powerdomain (iva2_pwrdm) didn't enter target state 1 (last power state 3) [ 496.176025] Powerdomain (core_pwrdm) didn't enter target state 1 (last power state 3) Hmm, this 'last power state' printk isn't in mainline, so it appears there are some other local modifications to this code. [ 496.183898] Could not enter target state in pm_suspend With the patch (and same kernel config) I see the following on resume: [ 234.867889] Successfully put all powerdomains to target state Before enabling the OTG code all powerdomains went into suspend. It could be that accessing registers at the incorrect addresses is causing DM37x to keep those domains out of retention... Hmm, very strange. The PM debug code only ever reads registers, never writes, so I can't imagine how that should prevent those power domains from hitting retention. Are there any other out-of-tree patches to the pm-debug code in your kernel? In any case, you've found a real bug, and your patch is valid. However, it doesn't currently apply to mainline, and it looks like it's because your patch is using spaces and the code being patched is using tabs. Also, you can simplify the changelog to to just describe the fix needed due to using negative offsets in some PRM modules. Kevin Kevin Signed-off-by: Peter Baradapeter.bar...@logicpd.com diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 125f565..b731ef3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -199,7 +199,7 @@ enum { struct pm_module_def { char name[8]; /* Name of the module */ short type; /* CM or PRM */ -unsigned short offset; +short offset; int low; /* First register address on this module */ int high; /* Last register address on this module */ }; -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] omap : nand : fix subpage ecc issue with prefetch
On Mon, 2011-05-02 at 16:40 +0530, Kishore Kadiyala wrote: For prefetch engine, read and write got broken in commit '2c01946c'. We never hit a scenario of not getting 'gpmc_prefetch_enable' call success. When reading/writing a subpage with a non divisible by 4 ecc number of bytes, the mis-aligned bytes gets handled first before enabling the Prefetch engine, then it reads/writes rest of the bytes. Signed-off-by: Kishore Kadiyala kishore.kadiy...@ti.com Signed-off-by: Vimal Singh vimal.neww...@gmail.com Reported-by: Bryan DE FARIA bdefa...@adeneo-embedded.com This needs a better commit message with more explanation and analysis of the problem and how it was fixed.This commit message is not very understandable. And then it needs also: Cc: sta...@kernel.org [2.6.36+] Right? And then we could send it upstream. -- Best Regards, Artem Bityutskiy (Артём Битюцкий) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Module + offset calculations have to be signed in arch/arm/mach-omap2/pm-debug.c
On 05/05/2011 02:16 PM, Kevin Hilman wrote: Peter Baradapeter.bar...@gmail.com writes: On 05/05/2011 01:11 PM, Kevin Hilman wrote: Peter Baradapeter.bar...@gmail.com writes: I've been working on getting the TI OMAPPSP-03.00.01.06 kernel to properly suspend/resume on my DM37x board and all was going well until I added OTG support to the kernel and on suspend, the IVA2 and CORE pwrdms would not properly go into suspend. When comparing output from /debug/pm-debug/registers/current to the TRM, I noticed the following: MOD: CM_IVA2 (48014000) 04 = 0017 20 = 0001 24 = 0001 34 = 0001 40 = 00080a00 44 = 0001 48 = 0003 MOD: PRM_IVA2 (48316000) 50 = 0007 e0 = 00ff0f05 e4 = 0ff7 e8 = 0ff7 f8 = 0001 Looking at the TRM, the PRM_IVA2 registers are at 0x48306000, not 0x48316000. OMAP3430_IVA2_MOD is defined in prcm-common.h as -0x800 which means any module + reg_offset address calculation has to be signed. Once I corrected the unsigned short offset declaration in pm_module_def, rebuilt and tested again, IVA2/core pwrdms go into suspend correctly (and addresses look correct): Just to be clear, this should only affect the display of the registers, not whether or not the power domains actually suspend correctly, right? Or, did you actually notice via some other method that this powerdomain was not hitting retention/off? Yes the change affects the registers displayed, but since the address calculation is incorrect with CONFIG_PM_DEBUG enabled, the PM_DEBUG code is reading the CM_IVA2/PRM_IVA2 registers at incorrect addresses. On my DM37x board when I suspended with OTG enabled (and without the patch), I see the following on resume: [ 496.168151] Powerdomain (iva2_pwrdm) didn't enter target state 1 (last power state 3) [ 496.176025] Powerdomain (core_pwrdm) didn't enter target state 1 (last power state 3) Hmm, this 'last power state' printk isn't in mainline, so it appears there are some other local modifications to this code. Yes, I added it to the printk to help figure out what state the domain was in: list_for_each_entry(pwrst, pwrst_list, node) { state = pwrdm_read_prev_pwrst(pwrst-pwrdm); if (state pwrst-next_state) { printk(KERN_INFO Powerdomain (%s) didn't enter target state %d (last power state %d)\n, pwrst-pwrdm-name, pwrst-next_state, state); ret = -1; } set_pwrdm_state(pwrst-pwrdm, pwrst-saved_state); } [ 496.183898] Could not enter target state in pm_suspend With the patch (and same kernel config) I see the following on resume: [ 234.867889] Successfully put all powerdomains to target state Before enabling the OTG code all powerdomains went into suspend. It could be that accessing registers at the incorrect addresses is causing DM37x to keep those domains out of retention... Hmm, very strange. The PM debug code only ever reads registers, never writes, so I can't imagine how that should prevent those power domains from hitting retention. Are there any other out-of-tree patches to the pm-debug code in your kernel? Yes there are, but I've kept it to just reading PRM/CM registers (and store them into SRAM to print out on resume). Still, I don't understand how just changing the address where to read the IVA2 registers can make it break/work, unless some side-effect of hte read make's life happy. I'll have to retry w/o PM_DEBUG enabled to see if the effect changes. In any case, you've found a real bug, and your patch is valid. However, it doesn't currently apply to mainline, and it looks like it's because your patch is using spaces and the code being patched is using tabs. Hmm, could be Thunderbird munching it... Also, you can simplify the changelog to to just describe the fix needed due to using negative offsets in some PRM modules. I'll rework the patch and send it back. I'm also comparing the list of registers you read with what the TRM lists (for the AM3730), and I see that you read entire ranges even if the range is sparsely populated, eg: { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x00, 0x04 }, { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x20, 0x24 }, { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x34, 0x34 }, { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x40, 0x4c }, and code to detect that its still looking at a pm_module_def entry that has the same type/offset as the previous to prevent the headers from being repeatedly printed. Kevin Kevin Signed-off-by: Peter Baradapeter.bar...@logicpd.com diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 125f565..b731ef3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -199,7 +199,7 @@ enum { struct pm_module_def { char name[8]; /* Name of the module */ short type; /* CM or PRM */ -unsigned short offset; +short offset; int low; /* First register
Re: Module + offset calculations have to be signed in arch/arm/mach-omap2/pm-debug.c
Peter Barada peter.bar...@gmail.com writes: On 05/05/2011 02:16 PM, Kevin Hilman wrote: Peter Baradapeter.bar...@gmail.com writes: On 05/05/2011 01:11 PM, Kevin Hilman wrote: Peter Baradapeter.bar...@gmail.com writes: I've been working on getting the TI OMAPPSP-03.00.01.06 kernel to properly suspend/resume on my DM37x board and all was going well until I added OTG support to the kernel and on suspend, the IVA2 and CORE pwrdms would not properly go into suspend. When comparing output from /debug/pm-debug/registers/current to the TRM, I noticed the following: MOD: CM_IVA2 (48014000) 04 = 0017 20 = 0001 24 = 0001 34 = 0001 40 = 00080a00 44 = 0001 48 = 0003 MOD: PRM_IVA2 (48316000) 50 = 0007 e0 = 00ff0f05 e4 = 0ff7 e8 = 0ff7 f8 = 0001 Looking at the TRM, the PRM_IVA2 registers are at 0x48306000, not 0x48316000. OMAP3430_IVA2_MOD is defined in prcm-common.h as -0x800 which means any module + reg_offset address calculation has to be signed. Once I corrected the unsigned short offset declaration in pm_module_def, rebuilt and tested again, IVA2/core pwrdms go into suspend correctly (and addresses look correct): Just to be clear, this should only affect the display of the registers, not whether or not the power domains actually suspend correctly, right? Or, did you actually notice via some other method that this powerdomain was not hitting retention/off? Yes the change affects the registers displayed, but since the address calculation is incorrect with CONFIG_PM_DEBUG enabled, the PM_DEBUG code is reading the CM_IVA2/PRM_IVA2 registers at incorrect addresses. On my DM37x board when I suspended with OTG enabled (and without the patch), I see the following on resume: [ 496.168151] Powerdomain (iva2_pwrdm) didn't enter target state 1 (last power state 3) [ 496.176025] Powerdomain (core_pwrdm) didn't enter target state 1 (last power state 3) Hmm, this 'last power state' printk isn't in mainline, so it appears there are some other local modifications to this code. Yes, I added it to the printk to help figure out what state the domain was in: list_for_each_entry(pwrst, pwrst_list, node) { state = pwrdm_read_prev_pwrst(pwrst-pwrdm); if (state pwrst-next_state) { printk(KERN_INFO Powerdomain (%s) didn't enter target state %d (last power state %d)\n, pwrst-pwrdm-name, pwrst-next_state, state); ret = -1; } set_pwrdm_state(pwrst-pwrdm, pwrst-saved_state); } [ 496.183898] Could not enter target state in pm_suspend With the patch (and same kernel config) I see the following on resume: [ 234.867889] Successfully put all powerdomains to target state Before enabling the OTG code all powerdomains went into suspend. It could be that accessing registers at the incorrect addresses is causing DM37x to keep those domains out of retention... Hmm, very strange. The PM debug code only ever reads registers, never writes, so I can't imagine how that should prevent those power domains from hitting retention. Are there any other out-of-tree patches to the pm-debug code in your kernel? Yes there are, but I've kept it to just reading PRM/CM registers (and store them into SRAM to print out on resume). Still, I don't understand how just changing the address where to read the IVA2 registers can make it break/work, unless some side-effect of hte read make's life happy. I'll have to retry w/o PM_DEBUG enabled to see if the effect changes. Rather than disable PM_DEBUG... Does your kernel do any pm_dbg_regset_save() calls in the suspend/idle path? If so, it would suffice to comment those out and see if that makes it work again (without your patch.) Would be interesting. In any case, you've found a real bug, and your patch is valid. However, it doesn't currently apply to mainline, and it looks like it's because your patch is using spaces and the code being patched is using tabs. Hmm, could be Thunderbird munching it... Also, you can simplify the changelog to to just describe the fix needed due to using negative offsets in some PRM modules. I'll rework the patch and send it back. I'm also comparing the list of registers you read with what the TRM lists (for the AM3730), and I see that you read entire ranges even if the range is sparsely populated, eg: { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x00, 0x04 }, { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x20, 0x24 }, { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x34, 0x34 }, { IVA2, MOD_CM, OMAP3430_IVA2_MOD, 0x40, 0x4c }, and code to detect that its still looking at a pm_module_def entry that has the same type/offset as the previous to prevent the headers from being repeatedly printed. Yes, admittedly this code is really awful and doesn't even belong in the kernel. It also doesn't scale well for OMAP4. Don't be
Re: Common clock and dvfs
On 5/5/2011 8:11 AM, Colin Cross wrote: On Wed, May 4, 2011 at 10:08 PM, Cousson, Benoitb-cous...@ti.com wrote: (Cc folks with some DVFS interest) Hi Colin, On Fri, 22 Apr 2011, Colin Cross wrote: Now that we are approaching a common clock management implementation, I was thinking it might be the right place to put a common dvfs implementation as well. It is very common for SoC manufacturers to provide a table of the minimum voltage required on a voltage rail for a clock to run at a given frequency. There may be multiple clocks in a voltage rail that each can specify their own minimum voltage, and one clock may affect multiple voltage rails. I have seen two ways to handle keeping the clocks and voltages within spec: The Tegra way is to put everything dvfs related under the clock framework. Enabling (or preparing, in the new clock world) or raising the frequency calls dvfs_set_rate before touching the clock, which looks up the required voltage on a voltage rail, aggregates it with the other voltage requests, and passes the minimum voltage required to the regulator api. Disabling or unpreparing, or lowering the frequency changes the clock first, and then calls dvfs_set_rate. For a generic implementation, an SoC would provide the clock/dvfs framework with a list of clocks, the voltages required for each frequency step on the clock, and the regulator name to change. The frequency/voltage tables are similar to OPP, except that OPP gets voltages for a device instead of a clock. In a few odd cases (Tegra always has a few odd cases), a clock that is internal to a device and not exposed to the clock framework (pclk output on the display, for example) has a voltage requirement, which requires some devices to manually call dvfs_set_rate directly, but with a common clock framework it would probably be possible for the display driver to export pclk as a real clock. Those kinds of exceptions are somehow the rules for an OMAP4 device. Most scalable devices are using some internal dividers or even internal PLL to control the scalable clock rate (DSS, HSI, MMC, McBSP... the OMAP4430 Data Manual [1] is providing the various clock rate limitation depending of the OPP). And none of these internal dividers are handled by the clock fmwk today. For sure, it should be possible to extend the clock data with internal devices clock nodes (like the UART baud rate divider for example), but then we will have to handle a bunch of nodes that may not be always available depending of device state. In order to do that, you have to tie these clocks node to the device that contains them. I agree there are cases where the clock framework may not be a fit for a specific divider, but it would be simple to export the same dvfs_set_rate functions that the generic clk_set_rate calls, and allow drivers that need to scale their own clocks to take advantage of the common tables. And for the clocks that do not belong to any device, like most PRCM source clocks or DPLL inside OMAP, we can easily define a PRCM device or several CM (Clock Manager) devices that will handle all these clock nodes. The proposed OMAP4 way (I believe, correct me if I am wrong) is to create a new api outside the clock api that calls into both the clock api and the regulator api in the correct order for each operation, using OPP to determine the voltage. This has a few disadvantages (obviously, I am biased, having written the Tegra code) - clocks and voltages are tied to a device, which is not always the case for platforms outside of OMAP, and drivers must know if their hardware requires voltage scaling. The clock api becomes unsafe to use on any device that requires dvfs, as it could change the frequency higher than the supported voltage. You have to tie clock and voltage to a device. Most of the time a clock does not have any clear relation with a voltage domain. It can even cross power / voltage domain without any issue. The efficiency of the DVFS technique is mainly due to the reduction of the voltage rail that supply a device. In order to achieve that you have to reduce the clock rate of one or several clocks nodes that supply the critical path inside the HW. A clock crossing a voltage domain is not a problem, a single clock can have relationships to multiple regulators. But a clock does not need to be tied to a device. From the silicon perspective, it doesn't matter how you divide up the devices in the kernel, a clock is just a line toggling at a rate, and the maximum speed it can toggle is determined by the silicon it feeds and the voltage that silicon is operating at. If a device can be turned on or off, that's a clock gate, and the line downstream from the clock gate is a separate clock. Fully agree. Just to clarify the terminology, I'm using device to represent the IP block as well. The mapping is not necessarily one to one, but for most relevant IPs this is mostly true. In our case, the hwmod will represent the HW device. My
Re: [PATCH v3] OMAP2/3: hwmod: fix the i2c-reset timeout during bootup
Hello Avinash On Mon, 2 May 2011, Avinash.H.M wrote: The sequence of _ocp_softreset doesn't work for i2c. The i2c module has a special sequence to reset the module. The sequence is - Disable the I2C. - Write to SOFTRESET bit. - Enable the I2C. - Poll on the RESETDONE bit. The sequence is implemented as a function and the i2c_class is updated with the correct 'reset' pointer. omap_hwmod_softreset function is implemented which triggers the softreset by writing into sysconfig register. On following this sequence, i2c module resets properly and timeouts are not seen. Cc: Rajendra Nayak rna...@ti.com Cc: Paul Walmsley p...@pwsan.com Cc: Benoit Cousson b-cous...@ti.com Cc: Kevin Hilman khil...@ti.com Signed-off-by: Avinash.H.M avinas...@ti.com --- The patch is based on * git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git * master branch. * 9be20f0 commit. ( Linux-omap rebuilt: Updated to -rc5 ) Please base all your patches against mainline commits. I suggest using v2.6.39-rc6. Also some comments: Changes from previous versions: from v1: - moved i2c specific things from hwmod files to i2c files. - fixed comments from Paul. - http://www.spinics.net/lists/linux-omap/msg49483.html from v2: - Avoided direct SYSCONFIG access in i2c.c - http://www.spinics.net/lists/linux-omap/msg49632.html Testing: * build tested omap2plus_defconfig for warnings and errors. none introduced. * boot tested on 2430. * tested for 'core off' in suspend resume on 3430 sdp. core off counters increment after suspend resume. arch/arm/mach-omap2/i2c.c| 54 ++ arch/arm/mach-omap2/omap_hwmod.c | 12 ++ arch/arm/mach-omap2/omap_hwmod_2420_data.c |1 + arch/arm/mach-omap2/omap_hwmod_2430_data.c |1 + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |1 + arch/arm/plat-omap/include/plat/i2c.h|4 ++ arch/arm/plat-omap/include/plat/omap_hwmod.h |1 + 7 files changed, 74 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c index 79c478c..bd50e26 100644 --- a/arch/arm/mach-omap2/i2c.c +++ b/arch/arm/mach-omap2/i2c.c @@ -21,9 +21,16 @@ #include plat/cpu.h #include plat/i2c.h +#include plat/common.h #include mux.h +/* In register I2C_CON, Bit 15 is the I2C enable bit */ +#define I2C_EN BIT(15) +#define I2C_CON_OFFSET 0x24 +/* Maximum microseconds to wait for OMAP module to softreset */ +#define MAX_MODULE_SOFTRESET_WAIT1 + void __init omap2_i2c_mux_pins(int bus_id) { char mux_name[sizeof(i2c2_scl.i2c2_scl)]; @@ -37,3 +44,50 @@ void __init omap2_i2c_mux_pins(int bus_id) sprintf(mux_name, i2c%i_sda.i2c%i_sda, bus_id, bus_id); omap_mux_init_signal(mux_name, OMAP_PIN_INPUT); } + +/** + * omap_i2c_reset- reset the omap i2c module. Please put a space before the dash. + * @oh: struct omap_hwmod * + * + * The i2c moudle in omap2, omap3 had a special sequence to reset. The + * sequence is: + * - Disable the I2C. + * - Write to SOFTRESET bit. + * - Enable the I2C. + * - Poll on the RESETDONE bit. + * The sequence is implemented in below function. This is called for 2420, + * 2430 and omap3. + */ +int omap_i2c_reset(struct omap_hwmod *oh) +{ + u32 v; + int c = 0; + + /* Disable I2C */ + v = omap_hwmod_read(oh, I2C_CON_OFFSET); + v = v ~I2C_EN; + omap_hwmod_write(v, oh, I2C_CON_OFFSET); + + /* Write to the SOFTRESET bit */ + omap_hwmod_softreset(oh); + + /* Enable I2C */ + v = omap_hwmod_read(oh, I2C_CON_OFFSET); + v |= I2C_EN; + omap_hwmod_write(v, oh, I2C_CON_OFFSET); + + /* Poll on RESETDONE bit */ + omap_test_timeout((omap_hwmod_read(oh, + oh-class-sysc-syss_offs) + SYSS_RESETDONE_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + + if (c == MAX_MODULE_SOFTRESET_WAIT) + pr_warning(%s: %s: softreset failed (waited %d usec)\n, + __func__, oh-name, MAX_MODULE_SOFTRESET_WAIT); + else + pr_debug(%s: %s: softreset in %d usec\n, __func__, + oh-name, c); + + return 0; +} diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index e034294..771fc15 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1561,6 +1561,18 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs) __raw_writel(v, oh-_mpu_rt_va + reg_offs); } You're missing kerneldoc here. Please add it. +void omap_hwmod_softreset(struct omap_hwmod *oh) +{ + u32 v; + + /* Write to the SOFTRESET bit in SYSCONFIG */ + v = oh-_sysc_cache; + v |= (0x1
Re: Common clock and dvfs
On Thu, May 5, 2011 at 2:08 PM, Cousson, Benoit b-cous...@ti.com wrote: On 5/5/2011 8:11 AM, Colin Cross wrote: On Wed, May 4, 2011 at 10:08 PM, Cousson, Benoitb-cous...@ti.com wrote: (Cc folks with some DVFS interest) Hi Colin, On Fri, 22 Apr 2011, Colin Cross wrote: Now that we are approaching a common clock management implementation, I was thinking it might be the right place to put a common dvfs implementation as well. It is very common for SoC manufacturers to provide a table of the minimum voltage required on a voltage rail for a clock to run at a given frequency. There may be multiple clocks in a voltage rail that each can specify their own minimum voltage, and one clock may affect multiple voltage rails. I have seen two ways to handle keeping the clocks and voltages within spec: The Tegra way is to put everything dvfs related under the clock framework. Enabling (or preparing, in the new clock world) or raising the frequency calls dvfs_set_rate before touching the clock, which looks up the required voltage on a voltage rail, aggregates it with the other voltage requests, and passes the minimum voltage required to the regulator api. Disabling or unpreparing, or lowering the frequency changes the clock first, and then calls dvfs_set_rate. For a generic implementation, an SoC would provide the clock/dvfs framework with a list of clocks, the voltages required for each frequency step on the clock, and the regulator name to change. The frequency/voltage tables are similar to OPP, except that OPP gets voltages for a device instead of a clock. In a few odd cases (Tegra always has a few odd cases), a clock that is internal to a device and not exposed to the clock framework (pclk output on the display, for example) has a voltage requirement, which requires some devices to manually call dvfs_set_rate directly, but with a common clock framework it would probably be possible for the display driver to export pclk as a real clock. Those kinds of exceptions are somehow the rules for an OMAP4 device. Most scalable devices are using some internal dividers or even internal PLL to control the scalable clock rate (DSS, HSI, MMC, McBSP... the OMAP4430 Data Manual [1] is providing the various clock rate limitation depending of the OPP). And none of these internal dividers are handled by the clock fmwk today. For sure, it should be possible to extend the clock data with internal devices clock nodes (like the UART baud rate divider for example), but then we will have to handle a bunch of nodes that may not be always available depending of device state. In order to do that, you have to tie these clocks node to the device that contains them. I agree there are cases where the clock framework may not be a fit for a specific divider, but it would be simple to export the same dvfs_set_rate functions that the generic clk_set_rate calls, and allow drivers that need to scale their own clocks to take advantage of the common tables. And for the clocks that do not belong to any device, like most PRCM source clocks or DPLL inside OMAP, we can easily define a PRCM device or several CM (Clock Manager) devices that will handle all these clock nodes. The proposed OMAP4 way (I believe, correct me if I am wrong) is to create a new api outside the clock api that calls into both the clock api and the regulator api in the correct order for each operation, using OPP to determine the voltage. This has a few disadvantages (obviously, I am biased, having written the Tegra code) - clocks and voltages are tied to a device, which is not always the case for platforms outside of OMAP, and drivers must know if their hardware requires voltage scaling. The clock api becomes unsafe to use on any device that requires dvfs, as it could change the frequency higher than the supported voltage. You have to tie clock and voltage to a device. Most of the time a clock does not have any clear relation with a voltage domain. It can even cross power / voltage domain without any issue. The efficiency of the DVFS technique is mainly due to the reduction of the voltage rail that supply a device. In order to achieve that you have to reduce the clock rate of one or several clocks nodes that supply the critical path inside the HW. A clock crossing a voltage domain is not a problem, a single clock can have relationships to multiple regulators. But a clock does not need to be tied to a device. From the silicon perspective, it doesn't matter how you divide up the devices in the kernel, a clock is just a line toggling at a rate, and the maximum speed it can toggle is determined by the silicon it feeds and the voltage that silicon is operating at. If a device can be turned on or off, that's a clock gate, and the line downstream from the clock gate is a separate clock. Fully agree. Just to clarify the terminology, I'm using device to represent the IP block as well.